@wordpress/block-library 10.4.0 → 10.5.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 (239) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/build/accordion/view.cjs +2 -5
  3. package/build/accordion/view.cjs.map +2 -2
  4. package/build/accordion-heading/block.json +1 -0
  5. package/build/audio/edit.cjs.map +2 -2
  6. package/build/avatar/edit.cjs.map +2 -2
  7. package/build/block/block.json +2 -1
  8. package/build/column/edit.cjs +1 -1
  9. package/build/column/edit.cjs.map +2 -2
  10. package/build/columns/edit.cjs.map +2 -2
  11. package/build/columns/transforms.cjs +161 -2
  12. package/build/columns/transforms.cjs.map +2 -2
  13. package/build/cover/edit/block-controls.cjs +1 -1
  14. package/build/cover/edit/block-controls.cjs.map +2 -2
  15. package/build/cover/edit/index.cjs +1 -1
  16. package/build/cover/edit/index.cjs.map +2 -2
  17. package/build/cover/edit/inspector-controls.cjs.map +3 -3
  18. package/build/embed/embed-placeholder.cjs.map +2 -2
  19. package/build/gallery/transforms.cjs +8 -0
  20. package/build/gallery/transforms.cjs.map +2 -2
  21. package/build/group/block.json +1 -1
  22. package/build/heading/transforms.cjs +36 -0
  23. package/build/heading/transforms.cjs.map +2 -2
  24. package/build/heading/variations.cjs +13 -1
  25. package/build/heading/variations.cjs.map +2 -2
  26. package/build/home-link/edit.cjs.map +3 -3
  27. package/build/icon/edit.cjs +7 -1
  28. package/build/icon/edit.cjs.map +2 -2
  29. package/build/image/image.cjs +1 -1
  30. package/build/image/image.cjs.map +3 -3
  31. package/build/list/block.json +1 -0
  32. package/build/math/edit.cjs +4 -5
  33. package/build/math/edit.cjs.map +3 -3
  34. package/build/media-text/edit.cjs.map +3 -3
  35. package/build/more/block.json +1 -1
  36. package/build/navigation-link/shared/controls.cjs.map +3 -3
  37. package/build/playlist/block.json +0 -1
  38. package/build/playlist/edit.cjs +46 -22
  39. package/build/playlist/edit.cjs.map +2 -2
  40. package/build/playlist-track/block.json +16 -8
  41. package/build/playlist-track/edit.cjs +74 -67
  42. package/build/playlist-track/edit.cjs.map +3 -3
  43. package/build/post-template/edit.cjs +5 -1
  44. package/build/post-template/edit.cjs.map +2 -2
  45. package/build/post-title/edit.cjs +3 -8
  46. package/build/post-title/edit.cjs.map +2 -2
  47. package/build/private-apis.cjs +0 -12
  48. package/build/private-apis.cjs.map +3 -3
  49. package/build/query/block.json +3 -0
  50. package/build/query-no-results/block.json +16 -1
  51. package/build/rss/edit.cjs.map +2 -2
  52. package/build/site-logo/edit.cjs +1 -1
  53. package/build/site-logo/edit.cjs.map +2 -2
  54. package/build/site-title/edit.cjs +2 -6
  55. package/build/site-title/edit.cjs.map +2 -2
  56. package/build/table-of-contents/block.json +2 -1
  57. package/build/table-of-contents/deprecated.cjs +165 -0
  58. package/build/table-of-contents/deprecated.cjs.map +7 -0
  59. package/build/table-of-contents/index.cjs +2 -2
  60. package/build/table-of-contents/index.cjs.map +3 -3
  61. package/build/tabs/view.cjs +32 -2
  62. package/build/tabs/view.cjs.map +2 -2
  63. package/build/term-template/edit.cjs +5 -1
  64. package/build/term-template/edit.cjs.map +2 -2
  65. package/build-module/accordion/view.mjs +2 -5
  66. package/build-module/accordion/view.mjs.map +2 -2
  67. package/build-module/accordion-heading/block.json +1 -0
  68. package/build-module/audio/edit.mjs.map +2 -2
  69. package/build-module/avatar/edit.mjs.map +2 -2
  70. package/build-module/block/block.json +2 -1
  71. package/build-module/column/edit.mjs +1 -1
  72. package/build-module/column/edit.mjs.map +2 -2
  73. package/build-module/columns/edit.mjs.map +2 -2
  74. package/build-module/columns/transforms.mjs +164 -3
  75. package/build-module/columns/transforms.mjs.map +2 -2
  76. package/build-module/cover/edit/block-controls.mjs +1 -1
  77. package/build-module/cover/edit/block-controls.mjs.map +2 -2
  78. package/build-module/cover/edit/index.mjs +1 -1
  79. package/build-module/cover/edit/index.mjs.map +2 -2
  80. package/build-module/cover/edit/inspector-controls.mjs +2 -2
  81. package/build-module/cover/edit/inspector-controls.mjs.map +2 -2
  82. package/build-module/embed/embed-placeholder.mjs +2 -2
  83. package/build-module/embed/embed-placeholder.mjs.map +1 -1
  84. package/build-module/gallery/transforms.mjs +8 -0
  85. package/build-module/gallery/transforms.mjs.map +2 -2
  86. package/build-module/group/block.json +1 -1
  87. package/build-module/heading/transforms.mjs +36 -0
  88. package/build-module/heading/transforms.mjs.map +2 -2
  89. package/build-module/heading/variations.mjs +13 -1
  90. package/build-module/heading/variations.mjs.map +2 -2
  91. package/build-module/home-link/edit.mjs +2 -2
  92. package/build-module/home-link/edit.mjs.map +2 -2
  93. package/build-module/icon/edit.mjs +7 -1
  94. package/build-module/icon/edit.mjs.map +2 -2
  95. package/build-module/image/image.mjs +4 -4
  96. package/build-module/image/image.mjs.map +2 -2
  97. package/build-module/list/block.json +1 -0
  98. package/build-module/math/edit.mjs +4 -8
  99. package/build-module/math/edit.mjs.map +2 -2
  100. package/build-module/media-text/edit.mjs +2 -2
  101. package/build-module/media-text/edit.mjs.map +2 -2
  102. package/build-module/more/block.json +1 -1
  103. package/build-module/navigation-link/shared/controls.mjs +2 -2
  104. package/build-module/navigation-link/shared/controls.mjs.map +2 -2
  105. package/build-module/playlist/block.json +0 -1
  106. package/build-module/playlist/edit.mjs +46 -22
  107. package/build-module/playlist/edit.mjs.map +2 -2
  108. package/build-module/playlist-track/block.json +16 -8
  109. package/build-module/playlist-track/edit.mjs +76 -69
  110. package/build-module/playlist-track/edit.mjs.map +2 -2
  111. package/build-module/post-template/edit.mjs +5 -1
  112. package/build-module/post-template/edit.mjs.map +2 -2
  113. package/build-module/post-title/edit.mjs +3 -8
  114. package/build-module/post-title/edit.mjs.map +2 -2
  115. package/build-module/private-apis.mjs +0 -2
  116. package/build-module/private-apis.mjs.map +2 -2
  117. package/build-module/query/block.json +3 -0
  118. package/build-module/query-no-results/block.json +16 -1
  119. package/build-module/rss/edit.mjs +2 -2
  120. package/build-module/rss/edit.mjs.map +1 -1
  121. package/build-module/site-logo/edit.mjs +1 -1
  122. package/build-module/site-logo/edit.mjs.map +2 -2
  123. package/build-module/site-title/edit.mjs +2 -6
  124. package/build-module/site-title/edit.mjs.map +2 -2
  125. package/build-module/table-of-contents/block.json +2 -1
  126. package/build-module/table-of-contents/deprecated.mjs +144 -0
  127. package/build-module/table-of-contents/deprecated.mjs.map +7 -0
  128. package/build-module/table-of-contents/index.mjs +2 -2
  129. package/build-module/table-of-contents/index.mjs.map +2 -2
  130. package/build-module/tabs/view.mjs +32 -2
  131. package/build-module/tabs/view.mjs.map +2 -2
  132. package/build-module/term-template/edit.mjs +5 -1
  133. package/build-module/term-template/edit.mjs.map +2 -2
  134. package/build-style/categories/style-rtl.css +2 -1
  135. package/build-style/categories/style.css +2 -1
  136. package/build-style/comments/editor-rtl.css +8 -10
  137. package/build-style/comments/editor.css +8 -10
  138. package/build-style/comments/style-rtl.css +8 -7
  139. package/build-style/comments/style.css +8 -7
  140. package/build-style/editor-rtl.css +8 -10
  141. package/build-style/editor.css +8 -10
  142. package/build-style/form-input/style-rtl.css +7 -7
  143. package/build-style/form-input/style.css +7 -7
  144. package/build-style/post-comments-form/style-rtl.css +7 -6
  145. package/build-style/post-comments-form/style.css +7 -6
  146. package/build-style/query-no-results/style-rtl.css +3 -0
  147. package/build-style/query-no-results/style.css +3 -0
  148. package/build-style/search/style-rtl.css +1 -1
  149. package/build-style/search/style.css +1 -1
  150. package/build-style/search/theme-rtl.css +1 -1
  151. package/build-style/search/theme.css +1 -1
  152. package/build-style/style-rtl.css +34 -23
  153. package/build-style/style.css +34 -23
  154. package/build-style/tab-panel/style-rtl.css +5 -1
  155. package/build-style/tab-panel/style.css +5 -1
  156. package/build-style/theme-rtl.css +1 -1
  157. package/build-style/theme.css +1 -1
  158. package/package.json +43 -43
  159. package/src/accordion/view.js +2 -5
  160. package/src/accordion-heading/README.md +1 -0
  161. package/src/accordion-heading/block.json +1 -0
  162. package/src/audio/edit.js +13 -0
  163. package/src/avatar/edit.js +78 -0
  164. package/src/block/README.md +1 -0
  165. package/src/block/block.json +2 -1
  166. package/src/categories/style.scss +4 -4
  167. package/src/column/edit.js +15 -1
  168. package/src/columns/edit.js +18 -0
  169. package/src/columns/test/transforms.js +517 -1
  170. package/src/columns/transforms.js +207 -2
  171. package/src/comments/style.scss +7 -10
  172. package/src/cover/edit/block-controls.js +1 -1
  173. package/src/cover/edit/index.js +1 -1
  174. package/src/cover/edit/inspector-controls.js +2 -2
  175. package/src/embed/embed-placeholder.js +2 -2
  176. package/src/form-input/style.scss +2 -2
  177. package/src/gallery/test/edit.js +57 -0
  178. package/src/gallery/test/transforms.js +57 -0
  179. package/src/gallery/transforms.js +8 -0
  180. package/src/group/README.md +1 -1
  181. package/src/group/block.json +1 -1
  182. package/src/heading/transforms.js +36 -0
  183. package/src/heading/variations.js +12 -0
  184. package/src/home-link/edit.js +2 -2
  185. package/src/icon/edit.js +9 -1
  186. package/src/image/image.js +4 -4
  187. package/src/list/README.md +1 -0
  188. package/src/list/block.json +1 -0
  189. package/src/math/edit.js +4 -9
  190. package/src/media-text/edit.js +2 -2
  191. package/src/more/README.md +1 -1
  192. package/src/more/block.json +1 -1
  193. package/src/navigation/index.php +8 -2
  194. package/src/navigation-link/shared/controls.js +2 -2
  195. package/src/playlist/block.json +0 -1
  196. package/src/playlist/edit.js +54 -21
  197. package/src/playlist/test/edit-component.js +78 -27
  198. package/src/playlist-track/README.md +8 -8
  199. package/src/playlist-track/block.json +16 -8
  200. package/src/playlist-track/edit.js +56 -27
  201. package/src/playlist-track/test/edit.js +145 -41
  202. package/src/post-comments-form/style.scss +7 -9
  203. package/src/post-template/edit.js +10 -1
  204. package/src/post-title/edit.js +2 -9
  205. package/src/private-apis.js +0 -2
  206. package/src/query/README.md +2 -0
  207. package/src/query/block.json +3 -0
  208. package/src/query-no-results/README.md +3 -0
  209. package/src/query-no-results/block.json +16 -1
  210. package/src/query-no-results/style.scss +5 -0
  211. package/src/rss/edit.js +2 -2
  212. package/src/search/style.scss +1 -1
  213. package/src/search/theme.scss +2 -4
  214. package/src/site-logo/edit.js +1 -1
  215. package/src/site-title/edit.js +1 -10
  216. package/src/social-link/index.php +6 -13
  217. package/src/style.scss +1 -0
  218. package/src/tab-panel/index.php +14 -5
  219. package/src/tab-panel/style.scss +7 -1
  220. package/src/table-of-contents/README.md +6 -6
  221. package/src/table-of-contents/block.json +2 -1
  222. package/src/table-of-contents/deprecated.js +173 -0
  223. package/src/table-of-contents/index.js +2 -2
  224. package/src/table-of-contents/index.php +16 -3
  225. package/src/tabs/index.php +5 -5
  226. package/src/tabs/view.js +32 -2
  227. package/src/term-description/index.php +1 -1
  228. package/src/term-template/edit.js +10 -1
  229. package/src/utils/test/waveform-player-dependency.js +0 -74
  230. package/build/block-keyboard-shortcuts/index.cjs +0 -131
  231. package/build/block-keyboard-shortcuts/index.cjs.map +0 -7
  232. package/build/table-of-contents/save.cjs +0 -55
  233. package/build/table-of-contents/save.cjs.map +0 -7
  234. package/build-module/block-keyboard-shortcuts/index.mjs +0 -113
  235. package/build-module/block-keyboard-shortcuts/index.mjs.map +0 -7
  236. package/build-module/table-of-contents/save.mjs +0 -24
  237. package/build-module/table-of-contents/save.mjs.map +0 -7
  238. package/src/block-keyboard-shortcuts/index.js +0 -135
  239. package/src/table-of-contents/save.js +0 -22
@@ -1,4 +1,4 @@
1
- import { fireEvent, render, screen } from '@testing-library/react';
1
+ import { act, fireEvent, render, screen, within } from '@testing-library/react';
2
2
  import { useDispatch } from '@wordpress/data';
3
3
  import PlaylistTrackEdit from '../edit';
4
4
  import { PlaylistContext } from '../../playlist/context';
@@ -6,44 +6,43 @@ import { useUploadMediaFromBlobURL } from '../../utils/hooks';
6
6
 
7
7
  let mockMediaReplaceFlowProps;
8
8
 
9
- jest.mock( '@wordpress/block-editor', () => ( {
10
- BlockControls: ( { children } ) => <div>{ children }</div>,
11
- BlockIcon: () => <span />,
12
- InspectorControls: ( { children } ) => <div>{ children }</div>,
13
- MediaPlaceholder: () => <div />,
14
- MediaReplaceFlow: ( props ) => {
15
- mockMediaReplaceFlowProps = props;
16
- const { name, onSelect } = props;
17
- return <button onClick={ () => onSelect( {} ) }>{ name }</button>;
18
- },
19
- MediaUpload: ( { render: renderMediaUpload } ) =>
20
- renderMediaUpload( { open: jest.fn() } ),
21
- MediaUploadCheck: ( { children } ) => <div>{ children }</div>,
22
- PlainText: ( {
23
- onChange,
24
- placeholder,
25
- tagName: TagName = 'div',
26
- value,
27
- __experimentalVersion,
28
- ...props
29
- } ) => <TagName { ...props }>{ value || placeholder }</TagName>,
30
- useBlockProps: jest.fn( () => ( {} ) ),
31
- } ) );
9
+ jest.mock( '@wordpress/block-editor', () => {
10
+ const PlainText = jest.requireActual(
11
+ '../../../../block-editor/src/components/plain-text'
12
+ ).default;
32
13
 
33
- jest.mock( '@wordpress/data', () => ( {
34
- useDispatch: jest.fn(),
35
- combineReducers: jest.fn( ( reducers ) => ( state = {}, action ) => {
36
- const newState = {};
37
- Object.keys( reducers ).forEach( ( key ) => {
38
- newState[ key ] = reducers[ key ]( state[ key ], action );
39
- } );
40
- return newState;
41
- } ),
42
- createRegistrySelector: jest.fn( ( fn ) => fn ),
43
- createReduxStore: jest.fn( () => ( {} ) ),
44
- createSelector: jest.fn( ( fn ) => fn ),
45
- register: jest.fn(),
46
- } ) );
14
+ return {
15
+ BlockControls: ( { children } ) => <div>{ children }</div>,
16
+ BlockIcon: () => <span />,
17
+ InspectorControls: ( { children } ) => <div>{ children }</div>,
18
+ MediaPlaceholder: () => <div />,
19
+ MediaReplaceFlow: ( props ) => {
20
+ mockMediaReplaceFlowProps = props;
21
+ const { name, onSelect } = props;
22
+ return <button onClick={ () => onSelect( {} ) }>{ name }</button>;
23
+ },
24
+ MediaUpload: ( { render: renderMediaUpload } ) =>
25
+ renderMediaUpload( { open: jest.fn() } ),
26
+ MediaUploadCheck: ( { children } ) => <div>{ children }</div>,
27
+ PlainText,
28
+ useBlockProps: jest.fn( () => ( {} ) ),
29
+ };
30
+ } );
31
+
32
+ jest.mock( '@wordpress/data', () => {
33
+ const data = jest.requireActual( '@wordpress/data' );
34
+ const mockUseDispatch = jest.fn();
35
+
36
+ return new Proxy( data, {
37
+ get( target, property ) {
38
+ if ( property === 'useDispatch' ) {
39
+ return mockUseDispatch;
40
+ }
41
+
42
+ return target[ property ];
43
+ },
44
+ } );
45
+ } );
47
46
 
48
47
  jest.mock( '@wordpress/notices', () => ( {
49
48
  store: 'core/notices',
@@ -53,6 +52,10 @@ jest.mock( '../../utils/hooks', () => ( {
53
52
  useUploadMediaFromBlobURL: jest.fn(),
54
53
  } ) );
55
54
 
55
+ // The handler only forwards the message to a notice, so its text is
56
+ // irrelevant to what these tests check.
57
+ const UPLOAD_ERROR = 'Upload failed.';
58
+
56
59
  const defaultAttributes = {
57
60
  id: 1,
58
61
  src: 'https://example.com/song.mp3',
@@ -67,12 +70,14 @@ const defaultAttributes = {
67
70
  function renderEdit( props = {} ) {
68
71
  const setAttributes = jest.fn();
69
72
  const setCurrentTrackClientId = props.setCurrentTrackClientId || jest.fn();
73
+ const removeTrack = props.removeTrack || jest.fn();
70
74
 
71
75
  render(
72
76
  <PlaylistContext.Provider
73
77
  value={ {
74
78
  currentTrackClientId: props.currentTrackClientId ?? null,
75
79
  setCurrentTrackClientId,
80
+ removeTrack,
76
81
  } }
77
82
  >
78
83
  <PlaylistTrackEdit
@@ -92,7 +97,7 @@ function renderEdit( props = {} ) {
92
97
  </PlaylistContext.Provider>
93
98
  );
94
99
 
95
- return { setAttributes, setCurrentTrackClientId };
100
+ return { setAttributes, setCurrentTrackClientId, removeTrack };
96
101
  }
97
102
 
98
103
  describe( 'PlaylistTrackEdit', () => {
@@ -104,6 +109,43 @@ describe( 'PlaylistTrackEdit', () => {
104
109
  useUploadMediaFromBlobURL.mockClear();
105
110
  } );
106
111
 
112
+ it( 'shows the title control for a single selected playlist track', () => {
113
+ renderEdit( { isSelected: true } );
114
+
115
+ expect(
116
+ screen.getByRole( 'textbox', { name: 'Title' } )
117
+ ).toBeInTheDocument();
118
+ } );
119
+
120
+ it( 'shows the replace track control for a single selected playlist track', () => {
121
+ renderEdit( { isSelected: true } );
122
+
123
+ expect( mockMediaReplaceFlowProps ).toBeDefined();
124
+ } );
125
+
126
+ it( 'does not show the replace track control when multiple playlist tracks are selected', () => {
127
+ renderEdit( { isSelected: false } );
128
+
129
+ expect( mockMediaReplaceFlowProps ).toBeUndefined();
130
+ } );
131
+
132
+ it( 'does not show the title control when multiple playlist tracks are selected', () => {
133
+ // The track inspector only renders for the selected block, or for the
134
+ // first block of a same-type multi-selection, where `isSelected` is
135
+ // false.
136
+ renderEdit( { isSelected: false } );
137
+
138
+ expect(
139
+ screen.queryByRole( 'textbox', { name: 'Title' } )
140
+ ).not.toBeInTheDocument();
141
+ expect(
142
+ screen.getByRole( 'textbox', { name: 'Artist' } )
143
+ ).toBeInTheDocument();
144
+ expect(
145
+ screen.getByRole( 'textbox', { name: 'Album' } )
146
+ ).toBeInTheDocument();
147
+ } );
148
+
107
149
  it( 'allows the track image alternative text to be edited', () => {
108
150
  const { setAttributes } = renderEdit();
109
151
 
@@ -169,6 +211,7 @@ describe( 'PlaylistTrackEdit', () => {
169
211
  renderEdit( {
170
212
  attributes: {
171
213
  blob: 'blob:https://example.com/temporary-track',
214
+ length: undefined,
172
215
  src: undefined,
173
216
  },
174
217
  } );
@@ -178,10 +221,71 @@ describe( 'PlaylistTrackEdit', () => {
178
221
  url: 'blob:https://example.com/temporary-track',
179
222
  } )
180
223
  );
224
+ const trackButton = screen.getByRole( 'button', {
225
+ name: /Song One/,
226
+ } );
227
+
228
+ expect(
229
+ within( trackButton ).getByRole( 'presentation', { hidden: true } )
230
+ ).toBeInTheDocument();
231
+ } );
232
+
233
+ it( 'removes the track when its initial upload fails', () => {
234
+ const createErrorNotice = jest.fn();
235
+ const removeBlock = jest.fn();
236
+ useDispatch.mockReturnValue( { createErrorNotice, removeBlock } );
237
+
238
+ const { removeTrack } = renderEdit( {
239
+ attributes: {
240
+ blob: 'blob:https://example.com/temporary-track',
241
+ id: undefined,
242
+ length: undefined,
243
+ src: undefined,
244
+ },
245
+ clientId: 'temporary-track',
246
+ } );
247
+
248
+ const { onError } = useUploadMediaFromBlobURL.mock.calls[ 0 ][ 0 ];
249
+ act( () => {
250
+ onError( UPLOAD_ERROR );
251
+ } );
252
+
253
+ expect( createErrorNotice ).toHaveBeenCalled();
254
+ // The playlist owns its inner blocks: removing the track directly
255
+ // would take an unmodified playlist with it.
256
+ expect( removeTrack ).toHaveBeenCalledWith( 'temporary-track' );
257
+ expect( removeBlock ).not.toHaveBeenCalled();
258
+ } );
259
+
260
+ // `onUploadError` also fires when replacing an existing track's media, so
261
+ // removing the block unconditionally would discard the original track.
262
+ it( 'keeps a track that already has a source when an upload fails', () => {
263
+ const createErrorNotice = jest.fn();
264
+ const removeBlock = jest.fn();
265
+ useDispatch.mockReturnValue( { createErrorNotice, removeBlock } );
266
+
267
+ const { setAttributes } = renderEdit( {
268
+ clientId: 'existing-track',
269
+ isSelected: true,
270
+ } );
271
+
272
+ // A failed replacement is reported by MediaReplaceFlow, not the
273
+ // blob uploader, which never runs for a track that has a source.
274
+ act( () => {
275
+ mockMediaReplaceFlowProps.onError( UPLOAD_ERROR );
276
+ } );
277
+
278
+ expect( createErrorNotice ).toHaveBeenCalled();
279
+ expect( removeBlock ).not.toHaveBeenCalled();
280
+ // The original track is left untouched, so its source still plays.
281
+ expect( setAttributes ).not.toHaveBeenCalled();
282
+ expect(
283
+ screen.getByRole( 'button', { name: /Song One/ } )
284
+ ).toBeInTheDocument();
181
285
  } );
182
286
 
183
287
  it( 'preserves the current track source when a replacement upload fails', () => {
184
- const { setAttributes } = renderEdit();
288
+ const { setAttributes } = renderEdit( { isSelected: true } );
185
289
 
186
290
  mockMediaReplaceFlowProps.onSelect();
187
291
 
@@ -192,7 +296,7 @@ describe( 'PlaylistTrackEdit', () => {
192
296
  } );
193
297
 
194
298
  it( 'accepts raw uploaded attachment data when replacing a track', () => {
195
- const { setAttributes } = renderEdit();
299
+ const { setAttributes } = renderEdit( { isSelected: true } );
196
300
 
197
301
  mockMediaReplaceFlowProps.onSelect( {
198
302
  id: 2,
@@ -59,15 +59,6 @@
59
59
  }
60
60
  }
61
61
 
62
- .comment-form-author,
63
- .comment-form-email,
64
- .comment-form-url {
65
- label {
66
- display: block;
67
- margin-bottom: 0.25em;
68
- }
69
- }
70
-
71
62
  .comment-form-cookies-consent {
72
63
  display: flex;
73
64
  gap: 0.25em;
@@ -85,3 +76,10 @@
85
76
  }
86
77
  }
87
78
  }
79
+
80
+ :where(.wp-block-post-comments-form .comment-form-author label),
81
+ :where(.wp-block-post-comments-form .comment-form-email label),
82
+ :where(.wp-block-post-comments-form .comment-form-url label) {
83
+ display: block;
84
+ margin-bottom: 0.25em;
85
+ }
@@ -14,10 +14,19 @@ import { Spinner, ToolbarGroup } from '@wordpress/components';
14
14
  import { store as coreStore } from '@wordpress/core-data';
15
15
  import { list, grid } from '@wordpress/icons';
16
16
 
17
+ // The Post Template's layout attribute arranges the post items, not the
18
+ // blocks of the template, which always stack vertically inside each post
19
+ // item. Override the inherited layout so inner block UI (movers, inserters,
20
+ // grid controls) doesn't follow the post items' grid.
21
+ const INNER_BLOCKS_LAYOUT = { type: 'default' };
22
+
17
23
  function PostTemplateInnerBlocks( { classList } ) {
18
24
  const innerBlocksProps = useInnerBlocksProps(
19
25
  { className: clsx( 'wp-block-post', classList ) },
20
- { __unstableDisableLayoutClassNames: true }
26
+ {
27
+ __unstableDisableLayoutClassNames: true,
28
+ layout: INNER_BLOCKS_LAYOUT,
29
+ }
21
30
  );
22
31
  return <li { ...innerBlocksProps } />;
23
32
  }
@@ -14,7 +14,6 @@ import {
14
14
  __experimentalToolsPanelItem as ToolsPanelItem,
15
15
  } from '@wordpress/components';
16
16
  import { __ } from '@wordpress/i18n';
17
- import { createBlock, getDefaultBlockName } from '@wordpress/blocks';
18
17
  import { useEntityProp, store as coreStore } from '@wordpress/core-data';
19
18
  import { useSelect } from '@wordpress/data';
20
19
  import { createInterpolateElement } from '@wordpress/element';
@@ -24,7 +23,6 @@ export default function PostTitleEdit( {
24
23
  attributes: { level, levelOptions, isLink, rel, linkTarget, placeholder },
25
24
  setAttributes,
26
25
  context: { postType, postId, queryId },
27
- insertBlocksAfter,
28
26
  } ) {
29
27
  const TagName = level === 0 ? 'p' : `h${ level }`;
30
28
  const isDescendentOfQueryLoop = Number.isFinite( queryId );
@@ -56,11 +54,6 @@ export default function PostTitleEdit( {
56
54
  postId
57
55
  );
58
56
  const [ link ] = useEntityProp( 'postType', postType, 'link', postId );
59
- const onSplitAtEnd = insertBlocksAfter
60
- ? () => {
61
- insertBlocksAfter( createBlock( getDefaultBlockName() ) );
62
- }
63
- : undefined;
64
57
  const blockProps = useBlockProps();
65
58
  const blockEditingMode = useBlockEditingMode();
66
59
  const dropdownMenuProps = useToolsPanelDropdownMenuProps();
@@ -77,7 +70,7 @@ export default function PostTitleEdit( {
77
70
  value={ rawTitle }
78
71
  onChange={ setTitle }
79
72
  __experimentalVersion={ 2 }
80
- __unstableOnSplitAtEnd={ onSplitAtEnd }
73
+ disableLineBreaks
81
74
  { ...blockProps }
82
75
  />
83
76
  ) : (
@@ -104,7 +97,7 @@ export default function PostTitleEdit( {
104
97
  value={ rawTitle }
105
98
  onChange={ setTitle }
106
99
  __experimentalVersion={ 2 }
107
- __unstableOnSplitAtEnd={ onSplitAtEnd }
100
+ disableLineBreaks
108
101
  />
109
102
  </TagName>
110
103
  ) : (
@@ -1,4 +1,3 @@
1
- import { default as BlockKeyboardShortcuts } from './block-keyboard-shortcuts';
2
1
  import { NAVIGATION_OVERLAY_TEMPLATE_PART_AREA } from './navigation/constants';
3
2
  import { NavigationLinkUI } from './navigation/edit/navigation-link-ui';
4
3
  import { lock } from './lock-unlock';
@@ -8,7 +7,6 @@ import { lock } from './lock-unlock';
8
7
  */
9
8
  export const privateApis = {};
10
9
  lock( privateApis, {
11
- BlockKeyboardShortcuts,
12
10
  NAVIGATION_OVERLAY_TEMPLATE_PART_AREA,
13
11
  NavigationLinkUI,
14
12
  } );
@@ -29,6 +29,8 @@ _Defined via the [`supports`](https://developer.wordpress.org/block-editor/refer
29
29
  - [`align`](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/#align): `"wide"`, `"full"`
30
30
  - [`html`](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/#html): `false`
31
31
  - [`layout`](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/#layout): `true`
32
+ - [`spacing`](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/#spacing):
33
+ - `blockGap`: `true`
32
34
  - [`interactivity`](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/#interactivity): `true`
33
35
 
34
36
  ## Context
@@ -55,6 +55,9 @@
55
55
  "align": [ "wide", "full" ],
56
56
  "html": false,
57
57
  "layout": true,
58
+ "spacing": {
59
+ "blockGap": true
60
+ },
58
61
  "interactivity": true
59
62
  },
60
63
  "editorStyle": "wp-block-query-editor"
@@ -30,6 +30,9 @@ _Defined via the [`supports`](https://developer.wordpress.org/block-editor/refer
30
30
  - [`color`](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/#color):
31
31
  - [`gradients`](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/#color-gradients): `true`
32
32
  - [`link`](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/#color-link): `true`
33
+ - [`spacing`](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/#spacing):
34
+ - `padding`: `true`
35
+ - `margin`: `true`
33
36
  - [`typography`](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/#typography):
34
37
  - [`fontSize`](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/#typography-fontsize): `true`
35
38
  - [`lineHeight`](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/#typography-lineheight): `true`
@@ -17,6 +17,14 @@
17
17
  "gradients": true,
18
18
  "link": true
19
19
  },
20
+ "spacing": {
21
+ "padding": true,
22
+ "margin": true,
23
+ "__experimentalDefaultControls": {
24
+ "margin": false,
25
+ "padding": false
26
+ }
27
+ },
20
28
  "typography": {
21
29
  "fontSize": true,
22
30
  "lineHeight": true,
@@ -32,6 +40,13 @@
32
40
  },
33
41
  "interactivity": {
34
42
  "clientNavigation": true
43
+ },
44
+ "__experimentalBorder": {
45
+ "radius": true,
46
+ "color": true,
47
+ "width": true,
48
+ "style": true
35
49
  }
36
- }
50
+ },
51
+ "style": "wp-block-query-no-results"
37
52
  }
@@ -0,0 +1,5 @@
1
+ // Lowest specificity so parent layout can still enforce width.
2
+ :where(.wp-block-query-no-results) {
3
+ // This block has customizable padding, border-box makes that more predictable.
4
+ box-sizing: border-box;
5
+ }
package/src/rss/edit.js CHANGED
@@ -12,7 +12,7 @@ import {
12
12
  ToolbarGroup,
13
13
  TextControl,
14
14
  ExternalLink,
15
- __experimentalInputControl as InputControl,
15
+ __experimentalInputControl as WCInputControl,
16
16
  __experimentalToolsPanel as ToolsPanel,
17
17
  __experimentalToolsPanelItem as ToolsPanelItem,
18
18
  } from '@wordpress/components';
@@ -88,7 +88,7 @@ export default function RSSEdit( { attributes, setAttributes, name } ) {
88
88
  onSubmit={ onSubmitURL }
89
89
  className="wp-block-rss__placeholder-form"
90
90
  >
91
- <InputControl
91
+ <WCInputControl
92
92
  label={ label }
93
93
  type="url"
94
94
  hideLabelFromVision
@@ -37,7 +37,7 @@ $button-spacing-y: math.div($grid-unit-15, 2); // 6px
37
37
  max-width: 100%;
38
38
  }
39
39
 
40
- .wp-block-search__label {
40
+ :where(.wp-block-search__label) {
41
41
  width: 100%;
42
42
  }
43
43
 
@@ -1,7 +1,5 @@
1
- .wp-block-search {
2
- .wp-block-search__label {
3
- font-weight: bold;
4
- }
1
+ :where(.wp-block-search .wp-block-search__label) {
2
+ font-weight: bold;
5
3
  }
6
4
 
7
5
  .wp-block-search__button {
@@ -344,7 +344,7 @@ const SiteLogo = ( {
344
344
  }
345
345
  aria-haspopup="dialog"
346
346
  icon={ crop }
347
- label={ __( 'Crop' ) }
347
+ label={ __( 'Edit image' ) }
348
348
  />
349
349
  </BlockControls>
350
350
  ) }
@@ -14,7 +14,6 @@ import {
14
14
  __experimentalToolsPanel as ToolsPanel,
15
15
  __experimentalToolsPanelItem as ToolsPanelItem,
16
16
  } from '@wordpress/components';
17
- import { createBlock, getDefaultBlockName } from '@wordpress/blocks';
18
17
  import { decodeEntities } from '@wordpress/html-entities';
19
18
  import { useToolsPanelDropdownMenuProps } from '../utils/hooks';
20
19
  import useDeprecatedTextAlign from '../utils/deprecated-text-align-attributes';
@@ -22,7 +21,7 @@ import useDeprecatedTextAlign from '../utils/deprecated-text-align-attributes';
22
21
  export default function SiteTitleEdit( props ) {
23
22
  useDeprecatedTextAlign( props );
24
23
 
25
- const { attributes, setAttributes, insertBlocksAfter } = props;
24
+ const { attributes, setAttributes } = props;
26
25
 
27
26
  const { level, levelOptions, isLink, linkTarget } = attributes;
28
27
  const { canUserEdit, title } = useSelect( ( select ) => {
@@ -66,14 +65,6 @@ export default function SiteTitleEdit( props ) {
66
65
  onChange={ setTitle }
67
66
  allowedFormats={ [] }
68
67
  disableLineBreaks
69
- __unstableOnSplitAtEnd={
70
- insertBlocksAfter
71
- ? () =>
72
- insertBlocksAfter(
73
- createBlock( getDefaultBlockName() )
74
- )
75
- : undefined
76
- }
77
68
  />
78
69
  </TagName>
79
70
  ) : (
@@ -10,10 +10,9 @@
10
10
  *
11
11
  * @since 5.4.0
12
12
  *
13
- * @param Array $attributes The block attributes.
14
- * @param String $content InnerBlocks content of the Block.
13
+ * @param array $attributes The block attributes.
14
+ * @param string $content InnerBlocks content of the Block.
15
15
  * @param WP_Block $block Block object.
16
- *
17
16
  * @return string Rendered HTML of the referenced block.
18
17
  */
19
18
  function render_block_core_social_link( $attributes, $content, $block ) {
@@ -39,7 +38,7 @@ function render_block_core_social_link( $attributes, $content, $block ) {
39
38
  return '';
40
39
  }
41
40
 
42
- /**
41
+ /*
43
42
  * Prepend emails with `mailto:` if not set.
44
43
  * The `is_email` returns false for emails with schema.
45
44
  */
@@ -47,7 +46,7 @@ function render_block_core_social_link( $attributes, $content, $block ) {
47
46
  $url = 'mailto:' . antispambot( $url );
48
47
  }
49
48
 
50
- /**
49
+ /*
51
50
  * Prepend URL with https:// if it doesn't appear to contain a scheme
52
51
  * and it's not a relative link or a fragment.
53
52
  */
@@ -95,14 +94,12 @@ function register_block_core_social_link() {
95
94
  }
96
95
  add_action( 'init', 'register_block_core_social_link' );
97
96
 
98
-
99
97
  /**
100
98
  * Returns the SVG for social link.
101
99
  *
102
100
  * @since 5.4.0
103
101
  *
104
102
  * @param string $service The service icon.
105
- *
106
103
  * @return string SVG Element for service icon.
107
104
  */
108
105
  function block_core_social_link_get_icon( $service ) {
@@ -120,7 +117,6 @@ function block_core_social_link_get_icon( $service ) {
120
117
  * @since 5.4.0
121
118
  *
122
119
  * @param string $service The service icon.
123
- *
124
120
  * @return string Brand label.
125
121
  */
126
122
  function block_core_social_link_get_name( $service ) {
@@ -138,8 +134,7 @@ function block_core_social_link_get_name( $service ) {
138
134
  * @since 5.4.0
139
135
  *
140
136
  * @param string $service The service slug to extract data from.
141
- * @param string $field The field ('name', 'icon', etc) to extract for a service.
142
- *
137
+ * @param string $field The field ('name', 'icon', etc) to extract for a service.
143
138
  * @return array|string
144
139
  */
145
140
  function block_core_social_link_services( $service = '', $field = '' ) {
@@ -346,7 +341,7 @@ function block_core_social_link_services( $service = '', $field = '' ) {
346
341
  );
347
342
 
348
343
  /**
349
- * Filter the list of available social service.
344
+ * Filters the list of available social service.
350
345
  *
351
346
  * This can be used to change icons or add custom icons (additionally to variations in the editor).
352
347
  * Icons should be directly renderable - therefore SVGs work best.
@@ -377,7 +372,6 @@ function block_core_social_link_services( $service = '', $field = '' ) {
377
372
  * @since 5.7.0
378
373
  *
379
374
  * @param array $context Block context passed to Social Link.
380
- *
381
375
  * @return string Inline CSS styles for link's icon and background colors.
382
376
  */
383
377
  function block_core_social_link_get_color_styles( $context ) {
@@ -400,7 +394,6 @@ function block_core_social_link_get_color_styles( $context ) {
400
394
  * @since 6.3.0
401
395
  *
402
396
  * @param array $context Block context passed to Social Sharing Link.
403
- *
404
397
  * @return string CSS classes for link's icon and background colors.
405
398
  */
406
399
  function block_core_social_link_get_color_classes( $context ) {
package/src/style.scss CHANGED
@@ -60,6 +60,7 @@
60
60
  @use "./preformatted/style.scss" as *;
61
61
  @use "./pullquote/style.scss" as *;
62
62
  @use "./post-template/style.scss" as *;
63
+ @use "./query-no-results/style.scss" as *;
63
64
  @use "./query-pagination/style.scss" as *;
64
65
  @use "./query-title/style.scss" as *;
65
66
  @use "./query-total/style.scss" as *;
@@ -22,10 +22,10 @@ function block_core_tab_panel_render( array $attributes, string $content, \WP_Bl
22
22
  static $tab_counters = array();
23
23
 
24
24
  if ( ! isset( $tab_counters[ $tabs_id ] ) ) {
25
- $tab_counters[ $tabs_id ] = 0;
25
+ $tab_counters[ $tabs_id ] = 1;
26
26
  }
27
27
 
28
- $tab_index = $tab_counters[ $tabs_id ];
28
+ $tab_number = $tab_counters[ $tabs_id ];
29
29
  ++$tab_counters[ $tabs_id ];
30
30
 
31
31
  $tag_processor = new WP_HTML_Tag_Processor( $content );
@@ -36,13 +36,22 @@ function block_core_tab_panel_render( array $attributes, string $content, \WP_Bl
36
36
  $tab_id = (string) $tag_processor->get_attribute( 'id' );
37
37
  if ( empty( $tab_id ) ) {
38
38
  $tab_id = ! empty( $tabs_id )
39
- ? $tabs_id . '-tab-' . $tab_index
40
- : 'tab-' . $tab_index;
39
+ ? $tabs_id . '-tab-' . $tab_number
40
+ : 'tab-' . $tab_number;
41
41
  $tag_processor->set_attribute( 'id', $tab_id );
42
42
  }
43
43
 
44
44
  $tag_processor->set_attribute( 'aria-labelledby', 'tab__' . $tab_id );
45
- $tag_processor->set_attribute( 'data-wp-bind--hidden', '!state.isActiveTab' );
45
+
46
+ /*
47
+ * Hiding a panel is left to the client, which is why `hidden` is bound to a
48
+ * state getter the server cannot resolve rather than set here: a visitor
49
+ * whose browser never runs the block's script is then given the content of
50
+ * every panel instead of none of it. `core/accordion` works the same way.
51
+ */
52
+ $tag_processor->set_attribute( 'data-wp-bind--hidden', 'state.isHidden' );
53
+ $tag_processor->set_attribute( 'data-wp-bind--tabindex', 'state.tabIndexAttribute' );
54
+ $tag_processor->set_attribute( 'data-wp-on--beforematch', 'actions.handleBeforeMatch' );
46
55
 
47
56
  return (string) $tag_processor->get_updated_html();
48
57
  }
@@ -1,6 +1,12 @@
1
1
  .wp-block-tab-panel {
2
- &[hidden],
3
2
  &:empty {
4
3
  display: none !important;
5
4
  }
5
+
6
+ // Prevent blockGap and padding from adding extra spacing when the panel is
7
+ // closed, which the panel would otherwise keep along with its layout box.
8
+ &[hidden] {
9
+ margin-block-start: 0;
10
+ padding: 0 !important;
11
+ }
6
12
  }