@wordpress/block-library 8.31.0 → 8.32.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 (157) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/build/block/edit.js +5 -8
  3. package/build/block/edit.js.map +1 -1
  4. package/build/button/edit.native.js +1 -1
  5. package/build/button/edit.native.js.map +1 -1
  6. package/build/image/edit.js +10 -39
  7. package/build/image/edit.js.map +1 -1
  8. package/build/image/image.js +27 -6
  9. package/build/image/image.js.map +1 -1
  10. package/build/navigation/view.js +12 -2
  11. package/build/navigation/view.js.map +1 -1
  12. package/build/navigation-link/edit.js +41 -18
  13. package/build/navigation-link/edit.js.map +1 -1
  14. package/build/navigation-submenu/edit.js +27 -9
  15. package/build/navigation-submenu/edit.js.map +1 -1
  16. package/build/pattern/edit.js +3 -1
  17. package/build/pattern/edit.js.map +1 -1
  18. package/build/post-featured-image/edit.js +12 -3
  19. package/build/post-featured-image/edit.js.map +1 -1
  20. package/build/post-featured-image/index.js +8 -3
  21. package/build/post-featured-image/index.js.map +1 -1
  22. package/build/post-featured-image/overlay-controls.js +82 -0
  23. package/build/post-featured-image/overlay-controls.js.map +1 -0
  24. package/build/post-featured-image/overlay.js +5 -54
  25. package/build/post-featured-image/overlay.js.map +1 -1
  26. package/build/quote/edit.js +18 -23
  27. package/build/quote/edit.js.map +1 -1
  28. package/build/site-tagline/edit.js +13 -4
  29. package/build/site-tagline/edit.js.map +1 -1
  30. package/build/site-tagline/index.js +4 -0
  31. package/build/site-tagline/index.js.map +1 -1
  32. package/build/template-part/edit/index.js +55 -47
  33. package/build/template-part/edit/index.js.map +1 -1
  34. package/build/template-part/edit/inner-blocks.js +106 -10
  35. package/build/template-part/edit/inner-blocks.js.map +1 -1
  36. package/build/template-part/edit/selection-modal.js +1 -9
  37. package/build/template-part/edit/selection-modal.js.map +1 -1
  38. package/build/utils/caption.js +19 -13
  39. package/build/utils/caption.js.map +1 -1
  40. package/build/utils/hooks.js +1 -0
  41. package/build/utils/hooks.js.map +1 -1
  42. package/build-module/block/edit.js +5 -8
  43. package/build-module/block/edit.js.map +1 -1
  44. package/build-module/button/edit.native.js +1 -1
  45. package/build-module/button/edit.native.js.map +1 -1
  46. package/build-module/image/edit.js +11 -40
  47. package/build-module/image/edit.js.map +1 -1
  48. package/build-module/image/image.js +27 -6
  49. package/build-module/image/image.js.map +1 -1
  50. package/build-module/navigation/view.js +12 -2
  51. package/build-module/navigation/view.js.map +1 -1
  52. package/build-module/navigation-link/edit.js +43 -20
  53. package/build-module/navigation-link/edit.js.map +1 -1
  54. package/build-module/navigation-submenu/edit.js +27 -9
  55. package/build-module/navigation-submenu/edit.js.map +1 -1
  56. package/build-module/pattern/edit.js +3 -1
  57. package/build-module/pattern/edit.js.map +1 -1
  58. package/build-module/post-featured-image/edit.js +12 -3
  59. package/build-module/post-featured-image/edit.js.map +1 -1
  60. package/build-module/post-featured-image/index.js +8 -3
  61. package/build-module/post-featured-image/index.js.map +1 -1
  62. package/build-module/post-featured-image/overlay-controls.js +75 -0
  63. package/build-module/post-featured-image/overlay-controls.js.map +1 -0
  64. package/build-module/post-featured-image/overlay.js +7 -56
  65. package/build-module/post-featured-image/overlay.js.map +1 -1
  66. package/build-module/quote/edit.js +20 -25
  67. package/build-module/quote/edit.js.map +1 -1
  68. package/build-module/site-tagline/edit.js +14 -5
  69. package/build-module/site-tagline/edit.js.map +1 -1
  70. package/build-module/site-tagline/index.js +4 -0
  71. package/build-module/site-tagline/index.js.map +1 -1
  72. package/build-module/template-part/edit/index.js +58 -50
  73. package/build-module/template-part/edit/index.js.map +1 -1
  74. package/build-module/template-part/edit/inner-blocks.js +108 -12
  75. package/build-module/template-part/edit/inner-blocks.js.map +1 -1
  76. package/build-module/template-part/edit/selection-modal.js +2 -10
  77. package/build-module/template-part/edit/selection-modal.js.map +1 -1
  78. package/build-module/utils/caption.js +19 -13
  79. package/build-module/utils/caption.js.map +1 -1
  80. package/build-module/utils/hooks.js +1 -0
  81. package/build-module/utils/hooks.js.map +1 -1
  82. package/build-style/audio/theme-rtl.css +1 -1
  83. package/build-style/audio/theme.css +1 -1
  84. package/build-style/cover/style-rtl.css +5 -2
  85. package/build-style/cover/style.css +5 -2
  86. package/build-style/editor-rtl.css +12 -8
  87. package/build-style/editor.css +12 -8
  88. package/build-style/embed/theme-rtl.css +1 -1
  89. package/build-style/embed/theme.css +1 -1
  90. package/build-style/image/theme-rtl.css +1 -1
  91. package/build-style/image/theme.css +1 -1
  92. package/build-style/pullquote/theme-rtl.css +2 -1
  93. package/build-style/pullquote/theme.css +2 -1
  94. package/build-style/quote/theme-rtl.css +6 -6
  95. package/build-style/quote/theme.css +6 -6
  96. package/build-style/search/style-rtl.css +10 -0
  97. package/build-style/search/style.css +10 -0
  98. package/build-style/social-links/editor-rtl.css +0 -4
  99. package/build-style/social-links/editor.css +0 -4
  100. package/build-style/style-rtl.css +15 -2
  101. package/build-style/style.css +15 -2
  102. package/build-style/table/theme-rtl.css +4 -3
  103. package/build-style/table/theme.css +4 -3
  104. package/build-style/template-part/editor-rtl.css +12 -4
  105. package/build-style/template-part/editor.css +12 -4
  106. package/build-style/template-part/theme-rtl.css +1 -1
  107. package/build-style/template-part/theme.css +1 -1
  108. package/build-style/theme-rtl.css +17 -15
  109. package/build-style/theme.css +17 -15
  110. package/build-style/video/theme-rtl.css +1 -1
  111. package/build-style/video/theme.css +1 -1
  112. package/package.json +34 -34
  113. package/src/audio/theme.scss +1 -1
  114. package/src/block/edit.js +5 -17
  115. package/src/button/edit.native.js +1 -1
  116. package/src/cover/style.scss +6 -2
  117. package/src/embed/theme.scss +1 -1
  118. package/src/gallery/editor.scss +1 -1
  119. package/src/gallery/index.php +1 -1
  120. package/src/image/edit.js +11 -40
  121. package/src/image/editor.scss +2 -2
  122. package/src/image/image.js +25 -7
  123. package/src/image/theme.scss +1 -1
  124. package/src/navigation/index.php +8 -0
  125. package/src/navigation/view.js +11 -2
  126. package/src/navigation-link/edit.js +53 -27
  127. package/src/navigation-submenu/edit.js +30 -10
  128. package/src/pattern/edit.js +4 -0
  129. package/src/post-featured-image/block.json +8 -3
  130. package/src/post-featured-image/edit.js +12 -1
  131. package/src/post-featured-image/editor.scss +1 -1
  132. package/src/post-featured-image/overlay-controls.js +88 -0
  133. package/src/post-featured-image/overlay.js +17 -84
  134. package/src/pullquote/theme.scss +3 -1
  135. package/src/query-no-results/index.php +2 -0
  136. package/src/query-pagination-next/index.php +2 -0
  137. package/src/query-pagination-numbers/index.php +2 -0
  138. package/src/quote/edit.js +27 -43
  139. package/src/quote/test/edit.native.js +4 -6
  140. package/src/quote/theme.scss +1 -2
  141. package/src/search/style.scss +11 -0
  142. package/src/site-logo/editor.scss +2 -2
  143. package/src/site-tagline/block.json +4 -0
  144. package/src/site-tagline/edit.js +16 -3
  145. package/src/site-tagline/index.php +9 -1
  146. package/src/social-links/editor.scss +1 -9
  147. package/src/table/theme.scss +4 -2
  148. package/src/template-part/edit/index.js +87 -79
  149. package/src/template-part/edit/inner-blocks.js +126 -13
  150. package/src/template-part/edit/selection-modal.js +1 -22
  151. package/src/template-part/editor.scss +11 -3
  152. package/src/template-part/index.php +2 -0
  153. package/src/template-part/theme.scss +1 -1
  154. package/src/utils/caption.js +19 -16
  155. package/src/utils/hooks.js +1 -0
  156. package/src/video/editor.scss +2 -2
  157. package/src/video/theme.scss +1 -1
@@ -1,6 +1,4 @@
1
1
  .wp-block-table {
2
- margin: 0 0 1em 0;
3
-
4
2
  td,
5
3
  th {
6
4
  word-break: normal;
@@ -10,3 +8,7 @@
10
8
  @include caption-style-theme();
11
9
  }
12
10
  }
11
+
12
+ :where(.wp-block-table) {
13
+ margin: 0 0 1em 0;
14
+ }
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * WordPress dependencies
3
3
  */
4
+ import { serialize } from '@wordpress/blocks';
4
5
  import { useSelect, useDispatch } from '@wordpress/data';
5
6
  import {
6
7
  BlockSettingsMenuControls,
@@ -11,8 +12,15 @@ import {
11
12
  useHasRecursion,
12
13
  InspectorControls,
13
14
  __experimentalBlockPatternsList as BlockPatternsList,
15
+ BlockControls,
14
16
  } from '@wordpress/block-editor';
15
- import { PanelBody, Spinner, Modal, MenuItem } from '@wordpress/components';
17
+ import {
18
+ PanelBody,
19
+ Spinner,
20
+ Modal,
21
+ MenuItem,
22
+ ToolbarButton,
23
+ } from '@wordpress/components';
16
24
  import { useAsyncList } from '@wordpress/compose';
17
25
  import { __, sprintf } from '@wordpress/i18n';
18
26
  import { store as coreStore } from '@wordpress/core-data';
@@ -27,28 +35,26 @@ import TemplatePartSelectionModal from './selection-modal';
27
35
  import { TemplatePartAdvancedControls } from './advanced-controls';
28
36
  import TemplatePartInnerBlocks from './inner-blocks';
29
37
  import { createTemplatePartId } from './utils/create-template-part-id';
30
- import { mapTemplatePartToBlockPattern } from './utils/map-template-part-to-block-pattern';
31
38
  import {
32
39
  useAlternativeBlockPatterns,
33
40
  useAlternativeTemplateParts,
34
41
  useTemplatePartArea,
35
- useCreateTemplatePartFromBlocks,
36
42
  } from './utils/hooks';
37
43
 
38
44
  function ReplaceButton( {
39
45
  isEntityAvailable,
40
46
  area,
41
- clientId,
42
47
  templatePartId,
43
48
  isTemplatePartSelectionOpen,
44
49
  setIsTemplatePartSelectionOpen,
45
50
  } ) {
51
+ // This hook fetches patterns, so don't run it unconditionally in the main
52
+ // edit function!
46
53
  const { templateParts } = useAlternativeTemplateParts(
47
54
  area,
48
55
  templatePartId
49
56
  );
50
- const blockPatterns = useAlternativeBlockPatterns( area, clientId );
51
- const hasReplacements = !! templateParts.length || !! blockPatterns.length;
57
+ const hasReplacements = !! templateParts.length;
52
58
  const canReplace =
53
59
  isEntityAvailable &&
54
60
  hasReplacements &&
@@ -71,20 +77,30 @@ function ReplaceButton( {
71
77
  );
72
78
  }
73
79
 
74
- function TemplatesList( { availableTemplates, onSelect } ) {
75
- const shownTemplates = useAsyncList( availableTemplates );
80
+ function TemplatesList( { area, clientId, isEntityAvailable, onSelect } ) {
81
+ // This hook fetches patterns, so don't run it unconditionally in the main
82
+ // edit function!
83
+ const blockPatterns = useAlternativeBlockPatterns( area, clientId );
84
+ const canReplace =
85
+ isEntityAvailable &&
86
+ !! blockPatterns.length &&
87
+ ( area === 'header' || area === 'footer' );
88
+ const shownTemplates = useAsyncList( blockPatterns );
76
89
 
77
- if ( ! availableTemplates ) {
90
+ if ( ! canReplace ) {
78
91
  return null;
79
92
  }
80
93
 
81
94
  return (
82
- <BlockPatternsList
83
- label={ __( 'Templates' ) }
84
- blockPatterns={ availableTemplates }
85
- shownPatterns={ shownTemplates }
86
- onClickPattern={ onSelect }
87
- />
95
+ <PanelBody title={ __( 'Design' ) }>
96
+ <BlockPatternsList
97
+ label={ __( 'Templates' ) }
98
+ blockPatterns={ blockPatterns }
99
+ shownPatterns={ shownTemplates }
100
+ onClickPattern={ onSelect }
101
+ showTitle={ false }
102
+ />
103
+ </PanelBody>
88
104
  );
89
105
  }
90
106
 
@@ -94,6 +110,7 @@ export default function TemplatePartEdit( {
94
110
  clientId,
95
111
  } ) {
96
112
  const { createSuccessNotice } = useDispatch( noticesStore );
113
+ const { editEntityRecord } = useDispatch( coreStore );
97
114
  const currentTheme = useSelect(
98
115
  ( select ) => select( coreStore ).getCurrentTheme()?.stylesheet,
99
116
  []
@@ -104,11 +121,18 @@ export default function TemplatePartEdit( {
104
121
  const [ isTemplatePartSelectionOpen, setIsTemplatePartSelectionOpen ] =
105
122
  useState( false );
106
123
 
107
- const { isResolved, hasInnerBlocks, isMissing, area } = useSelect(
124
+ const {
125
+ isResolved,
126
+ hasInnerBlocks,
127
+ isMissing,
128
+ area,
129
+ onNavigateToEntityRecord,
130
+ title,
131
+ } = useSelect(
108
132
  ( select ) => {
109
133
  const { getEditedEntityRecord, hasFinishedResolution } =
110
134
  select( coreStore );
111
- const { getBlockCount } = select( blockEditorStore );
135
+ const { getBlockCount, getSettings } = select( blockEditorStore );
112
136
 
113
137
  const getEntityArgs = [
114
138
  'postType',
@@ -134,32 +158,41 @@ export default function TemplatePartEdit( {
134
158
  ( ! entityRecord ||
135
159
  Object.keys( entityRecord ).length === 0 ),
136
160
  area: _area,
161
+ onNavigateToEntityRecord:
162
+ getSettings().onNavigateToEntityRecord,
163
+ title: entityRecord?.title,
137
164
  };
138
165
  },
139
166
  [ templatePartId, attributes.area, clientId ]
140
167
  );
141
168
 
142
- const { templateParts } = useAlternativeTemplateParts(
143
- area,
144
- templatePartId
145
- );
146
- const blockPatterns = useAlternativeBlockPatterns( area, clientId );
147
- const hasReplacements = !! templateParts.length || !! blockPatterns.length;
148
169
  const areaObject = useTemplatePartArea( area );
149
170
  const blockProps = useBlockProps();
150
171
  const isPlaceholder = ! slug;
151
172
  const isEntityAvailable = ! isPlaceholder && ! isMissing && isResolved;
152
173
  const TagName = tagName || areaObject.tagName;
153
174
 
154
- const canReplace =
155
- isEntityAvailable &&
156
- hasReplacements &&
157
- ( area === 'header' || area === 'footer' );
158
-
159
- const createFromBlocks = useCreateTemplatePartFromBlocks(
160
- area,
161
- setAttributes
162
- );
175
+ const onPatternSelect = async ( pattern ) => {
176
+ await editEntityRecord(
177
+ 'postType',
178
+ 'wp_template_part',
179
+ templatePartId,
180
+ {
181
+ blocks: pattern.blocks,
182
+ content: serialize( pattern.blocks ),
183
+ }
184
+ );
185
+ createSuccessNotice(
186
+ sprintf(
187
+ /* translators: %s: template part title. */
188
+ __( 'Template Part "%s" updated.' ),
189
+ title || slug
190
+ ),
191
+ {
192
+ type: 'snackbar',
193
+ }
194
+ );
195
+ };
163
196
 
164
197
  // We don't want to render a missing state if we have any inner blocks.
165
198
  // A new template part is automatically created if we have any inner blocks but no entity.
@@ -192,31 +225,23 @@ export default function TemplatePartEdit( {
192
225
  );
193
226
  }
194
227
 
195
- const partsAsPatterns = templateParts.map( ( templatePart ) =>
196
- mapTemplatePartToBlockPattern( templatePart )
197
- );
198
-
199
- const onTemplatePartSelect = ( templatePart ) => {
200
- setAttributes( {
201
- slug: templatePart.slug,
202
- theme: templatePart.theme,
203
- area: undefined,
204
- } );
205
- createSuccessNotice(
206
- sprintf(
207
- /* translators: %s: template part title. */
208
- __( 'Template Part "%s" replaced.' ),
209
- templatePart.title?.rendered || templatePart.slug
210
- ),
211
- {
212
- type: 'snackbar',
213
- }
214
- );
215
- };
216
-
217
228
  return (
218
229
  <>
219
230
  <RecursionProvider uniqueId={ templatePartId }>
231
+ { isEntityAvailable && onNavigateToEntityRecord && (
232
+ <BlockControls group="other">
233
+ <ToolbarButton
234
+ onClick={ () =>
235
+ onNavigateToEntityRecord( {
236
+ postId: templatePartId,
237
+ postType: 'wp_template_part',
238
+ } )
239
+ }
240
+ >
241
+ { __( 'Edit' ) }
242
+ </ToolbarButton>
243
+ </BlockControls>
244
+ ) }
220
245
  <InspectorControls group="advanced">
221
246
  <TemplatePartAdvancedControls
222
247
  tagName={ tagName }
@@ -268,31 +293,14 @@ export default function TemplatePartEdit( {
268
293
  } }
269
294
  </BlockSettingsMenuControls>
270
295
 
271
- { canReplace &&
272
- ( partsAsPatterns.length > 0 ||
273
- blockPatterns.length > 0 ) && (
274
- <InspectorControls>
275
- <PanelBody title={ __( 'Replace' ) }>
276
- <TemplatesList
277
- availableTemplates={ partsAsPatterns }
278
- onSelect={ ( pattern ) => {
279
- onTemplatePartSelect(
280
- pattern.templatePart
281
- );
282
- } }
283
- />
284
- <TemplatesList
285
- availableTemplates={ blockPatterns }
286
- onSelect={ ( pattern, blocks ) => {
287
- createFromBlocks(
288
- blocks,
289
- pattern.title
290
- );
291
- } }
292
- />
293
- </PanelBody>
294
- </InspectorControls>
295
- ) }
296
+ <InspectorControls>
297
+ <TemplatesList
298
+ area={ area }
299
+ clientId={ clientId }
300
+ isEntityAvailable={ isEntityAvailable }
301
+ onSelect={ ( pattern ) => onPatternSelect( pattern ) }
302
+ />
303
+ </InspectorControls>
296
304
 
297
305
  { isEntityAvailable && (
298
306
  <TemplatePartInnerBlocks
@@ -1,29 +1,105 @@
1
1
  /**
2
2
  * WordPress dependencies
3
3
  */
4
- import { useEntityBlockEditor } from '@wordpress/core-data';
4
+ import { useEntityBlockEditor, store as coreStore } from '@wordpress/core-data';
5
5
  import {
6
6
  InnerBlocks,
7
7
  useInnerBlocksProps,
8
8
  useSettings,
9
9
  store as blockEditorStore,
10
+ useBlockEditingMode,
10
11
  } from '@wordpress/block-editor';
11
12
  import { useSelect } from '@wordpress/data';
13
+ import { useMemo } from '@wordpress/element';
14
+ import { parse } from '@wordpress/blocks';
12
15
 
13
- export default function TemplatePartInnerBlocks( {
14
- postId: id,
15
- hasInnerBlocks,
16
- layout,
17
- tagName: TagName,
18
- blockProps,
19
- } ) {
16
+ function useRenderAppender( hasInnerBlocks ) {
17
+ const blockEditingMode = useBlockEditingMode();
18
+ // Disable appending when the editing mode is 'contentOnly'. This is so that the user can't
19
+ // append into a template part when editing a page in the site editor. See
20
+ // DisableNonPageContentBlocks. Ideally instead of (mis)using editing mode there would be a
21
+ // block editor API for achieving this.
22
+ if ( blockEditingMode === 'contentOnly' ) {
23
+ return false;
24
+ }
25
+ if ( ! hasInnerBlocks ) {
26
+ return InnerBlocks.ButtonBlockAppender;
27
+ }
28
+ }
29
+
30
+ function useLayout( layout ) {
20
31
  const themeSupportsLayout = useSelect( ( select ) => {
21
32
  const { getSettings } = select( blockEditorStore );
22
33
  return getSettings()?.supportsLayout;
23
34
  }, [] );
24
35
  const [ defaultLayout ] = useSettings( 'layout' );
25
- const usedLayout = layout?.inherit ? defaultLayout || {} : layout;
36
+ if ( themeSupportsLayout ) {
37
+ return layout?.inherit ? defaultLayout || {} : layout;
38
+ }
39
+ }
26
40
 
41
+ function NonEditableTemplatePartPreview( {
42
+ postId: id,
43
+ layout,
44
+ tagName: TagName,
45
+ blockProps,
46
+ } ) {
47
+ useBlockEditingMode( 'disabled' );
48
+
49
+ const { content, editedBlocks } = useSelect(
50
+ ( select ) => {
51
+ if ( ! id ) {
52
+ return {};
53
+ }
54
+ const { getEditedEntityRecord } = select( coreStore );
55
+ const editedRecord = getEditedEntityRecord(
56
+ 'postType',
57
+ 'wp_template_part',
58
+ id,
59
+ { context: 'view' }
60
+ );
61
+ return {
62
+ editedBlocks: editedRecord.blocks,
63
+ content: editedRecord.content,
64
+ };
65
+ },
66
+ [ id ]
67
+ );
68
+
69
+ const blocks = useMemo( () => {
70
+ if ( ! id ) {
71
+ return undefined;
72
+ }
73
+
74
+ if ( editedBlocks ) {
75
+ return editedBlocks;
76
+ }
77
+
78
+ if ( ! content || typeof content !== 'string' ) {
79
+ return [];
80
+ }
81
+
82
+ return parse( content );
83
+ }, [ id, editedBlocks, content ] );
84
+
85
+ const innerBlocksProps = useInnerBlocksProps( blockProps, {
86
+ value: blocks,
87
+ onInput: () => {},
88
+ onChange: () => {},
89
+ renderAppender: false,
90
+ layout: useLayout( layout ),
91
+ } );
92
+
93
+ return <TagName { ...innerBlocksProps } />;
94
+ }
95
+
96
+ function EditableTemplatePartInnerBlocks( {
97
+ postId: id,
98
+ hasInnerBlocks,
99
+ layout,
100
+ tagName: TagName,
101
+ blockProps,
102
+ } ) {
27
103
  const [ blocks, onInput, onChange ] = useEntityBlockEditor(
28
104
  'postType',
29
105
  'wp_template_part',
@@ -34,11 +110,48 @@ export default function TemplatePartInnerBlocks( {
34
110
  value: blocks,
35
111
  onInput,
36
112
  onChange,
37
- renderAppender: hasInnerBlocks
38
- ? undefined
39
- : InnerBlocks.ButtonBlockAppender,
40
- layout: themeSupportsLayout ? usedLayout : undefined,
113
+ renderAppender: useRenderAppender( hasInnerBlocks ),
114
+ layout: useLayout( layout ),
41
115
  } );
42
116
 
43
117
  return <TagName { ...innerBlocksProps } />;
44
118
  }
119
+
120
+ export default function TemplatePartInnerBlocks( {
121
+ postId: id,
122
+ hasInnerBlocks,
123
+ layout,
124
+ tagName: TagName,
125
+ blockProps,
126
+ } ) {
127
+ const { canViewTemplatePart, canEditTemplatePart } = useSelect(
128
+ ( select ) => {
129
+ return {
130
+ canViewTemplatePart:
131
+ select( coreStore ).canUser( 'read', 'templates' ) ?? false,
132
+ canEditTemplatePart:
133
+ select( coreStore ).canUser( 'create', 'templates' ) ??
134
+ false,
135
+ };
136
+ },
137
+ []
138
+ );
139
+
140
+ if ( ! canViewTemplatePart ) {
141
+ return null;
142
+ }
143
+
144
+ const TemplatePartInnerBlocksComponent = canEditTemplatePart
145
+ ? EditableTemplatePartInnerBlocks
146
+ : NonEditableTemplatePartPreview;
147
+
148
+ return (
149
+ <TemplatePartInnerBlocksComponent
150
+ postId={ id }
151
+ hasInnerBlocks={ hasInnerBlocks }
152
+ layout={ layout }
153
+ tagName={ TagName }
154
+ blockProps={ blockProps }
155
+ />
156
+ );
157
+ }
@@ -18,7 +18,6 @@ import {
18
18
  import {
19
19
  useAlternativeBlockPatterns,
20
20
  useAlternativeTemplateParts,
21
- useCreateTemplatePartFromBlocks,
22
21
  } from './utils/hooks';
23
22
  import { mapTemplatePartToBlockPattern } from './utils/map-template-part-to-block-pattern';
24
23
  import { searchPatterns } from '../../utils/search-patterns';
@@ -31,11 +30,11 @@ export default function TemplatePartSelectionModal( {
31
30
  clientId,
32
31
  } ) {
33
32
  const [ searchValue, setSearchValue ] = useState( '' );
34
-
35
33
  const { templateParts } = useAlternativeTemplateParts(
36
34
  area,
37
35
  templatePartId
38
36
  );
37
+
39
38
  // We can map template parts to block patters to reuse the BlockPatternsList UI
40
39
  const filteredTemplateParts = useMemo( () => {
41
40
  const partsAsPatterns = templateParts.map( ( templatePart ) =>
@@ -49,7 +48,6 @@ export default function TemplatePartSelectionModal( {
49
48
  const filteredBlockPatterns = useMemo( () => {
50
49
  return searchPatterns( blockPatterns, searchValue );
51
50
  }, [ blockPatterns, searchValue ] );
52
- const shownBlockPatterns = useAsyncList( filteredBlockPatterns );
53
51
 
54
52
  const { createSuccessNotice } = useDispatch( noticesStore );
55
53
 
@@ -72,11 +70,6 @@ export default function TemplatePartSelectionModal( {
72
70
  onClose();
73
71
  };
74
72
 
75
- const createFromBlocks = useCreateTemplatePartFromBlocks(
76
- area,
77
- setAttributes
78
- );
79
-
80
73
  const hasTemplateParts = !! filteredTemplateParts.length;
81
74
  const hasBlockPatterns = !! filteredBlockPatterns.length;
82
75
 
@@ -104,20 +97,6 @@ export default function TemplatePartSelectionModal( {
104
97
  </div>
105
98
  ) }
106
99
 
107
- { hasBlockPatterns && (
108
- <div>
109
- <h2>{ __( 'Patterns' ) }</h2>
110
- <BlockPatternsList
111
- blockPatterns={ filteredBlockPatterns }
112
- shownPatterns={ shownBlockPatterns }
113
- onClickPattern={ ( pattern, blocks ) => {
114
- createFromBlocks( blocks, pattern.title );
115
- onClose();
116
- } }
117
- />
118
- </div>
119
- ) }
120
-
121
100
  { ! hasTemplateParts && ! hasBlockPatterns && (
122
101
  <HStack alignment="center">
123
102
  <p>{ __( 'No results found.' ) }</p>
@@ -25,9 +25,13 @@
25
25
 
26
26
  .is-outline-mode .block-editor-block-list__block:not(.remove-outline).wp-block-template-part,
27
27
  .is-outline-mode .block-editor-block-list__block:not(.remove-outline).is-reusable {
28
- &.is-highlighted,
29
- &.is-selected {
30
- box-shadow: inset 0 0 0 var(--wp-admin-border-width-focus) var(--wp-block-synced-color);
28
+ &.is-highlighted::after,
29
+ &.is-selected::after {
30
+ box-shadow: 0 0 0 var(--wp-admin-border-width-focus) var(--wp-block-synced-color);
31
+ }
32
+
33
+ &.is-hovered::after {
34
+ box-shadow: 0 0 0 $border-width var(--wp-block-synced-color);
31
35
  }
32
36
 
33
37
  &.block-editor-block-list__block:not([contenteditable]):focus {
@@ -40,3 +44,7 @@
40
44
  }
41
45
  }
42
46
  }
47
+
48
+ .is-outline-mode .block-editor-block-list__block:not(.remove-outline).wp-block-template-part.has-editable-outline::after {
49
+ border: none;
50
+ }
@@ -10,6 +10,8 @@
10
10
  *
11
11
  * @since 5.9.0
12
12
  *
13
+ * @global WP_Embed $wp_embed WordPress Embed object.
14
+ *
13
15
  * @param array $attributes The block attributes.
14
16
  *
15
17
  * @return string The render.
@@ -1,5 +1,5 @@
1
1
  // Same as the group block styles.
2
- .wp-block-template-part {
2
+ :where(.wp-block-template-part) {
3
3
  &.has-background {
4
4
  // Matches paragraph Block padding
5
5
  padding: $block-bg-padding--v $block-bg-padding--h;
@@ -23,10 +23,8 @@ import { createBlock, getDefaultBlockName } from '@wordpress/blocks';
23
23
  */
24
24
  import { unlock } from '../lock-unlock';
25
25
 
26
- const { PrivateRichText: RichText } = unlock( blockEditorPrivateApis );
27
-
28
26
  export function Caption( {
29
- key = 'caption',
27
+ attributeKey = 'caption',
30
28
  attributes,
31
29
  setAttributes,
32
30
  isSelected,
@@ -35,10 +33,16 @@ export function Caption( {
35
33
  label = __( 'Caption text' ),
36
34
  showToolbarButton = true,
37
35
  className,
38
- disableEditing,
36
+ readOnly,
37
+ tagName = 'figcaption',
38
+ addLabel = __( 'Add caption' ),
39
+ removeLabel = __( 'Remove caption' ),
40
+ icon = captionIcon,
41
+ ...props
39
42
  } ) {
40
- const caption = attributes[ key ];
43
+ const caption = attributes[ attributeKey ];
41
44
  const prevCaption = usePrevious( caption );
45
+ const { PrivateRichText: RichText } = unlock( blockEditorPrivateApis );
42
46
  const isCaptionEmpty = RichText.isEmpty( caption );
43
47
  const isPrevCaptionEmpty = RichText.isEmpty( prevCaption );
44
48
  const [ showCaption, setShowCaption ] = useState( ! isCaptionEmpty );
@@ -74,24 +78,22 @@ export function Caption( {
74
78
  onClick={ () => {
75
79
  setShowCaption( ! showCaption );
76
80
  if ( showCaption && caption ) {
77
- setAttributes( { caption: undefined } );
81
+ setAttributes( {
82
+ [ attributeKey ]: undefined,
83
+ } );
78
84
  }
79
85
  } }
80
- icon={ captionIcon }
86
+ icon={ icon }
81
87
  isPressed={ showCaption }
82
- label={
83
- showCaption
84
- ? __( 'Remove caption' )
85
- : __( 'Add caption' )
86
- }
88
+ label={ showCaption ? removeLabel : addLabel }
87
89
  />
88
90
  </BlockControls>
89
91
  ) }
90
92
  { showCaption &&
91
93
  ( ! RichText.isEmpty( caption ) || isSelected ) && (
92
94
  <RichText
93
- identifier={ key }
94
- tagName="figcaption"
95
+ identifier={ attributeKey }
96
+ tagName={ tagName }
95
97
  className={ classnames(
96
98
  className,
97
99
  __experimentalGetElementClassName( 'caption' )
@@ -101,7 +103,7 @@ export function Caption( {
101
103
  placeholder={ placeholder }
102
104
  value={ caption }
103
105
  onChange={ ( value ) =>
104
- setAttributes( { caption: value } )
106
+ setAttributes( { [ attributeKey ]: value } )
105
107
  }
106
108
  inlineToolbar
107
109
  __unstableOnSplitAtEnd={ () =>
@@ -109,7 +111,8 @@ export function Caption( {
109
111
  createBlock( getDefaultBlockName() )
110
112
  )
111
113
  }
112
- disableEditing={ disableEditing }
114
+ readOnly={ readOnly }
115
+ { ...props }
113
116
  />
114
117
  ) }
115
118
  </>
@@ -67,6 +67,7 @@ export function useUploadMediaFromBlobURL( args = {} ) {
67
67
  onChange( media );
68
68
  },
69
69
  onError: ( message ) => {
70
+ revokeBlobURL( url );
70
71
  onError( message );
71
72
  },
72
73
  } );
@@ -1,5 +1,5 @@
1
1
  // Provide special styling for the placeholder.
2
- // @todo: this particular minimal style of placeholder could be componentized further.
2
+ // @todo this particular minimal style of placeholder could be componentized further.
3
3
  .wp-block-video.wp-block-video {
4
4
  // Show Placeholder style on-select.
5
5
  &.is-selected .components-placeholder {
@@ -9,7 +9,7 @@
9
9
  box-shadow: inset 0 0 0 $border-width $gray-900;
10
10
  border: none;
11
11
 
12
- // @todo: this should eventually be overridden by a custom border-radius set in the inspector.
12
+ // @todo this should eventually be overridden by a custom border-radius set in the inspector.
13
13
  border-radius: $radius-block-ui;
14
14
 
15
15
  > svg {
@@ -2,6 +2,6 @@
2
2
  @include caption-style-theme();
3
3
  }
4
4
 
5
- .wp-block-video {
5
+ :where(.wp-block-video) {
6
6
  margin: 0 0 1em 0;
7
7
  }