@wordpress/block-editor 15.9.0 → 15.9.1-next.6deb34194.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. package/README.md +12 -0
  2. package/build/components/block-alignment-matrix-control/index.js +1 -8
  3. package/build/components/block-alignment-matrix-control/index.js.map +2 -2
  4. package/build/components/block-bindings/attribute-control.js +172 -0
  5. package/build/components/block-bindings/attribute-control.js.map +7 -0
  6. package/build/components/block-bindings/index.js +47 -0
  7. package/build/components/block-bindings/index.js.map +7 -0
  8. package/build/components/block-bindings/source-fields-list.js +135 -0
  9. package/build/components/block-bindings/source-fields-list.js.map +7 -0
  10. package/build/components/block-bindings/use-block-bindings-utils.js +66 -0
  11. package/build/components/block-bindings/use-block-bindings-utils.js.map +7 -0
  12. package/build/components/block-edit/edit.js +1 -3
  13. package/build/components/block-edit/edit.js.map +2 -2
  14. package/build/components/block-styles/preview-panel.js +3 -5
  15. package/build/components/block-styles/preview-panel.js.map +2 -2
  16. package/build/components/block-styles/use-styles-for-block.js +2 -2
  17. package/build/components/block-styles/use-styles-for-block.js.map +2 -2
  18. package/build/components/block-toolbar/index.js +1 -8
  19. package/build/components/block-toolbar/index.js.map +3 -3
  20. package/build/components/content-only-controls/index.js +2 -25
  21. package/build/components/content-only-controls/index.js.map +2 -2
  22. package/build/components/content-only-controls/link/index.js +3 -3
  23. package/build/components/content-only-controls/link/index.js.map +2 -2
  24. package/build/components/content-only-controls/media/index.js +3 -3
  25. package/build/components/content-only-controls/media/index.js.map +2 -2
  26. package/build/components/content-only-controls/rich-text/index.js +3 -2
  27. package/build/components/content-only-controls/rich-text/index.js.map +2 -2
  28. package/build/components/dimensions-tool/width-height-tool.js +4 -16
  29. package/build/components/dimensions-tool/width-height-tool.js.map +3 -3
  30. package/build/components/image-editor/cropper.js +3 -34
  31. package/build/components/image-editor/cropper.js.map +3 -3
  32. package/build/components/image-editor/index.js +9 -3
  33. package/build/components/image-editor/index.js.map +2 -2
  34. package/build/components/image-editor/use-transform-image.js +62 -32
  35. package/build/components/image-editor/use-transform-image.js.map +2 -2
  36. package/build/components/image-editor/zoom-dropdown.js +2 -2
  37. package/build/components/image-editor/zoom-dropdown.js.map +2 -2
  38. package/build/components/index.js +10 -3
  39. package/build/components/index.js.map +2 -2
  40. package/build/components/inserter-draggable-blocks/index.js +8 -4
  41. package/build/components/inserter-draggable-blocks/index.js.map +2 -2
  42. package/build/components/inspector-controls-tabs/content-tab.js +3 -2
  43. package/build/components/inspector-controls-tabs/content-tab.js.map +2 -2
  44. package/build/components/tool-selector/index.js +46 -0
  45. package/build/components/tool-selector/index.js.map +7 -0
  46. package/build/hooks/block-bindings.js +22 -260
  47. package/build/hooks/block-bindings.js.map +3 -3
  48. package/build/layouts/grid.js +23 -28
  49. package/build/layouts/grid.js.map +2 -2
  50. package/build/utils/block-bindings.js +2 -44
  51. package/build/utils/block-bindings.js.map +3 -3
  52. package/build/utils/index.js +2 -5
  53. package/build/utils/index.js.map +2 -2
  54. package/build-module/components/block-alignment-matrix-control/index.js +1 -8
  55. package/build-module/components/block-alignment-matrix-control/index.js.map +2 -2
  56. package/build-module/components/block-bindings/attribute-control.js +150 -0
  57. package/build-module/components/block-bindings/attribute-control.js.map +7 -0
  58. package/build-module/components/block-bindings/index.js +10 -0
  59. package/build-module/components/block-bindings/index.js.map +7 -0
  60. package/build-module/components/block-bindings/source-fields-list.js +104 -0
  61. package/build-module/components/block-bindings/source-fields-list.js.map +7 -0
  62. package/build-module/components/block-bindings/use-block-bindings-utils.js +45 -0
  63. package/build-module/components/block-bindings/use-block-bindings-utils.js.map +7 -0
  64. package/build-module/components/block-edit/edit.js +1 -3
  65. package/build-module/components/block-edit/edit.js.map +2 -2
  66. package/build-module/components/block-styles/preview-panel.js +3 -5
  67. package/build-module/components/block-styles/preview-panel.js.map +2 -2
  68. package/build-module/components/block-styles/use-styles-for-block.js +2 -2
  69. package/build-module/components/block-styles/use-styles-for-block.js.map +2 -2
  70. package/build-module/components/block-toolbar/index.js +1 -8
  71. package/build-module/components/block-toolbar/index.js.map +2 -2
  72. package/build-module/components/content-only-controls/index.js +2 -25
  73. package/build-module/components/content-only-controls/index.js.map +2 -2
  74. package/build-module/components/content-only-controls/link/index.js +3 -3
  75. package/build-module/components/content-only-controls/link/index.js.map +2 -2
  76. package/build-module/components/content-only-controls/media/index.js +3 -3
  77. package/build-module/components/content-only-controls/media/index.js.map +2 -2
  78. package/build-module/components/content-only-controls/rich-text/index.js +3 -2
  79. package/build-module/components/content-only-controls/rich-text/index.js.map +2 -2
  80. package/build-module/components/dimensions-tool/width-height-tool.js +4 -6
  81. package/build-module/components/dimensions-tool/width-height-tool.js.map +2 -2
  82. package/build-module/components/image-editor/cropper.js +3 -34
  83. package/build-module/components/image-editor/cropper.js.map +2 -2
  84. package/build-module/components/image-editor/index.js +9 -3
  85. package/build-module/components/image-editor/index.js.map +2 -2
  86. package/build-module/components/image-editor/use-transform-image.js +63 -33
  87. package/build-module/components/image-editor/use-transform-image.js.map +2 -2
  88. package/build-module/components/image-editor/zoom-dropdown.js +2 -2
  89. package/build-module/components/image-editor/zoom-dropdown.js.map +2 -2
  90. package/build-module/components/index.js +74 -66
  91. package/build-module/components/index.js.map +2 -2
  92. package/build-module/components/inserter-draggable-blocks/index.js +8 -4
  93. package/build-module/components/inserter-draggable-blocks/index.js.map +2 -2
  94. package/build-module/components/inspector-controls-tabs/content-tab.js +3 -2
  95. package/build-module/components/inspector-controls-tabs/content-tab.js.map +2 -2
  96. package/build-module/components/tool-selector/index.js +15 -0
  97. package/build-module/components/tool-selector/index.js.map +7 -0
  98. package/build-module/hooks/block-bindings.js +27 -270
  99. package/build-module/hooks/block-bindings.js.map +2 -2
  100. package/build-module/layouts/grid.js +23 -28
  101. package/build-module/layouts/grid.js.map +2 -2
  102. package/build-module/utils/block-bindings.js +1 -42
  103. package/build-module/utils/block-bindings.js.map +2 -2
  104. package/build-module/utils/index.js +1 -3
  105. package/build-module/utils/index.js.map +2 -2
  106. package/build-style/style-rtl.css +6 -6
  107. package/build-style/style.css +6 -6
  108. package/package.json +39 -40
  109. package/src/components/block-alignment-matrix-control/index.js +1 -5
  110. package/src/components/block-bindings/attribute-control.js +174 -0
  111. package/src/components/block-bindings/index.js +6 -0
  112. package/src/components/block-bindings/source-fields-list.js +130 -0
  113. package/src/components/block-bindings/use-block-bindings-utils.js +156 -0
  114. package/src/components/block-edit/edit.js +1 -3
  115. package/src/components/block-styles/preview-panel.js +3 -5
  116. package/src/components/block-styles/use-styles-for-block.js +2 -2
  117. package/src/components/block-toolbar/index.js +1 -6
  118. package/src/components/block-toolbar/style.scss +6 -6
  119. package/src/components/content-only-controls/index.js +2 -27
  120. package/src/components/content-only-controls/link/index.js +3 -3
  121. package/src/components/content-only-controls/media/index.js +3 -3
  122. package/src/components/content-only-controls/rich-text/index.js +3 -2
  123. package/src/components/dimensions-tool/width-height-tool.js +6 -13
  124. package/src/components/image-editor/cropper.js +3 -32
  125. package/src/components/image-editor/index.js +34 -29
  126. package/src/components/image-editor/use-transform-image.js +80 -34
  127. package/src/components/image-editor/zoom-dropdown.js +2 -2
  128. package/src/components/index.js +9 -1
  129. package/src/components/inserter/style.scss +1 -1
  130. package/src/components/inserter-draggable-blocks/index.js +19 -8
  131. package/src/components/inspector-controls-tabs/content-tab.js +6 -2
  132. package/src/components/tool-selector/index.js +19 -0
  133. package/src/hooks/block-bindings.js +27 -347
  134. package/src/layouts/grid.js +40 -72
  135. package/src/layouts/test/grid.js +14 -0
  136. package/src/utils/block-bindings.js +0 -157
  137. package/src/utils/index.js +0 -1
  138. package/tsconfig.json +1 -0
  139. package/build/components/block-toolbar/block-name-context.js +0 -30
  140. package/build/components/block-toolbar/block-name-context.js.map +0 -7
  141. package/build-module/components/block-toolbar/block-name-context.js +0 -9
  142. package/build-module/components/block-toolbar/block-name-context.js.map +0 -7
  143. package/src/components/block-toolbar/block-name-context.js +0 -9
  144. /package/src/{utils → components/block-bindings}/test/use-block-bindings-utils.js +0 -0
@@ -1,25 +1,12 @@
1
- /**
2
- * External dependencies
3
- */
4
- import fastDeepEqual from 'fast-deep-equal/es6';
5
-
6
1
  /**
7
2
  * WordPress dependencies
8
3
  */
9
4
  import { __ } from '@wordpress/i18n';
10
- import {
11
- getBlockBindingsSource,
12
- getBlockType,
13
- store as blockStore,
14
- } from '@wordpress/blocks';
5
+ import { store as blocksStore } from '@wordpress/blocks';
15
6
  import {
16
7
  __experimentalItemGroup as ItemGroup,
17
- __experimentalItem as Item,
18
8
  __experimentalText as Text,
19
9
  __experimentalToolsPanel as ToolsPanel,
20
- __experimentalToolsPanelItem as ToolsPanelItem,
21
- __experimentalVStack as VStack,
22
- privateApis as componentsPrivateApis,
23
10
  } from '@wordpress/components';
24
11
  import { useSelect } from '@wordpress/data';
25
12
  import { useContext } from '@wordpress/element';
@@ -28,29 +15,15 @@ import { useViewportMatch } from '@wordpress/compose';
28
15
  /**
29
16
  * Internal dependencies
30
17
  */
31
- import { useBlockBindingsUtils } from '../utils/block-bindings';
18
+ import {
19
+ BlockBindingsAttributeControl,
20
+ useBlockBindingsUtils,
21
+ } from '../components/block-bindings';
32
22
  import { unlock } from '../lock-unlock';
33
23
  import InspectorControls from '../components/inspector-controls';
34
24
  import BlockContext from '../components/block-context';
35
- import { useBlockEditContext } from '../components/block-edit';
36
25
  import { store as blockEditorStore } from '../store';
37
26
 
38
- const { Menu } = unlock( componentsPrivateApis );
39
-
40
- /**
41
- * Get the normalized attribute type for block bindings.
42
- * Converts 'rich-text' to 'string' since rich-text is stored as string.
43
- *
44
- * @param {string} blockName The block name.
45
- * @param {string} attribute The attribute name.
46
- * @return {string} The normalized attribute type.
47
- */
48
- const getAttributeType = ( blockName, attribute ) => {
49
- const _attributeType =
50
- getBlockType( blockName ).attributes?.[ attribute ]?.type;
51
- return _attributeType === 'rich-text' ? 'string' : _attributeType;
52
- };
53
-
54
27
  const useToolsPanelDropdownMenuProps = () => {
55
28
  const isMobile = useViewportMatch( 'medium', '<' );
56
29
  return ! isMobile
@@ -64,295 +37,35 @@ const useToolsPanelDropdownMenuProps = () => {
64
37
  : {};
65
38
  };
66
39
 
67
- function BlockBindingsPanelMenuContent( { attribute, binding, sources } ) {
68
- const { clientId } = useBlockEditContext();
69
- const { updateBlockBindings } = useBlockBindingsUtils();
70
- const isMobile = useViewportMatch( 'medium', '<' );
71
- const blockContext = useContext( BlockContext );
72
- const { attributeType, select } = useSelect(
73
- ( _select ) => {
74
- const { name: blockName } =
75
- _select( blockEditorStore ).getBlock( clientId );
76
- return {
77
- attributeType: getAttributeType( blockName, attribute ),
78
- select: _select,
79
- };
80
- },
81
- [ clientId, attribute ]
82
- );
83
- return (
84
- <Menu placement={ isMobile ? 'bottom-start' : 'left-start' }>
85
- { Object.entries( sources ).map( ( [ sourceKey, data ] ) => {
86
- // Only show sources that have compatible data for this specific attribute.
87
- const sourceDataItems = data.filter(
88
- ( item ) => item.type === attributeType
89
- );
90
-
91
- const noItemsAvailable =
92
- ! sourceDataItems || sourceDataItems.length === 0;
93
-
94
- if ( noItemsAvailable ) {
95
- return null;
96
- }
97
-
98
- const source = getBlockBindingsSource( sourceKey );
99
-
100
- return (
101
- <Menu
102
- key={ sourceKey }
103
- placement={ isMobile ? 'bottom-start' : 'left-start' }
104
- >
105
- <Menu.SubmenuTriggerItem>
106
- <Menu.ItemLabel>{ source.label }</Menu.ItemLabel>
107
- </Menu.SubmenuTriggerItem>
108
- <Menu.Popover gutter={ 8 }>
109
- <Menu.Group>
110
- { sourceDataItems.map( ( item ) => {
111
- const itemBindings = {
112
- source: sourceKey,
113
- args: item.args || {
114
- key: item.key,
115
- },
116
- };
117
- let values = {};
118
- try {
119
- values = source.getValues( {
120
- select,
121
- context: blockContext,
122
- bindings: {
123
- [ attribute ]: itemBindings,
124
- },
125
- } );
126
- } catch ( e ) {}
127
-
128
- return (
129
- <Menu.CheckboxItem
130
- key={
131
- sourceKey +
132
- JSON.stringify(
133
- item.args
134
- ) || item.key
135
- }
136
- onChange={ () => {
137
- const isCurrentlySelected =
138
- fastDeepEqual(
139
- binding?.args,
140
- item.args
141
- ) ??
142
- // Deprecate key dependency in 7.0.
143
- item.key ===
144
- binding?.args?.key;
145
-
146
- if ( isCurrentlySelected ) {
147
- // Unset if the same item is selected again.
148
- updateBlockBindings( {
149
- [ attribute ]:
150
- undefined,
151
- } );
152
- } else {
153
- updateBlockBindings( {
154
- [ attribute ]:
155
- itemBindings,
156
- } );
157
- }
158
- } }
159
- name={ attribute + '-binding' }
160
- value={ values[ attribute ] }
161
- checked={
162
- fastDeepEqual(
163
- binding?.args,
164
- item.args
165
- ) ??
166
- // Deprecate key dependency in 7.0.
167
- item.key === binding?.args?.key
168
- }
169
- >
170
- <Menu.ItemLabel>
171
- { item.label }
172
- </Menu.ItemLabel>
173
- <Menu.ItemHelpText>
174
- { values[ attribute ] }
175
- </Menu.ItemHelpText>
176
- </Menu.CheckboxItem>
177
- );
178
- } ) }
179
- </Menu.Group>
180
- </Menu.Popover>
181
- </Menu>
182
- );
183
- } ) }
184
- </Menu>
185
- );
186
- }
187
-
188
- function BlockBindingsAttribute( { attribute, binding, sources, blockName } ) {
189
- const { source: sourceName, args } = binding || {};
190
- const data = sources?.[ sourceName ];
191
- const source = getBlockBindingsSource( sourceName );
192
-
193
- let displayText;
194
- let isValid = true;
195
- const isNotBound = binding === undefined;
196
-
197
- if ( isNotBound ) {
198
- // Check if there are any compatible sources for this attribute type.
199
- const attributeType = getAttributeType( blockName, attribute );
200
-
201
- const hasCompatibleSources = Object.values( sources ).some( ( items ) =>
202
- items.some( ( item ) => item.type === attributeType )
203
- );
204
-
205
- if ( ! hasCompatibleSources ) {
206
- displayText = __( 'No sources available' );
207
- } else {
208
- displayText = __( 'Not connected' );
209
- }
210
- isValid = true;
211
- } else if ( ! source ) {
212
- // If there's a binding but the source is not found, it's invalid.
213
- isValid = false;
214
- displayText = __( 'Source not registered' );
215
- } else {
216
- displayText =
217
- data?.find( ( item ) => fastDeepEqual( item.args, args ) )?.label ||
218
- source?.label ||
219
- sourceName;
220
- }
221
-
222
- return (
223
- <VStack className="block-editor-bindings__item" spacing={ 0 }>
224
- <Text truncate>{ attribute }</Text>
225
- <Text
226
- truncate
227
- variant={ isValid ? 'muted' : undefined }
228
- isDestructive={ ! isValid }
229
- >
230
- { displayText }
231
- </Text>
232
- </VStack>
233
- );
234
- }
235
-
236
- function ReadOnlyBlockBindingsPanelItem( {
237
- attribute,
238
- binding,
239
- sources,
240
- blockName,
241
- } ) {
242
- const isMobile = useViewportMatch( 'medium', '<' );
243
-
244
- return (
245
- <ToolsPanelItem hasValue={ () => !! binding } label={ attribute }>
246
- <Menu placement={ isMobile ? 'bottom-start' : 'left-start' }>
247
- <Menu.TriggerButton render={ <Item /> } disabled>
248
- <BlockBindingsAttribute
249
- attribute={ attribute }
250
- binding={ binding }
251
- sources={ sources }
252
- blockName={ blockName }
253
- />
254
- </Menu.TriggerButton>
255
- </Menu>
256
- </ToolsPanelItem>
257
- );
258
- }
259
-
260
- function EditableBlockBindingsPanelItem( {
261
- attribute,
262
- binding,
263
- sources,
264
- blockName,
265
- } ) {
266
- const { updateBlockBindings } = useBlockBindingsUtils();
267
- const isMobile = useViewportMatch( 'medium', '<' );
268
-
269
- return (
270
- <ToolsPanelItem
271
- hasValue={ () => !! binding }
272
- label={ attribute }
273
- onDeselect={ () => {
274
- updateBlockBindings( {
275
- [ attribute ]: undefined,
276
- } );
277
- } }
278
- >
279
- <Menu placement={ isMobile ? 'bottom-start' : 'left-start' }>
280
- <Menu.TriggerButton render={ <Item /> }>
281
- <BlockBindingsAttribute
282
- attribute={ attribute }
283
- binding={ binding }
284
- sources={ sources }
285
- blockName={ blockName }
286
- />
287
- </Menu.TriggerButton>
288
- <Menu.Popover gutter={ isMobile ? 8 : 36 }>
289
- <BlockBindingsPanelMenuContent
290
- attribute={ attribute }
291
- binding={ binding }
292
- sources={ sources }
293
- />
294
- </Menu.Popover>
295
- </Menu>
296
- </ToolsPanelItem>
297
- );
298
- }
299
-
300
40
  export const BlockBindingsPanel = ( { name: blockName, metadata } ) => {
301
41
  const blockContext = useContext( BlockContext );
302
42
  const { removeAllBlockBindings } = useBlockBindingsUtils();
303
43
  const dropdownMenuProps = useToolsPanelDropdownMenuProps();
304
44
 
305
- // Use useSelect to ensure sources are updated whenever there are updates in block context
306
- // or when underlying data changes.
307
- const { canUpdateBlockBindings, bindableAttributes } = useSelect(
45
+ const { bindableAttributes, hasCompatibleFields } = useSelect(
308
46
  ( select ) => {
309
47
  const { __experimentalBlockBindingsSupportedAttributes } =
310
48
  select( blockEditorStore ).getSettings();
49
+ const {
50
+ getAllBlockBindingsSources,
51
+ getBlockBindingsSourceFieldsList,
52
+ } = unlock( select( blocksStore ) );
311
53
 
312
54
  return {
313
- canUpdateBlockBindings:
314
- select( blockEditorStore ).getSettings()
315
- .canUpdateBlockBindings,
316
55
  bindableAttributes:
317
56
  __experimentalBlockBindingsSupportedAttributes?.[
318
57
  blockName
319
58
  ],
59
+ hasCompatibleFields: Object.values(
60
+ getAllBlockBindingsSources()
61
+ ).some(
62
+ ( source ) =>
63
+ getBlockBindingsSourceFieldsList( source, blockContext )
64
+ ?.length > 0
65
+ ),
320
66
  };
321
67
  },
322
- [ blockName ]
323
- );
324
-
325
- const sources = useSelect(
326
- ( select ) => {
327
- const { getAllBlockBindingsSources } = unlock(
328
- select( blockStore )
329
- );
330
- const data = {};
331
- Object.entries( getAllBlockBindingsSources() ).forEach(
332
- ( [ sourceName, source ] ) => {
333
- if ( ! source.getFieldsList ) {
334
- return;
335
- }
336
-
337
- const context = {};
338
- if ( source.usesContext?.length ) {
339
- for ( const key of source.usesContext ) {
340
- context[ key ] = blockContext[ key ];
341
- }
342
- }
343
-
344
- const items = source.getFieldsList( {
345
- select,
346
- context,
347
- } );
348
- if ( items?.length ) {
349
- data[ sourceName ] = items;
350
- }
351
- }
352
- );
353
- return data;
354
- },
355
- [ blockContext ]
68
+ [ blockName, blockContext ]
356
69
  );
357
70
 
358
71
  // Return early if there are no bindable attributes.
@@ -362,12 +75,7 @@ export const BlockBindingsPanel = ( { name: blockName, metadata } ) => {
362
75
 
363
76
  const { bindings } = metadata || {};
364
77
 
365
- const hasCompatibleData = Object.keys( sources ).length > 0;
366
-
367
- // Lock the UI when the user can't update bindings or there are no fields to connect to.
368
- const readOnly = ! canUpdateBlockBindings || ! hasCompatibleData;
369
-
370
- if ( bindings === undefined && ! hasCompatibleData ) {
78
+ if ( bindings === undefined && ! hasCompatibleFields ) {
371
79
  return null;
372
80
  }
373
81
 
@@ -382,42 +90,14 @@ export const BlockBindingsPanel = ( { name: blockName, metadata } ) => {
382
90
  className="block-editor-bindings__panel"
383
91
  >
384
92
  <ItemGroup isBordered isSeparated>
385
- { bindableAttributes.map( ( attribute ) => {
386
- const binding = bindings?.[ attribute ];
387
-
388
- // Check if this specific attribute has compatible data from any source.
389
- const attributeType = getAttributeType(
390
- blockName,
391
- attribute
392
- );
393
-
394
- const hasCompatibleDataForAttribute = Object.values(
395
- sources
396
- ).some( ( data ) =>
397
- data.some( ( item ) => item.type === attributeType )
398
- );
399
-
400
- const isAttributeReadOnly =
401
- readOnly || ! hasCompatibleDataForAttribute;
402
-
403
- return isAttributeReadOnly ? (
404
- <ReadOnlyBlockBindingsPanelItem
405
- key={ attribute }
406
- attribute={ attribute }
407
- binding={ binding }
408
- sources={ sources }
409
- blockName={ blockName }
410
- />
411
- ) : (
412
- <EditableBlockBindingsPanelItem
413
- key={ attribute }
414
- attribute={ attribute }
415
- binding={ binding }
416
- sources={ sources }
417
- blockName={ blockName }
418
- />
419
- );
420
- } ) }
93
+ { bindableAttributes.map( ( attribute ) => (
94
+ <BlockBindingsAttributeControl
95
+ key={ attribute }
96
+ attribute={ attribute }
97
+ blockName={ blockName }
98
+ binding={ bindings?.[ attribute ] }
99
+ />
100
+ ) ) }
421
101
  </ItemGroup>
422
102
  { /*
423
103
  Use a div element to make the ToolsPanelHiddenInnerWrapper
@@ -72,20 +72,20 @@ export default {
72
72
  } ) {
73
73
  const { allowSizingOnChildren = false } = layoutBlockSupport;
74
74
 
75
- // In the experiment we want to also show column control in Auto mode, and
76
- // the minimum width control in Manual mode.
77
- const showColumnsControl =
78
- window.__experimentalEnableGridInteractivity ||
79
- !! layout?.columnCount;
75
+ // Always show both column and minimum width controls in Auto mode.
76
+ // Manual mode (with isManualPlacement) is only available behind the experiment flag.
77
+ const showColumnsControl = true;
80
78
  const showMinWidthControl =
81
- window.__experimentalEnableGridInteractivity ||
82
- ! layout?.columnCount;
79
+ ! layout?.isManualPlacement ||
80
+ window.__experimentalEnableGridInteractivity;
83
81
  return (
84
82
  <>
85
- <GridLayoutTypeControl
86
- layout={ layout }
87
- onChange={ onChange }
88
- />
83
+ { window.__experimentalEnableGridInteractivity && (
84
+ <GridLayoutTypeControl
85
+ layout={ layout }
86
+ onChange={ onChange }
87
+ />
88
+ ) }
89
89
  <VStack spacing={ 4 }>
90
90
  { showColumnsControl && (
91
91
  <GridLayoutColumnsAndRowsControl
@@ -243,7 +243,7 @@ function GridLayoutMinimumWidthControl( { layout, onChange } ) {
243
243
  return (
244
244
  <fieldset className="block-editor-hooks__grid-layout-minimum-width-control">
245
245
  <BaseControl.VisualLabel as="legend">
246
- { __( 'Minimum column width' ) }
246
+ { __( 'Min. column width' ) }
247
247
  </BaseControl.VisualLabel>
248
248
  <Flex gap={ 4 }>
249
249
  <FlexItem isBlock>
@@ -278,6 +278,11 @@ function GridLayoutMinimumWidthControl( { layout, onChange } ) {
278
278
  />
279
279
  </FlexItem>
280
280
  </Flex>
281
+ <p className="components-base-control__help">
282
+ { __(
283
+ 'Columns will wrap to fewer per row when they can no longer maintain the minimum width.'
284
+ ) }
285
+ </p>
281
286
  </fieldset>
282
287
  );
283
288
  }
@@ -288,10 +293,8 @@ function GridLayoutColumnsAndRowsControl( {
288
293
  onChange,
289
294
  allowSizingOnChildren,
290
295
  } ) {
291
- // If the grid interactivity experiment is enabled, allow unsetting the column count.
292
- const defaultColumnCount = window.__experimentalEnableGridInteractivity
293
- ? undefined
294
- : 3;
296
+ // Allow unsetting the column count in Auto mode.
297
+ const defaultColumnCount = undefined;
295
298
  const {
296
299
  columnCount = defaultColumnCount,
297
300
  rowCount,
@@ -301,10 +304,9 @@ function GridLayoutColumnsAndRowsControl( {
301
304
  return (
302
305
  <>
303
306
  <fieldset className="block-editor-hooks__grid-layout-columns-and-rows-controls">
304
- { ( ! window.__experimentalEnableGridInteractivity ||
305
- ! isManualPlacement ) && (
307
+ { ! isManualPlacement && (
306
308
  <BaseControl.VisualLabel as="legend">
307
- { __( 'Columns' ) }
309
+ { __( 'Max. columns' ) }
308
310
  </BaseControl.VisualLabel>
309
311
  ) }
310
312
  <Flex gap={ 4 }>
@@ -312,46 +314,28 @@ function GridLayoutColumnsAndRowsControl( {
312
314
  <NumberControl
313
315
  size="__unstable-large"
314
316
  onChange={ ( value ) => {
315
- if (
316
- window.__experimentalEnableGridInteractivity
317
- ) {
318
- // Allow unsetting the column count when in auto mode.
319
- const defaultNewColumnCount =
320
- isManualPlacement ? 1 : undefined;
321
- const newColumnCount =
322
- value === '' || value === '0'
323
- ? defaultNewColumnCount
324
- : parseInt( value, 10 );
325
- onChange( {
326
- ...layout,
327
- columnCount: newColumnCount,
328
- } );
329
- } else {
330
- // Don't allow unsetting the column count.
331
- const newColumnCount =
332
- value === '' || value === '0'
333
- ? 1
334
- : parseInt( value, 10 );
335
- onChange( {
336
- ...layout,
337
- columnCount: newColumnCount,
338
- } );
339
- }
317
+ // Allow unsetting the column count when in auto mode.
318
+ const defaultNewColumnCount = isManualPlacement
319
+ ? 1
320
+ : undefined;
321
+ const newColumnCount =
322
+ value === '' || value === '0'
323
+ ? defaultNewColumnCount
324
+ : parseInt( value, 10 );
325
+ onChange( {
326
+ ...layout,
327
+ columnCount: newColumnCount,
328
+ } );
340
329
  } }
341
330
  value={ columnCount }
342
331
  min={ 1 }
343
332
  label={ __( 'Columns' ) }
344
- hideLabelFromVision={
345
- ! window.__experimentalEnableGridInteractivity ||
346
- ! isManualPlacement
347
- }
333
+ hideLabelFromVision={ ! isManualPlacement }
348
334
  />
349
335
  </FlexItem>
350
336
 
351
337
  <FlexItem isBlock>
352
- { window.__experimentalEnableGridInteractivity &&
353
- allowSizingOnChildren &&
354
- isManualPlacement ? (
338
+ { allowSizingOnChildren && isManualPlacement ? (
355
339
  <NumberControl
356
340
  size="__unstable-large"
357
341
  onChange={ ( value ) => {
@@ -414,11 +398,7 @@ function GridLayoutTypeControl( { layout, onChange } ) {
414
398
  minimumColumnWidth || '12rem'
415
399
  );
416
400
 
417
- const gridPlacement =
418
- isManualPlacement ||
419
- ( !! columnCount && ! window.__experimentalEnableGridInteractivity )
420
- ? 'manual'
421
- : 'auto';
401
+ const gridPlacement = isManualPlacement ? 'manual' : 'auto';
422
402
 
423
403
  const onChangeType = ( value ) => {
424
404
  if ( value === 'manual' ) {
@@ -429,17 +409,9 @@ function GridLayoutTypeControl( { layout, onChange } ) {
429
409
  }
430
410
  onChange( {
431
411
  ...layout,
432
- columnCount: value === 'manual' ? tempColumnCount : null,
433
- rowCount:
434
- value === 'manual' &&
435
- window.__experimentalEnableGridInteractivity
436
- ? tempRowCount
437
- : undefined,
438
- isManualPlacement:
439
- value === 'manual' &&
440
- window.__experimentalEnableGridInteractivity
441
- ? true
442
- : undefined,
412
+ columnCount: value === 'manual' ? tempColumnCount : tempColumnCount,
413
+ rowCount: value === 'manual' ? tempRowCount : undefined,
414
+ isManualPlacement: value === 'manual' ? true : undefined,
443
415
  minimumColumnWidth:
444
416
  value === 'auto' ? tempMinimumColumnWidth : null,
445
417
  } );
@@ -462,11 +434,7 @@ function GridLayoutTypeControl( { layout, onChange } ) {
462
434
  value={ gridPlacement }
463
435
  onChange={ onChangeType }
464
436
  isBlock
465
- help={
466
- window.__experimentalEnableGridInteractivity
467
- ? helpText
468
- : undefined
469
- }
437
+ help={ helpText }
470
438
  >
471
439
  <ToggleGroupControlOption
472
440
  key="auto"
@@ -30,6 +30,20 @@ describe( 'getLayoutStyle', () => {
30
30
  layoutDefinitions: undefined,
31
31
  } );
32
32
 
33
+ expect( result ).toBe( expected );
34
+ } );
35
+ it( 'should return `grid-template-columns` with max() function if both minimumColumnWidth and columnCount are provided', () => {
36
+ const expected = `.my-container { grid-template-columns: repeat(auto-fill, minmax(max(12rem, ( 100% - (1.2rem*2) ) / 3), 1fr)); container-type: inline-size; }`;
37
+
38
+ const result = grid.getLayoutStyle( {
39
+ selector: '.my-container',
40
+ layout: { minimumColumnWidth: '12rem', columnCount: 3 },
41
+ style: {},
42
+ blockName: 'test-block',
43
+ hasBlockGapSupport: false,
44
+ layoutDefinitions: undefined,
45
+ } );
46
+
33
47
  expect( result ).toBe( expected );
34
48
  } );
35
49
  } );