Skip to content

Commit

Permalink
Add Column Start and Row Start controls to Grid children (WordPress#5…
Browse files Browse the repository at this point in the history
…9483)

* Separate flex child controls so each has its own reset.

* Output grid-start styling

* Add Column Start and Row Start controls to block inspector

* Simplify php array access

* Remove a few more issets

* Adjust container query to take columnStart into account.

* Reset grid spans together

* Add max to column/row inputs

* Adjust copy

* Don't show Grid position by default

* Use 'Grid placement'

* Simplify input control labels for now

* Put placement behind the Grid interactivity experimental flag for now

* Fix input width issue in webkit

* Show placement after span

---------

Co-authored-by: tellthemachines <isabel@tellthemachines.com>

Co-authored-by: tellthemachines <isabel_brison@git.wordpress.org>
Co-authored-by: noisysocks <noisysocks@git.wordpress.org>
Co-authored-by: andrewserong <andrewserong@git.wordpress.org>
  • Loading branch information
4 people authored and carstingaxion committed Mar 27, 2024
1 parent 28da9b8 commit 27ec8da
Show file tree
Hide file tree
Showing 4 changed files with 233 additions and 90 deletions.
46 changes: 33 additions & 13 deletions lib/block-supports/layout.php
Expand Up @@ -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 );

Expand All @@ -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,
),
);
}
Expand Down
182 changes: 147 additions & 35 deletions packages/block-editor/src/components/child-layout-control/index.js
Expand Up @@ -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';
Expand All @@ -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( {
Expand All @@ -59,7 +100,15 @@ export default function ChildLayoutControl( {
return (
<>
{ parentLayoutType === 'flex' && (
<>
<VStack
as={ ToolsPanelItem }
spacing={ 2 }
hasValue={ hasFlexValue }
label={ flexResetLabel }
onDeselect={ resetFlex }
isShownByDefault={ isShownByDefault }
panelId={ panelId }
>
<ToggleGroupControl
__nextHasNoMarginBottom
size={ '__unstable-large' }
Expand Down Expand Up @@ -104,37 +153,100 @@ export default function ChildLayoutControl( {
value={ flexSize }
/>
) }
</>
</VStack>
) }
{ parentLayoutType === 'grid' && (
<HStack>
<InputControl
size={ '__unstable-large' }
label={ __( 'Column Span' ) }
type="number"
onChange={ ( value ) => {
onChange( {
rowSpan,
columnSpan: value,
} );
} }
value={ columnSpan }
min={ 1 }
/>
<InputControl
size={ '__unstable-large' }
label={ __( 'Row Span' ) }
type="number"
onChange={ ( value ) => {
onChange( {
columnSpan,
rowSpan: value,
} );
} }
value={ rowSpan }
min={ 1 }
/>
</HStack>
<>
<HStack
as={ ToolsPanelItem }
hasValue={ hasSpanValue }
label={ __( 'Grid span' ) }
onDeselect={ resetGridSpans }
isShownByDefault={ isShownByDefault }
panelId={ panelId }
>
<InputControl
size={ '__unstable-large' }
label={ __( 'Column span' ) }
type="number"
onChange={ ( value ) => {
onChange( {
columnStart,
rowStart,
rowSpan,
columnSpan: value,
} );
} }
value={ columnSpan }
min={ 1 }
/>
<InputControl
size={ '__unstable-large' }
label={ __( 'Row span' ) }
type="number"
onChange={ ( value ) => {
onChange( {
columnStart,
rowStart,
columnSpan,
rowSpan: value,
} );
} }
value={ rowSpan }
min={ 1 }
/>
</HStack>
{ 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.
<Flex
as={ ToolsPanelItem }
hasValue={ hasStartValue }
label={ __( 'Grid placement' ) }
onDeselect={ resetGridStarts }
isShownByDefault={ false }
panelId={ panelId }
>
<FlexItem style={ { width: '50%' } }>
<InputControl
size={ '__unstable-large' }
label={ __( 'Column' ) }
type="number"
onChange={ ( value ) => {
onChange( {
columnStart: value,
rowStart,
columnSpan,
rowSpan,
} );
} }
value={ columnStart }
min={ 1 }
max={ parentLayout?.columnCount }
/>
</FlexItem>
<FlexItem style={ { width: '50%' } }>
<InputControl
size={ '__unstable-large' }
label={ __( 'Row' ) }
type="number"
onChange={ ( value ) => {
onChange( {
columnStart,
rowStart: value,
columnSpan,
rowSpan,
} );
} }
value={ rowStart }
min={ 1 }
max={ parentLayout?.columnCount }
/>
</FlexItem>
</Flex>
) }
</>
) }
</>
);
Expand Down
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand All @@ -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 {
Expand All @@ -433,6 +414,8 @@ export default function DimensionsPanel( {
wideSize: undefined,
selfStretch: undefined,
flexSize: undefined,
columnStart: undefined,
rowStart: undefined,
columnSpan: undefined,
rowSpan: undefined,
} ),
Expand Down Expand Up @@ -650,24 +633,16 @@ export default function DimensionsPanel( {
</ToolsPanelItem>
) }
{ showChildLayoutControl && (
<VStack
as={ ToolsPanelItem }
spacing={ 2 }
hasValue={ hasChildLayoutValue }
label={ childLayoutResetLabel }
onDeselect={ resetChildLayoutValue }
<ChildLayoutControl
value={ childLayout }
onChange={ setChildLayout }
parentLayout={ settings?.parentLayout }
panelId={ panelId }
isShownByDefault={
defaultControls.childLayout ??
DEFAULT_CONTROLS.childLayout
}
panelId={ panelId }
>
<ChildLayoutControl
value={ childLayout }
onChange={ setChildLayout }
parentLayout={ settings?.parentLayout }
/>
</VStack>
/>
) }
{ showMinHeightControl && (
<ToolsPanelItem
Expand Down

0 comments on commit 27ec8da

Please sign in to comment.