@wordpress/block-library 8.25.0 → 8.25.1-next.79a6196f.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 (250) hide show
  1. package/LICENSE.md +1 -1
  2. package/build/audio/edit.js +10 -12
  3. package/build/audio/edit.js.map +1 -1
  4. package/build/block/edit.js +81 -34
  5. package/build/block/edit.js.map +1 -1
  6. package/build/comments-title/deprecated.js +1 -1
  7. package/build/comments-title/index.js +1 -1
  8. package/build/cover/edit/inspector-controls.js +1 -1
  9. package/build/cover/edit/inspector-controls.js.map +1 -1
  10. package/build/cover/edit.native.js +1 -0
  11. package/build/cover/edit.native.js.map +1 -1
  12. package/build/embed/util.js +4 -4
  13. package/build/embed/util.js.map +1 -1
  14. package/build/file/edit.js +19 -27
  15. package/build/file/edit.js.map +1 -1
  16. package/build/gallery/edit.js +36 -17
  17. package/build/gallery/edit.js.map +1 -1
  18. package/build/gallery/gallery.js +3 -2
  19. package/build/gallery/gallery.js.map +1 -1
  20. package/build/gallery/index.js +4 -0
  21. package/build/gallery/index.js.map +1 -1
  22. package/build/gallery/transforms.js +4 -68
  23. package/build/gallery/transforms.js.map +1 -1
  24. package/build/group/index.js +5 -1
  25. package/build/group/index.js.map +1 -1
  26. package/build/image/deprecated.js +11 -0
  27. package/build/image/deprecated.js.map +1 -1
  28. package/build/image/edit.native.js +3 -0
  29. package/build/image/edit.native.js.map +1 -1
  30. package/build/image/image.js +22 -21
  31. package/build/image/image.js.map +1 -1
  32. package/build/image/view.js +7 -1
  33. package/build/image/view.js.map +1 -1
  34. package/build/list/edit.js +10 -15
  35. package/build/list/edit.js.map +1 -1
  36. package/build/list-item/edit.js +17 -2
  37. package/build/list-item/edit.js.map +1 -1
  38. package/build/list-item/hooks/use-enter.js +5 -3
  39. package/build/list-item/hooks/use-enter.js.map +1 -1
  40. package/build/list-item/hooks/use-enter.native.js +4 -3
  41. package/build/list-item/hooks/use-enter.native.js.map +1 -1
  42. package/build/list-item/hooks/use-indent-list-item.js +2 -3
  43. package/build/list-item/hooks/use-indent-list-item.js.map +1 -1
  44. package/build/list-item/hooks/use-merge.js +1 -1
  45. package/build/list-item/hooks/use-merge.js.map +1 -1
  46. package/build/list-item/hooks/use-outdent-list-item.js +3 -17
  47. package/build/list-item/hooks/use-outdent-list-item.js.map +1 -1
  48. package/build/list-item/hooks/use-space.js +8 -4
  49. package/build/list-item/hooks/use-space.js.map +1 -1
  50. package/build/media-text/media-container.native.js +3 -0
  51. package/build/media-text/media-container.native.js.map +1 -1
  52. package/build/navigation/constants.js +3 -1
  53. package/build/navigation/constants.js.map +1 -1
  54. package/build/navigation/edit/index.js +4 -0
  55. package/build/navigation/edit/index.js.map +1 -1
  56. package/build/navigation/view.js +25 -1
  57. package/build/navigation/view.js.map +1 -1
  58. package/build/paragraph/index.js +0 -1
  59. package/build/paragraph/index.js.map +1 -1
  60. package/build/paragraph/transforms.js +0 -1
  61. package/build/paragraph/transforms.js.map +1 -1
  62. package/build/pattern/edit.js +24 -2
  63. package/build/pattern/edit.js.map +1 -1
  64. package/build/pattern/recursion-detector.js +147 -0
  65. package/build/pattern/recursion-detector.js.map +1 -0
  66. package/build/post-featured-image/edit.js +19 -2
  67. package/build/post-featured-image/edit.js.map +1 -1
  68. package/build/post-featured-image/index.js +4 -0
  69. package/build/post-featured-image/index.js.map +1 -1
  70. package/build/query/edit/inspector-controls/index.js +3 -1
  71. package/build/query/edit/inspector-controls/index.js.map +1 -1
  72. package/build/query-pagination-numbers/index.js +1 -1
  73. package/build/search/edit.js +3 -5
  74. package/build/search/edit.js.map +1 -1
  75. package/build/search/index.js +0 -4
  76. package/build/search/index.js.map +1 -1
  77. package/build/site-logo/edit.js +7 -6
  78. package/build/site-logo/edit.js.map +1 -1
  79. package/build/spacer/edit.native.js +2 -2
  80. package/build/spacer/edit.native.js.map +1 -1
  81. package/build/tag-cloud/edit.js +5 -9
  82. package/build/tag-cloud/edit.js.map +1 -1
  83. package/build/utils/constants.js +16 -0
  84. package/build/utils/constants.js.map +1 -0
  85. package/build/video/edit.js +11 -8
  86. package/build/video/edit.js.map +1 -1
  87. package/build-module/audio/edit.js +10 -12
  88. package/build-module/audio/edit.js.map +1 -1
  89. package/build-module/block/edit.js +85 -38
  90. package/build-module/block/edit.js.map +1 -1
  91. package/build-module/comments-title/deprecated.js +1 -1
  92. package/build-module/comments-title/index.js +1 -1
  93. package/build-module/cover/edit/inspector-controls.js +1 -1
  94. package/build-module/cover/edit/inspector-controls.js.map +1 -1
  95. package/build-module/cover/edit.native.js +1 -0
  96. package/build-module/cover/edit.native.js.map +1 -1
  97. package/build-module/embed/util.js +4 -4
  98. package/build-module/embed/util.js.map +1 -1
  99. package/build-module/file/edit.js +19 -27
  100. package/build-module/file/edit.js.map +1 -1
  101. package/build-module/gallery/edit.js +36 -17
  102. package/build-module/gallery/edit.js.map +1 -1
  103. package/build-module/gallery/gallery.js +3 -2
  104. package/build-module/gallery/gallery.js.map +1 -1
  105. package/build-module/gallery/index.js +4 -0
  106. package/build-module/gallery/index.js.map +1 -1
  107. package/build-module/gallery/transforms.js +4 -68
  108. package/build-module/gallery/transforms.js.map +1 -1
  109. package/build-module/group/index.js +5 -1
  110. package/build-module/group/index.js.map +1 -1
  111. package/build-module/image/deprecated.js +11 -0
  112. package/build-module/image/deprecated.js.map +1 -1
  113. package/build-module/image/edit.native.js +3 -0
  114. package/build-module/image/edit.native.js.map +1 -1
  115. package/build-module/image/image.js +17 -16
  116. package/build-module/image/image.js.map +1 -1
  117. package/build-module/image/view.js +7 -1
  118. package/build-module/image/view.js.map +1 -1
  119. package/build-module/list/edit.js +10 -15
  120. package/build-module/list/edit.js.map +1 -1
  121. package/build-module/list-item/edit.js +18 -3
  122. package/build-module/list-item/edit.js.map +1 -1
  123. package/build-module/list-item/hooks/use-enter.js +5 -3
  124. package/build-module/list-item/hooks/use-enter.js.map +1 -1
  125. package/build-module/list-item/hooks/use-enter.native.js +4 -3
  126. package/build-module/list-item/hooks/use-enter.native.js.map +1 -1
  127. package/build-module/list-item/hooks/use-indent-list-item.js +2 -3
  128. package/build-module/list-item/hooks/use-indent-list-item.js.map +1 -1
  129. package/build-module/list-item/hooks/use-merge.js +1 -1
  130. package/build-module/list-item/hooks/use-merge.js.map +1 -1
  131. package/build-module/list-item/hooks/use-outdent-list-item.js +3 -17
  132. package/build-module/list-item/hooks/use-outdent-list-item.js.map +1 -1
  133. package/build-module/list-item/hooks/use-space.js +8 -4
  134. package/build-module/list-item/hooks/use-space.js.map +1 -1
  135. package/build-module/media-text/media-container.native.js +3 -0
  136. package/build-module/media-text/media-container.native.js.map +1 -1
  137. package/build-module/navigation/constants.js +1 -0
  138. package/build-module/navigation/constants.js.map +1 -1
  139. package/build-module/navigation/edit/index.js +5 -1
  140. package/build-module/navigation/edit/index.js.map +1 -1
  141. package/build-module/navigation/view.js +25 -1
  142. package/build-module/navigation/view.js.map +1 -1
  143. package/build-module/paragraph/index.js +0 -1
  144. package/build-module/paragraph/index.js.map +1 -1
  145. package/build-module/paragraph/transforms.js +0 -1
  146. package/build-module/paragraph/transforms.js.map +1 -1
  147. package/build-module/pattern/edit.js +26 -4
  148. package/build-module/pattern/edit.js.map +1 -1
  149. package/build-module/pattern/recursion-detector.js +139 -0
  150. package/build-module/pattern/recursion-detector.js.map +1 -0
  151. package/build-module/post-featured-image/edit.js +19 -2
  152. package/build-module/post-featured-image/edit.js.map +1 -1
  153. package/build-module/post-featured-image/index.js +4 -0
  154. package/build-module/post-featured-image/index.js.map +1 -1
  155. package/build-module/query/edit/inspector-controls/index.js +3 -1
  156. package/build-module/query/edit/inspector-controls/index.js.map +1 -1
  157. package/build-module/query-pagination-numbers/index.js +1 -1
  158. package/build-module/search/edit.js +3 -5
  159. package/build-module/search/edit.js.map +1 -1
  160. package/build-module/search/index.js +0 -4
  161. package/build-module/search/index.js.map +1 -1
  162. package/build-module/site-logo/edit.js +7 -6
  163. package/build-module/site-logo/edit.js.map +1 -1
  164. package/build-module/spacer/edit.native.js +2 -2
  165. package/build-module/spacer/edit.native.js.map +1 -1
  166. package/build-module/tag-cloud/edit.js +6 -10
  167. package/build-module/tag-cloud/edit.js.map +1 -1
  168. package/build-module/utils/constants.js +9 -0
  169. package/build-module/utils/constants.js.map +1 -0
  170. package/build-module/video/edit.js +11 -8
  171. package/build-module/video/edit.js.map +1 -1
  172. package/build-style/button/editor-rtl.css +0 -37
  173. package/build-style/button/editor.css +0 -37
  174. package/build-style/button/style-rtl.css +6 -6
  175. package/build-style/button/style.css +6 -6
  176. package/build-style/editor-rtl.css +2 -44
  177. package/build-style/editor.css +2 -44
  178. package/build-style/navigation/editor-rtl.css +2 -4
  179. package/build-style/navigation/editor.css +2 -4
  180. package/build-style/navigation/style-rtl.css +14 -18
  181. package/build-style/navigation/style.css +14 -18
  182. package/build-style/search/style-rtl.css +26 -27
  183. package/build-style/search/style.css +26 -27
  184. package/build-style/style-rtl.css +46 -51
  185. package/build-style/style.css +46 -51
  186. package/build-style/table/editor-rtl.css +0 -3
  187. package/build-style/table/editor.css +0 -3
  188. package/package.json +32 -32
  189. package/src/audio/edit.js +19 -19
  190. package/src/audio/test/__snapshots__/edit.native.js.snap +12 -0
  191. package/src/audio/test/edit.native.js +29 -0
  192. package/src/block/edit.js +120 -66
  193. package/src/button/editor.scss +0 -43
  194. package/src/button/style.scss +6 -6
  195. package/src/buttons/test/__snapshots__/edit.native.js.snap +6 -0
  196. package/src/buttons/test/edit.native.js +49 -0
  197. package/src/comments-title/block.json +1 -1
  198. package/src/cover/edit/inspector-controls.js +1 -1
  199. package/src/cover/edit.native.js +1 -0
  200. package/src/embed/util.js +2 -2
  201. package/src/file/edit.js +17 -24
  202. package/src/gallery/block.json +4 -0
  203. package/src/gallery/edit.js +69 -42
  204. package/src/gallery/gallery.js +4 -1
  205. package/src/gallery/index.php +15 -0
  206. package/src/gallery/transforms.js +2 -55
  207. package/src/group/block.json +5 -1
  208. package/src/image/deprecated.js +8 -0
  209. package/src/image/edit.native.js +3 -0
  210. package/src/image/image.js +54 -35
  211. package/src/image/index.php +1 -6
  212. package/src/image/view.js +5 -2
  213. package/src/list/edit.js +27 -35
  214. package/src/list-item/edit.js +18 -2
  215. package/src/list-item/hooks/use-enter.js +63 -62
  216. package/src/list-item/hooks/use-enter.native.js +9 -5
  217. package/src/list-item/hooks/use-indent-list-item.js +43 -53
  218. package/src/list-item/hooks/use-merge.js +1 -1
  219. package/src/list-item/hooks/use-outdent-list-item.js +50 -69
  220. package/src/list-item/hooks/use-space.js +7 -4
  221. package/src/media-text/media-container.native.js +3 -1
  222. package/src/navigation/constants.js +2 -0
  223. package/src/navigation/edit/index.js +11 -1
  224. package/src/navigation/editor.scss +1 -1
  225. package/src/navigation/style.scss +18 -16
  226. package/src/navigation/view.js +29 -3
  227. package/src/paragraph/block.json +0 -1
  228. package/src/paragraph/test/__snapshots__/edit.native.js.snap +12 -0
  229. package/src/paragraph/test/edit.native.js +114 -0
  230. package/src/pattern/edit.js +35 -3
  231. package/src/pattern/index.php +16 -0
  232. package/src/pattern/recursion-detector.js +145 -0
  233. package/src/pattern/test/index.js +74 -0
  234. package/src/post-featured-image/block.json +4 -0
  235. package/src/post-featured-image/edit.js +32 -1
  236. package/src/post-featured-image/index.php +31 -0
  237. package/src/query/edit/inspector-controls/index.js +2 -0
  238. package/src/query-pagination-numbers/block.json +1 -1
  239. package/src/search/block.json +0 -4
  240. package/src/search/edit.js +2 -8
  241. package/src/search/index.php +3 -7
  242. package/src/search/style.scss +27 -29
  243. package/src/site-logo/edit.js +3 -4
  244. package/src/social-link/index.php +1 -1
  245. package/src/spacer/edit.native.js +4 -2
  246. package/src/table/editor.scss +0 -3
  247. package/src/tag-cloud/edit.js +7 -7
  248. package/src/template-part/index.php +6 -0
  249. package/src/utils/constants.js +8 -0
  250. package/src/video/edit.js +29 -27
@@ -5,7 +5,10 @@ import {
5
5
  addBlock,
6
6
  dismissModal,
7
7
  fireEvent,
8
+ getBlock,
9
+ getEditorHtml,
8
10
  initializeEditor,
11
+ openBlockSettings,
9
12
  render,
10
13
  screen,
11
14
  setupCoreBlocks,
@@ -31,6 +34,10 @@ jest.unmock( '@wordpress/react-native-aztec' );
31
34
 
32
35
  const MEDIA_UPLOAD_STATE_FAILED = 3;
33
36
 
37
+ const AUDIO_BLOCK = `<!-- wp:audio {"id":5} -->
38
+ <figure class="wp-block-audio"><audio controls src="https://cldup.com/59IrU0WJtq.mp3"></audio></figure>
39
+ <!-- /wp:audio -->`;
40
+
34
41
  let uploadCallBack;
35
42
  subscribeMediaUpload.mockImplementation( ( callback ) => {
36
43
  uploadCallBack = callback;
@@ -100,4 +107,26 @@ describe( 'Audio block', () => {
100
107
  screen.getByText( 'Invalid URL. Audio file not found.' )
101
108
  ).toBeVisible();
102
109
  } );
110
+
111
+ it( 'should enable autoplay setting', async () => {
112
+ await initializeEditor( { initialHtml: AUDIO_BLOCK } );
113
+
114
+ const audioBlock = getBlock( screen, 'Audio' );
115
+ fireEvent.press( audioBlock );
116
+ await openBlockSettings( screen );
117
+
118
+ fireEvent.press( screen.getByText( 'Autoplay' ) );
119
+ expect( getEditorHtml() ).toMatchSnapshot();
120
+ } );
121
+
122
+ it( 'should enable loop setting', async () => {
123
+ await initializeEditor( { initialHtml: AUDIO_BLOCK } );
124
+
125
+ const audioBlock = getBlock( screen, 'Audio' );
126
+ fireEvent.press( audioBlock );
127
+ await openBlockSettings( screen );
128
+
129
+ fireEvent.press( screen.getByText( 'Loop' ) );
130
+ expect( getEditorHtml() ).toMatchSnapshot();
131
+ } );
103
132
  } );
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 { parse, cloneBlock } from '@wordpress/blocks';
31
31
 
32
32
  /**
33
33
  * Internal dependencies
@@ -38,17 +38,17 @@ const { useLayoutClasses } = unlock( blockEditorPrivateApis );
38
38
 
39
39
  function isPartiallySynced( block ) {
40
40
  return (
41
- !! getBlockSupport( block.name, '__experimentalConnections', false ) &&
42
- !! block.attributes.connections?.attributes &&
43
- Object.values( block.attributes.connections.attributes ).some(
44
- ( connection ) => connection.source === 'pattern_attributes'
41
+ 'core/paragraph' === block.name &&
42
+ !! block.attributes.metadata?.bindings &&
43
+ Object.values( block.attributes.metadata.bindings ).some(
44
+ ( binding ) => binding.source.name === 'pattern_attributes'
45
45
  )
46
46
  );
47
47
  }
48
48
  function getPartiallySyncedAttributes( block ) {
49
- return Object.entries( block.attributes.connections.attributes )
49
+ return Object.entries( block.attributes.metadata.bindings )
50
50
  .filter(
51
- ( [ , connection ] ) => connection.source === 'pattern_attributes'
51
+ ( [ , binding ] ) => binding.source.name === 'pattern_attributes'
52
52
  )
53
53
  .map( ( [ attributeKey ] ) => attributeKey );
54
54
  }
@@ -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;
@@ -6,6 +6,12 @@ exports[`Buttons block color customization sets a background color 1`] = `
6
6
  <!-- /wp:buttons -->"
7
7
  `;
8
8
 
9
+ exports[`Buttons block color customization sets a custom gradient background color 1`] = `
10
+ "<!-- wp:buttons -->
11
+ <div class="wp-block-buttons"><!-- wp:button {"style":{"color":{"gradient":"linear-gradient(200deg,rgb(122,220,180) 0%,rgb(0,208,130) 100%)"}}} /--></div>
12
+ <!-- /wp:buttons -->"
13
+ `;
14
+
9
15
  exports[`Buttons block color customization sets a gradient background color 1`] = `
10
16
  "<!-- wp:buttons -->
11
17
  <div class="wp-block-buttons"><!-- wp:button {"gradient":"light-green-cyan-to-vivid-green-cyan"} /--></div>
@@ -10,6 +10,7 @@ import {
10
10
  initializeEditor,
11
11
  triggerBlockListLayout,
12
12
  typeInRichText,
13
+ openBlockSettings,
13
14
  waitFor,
14
15
  } from 'test/helpers';
15
16
 
@@ -391,5 +392,53 @@ describe( 'Buttons block', () => {
391
392
  // Assert
392
393
  expect( getEditorHtml() ).toMatchSnapshot();
393
394
  } );
395
+
396
+ it( 'sets a custom gradient background color', async () => {
397
+ // Arrange
398
+ const screen = await initializeEditor();
399
+ await addBlock( screen, 'Buttons' );
400
+
401
+ // Act
402
+ const buttonsBlock = getBlock( screen, 'Buttons' );
403
+ fireEvent.press( buttonsBlock );
404
+
405
+ // Trigger onLayout for the list
406
+ await triggerBlockListLayout( buttonsBlock );
407
+
408
+ const buttonBlock = await getBlock( screen, 'Button' );
409
+ fireEvent.press( buttonBlock );
410
+
411
+ // Open Block Settings.
412
+ await openBlockSettings( screen );
413
+
414
+ // Open Text color settings
415
+ fireEvent.press( screen.getByLabelText( 'Background, Default' ) );
416
+
417
+ // Tap on the gradient segment
418
+ fireEvent.press( screen.getByLabelText( 'Gradient' ) );
419
+
420
+ // Tap one gradient color
421
+ fireEvent.press(
422
+ screen.getByLabelText( 'Light green cyan to vivid green cyan' )
423
+ );
424
+
425
+ // Tap on Customize Gradient
426
+ fireEvent.press( screen.getByLabelText( /Customize Gradient/ ) );
427
+
428
+ // Change the current angle
429
+ fireEvent.press( screen.getByText( '135', { hidden: true } ) );
430
+ const angleTextInput = screen.getByDisplayValue( '135', {
431
+ hidden: true,
432
+ } );
433
+ fireEvent.changeText( angleTextInput, '200' );
434
+
435
+ // Go back to the settings list.
436
+ fireEvent.press( await screen.findByLabelText( 'Go back' ) );
437
+
438
+ // Assert
439
+ const customButton = await screen.findByText( 'CUSTOM' );
440
+ expect( customButton ).toBeVisible();
441
+ expect( getEditorHtml() ).toMatchSnapshot();
442
+ } );
394
443
  } );
395
444
  } );
@@ -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
  >
@@ -538,6 +538,7 @@ const Cover = ( {
538
538
  <BottomSheetConsumer>
539
539
  { ( { shouldEnableBottomSheetScroll } ) => (
540
540
  <ColorPalette
541
+ enableCustomColor={ true }
541
542
  customColorIndicatorStyles={
542
543
  styles.paletteColorIndicator
543
544
  }
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