diff --git a/lib/block-supports/layout.php b/lib/block-supports/layout.php index 30b5d8d02084a8..b53a90cde21855 100644 --- a/lib/block-supports/layout.php +++ b/lib/block-supports/layout.php @@ -581,28 +581,46 @@ function gutenberg_render_layout_support_flag( $block_content, $block ) { $child_layout_declarations['flex-grow'] = '1'; } - if ( isset( $block['attrs']['style']['layout']['columnSpan'] ) ) { - $column_span = $block['attrs']['style']['layout']['columnSpan']; + $column_start = isset( $block['attrs']['style']['layout']['columnStart'] ) ? $block['attrs']['style']['layout']['columnStart'] : null; + $column_span = isset( $block['attrs']['style']['layout']['columnSpan'] ) ? $block['attrs']['style']['layout']['columnSpan'] : null; + if ( $column_start && $column_span ) { + $child_layout_declarations['grid-column'] = "$column_start / span $column_span"; + } elseif ( $column_start ) { + $child_layout_declarations['grid-column'] = "$column_start"; + } elseif ( $column_span ) { $child_layout_declarations['grid-column'] = "span $column_span"; } - if ( isset( $block['attrs']['style']['layout']['rowSpan'] ) ) { - $row_span = $block['attrs']['style']['layout']['rowSpan']; + + $row_start = isset( $block['attrs']['style']['layout']['rowStart'] ) ? $block['attrs']['style']['layout']['rowStart'] : null; + $row_span = isset( $block['attrs']['style']['layout']['rowSpan'] ) ? $block['attrs']['style']['layout']['rowSpan'] : null; + if ( $row_start && $row_span ) { + $child_layout_declarations['grid-row'] = "$row_start / span $row_span"; + } elseif ( $row_start ) { + $child_layout_declarations['grid-row'] = "$row_start"; + } elseif ( $row_span ) { $child_layout_declarations['grid-row'] = "span $row_span"; } + $child_layout_styles[] = array( 'selector' => ".$container_content_class", 'declarations' => $child_layout_declarations, ); + $minimum_column_width = isset( $block['attrs']['style']['layout']['minimumColumnWidth'] ) ? $block['attrs']['style']['layout']['minimumColumnWidth'] : null; + $column_count = isset( $block['attrs']['style']['layout']['columnCount'] ) ? $block['attrs']['style']['layout']['columnCount'] : null; + /* - * If columnSpan is set, and the parent grid is responsive, i.e. if it has a minimumColumnWidth set, - * the columnSpan should be removed on small grids. If there's a minimumColumnWidth, the grid is responsive. - * But if the minimumColumnWidth value wasn't changed, it won't be set. In that case, if columnCount doesn't - * exist, we can assume that the grid is responsive. + * If columnSpan or columnStart is set, and the parent grid is responsive, i.e. if it has a minimumColumnWidth set, + * the columnSpan should be removed once the grid is smaller than the span, and columnStart should be removed + * once the grid has less columns than the start. + * If there's a minimumColumnWidth, the grid is responsive. But if the minimumColumnWidth value wasn't changed, it won't be set. + * In that case, if columnCount doesn't exist, we can assume that the grid is responsive. */ - if ( isset( $block['attrs']['style']['layout']['columnSpan'] ) && ( isset( $block['parentLayout']['minimumColumnWidth'] ) || ! isset( $block['parentLayout']['columnCount'] ) ) ) { - $column_span_number = floatval( $block['attrs']['style']['layout']['columnSpan'] ); - $parent_column_width = isset( $block['parentLayout']['minimumColumnWidth'] ) ? $block['parentLayout']['minimumColumnWidth'] : '12rem'; + if ( ( $column_span || $column_start ) && ( $minimum_column_width || ! $column_count ) ) { + $column_span_number = floatval( $column_span ); + $column_start_number = floatval( $column_start ); + $highest_number = max( $column_span_number, $column_start_number ); + $parent_column_width = $minimum_column_width ? $minimum_column_width : '12rem'; $parent_column_value = floatval( $parent_column_width ); $parent_column_unit = explode( $parent_column_value, $parent_column_width ); @@ -627,14 +645,16 @@ function gutenberg_render_layout_support_flag( $block_content, $block ) { * viable to use in the computation of the container query value. */ $default_gap_value = 'px' === $parent_column_unit ? 24 : 1.5; - $container_query_value = $column_span_number * $parent_column_value + ( $column_span_number - 1 ) * $default_gap_value; + $container_query_value = $highest_number * $parent_column_value + ( $highest_number - 1 ) * $default_gap_value; $container_query_value = $container_query_value . $parent_column_unit; + // If a span is set we want to preserve it as long as possible, otherwise we just reset the value. + $grid_column_value = $column_span ? '1/-1' : 'auto'; $child_layout_styles[] = array( 'rules_group' => "@container (max-width: $container_query_value )", 'selector' => ".$container_content_class", 'declarations' => array( - 'grid-column' => '1/-1', + 'grid-column' => $grid_column_value, ), ); } 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 fcdbc4369f33e9..e0af72c238ad53 100644 --- a/packages/block-editor/src/components/child-layout-control/index.js +++ b/packages/block-editor/src/components/child-layout-control/index.js @@ -7,6 +7,10 @@ import { __experimentalUnitControl as UnitControl, __experimentalInputControl as InputControl, __experimentalHStack as HStack, + __experimentalVStack as VStack, + __experimentalToolsPanelItem as ToolsPanelItem, + Flex, + FlexItem, } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import { useEffect } from '@wordpress/element'; @@ -28,25 +32,62 @@ function helpText( selfStretch, parentLayout ) { /** * Form to edit the child layout value. * - * @param {Object} props Props. - * @param {Object} props.value The child layout value. - * @param {Function} props.onChange Function to update the child layout value. - * @param {Object} props.parentLayout The parent layout value. + * @param {Object} props Props. + * @param {Object} props.value The child layout value. + * @param {Function} props.onChange Function to update the child layout value. + * @param {Object} props.parentLayout The parent layout value. * + * @param {boolean} props.isShownByDefault + * @param {string} props.panelId * @return {Element} child layout edit element. */ export default function ChildLayoutControl( { value: childLayout = {}, onChange, parentLayout, + isShownByDefault, + panelId, } ) { - const { selfStretch, flexSize, columnSpan, rowSpan } = childLayout; + const { + selfStretch, + flexSize, + columnStart, + rowStart, + columnSpan, + rowSpan, + } = childLayout; const { type: parentType, default: { type: defaultParentType = 'default' } = {}, + orientation = 'horizontal', } = parentLayout ?? {}; const parentLayoutType = parentType || defaultParentType; + const hasFlexValue = () => !! selfStretch; + const flexResetLabel = + orientation === 'horizontal' ? __( 'Width' ) : __( 'Height' ); + const resetFlex = () => { + onChange( { + selfStretch: undefined, + flexSize: undefined, + } ); + }; + + const hasStartValue = () => !! columnStart || !! rowStart; + const hasSpanValue = () => !! columnSpan || !! rowSpan; + const resetGridStarts = () => { + onChange( { + columnStart: undefined, + rowStart: undefined, + } ); + }; + const resetGridSpans = () => { + onChange( { + columnSpan: undefined, + rowSpan: undefined, + } ); + }; + useEffect( () => { if ( selfStretch === 'fixed' && ! flexSize ) { onChange( { @@ -59,7 +100,15 @@ export default function ChildLayoutControl( { return ( <> { parentLayoutType === 'flex' && ( - <> + ) } - + ) } { parentLayoutType === 'grid' && ( - - { - onChange( { - rowSpan, - columnSpan: value, - } ); - } } - value={ columnSpan } - min={ 1 } - /> - { - onChange( { - columnSpan, - rowSpan: value, - } ); - } } - value={ rowSpan } - min={ 1 } - /> - + <> + + { + onChange( { + columnStart, + rowStart, + rowSpan, + columnSpan: value, + } ); + } } + value={ columnSpan } + min={ 1 } + /> + { + onChange( { + columnStart, + rowStart, + columnSpan, + rowSpan: value, + } ); + } } + value={ rowSpan } + min={ 1 } + /> + + { window.__experimentalEnableGridInteractivity && ( + // Use Flex with an explicit width on the FlexItem instead of HStack to + // work around an issue in webkit where inputs with a max attribute are + // sized incorrectly. + + + { + onChange( { + columnStart: value, + rowStart, + columnSpan, + rowSpan, + } ); + } } + value={ columnStart } + min={ 1 } + max={ parentLayout?.columnCount } + /> + + + { + onChange( { + columnStart, + rowStart: value, + columnSpan, + rowSpan, + } ); + } } + value={ rowStart } + min={ 1 } + max={ parentLayout?.columnCount } + /> + + + ) } + ) } ); diff --git a/packages/block-editor/src/components/global-styles/dimensions-panel.js b/packages/block-editor/src/components/global-styles/dimensions-panel.js index 1386df0dfe2894..94e53eec163721 100644 --- a/packages/block-editor/src/components/global-styles/dimensions-panel.js +++ b/packages/block-editor/src/components/global-styles/dimensions-panel.js @@ -12,7 +12,6 @@ import { __experimentalToolsPanelItem as ToolsPanelItem, __experimentalBoxControl as BoxControl, __experimentalHStack as HStack, - __experimentalVStack as VStack, __experimentalUnitControl as UnitControl, __experimentalUseCustomUnits as useCustomUnits, __experimentalView as View, @@ -396,16 +395,7 @@ export default function DimensionsPanel( { // Child Layout const showChildLayoutControl = useHasChildLayout( settings ); const childLayout = inheritedValue?.layout; - const { orientation = 'horizontal' } = settings?.parentLayout ?? {}; - const { - type: parentType, - default: { type: defaultParentType = 'default' } = {}, - } = settings?.parentLayout ?? {}; - const parentLayoutType = parentType || defaultParentType; - const flexResetLabel = - orientation === 'horizontal' ? __( 'Width' ) : __( 'Height' ); - const childLayoutResetLabel = - parentLayoutType === 'flex' ? flexResetLabel : __( 'Grid spans' ); + const setChildLayout = ( newChildLayout ) => { onChange( { ...value, @@ -414,15 +404,6 @@ export default function DimensionsPanel( { }, } ); }; - const resetChildLayoutValue = () => { - setChildLayout( { - selfStretch: undefined, - flexSize: undefined, - columnSpan: undefined, - rowSpan: undefined, - } ); - }; - const hasChildLayoutValue = () => !! value?.layout; const resetAllFilter = useCallback( ( previousValue ) => { return { @@ -433,6 +414,8 @@ export default function DimensionsPanel( { wideSize: undefined, selfStretch: undefined, flexSize: undefined, + columnStart: undefined, + rowStart: undefined, columnSpan: undefined, rowSpan: undefined, } ), @@ -650,24 +633,16 @@ export default function DimensionsPanel( { ) } { showChildLayoutControl && ( - - - + /> ) } { showMinHeightControl && (