@wordpress/block-library 8.25.0 → 8.26.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 (235) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/LICENSE.md +1 -1
  3. package/build/audio/edit.js +10 -12
  4. package/build/audio/edit.js.map +1 -1
  5. package/build/block/edit.js +79 -32
  6. package/build/block/edit.js.map +1 -1
  7. package/build/comments-title/deprecated.js +1 -1
  8. package/build/comments-title/index.js +1 -1
  9. package/build/cover/edit/inspector-controls.js +1 -1
  10. package/build/cover/edit/inspector-controls.js.map +1 -1
  11. package/build/embed/util.js +4 -4
  12. package/build/embed/util.js.map +1 -1
  13. package/build/file/edit.js +19 -27
  14. package/build/file/edit.js.map +1 -1
  15. package/build/gallery/edit.js +36 -17
  16. package/build/gallery/edit.js.map +1 -1
  17. package/build/gallery/gallery.js +3 -2
  18. package/build/gallery/gallery.js.map +1 -1
  19. package/build/gallery/index.js +4 -0
  20. package/build/gallery/index.js.map +1 -1
  21. package/build/gallery/transforms.js +4 -68
  22. package/build/gallery/transforms.js.map +1 -1
  23. package/build/group/index.js +5 -1
  24. package/build/group/index.js.map +1 -1
  25. package/build/image/deprecated.js +11 -0
  26. package/build/image/deprecated.js.map +1 -1
  27. package/build/image/edit.native.js +3 -0
  28. package/build/image/edit.native.js.map +1 -1
  29. package/build/image/image.js +22 -21
  30. package/build/image/image.js.map +1 -1
  31. package/build/image/view.js +7 -1
  32. package/build/image/view.js.map +1 -1
  33. package/build/list/edit.js +10 -15
  34. package/build/list/edit.js.map +1 -1
  35. package/build/list-item/edit.js +17 -2
  36. package/build/list-item/edit.js.map +1 -1
  37. package/build/list-item/hooks/use-enter.js +5 -3
  38. package/build/list-item/hooks/use-enter.js.map +1 -1
  39. package/build/list-item/hooks/use-enter.native.js +4 -3
  40. package/build/list-item/hooks/use-enter.native.js.map +1 -1
  41. package/build/list-item/hooks/use-indent-list-item.js +2 -3
  42. package/build/list-item/hooks/use-indent-list-item.js.map +1 -1
  43. package/build/list-item/hooks/use-merge.js +1 -1
  44. package/build/list-item/hooks/use-merge.js.map +1 -1
  45. package/build/list-item/hooks/use-outdent-list-item.js +3 -17
  46. package/build/list-item/hooks/use-outdent-list-item.js.map +1 -1
  47. package/build/list-item/hooks/use-space.js +8 -4
  48. package/build/list-item/hooks/use-space.js.map +1 -1
  49. package/build/media-text/media-container.native.js +3 -0
  50. package/build/media-text/media-container.native.js.map +1 -1
  51. package/build/navigation/constants.js +3 -1
  52. package/build/navigation/constants.js.map +1 -1
  53. package/build/navigation/edit/index.js +4 -0
  54. package/build/navigation/edit/index.js.map +1 -1
  55. package/build/navigation/view.js +25 -1
  56. package/build/navigation/view.js.map +1 -1
  57. package/build/pattern/edit.js +24 -2
  58. package/build/pattern/edit.js.map +1 -1
  59. package/build/pattern/recursion-detector.js +147 -0
  60. package/build/pattern/recursion-detector.js.map +1 -0
  61. package/build/post-featured-image/edit.js +19 -2
  62. package/build/post-featured-image/edit.js.map +1 -1
  63. package/build/post-featured-image/index.js +4 -0
  64. package/build/post-featured-image/index.js.map +1 -1
  65. package/build/query/edit/inspector-controls/index.js +3 -1
  66. package/build/query/edit/inspector-controls/index.js.map +1 -1
  67. package/build/query-pagination-numbers/index.js +1 -1
  68. package/build/search/edit.js +3 -5
  69. package/build/search/edit.js.map +1 -1
  70. package/build/search/index.js +0 -4
  71. package/build/search/index.js.map +1 -1
  72. package/build/site-logo/edit.js +7 -6
  73. package/build/site-logo/edit.js.map +1 -1
  74. package/build/spacer/edit.native.js +2 -2
  75. package/build/spacer/edit.native.js.map +1 -1
  76. package/build/tag-cloud/edit.js +5 -9
  77. package/build/tag-cloud/edit.js.map +1 -1
  78. package/build/utils/constants.js +16 -0
  79. package/build/utils/constants.js.map +1 -0
  80. package/build/video/edit.js +11 -8
  81. package/build/video/edit.js.map +1 -1
  82. package/build-module/audio/edit.js +10 -12
  83. package/build-module/audio/edit.js.map +1 -1
  84. package/build-module/block/edit.js +83 -36
  85. package/build-module/block/edit.js.map +1 -1
  86. package/build-module/comments-title/deprecated.js +1 -1
  87. package/build-module/comments-title/index.js +1 -1
  88. package/build-module/cover/edit/inspector-controls.js +1 -1
  89. package/build-module/cover/edit/inspector-controls.js.map +1 -1
  90. package/build-module/embed/util.js +4 -4
  91. package/build-module/embed/util.js.map +1 -1
  92. package/build-module/file/edit.js +19 -27
  93. package/build-module/file/edit.js.map +1 -1
  94. package/build-module/gallery/edit.js +36 -17
  95. package/build-module/gallery/edit.js.map +1 -1
  96. package/build-module/gallery/gallery.js +3 -2
  97. package/build-module/gallery/gallery.js.map +1 -1
  98. package/build-module/gallery/index.js +4 -0
  99. package/build-module/gallery/index.js.map +1 -1
  100. package/build-module/gallery/transforms.js +4 -68
  101. package/build-module/gallery/transforms.js.map +1 -1
  102. package/build-module/group/index.js +5 -1
  103. package/build-module/group/index.js.map +1 -1
  104. package/build-module/image/deprecated.js +11 -0
  105. package/build-module/image/deprecated.js.map +1 -1
  106. package/build-module/image/edit.native.js +3 -0
  107. package/build-module/image/edit.native.js.map +1 -1
  108. package/build-module/image/image.js +17 -16
  109. package/build-module/image/image.js.map +1 -1
  110. package/build-module/image/view.js +7 -1
  111. package/build-module/image/view.js.map +1 -1
  112. package/build-module/list/edit.js +10 -15
  113. package/build-module/list/edit.js.map +1 -1
  114. package/build-module/list-item/edit.js +18 -3
  115. package/build-module/list-item/edit.js.map +1 -1
  116. package/build-module/list-item/hooks/use-enter.js +5 -3
  117. package/build-module/list-item/hooks/use-enter.js.map +1 -1
  118. package/build-module/list-item/hooks/use-enter.native.js +4 -3
  119. package/build-module/list-item/hooks/use-enter.native.js.map +1 -1
  120. package/build-module/list-item/hooks/use-indent-list-item.js +2 -3
  121. package/build-module/list-item/hooks/use-indent-list-item.js.map +1 -1
  122. package/build-module/list-item/hooks/use-merge.js +1 -1
  123. package/build-module/list-item/hooks/use-merge.js.map +1 -1
  124. package/build-module/list-item/hooks/use-outdent-list-item.js +3 -17
  125. package/build-module/list-item/hooks/use-outdent-list-item.js.map +1 -1
  126. package/build-module/list-item/hooks/use-space.js +8 -4
  127. package/build-module/list-item/hooks/use-space.js.map +1 -1
  128. package/build-module/media-text/media-container.native.js +3 -0
  129. package/build-module/media-text/media-container.native.js.map +1 -1
  130. package/build-module/navigation/constants.js +1 -0
  131. package/build-module/navigation/constants.js.map +1 -1
  132. package/build-module/navigation/edit/index.js +5 -1
  133. package/build-module/navigation/edit/index.js.map +1 -1
  134. package/build-module/navigation/view.js +25 -1
  135. package/build-module/navigation/view.js.map +1 -1
  136. package/build-module/pattern/edit.js +26 -4
  137. package/build-module/pattern/edit.js.map +1 -1
  138. package/build-module/pattern/recursion-detector.js +139 -0
  139. package/build-module/pattern/recursion-detector.js.map +1 -0
  140. package/build-module/post-featured-image/edit.js +19 -2
  141. package/build-module/post-featured-image/edit.js.map +1 -1
  142. package/build-module/post-featured-image/index.js +4 -0
  143. package/build-module/post-featured-image/index.js.map +1 -1
  144. package/build-module/query/edit/inspector-controls/index.js +3 -1
  145. package/build-module/query/edit/inspector-controls/index.js.map +1 -1
  146. package/build-module/query-pagination-numbers/index.js +1 -1
  147. package/build-module/search/edit.js +3 -5
  148. package/build-module/search/edit.js.map +1 -1
  149. package/build-module/search/index.js +0 -4
  150. package/build-module/search/index.js.map +1 -1
  151. package/build-module/site-logo/edit.js +7 -6
  152. package/build-module/site-logo/edit.js.map +1 -1
  153. package/build-module/spacer/edit.native.js +2 -2
  154. package/build-module/spacer/edit.native.js.map +1 -1
  155. package/build-module/tag-cloud/edit.js +6 -10
  156. package/build-module/tag-cloud/edit.js.map +1 -1
  157. package/build-module/utils/constants.js +9 -0
  158. package/build-module/utils/constants.js.map +1 -0
  159. package/build-module/video/edit.js +11 -8
  160. package/build-module/video/edit.js.map +1 -1
  161. package/build-style/button/editor-rtl.css +0 -37
  162. package/build-style/button/editor.css +0 -37
  163. package/build-style/button/style-rtl.css +6 -6
  164. package/build-style/button/style.css +6 -6
  165. package/build-style/editor-rtl.css +2 -44
  166. package/build-style/editor.css +2 -44
  167. package/build-style/navigation/editor-rtl.css +2 -4
  168. package/build-style/navigation/editor.css +2 -4
  169. package/build-style/navigation/style-rtl.css +14 -18
  170. package/build-style/navigation/style.css +14 -18
  171. package/build-style/search/style-rtl.css +26 -27
  172. package/build-style/search/style.css +26 -27
  173. package/build-style/style-rtl.css +46 -51
  174. package/build-style/style.css +46 -51
  175. package/build-style/table/editor-rtl.css +0 -3
  176. package/build-style/table/editor.css +0 -3
  177. package/package.json +32 -32
  178. package/src/audio/edit.js +19 -19
  179. package/src/audio/test/__snapshots__/edit.native.js.snap +12 -0
  180. package/src/audio/test/edit.native.js +29 -0
  181. package/src/block/edit.js +114 -60
  182. package/src/button/editor.scss +0 -43
  183. package/src/button/style.scss +6 -6
  184. package/src/comments-title/block.json +1 -1
  185. package/src/cover/edit/inspector-controls.js +1 -1
  186. package/src/embed/util.js +2 -2
  187. package/src/file/edit.js +17 -24
  188. package/src/gallery/block.json +4 -0
  189. package/src/gallery/edit.js +69 -42
  190. package/src/gallery/gallery.js +4 -1
  191. package/src/gallery/index.php +18 -0
  192. package/src/gallery/transforms.js +2 -55
  193. package/src/group/block.json +5 -1
  194. package/src/image/deprecated.js +8 -0
  195. package/src/image/edit.native.js +3 -0
  196. package/src/image/image.js +54 -35
  197. package/src/image/index.php +1 -6
  198. package/src/image/view.js +5 -2
  199. package/src/list/edit.js +27 -35
  200. package/src/list-item/edit.js +18 -2
  201. package/src/list-item/hooks/use-enter.js +63 -62
  202. package/src/list-item/hooks/use-enter.native.js +9 -5
  203. package/src/list-item/hooks/use-indent-list-item.js +43 -53
  204. package/src/list-item/hooks/use-merge.js +1 -1
  205. package/src/list-item/hooks/use-outdent-list-item.js +50 -69
  206. package/src/list-item/hooks/use-space.js +7 -4
  207. package/src/media-text/media-container.native.js +3 -1
  208. package/src/navigation/constants.js +2 -0
  209. package/src/navigation/edit/index.js +11 -1
  210. package/src/navigation/editor.scss +1 -1
  211. package/src/navigation/style.scss +18 -16
  212. package/src/navigation/view.js +29 -3
  213. package/src/paragraph/test/__snapshots__/edit.native.js.snap +12 -0
  214. package/src/paragraph/test/edit.native.js +114 -0
  215. package/src/pattern/edit.js +35 -3
  216. package/src/pattern/index.php +16 -0
  217. package/src/pattern/recursion-detector.js +145 -0
  218. package/src/pattern/test/index.js +74 -0
  219. package/src/post-featured-image/block.json +4 -0
  220. package/src/post-featured-image/edit.js +32 -1
  221. package/src/post-featured-image/index.php +31 -0
  222. package/src/query/edit/inspector-controls/index.js +2 -0
  223. package/src/query-pagination-numbers/block.json +1 -1
  224. package/src/search/block.json +0 -4
  225. package/src/search/edit.js +2 -8
  226. package/src/search/index.php +3 -7
  227. package/src/search/style.scss +27 -29
  228. package/src/site-logo/edit.js +3 -4
  229. package/src/social-link/index.php +1 -1
  230. package/src/spacer/edit.native.js +4 -2
  231. package/src/table/editor.scss +0 -3
  232. package/src/tag-cloud/edit.js +7 -7
  233. package/src/template-part/index.php +6 -0
  234. package/src/utils/constants.js +8 -0
  235. package/src/video/edit.js +29 -27
package/src/block/edit.js CHANGED
@@ -8,12 +8,12 @@ import classnames from 'classnames';
8
8
  */
9
9
  import { useRegistry, useSelect, useDispatch } from '@wordpress/data';
10
10
  import { useRef, useMemo, useEffect } from '@wordpress/element';
11
- import { useEntityProp, useEntityRecord } from '@wordpress/core-data';
11
+ import { useEntityRecord, store as coreStore } from '@wordpress/core-data';
12
12
  import {
13
13
  Placeholder,
14
14
  Spinner,
15
- TextControl,
16
- PanelBody,
15
+ ToolbarButton,
16
+ ToolbarGroup,
17
17
  } from '@wordpress/components';
18
18
  import { __ } from '@wordpress/i18n';
19
19
  import {
@@ -21,13 +21,13 @@ import {
21
21
  __experimentalRecursionProvider as RecursionProvider,
22
22
  __experimentalUseHasRecursion as useHasRecursion,
23
23
  InnerBlocks,
24
- InspectorControls,
25
24
  useBlockProps,
26
25
  Warning,
27
26
  privateApis as blockEditorPrivateApis,
28
27
  store as blockEditorStore,
28
+ BlockControls,
29
29
  } from '@wordpress/block-editor';
30
- import { getBlockSupport, parse } from '@wordpress/blocks';
30
+ import { getBlockSupport, parse, cloneBlock } from '@wordpress/blocks';
31
31
 
32
32
  /**
33
33
  * Internal dependencies
@@ -97,9 +97,12 @@ function applyInitialOverrides( blocks, overrides = {}, defaultValues ) {
97
97
  const attributes = getPartiallySyncedAttributes( block );
98
98
  const newAttributes = { ...block.attributes };
99
99
  for ( const attributeKey of attributes ) {
100
- defaultValues[ blockId ] = block.attributes[ attributeKey ];
100
+ defaultValues[ blockId ] ??= {};
101
+ defaultValues[ blockId ][ attributeKey ] =
102
+ block.attributes[ attributeKey ];
101
103
  if ( overrides[ blockId ] ) {
102
- newAttributes[ attributeKey ] = overrides[ blockId ];
104
+ newAttributes[ attributeKey ] =
105
+ overrides[ blockId ][ attributeKey ];
103
106
  }
104
107
  }
105
108
  return {
@@ -111,7 +114,7 @@ function applyInitialOverrides( blocks, overrides = {}, defaultValues ) {
111
114
  }
112
115
 
113
116
  function getOverridesFromBlocks( blocks, defaultValues ) {
114
- /** @type {Record<string, unknown>} */
117
+ /** @type {Record<string, Record<string, unknown>>} */
115
118
  const overrides = {};
116
119
  for ( const block of blocks ) {
117
120
  Object.assign(
@@ -123,24 +126,37 @@ function getOverridesFromBlocks( blocks, defaultValues ) {
123
126
  const attributes = getPartiallySyncedAttributes( block );
124
127
  for ( const attributeKey of attributes ) {
125
128
  if (
126
- block.attributes[ attributeKey ] !== defaultValues[ blockId ]
129
+ block.attributes[ attributeKey ] !==
130
+ defaultValues[ blockId ][ attributeKey ]
127
131
  ) {
128
- overrides[ blockId ] = block.attributes[ attributeKey ];
132
+ overrides[ blockId ] ??= {};
133
+ overrides[ blockId ][ attributeKey ] =
134
+ block.attributes[ attributeKey ];
129
135
  }
130
136
  }
131
137
  }
132
138
  return Object.keys( overrides ).length > 0 ? overrides : undefined;
133
139
  }
134
140
 
141
+ function setBlockEditMode( setEditMode, blocks, mode ) {
142
+ blocks.forEach( ( block ) => {
143
+ const editMode =
144
+ mode || ( isPartiallySynced( block ) ? 'contentOnly' : 'disabled' );
145
+ setEditMode( block.clientId, editMode );
146
+ setBlockEditMode( setEditMode, block.innerBlocks, mode );
147
+ } );
148
+ }
149
+
135
150
  export default function ReusableBlockEdit( {
136
151
  name,
137
152
  attributes: { ref, overrides },
138
153
  __unstableParentLayout: parentLayout,
139
154
  clientId: patternClientId,
155
+ setAttributes,
140
156
  } ) {
141
157
  const registry = useRegistry();
142
158
  const hasAlreadyRendered = useHasRecursion( ref );
143
- const { record, hasResolved } = useEntityRecord(
159
+ const { record, editedRecord, hasResolved } = useEntityRecord(
144
160
  'postType',
145
161
  'wp_block',
146
162
  ref
@@ -148,53 +164,87 @@ export default function ReusableBlockEdit( {
148
164
  const isMissing = hasResolved && ! record;
149
165
  const initialOverrides = useRef( overrides );
150
166
  const defaultValuesRef = useRef( {} );
167
+
151
168
  const {
152
169
  replaceInnerBlocks,
153
170
  __unstableMarkNextChangeAsNotPersistent,
154
171
  setBlockEditingMode,
155
172
  } = useDispatch( blockEditorStore );
156
- const { getBlockEditingMode } = useSelect( blockEditorStore );
173
+ const { syncDerivedUpdates } = unlock( useDispatch( blockEditorStore ) );
174
+
175
+ const { innerBlocks, userCanEdit, getBlockEditingMode, getPostLinkProps } =
176
+ useSelect(
177
+ ( select ) => {
178
+ const { canUser } = select( coreStore );
179
+ const {
180
+ getBlocks,
181
+ getBlockEditingMode: editingMode,
182
+ getSettings,
183
+ } = select( blockEditorStore );
184
+ const blocks = getBlocks( patternClientId );
185
+ const canEdit = canUser( 'update', 'blocks', ref );
186
+
187
+ // For editing link to the site editor if the theme and user permissions support it.
188
+ return {
189
+ innerBlocks: blocks,
190
+ userCanEdit: canEdit,
191
+ getBlockEditingMode: editingMode,
192
+ getPostLinkProps: getSettings().getPostLinkProps,
193
+ };
194
+ },
195
+ [ patternClientId, ref ]
196
+ );
197
+
198
+ const editOriginalProps = getPostLinkProps
199
+ ? getPostLinkProps( {
200
+ postId: ref,
201
+ postType: 'wp_block',
202
+ canvas: 'edit',
203
+ } )
204
+ : {};
205
+
206
+ useEffect(
207
+ () => setBlockEditMode( setBlockEditingMode, innerBlocks ),
208
+ [ innerBlocks, setBlockEditingMode ]
209
+ );
157
210
 
211
+ // Apply the initial overrides from the pattern block to the inner blocks.
158
212
  useEffect( () => {
159
- if ( ! record?.content?.raw ) return;
160
- const initialBlocks = parse( record.content.raw );
213
+ const initialBlocks =
214
+ // Clone the blocks to generate new client IDs.
215
+ editedRecord.blocks?.map( ( block ) => cloneBlock( block ) ) ??
216
+ ( editedRecord.content && typeof editedRecord.content !== 'function'
217
+ ? parse( editedRecord.content )
218
+ : [] );
161
219
 
220
+ defaultValuesRef.current = {};
162
221
  const editingMode = getBlockEditingMode( patternClientId );
222
+ // Replace the contents of the blocks with the overrides.
163
223
  registry.batch( () => {
164
224
  setBlockEditingMode( patternClientId, 'default' );
165
- __unstableMarkNextChangeAsNotPersistent();
166
- replaceInnerBlocks(
167
- patternClientId,
168
- applyInitialOverrides(
169
- initialBlocks,
170
- initialOverrides.current,
171
- defaultValuesRef.current
172
- )
173
- );
225
+ syncDerivedUpdates( () => {
226
+ replaceInnerBlocks(
227
+ patternClientId,
228
+ applyInitialOverrides(
229
+ initialBlocks,
230
+ initialOverrides.current,
231
+ defaultValuesRef.current
232
+ )
233
+ );
234
+ } );
174
235
  setBlockEditingMode( patternClientId, editingMode );
175
236
  } );
176
237
  }, [
177
238
  __unstableMarkNextChangeAsNotPersistent,
178
239
  patternClientId,
179
- record,
240
+ editedRecord,
180
241
  replaceInnerBlocks,
181
242
  registry,
182
243
  getBlockEditingMode,
183
244
  setBlockEditingMode,
245
+ syncDerivedUpdates,
184
246
  ] );
185
247
 
186
- const innerBlocks = useSelect(
187
- ( select ) => select( blockEditorStore ).getBlocks( patternClientId ),
188
- [ patternClientId ]
189
- );
190
-
191
- const [ title, setTitle ] = useEntityProp(
192
- 'postType',
193
- 'wp_block',
194
- 'title',
195
- ref
196
- );
197
-
198
248
  const { alignment, layout } = useInferredLayout(
199
249
  innerBlocks,
200
250
  parentLayout
@@ -210,35 +260,38 @@ export default function ReusableBlockEdit( {
210
260
  } );
211
261
 
212
262
  const innerBlocksProps = useInnerBlocksProps( blockProps, {
263
+ templateLock: 'all',
213
264
  layout,
214
265
  renderAppender: innerBlocks?.length
215
266
  ? undefined
216
267
  : InnerBlocks.ButtonBlockAppender,
217
268
  } );
218
269
 
219
- // Sync the `overrides` attribute from the updated blocks.
220
- // `syncDerivedBlockAttributes` is an action that just like `updateBlockAttributes`
221
- // but won't create an undo level.
222
- // This can be abstracted into a `useSyncDerivedAttributes` hook if needed.
270
+ // Sync the `overrides` attribute from the updated blocks to the pattern block.
271
+ // `syncDerivedUpdates` is used here to avoid creating an additional undo level.
223
272
  useEffect( () => {
224
273
  const { getBlocks } = registry.select( blockEditorStore );
225
- const { syncDerivedBlockAttributes } = unlock(
226
- registry.dispatch( blockEditorStore )
227
- );
228
274
  let prevBlocks = getBlocks( patternClientId );
229
275
  return registry.subscribe( () => {
230
276
  const blocks = getBlocks( patternClientId );
231
277
  if ( blocks !== prevBlocks ) {
232
278
  prevBlocks = blocks;
233
- syncDerivedBlockAttributes( patternClientId, {
234
- overrides: getOverridesFromBlocks(
235
- blocks,
236
- defaultValuesRef.current
237
- ),
279
+ syncDerivedUpdates( () => {
280
+ setAttributes( {
281
+ overrides: getOverridesFromBlocks(
282
+ blocks,
283
+ defaultValuesRef.current
284
+ ),
285
+ } );
238
286
  } );
239
287
  }
240
288
  }, blockEditorStore );
241
- }, [ patternClientId, registry ] );
289
+ }, [ syncDerivedUpdates, patternClientId, registry, setAttributes ] );
290
+
291
+ const handleEditOriginal = ( event ) => {
292
+ setBlockEditMode( setBlockEditingMode, innerBlocks, 'default' );
293
+ editOriginalProps.onClick( event );
294
+ };
242
295
 
243
296
  let children = null;
244
297
 
@@ -268,17 +321,18 @@ export default function ReusableBlockEdit( {
268
321
 
269
322
  return (
270
323
  <RecursionProvider uniqueId={ ref }>
271
- <InspectorControls>
272
- <PanelBody>
273
- <TextControl
274
- label={ __( 'Name' ) }
275
- value={ title }
276
- onChange={ setTitle }
277
- __nextHasNoMarginBottom
278
- __next40pxDefaultSize
279
- />
280
- </PanelBody>
281
- </InspectorControls>
324
+ { userCanEdit && editOriginalProps && (
325
+ <BlockControls>
326
+ <ToolbarGroup>
327
+ <ToolbarButton
328
+ href={ editOriginalProps.href }
329
+ onClick={ handleEditOriginal }
330
+ >
331
+ { __( 'Edit original' ) }
332
+ </ToolbarButton>
333
+ </ToolbarGroup>
334
+ </BlockControls>
335
+ ) }
282
336
  { children === null ? (
283
337
  <div { ...innerBlocksProps } />
284
338
  ) : (
@@ -28,49 +28,6 @@
28
28
  }
29
29
  }
30
30
 
31
- .wp-block-button__inline-link {
32
- color: $gray-700;
33
- height: 0;
34
- overflow: hidden;
35
- max-width: 290px;
36
-
37
- &-input__suggestions {
38
- max-width: 290px;
39
- }
40
-
41
- @include break-medium() {
42
- max-width: 260px;
43
-
44
- &-input__suggestions {
45
- max-width: 260px;
46
- }
47
-
48
- }
49
- @include break-large() {
50
- max-width: 290px;
51
-
52
- &-input__suggestions {
53
- max-width: 290px;
54
- }
55
-
56
- }
57
-
58
- .is-selected & {
59
- height: auto;
60
- overflow: visible;
61
- }
62
- }
63
-
64
- .wp-button-label__width {
65
- .components-button-group {
66
- display: block;
67
- }
68
-
69
- .components-base-control__field {
70
- margin-bottom: 12px;
71
- }
72
- }
73
-
74
31
  // Display "table" is used because the button container should only wrap the content and not takes the full width.
75
32
  div[data-type="core/button"] {
76
33
  display: table;
@@ -98,19 +98,19 @@ $blocks-block__margin: 0.5em;
98
98
  border-radius: 0 !important;
99
99
  }
100
100
 
101
- .wp-block-button.is-style-outline > .wp-block-button__link,
102
- .wp-block-button .wp-block-button__link.is-style-outline {
101
+ .wp-block-button:where(.is-style-outline) > .wp-block-button__link,
102
+ .wp-block-button .wp-block-button__link:where(.is-style-outline) {
103
103
  border: 2px solid currentColor;
104
104
  padding: 0.667em 1.333em;
105
105
  }
106
106
 
107
- .wp-block-button.is-style-outline > .wp-block-button__link:not(.has-text-color),
108
- .wp-block-button .wp-block-button__link.is-style-outline:not(.has-text-color) {
107
+ .wp-block-button:where(.is-style-outline) > .wp-block-button__link:not(.has-text-color),
108
+ .wp-block-button .wp-block-button__link:where(.is-style-outline):not(.has-text-color) {
109
109
  color: currentColor;
110
110
  }
111
111
 
112
- .wp-block-button.is-style-outline > .wp-block-button__link:not(.has-background),
113
- .wp-block-button .wp-block-button__link.is-style-outline:not(.has-background) {
112
+ .wp-block-button:where(.is-style-outline) > .wp-block-button__link:not(.has-background),
113
+ .wp-block-button .wp-block-button__link:where(.is-style-outline):not(.has-background) {
114
114
  background-color: transparent;
115
115
  // background-image is required to overwrite a gradient background
116
116
  background-image: none;
@@ -5,7 +5,7 @@
5
5
  "title": "Comments Title",
6
6
  "category": "theme",
7
7
  "ancestor": [ "core/comments" ],
8
- "description": "Displays a title with the number of comments",
8
+ "description": "Displays a title with the number of comments.",
9
9
  "textdomain": "default",
10
10
  "usesContext": [ "postId", "postType" ],
11
11
  "attributes": {
@@ -220,7 +220,7 @@ export default function CoverInspectorControls( {
220
220
  <PanelRow>
221
221
  <Button
222
222
  variant="secondary"
223
- isSmall
223
+ size="small"
224
224
  className="block-library-cover__reset-button"
225
225
  onClick={ onClearMedia }
226
226
  >
package/src/embed/util.js CHANGED
@@ -7,7 +7,7 @@ import memoize from 'memize';
7
7
  /**
8
8
  * WordPress dependencies
9
9
  */
10
- import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor';
10
+ import { privateApis as componentsPrivateApis } from '@wordpress/components';
11
11
  import { renderToString } from '@wordpress/element';
12
12
  import {
13
13
  createBlock,
@@ -23,7 +23,6 @@ import { ASPECT_RATIOS, WP_EMBED_TYPE } from './constants';
23
23
  import { unlock } from '../lock-unlock';
24
24
 
25
25
  const { name: DEFAULT_EMBED_BLOCK } = metadata;
26
- const { kebabCase } = unlock( blockEditorPrivateApis );
27
26
 
28
27
  /** @typedef {import('@wordpress/blocks').WPBlockVariation} WPBlockVariation */
29
28
 
@@ -283,6 +282,7 @@ export const getAttributesFromPreview = memoize(
283
282
  // If we got a provider name from the API, use it for the slug, otherwise we use the title,
284
283
  // because not all embed code gives us a provider name.
285
284
  const { html, provider_name: providerName } = preview;
285
+ const { kebabCase } = unlock( componentsPrivateApis );
286
286
  const providerNameSlug = kebabCase(
287
287
  ( providerName || title ).toLowerCase()
288
288
  );
package/src/file/edit.js CHANGED
@@ -63,7 +63,6 @@ function ClipboardToolbarButton( { text, disabled } ) {
63
63
  function FileEdit( { attributes, isSelected, setAttributes, clientId } ) {
64
64
  const {
65
65
  id,
66
- fileId,
67
66
  fileName,
68
67
  href,
69
68
  textLinkHref,
@@ -73,27 +72,26 @@ function FileEdit( { attributes, isSelected, setAttributes, clientId } ) {
73
72
  displayPreview,
74
73
  previewHeight,
75
74
  } = attributes;
76
- const { media, mediaUpload } = useSelect(
75
+ const { getSettings } = useSelect( blockEditorStore );
76
+ const { media } = useSelect(
77
77
  ( select ) => ( {
78
78
  media:
79
79
  id === undefined
80
80
  ? undefined
81
81
  : select( coreStore ).getMedia( id ),
82
- mediaUpload: select( blockEditorStore ).getSettings().mediaUpload,
83
82
  } ),
84
83
  [ id ]
85
84
  );
86
85
 
87
86
  const { createErrorNotice } = useDispatch( noticesStore );
88
- const { toggleSelection, __unstableMarkNextChangeAsNotPersistent } =
89
- useDispatch( blockEditorStore );
87
+ const { toggleSelection } = useDispatch( blockEditorStore );
90
88
 
91
89
  useEffect( () => {
92
90
  // Upload a file drag-and-dropped into the editor.
93
91
  if ( isBlobURL( href ) ) {
94
92
  const file = getBlobByURL( href );
95
93
 
96
- mediaUpload( {
94
+ getSettings().mediaUpload( {
97
95
  filesList: [ file ],
98
96
  onFileChange: ( [ newMedia ] ) => onSelectFile( newMedia ),
99
97
  onError: onUploadError,
@@ -109,26 +107,21 @@ function FileEdit( { attributes, isSelected, setAttributes, clientId } ) {
109
107
  }
110
108
  }, [] );
111
109
 
112
- useEffect( () => {
113
- if ( ! fileId && href ) {
114
- // Add a unique fileId to each file block.
115
- __unstableMarkNextChangeAsNotPersistent();
116
- setAttributes( { fileId: `wp-block-file--media-${ clientId }` } );
117
- }
118
- }, [ href, fileId, clientId ] );
119
-
120
110
  function onSelectFile( newMedia ) {
121
- if ( newMedia && newMedia.url ) {
122
- const isPdf = newMedia.url.endsWith( '.pdf' );
123
- setAttributes( {
124
- href: newMedia.url,
125
- fileName: newMedia.title,
126
- textLinkHref: newMedia.url,
127
- id: newMedia.id,
128
- displayPreview: isPdf ? true : undefined,
129
- previewHeight: isPdf ? 600 : undefined,
130
- } );
111
+ if ( ! newMedia || ! newMedia.url ) {
112
+ return;
131
113
  }
114
+
115
+ const isPdf = newMedia.url.endsWith( '.pdf' );
116
+ setAttributes( {
117
+ href: newMedia.url,
118
+ fileName: newMedia.title,
119
+ textLinkHref: newMedia.url,
120
+ id: newMedia.id,
121
+ displayPreview: isPdf ? true : undefined,
122
+ previewHeight: isPdf ? 600 : undefined,
123
+ fileId: `wp-block-file--media-${ clientId }`,
124
+ } );
132
125
  }
133
126
 
134
127
  function onUploadError( message ) {
@@ -80,6 +80,10 @@
80
80
  "type": "boolean",
81
81
  "default": true
82
82
  },
83
+ "randomOrder": {
84
+ "type": "boolean",
85
+ "default": false
86
+ },
83
87
  "fixedHeight": {
84
88
  "type": "boolean",
85
89
  "default": true
@@ -74,6 +74,8 @@ const MOBILE_CONTROL_PROPS_RANGE_CONTROL = Platform.isNative
74
74
  ? { type: 'stepper' }
75
75
  : {};
76
76
 
77
+ const EMPTY_ARRAY = [];
78
+
77
79
  function GalleryEdit( props ) {
78
80
  const {
79
81
  setAttributes,
@@ -86,7 +88,8 @@ function GalleryEdit( props ) {
86
88
  onFocus,
87
89
  } = props;
88
90
 
89
- const { columns, imageCrop, linkTarget, linkTo, sizeSlug } = attributes;
91
+ const { columns, imageCrop, randomOrder, linkTarget, linkTo, sizeSlug } =
92
+ attributes;
90
93
 
91
94
  const {
92
95
  __unstableMarkNextChangeAsNotPersistent,
@@ -97,33 +100,44 @@ function GalleryEdit( props ) {
97
100
  const { createSuccessNotice, createErrorNotice } =
98
101
  useDispatch( noticesStore );
99
102
 
100
- const { getBlock, getSettings, preferredStyle } = useSelect( ( select ) => {
101
- const settings = select( blockEditorStore ).getSettings();
102
- const preferredStyleVariations =
103
- settings.__experimentalPreferredStyleVariations;
104
- return {
105
- getBlock: select( blockEditorStore ).getBlock,
106
- getSettings: select( blockEditorStore ).getSettings,
107
- preferredStyle: preferredStyleVariations?.value?.[ 'core/image' ],
108
- };
109
- }, [] );
110
-
111
- const innerBlockImages = useSelect(
112
- ( select ) => {
113
- const innerBlocks =
114
- select( blockEditorStore ).getBlock( clientId )?.innerBlocks ??
115
- [];
116
- return innerBlocks;
117
- },
118
- [ clientId ]
119
- );
120
-
121
- const wasBlockJustInserted = useSelect(
103
+ const {
104
+ getBlock,
105
+ getSettings,
106
+ preferredStyle,
107
+ innerBlockImages,
108
+ blockWasJustInserted,
109
+ multiGallerySelection,
110
+ } = useSelect(
122
111
  ( select ) => {
123
- return select( blockEditorStore ).wasBlockJustInserted(
124
- clientId,
125
- 'inserter_menu'
126
- );
112
+ const {
113
+ getBlockName,
114
+ getMultiSelectedBlockClientIds,
115
+ getSettings: _getSettings,
116
+ getBlock: _getBlock,
117
+ wasBlockJustInserted,
118
+ } = select( blockEditorStore );
119
+ const preferredStyleVariations =
120
+ _getSettings().__experimentalPreferredStyleVariations;
121
+ const multiSelectedClientIds = getMultiSelectedBlockClientIds();
122
+
123
+ return {
124
+ getBlock: _getBlock,
125
+ getSettings: _getSettings,
126
+ preferredStyle:
127
+ preferredStyleVariations?.value?.[ 'core/image' ],
128
+ innerBlockImages:
129
+ _getBlock( clientId )?.innerBlocks ?? EMPTY_ARRAY,
130
+ blockWasJustInserted: wasBlockJustInserted(
131
+ clientId,
132
+ 'inserter_menu'
133
+ ),
134
+ multiGallerySelection:
135
+ multiSelectedClientIds.length &&
136
+ multiSelectedClientIds.every(
137
+ ( _clientId ) =>
138
+ getBlockName( _clientId ) === 'core/gallery'
139
+ ),
140
+ };
127
141
  },
128
142
  [ clientId ]
129
143
  );
@@ -375,6 +389,10 @@ function GalleryEdit( props ) {
375
389
  : __( 'Thumbnails are not cropped.' );
376
390
  }
377
391
 
392
+ function toggleRandomOrder() {
393
+ setAttributes( { randomOrder: ! randomOrder } );
394
+ }
395
+
378
396
  function toggleOpenInNewTab( openInNewTab ) {
379
397
  const newLinkTarget = openInNewTab ? '_blank' : undefined;
380
398
  setAttributes( { linkTarget: newLinkTarget } );
@@ -463,7 +481,7 @@ function GalleryEdit( props ) {
463
481
  ( hasImages && ! isSelected ) || imagesUploading,
464
482
  value: hasImageIds ? images : {},
465
483
  autoOpenMediaUpload:
466
- ! hasImages && isSelected && wasBlockJustInserted,
484
+ ! hasImages && isSelected && blockWasJustInserted,
467
485
  onFocus,
468
486
  },
469
487
  } );
@@ -539,6 +557,12 @@ function GalleryEdit( props ) {
539
557
  onChange={ toggleImageCrop }
540
558
  help={ getImageCropHelp }
541
559
  />
560
+ <ToggleControl
561
+ __nextHasNoMarginBottom
562
+ label={ __( 'Random order' ) }
563
+ checked={ !! randomOrder }
564
+ onChange={ toggleRandomOrder }
565
+ />
542
566
  <SelectControl
543
567
  __nextHasNoMarginBottom
544
568
  label={ __( 'Link to' ) }
@@ -585,20 +609,22 @@ function GalleryEdit( props ) {
585
609
  </InspectorControls>
586
610
  { Platform.isWeb && (
587
611
  <>
588
- <BlockControls group="other">
589
- <MediaReplaceFlow
590
- allowedTypes={ ALLOWED_MEDIA_TYPES }
591
- accept="image/*"
592
- handleUpload={ false }
593
- onSelect={ updateImages }
594
- name={ __( 'Add' ) }
595
- multiple={ true }
596
- mediaIds={ images
597
- .filter( ( image ) => image.id )
598
- .map( ( image ) => image.id ) }
599
- addToGallery={ hasImageIds }
600
- />
601
- </BlockControls>
612
+ { ! multiGallerySelection && (
613
+ <BlockControls group="other">
614
+ <MediaReplaceFlow
615
+ allowedTypes={ ALLOWED_MEDIA_TYPES }
616
+ accept="image/*"
617
+ handleUpload={ false }
618
+ onSelect={ updateImages }
619
+ name={ __( 'Add' ) }
620
+ multiple={ true }
621
+ mediaIds={ images
622
+ .filter( ( image ) => image.id )
623
+ .map( ( image ) => image.id ) }
624
+ addToGallery={ hasImageIds }
625
+ />
626
+ </BlockControls>
627
+ ) }
602
628
  <GapStyles
603
629
  blockGap={ attributes.style?.spacing?.blockGap }
604
630
  clientId={ clientId }
@@ -616,6 +642,7 @@ function GalleryEdit( props ) {
616
642
  }
617
643
  blockProps={ innerBlocksProps }
618
644
  insertBlocksAfter={ insertBlocksAfter }
645
+ multiGallerySelection={ multiGallerySelection }
619
646
  />
620
647
  </>
621
648
  );
@@ -24,6 +24,7 @@ export default function Gallery( props ) {
24
24
  blockProps,
25
25
  __unstableLayoutClassNames: layoutClassNames,
26
26
  isContentLocked,
27
+ multiGallerySelection,
27
28
  } = props;
28
29
 
29
30
  const { align, columns, imageCrop } = attributes;
@@ -54,7 +55,9 @@ export default function Gallery( props ) {
54
55
  setAttributes={ setAttributes }
55
56
  isSelected={ isSelected }
56
57
  insertBlocksAfter={ insertBlocksAfter }
57
- showToolbarButton={ ! isContentLocked }
58
+ showToolbarButton={
59
+ ! multiGallerySelection && ! isContentLocked
60
+ }
58
61
  className="blocks-gallery-caption"
59
62
  label={ __( 'Gallery caption text' ) }
60
63
  placeholder={ __( 'Add gallery caption' ) }