@wordpress/block-library 9.45.1-next.v.202605131032.0 → 9.47.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 (182) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/build/button/edit.cjs +7 -4
  3. package/build/button/edit.cjs.map +3 -3
  4. package/build/columns/edit.cjs +4 -10
  5. package/build/columns/edit.cjs.map +2 -2
  6. package/build/comments/edit/placeholder.cjs +1 -1
  7. package/build/comments/edit/placeholder.cjs.map +2 -2
  8. package/build/cover/edit/inspector-controls.cjs +4 -2
  9. package/build/cover/edit/inspector-controls.cjs.map +2 -2
  10. package/build/freeform/migration-notice.cjs +1 -1
  11. package/build/freeform/migration-notice.cjs.map +1 -1
  12. package/build/home-link/block.json +7 -0
  13. package/build/home-link/edit.cjs +167 -24
  14. package/build/home-link/edit.cjs.map +3 -3
  15. package/build/html/edit.cjs +2 -4
  16. package/build/html/edit.cjs.map +2 -2
  17. package/build/html/modal.cjs +0 -4
  18. package/build/html/modal.cjs.map +2 -2
  19. package/build/image/block.json +4 -0
  20. package/build/image/deprecated.cjs +202 -4
  21. package/build/image/deprecated.cjs.map +3 -3
  22. package/build/image/image.cjs +80 -27
  23. package/build/image/image.cjs.map +2 -2
  24. package/build/image/index.cjs +23 -4
  25. package/build/image/index.cjs.map +2 -2
  26. package/build/image/save.cjs +25 -10
  27. package/build/image/save.cjs.map +2 -2
  28. package/build/image/transforms.cjs +15 -3
  29. package/build/image/transforms.cjs.map +2 -2
  30. package/build/image/use-open-image-media-editor-modal.cjs +29 -12
  31. package/build/image/use-open-image-media-editor-modal.cjs.map +2 -2
  32. package/build/list-item/hooks/use-enter.cjs +8 -4
  33. package/build/list-item/hooks/use-enter.cjs.map +3 -3
  34. package/build/list-item/hooks/use-space.cjs +8 -4
  35. package/build/list-item/hooks/use-space.cjs.map +3 -3
  36. package/build/navigation-link/edit.cjs +2 -1
  37. package/build/navigation-link/edit.cjs.map +2 -2
  38. package/build/navigation-link/shared/use-handle-link-change.cjs +19 -3
  39. package/build/navigation-link/shared/use-handle-link-change.cjs.map +3 -3
  40. package/build/navigation-submenu/edit.cjs +8 -22
  41. package/build/navigation-submenu/edit.cjs.map +2 -2
  42. package/build/paragraph/use-enter.cjs +8 -4
  43. package/build/paragraph/use-enter.cjs.map +3 -3
  44. package/build/post-date/edit.cjs +9 -1
  45. package/build/post-date/edit.cjs.map +2 -2
  46. package/build/post-featured-image/edit.cjs +0 -1
  47. package/build/post-featured-image/edit.cjs.map +2 -2
  48. package/build/site-logo/edit.cjs +1 -1
  49. package/build/site-logo/edit.cjs.map +2 -2
  50. package/build/social-link/edit.cjs.map +3 -3
  51. package/build/tab-list/edit.cjs +2 -0
  52. package/build/tab-list/edit.cjs.map +2 -2
  53. package/build/tab-panels/edit.cjs +5 -1
  54. package/build/tab-panels/edit.cjs.map +2 -2
  55. package/build/table/edit.cjs +1 -0
  56. package/build/table/edit.cjs.map +2 -2
  57. package/build/tabs/edit.cjs +1 -36
  58. package/build/tabs/edit.cjs.map +2 -2
  59. package/build-module/button/edit.mjs +12 -5
  60. package/build-module/button/edit.mjs.map +2 -2
  61. package/build-module/columns/edit.mjs +4 -10
  62. package/build-module/columns/edit.mjs.map +2 -2
  63. package/build-module/comments/edit/placeholder.mjs +1 -1
  64. package/build-module/comments/edit/placeholder.mjs.map +2 -2
  65. package/build-module/cover/edit/inspector-controls.mjs +4 -3
  66. package/build-module/cover/edit/inspector-controls.mjs.map +2 -2
  67. package/build-module/freeform/migration-notice.mjs +1 -1
  68. package/build-module/freeform/migration-notice.mjs.map +1 -1
  69. package/build-module/home-link/block.json +7 -0
  70. package/build-module/home-link/edit.mjs +181 -26
  71. package/build-module/home-link/edit.mjs.map +2 -2
  72. package/build-module/html/edit.mjs +2 -4
  73. package/build-module/html/edit.mjs.map +2 -2
  74. package/build-module/html/modal.mjs +0 -4
  75. package/build-module/html/modal.mjs.map +2 -2
  76. package/build-module/image/block.json +4 -0
  77. package/build-module/image/deprecated.mjs +204 -5
  78. package/build-module/image/deprecated.mjs.map +2 -2
  79. package/build-module/image/image.mjs +81 -27
  80. package/build-module/image/image.mjs.map +2 -2
  81. package/build-module/image/index.mjs +23 -4
  82. package/build-module/image/index.mjs.map +2 -2
  83. package/build-module/image/save.mjs +25 -10
  84. package/build-module/image/save.mjs.map +2 -2
  85. package/build-module/image/transforms.mjs +15 -3
  86. package/build-module/image/transforms.mjs.map +2 -2
  87. package/build-module/image/use-open-image-media-editor-modal.mjs +29 -12
  88. package/build-module/image/use-open-image-media-editor-modal.mjs.map +2 -2
  89. package/build-module/list-item/hooks/use-enter.mjs +12 -5
  90. package/build-module/list-item/hooks/use-enter.mjs.map +2 -2
  91. package/build-module/list-item/hooks/use-space.mjs +12 -5
  92. package/build-module/list-item/hooks/use-space.mjs.map +2 -2
  93. package/build-module/navigation-link/edit.mjs +2 -1
  94. package/build-module/navigation-link/edit.mjs.map +2 -2
  95. package/build-module/navigation-link/shared/use-handle-link-change.mjs +19 -3
  96. package/build-module/navigation-link/shared/use-handle-link-change.mjs.map +2 -2
  97. package/build-module/navigation-submenu/edit.mjs +9 -23
  98. package/build-module/navigation-submenu/edit.mjs.map +2 -2
  99. package/build-module/paragraph/use-enter.mjs +12 -5
  100. package/build-module/paragraph/use-enter.mjs.map +2 -2
  101. package/build-module/post-date/edit.mjs +9 -1
  102. package/build-module/post-date/edit.mjs.map +2 -2
  103. package/build-module/post-featured-image/edit.mjs +0 -1
  104. package/build-module/post-featured-image/edit.mjs.map +2 -2
  105. package/build-module/site-logo/edit.mjs +1 -1
  106. package/build-module/site-logo/edit.mjs.map +2 -2
  107. package/build-module/social-link/edit.mjs +2 -2
  108. package/build-module/social-link/edit.mjs.map +2 -2
  109. package/build-module/tab-list/edit.mjs +2 -0
  110. package/build-module/tab-list/edit.mjs.map +2 -2
  111. package/build-module/tab-panels/edit.mjs +5 -1
  112. package/build-module/tab-panels/edit.mjs.map +2 -2
  113. package/build-module/table/edit.mjs +1 -0
  114. package/build-module/table/edit.mjs.map +2 -2
  115. package/build-module/tabs/edit.mjs +2 -37
  116. package/build-module/tabs/edit.mjs.map +2 -2
  117. package/build-style/breadcrumbs/style-rtl.css +1 -1
  118. package/build-style/breadcrumbs/style.css +1 -1
  119. package/build-style/editor-rtl.css +0 -11
  120. package/build-style/editor.css +0 -11
  121. package/build-style/gallery/editor-rtl.css +0 -11
  122. package/build-style/gallery/editor.css +0 -11
  123. package/build-style/style-rtl.css +1 -1
  124. package/build-style/style.css +1 -1
  125. package/package.json +42 -42
  126. package/src/block/edit-title.native.js +3 -3
  127. package/src/block/edit.native.js +2 -2
  128. package/src/breadcrumbs/style.scss +1 -1
  129. package/src/button/edit.js +14 -5
  130. package/src/columns/edit.js +3 -9
  131. package/src/comments/edit/placeholder.js +1 -1
  132. package/src/cover/controls.native.js +2 -2
  133. package/src/cover/edit/inspector-controls.js +8 -7
  134. package/src/cover/edit.native.js +6 -4
  135. package/src/cover/focal-point-settings-button.native.js +2 -2
  136. package/src/cover/test/edit.js +32 -31
  137. package/src/embed/embed-no-preview.native.js +7 -3
  138. package/src/embed/embed-placeholder.native.js +2 -2
  139. package/src/file/edit.native.js +2 -2
  140. package/src/freeform/migration-notice.js +1 -1
  141. package/src/gallery/editor.scss +0 -14
  142. package/src/home-link/block.json +7 -0
  143. package/src/home-link/edit.js +185 -22
  144. package/src/home-link/index.php +14 -2
  145. package/src/html/edit.js +14 -12
  146. package/src/html/modal.js +0 -5
  147. package/src/image/block.json +4 -0
  148. package/src/image/deprecated.js +236 -4
  149. package/src/image/edit.native.js +2 -2
  150. package/src/image/image.js +116 -41
  151. package/src/image/index.js +20 -1
  152. package/src/image/index.php +1 -1
  153. package/src/image/save.js +39 -12
  154. package/src/image/test/use-open-image-media-editor-modal.js +60 -0
  155. package/src/image/transforms.js +21 -5
  156. package/src/image/use-open-image-media-editor-modal.js +34 -16
  157. package/src/latest-posts/edit.native.js +2 -2
  158. package/src/list-item/hooks/use-enter.js +15 -5
  159. package/src/list-item/hooks/use-space.js +15 -5
  160. package/src/list-item/list-style-type.native.js +2 -2
  161. package/src/media-text/media-container.native.js +7 -3
  162. package/src/missing/edit.native.js +4 -4
  163. package/src/missing/test/edit.native.js +3 -3
  164. package/src/navigation/test/use-navigation-menu.js +8 -2
  165. package/src/navigation-link/edit.js +1 -0
  166. package/src/navigation-link/shared/test/use-handle-link-change.test.js +212 -0
  167. package/src/navigation-link/shared/use-handle-link-change.js +36 -9
  168. package/src/navigation-link/test/__snapshots__/hooks.js.snap +134 -45
  169. package/src/navigation-submenu/edit.js +11 -28
  170. package/src/navigation-submenu/index.php +13 -0
  171. package/src/paragraph/use-enter.js +19 -5
  172. package/src/post-date/edit.js +7 -3
  173. package/src/post-featured-image/edit.js +0 -1
  174. package/src/search/edit.native.js +2 -2
  175. package/src/search/test/edit.native.js +2 -2
  176. package/src/site-logo/edit.js +2 -1
  177. package/src/social-link/edit.js +2 -2
  178. package/src/tab-list/edit.js +3 -0
  179. package/src/tab-panels/edit.js +10 -1
  180. package/src/table/edit.js +1 -0
  181. package/src/tabs/edit.js +14 -42
  182. package/src/video/edit.native.js +3 -3
@@ -4,6 +4,8 @@
4
4
  import { useCallback } from '@wordpress/element';
5
5
  import { useDispatch } from '@wordpress/data';
6
6
  import { store as blockEditorStore } from '@wordpress/block-editor';
7
+ import { __unstableStripHTML as stripHTML } from '@wordpress/dom';
8
+ import { escapeHTML } from '@wordpress/escape-html';
7
9
 
8
10
  /**
9
11
  * Internal dependencies
@@ -16,13 +18,19 @@ import { useEntityBinding } from './use-entity-binding';
16
18
  * Manages the transition between entity links and custom links,
17
19
  * including proper binding creation and cleanup.
18
20
  *
19
- * @param {Object} options - Configuration options
20
- * @param {string} options.clientId - Block client ID
21
- * @param {Object} options.attributes - Current block attributes
22
- * @param {Function} options.setAttributes - Standard setAttribute function
21
+ * @param {Object} options - Configuration options
22
+ * @param {string} options.clientId - Block client ID
23
+ * @param {Object} options.attributes - Current block attributes
24
+ * @param {Function} options.setAttributes - Standard setAttribute function
25
+ * @param {boolean} options.allowTextUpdate - Whether this control can update the link text
23
26
  * @return {Function} Callback function to handle link changes
24
27
  */
25
- export function useHandleLinkChange( { clientId, attributes, setAttributes } ) {
28
+ export function useHandleLinkChange( {
29
+ clientId,
30
+ attributes,
31
+ setAttributes,
32
+ allowTextUpdate = false,
33
+ } ) {
26
34
  const { updateBlockAttributes } = useDispatch( blockEditorStore );
27
35
  const { hasUrlBinding, createBinding, clearBinding } = useEntityBinding( {
28
36
  clientId,
@@ -42,12 +50,25 @@ export function useHandleLinkChange( { clientId, attributes, setAttributes } ) {
42
50
  id: updatedLink.id,
43
51
  };
44
52
 
45
- // Only include title when there's no existing label
46
- // This preserves user-customized labels when updating links
47
- if ( ! attributes.label || attributes.label === '' ) {
53
+ const currentText = attributes.label
54
+ ? stripHTML( attributes.label )
55
+ : '';
56
+ const updatedText = updatedLink.title ?? '';
57
+ const hasTextUpdate =
58
+ allowTextUpdate &&
59
+ updatedLink.title !== undefined &&
60
+ updatedText !== currentText;
61
+ const textUpdateAttributes = hasTextUpdate
62
+ ? { label: escapeHTML( updatedText ) }
63
+ : {};
64
+
65
+ if (
66
+ ! attributes.label ||
67
+ attributes.label === '' ||
68
+ hasTextUpdate
69
+ ) {
48
70
  attrs.title = updatedLink.title;
49
71
  }
50
-
51
72
  // Check if transitioning from entity to custom link
52
73
  const willBeCustomLink = ! updatedLink.id && hasUrlBinding;
53
74
 
@@ -62,6 +83,7 @@ export function useHandleLinkChange( { clientId, attributes, setAttributes } ) {
62
83
  kind: 'custom',
63
84
  type: 'custom',
64
85
  id: undefined,
86
+ ...textUpdateAttributes,
65
87
  } );
66
88
  } else {
67
89
  // Normal flow for entity links or unbound custom links
@@ -76,10 +98,15 @@ export function useHandleLinkChange( { clientId, attributes, setAttributes } ) {
76
98
  } else {
77
99
  clearBinding();
78
100
  }
101
+
102
+ if ( Object.keys( textUpdateAttributes ).length ) {
103
+ updateBlockAttributes( clientId, textUpdateAttributes );
104
+ }
79
105
  }
80
106
  },
81
107
  [
82
108
  attributes,
109
+ allowTextUpdate,
83
110
  clientId,
84
111
  hasUrlBinding,
85
112
  createBinding,
@@ -8,14 +8,30 @@ exports[`hooks enhanceNavigationLinkVariations enhances variations with icon and
8
8
  {
9
9
  "attributes": {},
10
10
  "description": "A link to a custom URL.",
11
- "icon": <SVG
12
- viewBox="0 0 24 24"
13
- xmlns="http://www.w3.org/2000/svg"
14
- >
15
- <Path
16
- d="M4 20h9v-1.5H4V20zm0-5.5V16h16v-1.5H4zm.8-4l.7.7 2-2V12h1V9.2l2 2 .7-.7-2-2H12v-1H9.2l2-2-.7-.7-2 2V4h-1v2.8l-2-2-.7.7 2 2H4v1h2.8l-2 2z"
17
- />
18
- </SVG>,
11
+ "icon": {
12
+ "$$typeof": Symbol(react.transitional.element),
13
+ "_owner": null,
14
+ "_store": {},
15
+ "key": null,
16
+ "props": {
17
+ "children": {
18
+ "$$typeof": Symbol(react.transitional.element),
19
+ "_owner": null,
20
+ "_store": {},
21
+ "key": null,
22
+ "props": {
23
+ "d": "M4 20h9v-1.5H4V20zm0-5.5V16h16v-1.5H4zm.8-4l.7.7 2-2V12h1V9.2l2 2 .7-.7-2-2H12v-1H9.2l2-2-.7-.7-2 2V4h-1v2.8l-2-2-.7.7 2 2H4v1h2.8l-2 2z",
24
+ },
25
+ "type": [Function],
26
+ },
27
+ "viewBox": "0 0 24 24",
28
+ "xmlns": "http://www.w3.org/2000/svg",
29
+ },
30
+ "type": {
31
+ "$$typeof": Symbol(react.forward_ref),
32
+ "render": [Function],
33
+ },
34
+ },
19
35
  "isActive": [Function],
20
36
  "name": "link",
21
37
  "title": "Custom Link",
@@ -25,14 +41,30 @@ exports[`hooks enhanceNavigationLinkVariations enhances variations with icon and
25
41
  "type": "post",
26
42
  },
27
43
  "description": "A link to a post.",
28
- "icon": <SVG
29
- viewBox="0 0 24 24"
30
- xmlns="http://www.w3.org/2000/svg"
31
- >
32
- <Path
33
- d="M18 5.5H6a.5.5 0 0 0-.5.5v12a.5.5 0 0 0 .5.5h12a.5.5 0 0 0 .5-.5V6a.5.5 0 0 0-.5-.5ZM6 4h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2Zm1 5h1.5v1.5H7V9Zm1.5 4.5H7V15h1.5v-1.5ZM10 9h7v1.5h-7V9Zm7 4.5h-7V15h7v-1.5Z"
34
- />
35
- </SVG>,
44
+ "icon": {
45
+ "$$typeof": Symbol(react.transitional.element),
46
+ "_owner": null,
47
+ "_store": {},
48
+ "key": null,
49
+ "props": {
50
+ "children": {
51
+ "$$typeof": Symbol(react.transitional.element),
52
+ "_owner": null,
53
+ "_store": {},
54
+ "key": null,
55
+ "props": {
56
+ "d": "M18 5.5H6a.5.5 0 0 0-.5.5v12a.5.5 0 0 0 .5.5h12a.5.5 0 0 0 .5-.5V6a.5.5 0 0 0-.5-.5ZM6 4h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2Zm1 5h1.5v1.5H7V9Zm1.5 4.5H7V15h1.5v-1.5ZM10 9h7v1.5h-7V9Zm7 4.5h-7V15h7v-1.5Z",
57
+ },
58
+ "type": [Function],
59
+ },
60
+ "viewBox": "0 0 24 24",
61
+ "xmlns": "http://www.w3.org/2000/svg",
62
+ },
63
+ "type": {
64
+ "$$typeof": Symbol(react.forward_ref),
65
+ "render": [Function],
66
+ },
67
+ },
36
68
  "isActive": [Function],
37
69
  "name": "post",
38
70
  "title": "Post Link",
@@ -42,17 +74,42 @@ exports[`hooks enhanceNavigationLinkVariations enhances variations with icon and
42
74
  "type": "page",
43
75
  },
44
76
  "description": "A link to a page.",
45
- "icon": <SVG
46
- viewBox="0 0 24 24"
47
- xmlns="http://www.w3.org/2000/svg"
48
- >
49
- <Path
50
- d="M15.5 7.5h-7V9h7V7.5Zm-7 3.5h7v1.5h-7V11Zm7 3.5h-7V16h7v-1.5Z"
51
- />
52
- <Path
53
- d="M17 4H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2ZM7 5.5h10a.5.5 0 0 1 .5.5v12a.5.5 0 0 1-.5.5H7a.5.5 0 0 1-.5-.5V6a.5.5 0 0 1 .5-.5Z"
54
- />
55
- </SVG>,
77
+ "icon": {
78
+ "$$typeof": Symbol(react.transitional.element),
79
+ "_owner": null,
80
+ "_store": {},
81
+ "key": null,
82
+ "props": {
83
+ "children": [
84
+ {
85
+ "$$typeof": Symbol(react.transitional.element),
86
+ "_owner": null,
87
+ "_store": {},
88
+ "key": null,
89
+ "props": {
90
+ "d": "M15.5 7.5h-7V9h7V7.5Zm-7 3.5h7v1.5h-7V11Zm7 3.5h-7V16h7v-1.5Z",
91
+ },
92
+ "type": [Function],
93
+ },
94
+ {
95
+ "$$typeof": Symbol(react.transitional.element),
96
+ "_owner": null,
97
+ "_store": {},
98
+ "key": null,
99
+ "props": {
100
+ "d": "M17 4H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2ZM7 5.5h10a.5.5 0 0 1 .5.5v12a.5.5 0 0 1-.5.5H7a.5.5 0 0 1-.5-.5V6a.5.5 0 0 1 .5-.5Z",
101
+ },
102
+ "type": [Function],
103
+ },
104
+ ],
105
+ "viewBox": "0 0 24 24",
106
+ "xmlns": "http://www.w3.org/2000/svg",
107
+ },
108
+ "type": {
109
+ "$$typeof": Symbol(react.forward_ref),
110
+ "render": [Function],
111
+ },
112
+ },
56
113
  "isActive": [Function],
57
114
  "name": "page",
58
115
  "title": "Page Link",
@@ -62,16 +119,32 @@ exports[`hooks enhanceNavigationLinkVariations enhances variations with icon and
62
119
  "type": "category",
63
120
  },
64
121
  "description": "A link to a category.",
65
- "icon": <SVG
66
- viewBox="0 0 24 24"
67
- xmlns="http://www.w3.org/2000/svg"
68
- >
69
- <Path
70
- clipRule="evenodd"
71
- d="M6 5.5h3a.5.5 0 01.5.5v3a.5.5 0 01-.5.5H6a.5.5 0 01-.5-.5V6a.5.5 0 01.5-.5zM4 6a2 2 0 012-2h3a2 2 0 012 2v3a2 2 0 01-2 2H6a2 2 0 01-2-2V6zm11-.5h3a.5.5 0 01.5.5v3a.5.5 0 01-.5.5h-3a.5.5 0 01-.5-.5V6a.5.5 0 01.5-.5zM13 6a2 2 0 012-2h3a2 2 0 012 2v3a2 2 0 01-2 2h-3a2 2 0 01-2-2V6zm5 8.5h-3a.5.5 0 00-.5.5v3a.5.5 0 00.5.5h3a.5.5 0 00.5-.5v-3a.5.5 0 00-.5-.5zM15 13a2 2 0 00-2 2v3a2 2 0 002 2h3a2 2 0 002-2v-3a2 2 0 00-2-2h-3zm-9 1.5h3a.5.5 0 01.5.5v3a.5.5 0 01-.5.5H6a.5.5 0 01-.5-.5v-3a.5.5 0 01.5-.5zM4 15a2 2 0 012-2h3a2 2 0 012 2v3a2 2 0 01-2 2H6a2 2 0 01-2-2v-3z"
72
- fillRule="evenodd"
73
- />
74
- </SVG>,
122
+ "icon": {
123
+ "$$typeof": Symbol(react.transitional.element),
124
+ "_owner": null,
125
+ "_store": {},
126
+ "key": null,
127
+ "props": {
128
+ "children": {
129
+ "$$typeof": Symbol(react.transitional.element),
130
+ "_owner": null,
131
+ "_store": {},
132
+ "key": null,
133
+ "props": {
134
+ "clipRule": "evenodd",
135
+ "d": "M6 5.5h3a.5.5 0 01.5.5v3a.5.5 0 01-.5.5H6a.5.5 0 01-.5-.5V6a.5.5 0 01.5-.5zM4 6a2 2 0 012-2h3a2 2 0 012 2v3a2 2 0 01-2 2H6a2 2 0 01-2-2V6zm11-.5h3a.5.5 0 01.5.5v3a.5.5 0 01-.5.5h-3a.5.5 0 01-.5-.5V6a.5.5 0 01.5-.5zM13 6a2 2 0 012-2h3a2 2 0 012 2v3a2 2 0 01-2 2h-3a2 2 0 01-2-2V6zm5 8.5h-3a.5.5 0 00-.5.5v3a.5.5 0 00.5.5h3a.5.5 0 00.5-.5v-3a.5.5 0 00-.5-.5zM15 13a2 2 0 00-2 2v3a2 2 0 002 2h3a2 2 0 002-2v-3a2 2 0 00-2-2h-3zm-9 1.5h3a.5.5 0 01.5.5v3a.5.5 0 01-.5.5H6a.5.5 0 01-.5-.5v-3a.5.5 0 01.5-.5zM4 15a2 2 0 012-2h3a2 2 0 012 2v3a2 2 0 01-2 2H6a2 2 0 01-2-2v-3z",
136
+ "fillRule": "evenodd",
137
+ },
138
+ "type": [Function],
139
+ },
140
+ "viewBox": "0 0 24 24",
141
+ "xmlns": "http://www.w3.org/2000/svg",
142
+ },
143
+ "type": {
144
+ "$$typeof": Symbol(react.forward_ref),
145
+ "render": [Function],
146
+ },
147
+ },
75
148
  "isActive": [Function],
76
149
  "name": "category",
77
150
  "title": "Category Link",
@@ -81,14 +154,30 @@ exports[`hooks enhanceNavigationLinkVariations enhances variations with icon and
81
154
  "type": "tag",
82
155
  },
83
156
  "description": "A link to a tag.",
84
- "icon": <SVG
85
- viewBox="0 0 24 24"
86
- xmlns="http://www.w3.org/2000/svg"
87
- >
88
- <Path
89
- d="M4.75 4a.75.75 0 0 0-.75.75v7.826c0 .2.08.39.22.53l6.72 6.716a2.313 2.313 0 0 0 3.276-.001l5.61-5.611-.531-.53.532.528a2.315 2.315 0 0 0 0-3.264L13.104 4.22a.75.75 0 0 0-.53-.22H4.75ZM19 12.576a.815.815 0 0 1-.236.574l-5.61 5.611a.814.814 0 0 1-1.153 0L5.5 12.264V5.5h6.763l6.5 6.502a.816.816 0 0 1 .237.574ZM8.75 9.75a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z"
90
- />
91
- </SVG>,
157
+ "icon": {
158
+ "$$typeof": Symbol(react.transitional.element),
159
+ "_owner": null,
160
+ "_store": {},
161
+ "key": null,
162
+ "props": {
163
+ "children": {
164
+ "$$typeof": Symbol(react.transitional.element),
165
+ "_owner": null,
166
+ "_store": {},
167
+ "key": null,
168
+ "props": {
169
+ "d": "M4.75 4a.75.75 0 0 0-.75.75v7.826c0 .2.08.39.22.53l6.72 6.716a2.313 2.313 0 0 0 3.276-.001l5.61-5.611-.531-.53.532.528a2.315 2.315 0 0 0 0-3.264L13.104 4.22a.75.75 0 0 0-.53-.22H4.75ZM19 12.576a.815.815 0 0 1-.236.574l-5.61 5.611a.814.814 0 0 1-1.153 0L5.5 12.264V5.5h6.763l6.5 6.502a.816.816 0 0 1 .237.574ZM8.75 9.75a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z",
170
+ },
171
+ "type": [Function],
172
+ },
173
+ "viewBox": "0 0 24 24",
174
+ "xmlns": "http://www.w3.org/2000/svg",
175
+ },
176
+ "type": {
177
+ "$$typeof": Symbol(react.forward_ref),
178
+ "render": [Function],
179
+ },
180
+ },
92
181
  "isActive": [Function],
93
182
  "name": "tag",
94
183
  "title": "Tag Link",
@@ -35,8 +35,8 @@ import { ItemSubmenuIcon } from './icons';
35
35
  import {
36
36
  Controls,
37
37
  LinkUI,
38
- updateAttributes,
39
38
  useEntityBinding,
39
+ useHandleLinkChange,
40
40
  useIsInvalidLink,
41
41
  InvalidDraftDisplay,
42
42
  useEnableLinkStatusValidation,
@@ -92,15 +92,17 @@ export default function NavigationSubmenuEdit( {
92
92
  blockEditingMode !== 'default' ? true : submenuVisibility === 'click';
93
93
 
94
94
  // URL binding logic
95
- const {
96
- clearBinding,
97
- createBinding,
98
- hasUrlBinding,
99
- isBoundEntityAvailable,
100
- entityRecord,
101
- } = useEntityBinding( {
95
+ const { hasUrlBinding, isBoundEntityAvailable, entityRecord } =
96
+ useEntityBinding( {
97
+ clientId,
98
+ attributes,
99
+ } );
100
+
101
+ const handleLinkChange = useHandleLinkChange( {
102
102
  clientId,
103
103
  attributes,
104
+ setAttributes,
105
+ allowTextUpdate: true,
104
106
  } );
105
107
 
106
108
  const { __unstableMarkNextChangeAsNotPersistent, replaceBlock } =
@@ -398,26 +400,7 @@ export default function NavigationSubmenuEdit( {
398
400
  setAttributes( { url: '' } );
399
401
  speak( __( 'Link removed.' ), 'assertive' );
400
402
  } }
401
- onChange={ ( updatedValue ) => {
402
- // updateAttributes determines the final state and returns metadata
403
- const {
404
- isEntityLink,
405
- attributes: updatedAttributes,
406
- } = updateAttributes(
407
- updatedValue,
408
- setAttributes,
409
- attributes
410
- );
411
-
412
- // Handle URL binding based on the final computed state
413
- // Only create bindings for entity links (posts, pages, taxonomies)
414
- // Never create bindings for custom links (manual URLs)
415
- if ( isEntityLink ) {
416
- createBinding( updatedAttributes );
417
- } else {
418
- clearBinding();
419
- }
420
- } }
403
+ onChange={ handleLinkChange }
421
404
  />
422
405
  ) }
423
406
  </ParentElement>
@@ -9,6 +9,19 @@ require_once __DIR__ . '/navigation-link/shared/item-should-render.php';
9
9
  require_once __DIR__ . '/navigation-link/shared/render-submenu-icon.php';
10
10
  require_once __DIR__ . '/navigation-link/shared/build-css-font-sizes.php';
11
11
 
12
+ /**
13
+ * Renders the submenu icon SVG for the Navigation Submenu block.
14
+ *
15
+ * @since 5.9.0
16
+ * @deprecated 7.0.0 Use block_core_shared_navigation_render_submenu_icon() instead.
17
+ *
18
+ * @return string SVG markup for the submenu icon.
19
+ */
20
+ function block_core_navigation_submenu_render_submenu_icon() {
21
+ _deprecated_function( __FUNCTION__, '7.0.0', 'block_core_shared_navigation_render_submenu_icon()' );
22
+ return block_core_shared_navigation_render_submenu_icon();
23
+ }
24
+
12
25
  /**
13
26
  * Returns the submenu visibility value with backward compatibility
14
27
  * for the deprecated openSubmenusOnClick attribute.
@@ -2,7 +2,10 @@
2
2
  * WordPress dependencies
3
3
  */
4
4
  import { useRef } from '@wordpress/element';
5
- import { useRefEffect } from '@wordpress/compose';
5
+ import {
6
+ useRefEffect,
7
+ privateApis as composePrivateApis,
8
+ } from '@wordpress/compose';
6
9
  import { ENTER } from '@wordpress/keycodes';
7
10
  import { useSelect, useDispatch, useRegistry } from '@wordpress/data';
8
11
  import { store as blockEditorStore } from '@wordpress/block-editor';
@@ -13,6 +16,13 @@ import {
13
16
  getDefaultBlockName,
14
17
  } from '@wordpress/blocks';
15
18
 
19
+ /**
20
+ * Internal dependencies
21
+ */
22
+ import { unlock } from '../lock-unlock';
23
+
24
+ const { subscribeDelegatedListener } = unlock( composePrivateApis );
25
+
16
26
  export function useOnEnter( props ) {
17
27
  const { batch } = useRegistry();
18
28
  const { moveBlocksToPosition, replaceBlocks, selectionChange } =
@@ -119,9 +129,13 @@ export function useOnEnter( props ) {
119
129
  } );
120
130
  }
121
131
 
122
- element.addEventListener( 'keydown', onKeyDown );
123
- return () => {
124
- element.removeEventListener( 'keydown', onKeyDown );
125
- };
132
+ // Capture phase so we run before writing-flow's ancestor-bubble
133
+ // keydown handlers that gate on `event.defaultPrevented`.
134
+ return subscribeDelegatedListener(
135
+ element,
136
+ 'keydown',
137
+ onKeyDown,
138
+ true
139
+ );
126
140
  }, [] );
127
141
  }
@@ -99,11 +99,15 @@ export default function PostDateEdit( props ) {
99
99
 
100
100
  const blockEditingMode = useBlockEditingMode();
101
101
 
102
+ const validDatetime = datetime || new Date();
102
103
  let postDate = (
103
- <time dateTime={ dateI18n( 'c', datetime ) } ref={ setPopoverAnchor }>
104
+ <time
105
+ dateTime={ dateI18n( 'c', validDatetime ) }
106
+ ref={ setPopoverAnchor }
107
+ >
104
108
  { format === 'human-diff'
105
- ? humanTimeDiff( datetime )
106
- : dateI18n( format || siteFormat, datetime ) }
109
+ ? humanTimeDiff( validDatetime )
110
+ : dateI18n( format || siteFormat, validDatetime ) }
107
111
  </time>
108
112
  );
109
113
 
@@ -278,7 +278,6 @@ export default function PostFeaturedImageEdit( {
278
278
  }
279
279
  >
280
280
  <ToggleControl
281
- __nextHasNoMarginBottom
282
281
  label={ __( 'Make image a link' ) }
283
282
  onChange={ () =>
284
283
  setAttributes( { isLink: ! isLink } )
@@ -17,7 +17,7 @@ import {
17
17
  PanelBody,
18
18
  SelectControl,
19
19
  ToggleControl,
20
- Icon,
20
+ Icon as WCIcon,
21
21
  } from '@wordpress/components';
22
22
  import { __ } from '@wordpress/i18n';
23
23
  import { search } from '@wordpress/icons';
@@ -374,7 +374,7 @@ export default function SearchEdit( {
374
374
  return (
375
375
  <View style={ richTextButtonContainerStyle }>
376
376
  { buttonUseIcon && (
377
- <Icon
377
+ <WCIcon
378
378
  icon={ search }
379
379
  { ...iconStyles }
380
380
  onLayout={ onLayoutButton }
@@ -6,7 +6,7 @@ import { render } from 'test/helpers';
6
6
  /**
7
7
  * WordPress dependencies
8
8
  */
9
- import { Icon } from '@wordpress/components';
9
+ import { Icon as WCIcon } from '@wordpress/components';
10
10
 
11
11
  /**
12
12
  * Internal dependencies
@@ -129,7 +129,7 @@ describe( 'Search Block', () => {
129
129
  } );
130
130
 
131
131
  it( 'search button uses icon', () => {
132
- const button = instance.UNSAFE_getByType( Icon );
132
+ const button = instance.UNSAFE_getByType( WCIcon );
133
133
  expect( button ).toBeTruthy();
134
134
  } );
135
135
 
@@ -116,8 +116,9 @@ const SiteLogo = ( {
116
116
  }
117
117
  }, [ isSelected ] );
118
118
 
119
+ // Always apply modal updates as snackbar Undo may restore the original id.
119
120
  const handleMediaUpdate = ( { id: newId } ) => {
120
- if ( typeof newId === 'number' && newId !== logoId ) {
121
+ if ( typeof newId === 'number' ) {
121
122
  setLogo( newId );
122
123
  }
123
124
  };
@@ -19,7 +19,7 @@ import {
19
19
  } from '@wordpress/block-editor';
20
20
  import { useState, useRef, createInterpolateElement } from '@wordpress/element';
21
21
  import {
22
- Icon,
22
+ Icon as WCIcon,
23
23
  Button,
24
24
  Dropdown,
25
25
  TextControl,
@@ -277,7 +277,7 @@ const SocialLinkEdit = ( {
277
277
  */
278
278
  /* eslint-disable jsx-a11y/no-redundant-roles */ }
279
279
  <button aria-haspopup="dialog" { ...blockProps } role="button">
280
- <Icon icon={ icon } />
280
+ <WCIcon icon={ icon } />
281
281
  <span
282
282
  className={ clsx( 'wp-block-social-link-label', {
283
283
  'screen-reader-text': ! showLabels,
@@ -14,6 +14,8 @@ import { useSelect } from '@wordpress/data';
14
14
  import AddTabToolbarControl from '../tab-panel/add-tab-toolbar-control';
15
15
  import RemoveTabToolbarControl from '../tab-panel/remove-tab-toolbar-control';
16
16
 
17
+ const TAB_LIST_TEMPLATE = [ [ 'core/tab' ], [ 'core/tab' ] ];
18
+
17
19
  function Edit( { clientId } ) {
18
20
  const tabsClientId = useSelect(
19
21
  ( select ) =>
@@ -26,6 +28,7 @@ function Edit( { clientId } ) {
26
28
  const innerBlocksProps = useInnerBlocksProps( blockProps, {
27
29
  allowedBlocks: [ 'core/tab' ],
28
30
  orientation: 'horizontal',
31
+ template: TAB_LIST_TEMPLATE,
29
32
  templateLock: false,
30
33
  renderAppender: false,
31
34
  } );
@@ -7,6 +7,7 @@ import {
7
7
  store as blockEditorStore,
8
8
  } from '@wordpress/block-editor';
9
9
  import { useSelect } from '@wordpress/data';
10
+ import { __ } from '@wordpress/i18n';
10
11
 
11
12
  /**
12
13
  * Internal dependencies
@@ -14,7 +15,15 @@ import { useSelect } from '@wordpress/data';
14
15
  import AddTabToolbarControl from '../tab-panel/add-tab-toolbar-control';
15
16
  import RemoveTabToolbarControl from '../tab-panel/remove-tab-toolbar-control';
16
17
 
17
- const TAB_PANELS_TEMPLATE = [ [ 'core/tab-panel', {} ] ];
18
+ /**
19
+ * Initial template applied only when the block is first inserted (i.e. when
20
+ * inner blocks are empty). templateLock is false, so this is never applied to
21
+ * existing blocks that already have tab panels saved.
22
+ */
23
+ const TAB_PANELS_TEMPLATE = [
24
+ [ 'core/tab-panel', { label: __( 'Tab' ) } ],
25
+ [ 'core/tab-panel', { label: __( 'Tab' ) } ],
26
+ ];
18
27
 
19
28
  export default function Edit( { clientId } ) {
20
29
  const blockProps = useBlockProps();
package/src/table/edit.js CHANGED
@@ -631,6 +631,7 @@ const Cell = memo( function ( {
631
631
  ) }
632
632
  >
633
633
  <RichText
634
+ identifier={ `${ name }.${ rowIndex }.cells.${ columnIndex }.content` }
634
635
  value={ content }
635
636
  onChange={ onChange }
636
637
  onFocus={ () => {
package/src/tabs/edit.js CHANGED
@@ -8,8 +8,7 @@ import {
8
8
  store as blockEditorStore,
9
9
  } from '@wordpress/block-editor';
10
10
  import { useSelect } from '@wordpress/data';
11
- import { useMemo, useEffect } from '@wordpress/element';
12
- import { __ } from '@wordpress/i18n';
11
+ import { useMemo } from '@wordpress/element';
13
12
 
14
13
  /**
15
14
  * Internal dependencies
@@ -19,50 +18,23 @@ import useTabListSync from './use-tab-list-sync';
19
18
 
20
19
  const EMPTY_ARRAY = [];
21
20
 
22
- const TABS_TEMPLATE = [
23
- [
24
- 'core/tab-list',
25
- {},
26
- [
27
- [ 'core/tab', {} ],
28
- [ 'core/tab', {} ],
29
- ],
30
- ],
31
- [
32
- 'core/tab-panels',
33
- {},
34
- [
35
- [
36
- 'core/tab-panel',
37
- {
38
- label: __( 'Tab' ),
39
- },
40
- [ [ 'core/paragraph' ] ],
41
- ],
42
- [
43
- 'core/tab-panel',
44
- {
45
- label: __( 'Tab' ),
46
- },
47
- [ [ 'core/paragraph' ] ],
48
- ],
49
- ],
50
- ],
51
- ];
21
+ /**
22
+ * Only the two structural child blocks are specified here — without inner
23
+ * block entries for core/tab-list or core/tab-panels.
24
+ *
25
+ * If inner blocks were included in this template, `synchronizeBlocksWithTemplate`
26
+ * (called whenever templateLock === 'all') would recurse into the containers and
27
+ * truncate them to the template count, causing data loss when a saved block with
28
+ * more than two tabs is re-opened in the editor.
29
+ *
30
+ * Initial tab/panel creation is delegated to the tab-panels template in
31
+ * tab-panels/edit.js (templateLock: false, applied only when empty).
32
+ */
33
+ const TABS_TEMPLATE = [ [ 'core/tab-list' ], [ 'core/tab-panels' ] ];
52
34
 
53
35
  function Edit( { clientId, attributes, setAttributes } ) {
54
36
  const { anchor, activeTabIndex, editorActiveTabIndex } = attributes;
55
37
 
56
- /**
57
- * Initialize editorActiveTabIndex to activeTabIndex on mount.
58
- * This ensures the ephemeral editor state starts at the persisted default.
59
- */
60
- useEffect( () => {
61
- if ( editorActiveTabIndex === undefined ) {
62
- setAttributes( { editorActiveTabIndex: activeTabIndex } );
63
- }
64
- }, [] ); // eslint-disable-line react-hooks/exhaustive-deps
65
-
66
38
  const { tabPanels, tabPanelsClientId, tabs, tabListClientId } = useSelect(
67
39
  ( select ) => {
68
40
  const { getBlocks } = select( blockEditorStore );