@wordpress/block-editor 13.0.3 → 13.2.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 (141) hide show
  1. package/CHANGELOG.md +21 -17
  2. package/README.md +1 -1
  3. package/build/components/block-lock/modal.js +67 -67
  4. package/build/components/block-lock/modal.js.map +1 -1
  5. package/build/components/block-mover/index.js +12 -6
  6. package/build/components/block-mover/index.js.map +1 -1
  7. package/build/components/child-layout-control/index.js +185 -127
  8. package/build/components/child-layout-control/index.js.map +1 -1
  9. package/build/components/date-format-picker/index.js +18 -10
  10. package/build/components/date-format-picker/index.js.map +1 -1
  11. package/build/components/grid/grid-item-movers.js +97 -0
  12. package/build/components/grid/grid-item-movers.js.map +1 -0
  13. package/build/components/{grid-visualizer → grid}/grid-item-resizer.js +18 -56
  14. package/build/components/grid/grid-item-resizer.js.map +1 -0
  15. package/build/components/grid/grid-visualizer.js +225 -0
  16. package/build/components/grid/grid-visualizer.js.map +1 -0
  17. package/build/components/{grid-visualizer → grid}/index.js +14 -0
  18. package/build/components/grid/index.js.map +1 -0
  19. package/build/components/grid/use-get-number-of-blocks-before-cell.js +40 -0
  20. package/build/components/grid/use-get-number-of-blocks-before-cell.js.map +1 -0
  21. package/build/components/grid/use-grid-layout-sync.js +162 -0
  22. package/build/components/grid/use-grid-layout-sync.js.map +1 -0
  23. package/build/components/grid/utils.js +145 -0
  24. package/build/components/grid/utils.js.map +1 -0
  25. package/build/components/inner-blocks/index.js +1 -1
  26. package/build/components/inner-blocks/index.js.map +1 -1
  27. package/build/components/inserter/block-types-tab.native.js +1 -1
  28. package/build/components/inserter/block-types-tab.native.js.map +1 -1
  29. package/build/components/link-control/link-preview.js +12 -1
  30. package/build/components/link-control/link-preview.js.map +1 -1
  31. package/build/components/provider/use-block-sync.js +1 -7
  32. package/build/components/provider/use-block-sync.js.map +1 -1
  33. package/build/components/rich-text/event-listeners/input-rules.js +1 -0
  34. package/build/components/rich-text/event-listeners/input-rules.js.map +1 -1
  35. package/build/components/rich-text/index.native.js +14 -4
  36. package/build/components/rich-text/index.native.js.map +1 -1
  37. package/build/components/rich-text/native/index.native.js +20 -4
  38. package/build/components/rich-text/native/index.native.js.map +1 -1
  39. package/build/hooks/block-style-variation.js +2 -2
  40. package/build/hooks/block-style-variation.js.map +1 -1
  41. package/build/hooks/layout-child.js +29 -21
  42. package/build/hooks/layout-child.js.map +1 -1
  43. package/build/layouts/grid.js +24 -47
  44. package/build/layouts/grid.js.map +1 -1
  45. package/build/store/private-actions.js +0 -34
  46. package/build/store/private-actions.js.map +1 -1
  47. package/build-module/components/block-lock/modal.js +67 -67
  48. package/build-module/components/block-lock/modal.js.map +1 -1
  49. package/build-module/components/block-mover/index.js +12 -6
  50. package/build-module/components/block-mover/index.js.map +1 -1
  51. package/build-module/components/child-layout-control/index.js +185 -127
  52. package/build-module/components/child-layout-control/index.js.map +1 -1
  53. package/build-module/components/date-format-picker/index.js +19 -11
  54. package/build-module/components/date-format-picker/index.js.map +1 -1
  55. package/build-module/components/grid/grid-item-movers.js +90 -0
  56. package/build-module/components/grid/grid-item-movers.js.map +1 -0
  57. package/build-module/components/{grid-visualizer → grid}/grid-item-resizer.js +13 -51
  58. package/build-module/components/grid/grid-item-resizer.js.map +1 -0
  59. package/build-module/components/grid/grid-visualizer.js +217 -0
  60. package/build-module/components/grid/grid-visualizer.js.map +1 -0
  61. package/build-module/components/grid/index.js +5 -0
  62. package/build-module/components/grid/index.js.map +1 -0
  63. package/build-module/components/grid/use-get-number-of-blocks-before-cell.js +33 -0
  64. package/build-module/components/grid/use-get-number-of-blocks-before-cell.js.map +1 -0
  65. package/build-module/components/grid/use-grid-layout-sync.js +155 -0
  66. package/build-module/components/grid/use-grid-layout-sync.js.map +1 -0
  67. package/build-module/components/grid/utils.js +131 -0
  68. package/build-module/components/grid/utils.js.map +1 -0
  69. package/build-module/components/inner-blocks/index.js +1 -1
  70. package/build-module/components/inner-blocks/index.js.map +1 -1
  71. package/build-module/components/inserter/block-types-tab.native.js +1 -1
  72. package/build-module/components/inserter/block-types-tab.native.js.map +1 -1
  73. package/build-module/components/link-control/link-preview.js +14 -1
  74. package/build-module/components/link-control/link-preview.js.map +1 -1
  75. package/build-module/components/provider/use-block-sync.js +1 -7
  76. package/build-module/components/provider/use-block-sync.js.map +1 -1
  77. package/build-module/components/rich-text/event-listeners/input-rules.js +1 -1
  78. package/build-module/components/rich-text/event-listeners/input-rules.js.map +1 -1
  79. package/build-module/components/rich-text/index.native.js +15 -5
  80. package/build-module/components/rich-text/index.native.js.map +1 -1
  81. package/build-module/components/rich-text/native/index.native.js +20 -4
  82. package/build-module/components/rich-text/native/index.native.js.map +1 -1
  83. package/build-module/hooks/block-style-variation.js +2 -2
  84. package/build-module/hooks/block-style-variation.js.map +1 -1
  85. package/build-module/hooks/layout-child.js +27 -19
  86. package/build-module/hooks/layout-child.js.map +1 -1
  87. package/build-module/layouts/grid.js +24 -47
  88. package/build-module/layouts/grid.js.map +1 -1
  89. package/build-module/store/private-actions.js +0 -33
  90. package/build-module/store/private-actions.js.map +1 -1
  91. package/build-style/style-rtl.css +38 -16
  92. package/build-style/style.css +38 -16
  93. package/package.json +31 -31
  94. package/src/components/block-lock/modal.js +95 -82
  95. package/src/components/block-lock/style.scss +11 -1
  96. package/src/components/block-mover/index.js +37 -24
  97. package/src/components/child-layout-control/index.js +224 -159
  98. package/src/components/date-format-picker/index.js +25 -13
  99. package/src/components/grid/grid-item-movers.js +128 -0
  100. package/src/components/{grid-visualizer → grid}/grid-item-resizer.js +14 -52
  101. package/src/components/grid/grid-visualizer.js +267 -0
  102. package/src/components/grid/index.js +4 -0
  103. package/src/components/grid/style.scss +63 -0
  104. package/src/components/grid/use-get-number-of-blocks-before-cell.js +30 -0
  105. package/src/components/grid/use-grid-layout-sync.js +167 -0
  106. package/src/components/grid/utils.js +178 -0
  107. package/src/components/inner-blocks/index.js +3 -1
  108. package/src/components/inserter/block-types-tab.native.js +2 -1
  109. package/src/components/link-control/link-preview.js +18 -1
  110. package/src/components/provider/use-block-sync.js +0 -6
  111. package/src/components/rich-text/event-listeners/input-rules.js +1 -1
  112. package/src/components/rich-text/index.native.js +14 -8
  113. package/src/components/rich-text/native/index.native.js +20 -1
  114. package/src/hooks/block-style-variation.js +2 -2
  115. package/src/hooks/layout-child.js +34 -14
  116. package/src/layouts/grid.js +54 -62
  117. package/src/store/private-actions.js +0 -29
  118. package/src/style.scss +1 -1
  119. package/build/components/grid-visualizer/grid-item-resizer.js.map +0 -1
  120. package/build/components/grid-visualizer/grid-visualizer.js +0 -92
  121. package/build/components/grid-visualizer/grid-visualizer.js.map +0 -1
  122. package/build/components/grid-visualizer/index.js.map +0 -1
  123. package/build/components/grid-visualizer/utils.js +0 -10
  124. package/build/components/grid-visualizer/utils.js.map +0 -1
  125. package/build/store/undo-ignore.js +0 -11
  126. package/build/store/undo-ignore.js.map +0 -1
  127. package/build-module/components/grid-visualizer/grid-item-resizer.js.map +0 -1
  128. package/build-module/components/grid-visualizer/grid-visualizer.js +0 -84
  129. package/build-module/components/grid-visualizer/grid-visualizer.js.map +0 -1
  130. package/build-module/components/grid-visualizer/index.js +0 -3
  131. package/build-module/components/grid-visualizer/index.js.map +0 -1
  132. package/build-module/components/grid-visualizer/utils.js +0 -4
  133. package/build-module/components/grid-visualizer/utils.js.map +0 -1
  134. package/build-module/store/undo-ignore.js +0 -5
  135. package/build-module/store/undo-ignore.js.map +0 -1
  136. package/src/components/grid-visualizer/grid-visualizer.js +0 -101
  137. package/src/components/grid-visualizer/index.js +0 -2
  138. package/src/components/grid-visualizer/style.scss +0 -34
  139. package/src/components/grid-visualizer/utils.js +0 -5
  140. package/src/store/undo-ignore.js +0 -4
  141. /package/src/components/font-sizes/{README.MD → README.md} +0 -0
@@ -0,0 +1,178 @@
1
+ export function range( start, length ) {
2
+ return Array.from( { length }, ( _, i ) => start + i );
3
+ }
4
+
5
+ export class GridRect {
6
+ constructor( {
7
+ columnStart,
8
+ rowStart,
9
+ columnEnd,
10
+ rowEnd,
11
+ columnSpan,
12
+ rowSpan,
13
+ } = {} ) {
14
+ this.columnStart = columnStart ?? 1;
15
+ this.rowStart = rowStart ?? 1;
16
+ if ( columnSpan !== undefined ) {
17
+ this.columnEnd = this.columnStart + columnSpan - 1;
18
+ } else {
19
+ this.columnEnd = columnEnd ?? this.columnStart;
20
+ }
21
+ if ( rowSpan !== undefined ) {
22
+ this.rowEnd = this.rowStart + rowSpan - 1;
23
+ } else {
24
+ this.rowEnd = rowEnd ?? this.rowStart;
25
+ }
26
+ }
27
+
28
+ get columnSpan() {
29
+ return this.columnEnd - this.columnStart + 1;
30
+ }
31
+
32
+ get rowSpan() {
33
+ return this.rowEnd - this.rowStart + 1;
34
+ }
35
+
36
+ contains( column, row ) {
37
+ return (
38
+ column >= this.columnStart &&
39
+ column <= this.columnEnd &&
40
+ row >= this.rowStart &&
41
+ row <= this.rowEnd
42
+ );
43
+ }
44
+
45
+ containsRect( rect ) {
46
+ return (
47
+ this.contains( rect.columnStart, rect.rowStart ) &&
48
+ this.contains( rect.columnEnd, rect.rowEnd )
49
+ );
50
+ }
51
+
52
+ intersectsRect( rect ) {
53
+ return (
54
+ this.columnStart <= rect.columnEnd &&
55
+ this.columnEnd >= rect.columnStart &&
56
+ this.rowStart <= rect.rowEnd &&
57
+ this.rowEnd >= rect.rowStart
58
+ );
59
+ }
60
+ }
61
+
62
+ export function getComputedCSS( element, property ) {
63
+ return element.ownerDocument.defaultView
64
+ .getComputedStyle( element )
65
+ .getPropertyValue( property );
66
+ }
67
+
68
+ /**
69
+ * Given a grid-template-columns or grid-template-rows CSS property value, gets the start and end
70
+ * position in pixels of each grid track.
71
+ *
72
+ * https://css-tricks.com/snippets/css/complete-guide-grid/#aa-grid-track
73
+ *
74
+ * @param {string} template The grid-template-columns or grid-template-rows CSS property value.
75
+ * Only supports fixed sizes in pixels.
76
+ * @param {number} gap The gap between grid tracks in pixels.
77
+ *
78
+ * @return {Array<{start: number, end: number}>} An array of objects with the start and end
79
+ * position in pixels of each grid track.
80
+ */
81
+ export function getGridTracks( template, gap ) {
82
+ const tracks = [];
83
+ for ( const size of template.split( ' ' ) ) {
84
+ const previousTrack = tracks[ tracks.length - 1 ];
85
+ const start = previousTrack ? previousTrack.end + gap : 0;
86
+ const end = start + parseFloat( size );
87
+ tracks.push( { start, end } );
88
+ }
89
+ return tracks;
90
+ }
91
+
92
+ /**
93
+ * Given an array of grid tracks and a position in pixels, gets the index of the closest track to
94
+ * that position.
95
+ *
96
+ * https://css-tricks.com/snippets/css/complete-guide-grid/#aa-grid-track
97
+ *
98
+ * @param {Array<{start: number, end: number}>} tracks An array of objects with the start and end
99
+ * position in pixels of each grid track.
100
+ * @param {number} position The position in pixels.
101
+ * @param {string} edge The edge of the track to compare the
102
+ * position to. Either 'start' or 'end'.
103
+ *
104
+ * @return {number} The index of the closest track to the position. 0-based, unlike CSS grid which
105
+ * is 1-based.
106
+ */
107
+ export function getClosestTrack( tracks, position, edge = 'start' ) {
108
+ return tracks.reduce(
109
+ ( closest, track, index ) =>
110
+ Math.abs( track[ edge ] - position ) <
111
+ Math.abs( tracks[ closest ][ edge ] - position )
112
+ ? index
113
+ : closest,
114
+ 0
115
+ );
116
+ }
117
+
118
+ export function getGridRect( gridElement, rect ) {
119
+ const columnGap = parseFloat( getComputedCSS( gridElement, 'column-gap' ) );
120
+ const rowGap = parseFloat( getComputedCSS( gridElement, 'row-gap' ) );
121
+ const gridColumnTracks = getGridTracks(
122
+ getComputedCSS( gridElement, 'grid-template-columns' ),
123
+ columnGap
124
+ );
125
+ const gridRowTracks = getGridTracks(
126
+ getComputedCSS( gridElement, 'grid-template-rows' ),
127
+ rowGap
128
+ );
129
+ const columnStart = getClosestTrack( gridColumnTracks, rect.left ) + 1;
130
+ const rowStart = getClosestTrack( gridRowTracks, rect.top ) + 1;
131
+ const columnEnd =
132
+ getClosestTrack( gridColumnTracks, rect.right, 'end' ) + 1;
133
+ const rowEnd = getClosestTrack( gridRowTracks, rect.bottom, 'end' ) + 1;
134
+ return new GridRect( {
135
+ columnStart,
136
+ columnEnd,
137
+ rowStart,
138
+ rowEnd,
139
+ } );
140
+ }
141
+
142
+ export function getGridItemRect( gridItemElement ) {
143
+ return getGridRect(
144
+ gridItemElement.parentElement,
145
+ new window.DOMRect(
146
+ gridItemElement.offsetLeft,
147
+ gridItemElement.offsetTop,
148
+ gridItemElement.offsetWidth,
149
+ gridItemElement.offsetHeight
150
+ )
151
+ );
152
+ }
153
+
154
+ export function getGridInfo( gridElement ) {
155
+ const gridTemplateColumns = getComputedCSS(
156
+ gridElement,
157
+ 'grid-template-columns'
158
+ );
159
+ const gridTemplateRows = getComputedCSS(
160
+ gridElement,
161
+ 'grid-template-rows'
162
+ );
163
+ const numColumns = gridTemplateColumns.split( ' ' ).length;
164
+ const numRows = gridTemplateRows.split( ' ' ).length;
165
+ const numItems = numColumns * numRows;
166
+ return {
167
+ numColumns,
168
+ numRows,
169
+ numItems,
170
+ currentColor: getComputedCSS( gridElement, 'color' ),
171
+ style: {
172
+ gridTemplateColumns,
173
+ gridTemplateRows,
174
+ gap: getComputedCSS( gridElement, 'gap' ),
175
+ padding: getComputedCSS( gridElement, 'padding' ),
176
+ },
177
+ };
178
+ }
@@ -267,7 +267,9 @@ export function useInnerBlocksProps( props = {}, options = {} ) {
267
267
 
268
268
  const ref = useMergeRefs( [
269
269
  props.ref,
270
- __unstableDisableDropZone || isDropZoneDisabled
270
+ __unstableDisableDropZone ||
271
+ isDropZoneDisabled ||
272
+ ( layout?.columnCount && window.__experimentalEnableGridInteractivity )
271
273
  ? null
272
274
  : blockDropZoneRef,
273
275
  ] );
@@ -18,7 +18,8 @@ const getBlockNamespace = ( item ) => item.name.split( '/' )[ 0 ];
18
18
  function BlockTypesTab( { onSelect, rootClientId, listProps } ) {
19
19
  const [ rawBlockTypes, , collections ] = useBlockTypesState(
20
20
  rootClientId,
21
- onSelect
21
+ onSelect,
22
+ true
22
23
  );
23
24
  const clipboardBlock = useClipboardBlock( rootClientId );
24
25
  const filteredBlockTypes = filterInserterItems( rawBlockTypes );
@@ -27,6 +27,20 @@ import { ViewerSlot } from './viewer-slot';
27
27
 
28
28
  import useRichUrlData from './use-rich-url-data';
29
29
 
30
+ /**
31
+ * Filters the title for display. Removes the protocol and www prefix.
32
+ *
33
+ * @param {string} title The title to be filtered.
34
+ *
35
+ * @return {string} The filtered title.
36
+ */
37
+ function filterTitleForDisplay( title ) {
38
+ // Derived from `filterURLForDisplay` in `@wordpress/url`.
39
+ return title
40
+ .replace( /^[a-z\-.\+]+[0-9]*:(\/\/)?/i, '' )
41
+ .replace( /^www\./i, '' );
42
+ }
43
+
30
44
  export default function LinkPreview( {
31
45
  value,
32
46
  onEditClick,
@@ -59,6 +73,9 @@ export default function LinkPreview( {
59
73
  ! isEmptyURL &&
60
74
  stripHTML( richData?.title || value?.title || displayURL );
61
75
 
76
+ const isUrlRedundant =
77
+ ! value?.url || filterTitleForDisplay( displayTitle ) === displayURL;
78
+
62
79
  let icon;
63
80
 
64
81
  if ( richData?.icon ) {
@@ -112,7 +129,7 @@ export default function LinkPreview( {
112
129
  { displayTitle }
113
130
  </Truncate>
114
131
  </ExternalLink>
115
- { value?.url && displayTitle !== displayURL && (
132
+ { ! isUrlRedundant && (
116
133
  <span className="block-editor-link-control__search-item-info">
117
134
  <Truncate numberOfLines={ 1 }>
118
135
  { displayURL }
@@ -9,7 +9,6 @@ import { cloneBlock } from '@wordpress/blocks';
9
9
  * Internal dependencies
10
10
  */
11
11
  import { store as blockEditorStore } from '../../store';
12
- import { undoIgnoreBlocks } from '../../store/undo-ignore';
13
12
 
14
13
  const noop = () => {};
15
14
 
@@ -274,10 +273,6 @@ export default function useBlockSync( {
274
273
  const updateParent = isPersistent
275
274
  ? onChangeRef.current
276
275
  : onInputRef.current;
277
- const undoIgnore = undoIgnoreBlocks.has( blocks );
278
- if ( undoIgnore ) {
279
- undoIgnoreBlocks.delete( blocks );
280
- }
281
276
  updateParent( blocks, {
282
277
  selection: {
283
278
  selectionStart: getSelectionStart(),
@@ -285,7 +280,6 @@ export default function useBlockSync( {
285
280
  initialPosition:
286
281
  getSelectedBlocksInitialCaretPosition(),
287
282
  },
288
- undoIgnore,
289
283
  } );
290
284
  }
291
285
  previousAreBlocksDifferent = areBlocksDifferent;
@@ -14,7 +14,7 @@ import {
14
14
  START_OF_SELECTED_AREA,
15
15
  } from '../../../utils/selection';
16
16
 
17
- function findSelection( blocks ) {
17
+ export function findSelection( blocks ) {
18
18
  let i = blocks.length;
19
19
 
20
20
  while ( i-- ) {
@@ -24,7 +24,6 @@ import {
24
24
  create,
25
25
  split,
26
26
  toHTMLString,
27
- slice,
28
27
  } from '@wordpress/rich-text';
29
28
  import { isURL } from '@wordpress/url';
30
29
 
@@ -46,6 +45,8 @@ import EmbedHandlerPicker from './embed-handler-picker';
46
45
  import { Content } from './content';
47
46
  import RichText from './native';
48
47
  import { withDeprecations } from './with-deprecations';
48
+ import { findSelection } from './event-listeners/input-rules';
49
+ import { START_OF_SELECTED_AREA } from '../../utils/selection';
49
50
 
50
51
  const classes = 'block-editor-rich-text__editable';
51
52
 
@@ -80,6 +81,7 @@ export function RichTextWrapper(
80
81
  unstableOnFocus,
81
82
  __unstableAllowPrefixTransformations,
82
83
  // Native props.
84
+ __unstableUseSplitSelection,
83
85
  __unstableMobileNoFocusOnMount,
84
86
  deleteEnter,
85
87
  placeholderTextColor,
@@ -178,6 +180,7 @@ export function RichTextWrapper(
178
180
  exitFormattedText,
179
181
  selectionChange,
180
182
  __unstableMarkAutomaticChange,
183
+ __unstableSplitSelection,
181
184
  clearSelectedBlock,
182
185
  } = useDispatch( blockEditorStore );
183
186
  const adjustedAllowedFormats = getAllowedFormats( {
@@ -345,6 +348,8 @@ export function RichTextWrapper(
345
348
  }
346
349
  } else if ( canSplit ) {
347
350
  splitValue( value );
351
+ } else if ( __unstableUseSplitSelection ) {
352
+ __unstableSplitSelection();
348
353
  } else if ( canSplitAtEnd ) {
349
354
  onSplitAtEnd();
350
355
  } else if (
@@ -498,7 +503,7 @@ export function RichTextWrapper(
498
503
  );
499
504
 
500
505
  const inputRule = useCallback(
501
- ( value, valueToFormat ) => {
506
+ ( value ) => {
502
507
  if ( ! onReplace ) {
503
508
  return;
504
509
  }
@@ -514,7 +519,7 @@ export function RichTextWrapper(
514
519
  return;
515
520
  }
516
521
 
517
- const trimmedTextBefore = text.slice( 0, startPosition ).trim();
522
+ const trimmedTextBefore = text.slice( 0, start ).trim();
518
523
  const prefixTransforms = getBlockTransforms( 'from' ).filter(
519
524
  ( { type } ) => type === 'prefix'
520
525
  );
@@ -529,15 +534,16 @@ export function RichTextWrapper(
529
534
  return;
530
535
  }
531
536
 
532
- const content = valueToFormat(
533
- slice( value, startPosition, text.length )
534
- );
537
+ const content = toHTMLString( {
538
+ value: insert( value, START_OF_SELECTED_AREA, 0, start ),
539
+ } );
535
540
  const block = transformation.transform( content );
536
-
541
+ const currentSelection = findSelection( [ block ] );
537
542
  onReplace( [ block ] );
543
+ selectionChange( ...currentSelection );
538
544
  __unstableMarkAutomaticChange();
539
545
  },
540
- [ onReplace, __unstableMarkAutomaticChange ]
546
+ [ onReplace, start, selectionChange, __unstableMarkAutomaticChange ]
541
547
  );
542
548
 
543
549
  const mergedRef = useMergeRefs( [ providedRef, fallbackRef ] );
@@ -316,6 +316,23 @@ export class RichText extends Component {
316
316
  const contentWithoutRootTag = this.removeRootTagsProducedByAztec(
317
317
  event.nativeEvent.text
318
318
  );
319
+
320
+ const { __unstableInputRule } = this.props;
321
+ const currentValuePosition = {
322
+ end: this.isIOS ? this.selectionEnd : this.selectionEnd + 1,
323
+ start: this.isIOS ? this.selectionStart : this.selectionStart + 1,
324
+ };
325
+
326
+ if (
327
+ __unstableInputRule &&
328
+ __unstableInputRule( {
329
+ ...currentValuePosition,
330
+ ...this.formatToValue( contentWithoutRootTag ),
331
+ } )
332
+ ) {
333
+ return;
334
+ }
335
+
319
336
  // On iOS, onChange can be triggered after selection changes, even though there are no content changes.
320
337
  if ( contentWithoutRootTag === this.value?.toString() ) {
321
338
  return;
@@ -424,7 +441,9 @@ export class RichText extends Component {
424
441
  return;
425
442
  }
426
443
 
427
- onDelete( { isReverse, value } );
444
+ if ( onDelete ) {
445
+ onDelete( { isReverse, value } );
446
+ }
428
447
 
429
448
  event.preventDefault();
430
449
  this.lastAztecEventType = 'input';
@@ -59,7 +59,7 @@ function getVariationNameFromClass( className, registeredStyles = [] ) {
59
59
  return null;
60
60
  }
61
61
 
62
- function useBlockSyleVariation( name, variation, clientId ) {
62
+ function useBlockStyleVariation( name, variation, clientId ) {
63
63
  // Prefer global styles data in GlobalStylesContext, which are available
64
64
  // if in the site editor. Otherwise fall back to whatever is in the
65
65
  // editor settings and available in the post editor.
@@ -112,7 +112,7 @@ function useBlockProps( { name, className, clientId } ) {
112
112
  const variation = getVariationNameFromClass( className, registeredStyles );
113
113
  const variationClass = `${ VARIATION_PREFIX }${ variation }-${ clientId }`;
114
114
 
115
- const { settings, styles } = useBlockSyleVariation(
115
+ const { settings, styles } = useBlockStyleVariation(
116
116
  name,
117
117
  variation,
118
118
  clientId
@@ -11,7 +11,11 @@ import { useState } from '@wordpress/element';
11
11
  import { store as blockEditorStore } from '../store';
12
12
  import { useStyleOverride } from './utils';
13
13
  import { useLayout } from '../components/block-list/layout';
14
- import { GridVisualizer, GridItemResizer } from '../components/grid-visualizer';
14
+ import {
15
+ GridVisualizer,
16
+ GridItemResizer,
17
+ GridItemMovers,
18
+ } from '../components/grid';
15
19
 
16
20
  function useBlockPropsChildLayoutStyles( { style } ) {
17
21
  const shouldRenderChildLayoutStyles = useSelect( ( select ) => {
@@ -135,10 +139,12 @@ function useBlockPropsChildLayoutStyles( { style } ) {
135
139
  }
136
140
 
137
141
  function ChildLayoutControlsPure( { clientId, style, setAttributes } ) {
142
+ const parentLayout = useLayout() || {};
138
143
  const {
139
144
  type: parentLayoutType = 'default',
140
145
  allowSizingOnChildren = false,
141
- } = useLayout() || {};
146
+ columnCount,
147
+ } = parentLayout;
142
148
 
143
149
  const rootClientId = useSelect(
144
150
  ( select ) => {
@@ -154,29 +160,43 @@ function ChildLayoutControlsPure( { clientId, style, setAttributes } ) {
154
160
  return null;
155
161
  }
156
162
 
163
+ const isManualGrid = !! columnCount;
164
+
165
+ function updateLayout( layout ) {
166
+ setAttributes( {
167
+ style: {
168
+ ...style,
169
+ layout: {
170
+ ...style?.layout,
171
+ ...layout,
172
+ },
173
+ },
174
+ } );
175
+ }
176
+
157
177
  return (
158
178
  <>
159
179
  <GridVisualizer
160
180
  clientId={ rootClientId }
161
181
  contentRef={ setResizerBounds }
182
+ parentLayout={ parentLayout }
162
183
  />
163
184
  { allowSizingOnChildren && (
164
185
  <GridItemResizer
165
186
  clientId={ clientId }
166
187
  // Don't allow resizing beyond the grid visualizer.
167
188
  bounds={ resizerBounds }
168
- onChange={ ( { columnSpan, rowSpan } ) => {
169
- setAttributes( {
170
- style: {
171
- ...style,
172
- layout: {
173
- ...style?.layout,
174
- columnSpan,
175
- rowSpan,
176
- },
177
- },
178
- } );
179
- } }
189
+ onChange={ updateLayout }
190
+ parentLayout={ parentLayout }
191
+ />
192
+ ) }
193
+ { isManualGrid && window.__experimentalEnableGridInteractivity && (
194
+ <GridItemMovers
195
+ layout={ style?.layout }
196
+ parentLayout={ parentLayout }
197
+ onChange={ updateLayout }
198
+ gridClientId={ rootClientId }
199
+ blockClientId={ clientId }
180
200
  />
181
201
  ) }
182
202
  </>
@@ -23,7 +23,7 @@ import { appendSelectors, getBlockGapCSS } from './utils';
23
23
  import { getGapCSSValue } from '../hooks/gap';
24
24
  import { shouldSkipSerialization } from '../hooks/utils';
25
25
  import { LAYOUT_DEFINITIONS } from './definitions';
26
- import { GridVisualizer } from '../components/grid-visualizer';
26
+ import { GridVisualizer, useGridLayoutSync } from '../components/grid';
27
27
 
28
28
  const RANGE_CONTROL_MAX_VALUES = {
29
29
  px: 600,
@@ -93,7 +93,14 @@ export default {
93
93
  );
94
94
  },
95
95
  toolBarControls: function GridLayoutToolbarControls( { clientId } ) {
96
- return <GridVisualizer clientId={ clientId } />;
96
+ return (
97
+ <>
98
+ { window.__experimentalEnableGridInteractivity && (
99
+ <GridLayoutSync clientId={ clientId } />
100
+ ) }
101
+ <GridVisualizer clientId={ clientId } />
102
+ </>
103
+ );
97
104
  },
98
105
  getLayoutStyle: function getLayoutStyle( {
99
106
  selector,
@@ -245,9 +252,6 @@ function GridLayoutColumnsAndRowsControl( {
245
252
  return (
246
253
  <>
247
254
  <fieldset>
248
- <BaseControl.VisualLabel as="legend">
249
- { __( 'Columns' ) }
250
- </BaseControl.VisualLabel>
251
255
  <Flex gap={ 4 }>
252
256
  <FlexItem isBlock>
253
257
  <NumberControl
@@ -266,68 +270,43 @@ function GridLayoutColumnsAndRowsControl( {
266
270
  value={ columnCount }
267
271
  min={ 1 }
268
272
  label={ __( 'Columns' ) }
269
- hideLabelFromVision
270
273
  />
271
274
  </FlexItem>
275
+
272
276
  <FlexItem isBlock>
273
- <RangeControl
274
- value={ parseInt( columnCount, 10 ) } // RangeControl can't deal with strings.
275
- onChange={ ( value ) =>
276
- onChange( {
277
- ...layout,
278
- columnCount: value,
279
- } )
280
- }
281
- min={ 1 }
282
- max={ 16 }
283
- withInputField={ false }
284
- label={ __( 'Columns' ) }
285
- hideLabelFromVision
286
- />
277
+ { window.__experimentalEnableGridInteractivity &&
278
+ allowSizingOnChildren ? (
279
+ <NumberControl
280
+ size="__unstable-large"
281
+ onChange={ ( value ) => {
282
+ onChange( {
283
+ ...layout,
284
+ rowCount: value,
285
+ } );
286
+ } }
287
+ value={ rowCount }
288
+ min={ 1 }
289
+ label={ __( 'Rows' ) }
290
+ />
291
+ ) : (
292
+ <RangeControl
293
+ value={ parseInt( columnCount, 10 ) } // RangeControl can't deal with strings.
294
+ onChange={ ( value ) =>
295
+ onChange( {
296
+ ...layout,
297
+ columnCount: value,
298
+ } )
299
+ }
300
+ min={ 1 }
301
+ max={ 16 }
302
+ withInputField={ false }
303
+ label={ __( 'Columns' ) }
304
+ hideLabelFromVision
305
+ />
306
+ ) }
287
307
  </FlexItem>
288
308
  </Flex>
289
309
  </fieldset>
290
- { allowSizingOnChildren &&
291
- window.__experimentalEnableGridInteractivity && (
292
- <fieldset>
293
- <BaseControl.VisualLabel as="legend">
294
- { __( 'Rows' ) }
295
- </BaseControl.VisualLabel>
296
- <Flex gap={ 4 }>
297
- <FlexItem isBlock>
298
- <NumberControl
299
- size="__unstable-large"
300
- onChange={ ( value ) => {
301
- onChange( {
302
- ...layout,
303
- rowCount: value,
304
- } );
305
- } }
306
- value={ rowCount }
307
- min={ 1 }
308
- label={ __( 'Rows' ) }
309
- hideLabelFromVision
310
- />
311
- </FlexItem>
312
- <FlexItem isBlock>
313
- <RangeControl
314
- value={ parseInt( rowCount, 10 ) } // RangeControl can't deal with strings.
315
- onChange={ ( value ) =>
316
- onChange( {
317
- ...layout,
318
- rowCount: value,
319
- } )
320
- }
321
- min={ 1 }
322
- max={ 16 }
323
- withInputField={ false }
324
- label={ __( 'Rows' ) }
325
- hideLabelFromVision
326
- />
327
- </FlexItem>
328
- </Flex>
329
- </fieldset>
330
- ) }
331
310
  </>
332
311
  );
333
312
  }
@@ -366,10 +345,19 @@ function GridLayoutTypeControl( { layout, onChange } ) {
366
345
  return (
367
346
  <ToggleGroupControl
368
347
  __nextHasNoMarginBottom
369
- label={ __( 'Type' ) }
348
+ label={ __( 'Grid item position' ) }
370
349
  value={ isManual }
371
350
  onChange={ onChangeType }
372
351
  isBlock
352
+ help={
353
+ isManual === 'manual'
354
+ ? __(
355
+ 'Grid items can be manually placed in any position on the grid.'
356
+ )
357
+ : __(
358
+ 'Grid items are placed automatically depending on their order.'
359
+ )
360
+ }
373
361
  >
374
362
  <ToggleGroupControlOption
375
363
  key="auto"
@@ -384,3 +372,7 @@ function GridLayoutTypeControl( { layout, onChange } ) {
384
372
  </ToggleGroupControl>
385
373
  );
386
374
  }
375
+
376
+ function GridLayoutSync( props ) {
377
+ useGridLayoutSync( props );
378
+ }