@wordpress/block-library 9.35.1-next.16d95556a.0 → 9.36.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 (311) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/build/accordion/view.js +46 -4
  3. package/build/accordion/view.js.map +2 -2
  4. package/build/accordion-heading/block.json +1 -1
  5. package/build/accordion-heading/deprecated.js +1 -1
  6. package/build/accordion-heading/deprecated.js.map +2 -2
  7. package/build/accordion-panel/block.json +1 -1
  8. package/build/audio/index.js +29 -0
  9. package/build/audio/index.js.map +3 -3
  10. package/build/breadcrumbs/edit.js +1 -1
  11. package/build/breadcrumbs/edit.js.map +2 -2
  12. package/build/button/index.js +25 -0
  13. package/build/button/index.js.map +3 -3
  14. package/build/code/index.js +15 -0
  15. package/build/code/index.js.map +3 -3
  16. package/build/cover/edit/block-controls.js +37 -3
  17. package/build/cover/edit/block-controls.js.map +3 -3
  18. package/build/cover/edit/cover-placeholder.js +0 -1
  19. package/build/cover/edit/cover-placeholder.js.map +2 -2
  20. package/build/cover/edit/embed-video-url-input.js +83 -0
  21. package/build/cover/edit/embed-video-url-input.js.map +7 -0
  22. package/build/cover/edit/index.js +60 -0
  23. package/build/cover/edit/index.js.map +2 -2
  24. package/build/cover/embed-video-utils.js +151 -0
  25. package/build/cover/embed-video-utils.js.map +7 -0
  26. package/build/cover/index.js +28 -0
  27. package/build/cover/index.js.map +3 -3
  28. package/build/cover/save.js +12 -0
  29. package/build/cover/save.js.map +2 -2
  30. package/build/cover/shared.js +3 -0
  31. package/build/cover/shared.js.map +2 -2
  32. package/build/details/index.js +15 -0
  33. package/build/details/index.js.map +3 -3
  34. package/build/file/index.js +33 -0
  35. package/build/file/index.js.map +3 -3
  36. package/build/freeform/block.json +1 -1
  37. package/build/gallery/edit.js +0 -2
  38. package/build/gallery/edit.js.map +2 -2
  39. package/build/heading/index.js +15 -0
  40. package/build/heading/index.js.map +3 -3
  41. package/build/html/modal.js +139 -148
  42. package/build/html/modal.js.map +3 -3
  43. package/build/image/edit.js +0 -1
  44. package/build/image/edit.js.map +2 -2
  45. package/build/image/image.js +0 -1
  46. package/build/image/image.js.map +2 -2
  47. package/build/image/index.js +46 -0
  48. package/build/image/index.js.map +3 -3
  49. package/build/list-item/index.js +15 -0
  50. package/build/list-item/index.js.map +3 -3
  51. package/build/math/block.json +28 -1
  52. package/build/math/edit.js +4 -1
  53. package/build/math/edit.js.map +2 -2
  54. package/build/media-text/index.js +35 -0
  55. package/build/media-text/index.js.map +3 -3
  56. package/build/media-text/media-container.js +0 -2
  57. package/build/media-text/media-container.js.map +2 -2
  58. package/build/missing/block.json +1 -1
  59. package/build/missing/edit.js +2 -2
  60. package/build/missing/edit.js.map +1 -1
  61. package/build/more/index.js +16 -0
  62. package/build/more/index.js.map +3 -3
  63. package/build/navigation/block.json +2 -2
  64. package/build/navigation-link/block.json +2 -1
  65. package/build/navigation-link/edit.js +42 -11
  66. package/build/navigation-link/edit.js.map +2 -2
  67. package/build/navigation-link/index.js +25 -0
  68. package/build/navigation-link/index.js.map +3 -3
  69. package/build/navigation-link/shared/controls.js +15 -19
  70. package/build/navigation-link/shared/controls.js.map +2 -2
  71. package/build/navigation-link/shared/index.js +4 -0
  72. package/build/navigation-link/shared/index.js.map +2 -2
  73. package/build/navigation-link/shared/use-entity-binding.js +3 -2
  74. package/build/navigation-link/shared/use-entity-binding.js.map +2 -2
  75. package/build/navigation-submenu/block.json +2 -1
  76. package/build/navigation-submenu/index.js +25 -0
  77. package/build/navigation-submenu/index.js.map +3 -3
  78. package/build/paragraph/deprecated-attributes.js +68 -0
  79. package/build/paragraph/deprecated-attributes.js.map +7 -0
  80. package/build/paragraph/edit.js +2 -0
  81. package/build/paragraph/edit.js.map +3 -3
  82. package/build/paragraph/index.js +15 -0
  83. package/build/paragraph/index.js.map +3 -3
  84. package/build/pattern/block.json +1 -1
  85. package/build/post-comments-count/edit.js +1 -2
  86. package/build/post-comments-count/edit.js.map +2 -2
  87. package/build/post-comments-link/edit.js +10 -7
  88. package/build/post-comments-link/edit.js.map +2 -2
  89. package/build/preformatted/index.js +15 -0
  90. package/build/preformatted/index.js.map +3 -3
  91. package/build/pullquote/index.js +20 -0
  92. package/build/pullquote/index.js.map +3 -3
  93. package/build/search/index.js +26 -0
  94. package/build/search/index.js.map +3 -3
  95. package/build/social-link/index.js +25 -0
  96. package/build/social-link/index.js.map +3 -3
  97. package/build/social-links/edit.js +1 -1
  98. package/build/social-links/edit.js.map +1 -1
  99. package/build/tabs/view.js +17 -4
  100. package/build/tabs/view.js.map +2 -2
  101. package/build/template-part/edit/index.js +37 -7
  102. package/build/template-part/edit/index.js.map +2 -2
  103. package/build/template-part/edit/utils/hooks.js +2 -3
  104. package/build/template-part/edit/utils/hooks.js.map +2 -2
  105. package/build/term-count/index.js +1 -0
  106. package/build/term-count/index.js.map +2 -2
  107. package/build/term-name/index.js +1 -0
  108. package/build/term-name/index.js.map +2 -2
  109. package/build/verse/index.js +15 -0
  110. package/build/verse/index.js.map +3 -3
  111. package/build/video/index.js +30 -0
  112. package/build/video/index.js.map +3 -3
  113. package/build-module/accordion/view.js +46 -4
  114. package/build-module/accordion/view.js.map +2 -2
  115. package/build-module/accordion-heading/block.json +1 -1
  116. package/build-module/accordion-heading/deprecated.js +1 -1
  117. package/build-module/accordion-heading/deprecated.js.map +2 -2
  118. package/build-module/accordion-panel/block.json +1 -1
  119. package/build-module/audio/index.js +29 -0
  120. package/build-module/audio/index.js.map +2 -2
  121. package/build-module/breadcrumbs/edit.js +1 -1
  122. package/build-module/breadcrumbs/edit.js.map +2 -2
  123. package/build-module/button/index.js +25 -0
  124. package/build-module/button/index.js.map +2 -2
  125. package/build-module/code/index.js +15 -0
  126. package/build-module/code/index.js.map +2 -2
  127. package/build-module/cover/edit/block-controls.js +27 -3
  128. package/build-module/cover/edit/block-controls.js.map +2 -2
  129. package/build-module/cover/edit/cover-placeholder.js +0 -1
  130. package/build-module/cover/edit/cover-placeholder.js.map +2 -2
  131. package/build-module/cover/edit/embed-video-url-input.js +67 -0
  132. package/build-module/cover/edit/embed-video-url-input.js.map +7 -0
  133. package/build-module/cover/edit/index.js +61 -0
  134. package/build-module/cover/edit/index.js.map +2 -2
  135. package/build-module/cover/embed-video-utils.js +122 -0
  136. package/build-module/cover/embed-video-utils.js.map +7 -0
  137. package/build-module/cover/index.js +28 -0
  138. package/build-module/cover/index.js.map +2 -2
  139. package/build-module/cover/save.js +13 -0
  140. package/build-module/cover/save.js.map +2 -2
  141. package/build-module/cover/shared.js +2 -0
  142. package/build-module/cover/shared.js.map +2 -2
  143. package/build-module/details/index.js +15 -0
  144. package/build-module/details/index.js.map +2 -2
  145. package/build-module/file/index.js +34 -1
  146. package/build-module/file/index.js.map +2 -2
  147. package/build-module/freeform/block.json +1 -1
  148. package/build-module/gallery/edit.js +0 -2
  149. package/build-module/gallery/edit.js.map +2 -2
  150. package/build-module/heading/index.js +15 -0
  151. package/build-module/heading/index.js.map +2 -2
  152. package/build-module/html/modal.js +141 -150
  153. package/build-module/html/modal.js.map +2 -2
  154. package/build-module/image/edit.js +0 -1
  155. package/build-module/image/edit.js.map +2 -2
  156. package/build-module/image/image.js +0 -1
  157. package/build-module/image/image.js.map +2 -2
  158. package/build-module/image/index.js +46 -0
  159. package/build-module/image/index.js.map +2 -2
  160. package/build-module/list-item/index.js +15 -0
  161. package/build-module/list-item/index.js.map +2 -2
  162. package/build-module/math/block.json +28 -1
  163. package/build-module/math/edit.js +4 -1
  164. package/build-module/math/edit.js.map +2 -2
  165. package/build-module/media-text/index.js +35 -0
  166. package/build-module/media-text/index.js.map +2 -2
  167. package/build-module/media-text/media-container.js +0 -2
  168. package/build-module/media-text/media-container.js.map +2 -2
  169. package/build-module/missing/block.json +1 -1
  170. package/build-module/missing/edit.js +2 -2
  171. package/build-module/missing/edit.js.map +1 -1
  172. package/build-module/more/index.js +16 -0
  173. package/build-module/more/index.js.map +2 -2
  174. package/build-module/navigation/block.json +2 -2
  175. package/build-module/navigation-link/block.json +2 -1
  176. package/build-module/navigation-link/edit.js +56 -15
  177. package/build-module/navigation-link/edit.js.map +2 -2
  178. package/build-module/navigation-link/index.js +26 -1
  179. package/build-module/navigation-link/index.js.map +2 -2
  180. package/build-module/navigation-link/shared/controls.js +12 -18
  181. package/build-module/navigation-link/shared/controls.js.map +2 -2
  182. package/build-module/navigation-link/shared/index.js +3 -1
  183. package/build-module/navigation-link/shared/index.js.map +2 -2
  184. package/build-module/navigation-link/shared/use-entity-binding.js +3 -2
  185. package/build-module/navigation-link/shared/use-entity-binding.js.map +2 -2
  186. package/build-module/navigation-submenu/block.json +2 -1
  187. package/build-module/navigation-submenu/index.js +26 -1
  188. package/build-module/navigation-submenu/index.js.map +2 -2
  189. package/build-module/paragraph/deprecated-attributes.js +37 -0
  190. package/build-module/paragraph/deprecated-attributes.js.map +7 -0
  191. package/build-module/paragraph/edit.js +2 -0
  192. package/build-module/paragraph/edit.js.map +2 -2
  193. package/build-module/paragraph/index.js +15 -0
  194. package/build-module/paragraph/index.js.map +2 -2
  195. package/build-module/pattern/block.json +1 -1
  196. package/build-module/post-comments-count/edit.js +1 -3
  197. package/build-module/post-comments-count/edit.js.map +2 -2
  198. package/build-module/post-comments-link/edit.js +10 -8
  199. package/build-module/post-comments-link/edit.js.map +2 -2
  200. package/build-module/preformatted/index.js +15 -0
  201. package/build-module/preformatted/index.js.map +2 -2
  202. package/build-module/pullquote/index.js +20 -0
  203. package/build-module/pullquote/index.js.map +2 -2
  204. package/build-module/search/index.js +26 -0
  205. package/build-module/search/index.js.map +2 -2
  206. package/build-module/social-link/index.js +25 -0
  207. package/build-module/social-link/index.js.map +2 -2
  208. package/build-module/social-links/edit.js +1 -1
  209. package/build-module/social-links/edit.js.map +1 -1
  210. package/build-module/tabs/view.js +17 -4
  211. package/build-module/tabs/view.js.map +2 -2
  212. package/build-module/template-part/edit/index.js +37 -7
  213. package/build-module/template-part/edit/index.js.map +2 -2
  214. package/build-module/template-part/edit/utils/hooks.js +2 -3
  215. package/build-module/template-part/edit/utils/hooks.js.map +2 -2
  216. package/build-module/term-count/index.js +1 -0
  217. package/build-module/term-count/index.js.map +2 -2
  218. package/build-module/term-name/index.js +1 -0
  219. package/build-module/term-name/index.js.map +2 -2
  220. package/build-module/verse/index.js +15 -0
  221. package/build-module/verse/index.js.map +2 -2
  222. package/build-module/video/index.js +30 -0
  223. package/build-module/video/index.js.map +2 -2
  224. package/build-style/accordion/style-rtl.css +3 -0
  225. package/build-style/accordion/style.css +3 -0
  226. package/build-style/accordion-heading/style-rtl.css +1 -2
  227. package/build-style/accordion-heading/style.css +1 -2
  228. package/build-style/accordion-item/style-rtl.css +0 -7
  229. package/build-style/accordion-item/style.css +0 -7
  230. package/build-style/accordion-panel/style-rtl.css +1 -4
  231. package/build-style/accordion-panel/style.css +1 -4
  232. package/build-style/cover/style-rtl.css +47 -0
  233. package/build-style/cover/style.css +47 -0
  234. package/build-style/editor-rtl.css +11 -13
  235. package/build-style/editor.css +11 -13
  236. package/build-style/html/editor-rtl.css +11 -13
  237. package/build-style/html/editor.css +11 -13
  238. package/build-style/style-rtl.css +52 -12
  239. package/build-style/style.css +52 -12
  240. package/package.json +37 -37
  241. package/src/accordion/style.scss +4 -0
  242. package/src/accordion/view.js +60 -3
  243. package/src/accordion-heading/block.json +1 -1
  244. package/src/accordion-heading/deprecated.js +1 -1
  245. package/src/accordion-heading/style.scss +1 -9
  246. package/src/accordion-item/index.php +1 -0
  247. package/src/accordion-item/style.scss +2 -9
  248. package/src/accordion-panel/block.json +1 -1
  249. package/src/accordion-panel/style.scss +1 -5
  250. package/src/audio/index.js +31 -0
  251. package/src/breadcrumbs/edit.js +4 -2
  252. package/src/breadcrumbs/index.php +171 -100
  253. package/src/button/index.js +27 -0
  254. package/src/code/index.js +17 -0
  255. package/src/cover/edit/block-controls.js +26 -2
  256. package/src/cover/edit/cover-placeholder.js +0 -1
  257. package/src/cover/edit/embed-video-url-input.js +74 -0
  258. package/src/cover/edit/index.js +81 -0
  259. package/src/cover/embed-video-utils.js +196 -0
  260. package/src/cover/index.js +30 -0
  261. package/src/cover/index.php +106 -0
  262. package/src/cover/save.js +14 -0
  263. package/src/cover/shared.js +1 -0
  264. package/src/cover/style.scss +47 -0
  265. package/src/details/index.js +17 -0
  266. package/src/file/index.js +36 -1
  267. package/src/freeform/block.json +1 -1
  268. package/src/gallery/edit.js +0 -2
  269. package/src/heading/index.js +17 -0
  270. package/src/html/editor.scss +10 -15
  271. package/src/html/modal.js +23 -38
  272. package/src/image/edit.js +0 -1
  273. package/src/image/image.js +0 -1
  274. package/src/image/index.js +48 -0
  275. package/src/image/index.php +1 -0
  276. package/src/list-item/index.js +17 -0
  277. package/src/math/block.json +28 -1
  278. package/src/math/edit.js +4 -1
  279. package/src/media-text/index.js +37 -0
  280. package/src/media-text/media-container.js +0 -2
  281. package/src/missing/block.json +1 -1
  282. package/src/missing/edit.js +2 -2
  283. package/src/more/index.js +18 -0
  284. package/src/navigation/block.json +2 -2
  285. package/src/navigation-link/block.json +2 -1
  286. package/src/navigation-link/edit.js +98 -29
  287. package/src/navigation-link/index.js +28 -1
  288. package/src/navigation-link/shared/controls.js +13 -17
  289. package/src/navigation-link/shared/index.js +1 -1
  290. package/src/navigation-link/shared/use-entity-binding.js +5 -2
  291. package/src/navigation-submenu/block.json +2 -1
  292. package/src/navigation-submenu/index.js +28 -1
  293. package/src/paragraph/deprecated-attributes.js +45 -0
  294. package/src/paragraph/edit.js +2 -0
  295. package/src/paragraph/index.js +17 -0
  296. package/src/pattern/block.json +1 -1
  297. package/src/post-comments-count/edit.js +1 -9
  298. package/src/post-comments-link/edit.js +8 -18
  299. package/src/preformatted/index.js +17 -0
  300. package/src/pullquote/index.js +22 -0
  301. package/src/search/index.js +28 -0
  302. package/src/social-link/index.js +27 -0
  303. package/src/social-links/edit.js +1 -1
  304. package/src/style.scss +1 -0
  305. package/src/tabs/view.js +19 -4
  306. package/src/template-part/edit/index.js +44 -6
  307. package/src/template-part/edit/utils/hooks.js +2 -4
  308. package/src/term-count/index.js +1 -0
  309. package/src/term-name/index.js +1 -0
  310. package/src/verse/index.js +17 -0
  311. package/src/video/index.js +32 -0
@@ -8,9 +8,13 @@ import clsx from 'clsx';
8
8
  */
9
9
  import { createBlock } from '@wordpress/blocks';
10
10
  import { useSelect, useDispatch } from '@wordpress/data';
11
- import { ToolbarButton, ToolbarGroup } from '@wordpress/components';
11
+ import {
12
+ ToolbarButton,
13
+ ToolbarGroup,
14
+ VisuallyHidden,
15
+ } from '@wordpress/components';
12
16
  import { displayShortcut, isKeyboardEvent } from '@wordpress/keycodes';
13
- import { __ } from '@wordpress/i18n';
17
+ import { __, sprintf } from '@wordpress/i18n';
14
18
  import {
15
19
  BlockControls,
16
20
  InspectorControls,
@@ -26,13 +30,19 @@ import { useState, useEffect, useRef, useCallback } from '@wordpress/element';
26
30
  import { decodeEntities } from '@wordpress/html-entities';
27
31
  import { link as linkIcon, addSubmenu } from '@wordpress/icons';
28
32
  import { store as coreStore } from '@wordpress/core-data';
29
- import { useMergeRefs, usePrevious } from '@wordpress/compose';
33
+ import { useMergeRefs, useInstanceId } from '@wordpress/compose';
30
34
 
31
35
  /**
32
36
  * Internal dependencies
33
37
  */
34
38
  import { getColors } from '../navigation/edit/utils';
35
- import { Controls, LinkUI, updateAttributes, useEntityBinding } from './shared';
39
+ import {
40
+ Controls,
41
+ LinkUI,
42
+ updateAttributes,
43
+ useEntityBinding,
44
+ MissingEntityHelpText,
45
+ } from './shared';
36
46
 
37
47
  const DEFAULT_BLOCK = { name: 'core/navigation-link' };
38
48
  const NESTING_BLOCK_NAMES = [
@@ -203,8 +213,11 @@ export default function NavigationLinkEdit( {
203
213
  const itemLabelPlaceholder = __( 'Add label…' );
204
214
  const ref = useRef();
205
215
  const linkUIref = useRef();
206
- const prevUrl = usePrevious( url );
207
- const isNewLink = useRef( ! url );
216
+ // A link is "new" only if it has an undefined label
217
+ // After the link is created, even if no label is provided, it's set to an empty string.
218
+ const isNewLink = useRef( label === undefined );
219
+ // Track whether we should focus the submenu appender when closing the link UI
220
+ const shouldSelectSubmenuAppenderOnClose = useRef( false );
208
221
 
209
222
  const {
210
223
  isAtMaxNesting,
@@ -213,6 +226,7 @@ export default function NavigationLinkEdit( {
213
226
  hasChildren,
214
227
  validateLinkStatus,
215
228
  parentBlockClientId,
229
+ isSubmenu,
216
230
  } = useSelect(
217
231
  ( select ) => {
218
232
  const {
@@ -257,6 +271,7 @@ export default function NavigationLinkEdit( {
257
271
  hasChildren: !! getBlockCount( clientId ),
258
272
  validateLinkStatus: enableLinkStatusValidation,
259
273
  parentBlockClientId: parentBlockId,
274
+ isSubmenu: parentBlockName === 'core/navigation-submenu',
260
275
  };
261
276
  },
262
277
  [ clientId, maxNestingLevel ]
@@ -304,7 +319,7 @@ export default function NavigationLinkEdit( {
304
319
  // If we leave focus on this block, then when we close the link without creating a link, focus will
305
320
  // be lost during the new block selection process.
306
321
  useEffect( () => {
307
- if ( isNewLink.current && isSelected && ! url ) {
322
+ if ( isNewLink.current && isSelected ) {
308
323
  selectBlock( parentBlockClientId );
309
324
  }
310
325
  }, [] ); // eslint-disable-line react-hooks/exhaustive-deps
@@ -323,20 +338,46 @@ export default function NavigationLinkEdit( {
323
338
  transformToSubmenu,
324
339
  ] );
325
340
 
326
- // If the LinkControl popover is open and the URL has changed, close the LinkControl and focus the label text.
341
+ // Handle link UI when a new link is created
327
342
  useEffect( () => {
328
- // We only want to do this when the URL has gone from nothing to a new URL AND the label looks like a URL
329
- if (
330
- ! prevUrl &&
331
- url &&
332
- isLinkOpen &&
333
- isURL( prependHTTP( label ) ) &&
334
- /^.+\.[a-z]+/.test( label )
335
- ) {
343
+ // We know if a link was just created from our link UI if
344
+ // 1. isNewLink.current is true
345
+ // 2. url has a value
346
+ // 3. isLinkOpen is true
347
+ if ( ! isNewLink.current || ! url || ! isLinkOpen ) {
348
+ return;
349
+ }
350
+
351
+ // Ensure this only runs once
352
+ isNewLink.current = false;
353
+
354
+ // We just created a link and the block is now selected.
355
+ // If the label looks like a URL, focus and select the label text.
356
+ if ( isURL( prependHTTP( label ) ) && /^.+\.[a-z]+/.test( label ) ) {
336
357
  // Focus and select the label text.
337
358
  selectLabelText();
359
+ } else {
360
+ // If the link was just created, we want to select the block so the inspector controls
361
+ // are accurate.
362
+ selectBlock( clientId, null );
363
+
364
+ // Edge case: When the created link is the first child of a submenu, the focus will have
365
+ // originated from the add submenu toolbar button. In this case, we need to return focus
366
+ // to the submenu appender if the user closes the link ui using the keyboard.
367
+ // Check if this is the first and only child of a newly created submenu.
368
+ if ( isSubmenu ) {
369
+ const parentBlocks = getBlocks( parentBlockClientId );
370
+ // If this is the only child, then this is a new submenu.
371
+ // Set the flag to select the submenu appender when the link ui is closed.
372
+ if (
373
+ parentBlocks.length === 1 &&
374
+ parentBlocks[ 0 ].clientId === clientId
375
+ ) {
376
+ shouldSelectSubmenuAppenderOnClose.current = true;
377
+ }
378
+ }
338
379
  }
339
- }, [ prevUrl, url, isLinkOpen, label ] );
380
+ }, [ url, isLinkOpen, isNewLink, label ] );
340
381
 
341
382
  /**
342
383
  * Focus the Link label text and select it.
@@ -394,6 +435,12 @@ export default function NavigationLinkEdit( {
394
435
  }
395
436
  }
396
437
 
438
+ const instanceId = useInstanceId( NavigationLinkEdit );
439
+ const hasMissingEntity = hasUrlBinding && ! isBoundEntityAvailable;
440
+ const missingEntityDescriptionId = hasMissingEntity
441
+ ? sprintf( 'navigation-link-edit-%d-desc', instanceId )
442
+ : undefined;
443
+
397
444
  const blockProps = useBlockProps( {
398
445
  ref: useMergeRefs( [ setPopoverAnchor, listItemRef ] ),
399
446
  className: clsx( 'wp-block-navigation-item', {
@@ -407,6 +454,8 @@ export default function NavigationLinkEdit( {
407
454
  [ getColorClassName( 'background-color', backgroundColor ) ]:
408
455
  !! backgroundColor,
409
456
  } ),
457
+ 'aria-describedby': missingEntityDescriptionId,
458
+ 'aria-invalid': hasMissingEntity,
410
459
  style: {
411
460
  color: ! textColor && customTextColor,
412
461
  backgroundColor: ! backgroundColor && customBackgroundColor,
@@ -426,23 +475,20 @@ export default function NavigationLinkEdit( {
426
475
  }
427
476
  );
428
477
 
429
- if (
430
- ! url ||
478
+ const needsValidLink =
479
+ ( ! url && ! ( hasUrlBinding && isBoundEntityAvailable ) ) ||
431
480
  isInvalid ||
432
481
  isDraft ||
433
- ( hasUrlBinding && ! isBoundEntityAvailable )
434
- ) {
482
+ ( hasUrlBinding && ! isBoundEntityAvailable );
483
+
484
+ if ( needsValidLink ) {
435
485
  blockProps.onClick = () => {
436
486
  setIsLinkOpen( true );
437
487
  };
438
488
  }
439
489
 
440
490
  const classes = clsx( 'wp-block-navigation-item__content', {
441
- 'wp-block-navigation-link__placeholder':
442
- ! url ||
443
- isInvalid ||
444
- isDraft ||
445
- ( hasUrlBinding && ! isBoundEntityAvailable ),
491
+ 'wp-block-navigation-link__placeholder': needsValidLink,
446
492
  } );
447
493
 
448
494
  const missingText = getMissingText( type );
@@ -482,6 +528,11 @@ export default function NavigationLinkEdit( {
482
528
  />
483
529
  </InspectorControls>
484
530
  <div { ...blockProps }>
531
+ { hasMissingEntity && (
532
+ <VisuallyHidden id={ missingEntityDescriptionId }>
533
+ <MissingEntityHelpText type={ type } kind={ kind } />
534
+ </VisuallyHidden>
535
+ ) }
485
536
  { /* eslint-disable jsx-a11y/anchor-is-valid */ }
486
537
  <a className={ classes }>
487
538
  { /* eslint-enable */ }
@@ -566,9 +617,27 @@ export default function NavigationLinkEdit( {
566
617
  // Don't remove if binding exists (even if entity is unavailable) so user can fix it.
567
618
  if ( ! url && ! hasUrlBinding ) {
568
619
  onReplace( [] );
569
- } else if ( isNewLink.current ) {
570
- // If we just created a new link, select it
571
- selectBlock( clientId );
620
+ return;
621
+ }
622
+
623
+ // Edge case: If this is the first child of a new submenu, focus the submenu's appender
624
+ if (
625
+ shouldSelectSubmenuAppenderOnClose.current
626
+ ) {
627
+ shouldSelectSubmenuAppenderOnClose.current = false;
628
+
629
+ // The appender is the next sibling in the DOM after the current block
630
+ if (
631
+ listItemRef.current?.nextElementSibling
632
+ ) {
633
+ const appenderButton =
634
+ listItemRef.current.nextElementSibling.querySelector(
635
+ '.block-editor-button-block-appender'
636
+ );
637
+ if ( appenderButton ) {
638
+ appenderButton.focus();
639
+ }
640
+ }
572
641
  }
573
642
  } }
574
643
  anchor={ popoverAnchor }
@@ -1,10 +1,11 @@
1
1
  /**
2
2
  * WordPress dependencies
3
3
  */
4
- import { _x } from '@wordpress/i18n';
4
+ import { _x, __ } from '@wordpress/i18n';
5
5
  import { customLink as linkIcon } from '@wordpress/icons';
6
6
  import { InnerBlocks } from '@wordpress/block-editor';
7
7
  import { addFilter } from '@wordpress/hooks';
8
+ import { privateApis as blocksPrivateApis } from '@wordpress/blocks';
8
9
 
9
10
  /**
10
11
  * Internal dependencies
@@ -15,6 +16,9 @@ import edit from './edit';
15
16
  import save from './save';
16
17
  import { enhanceNavigationLinkVariations } from './hooks';
17
18
  import transforms from './transforms';
19
+ import { unlock } from '../lock-unlock';
20
+
21
+ const { fieldsKey, formKey } = unlock( blocksPrivateApis );
18
22
 
19
23
  const { name } = metadata;
20
24
 
@@ -89,6 +93,29 @@ export const settings = {
89
93
  transforms,
90
94
  };
91
95
 
96
+ if ( window.__experimentalContentOnlyPatternInsertion ) {
97
+ settings[ fieldsKey ] = [
98
+ {
99
+ id: 'label',
100
+ label: __( 'Label' ),
101
+ type: 'richtext',
102
+ },
103
+ {
104
+ id: 'link',
105
+ label: __( 'Link' ),
106
+ type: 'link',
107
+ mapping: {
108
+ href: 'url',
109
+ rel: 'rel',
110
+ // TODO - opens in new tab? id?
111
+ },
112
+ },
113
+ ];
114
+ settings[ formKey ] = {
115
+ fields: [ 'label' ],
116
+ };
117
+ }
118
+
92
119
  export const init = () => {
93
120
  addFilter(
94
121
  'blocks.registerBlockType',
@@ -221,7 +221,7 @@ export function Controls( { attributes, setAttributes, clientId } ) {
221
221
  } }
222
222
  help={
223
223
  hasUrlBinding && ! isBoundEntityAvailable ? (
224
- <MissingEntityHelpText
224
+ <MissingEntityHelp
225
225
  id={ helpTextId }
226
226
  type={ attributes.type }
227
227
  kind={ attributes.kind }
@@ -327,7 +327,7 @@ export function Controls( { attributes, setAttributes, clientId } ) {
327
327
  * @param {string} props.kind - The entity kind
328
328
  * @return {string} Help text for the bound URL
329
329
  */
330
- function BindingHelpText( { type, kind } ) {
330
+ export function BindingHelpText( { type, kind } ) {
331
331
  const entityType = getEntityTypeName( type, kind );
332
332
  return sprintf(
333
333
  /* translators: %s is the entity type (e.g., "page", "post", "category") */
@@ -340,27 +340,23 @@ function BindingHelpText( { type, kind } ) {
340
340
  * Component to display error help text for missing entity bindings.
341
341
  *
342
342
  * @param {Object} props - Component props
343
- * @param {string} props.id - ID for the help text element (for aria-describedby)
344
343
  * @param {string} props.type - The entity type
345
344
  * @param {string} props.kind - The entity kind
346
345
  * @return {JSX.Element} Error help text component
347
346
  */
348
- function MissingEntityHelpText( { id, type, kind } ) {
347
+ export function MissingEntityHelpText( { type, kind } ) {
349
348
  const entityType = getEntityTypeName( type, kind );
349
+ return sprintf(
350
+ /* translators: %s is the entity type (e.g., "page", "post", "category") */
351
+ __( 'Synced %s is missing. Please update or remove this link.' ),
352
+ entityType
353
+ );
354
+ }
355
+
356
+ function MissingEntityHelp( { id, type, kind } ) {
350
357
  return (
351
- <span
352
- id={ id }
353
- className="navigation-link-control__error-text"
354
- role="alert"
355
- aria-live="polite"
356
- >
357
- { sprintf(
358
- /* translators: %s is the entity type (e.g., "page", "post", "category") */
359
- __(
360
- 'Synced %s is missing. Please update or remove this link.'
361
- ),
362
- entityType
363
- ) }
358
+ <span id={ id } className="navigation-link-control__error-text">
359
+ <MissingEntityHelpText type={ type } kind={ kind } />
364
360
  </span>
365
361
  );
366
362
  }
@@ -5,7 +5,7 @@
5
5
  * to reduce code duplication and ensure consistent behavior.
6
6
  */
7
7
 
8
- export { Controls } from './controls';
8
+ export { Controls, BindingHelpText, MissingEntityHelpText } from './controls';
9
9
  export { updateAttributes } from './update-attributes';
10
10
  export {
11
11
  useEntityBinding,
@@ -98,10 +98,13 @@ export function useEntityBinding( { clientId, attributes } ) {
98
98
 
99
99
  // Use the correct entity type based on kind.
100
100
  const entityType = isTaxonomy ? 'taxonomy' : 'postType';
101
- const entityRecord = getEntityRecord( entityType, type, id );
101
+ // Convert 'tag' back to 'post_tag' for the API call
102
+ // (it was converted from 'post_tag' to 'tag' for storage in updateAttributes)
103
+ const typeForAPI = type === 'tag' ? 'post_tag' : type;
104
+ const entityRecord = getEntityRecord( entityType, typeForAPI, id );
102
105
  const hasResolved = hasFinishedResolution( 'getEntityRecord', [
103
106
  entityType,
104
- type,
107
+ typeForAPI,
105
108
  id,
106
109
  ] );
107
110
 
@@ -29,7 +29,8 @@
29
29
  "default": false
30
30
  },
31
31
  "url": {
32
- "type": "string"
32
+ "type": "string",
33
+ "role": "content"
33
34
  },
34
35
  "title": {
35
36
  "type": "string"
@@ -2,7 +2,8 @@
2
2
  * WordPress dependencies
3
3
  */
4
4
  import { page, addSubmenu } from '@wordpress/icons';
5
- import { _x } from '@wordpress/i18n';
5
+ import { _x, __ } from '@wordpress/i18n';
6
+ import { privateApis as blocksPrivateApis } from '@wordpress/blocks';
6
7
 
7
8
  /**
8
9
  * Internal dependencies
@@ -12,6 +13,9 @@ import metadata from './block.json';
12
13
  import edit from './edit';
13
14
  import save from './save';
14
15
  import transforms from './transforms';
16
+ import { unlock } from '../lock-unlock';
17
+
18
+ const { fieldsKey, formKey } = unlock( blocksPrivateApis );
15
19
 
16
20
  const { name } = metadata;
17
21
 
@@ -48,4 +52,27 @@ export const settings = {
48
52
  transforms,
49
53
  };
50
54
 
55
+ if ( window.__experimentalContentOnlyPatternInsertion ) {
56
+ settings[ fieldsKey ] = [
57
+ {
58
+ id: 'label',
59
+ label: __( 'Label' ),
60
+ type: 'richtext',
61
+ },
62
+ {
63
+ id: 'link',
64
+ label: __( 'Link' ),
65
+ type: 'link',
66
+ mapping: {
67
+ href: 'url',
68
+ rel: 'rel',
69
+ // TODO - opens in new tab? id?
70
+ },
71
+ },
72
+ ];
73
+ settings[ formKey ] = {
74
+ fields: [ 'label' ],
75
+ };
76
+ }
77
+
51
78
  export const init = () => initBlock( { name, metadata, settings } );
@@ -0,0 +1,45 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useEvent } from '@wordpress/compose';
5
+ import { useEffect, useRef } from '@wordpress/element';
6
+ import deprecated from '@wordpress/deprecated';
7
+ import { useDispatch } from '@wordpress/data';
8
+ import { store as blockEditorStore } from '@wordpress/block-editor';
9
+
10
+ /**
11
+ * If a plugin is still using the old align attribute, we need to migrate its value
12
+ * to the new style.typography.textAlign attribute.
13
+ *
14
+ * @param {string?} align Align attribute value.
15
+ * @param {Object?} style Style attribute value.
16
+ * @param {(Object) => void} setAttributes Updater function for block attributes.
17
+ */
18
+ export default function useDeprecatedAlign( align, style, setAttributes ) {
19
+ const { __unstableMarkNextChangeAsNotPersistent } =
20
+ useDispatch( blockEditorStore );
21
+ const updateStyleWithAlign = useEvent( () => {
22
+ deprecated( 'align attribute in paragraph block', {
23
+ alternative: 'style.typography.textAlign',
24
+ since: '7.0',
25
+ } );
26
+ __unstableMarkNextChangeAsNotPersistent();
27
+ setAttributes( {
28
+ style: {
29
+ ...style,
30
+ typography: {
31
+ ...style?.typography,
32
+ textAlign: align,
33
+ },
34
+ },
35
+ } );
36
+ } );
37
+ const lastUpdatedAlignRef = useRef();
38
+ useEffect( () => {
39
+ if ( align === lastUpdatedAlignRef.current ) {
40
+ return;
41
+ }
42
+ lastUpdatedAlignRef.current = align;
43
+ updateStyleWithAlign();
44
+ }, [ align, updateStyleWithAlign ] );
45
+ }
@@ -26,6 +26,7 @@ import { formatLtr } from '@wordpress/icons';
26
26
  * Internal dependencies
27
27
  */
28
28
  import { useOnEnter } from './use-enter';
29
+ import useDeprecatedAlign from './deprecated-attributes';
29
30
 
30
31
  function ParagraphRTLControl( { direction, setDirection } ) {
31
32
  return (
@@ -110,6 +111,7 @@ function ParagraphBlock( {
110
111
  } ) {
111
112
  const { content, direction, dropCap, placeholder, style } = attributes;
112
113
  const textAlign = style?.typography?.textAlign;
114
+ useDeprecatedAlign( attributes.align, style, setAttributes );
113
115
  const blockProps = useBlockProps( {
114
116
  ref: useOnEnter( { clientId, content } ),
115
117
  className: clsx( {
@@ -3,6 +3,7 @@
3
3
  */
4
4
  import { __ } from '@wordpress/i18n';
5
5
  import { paragraph as icon } from '@wordpress/icons';
6
+ import { privateApis as blocksPrivateApis } from '@wordpress/blocks';
6
7
 
7
8
  /**
8
9
  * Internal dependencies
@@ -14,6 +15,9 @@ import metadata from './block.json';
14
15
  import save from './save';
15
16
  import transforms from './transforms';
16
17
  import variations from './variations';
18
+ import { unlock } from '../lock-unlock';
19
+
20
+ const { fieldsKey, formKey } = unlock( blocksPrivateApis );
17
21
 
18
22
  const { name } = metadata;
19
23
 
@@ -58,4 +62,17 @@ export const settings = {
58
62
  variations,
59
63
  };
60
64
 
65
+ if ( window.__experimentalContentOnlyPatternInsertion ) {
66
+ settings[ fieldsKey ] = [
67
+ {
68
+ id: 'content',
69
+ label: __( 'Content' ),
70
+ type: 'richtext',
71
+ },
72
+ ];
73
+ settings[ formKey ] = {
74
+ fields: [ 'content' ],
75
+ };
76
+ }
77
+
61
78
  export const init = () => initBlock( { name, metadata, settings } );
@@ -9,7 +9,7 @@
9
9
  "html": false,
10
10
  "inserter": false,
11
11
  "renaming": false,
12
- "blockVisibility": false,
12
+ "visibility": false,
13
13
  "interactivity": {
14
14
  "clientNavigation": true
15
15
  }
@@ -9,13 +9,11 @@ import clsx from 'clsx';
9
9
  import {
10
10
  AlignmentControl,
11
11
  BlockControls,
12
- Warning,
13
12
  useBlockProps,
14
13
  } from '@wordpress/block-editor';
15
14
  import { useState, useEffect } from '@wordpress/element';
16
15
  import apiFetch from '@wordpress/api-fetch';
17
16
  import { addQueryArgs } from '@wordpress/url';
18
- import { __ } from '@wordpress/i18n';
19
17
 
20
18
  export default function PostCommentsCountEdit( {
21
19
  attributes,
@@ -68,13 +66,7 @@ export default function PostCommentsCountEdit( {
68
66
  />
69
67
  </BlockControls>
70
68
  <div { ...blockProps } style={ blockStyles }>
71
- { hasPostAndComments ? (
72
- commentsCount
73
- ) : (
74
- <Warning>
75
- { __( 'Post Comments Count block: post not found.' ) }
76
- </Warning>
77
- ) }
69
+ { hasPostAndComments ? commentsCount : '0' }
78
70
  </div>
79
71
  </>
80
72
  );
@@ -9,7 +9,6 @@ import clsx from 'clsx';
9
9
  import {
10
10
  AlignmentControl,
11
11
  BlockControls,
12
- Warning,
13
12
  useBlockProps,
14
13
  } from '@wordpress/block-editor';
15
14
  import { useState, useEffect } from '@wordpress/element';
@@ -59,18 +58,6 @@ function PostCommentsLinkEdit( { context, attributes, setAttributes } ) {
59
58
  [ postType, postId ]
60
59
  );
61
60
 
62
- if ( ! post ) {
63
- return (
64
- <div { ...blockProps }>
65
- <Warning>
66
- { __( 'Post Comments Link block: post not found.' ) }
67
- </Warning>
68
- </div>
69
- );
70
- }
71
-
72
- const { link } = post;
73
-
74
61
  let commentsText;
75
62
  if ( commentsCount !== undefined ) {
76
63
  const commentsNumber = parseInt( commentsCount );
@@ -98,17 +85,20 @@ function PostCommentsLinkEdit( { context, attributes, setAttributes } ) {
98
85
  </BlockControls>
99
86
 
100
87
  <div { ...blockProps }>
101
- { link && commentsText !== undefined ? (
88
+ { post?.link && commentsText !== undefined ? (
102
89
  <a
103
- href={ link + '#comments' }
90
+ href={ post?.link + '#comments' }
104
91
  onClick={ ( event ) => event.preventDefault() }
105
92
  >
106
93
  { commentsText }
107
94
  </a>
108
95
  ) : (
109
- <Warning>
110
- { __( 'Post Comments Link block: post not found.' ) }
111
- </Warning>
96
+ <a
97
+ href="#post-comments-link-pseudo-link"
98
+ onClick={ ( event ) => event.preventDefault() }
99
+ >
100
+ { __( 'No comments' ) }
101
+ </a>
112
102
  ) }
113
103
  </div>
114
104
  </>
@@ -3,6 +3,7 @@
3
3
  */
4
4
  import { __ } from '@wordpress/i18n';
5
5
  import { preformatted as icon } from '@wordpress/icons';
6
+ import { privateApis as blocksPrivateApis } from '@wordpress/blocks';
6
7
 
7
8
  /**
8
9
  * Internal dependencies
@@ -12,6 +13,9 @@ import edit from './edit';
12
13
  import metadata from './block.json';
13
14
  import save from './save';
14
15
  import transforms from './transforms';
16
+ import { unlock } from '../lock-unlock';
17
+
18
+ const { fieldsKey, formKey } = unlock( blocksPrivateApis );
15
19
 
16
20
  const { name } = metadata;
17
21
 
@@ -39,4 +43,17 @@ export const settings = {
39
43
  },
40
44
  };
41
45
 
46
+ if ( window.__experimentalContentOnlyPatternInsertion ) {
47
+ settings[ fieldsKey ] = [
48
+ {
49
+ id: 'content',
50
+ label: __( 'Content' ),
51
+ type: 'richtext',
52
+ },
53
+ ];
54
+ settings[ formKey ] = {
55
+ fields: [ 'content' ],
56
+ };
57
+ }
58
+
42
59
  export const init = () => initBlock( { name, metadata, settings } );
@@ -3,6 +3,7 @@
3
3
  */
4
4
  import { __ } from '@wordpress/i18n';
5
5
  import { pullquote as icon } from '@wordpress/icons';
6
+ import { privateApis as blocksPrivateApis } from '@wordpress/blocks';
6
7
 
7
8
  /**
8
9
  * Internal dependencies
@@ -13,6 +14,9 @@ import edit from './edit';
13
14
  import metadata from './block.json';
14
15
  import save from './save';
15
16
  import transforms from './transforms';
17
+ import { unlock } from '../lock-unlock';
18
+
19
+ const { fieldsKey, formKey } = unlock( blocksPrivateApis );
16
20
 
17
21
  const { name } = metadata;
18
22
 
@@ -36,4 +40,22 @@ export const settings = {
36
40
  deprecated,
37
41
  };
38
42
 
43
+ if ( window.__experimentalContentOnlyPatternInsertion ) {
44
+ settings[ fieldsKey ] = [
45
+ {
46
+ id: 'value',
47
+ label: __( 'Content' ),
48
+ type: 'richtext',
49
+ },
50
+ {
51
+ id: 'citation',
52
+ label: __( 'Citation' ),
53
+ type: 'richtext',
54
+ },
55
+ ];
56
+ settings[ formKey ] = {
57
+ fields: [ 'value' ],
58
+ };
59
+ }
60
+
39
61
  export const init = () => initBlock( { name, metadata, settings } );