Skip to content

Commit 9c213e9

Browse files
noisysockstellthemachinesandrewserong
authored
Add Column Start and Row Start controls to Grid children (#59483)
* 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 <[email protected]> Co-authored-by: tellthemachines <[email protected]> Co-authored-by: noisysocks <[email protected]> Co-authored-by: andrewserong <[email protected]>
1 parent 01eb7eb commit 9c213e9

File tree

4 files changed

+233
-90
lines changed

4 files changed

+233
-90
lines changed

lib/block-supports/layout.php

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -581,28 +581,46 @@ function gutenberg_render_layout_support_flag( $block_content, $block ) {
581581
$child_layout_declarations['flex-grow'] = '1';
582582
}
583583

584-
if ( isset( $block['attrs']['style']['layout']['columnSpan'] ) ) {
585-
$column_span = $block['attrs']['style']['layout']['columnSpan'];
584+
$column_start = isset( $block['attrs']['style']['layout']['columnStart'] ) ? $block['attrs']['style']['layout']['columnStart'] : null;
585+
$column_span = isset( $block['attrs']['style']['layout']['columnSpan'] ) ? $block['attrs']['style']['layout']['columnSpan'] : null;
586+
if ( $column_start && $column_span ) {
587+
$child_layout_declarations['grid-column'] = "$column_start / span $column_span";
588+
} elseif ( $column_start ) {
589+
$child_layout_declarations['grid-column'] = "$column_start";
590+
} elseif ( $column_span ) {
586591
$child_layout_declarations['grid-column'] = "span $column_span";
587592
}
588-
if ( isset( $block['attrs']['style']['layout']['rowSpan'] ) ) {
589-
$row_span = $block['attrs']['style']['layout']['rowSpan'];
593+
594+
$row_start = isset( $block['attrs']['style']['layout']['rowStart'] ) ? $block['attrs']['style']['layout']['rowStart'] : null;
595+
$row_span = isset( $block['attrs']['style']['layout']['rowSpan'] ) ? $block['attrs']['style']['layout']['rowSpan'] : null;
596+
if ( $row_start && $row_span ) {
597+
$child_layout_declarations['grid-row'] = "$row_start / span $row_span";
598+
} elseif ( $row_start ) {
599+
$child_layout_declarations['grid-row'] = "$row_start";
600+
} elseif ( $row_span ) {
590601
$child_layout_declarations['grid-row'] = "span $row_span";
591602
}
603+
592604
$child_layout_styles[] = array(
593605
'selector' => ".$container_content_class",
594606
'declarations' => $child_layout_declarations,
595607
);
596608

609+
$minimum_column_width = isset( $block['attrs']['style']['layout']['minimumColumnWidth'] ) ? $block['attrs']['style']['layout']['minimumColumnWidth'] : null;
610+
$column_count = isset( $block['attrs']['style']['layout']['columnCount'] ) ? $block['attrs']['style']['layout']['columnCount'] : null;
611+
597612
/*
598-
* If columnSpan is set, and the parent grid is responsive, i.e. if it has a minimumColumnWidth set,
599-
* the columnSpan should be removed on small grids. If there's a minimumColumnWidth, the grid is responsive.
600-
* But if the minimumColumnWidth value wasn't changed, it won't be set. In that case, if columnCount doesn't
601-
* exist, we can assume that the grid is responsive.
613+
* If columnSpan or columnStart is set, and the parent grid is responsive, i.e. if it has a minimumColumnWidth set,
614+
* the columnSpan should be removed once the grid is smaller than the span, and columnStart should be removed
615+
* once the grid has less columns than the start.
616+
* If there's a minimumColumnWidth, the grid is responsive. But if the minimumColumnWidth value wasn't changed, it won't be set.
617+
* In that case, if columnCount doesn't exist, we can assume that the grid is responsive.
602618
*/
603-
if ( isset( $block['attrs']['style']['layout']['columnSpan'] ) && ( isset( $block['parentLayout']['minimumColumnWidth'] ) || ! isset( $block['parentLayout']['columnCount'] ) ) ) {
604-
$column_span_number = floatval( $block['attrs']['style']['layout']['columnSpan'] );
605-
$parent_column_width = isset( $block['parentLayout']['minimumColumnWidth'] ) ? $block['parentLayout']['minimumColumnWidth'] : '12rem';
619+
if ( ( $column_span || $column_start ) && ( $minimum_column_width || ! $column_count ) ) {
620+
$column_span_number = floatval( $column_span );
621+
$column_start_number = floatval( $column_start );
622+
$highest_number = max( $column_span_number, $column_start_number );
623+
$parent_column_width = $minimum_column_width ? $minimum_column_width : '12rem';
606624
$parent_column_value = floatval( $parent_column_width );
607625
$parent_column_unit = explode( $parent_column_value, $parent_column_width );
608626

@@ -627,14 +645,16 @@ function gutenberg_render_layout_support_flag( $block_content, $block ) {
627645
* viable to use in the computation of the container query value.
628646
*/
629647
$default_gap_value = 'px' === $parent_column_unit ? 24 : 1.5;
630-
$container_query_value = $column_span_number * $parent_column_value + ( $column_span_number - 1 ) * $default_gap_value;
648+
$container_query_value = $highest_number * $parent_column_value + ( $highest_number - 1 ) * $default_gap_value;
631649
$container_query_value = $container_query_value . $parent_column_unit;
650+
// If a span is set we want to preserve it as long as possible, otherwise we just reset the value.
651+
$grid_column_value = $column_span ? '1/-1' : 'auto';
632652

633653
$child_layout_styles[] = array(
634654
'rules_group' => "@container (max-width: $container_query_value )",
635655
'selector' => ".$container_content_class",
636656
'declarations' => array(
637-
'grid-column' => '1/-1',
657+
'grid-column' => $grid_column_value,
638658
),
639659
);
640660
}

packages/block-editor/src/components/child-layout-control/index.js

Lines changed: 147 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ import {
77
__experimentalUnitControl as UnitControl,
88
__experimentalInputControl as InputControl,
99
__experimentalHStack as HStack,
10+
__experimentalVStack as VStack,
11+
__experimentalToolsPanelItem as ToolsPanelItem,
12+
Flex,
13+
FlexItem,
1014
} from '@wordpress/components';
1115
import { __ } from '@wordpress/i18n';
1216
import { useEffect } from '@wordpress/element';
@@ -28,25 +32,62 @@ function helpText( selfStretch, parentLayout ) {
2832
/**
2933
* Form to edit the child layout value.
3034
*
31-
* @param {Object} props Props.
32-
* @param {Object} props.value The child layout value.
33-
* @param {Function} props.onChange Function to update the child layout value.
34-
* @param {Object} props.parentLayout The parent layout value.
35+
* @param {Object} props Props.
36+
* @param {Object} props.value The child layout value.
37+
* @param {Function} props.onChange Function to update the child layout value.
38+
* @param {Object} props.parentLayout The parent layout value.
3539
*
40+
* @param {boolean} props.isShownByDefault
41+
* @param {string} props.panelId
3642
* @return {Element} child layout edit element.
3743
*/
3844
export default function ChildLayoutControl( {
3945
value: childLayout = {},
4046
onChange,
4147
parentLayout,
48+
isShownByDefault,
49+
panelId,
4250
} ) {
43-
const { selfStretch, flexSize, columnSpan, rowSpan } = childLayout;
51+
const {
52+
selfStretch,
53+
flexSize,
54+
columnStart,
55+
rowStart,
56+
columnSpan,
57+
rowSpan,
58+
} = childLayout;
4459
const {
4560
type: parentType,
4661
default: { type: defaultParentType = 'default' } = {},
62+
orientation = 'horizontal',
4763
} = parentLayout ?? {};
4864
const parentLayoutType = parentType || defaultParentType;
4965

66+
const hasFlexValue = () => !! selfStretch;
67+
const flexResetLabel =
68+
orientation === 'horizontal' ? __( 'Width' ) : __( 'Height' );
69+
const resetFlex = () => {
70+
onChange( {
71+
selfStretch: undefined,
72+
flexSize: undefined,
73+
} );
74+
};
75+
76+
const hasStartValue = () => !! columnStart || !! rowStart;
77+
const hasSpanValue = () => !! columnSpan || !! rowSpan;
78+
const resetGridStarts = () => {
79+
onChange( {
80+
columnStart: undefined,
81+
rowStart: undefined,
82+
} );
83+
};
84+
const resetGridSpans = () => {
85+
onChange( {
86+
columnSpan: undefined,
87+
rowSpan: undefined,
88+
} );
89+
};
90+
5091
useEffect( () => {
5192
if ( selfStretch === 'fixed' && ! flexSize ) {
5293
onChange( {
@@ -59,7 +100,15 @@ export default function ChildLayoutControl( {
59100
return (
60101
<>
61102
{ parentLayoutType === 'flex' && (
62-
<>
103+
<VStack
104+
as={ ToolsPanelItem }
105+
spacing={ 2 }
106+
hasValue={ hasFlexValue }
107+
label={ flexResetLabel }
108+
onDeselect={ resetFlex }
109+
isShownByDefault={ isShownByDefault }
110+
panelId={ panelId }
111+
>
63112
<ToggleGroupControl
64113
__nextHasNoMarginBottom
65114
size={ '__unstable-large' }
@@ -104,37 +153,100 @@ export default function ChildLayoutControl( {
104153
value={ flexSize }
105154
/>
106155
) }
107-
</>
156+
</VStack>
108157
) }
109158
{ parentLayoutType === 'grid' && (
110-
<HStack>
111-
<InputControl
112-
size={ '__unstable-large' }
113-
label={ __( 'Column Span' ) }
114-
type="number"
115-
onChange={ ( value ) => {
116-
onChange( {
117-
rowSpan,
118-
columnSpan: value,
119-
} );
120-
} }
121-
value={ columnSpan }
122-
min={ 1 }
123-
/>
124-
<InputControl
125-
size={ '__unstable-large' }
126-
label={ __( 'Row Span' ) }
127-
type="number"
128-
onChange={ ( value ) => {
129-
onChange( {
130-
columnSpan,
131-
rowSpan: value,
132-
} );
133-
} }
134-
value={ rowSpan }
135-
min={ 1 }
136-
/>
137-
</HStack>
159+
<>
160+
<HStack
161+
as={ ToolsPanelItem }
162+
hasValue={ hasSpanValue }
163+
label={ __( 'Grid span' ) }
164+
onDeselect={ resetGridSpans }
165+
isShownByDefault={ isShownByDefault }
166+
panelId={ panelId }
167+
>
168+
<InputControl
169+
size={ '__unstable-large' }
170+
label={ __( 'Column span' ) }
171+
type="number"
172+
onChange={ ( value ) => {
173+
onChange( {
174+
columnStart,
175+
rowStart,
176+
rowSpan,
177+
columnSpan: value,
178+
} );
179+
} }
180+
value={ columnSpan }
181+
min={ 1 }
182+
/>
183+
<InputControl
184+
size={ '__unstable-large' }
185+
label={ __( 'Row span' ) }
186+
type="number"
187+
onChange={ ( value ) => {
188+
onChange( {
189+
columnStart,
190+
rowStart,
191+
columnSpan,
192+
rowSpan: value,
193+
} );
194+
} }
195+
value={ rowSpan }
196+
min={ 1 }
197+
/>
198+
</HStack>
199+
{ window.__experimentalEnableGridInteractivity && (
200+
// Use Flex with an explicit width on the FlexItem instead of HStack to
201+
// work around an issue in webkit where inputs with a max attribute are
202+
// sized incorrectly.
203+
<Flex
204+
as={ ToolsPanelItem }
205+
hasValue={ hasStartValue }
206+
label={ __( 'Grid placement' ) }
207+
onDeselect={ resetGridStarts }
208+
isShownByDefault={ false }
209+
panelId={ panelId }
210+
>
211+
<FlexItem style={ { width: '50%' } }>
212+
<InputControl
213+
size={ '__unstable-large' }
214+
label={ __( 'Column' ) }
215+
type="number"
216+
onChange={ ( value ) => {
217+
onChange( {
218+
columnStart: value,
219+
rowStart,
220+
columnSpan,
221+
rowSpan,
222+
} );
223+
} }
224+
value={ columnStart }
225+
min={ 1 }
226+
max={ parentLayout?.columnCount }
227+
/>
228+
</FlexItem>
229+
<FlexItem style={ { width: '50%' } }>
230+
<InputControl
231+
size={ '__unstable-large' }
232+
label={ __( 'Row' ) }
233+
type="number"
234+
onChange={ ( value ) => {
235+
onChange( {
236+
columnStart,
237+
rowStart: value,
238+
columnSpan,
239+
rowSpan,
240+
} );
241+
} }
242+
value={ rowStart }
243+
min={ 1 }
244+
max={ parentLayout?.columnCount }
245+
/>
246+
</FlexItem>
247+
</Flex>
248+
) }
249+
</>
138250
) }
139251
</>
140252
);

packages/block-editor/src/components/global-styles/dimensions-panel.js

Lines changed: 9 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import {
1212
__experimentalToolsPanelItem as ToolsPanelItem,
1313
__experimentalBoxControl as BoxControl,
1414
__experimentalHStack as HStack,
15-
__experimentalVStack as VStack,
1615
__experimentalUnitControl as UnitControl,
1716
__experimentalUseCustomUnits as useCustomUnits,
1817
__experimentalView as View,
@@ -396,16 +395,7 @@ export default function DimensionsPanel( {
396395
// Child Layout
397396
const showChildLayoutControl = useHasChildLayout( settings );
398397
const childLayout = inheritedValue?.layout;
399-
const { orientation = 'horizontal' } = settings?.parentLayout ?? {};
400-
const {
401-
type: parentType,
402-
default: { type: defaultParentType = 'default' } = {},
403-
} = settings?.parentLayout ?? {};
404-
const parentLayoutType = parentType || defaultParentType;
405-
const flexResetLabel =
406-
orientation === 'horizontal' ? __( 'Width' ) : __( 'Height' );
407-
const childLayoutResetLabel =
408-
parentLayoutType === 'flex' ? flexResetLabel : __( 'Grid spans' );
398+
409399
const setChildLayout = ( newChildLayout ) => {
410400
onChange( {
411401
...value,
@@ -414,15 +404,6 @@ export default function DimensionsPanel( {
414404
},
415405
} );
416406
};
417-
const resetChildLayoutValue = () => {
418-
setChildLayout( {
419-
selfStretch: undefined,
420-
flexSize: undefined,
421-
columnSpan: undefined,
422-
rowSpan: undefined,
423-
} );
424-
};
425-
const hasChildLayoutValue = () => !! value?.layout;
426407

427408
const resetAllFilter = useCallback( ( previousValue ) => {
428409
return {
@@ -433,6 +414,8 @@ export default function DimensionsPanel( {
433414
wideSize: undefined,
434415
selfStretch: undefined,
435416
flexSize: undefined,
417+
columnStart: undefined,
418+
rowStart: undefined,
436419
columnSpan: undefined,
437420
rowSpan: undefined,
438421
} ),
@@ -650,24 +633,16 @@ export default function DimensionsPanel( {
650633
</ToolsPanelItem>
651634
) }
652635
{ showChildLayoutControl && (
653-
<VStack
654-
as={ ToolsPanelItem }
655-
spacing={ 2 }
656-
hasValue={ hasChildLayoutValue }
657-
label={ childLayoutResetLabel }
658-
onDeselect={ resetChildLayoutValue }
636+
<ChildLayoutControl
637+
value={ childLayout }
638+
onChange={ setChildLayout }
639+
parentLayout={ settings?.parentLayout }
640+
panelId={ panelId }
659641
isShownByDefault={
660642
defaultControls.childLayout ??
661643
DEFAULT_CONTROLS.childLayout
662644
}
663-
panelId={ panelId }
664-
>
665-
<ChildLayoutControl
666-
value={ childLayout }
667-
onChange={ setChildLayout }
668-
parentLayout={ settings?.parentLayout }
669-
/>
670-
</VStack>
645+
/>
671646
) }
672647
{ showMinHeightControl && (
673648
<ToolsPanelItem

0 commit comments

Comments
 (0)