diff --git a/lib/block-supports/layout.php b/lib/block-supports/layout.php index 48cb206fd7894..66e731b76599a 100644 --- a/lib/block-supports/layout.php +++ b/lib/block-supports/layout.php @@ -573,7 +573,22 @@ function gutenberg_render_layout_support_flag( $block_content, $block ) { $child_layout_styles = array(); $self_stretch = isset( $block['attrs']['style']['layout']['selfStretch'] ) ? $block['attrs']['style']['layout']['selfStretch'] : null; + $self_align = isset( $block['attrs']['style']['layout']['selfAlign'] ) ? $block['attrs']['style']['layout']['selfAlign'] : null; + $height = isset( $block['attrs']['style']['layout']['height'] ) ? $block['attrs']['style']['layout']['height'] : null; + $width = isset( $block['attrs']['style']['layout']['width'] ) ? $block['attrs']['style']['layout']['width'] : null; + + $parent_layout_type = 'default'; + if ( isset( $block['parentLayout']['type'] ) ) { + $parent_layout_type = $block['parentLayout']['type']; + } elseif ( isset( $block['parentLayout']['default']['type'] ) ) { + $parent_layout_type = $block['parentLayout']['default']['type']; + } + + // Orientation is only used for flex layouts so its default is horizontal. + $parent_orientation = isset( $block['parentLayout']['orientation'] ) ? $block['parentLayout']['orientation'] : 'horizontal'; + $vertical_parent_layout = in_array( $parent_layout_type, array( 'constrained', 'default' ), true ) || ( 'flex' === $parent_layout_type && 'vertical' === $parent_orientation ); + // Support for legacy flexSize value. if ( 'fixed' === $self_stretch && isset( $block['attrs']['style']['layout']['flexSize'] ) ) { $child_layout_declarations['flex-basis'] = $block['attrs']['style']['layout']['flexSize']; $child_layout_declarations['box-sizing'] = 'border-box'; @@ -581,6 +596,49 @@ function gutenberg_render_layout_support_flag( $block_content, $block ) { $child_layout_declarations['flex-grow'] = '1'; } + if ( $vertical_parent_layout ) { + // Width styles. + if ( 'fixed' === $self_align && $width ) { + $child_layout_declarations['max-width'] = $width; + } elseif ( 'fixedNoShrink' === $self_align && $width ) { + $child_layout_declarations['width'] = $width; + } elseif ( 'fill' === $self_align ) { + $child_layout_declarations['align-self'] = 'stretch'; + } elseif ( 'fit' === $self_align ) { + $child_layout_declarations['width'] = 'fit-content'; + } + // Height styles. + if ( 'fixed' === $self_stretch && $height ) { + $child_layout_declarations['max-height'] = $height; + $child_layout_declarations['flex-basis'] = $height; + } elseif ( 'fixedNoShrink' === $self_stretch && $height ) { + $child_layout_declarations['height'] = $height; + $child_layout_declarations['flex-shrink'] = '0'; + $child_layout_declarations['flex-basis'] = $height; + } elseif ( 'fill' === $self_stretch ) { + $child_layout_declarations['flex-grow'] = '1'; + } + } elseif ( 'grid' !== $parent_layout_type ) { + // Width styles. + if ( 'fixed' === $self_stretch && $width ) { + $child_layout_declarations['flex-basis'] = $width; + } elseif ( 'fixedNoShrink' === $self_stretch && $width ) { + $child_layout_declarations['flex-shrink'] = '0'; + $child_layout_declarations['flex-basis'] = $width; + } elseif ( 'fill' === $self_stretch ) { + $child_layout_declarations['flex-grow'] = '1'; + } + // Height styles. + if ( 'fixed' === $self_align && $height ) { + $child_layout_declarations['max-height'] = $height; + } elseif ( 'fixedNoShrink' === $self_align && $height ) { + $child_layout_declarations['height'] = $height; + } elseif ( 'fill' === $self_align ) { + $child_layout_declarations['align-self'] = 'stretch'; + } + } + + // Grid specific styles. if ( isset( $block['attrs']['style']['layout']['columnSpan'] ) ) { $column_span = $block['attrs']['style']['layout']['columnSpan']; $child_layout_declarations['grid-column'] = "span $column_span"; @@ -589,6 +647,7 @@ function gutenberg_render_layout_support_flag( $block_content, $block ) { $row_span = $block['attrs']['style']['layout']['rowSpan']; $child_layout_declarations['grid-row'] = "span $row_span"; } + $child_layout_styles[] = array( 'selector' => ".$container_content_class", 'declarations' => $child_layout_declarations, @@ -902,6 +961,8 @@ function ( $parsed_block, $source_block, $parent_block ) { */ if ( $parent_block && isset( $parent_block->parsed_block['attrs']['layout'] ) ) { $parsed_block['parentLayout'] = $parent_block->parsed_block['attrs']['layout']; + } elseif ( $parent_block && isset( $parent_block->block_type->supports['layout'] ) ) { + $parsed_block['parentLayout'] = $parent_block->block_type->supports['layout']; } return $parsed_block; }, diff --git a/packages/block-editor/src/components/child-layout-control/index.js b/packages/block-editor/src/components/child-layout-control/index.js index 39625da4c0331..bfa7d6510c0c6 100644 --- a/packages/block-editor/src/components/child-layout-control/index.js +++ b/packages/block-editor/src/components/child-layout-control/index.js @@ -299,10 +299,24 @@ export default function ChildLayoutControl( { }; useEffect( () => { - if ( selfStretch === 'fixed' && ! flexSize ) { + if ( + ( childLayout[ heightProp ] === 'fixed' || + childLayout[ heightProp ] === 'fixedNoShrink' ) && + ! height + ) { + onChange( { + ...childLayout, + [ heightProp ]: undefined, + } ); + } + if ( + ( childLayout[ widthProp ] === 'fixed' || + childLayout[ widthProp ] === 'fixedNoShrink' ) && + ! width + ) { onChange( { ...childLayout, - selfStretch: 'fit', + [ widthProp ]: undefined, } ); } }, [] ); diff --git a/packages/block-editor/src/hooks/layout-child.js b/packages/block-editor/src/hooks/layout-child.js index c0db8ef428d15..9d52a3b941c0f 100644 --- a/packages/block-editor/src/hooks/layout-child.js +++ b/packages/block-editor/src/hooks/layout-child.js @@ -16,8 +16,15 @@ function useBlockPropsChildLayoutStyles( { style } ) { return ! select( blockEditorStore ).getSettings().disableLayoutStyles; } ); const layout = style?.layout ?? {}; - const { selfStretch, flexSize, columnSpan, rowSpan, height, width } = - layout; + const { + selfStretch, + selfAlign, + flexSize, + columnSpan, + rowSpan, + height, + width, + } = layout; const parentLayout = useLayout() || {}; const { columnCount, @@ -30,19 +37,11 @@ function useBlockPropsChildLayoutStyles( { style } ) { const id = useInstanceId( useBlockPropsChildLayoutStyles ); const selector = `.wp-container-content-${ id }`; - const isFlowOrConstrained = + const isVerticalLayout = parentLayout.type === 'constrained' || parentLayout.type === 'default' || - parentLayout.type === undefined; - - const widthProp = - isFlowOrConstrained || orientation === 'vertical' - ? 'selfAlign' - : 'selfStretch'; - const heightProp = - isFlowOrConstrained || orientation === 'vertical' - ? 'selfStretch' - : 'selfAlign'; + parentLayout.type === undefined || + orientation === 'vertical'; let css = ''; if ( shouldRenderChildLayoutStyles ) { @@ -58,100 +57,76 @@ function useBlockPropsChildLayoutStyles( { style } ) { grid-column: span ${ columnSpan }; }`; } - if ( isFlowOrConstrained || orientation === 'vertical' ) { - // set width - if ( layout[ widthProp ] === 'fixed' && width ) { + // All vertical layout types have the same styles. + if ( isVerticalLayout ) { + if ( selfAlign === 'fixed' && width ) { css += `${ selector } { max-width: ${ width }; }`; - } else if ( layout[ widthProp ] === 'fixedNoShrink' && width ) { + } else if ( selfAlign === 'fixedNoShrink' && width ) { css += `${ selector } { width: ${ width }; }`; - } else if ( layout[ widthProp ] === 'fill' ) { + } else if ( selfAlign === 'fill' ) { + /** + * This style is only needed for flex layouts because + * constrained children have alignment set and flow + * children are 100% width by default. + */ css += `${ selector } { align-self: stretch; }`; - } else if ( layout[ widthProp ] === 'fit' ) { + } else if ( selfAlign === 'fit' ) { css += `${ selector } { width: fit-content; }`; } - // set height - if ( layout[ heightProp ] === 'fixed' && height ) { + if ( selfStretch === 'fixed' && height ) { + // Max-height is needed for flow and constrained children. css += `${ selector } { max-height: ${ height }; - flex-grow: 0; - flex-shrink: 1; flex-basis: ${ height }; }`; - } else if ( layout[ heightProp ] === 'fixedNoShrink' && height ) { + } else if ( selfStretch === 'fixedNoShrink' && height ) { + // Height is needed for flow and constrained children. css += `${ selector } { height: ${ height }; flex-shrink: 0; - flex-grow: 0; - flex-basis: auto; + flex-basis: ${ height }; }`; - } else if ( layout[ heightProp ] === 'fill' ) { + } else if ( selfStretch === 'fill' ) { css += `${ selector } { flex-grow: 1; - flex-shrink: 1; - }`; - } else if ( layout[ heightProp ] === 'fit' ) { - css += `${ selector } { - flex-grow: 0; - flex-shrink: 0; - flex-basis: auto; - height: auto; }`; } + // Everything else that isn't a grid is a horizontal layout. } else if ( parentLayoutType !== 'grid' ) { - // set width - if ( layout[ widthProp ] === 'fixed' && width ) { + if ( selfStretch === 'fixed' && width ) { css += `${ selector } { - max-width: ${ width }; - flex-grow: 0; - flex-shrink: 1; flex-basis: ${ width }; }`; - } else if ( layout[ widthProp ] === 'fixedNoShrink' && width ) { + } else if ( selfStretch === 'fixedNoShrink' && width ) { css += `${ selector } { - width: ${ width }; flex-shrink: 0; - flex-grow: 0; - flex-basis: auto; + flex-basis: ${ width }; }`; - } else if ( layout[ widthProp ] === 'fill' ) { + } else if ( selfStretch === 'fill' ) { css += `${ selector } { flex-grow: 1; - flex-shrink: 1; - flex-basis: 100%; - }`; - } else if ( layout[ widthProp ] === 'fit' ) { - css += `${ selector } { - flex-grow: 0; - flex-shrink: 0; - flex-basis: auto; - width: fit-content; }`; } - // set height - if ( layout[ heightProp ] === 'fill' ) { + if ( selfAlign === 'fill' ) { css += `${ selector } { align-self: stretch; }`; - } else if ( layout[ heightProp ] === 'fit' ) { - css += `${ selector } { - height: fit-content; - }`; - } else if ( layout[ heightProp ] === 'fixedNoShrink' && height ) { + } else if ( selfAlign === 'fixedNoShrink' && height ) { css += `${ selector } { height: ${ height }; }`; - } else if ( layout[ heightProp ] === 'fixed' && height ) { + } else if ( selfAlign === 'fixed' && height ) { css += `${ selector } { max-height: ${ height }; }`;