@wordpress/block-editor 14.6.0 → 14.7.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 (187) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/build/components/block-list/block.js +14 -28
  3. package/build/components/block-list/block.js.map +1 -1
  4. package/build/components/block-patterns-list/index.js +23 -26
  5. package/build/components/block-patterns-list/index.js.map +1 -1
  6. package/build/components/block-popover/index.js +1 -1
  7. package/build/components/block-popover/index.js.map +1 -1
  8. package/build/components/block-preview/async.js +51 -0
  9. package/build/components/block-preview/async.js.map +1 -0
  10. package/build/components/block-preview/index.js +4 -1
  11. package/build/components/block-preview/index.js.map +1 -1
  12. package/build/components/block-toolbar/change-design.js +1 -4
  13. package/build/components/block-toolbar/change-design.js.map +1 -1
  14. package/build/components/block-tools/index.js +12 -9
  15. package/build/components/block-tools/index.js.map +1 -1
  16. package/build/components/block-tools/use-block-toolbar-popover-props.js +1 -1
  17. package/build/components/block-tools/use-block-toolbar-popover-props.js.map +1 -1
  18. package/build/components/block-tools/use-show-block-tools.js +4 -1
  19. package/build/components/block-tools/use-show-block-tools.js.map +1 -1
  20. package/build/components/global-styles/dimensions-panel.js +26 -14
  21. package/build/components/global-styles/dimensions-panel.js.map +1 -1
  22. package/build/components/iframe/get-compatibility-styles.js +4 -4
  23. package/build/components/iframe/get-compatibility-styles.js.map +1 -1
  24. package/build/components/iframe/index.js +16 -0
  25. package/build/components/iframe/index.js.map +1 -1
  26. package/build/components/inserter/block-patterns-explorer/pattern-list.js +2 -2
  27. package/build/components/inserter/block-patterns-explorer/pattern-list.js.map +1 -1
  28. package/build/components/inserter/block-patterns-tab/index.js +1 -2
  29. package/build/components/inserter/block-patterns-tab/index.js.map +1 -1
  30. package/build/components/inserter/block-patterns-tab/pattern-category-previews.js +3 -1
  31. package/build/components/inserter/block-patterns-tab/pattern-category-previews.js.map +1 -1
  32. package/build/components/inserter/block-patterns-tab/use-pattern-categories.js +3 -0
  33. package/build/components/inserter/block-patterns-tab/use-pattern-categories.js.map +1 -1
  34. package/build/components/inserter/block-patterns-tab/utils.js +5 -1
  35. package/build/components/inserter/block-patterns-tab/utils.js.map +1 -1
  36. package/build/components/inserter/hooks/use-block-types-state.js +1 -1
  37. package/build/components/inserter/hooks/use-block-types-state.js.map +1 -1
  38. package/build/components/inserter/hooks/use-patterns-paging.js +0 -5
  39. package/build/components/inserter/hooks/use-patterns-paging.js.map +1 -1
  40. package/build/components/inserter/search-results.js +0 -2
  41. package/build/components/inserter/search-results.js.map +1 -1
  42. package/build/components/media-placeholder/index.js +4 -4
  43. package/build/components/media-placeholder/index.js.map +1 -1
  44. package/build/components/rich-text/index.js +1 -1
  45. package/build/components/rich-text/index.js.map +1 -1
  46. package/build/components/tabbed-sidebar/index.js +1 -1
  47. package/build/components/tabbed-sidebar/index.js.map +1 -1
  48. package/build/components/url-input/index.js +3 -1
  49. package/build/components/url-input/index.js.map +1 -1
  50. package/build/components/use-block-commands/index.js +5 -6
  51. package/build/components/use-block-commands/index.js.map +1 -1
  52. package/build/hooks/font-family.js +1 -1
  53. package/build/hooks/font-family.js.map +1 -1
  54. package/build/hooks/supports.js +6 -6
  55. package/build/hooks/supports.js.map +1 -1
  56. package/build/hooks/typography.js +5 -5
  57. package/build/hooks/typography.js.map +1 -1
  58. package/build/hooks/utils.js +2 -2
  59. package/build/hooks/utils.js.map +1 -1
  60. package/build/lock-unlock.js.map +1 -1
  61. package/build/store/private-selectors.js +2 -2
  62. package/build/store/private-selectors.js.map +1 -1
  63. package/build/store/selectors.js +9 -8
  64. package/build/store/selectors.js.map +1 -1
  65. package/build/store/utils.js +5 -4
  66. package/build/store/utils.js.map +1 -1
  67. package/build/utils/dom.js +27 -22
  68. package/build/utils/dom.js.map +1 -1
  69. package/build-module/components/block-list/block.js +15 -27
  70. package/build-module/components/block-list/block.js.map +1 -1
  71. package/build-module/components/block-patterns-list/index.js +23 -26
  72. package/build-module/components/block-patterns-list/index.js.map +1 -1
  73. package/build-module/components/block-popover/index.js +2 -2
  74. package/build-module/components/block-popover/index.js.map +1 -1
  75. package/build-module/components/block-preview/async.js +44 -0
  76. package/build-module/components/block-preview/async.js.map +1 -0
  77. package/build-module/components/block-preview/index.js +4 -1
  78. package/build-module/components/block-preview/index.js.map +1 -1
  79. package/build-module/components/block-toolbar/change-design.js +1 -4
  80. package/build-module/components/block-toolbar/change-design.js.map +1 -1
  81. package/build-module/components/block-tools/index.js +13 -10
  82. package/build-module/components/block-tools/index.js.map +1 -1
  83. package/build-module/components/block-tools/use-block-toolbar-popover-props.js +2 -2
  84. package/build-module/components/block-tools/use-block-toolbar-popover-props.js.map +1 -1
  85. package/build-module/components/block-tools/use-show-block-tools.js +4 -1
  86. package/build-module/components/block-tools/use-show-block-tools.js.map +1 -1
  87. package/build-module/components/global-styles/dimensions-panel.js +26 -14
  88. package/build-module/components/global-styles/dimensions-panel.js.map +1 -1
  89. package/build-module/components/iframe/get-compatibility-styles.js +4 -4
  90. package/build-module/components/iframe/get-compatibility-styles.js.map +1 -1
  91. package/build-module/components/iframe/index.js +16 -0
  92. package/build-module/components/iframe/index.js.map +1 -1
  93. package/build-module/components/inserter/block-patterns-explorer/pattern-list.js +2 -2
  94. package/build-module/components/inserter/block-patterns-explorer/pattern-list.js.map +1 -1
  95. package/build-module/components/inserter/block-patterns-tab/index.js +1 -2
  96. package/build-module/components/inserter/block-patterns-tab/index.js.map +1 -1
  97. package/build-module/components/inserter/block-patterns-tab/pattern-category-previews.js +4 -2
  98. package/build-module/components/inserter/block-patterns-tab/pattern-category-previews.js.map +1 -1
  99. package/build-module/components/inserter/block-patterns-tab/use-pattern-categories.js +4 -1
  100. package/build-module/components/inserter/block-patterns-tab/use-pattern-categories.js.map +1 -1
  101. package/build-module/components/inserter/block-patterns-tab/utils.js +4 -0
  102. package/build-module/components/inserter/block-patterns-tab/utils.js.map +1 -1
  103. package/build-module/components/inserter/hooks/use-block-types-state.js +1 -1
  104. package/build-module/components/inserter/hooks/use-block-types-state.js.map +1 -1
  105. package/build-module/components/inserter/hooks/use-patterns-paging.js +1 -6
  106. package/build-module/components/inserter/hooks/use-patterns-paging.js.map +1 -1
  107. package/build-module/components/inserter/search-results.js +0 -2
  108. package/build-module/components/inserter/search-results.js.map +1 -1
  109. package/build-module/components/media-placeholder/index.js +4 -4
  110. package/build-module/components/media-placeholder/index.js.map +1 -1
  111. package/build-module/components/rich-text/index.js +1 -1
  112. package/build-module/components/rich-text/index.js.map +1 -1
  113. package/build-module/components/tabbed-sidebar/index.js +1 -1
  114. package/build-module/components/tabbed-sidebar/index.js.map +1 -1
  115. package/build-module/components/url-input/index.js +3 -1
  116. package/build-module/components/url-input/index.js.map +1 -1
  117. package/build-module/components/use-block-commands/index.js +4 -4
  118. package/build-module/components/use-block-commands/index.js.map +1 -1
  119. package/build-module/hooks/font-family.js +1 -1
  120. package/build-module/hooks/font-family.js.map +1 -1
  121. package/build-module/hooks/supports.js +6 -6
  122. package/build-module/hooks/supports.js.map +1 -1
  123. package/build-module/hooks/typography.js +5 -5
  124. package/build-module/hooks/typography.js.map +1 -1
  125. package/build-module/hooks/utils.js +2 -2
  126. package/build-module/hooks/utils.js.map +1 -1
  127. package/build-module/lock-unlock.js.map +1 -1
  128. package/build-module/store/private-selectors.js +2 -2
  129. package/build-module/store/private-selectors.js.map +1 -1
  130. package/build-module/store/selectors.js +9 -8
  131. package/build-module/store/selectors.js.map +1 -1
  132. package/build-module/store/utils.js +3 -3
  133. package/build-module/store/utils.js.map +1 -1
  134. package/build-module/utils/dom.js +25 -21
  135. package/build-module/utils/dom.js.map +1 -1
  136. package/build-style/content-rtl.css +7 -6
  137. package/build-style/content.css +7 -6
  138. package/build-style/style-rtl.css +14 -3
  139. package/build-style/style.css +14 -3
  140. package/build-types/utils/dom.d.ts +7 -9
  141. package/build-types/utils/dom.d.ts.map +1 -1
  142. package/package.json +4 -3
  143. package/src/components/block-canvas/style.scss +1 -1
  144. package/src/components/block-inspector/style.scss +2 -1
  145. package/src/components/block-list/block.js +28 -48
  146. package/src/components/block-patterns-list/README.md +8 -8
  147. package/src/components/block-patterns-list/index.js +35 -51
  148. package/src/components/block-patterns-list/stories/index.story.js +2 -19
  149. package/src/components/block-popover/index.js +4 -4
  150. package/src/components/block-preview/async.js +43 -0
  151. package/src/components/block-preview/index.js +6 -1
  152. package/src/components/block-toolbar/change-design.js +1 -7
  153. package/src/components/block-tools/index.js +26 -10
  154. package/src/components/block-tools/style.scss +12 -0
  155. package/src/components/block-tools/use-block-toolbar-popover-props.js +2 -2
  156. package/src/components/block-tools/use-show-block-tools.js +3 -1
  157. package/src/components/default-block-appender/content.scss +13 -19
  158. package/src/components/global-styles/dimensions-panel.js +22 -16
  159. package/src/components/iframe/get-compatibility-styles.js +4 -9
  160. package/src/components/iframe/index.js +17 -0
  161. package/src/components/inserter/block-patterns-explorer/pattern-list.js +3 -6
  162. package/src/components/inserter/block-patterns-tab/index.js +0 -1
  163. package/src/components/inserter/block-patterns-tab/pattern-category-previews.js +8 -1
  164. package/src/components/inserter/block-patterns-tab/use-pattern-categories.js +8 -0
  165. package/src/components/inserter/block-patterns-tab/utils.js +5 -0
  166. package/src/components/inserter/hooks/use-block-types-state.js +6 -1
  167. package/src/components/inserter/hooks/use-patterns-paging.js +1 -6
  168. package/src/components/inserter/search-results.js +0 -6
  169. package/src/components/media-placeholder/index.js +4 -4
  170. package/src/components/rich-text/index.js +8 -1
  171. package/src/components/tabbed-sidebar/index.js +1 -1
  172. package/src/components/tabbed-sidebar/style.scss +1 -1
  173. package/src/components/url-input/index.js +3 -4
  174. package/src/components/use-block-commands/index.js +245 -234
  175. package/src/hooks/font-family.js +1 -1
  176. package/src/hooks/supports.js +6 -6
  177. package/src/hooks/typography.js +5 -5
  178. package/src/hooks/utils.js +7 -2
  179. package/src/store/private-selectors.js +5 -6
  180. package/src/store/selectors.js +57 -45
  181. package/src/store/test/private-selectors.js +5 -0
  182. package/src/store/utils.js +12 -11
  183. package/src/utils/dom.js +26 -21
  184. package/src/utils/test/dom.js +224 -0
  185. package/tsconfig.json +1 -0
  186. package/tsconfig.tsbuildinfo +1 -1
  187. /package/src/{lock-unlock.js → lock-unlock.ts} +0 -0
@@ -39,14 +39,14 @@ function BlockPattern( {
39
39
  pattern,
40
40
  onClick,
41
41
  onHover,
42
- showTitle = true,
43
- showTooltip,
42
+ showTitlesAsTooltip,
44
43
  category,
45
44
  } ) {
46
45
  const [ isDragging, setIsDragging ] = useState( false );
47
46
  const { blocks, viewportWidth } = pattern;
48
47
  const instanceId = useInstanceId( BlockPattern );
49
48
  const descriptionId = `block-editor-block-patterns-list__item-description-${ instanceId }`;
49
+ const isUserPattern = pattern.type === INSERTER_PATTERN_TYPES.user;
50
50
 
51
51
  // When we have a selected category and the pattern is draggable, we need to update the
52
52
  // pattern's categories in metadata to only contain the selected category, and pass this to
@@ -94,10 +94,7 @@ function BlockPattern( {
94
94
  } }
95
95
  >
96
96
  <WithToolTip
97
- showTooltip={
98
- showTooltip &&
99
- ! pattern.type !== INSERTER_PATTERN_TYPES.user
100
- }
97
+ showTooltip={ showTitlesAsTooltip && ! isUserPattern }
101
98
  title={ pattern.title }
102
99
  >
103
100
  <Composite.Item
@@ -134,33 +131,30 @@ function BlockPattern( {
134
131
  } }
135
132
  onMouseLeave={ () => onHover?.( null ) }
136
133
  >
137
- <BlockPreview
138
- blocks={ blocks }
139
- viewportWidth={ viewportWidth }
140
- />
141
-
142
- { showTitle && (
134
+ <BlockPreview.Async
135
+ placeholder={ <BlockPatternPlaceholder /> }
136
+ >
137
+ <BlockPreview
138
+ blocks={ blocks }
139
+ viewportWidth={ viewportWidth }
140
+ />
141
+ </BlockPreview.Async>
142
+ { ( ! showTitlesAsTooltip || isUserPattern ) && (
143
143
  <HStack
144
144
  className="block-editor-patterns__pattern-details"
145
145
  spacing={ 2 }
146
146
  >
147
- { pattern.type ===
148
- INSERTER_PATTERN_TYPES.user &&
149
- ! pattern.syncStatus && (
150
- <div className="block-editor-patterns__pattern-icon-wrapper">
151
- <Icon
152
- className="block-editor-patterns__pattern-icon"
153
- icon={ symbol }
154
- />
155
- </div>
156
- ) }
157
- { ( ! showTooltip ||
158
- pattern.type ===
159
- INSERTER_PATTERN_TYPES.user ) && (
160
- <div className="block-editor-block-patterns-list__item-title">
161
- { pattern.title }
147
+ { isUserPattern && ! pattern.syncStatus && (
148
+ <div className="block-editor-patterns__pattern-icon-wrapper">
149
+ <Icon
150
+ className="block-editor-patterns__pattern-icon"
151
+ icon={ symbol }
152
+ />
162
153
  </div>
163
154
  ) }
155
+ <div className="block-editor-block-patterns-list__item-title">
156
+ { pattern.title }
157
+ </div>
164
158
  </HStack>
165
159
  ) }
166
160
 
@@ -187,13 +181,11 @@ function BlockPatternsList(
187
181
  {
188
182
  isDraggable,
189
183
  blockPatterns,
190
- shownPatterns,
191
184
  onHover,
192
185
  onClickPattern,
193
186
  orientation,
194
187
  label = __( 'Block patterns' ),
195
188
  category,
196
- showTitle = true,
197
189
  showTitlesAsTooltip,
198
190
  pagingProps,
199
191
  },
@@ -205,11 +197,9 @@ function BlockPatternsList(
205
197
  // Reset the active composite item whenever the available patterns change,
206
198
  // to make sure that Composite widget can receive focus correctly when its
207
199
  // composite items change. The first composite item will receive focus.
208
- const firstCompositeItemId = blockPatterns.find( ( pattern ) =>
209
- shownPatterns.includes( pattern )
210
- )?.name;
200
+ const firstCompositeItemId = blockPatterns[ 0 ]?.name;
211
201
  setActiveCompositeId( firstCompositeItemId );
212
- }, [ shownPatterns, blockPatterns ] );
202
+ }, [ blockPatterns ] );
213
203
 
214
204
  return (
215
205
  <Composite
@@ -221,24 +211,18 @@ function BlockPatternsList(
221
211
  aria-label={ label }
222
212
  ref={ ref }
223
213
  >
224
- { blockPatterns.map( ( pattern ) => {
225
- const isShown = shownPatterns.includes( pattern );
226
- return isShown ? (
227
- <BlockPattern
228
- key={ pattern.name }
229
- id={ pattern.name }
230
- pattern={ pattern }
231
- onClick={ onClickPattern }
232
- onHover={ onHover }
233
- isDraggable={ isDraggable }
234
- showTitle={ showTitle }
235
- showTooltip={ showTitlesAsTooltip }
236
- category={ category }
237
- />
238
- ) : (
239
- <BlockPatternPlaceholder key={ pattern.name } />
240
- );
241
- } ) }
214
+ { blockPatterns.map( ( pattern ) => (
215
+ <BlockPattern
216
+ key={ pattern.name }
217
+ id={ pattern.name }
218
+ pattern={ pattern }
219
+ onClick={ onClickPattern }
220
+ onHover={ onHover }
221
+ isDraggable={ isDraggable }
222
+ showTitlesAsTooltip={ showTitlesAsTooltip }
223
+ category={ category }
224
+ />
225
+ ) ) }
242
226
  { pagingProps && <BlockPatternsPaging { ...pagingProps } /> }
243
227
  </Composite>
244
228
  );
@@ -3,11 +3,6 @@
3
3
  */
4
4
  import blockLibraryStyles from '!!raw-loader!../../../../../block-library/build-style/style.css';
5
5
 
6
- /**
7
- * WordPress dependencies
8
- */
9
- import { useAsyncList } from '@wordpress/compose';
10
-
11
6
  /**
12
7
  * Internal dependencies
13
8
  */
@@ -26,13 +21,9 @@ export default {
26
21
 
27
22
  export const Default = {
28
23
  render: function Template( props ) {
29
- const shownPatterns = useAsyncList( props.blockPatterns );
30
24
  return (
31
25
  <ExperimentalBlockEditorProvider settings={ blockEditorSettings }>
32
- <BlockPatternsList
33
- shownPatterns={ shownPatterns }
34
- { ...props }
35
- />
26
+ <BlockPatternsList { ...props } />
36
27
  </ExperimentalBlockEditorProvider>
37
28
  );
38
29
  },
@@ -40,7 +31,6 @@ export const Default = {
40
31
  blockPatterns: patterns,
41
32
  isDraggable: false,
42
33
  label: 'Block patterns story',
43
- showTitle: true,
44
34
  showTitlesAsTooltip: false,
45
35
  },
46
36
  argTypes: {
@@ -49,18 +39,11 @@ export const Default = {
49
39
  description:
50
40
  'Usually this component is used with `useAsyncList` for performance reasons and you should provide the returned list from that hook. Alternatively it should have the same value with `blockPatterns`.',
51
41
  },
52
- showTitle: {
53
- description: 'Whether to render the title of each pattern.',
54
- table: {
55
- defaultValue: { summary: true },
56
- type: { summary: 'boolean' },
57
- },
58
- },
59
42
  onClickPattern: { type: 'function' },
60
43
  onHover: { type: 'function' },
61
44
  showTitlesAsTooltip: {
62
45
  description:
63
- 'Whether to render the title of each pattern as a tooltip. If enabled, it takes precedence over `showTitle` prop.',
46
+ 'Whether to render the title of each pattern as a tooltip. If enabled',
64
47
  },
65
48
  orientation: {
66
49
  description: 'Orientation for the underlying composite widget.',
@@ -20,7 +20,7 @@ import {
20
20
  */
21
21
  import { useBlockElement } from '../block-list/use-block-props/use-block-refs';
22
22
  import usePopoverScroll from './use-popover-scroll';
23
- import { rectUnion, getVisibleElementBounds } from '../../utils/dom';
23
+ import { rectUnion, getElementBounds } from '../../utils/dom';
24
24
 
25
25
  const MAX_POPOVER_RECOMPUTE_COUNTER = Number.MAX_SAFE_INTEGER;
26
26
 
@@ -90,10 +90,10 @@ function BlockPopover(
90
90
  getBoundingClientRect() {
91
91
  return lastSelectedElement
92
92
  ? rectUnion(
93
- getVisibleElementBounds( selectedElement ),
94
- getVisibleElementBounds( lastSelectedElement )
93
+ getElementBounds( selectedElement ),
94
+ getElementBounds( lastSelectedElement )
95
95
  )
96
- : getVisibleElementBounds( selectedElement );
96
+ : getElementBounds( selectedElement );
97
97
  },
98
98
  contextElement: selectedElement,
99
99
  };
@@ -0,0 +1,43 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useEffect, useState, flushSync } from '@wordpress/element';
5
+ import { createQueue } from '@wordpress/priority-queue';
6
+
7
+ const blockPreviewQueue = createQueue();
8
+
9
+ /**
10
+ * Renders a component at the next idle time.
11
+ * @param {*} props
12
+ */
13
+ export function Async( { children, placeholder } ) {
14
+ const [ shouldRender, setShouldRender ] = useState( false );
15
+
16
+ // In the future, we could try to use startTransition here, but currently
17
+ // react will batch all transitions, which means all previews will be
18
+ // rendered at the same time.
19
+ // https://react.dev/reference/react/startTransition#caveats
20
+ // > If there are multiple ongoing Transitions, React currently batches them
21
+ // > together. This is a limitation that will likely be removed in a future
22
+ // > release.
23
+
24
+ useEffect( () => {
25
+ const context = {};
26
+ blockPreviewQueue.add( context, () => {
27
+ // Synchronously run all renders so it consumes timeRemaining.
28
+ // See https://github.com/WordPress/gutenberg/pull/48238
29
+ flushSync( () => {
30
+ setShouldRender( true );
31
+ } );
32
+ } );
33
+ return () => {
34
+ blockPreviewQueue.cancel( context );
35
+ };
36
+ }, [] );
37
+
38
+ if ( ! shouldRender ) {
39
+ return placeholder;
40
+ }
41
+
42
+ return children;
43
+ }
@@ -19,6 +19,7 @@ import AutoHeightBlockPreview from './auto';
19
19
  import EditorStyles from '../editor-styles';
20
20
  import { store as blockEditorStore } from '../../store';
21
21
  import { BlockListItems } from '../block-list';
22
+ import { Async } from './async';
22
23
 
23
24
  const EMPTY_ADDITIONAL_STYLES = [];
24
25
 
@@ -86,6 +87,10 @@ export function BlockPreview( {
86
87
  );
87
88
  }
88
89
 
90
+ const MemoizedBlockPreview = memo( BlockPreview );
91
+
92
+ MemoizedBlockPreview.Async = Async;
93
+
89
94
  /**
90
95
  * BlockPreview renders a preview of a block or array of blocks.
91
96
  *
@@ -97,7 +102,7 @@ export function BlockPreview( {
97
102
  *
98
103
  * @return {Component} The component to be rendered.
99
104
  */
100
- export default memo( BlockPreview );
105
+ export default MemoizedBlockPreview;
101
106
 
102
107
  /**
103
108
  * This hook is used to lightly mark an element as a block preview wrapper
@@ -10,7 +10,6 @@ import {
10
10
  import { __ } from '@wordpress/i18n';
11
11
  import { cloneBlock } from '@wordpress/blocks';
12
12
  import { useMemo } from '@wordpress/element';
13
- import { useAsyncList } from '@wordpress/compose';
14
13
  import { useSelect, useDispatch } from '@wordpress/data';
15
14
 
16
15
  /**
@@ -81,10 +80,6 @@ export default function ChangeDesign( { clientId } ) {
81
80
  .slice( 0, MAX_PATTERNS_TO_SHOW );
82
81
  }, [ categories, currentPatternName, patterns ] );
83
82
 
84
- const currentShownPatterns = useAsyncList(
85
- sameCategoryPatternsWithSingleWrapper
86
- );
87
-
88
83
  if ( sameCategoryPatternsWithSingleWrapper.length < 2 ) {
89
84
  return null;
90
85
  }
@@ -121,10 +116,9 @@ export default function ChangeDesign( { clientId } ) {
121
116
  paddingSize="none"
122
117
  >
123
118
  <BlockPatternsList
124
- shownPatterns={ currentShownPatterns }
125
119
  blockPatterns={ sameCategoryPatternsWithSingleWrapper }
126
120
  onClickPattern={ onClickPattern }
127
- showTitle={ false }
121
+ showTitlesAsTooltip
128
122
  />
129
123
  </DropdownContentWrapper>
130
124
  ) }
@@ -8,7 +8,7 @@ import { __unstableUseShortcutEventMatch as useShortcutEventMatch } from '@wordp
8
8
  import { useRef } from '@wordpress/element';
9
9
  import { switchToBlockType, store as blocksStore } from '@wordpress/blocks';
10
10
  import { speak } from '@wordpress/a11y';
11
- import { __ } from '@wordpress/i18n';
11
+ import { __, sprintf, _n } from '@wordpress/i18n';
12
12
 
13
13
  /**
14
14
  * Internal dependencies
@@ -92,19 +92,35 @@ export default function BlockTools( {
92
92
  return;
93
93
  }
94
94
 
95
- if ( isMatch( 'core/block-editor/move-up', event ) ) {
95
+ if (
96
+ isMatch( 'core/block-editor/move-up', event ) ||
97
+ isMatch( 'core/block-editor/move-down', event )
98
+ ) {
96
99
  const clientIds = getSelectedBlockClientIds();
97
100
  if ( clientIds.length ) {
98
101
  event.preventDefault();
99
102
  const rootClientId = getBlockRootClientId( clientIds[ 0 ] );
100
- moveBlocksUp( clientIds, rootClientId );
101
- }
102
- } else if ( isMatch( 'core/block-editor/move-down', event ) ) {
103
- const clientIds = getSelectedBlockClientIds();
104
- if ( clientIds.length ) {
105
- event.preventDefault();
106
- const rootClientId = getBlockRootClientId( clientIds[ 0 ] );
107
- moveBlocksDown( clientIds, rootClientId );
103
+ const direction = isMatch( 'core/block-editor/move-up', event )
104
+ ? 'up'
105
+ : 'down';
106
+ if ( direction === 'up' ) {
107
+ moveBlocksUp( clientIds, rootClientId );
108
+ } else {
109
+ moveBlocksDown( clientIds, rootClientId );
110
+ }
111
+ const blockLength = Array.isArray( clientIds )
112
+ ? clientIds.length
113
+ : 1;
114
+ const message = sprintf(
115
+ // translators: %d: the name of the block that has been moved
116
+ _n(
117
+ '%d block moved.',
118
+ '%d blocks moved.',
119
+ clientIds.length
120
+ ),
121
+ blockLength
122
+ );
123
+ speak( message );
108
124
  }
109
125
  } else if ( isMatch( 'core/block-editor/duplicate', event ) ) {
110
126
  const clientIds = getSelectedBlockClientIds();
@@ -57,6 +57,18 @@
57
57
  }
58
58
  }
59
59
 
60
+ // The black plus that shows up on the right side of an empty paragraph block.
61
+ .block-editor-block-list__empty-block-inserter.block-editor-block-list__empty-block-inserter {
62
+ position: absolute;
63
+ top: 0;
64
+ right: 0;
65
+ line-height: 0;
66
+
67
+ &:disabled {
68
+ display: none;
69
+ }
70
+ }
71
+
60
72
  // Sibling inserter / "inbetweenserter".
61
73
  .block-editor-block-list__empty-block-inserter,
62
74
  .block-editor-block-list__insertion-point-inserter {
@@ -17,7 +17,7 @@ import {
17
17
  import { store as blockEditorStore } from '../../store';
18
18
  import { useBlockElement } from '../block-list/use-block-props/use-block-refs';
19
19
  import { hasStickyOrFixedPositionValue } from '../../hooks/position';
20
- import { getVisibleElementBounds } from '../../utils/dom';
20
+ import { getElementBounds } from '../../utils/dom';
21
21
 
22
22
  const COMMON_PROPS = {
23
23
  placement: 'top-start',
@@ -68,7 +68,7 @@ function getProps(
68
68
  // Get how far the content area has been scrolled.
69
69
  const scrollTop = scrollContainer?.scrollTop || 0;
70
70
 
71
- const blockRect = getVisibleElementBounds( selectedBlockElement );
71
+ const blockRect = getElementBounds( selectedBlockElement );
72
72
  const contentRect = contentElement.getBoundingClientRect();
73
73
 
74
74
  // Get the vertical position of top of the visible content area.
@@ -40,7 +40,9 @@ export function useShowBlockTools() {
40
40
  const _showEmptyBlockSideInserter =
41
41
  clientId &&
42
42
  ! isTyping() &&
43
- editorMode === 'edit' &&
43
+ // Hide the block inserter on the navigation mode.
44
+ // See https://github.com/WordPress/gutenberg/pull/66636#discussion_r1824728483.
45
+ editorMode !== 'navigation' &&
44
46
  isEmptyDefaultBlock;
45
47
  const _showBlockToolbarPopover =
46
48
  ! getSettings().hasFixedToolbar &&
@@ -24,20 +24,11 @@
24
24
  .block-editor-default-block-appender__content {
25
25
  // Set the opacity of the initial block appender to the same as placeholder text in an empty Paragraph block.
26
26
  opacity: 0.62;
27
- }
28
-
29
- // In "constrained" layout containers, the first and last paragraphs have their margins zeroed out.
30
- // In the case of this appender, it needs to apply those same rules to avoid layout shifts.
31
- // Such shifts happen when the bottom margin of the Title block has been set to less than the default 1em margin of paragraphs.
32
- :where(body .is-layout-constrained) &,
33
- :where(.wp-site-blocks) & {
34
- > :first-child {
35
- margin-block-start: 0;
36
- margin-block-end: 0;
37
- }
38
27
 
39
- // Since this appender will only ever appear on an entirely empty document, we don't account for last-child.
40
- // This is also because it will never be the last child, the block inserter that sits in this appender is the last child.
28
+ // The following prevents user agent styles from applying margins to the appender's inner paragraph.
29
+ // This in turn prevents layout shift due to layout styles removing margins from first and last children.
30
+ margin-block-start: 0;
31
+ margin-block-end: 0;
41
32
  }
42
33
 
43
34
  // Dropzone.
@@ -62,9 +53,7 @@
62
53
  }
63
54
  }
64
55
 
65
- // The black plus that shows up on the right side of an empty paragraph block, or the initial appender
66
- // that exists only on empty documents.
67
- .block-editor-block-list__empty-block-inserter.block-editor-block-list__empty-block-inserter,
56
+ // The initial appender that exists only on empty documents.
68
57
  .block-editor-default-block-appender .block-editor-inserter {
69
58
  position: absolute;
70
59
  top: 0;
@@ -76,10 +65,11 @@
76
65
  }
77
66
  }
78
67
 
79
-
80
68
  /**
81
- * Fixed position appender.
82
- * These styles apply to all in-canvas inserters that exist inside nesting containers.
69
+ * Fixed position appender (right bottom corner).
70
+ *
71
+ * These styles apply to all in-canvas inserters. All in-canvas inserters always
72
+ * exist within a block.
83
73
  */
84
74
 
85
75
  .block-editor-block-list__block .block-list-appender {
@@ -96,6 +86,10 @@
96
86
  line-height: 0;
97
87
  }
98
88
 
89
+ .block-editor-inserter:disabled {
90
+ display: none;
91
+ }
92
+
99
93
  .block-editor-default-block-appender {
100
94
  height: $button-size-small;
101
95
  }
@@ -147,24 +147,30 @@ function splitStyleValue( value ) {
147
147
  return value;
148
148
  }
149
149
 
150
- function splitGapValue( value ) {
151
- // Check for shorthand value (a string value).
152
- if ( value && typeof value === 'string' ) {
153
- // If the value is a string, treat it as a single side (top) for the spacing controls.
154
- return {
155
- top: value,
156
- };
150
+ function splitGapValue( value, isAxialGap ) {
151
+ if ( ! value ) {
152
+ return value;
157
153
  }
158
154
 
159
- if ( value ) {
160
- return {
161
- ...value,
162
- right: value?.left,
163
- bottom: value?.top,
164
- };
155
+ // Check for shorthand value (a string value).
156
+ if ( typeof value === 'string' ) {
157
+ /*
158
+ * Map the string value to appropriate sides for the spacing control depending
159
+ * on whether the current block has axial gap support or not.
160
+ *
161
+ * Note: The axial value pairs must match for the spacing control to display
162
+ * the appropriate horizontal/vertical sliders.
163
+ */
164
+ return isAxialGap
165
+ ? { top: value, right: value, bottom: value, left: value }
166
+ : { top: value };
165
167
  }
166
168
 
167
- return value;
169
+ return {
170
+ ...value,
171
+ right: value?.left,
172
+ bottom: value?.top,
173
+ };
168
174
  }
169
175
 
170
176
  function DimensionsToolsPanel( {
@@ -325,13 +331,13 @@ export default function DimensionsPanel( {
325
331
 
326
332
  // Block Gap
327
333
  const showGapControl = useHasGap( settings );
328
- const gapValue = decodeValue( inheritedValue?.spacing?.blockGap );
329
- const gapValues = splitGapValue( gapValue );
330
334
  const gapSides = Array.isArray( settings?.spacing?.blockGap )
331
335
  ? settings?.spacing?.blockGap
332
336
  : settings?.spacing?.blockGap?.sides;
333
337
  const isAxialGap =
334
338
  gapSides && gapSides.some( ( side ) => AXIAL_SIDES.includes( side ) );
339
+ const gapValue = decodeValue( inheritedValue?.spacing?.blockGap );
340
+ const gapValues = splitGapValue( gapValue, isAxialGap );
335
341
  const setGapValue = ( newGapValue ) => {
336
342
  onChange(
337
343
  setImmutably( value, [ 'spacing', 'blockGap' ], newGapValue )
@@ -37,15 +37,10 @@ export function getCompatibilityStyles() {
37
37
  return accumulator;
38
38
  }
39
39
 
40
- // Don't try to add the reset styles, which were removed as a dependency
41
- // from `edit-blocks` for the iframe since we don't need to reset admin
42
- // styles.
43
- if (
44
- [
45
- 'wp-reset-editor-styles-css',
46
- 'wp-reset-editor-styles-rtl-css',
47
- ].includes( ownerNode.id )
48
- ) {
40
+ // Don't try to add core WP styles. We are responsible for adding
41
+ // them. This compatibility layer is only meant to add styles added
42
+ // by plugins or themes.
43
+ if ( ownerNode.id.startsWith( 'wp-' ) ) {
49
44
  return accumulator;
50
45
  }
51
46
 
@@ -191,6 +191,22 @@ function Iframe( {
191
191
  preventFileDropDefault,
192
192
  false
193
193
  );
194
+ // Prevent clicks on links from navigating away. Note that links
195
+ // inside `contenteditable` are already disabled by the browser, so
196
+ // this is for links in blocks outside of `contenteditable`.
197
+ iFrameDocument.addEventListener( 'click', ( event ) => {
198
+ if ( event.target.tagName === 'A' ) {
199
+ event.preventDefault();
200
+
201
+ // Appending a hash to the current URL will not reload the
202
+ // page. This is useful for e.g. footnotes.
203
+ const href = event.target.getAttribute( 'href' );
204
+ if ( href.startsWith( '#' ) ) {
205
+ iFrameDocument.defaultView.location.hash =
206
+ href.slice( 1 );
207
+ }
208
+ }
209
+ } );
194
210
  }
195
211
 
196
212
  node.addEventListener( 'load', onLoad );
@@ -272,6 +288,7 @@ function Iframe( {
272
288
  <html>
273
289
  <head>
274
290
  <meta charset="utf-8">
291
+ <base href="${ window.location.origin }">
275
292
  <script>window.frameElement._load()</script>
276
293
  <style>
277
294
  html{
@@ -85,10 +85,10 @@ function PatternList( {
85
85
  return true;
86
86
  }
87
87
  if ( selectedCategory === 'uncategorized' ) {
88
- const hasKnownCategory = pattern.categories.some(
89
- ( category ) =>
88
+ const hasKnownCategory =
89
+ pattern.categories?.some( ( category ) =>
90
90
  registeredPatternCategories.includes( category )
91
- );
91
+ ) ?? false;
92
92
 
93
93
  return ! pattern.categories?.length || ! hasKnownCategory;
94
94
  }
@@ -151,9 +151,6 @@ function PatternList( {
151
151
  { hasItems && (
152
152
  <>
153
153
  <BlockPatternsList
154
- shownPatterns={
155
- pagingProps.categoryPatternsAsyncList
156
- }
157
154
  blockPatterns={ pagingProps.categoryPatterns }
158
155
  onClickPattern={ onClickPattern }
159
156
  isDraggable={ false }
@@ -79,7 +79,6 @@ function BlockPatternsTab( {
79
79
  onInsert={ onInsert }
80
80
  rootClientId={ rootClientId }
81
81
  category={ category }
82
- showTitlesAsTooltip={ false }
83
82
  />
84
83
  </div>
85
84
  ) }
@@ -31,6 +31,7 @@ import {
31
31
  isPatternFiltered,
32
32
  allPatternsCategory,
33
33
  myPatternsCategory,
34
+ starterPatternsCategory,
34
35
  INSERTER_PATTERN_TYPES,
35
36
  } from './utils';
36
37
  import { store as blockEditorStore } from '../../../store';
@@ -86,6 +87,13 @@ export function PatternCategoryPreviews( {
86
87
  return true;
87
88
  }
88
89
 
90
+ if (
91
+ category.name === starterPatternsCategory.name &&
92
+ pattern.blockTypes?.includes( 'core/post-content' )
93
+ ) {
94
+ return true;
95
+ }
96
+
89
97
  if ( category.name === 'uncategorized' ) {
90
98
  // The uncategorized category should show all the patterns without any category...
91
99
  if ( ! pattern.categories ) {
@@ -182,7 +190,6 @@ export function PatternCategoryPreviews( {
182
190
  ) }
183
191
  <BlockPatternsList
184
192
  ref={ scrollContainerRef }
185
- shownPatterns={ pagingProps.categoryPatternsAsyncList }
186
193
  blockPatterns={ pagingProps.categoryPatterns }
187
194
  onClickPattern={ onClickPattern }
188
195
  onHover={ onHover }