@wordpress/block-editor 15.18.1-next.v.202604201441.0 → 15.19.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 (283) hide show
  1. package/CHANGELOG.md +7 -1
  2. package/build/components/autocomplete/index.cjs.map +3 -3
  3. package/build/components/background-image-control/index.cjs +2 -1
  4. package/build/components/background-image-control/index.cjs.map +2 -2
  5. package/build/components/block-allowed-blocks/modal.cjs.map +2 -2
  6. package/build/components/block-bindings/attribute-control.cjs.map +3 -3
  7. package/build/components/block-card/index.cjs +2 -2
  8. package/build/components/block-card/index.cjs.map +3 -3
  9. package/build/components/block-controls/fill.cjs.map +2 -2
  10. package/build/components/block-inspector/edit-contents.cjs +7 -1
  11. package/build/components/block-inspector/edit-contents.cjs.map +2 -2
  12. package/build/components/block-mover/button.cjs +9 -3
  13. package/build/components/block-mover/button.cjs.map +2 -2
  14. package/build/components/block-pattern-setup/index.cjs +3 -2
  15. package/build/components/block-pattern-setup/index.cjs.map +2 -2
  16. package/build/components/block-patterns-list/index.cjs +2 -1
  17. package/build/components/block-patterns-list/index.cjs.map +2 -2
  18. package/build/components/block-patterns-paging/index.cjs.map +3 -3
  19. package/build/components/block-settings-menu/block-settings-dropdown.cjs +2 -2
  20. package/build/components/block-settings-menu/block-settings-dropdown.cjs.map +3 -3
  21. package/build/components/block-settings-menu/index.cjs +2 -2
  22. package/build/components/block-settings-menu/index.cjs.map +3 -3
  23. package/build/components/block-styles/menu-items.cjs.map +3 -3
  24. package/build/components/block-switcher/index.cjs.map +3 -3
  25. package/build/components/block-switcher/pattern-transformations-menu.cjs +2 -1
  26. package/build/components/block-switcher/pattern-transformations-menu.cjs.map +2 -2
  27. package/build/components/block-toolbar/edit-section-button.cjs +7 -1
  28. package/build/components/block-toolbar/edit-section-button.cjs.map +2 -2
  29. package/build/components/block-toolbar/pattern-overrides-dropdown.cjs.map +3 -3
  30. package/build/components/block-variation-transforms/index.cjs +4 -3
  31. package/build/components/block-variation-transforms/index.cjs.map +2 -2
  32. package/build/components/block-visibility/modal.cjs +0 -10
  33. package/build/components/block-visibility/modal.cjs.map +3 -3
  34. package/build/components/block-visibility/viewport-visibility-info.cjs +2 -2
  35. package/build/components/block-visibility/viewport-visibility-info.cjs.map +3 -3
  36. package/build/components/collab/{block-comment-icon-slot.cjs → note-icon-slot.cjs} +8 -8
  37. package/build/components/collab/note-icon-slot.cjs.map +7 -0
  38. package/build/components/collab/{block-comment-icon-toolbar-slot.cjs → note-icon-toolbar-slot.cjs} +9 -9
  39. package/build/components/collab/note-icon-toolbar-slot.cjs.map +7 -0
  40. package/build/components/date-format-picker/index.cjs +2 -1
  41. package/build/components/date-format-picker/index.cjs.map +2 -2
  42. package/build/components/dimensions-tool/scale-tool.cjs +2 -2
  43. package/build/components/dimensions-tool/scale-tool.cjs.map +2 -2
  44. package/build/components/global-styles/state-control.cjs +111 -37
  45. package/build/components/global-styles/state-control.cjs.map +3 -3
  46. package/build/components/gradients/use-gradient.cjs +2 -2
  47. package/build/components/gradients/use-gradient.cjs.map +2 -2
  48. package/build/components/grid/grid-item-movers.cjs +2 -1
  49. package/build/components/grid/grid-item-movers.cjs.map +2 -2
  50. package/build/components/iframe/use-scale-canvas.cjs.map +2 -2
  51. package/build/components/inserter/block-patterns-tab/pattern-category-previews.cjs.map +2 -2
  52. package/build/components/inserter/index.cjs +41 -43
  53. package/build/components/inserter/index.cjs.map +2 -2
  54. package/build/components/inserter/menu.cjs +32 -3
  55. package/build/components/inserter/menu.cjs.map +3 -3
  56. package/build/components/inserter/search-results.cjs +3 -3
  57. package/build/components/inserter/search-results.cjs.map +2 -2
  58. package/build/components/inserter/tips.cjs +1 -1
  59. package/build/components/inserter/tips.cjs.map +2 -2
  60. package/build/components/inspector-popover-header/index.cjs.map +3 -3
  61. package/build/components/link-control/link-preview.cjs +2 -2
  62. package/build/components/link-control/link-preview.cjs.map +2 -2
  63. package/build/components/link-control/settings.cjs +2 -1
  64. package/build/components/link-control/settings.cjs.map +2 -2
  65. package/build/components/link-picker/link-picker.cjs +3 -2
  66. package/build/components/link-picker/link-picker.cjs.map +2 -2
  67. package/build/components/link-picker/link-preview.cjs +2 -2
  68. package/build/components/link-picker/link-preview.cjs.map +2 -2
  69. package/build/components/list-view/block-select-button.cjs +2 -2
  70. package/build/components/list-view/block-select-button.cjs.map +2 -2
  71. package/build/components/list-view/index.cjs +2 -1
  72. package/build/components/list-view/index.cjs.map +2 -2
  73. package/build/components/provider/index.cjs +80 -7
  74. package/build/components/provider/index.cjs.map +2 -2
  75. package/build/components/responsive-block-control/label.cjs +9 -2
  76. package/build/components/responsive-block-control/label.cjs.map +2 -2
  77. package/build/components/rich-text/event-listeners/index.cjs.map +2 -2
  78. package/build/components/rich-text/event-listeners/paste-handler.cjs +12 -5
  79. package/build/components/rich-text/event-listeners/paste-handler.cjs.map +3 -3
  80. package/build/hooks/block-bindings.cjs.map +3 -3
  81. package/build/hooks/custom-css.cjs +1 -1
  82. package/build/hooks/custom-css.cjs.map +2 -2
  83. package/build/layouts/flex.cjs +5 -8
  84. package/build/layouts/flex.cjs.map +3 -3
  85. package/build/layouts/grid.cjs +5 -5
  86. package/build/layouts/grid.cjs.map +2 -2
  87. package/build/private-apis.cjs +5 -4
  88. package/build/private-apis.cjs.map +3 -3
  89. package/build/store/actions.cjs +2 -2
  90. package/build/store/actions.cjs.map +2 -2
  91. package/build/store/private-keys.cjs +3 -0
  92. package/build/store/private-keys.cjs.map +2 -2
  93. package/build/store/reducer.cjs +8 -30
  94. package/build/store/reducer.cjs.map +2 -2
  95. package/build/store/selectors.cjs.map +2 -2
  96. package/build/utils/dom.cjs +3 -1
  97. package/build/utils/dom.cjs.map +2 -2
  98. package/build-module/components/autocomplete/index.mjs +2 -2
  99. package/build-module/components/autocomplete/index.mjs.map +2 -2
  100. package/build-module/components/background-image-control/index.mjs +2 -2
  101. package/build-module/components/background-image-control/index.mjs.map +2 -2
  102. package/build-module/components/block-allowed-blocks/modal.mjs +2 -2
  103. package/build-module/components/block-allowed-blocks/modal.mjs.map +2 -2
  104. package/build-module/components/block-bindings/attribute-control.mjs +3 -3
  105. package/build-module/components/block-bindings/attribute-control.mjs.map +2 -2
  106. package/build-module/components/block-card/index.mjs +4 -4
  107. package/build-module/components/block-card/index.mjs.map +2 -2
  108. package/build-module/components/block-controls/fill.mjs.map +2 -2
  109. package/build-module/components/block-inspector/edit-contents.mjs +7 -1
  110. package/build-module/components/block-inspector/edit-contents.mjs.map +2 -2
  111. package/build-module/components/block-mover/button.mjs +11 -5
  112. package/build-module/components/block-mover/button.mjs.map +2 -2
  113. package/build-module/components/block-pattern-setup/index.mjs +2 -1
  114. package/build-module/components/block-pattern-setup/index.mjs.map +2 -2
  115. package/build-module/components/block-patterns-list/index.mjs +1 -1
  116. package/build-module/components/block-patterns-list/index.mjs.map +2 -2
  117. package/build-module/components/block-patterns-paging/index.mjs +3 -3
  118. package/build-module/components/block-patterns-paging/index.mjs.map +2 -2
  119. package/build-module/components/block-settings-menu/block-settings-dropdown.mjs +2 -2
  120. package/build-module/components/block-settings-menu/block-settings-dropdown.mjs.map +2 -2
  121. package/build-module/components/block-settings-menu/index.mjs +2 -2
  122. package/build-module/components/block-settings-menu/index.mjs.map +2 -2
  123. package/build-module/components/block-styles/menu-items.mjs +2 -2
  124. package/build-module/components/block-styles/menu-items.mjs.map +2 -2
  125. package/build-module/components/block-switcher/index.mjs +2 -2
  126. package/build-module/components/block-switcher/index.mjs.map +2 -2
  127. package/build-module/components/block-switcher/pattern-transformations-menu.mjs +2 -7
  128. package/build-module/components/block-switcher/pattern-transformations-menu.mjs.map +2 -2
  129. package/build-module/components/block-toolbar/edit-section-button.mjs +7 -1
  130. package/build-module/components/block-toolbar/edit-section-button.mjs.map +2 -2
  131. package/build-module/components/block-toolbar/pattern-overrides-dropdown.mjs +2 -2
  132. package/build-module/components/block-toolbar/pattern-overrides-dropdown.mjs.map +2 -2
  133. package/build-module/components/block-variation-transforms/index.mjs +4 -4
  134. package/build-module/components/block-variation-transforms/index.mjs.map +2 -2
  135. package/build-module/components/block-visibility/modal.mjs +0 -10
  136. package/build-module/components/block-visibility/modal.mjs.map +3 -3
  137. package/build-module/components/block-visibility/viewport-visibility-info.mjs +4 -4
  138. package/build-module/components/block-visibility/viewport-visibility-info.mjs.map +2 -2
  139. package/build-module/components/collab/note-icon-slot.mjs +8 -0
  140. package/build-module/components/collab/note-icon-slot.mjs.map +7 -0
  141. package/build-module/components/collab/note-icon-toolbar-slot.mjs +10 -0
  142. package/build-module/components/collab/note-icon-toolbar-slot.mjs.map +7 -0
  143. package/build-module/components/date-format-picker/index.mjs +2 -2
  144. package/build-module/components/date-format-picker/index.mjs.map +2 -2
  145. package/build-module/components/dimensions-tool/scale-tool.mjs +2 -2
  146. package/build-module/components/dimensions-tool/scale-tool.mjs.map +2 -2
  147. package/build-module/components/global-styles/state-control.mjs +119 -40
  148. package/build-module/components/global-styles/state-control.mjs.map +2 -2
  149. package/build-module/components/gradients/use-gradient.mjs +2 -2
  150. package/build-module/components/gradients/use-gradient.mjs.map +2 -2
  151. package/build-module/components/grid/grid-item-movers.mjs +2 -5
  152. package/build-module/components/grid/grid-item-movers.mjs.map +2 -2
  153. package/build-module/components/iframe/use-scale-canvas.mjs.map +2 -2
  154. package/build-module/components/inserter/block-patterns-tab/pattern-category-previews.mjs +3 -3
  155. package/build-module/components/inserter/block-patterns-tab/pattern-category-previews.mjs.map +1 -1
  156. package/build-module/components/inserter/index.mjs +41 -43
  157. package/build-module/components/inserter/index.mjs.map +2 -2
  158. package/build-module/components/inserter/menu.mjs +34 -4
  159. package/build-module/components/inserter/menu.mjs.map +2 -2
  160. package/build-module/components/inserter/search-results.mjs +1 -1
  161. package/build-module/components/inserter/search-results.mjs.map +1 -1
  162. package/build-module/components/inserter/tips.mjs +1 -1
  163. package/build-module/components/inserter/tips.mjs.map +2 -2
  164. package/build-module/components/inspector-popover-header/index.mjs +2 -2
  165. package/build-module/components/inspector-popover-header/index.mjs.map +2 -2
  166. package/build-module/components/link-control/link-preview.mjs +2 -2
  167. package/build-module/components/link-control/link-preview.mjs.map +2 -2
  168. package/build-module/components/link-control/settings.mjs +3 -2
  169. package/build-module/components/link-control/settings.mjs.map +2 -2
  170. package/build-module/components/link-picker/link-picker.mjs +1 -1
  171. package/build-module/components/link-picker/link-picker.mjs.map +2 -2
  172. package/build-module/components/link-picker/link-preview.mjs +2 -2
  173. package/build-module/components/link-picker/link-preview.mjs.map +2 -2
  174. package/build-module/components/list-view/block-select-button.mjs +2 -2
  175. package/build-module/components/list-view/block-select-button.mjs.map +2 -2
  176. package/build-module/components/list-view/index.mjs +2 -4
  177. package/build-module/components/list-view/index.mjs.map +2 -2
  178. package/build-module/components/provider/index.mjs +82 -8
  179. package/build-module/components/provider/index.mjs.map +2 -2
  180. package/build-module/components/responsive-block-control/label.mjs +9 -2
  181. package/build-module/components/responsive-block-control/label.mjs.map +2 -2
  182. package/build-module/components/rich-text/event-listeners/index.mjs.map +2 -2
  183. package/build-module/components/rich-text/event-listeners/paste-handler.mjs +12 -5
  184. package/build-module/components/rich-text/event-listeners/paste-handler.mjs.map +2 -2
  185. package/build-module/hooks/block-bindings.mjs +2 -2
  186. package/build-module/hooks/block-bindings.mjs.map +2 -2
  187. package/build-module/hooks/custom-css.mjs +1 -1
  188. package/build-module/hooks/custom-css.mjs.map +2 -2
  189. package/build-module/layouts/flex.mjs +4 -7
  190. package/build-module/layouts/flex.mjs.map +2 -2
  191. package/build-module/layouts/grid.mjs +4 -4
  192. package/build-module/layouts/grid.mjs.map +2 -2
  193. package/build-module/private-apis.mjs +7 -5
  194. package/build-module/private-apis.mjs.map +2 -2
  195. package/build-module/store/actions.mjs +2 -2
  196. package/build-module/store/actions.mjs.map +2 -2
  197. package/build-module/store/private-keys.mjs +2 -0
  198. package/build-module/store/private-keys.mjs.map +2 -2
  199. package/build-module/store/reducer.mjs +8 -30
  200. package/build-module/store/reducer.mjs.map +2 -2
  201. package/build-module/store/selectors.mjs.map +2 -2
  202. package/build-module/utils/dom.mjs +2 -1
  203. package/build-module/utils/dom.mjs.map +2 -2
  204. package/build-style/content-rtl.css +0 -3
  205. package/build-style/content.css +0 -3
  206. package/build-style/style-rtl.css +29 -3
  207. package/build-style/style.css +29 -3
  208. package/build-types/components/block-context/index.d.ts +9 -16
  209. package/build-types/components/block-context/index.d.ts.map +1 -1
  210. package/build-types/utils/dom.d.ts +13 -6
  211. package/build-types/utils/dom.d.ts.map +1 -1
  212. package/package.json +39 -38
  213. package/src/components/autocomplete/index.js +4 -2
  214. package/src/components/background-image-control/index.js +2 -2
  215. package/src/components/block-allowed-blocks/modal.js +3 -3
  216. package/src/components/block-bindings/attribute-control.js +4 -4
  217. package/src/components/block-card/index.js +5 -5
  218. package/src/components/block-controls/fill.js +1 -0
  219. package/src/components/block-inspector/edit-contents.js +4 -2
  220. package/src/components/block-list/content.scss +0 -4
  221. package/src/components/block-manager/style.scss +3 -2
  222. package/src/components/block-mover/button.js +17 -7
  223. package/src/components/block-pattern-setup/index.js +2 -1
  224. package/src/components/block-patterns-list/index.js +1 -1
  225. package/src/components/block-patterns-paging/index.js +5 -6
  226. package/src/components/block-settings-menu/block-settings-dropdown.js +2 -2
  227. package/src/components/block-settings-menu/index.js +2 -2
  228. package/src/components/block-styles/menu-items.js +3 -3
  229. package/src/components/block-switcher/index.js +3 -3
  230. package/src/components/block-switcher/pattern-transformations-menu.js +2 -7
  231. package/src/components/block-toolbar/edit-section-button.js +5 -1
  232. package/src/components/block-toolbar/pattern-overrides-dropdown.js +2 -2
  233. package/src/components/block-variation-transforms/index.js +4 -4
  234. package/src/components/block-visibility/modal.js +0 -1
  235. package/src/components/block-visibility/viewport-visibility-info.js +5 -5
  236. package/src/components/collab/note-icon-slot.js +8 -0
  237. package/src/components/collab/note-icon-toolbar-slot.js +10 -0
  238. package/src/components/date-format-picker/index.js +4 -2
  239. package/src/components/dimensions-tool/scale-tool.js +2 -2
  240. package/src/components/global-styles/state-control.js +152 -49
  241. package/src/components/global-styles/style.scss +9 -0
  242. package/src/components/gradients/use-gradient.js +3 -1
  243. package/src/components/grid/grid-item-movers.js +2 -5
  244. package/src/components/iframe/use-scale-canvas.js +0 -4
  245. package/src/components/inner-blocks/README.md +5 -1
  246. package/src/components/inner-blocks/index.native.js +1 -1
  247. package/src/components/inserter/block-patterns-tab/pattern-category-previews.js +5 -5
  248. package/src/components/inserter/index.js +58 -69
  249. package/src/components/inserter/menu.js +35 -3
  250. package/src/components/inserter/search-results.js +1 -1
  251. package/src/components/inserter/style.scss +18 -3
  252. package/src/components/inserter/tips.js +1 -1
  253. package/src/components/inspector-popover-header/index.js +2 -2
  254. package/src/components/link-control/link-preview.js +3 -3
  255. package/src/components/link-control/settings.js +3 -2
  256. package/src/components/link-picker/link-picker.js +1 -1
  257. package/src/components/link-picker/link-preview.js +3 -3
  258. package/src/components/list-view/block-select-button.js +3 -3
  259. package/src/components/list-view/index.js +2 -4
  260. package/src/components/provider/index.js +149 -8
  261. package/src/components/responsive-block-control/label.js +5 -2
  262. package/src/components/rich-text/event-listeners/index.js +0 -1
  263. package/src/components/rich-text/event-listeners/paste-handler.js +18 -4
  264. package/src/hooks/block-bindings.js +3 -3
  265. package/src/hooks/custom-css.js +1 -8
  266. package/src/layouts/flex.js +7 -9
  267. package/src/layouts/grid.js +7 -4
  268. package/src/private-apis.js +6 -4
  269. package/src/store/actions.js +12 -6
  270. package/src/store/private-keys.js +1 -0
  271. package/src/store/reducer.js +11 -39
  272. package/src/store/selectors.js +6 -0
  273. package/src/store/test/reducer.js +39 -0
  274. package/src/utils/dom.js +3 -3
  275. package/src/utils/test/dom.js +47 -4
  276. package/build/components/collab/block-comment-icon-slot.cjs.map +0 -7
  277. package/build/components/collab/block-comment-icon-toolbar-slot.cjs.map +0 -7
  278. package/build-module/components/collab/block-comment-icon-slot.mjs +0 -8
  279. package/build-module/components/collab/block-comment-icon-slot.mjs.map +0 -7
  280. package/build-module/components/collab/block-comment-icon-toolbar-slot.mjs +0 -10
  281. package/build-module/components/collab/block-comment-icon-toolbar-slot.mjs.map +0 -7
  282. package/src/components/collab/block-comment-icon-slot.js +0 -8
  283. package/src/components/collab/block-comment-icon-toolbar-slot.js +0 -10
@@ -8,6 +8,7 @@ import {
8
8
  MediaUploadProvider,
9
9
  store as uploadStore,
10
10
  detectClientSideMediaSupport,
11
+ isHeicCanvasSupported,
11
12
  } from '@wordpress/upload-media';
12
13
 
13
14
  /**
@@ -38,6 +39,17 @@ let hasLoggedFallback = false;
38
39
  */
39
40
  let isClientSideMediaEnabledCache = null;
40
41
 
42
+ /**
43
+ * Cached result of whether HEIC-only canvas processing should be enabled.
44
+ */
45
+ let isHeicCanvasEnabledCache = null;
46
+
47
+ /**
48
+ * HEIC MIME types that should be routed through the upload-media pipeline
49
+ * when in HEIC-only mode.
50
+ */
51
+ const HEIC_MIME_TYPES = [ 'image/heic', 'image/heif' ];
52
+
41
53
  /**
42
54
  * Checks if client-side media processing should be enabled.
43
55
  *
@@ -85,6 +97,44 @@ function shouldEnableClientSideMediaProcessing() {
85
97
  return true;
86
98
  }
87
99
 
100
+ /**
101
+ * Checks if HEIC-only canvas processing should be enabled.
102
+ *
103
+ * Returns true when:
104
+ * 1. Full client-side processing is NOT available (otherwise it handles HEIC already)
105
+ * 2. The server has set the __heicUploadSupport flag
106
+ * 3. The browser supports createImageBitmap + OffscreenCanvas (e.g. Safari)
107
+ *
108
+ * @return {boolean} Whether HEIC-only canvas processing should be enabled.
109
+ */
110
+ function shouldEnableHeicCanvasProcessing() {
111
+ if ( isHeicCanvasEnabledCache !== null ) {
112
+ return isHeicCanvasEnabledCache;
113
+ }
114
+
115
+ // If full client-side processing is enabled, it already handles HEIC.
116
+ if ( shouldEnableClientSideMediaProcessing() ) {
117
+ isHeicCanvasEnabledCache = false;
118
+ return false;
119
+ }
120
+
121
+ if ( ! window.__heicUploadSupport ) {
122
+ isHeicCanvasEnabledCache = false;
123
+ return false;
124
+ }
125
+
126
+ if (
127
+ typeof isHeicCanvasSupported !== 'function' ||
128
+ ! isHeicCanvasSupported()
129
+ ) {
130
+ isHeicCanvasEnabledCache = false;
131
+ return false;
132
+ }
133
+
134
+ isHeicCanvasEnabledCache = true;
135
+ return true;
136
+ }
137
+
88
138
  /**
89
139
  * Upload a media file when the file upload button is activated
90
140
  * or when adding a file to the editor via drag & drop.
@@ -128,6 +178,92 @@ function mediaUpload(
128
178
  } );
129
179
  }
130
180
 
181
+ /**
182
+ * Upload interceptor for HEIC-only mode.
183
+ *
184
+ * Routes HEIC files through the upload-media pipeline for canvas-based
185
+ * conversion, while passing non-HEIC files to the original mediaUpload
186
+ * function for standard server-side processing.
187
+ *
188
+ * @param {WPDataRegistry} registry
189
+ * @param {Object} settings Block editor settings.
190
+ * @param {Object} $3 Parameters object passed to the function.
191
+ * @param {Array} $3.allowedTypes Array with the types of media that can be uploaded, if unset all types are allowed.
192
+ * @param {Object} $3.additionalData Additional data to include in the request.
193
+ * @param {Array<File>} $3.filesList List of files.
194
+ * @param {Function} $3.onError Function called when an error happens.
195
+ * @param {Function} $3.onFileChange Function called each time a file or a temporary representation of the file is available.
196
+ * @param {Function} $3.onSuccess Function called once a file has completely finished uploading, including thumbnails.
197
+ * @param {Function} $3.onBatchSuccess Function called once all files in a group have completely finished uploading, including thumbnails.
198
+ */
199
+ function heicMediaUpload(
200
+ registry,
201
+ settings,
202
+ {
203
+ allowedTypes,
204
+ additionalData = {},
205
+ filesList,
206
+ onError = noop,
207
+ onFileChange,
208
+ onSuccess,
209
+ onBatchSuccess,
210
+ }
211
+ ) {
212
+ const files = Array.from( filesList );
213
+ const heicFiles = files.filter( ( file ) =>
214
+ HEIC_MIME_TYPES.includes( file.type )
215
+ );
216
+ const otherFiles = files.filter(
217
+ ( file ) => ! HEIC_MIME_TYPES.includes( file.type )
218
+ );
219
+
220
+ // When the batch contains both HEIC and non-HEIC files, coordinate
221
+ // onBatchSuccess so it fires only after *both* paths have completed.
222
+ const hasBothPaths =
223
+ heicFiles.length > 0 && otherFiles.length > 0 && settings?.mediaUpload;
224
+ let pathsRemaining = hasBothPaths ? 2 : 1;
225
+ const coordinatedBatchSuccess = hasBothPaths
226
+ ? () => {
227
+ pathsRemaining--;
228
+ if ( pathsRemaining <= 0 ) {
229
+ onBatchSuccess?.();
230
+ }
231
+ }
232
+ : onBatchSuccess;
233
+
234
+ // Route HEIC files through the upload-media pipeline.
235
+ if ( heicFiles.length > 0 ) {
236
+ void registry.dispatch( uploadStore ).addItems( {
237
+ files: heicFiles,
238
+ onChange: onFileChange,
239
+ onSuccess: ( attachments ) => {
240
+ settings?.[ mediaUploadOnSuccessKey ]?.( attachments );
241
+ onSuccess?.( attachments );
242
+ },
243
+ onBatchSuccess: coordinatedBatchSuccess,
244
+ onError: ( error ) =>
245
+ onError(
246
+ typeof error === 'string' ? error : error?.message ?? ''
247
+ ),
248
+ additionalData,
249
+ allowedTypes,
250
+ } );
251
+ }
252
+
253
+ // Pass non-HEIC files to the original server-side upload function.
254
+ if ( otherFiles.length > 0 && settings?.mediaUpload ) {
255
+ settings.mediaUpload( {
256
+ allowedTypes,
257
+ additionalData,
258
+ filesList: otherFiles,
259
+ onError,
260
+ onFileChange,
261
+ onSuccess,
262
+ onBatchSuccess: coordinatedBatchSuccess,
263
+ } );
264
+ }
265
+ }
266
+
131
267
  /**
132
268
  * Calls useBlockSync as a child of SelectionContext.Provider so that the
133
269
  * hook can read selection state from the context provided by this tree
@@ -152,6 +288,9 @@ export const ExperimentalBlockEditorProvider = withRegistryProvider(
152
288
 
153
289
  const isClientSideMediaEnabled =
154
290
  shouldEnableClientSideMediaProcessing();
291
+ const isHeicCanvasEnabled = shouldEnableHeicCanvasProcessing();
292
+ const useUploadMediaPipeline =
293
+ isClientSideMediaEnabled || isHeicCanvasEnabled;
155
294
 
156
295
  // Nested providers (e.g. from useBlockPreview) inherit settings
157
296
  // where mediaUpload has already been replaced with the
@@ -162,16 +301,17 @@ export const ExperimentalBlockEditorProvider = withRegistryProvider(
162
301
 
163
302
  const settings = useMemo( () => {
164
303
  if (
165
- isClientSideMediaEnabled &&
304
+ useUploadMediaPipeline &&
166
305
  _settings?.mediaUpload &&
167
306
  ! isMediaUploadIntercepted
168
307
  ) {
169
- // Create a new object so that the original props.settings.mediaUpload is not modified.
170
- const interceptor = mediaUpload.bind(
171
- null,
172
- registry,
173
- _settings
174
- );
308
+ // Choose the right interceptor:
309
+ // - Full mode: all uploads go through upload-media pipeline.
310
+ // - HEIC-only mode: only HEIC files go through, rest use legacy path.
311
+ const uploadFn = isClientSideMediaEnabled
312
+ ? mediaUpload
313
+ : heicMediaUpload;
314
+ const interceptor = uploadFn.bind( null, registry, _settings );
175
315
  interceptor.__isMediaUploadInterceptor = true;
176
316
  return {
177
317
  ..._settings,
@@ -182,6 +322,7 @@ export const ExperimentalBlockEditorProvider = withRegistryProvider(
182
322
  }, [
183
323
  _settings,
184
324
  registry,
325
+ useUploadMediaPipeline,
185
326
  isClientSideMediaEnabled,
186
327
  isMediaUploadIntercepted,
187
328
  ] );
@@ -258,7 +399,7 @@ export const ExperimentalBlockEditorProvider = withRegistryProvider(
258
399
  // overwrite the store's server-side function with the
259
400
  // interceptor, causing uploads to loop instead of reaching
260
401
  // the server.
261
- if ( isClientSideMediaEnabled && ! isMediaUploadIntercepted ) {
402
+ if ( useUploadMediaPipeline && ! isMediaUploadIntercepted ) {
262
403
  return (
263
404
  <MediaUploadProvider
264
405
  settings={ mediaUploadSettings }
@@ -2,7 +2,7 @@
2
2
  * WordPress dependencies
3
3
  */
4
4
  import { useInstanceId } from '@wordpress/compose';
5
- import { VisuallyHidden } from '@wordpress/components';
5
+ import { VisuallyHidden } from '@wordpress/ui';
6
6
  import { _x, sprintf } from '@wordpress/i18n';
7
7
 
8
8
  export default function ResponsiveBlockControlLabel( {
@@ -27,7 +27,10 @@ export default function ResponsiveBlockControlLabel( {
27
27
  <span aria-describedby={ `rbc-desc-${ instanceId }` }>
28
28
  { viewport.label }
29
29
  </span>
30
- <VisuallyHidden as="span" id={ `rbc-desc-${ instanceId }` }>
30
+ <VisuallyHidden
31
+ id={ `rbc-desc-${ instanceId }` }
32
+ render={ <span /> }
33
+ >
31
34
  { accessibleLabel }
32
35
  </VisuallyHidden>
33
36
  </>
@@ -36,7 +36,6 @@ const allEventListeners = [
36
36
  export function useEventListeners( props ) {
37
37
  const propsRef = useRef( props );
38
38
  useInsertionEffect( () => {
39
- // eslint-disable-next-line react-compiler/react-compiler -- false positive, see https://github.com/facebook/react/issues/29196
40
39
  propsRef.current = props;
41
40
  } );
42
41
  const refEffects = useMemo(
@@ -8,6 +8,7 @@ import { isURL } from '@wordpress/url';
8
8
  /**
9
9
  * Internal dependencies
10
10
  */
11
+ import { store as blockEditorStore } from '../../../store';
11
12
  import { addActiveFormats } from '../utils';
12
13
  import { getPasteEventData } from '../../../utils/pasting';
13
14
 
@@ -25,6 +26,7 @@ export default ( props ) => ( element ) => {
25
26
  __unstableEmbedURLOnPaste,
26
27
  preserveWhiteSpace,
27
28
  pastePlainText,
29
+ registry,
28
30
  } = props.current;
29
31
 
30
32
  // The event listener is attached to the window, so we need to check if
@@ -116,11 +118,23 @@ export default ( props ) => ( element ) => {
116
118
 
117
119
  if ( typeof content === 'string' ) {
118
120
  pasteInline( content );
119
- } else if ( content.length > 0 ) {
120
- if ( onReplace && isEmpty( value ) ) {
121
- onReplace( content, content.length - 1, -1 );
122
- }
121
+ return;
122
+ }
123
+
124
+ if ( ! content.length || ! onReplace || ! isEmpty( value ) ) {
125
+ return;
123
126
  }
127
+
128
+ // Record an intermediate paragraph-with-URL state so a single undo
129
+ // after the URL → block transformation restores the pasted link.
130
+ if ( mode === 'BLOCKS' ) {
131
+ pasteInline( html );
132
+ registry
133
+ .dispatch( blockEditorStore )
134
+ .__unstableMarkLastChangeAsPersistent();
135
+ }
136
+
137
+ onReplace( content, content.length - 1, -1 );
124
138
  }
125
139
 
126
140
  const { defaultView } = element.ownerDocument;
@@ -5,7 +5,7 @@ import { __ } from '@wordpress/i18n';
5
5
  import { store as blocksStore } from '@wordpress/blocks';
6
6
  import {
7
7
  __experimentalItemGroup as ItemGroup,
8
- __experimentalText as Text,
8
+ __experimentalText as WCText,
9
9
  __experimentalToolsPanel as ToolsPanel,
10
10
  } from '@wordpress/components';
11
11
  import { useSelect } from '@wordpress/data';
@@ -103,13 +103,13 @@ export const BlockBindingsPanel = ( { name: blockName, metadata } ) => {
103
103
  Use a div element to make the ToolsPanelHiddenInnerWrapper
104
104
  toggle the visibility of this help text automatically.
105
105
  */ }
106
- <Text as="div" variant="muted">
106
+ <WCText as="div" variant="muted">
107
107
  <p>
108
108
  { __(
109
109
  'Attributes connected to custom fields or other dynamic data.'
110
110
  ) }
111
111
  </p>
112
- </Text>
112
+ </WCText>
113
113
  </ToolsPanel>
114
114
  </InspectorControls>
115
115
  );
@@ -1,18 +1,11 @@
1
- /**
2
- * WordPress dependencies
3
- */
4
1
  import { useEffect, useMemo } from '@wordpress/element';
5
2
  import { useDispatch, useSelect } from '@wordpress/data';
6
3
  import { useInstanceId } from '@wordpress/compose';
7
4
  import { getBlockType, hasBlockSupport } from '@wordpress/blocks';
8
5
  import { __, sprintf } from '@wordpress/i18n';
9
6
  import { processCSSNesting } from '@wordpress/global-styles-engine';
10
- import { useBlockEditingMode } from '../components/block-editing-mode';
11
7
  import { store as noticesStore } from '@wordpress/notices';
12
-
13
- /**
14
- * Internal dependencies
15
- */
8
+ import { useBlockEditingMode } from '../components/block-editing-mode';
16
9
  import InspectorControls from '../components/inspector-controls';
17
10
  import AdvancedPanel, {
18
11
  validateCSS,
@@ -23,7 +23,8 @@ import {
23
23
  * Internal dependencies
24
24
  */
25
25
  import { appendSelectors, getBlockGapCSS } from './utils';
26
- import { getGapCSSValue } from '../hooks/gap';
26
+ import { getGapCSSValue, getGapBoxControlValueFromStyle } from '../hooks/gap';
27
+ import { getSpacingPresetCssVar } from '../components/spacing-sizes-control/utils';
27
28
  import {
28
29
  BlockControls,
29
30
  JustifyContentControl,
@@ -147,15 +148,12 @@ export default {
147
148
  // falling back to '0.5em' for backwards compatibility.
148
149
  let fallbackGapValue = '0.5em';
149
150
  if ( globalBlockGapValue ) {
150
- // Process the global gap value to handle preset values
151
- const processedGlobalGap = getGapCSSValue(
152
- globalBlockGapValue,
153
- '0.5em'
154
- );
155
- // Use the column gap value (second value if two values exist)
156
- const gapParts = processedGlobalGap.split( ' ' );
151
+ const gapBox =
152
+ getGapBoxControlValueFromStyle( globalBlockGapValue );
157
153
  fallbackGapValue =
158
- gapParts.length > 1 ? gapParts[ 1 ] : gapParts[ 0 ];
154
+ getSpacingPresetCssVar( gapBox?.left ) ||
155
+ getSpacingPresetCssVar( gapBox?.top ) ||
156
+ '0.5em';
159
157
  }
160
158
 
161
159
  // If a block's block.json skips serialization for spacing or spacing.blockGap,
@@ -21,7 +21,8 @@ import { useState } from '@wordpress/element';
21
21
  * Internal dependencies
22
22
  */
23
23
  import { appendSelectors, getBlockGapCSS } from './utils';
24
- import { getGapCSSValue } from '../hooks/gap';
24
+ import { getGapCSSValue, getGapBoxControlValueFromStyle } from '../hooks/gap';
25
+ import { getSpacingPresetCssVar } from '../components/spacing-sizes-control/utils';
25
26
  import { shouldSkipSerialization } from '../hooks/utils';
26
27
  import { LAYOUT_DEFINITIONS } from './definitions';
27
28
 
@@ -143,10 +144,12 @@ export default {
143
144
  // If the gap value has both top and left (separated by space), use the left value for horizontal calculations.
144
145
  let fallbackGapValue = '1.2rem';
145
146
  if ( globalBlockGapValue ) {
146
- const processedGap = getGapCSSValue( globalBlockGapValue, '0.5em' );
147
- const gapParts = processedGap.split( ' ' );
147
+ const gapBox =
148
+ getGapBoxControlValueFromStyle( globalBlockGapValue );
148
149
  fallbackGapValue =
149
- gapParts.length > 1 ? gapParts[ 1 ] : gapParts[ 0 ];
150
+ getSpacingPresetCssVar( gapBox?.left ) ||
151
+ getSpacingPresetCssVar( gapBox?.top ) ||
152
+ '1.2rem';
150
153
  }
151
154
 
152
155
  // If a block's block.json skips serialization for spacing or spacing.blockGap,
@@ -50,6 +50,7 @@ import {
50
50
  isNavigationOverlayContextKey,
51
51
  isNavigationPostEditorKey,
52
52
  mediaUploadOnSuccessKey,
53
+ openMediaEditorModalKey,
53
54
  } from './store/private-keys';
54
55
  import { requiresWrapperOnCopy } from './components/writing-flow/utils';
55
56
  import { PrivateRichText } from './components/rich-text/';
@@ -59,8 +60,8 @@ import { PrivatePublishDateTimePicker } from './components/publish-date-time-pic
59
60
  import useSpacingSizes from './components/spacing-sizes-control/hooks/use-spacing-sizes';
60
61
  import useBlockDisplayTitle from './components/block-title/use-block-display-title';
61
62
  import TabbedSidebar from './components/tabbed-sidebar';
62
- import CommentIconSlotFill from './components/collab/block-comment-icon-slot';
63
- import CommentIconToolbarSlotFill from './components/collab/block-comment-icon-toolbar-slot';
63
+ import NoteIconSlotFill from './components/collab/note-icon-slot';
64
+ import NoteIconToolbarSlotFill from './components/collab/note-icon-toolbar-slot';
64
65
  import HTMLElementControl from './components/html-element-control';
65
66
  import {
66
67
  useBlockElementRef,
@@ -124,8 +125,8 @@ lock( privateApis, {
124
125
  BlockStyleVariationOverridesWithConfig,
125
126
  setBackgroundStyleDefaults,
126
127
  sectionRootClientIdKey,
127
- CommentIconSlotFill,
128
- CommentIconToolbarSlotFill,
128
+ NoteIconSlotFill,
129
+ NoteIconToolbarSlotFill,
129
130
  mediaEditKey,
130
131
  getMediaSelectKey,
131
132
  deviceTypeKey,
@@ -133,6 +134,7 @@ lock( privateApis, {
133
134
  isNavigationOverlayContextKey,
134
135
  isNavigationPostEditorKey,
135
136
  mediaUploadOnSuccessKey,
137
+ openMediaEditorModalKey,
136
138
  useBlockElement,
137
139
  useBlockElementRef,
138
140
  LinkPicker,
@@ -88,6 +88,12 @@ export const validateBlocksToTemplate =
88
88
  /**
89
89
  * A block selection object.
90
90
  *
91
+ * This type is duplicated to avoid creating circular dependencies.
92
+ *
93
+ * @see {import("@wordpress/block-editor/src/store/selectors").WPBlockSelection}
94
+ * @see {import("@wordpress/core-data/src/types").WPBlockSelection}
95
+ * @see {import("@wordpress/editor/src/store/selectors").WPBlockSelection}
96
+ *
91
97
  * @typedef {Object} WPBlockSelection
92
98
  *
93
99
  * @property {string} clientId A block client ID.
@@ -1770,9 +1776,9 @@ export const insertBeforeBlock =
1770
1776
  const rootClientId = select.getBlockRootClientId( clientId );
1771
1777
 
1772
1778
  const blockIndex = select.getBlockIndex( clientId );
1773
- const directInsertBlock = rootClientId
1774
- ? select.getDirectInsertBlock( rootClientId )
1775
- : null;
1779
+ const { defaultBlock: directInsertBlock } = rootClientId
1780
+ ? select.getBlockListSettings( rootClientId ) ?? {}
1781
+ : {};
1776
1782
 
1777
1783
  if ( ! directInsertBlock ) {
1778
1784
  return dispatch.insertDefaultBlock( {}, rootClientId, blockIndex );
@@ -1809,9 +1815,9 @@ export const insertAfterBlock =
1809
1815
  const rootClientId = select.getBlockRootClientId( clientId );
1810
1816
 
1811
1817
  const blockIndex = select.getBlockIndex( clientId );
1812
- const directInsertBlock = rootClientId
1813
- ? select.getDirectInsertBlock( rootClientId )
1814
- : null;
1818
+ const { defaultBlock: directInsertBlock } = rootClientId
1819
+ ? select.getBlockListSettings( rootClientId ) ?? {}
1820
+ : {};
1815
1821
 
1816
1822
  if ( ! directInsertBlock ) {
1817
1823
  return dispatch.insertDefaultBlock(
@@ -12,3 +12,4 @@ export const isNavigationOverlayContextKey = Symbol(
12
12
  );
13
13
  export const isNavigationPostEditorKey = Symbol( 'isNavigationPostEditor' );
14
14
  export const mediaUploadOnSuccessKey = Symbol( 'mediaUploadOnSuccess' );
15
+ export const openMediaEditorModalKey = Symbol( 'openMediaEditorModal' );
@@ -292,7 +292,6 @@ const withBlockTree =
292
292
  false
293
293
  );
294
294
  break;
295
- case 'SYNC_DERIVED_BLOCK_ATTRIBUTES':
296
295
  case 'UPDATE_BLOCK_ATTRIBUTES': {
297
296
  newState.tree = new Map( newState.tree );
298
297
  action.clientIds.forEach( ( clientId ) => {
@@ -421,63 +420,37 @@ const withBlockTree =
421
420
  function withPersistentBlockChange( reducer ) {
422
421
  let lastAction;
423
422
  let markNextChangeAsNotPersistent = false;
424
- let explicitPersistent;
425
423
 
426
424
  return ( state, action ) => {
427
- let nextState = reducer( state, action );
428
-
429
- let nextIsPersistentChange;
430
- if ( action.type === 'SET_EXPLICIT_PERSISTENT' ) {
431
- explicitPersistent = action.isPersistentChange;
432
- nextIsPersistentChange = state.isPersistentChange ?? true;
433
- }
425
+ const nextState = reducer( state, action );
434
426
 
435
- if ( explicitPersistent !== undefined ) {
436
- nextIsPersistentChange = explicitPersistent;
437
- return nextIsPersistentChange === nextState.isPersistentChange
438
- ? nextState
439
- : {
440
- ...nextState,
441
- isPersistentChange: nextIsPersistentChange,
442
- };
443
- }
427
+ const wasMarkedAsNotPersistent = markNextChangeAsNotPersistent;
428
+ markNextChangeAsNotPersistent =
429
+ action.type === 'MARK_NEXT_CHANGE_AS_NOT_PERSISTENT';
444
430
 
445
431
  const isExplicitPersistentChange =
446
432
  action.type === 'MARK_LAST_CHANGE_AS_PERSISTENT' ||
447
- markNextChangeAsNotPersistent;
433
+ wasMarkedAsNotPersistent;
448
434
 
449
435
  // Defer to previous state value (or default) unless changing or
450
436
  // explicitly marking as persistent.
451
437
  if ( state === nextState && ! isExplicitPersistentChange ) {
452
- markNextChangeAsNotPersistent =
453
- action.type === 'MARK_NEXT_CHANGE_AS_NOT_PERSISTENT';
454
-
455
- nextIsPersistentChange = state?.isPersistentChange ?? true;
456
- if ( state.isPersistentChange === nextIsPersistentChange ) {
438
+ if ( state.isPersistentChange !== undefined ) {
457
439
  return state;
458
440
  }
459
-
460
- return {
461
- ...nextState,
462
- isPersistentChange: nextIsPersistentChange,
463
- };
441
+ return { ...nextState, isPersistentChange: true };
464
442
  }
465
443
 
466
- nextState = {
467
- ...nextState,
468
- isPersistentChange: isExplicitPersistentChange
469
- ? ! markNextChangeAsNotPersistent
470
- : ! isUpdatingSameBlockAttribute( action, lastAction ),
471
- };
444
+ const isPersistentChange = isExplicitPersistentChange
445
+ ? ! wasMarkedAsNotPersistent
446
+ : ! isUpdatingSameBlockAttribute( action, lastAction );
472
447
 
473
448
  // In comparing against the previous action, consider only those which
474
449
  // would have qualified as one which would have been ignored or not
475
450
  // have resulted in a changed state.
476
451
  lastAction = action;
477
- markNextChangeAsNotPersistent =
478
- action.type === 'MARK_NEXT_CHANGE_AS_NOT_PERSISTENT';
479
452
 
480
- return nextState;
453
+ return { ...nextState, isPersistentChange };
481
454
  };
482
455
  }
483
456
 
@@ -897,7 +870,6 @@ export const blocks = pipe(
897
870
  return newState;
898
871
  }
899
872
 
900
- case 'SYNC_DERIVED_BLOCK_ATTRIBUTES':
901
873
  case 'UPDATE_BLOCK_ATTRIBUTES': {
902
874
  // Avoid a state change if none of the block IDs are known.
903
875
  if ( action.clientIds.every( ( id ) => ! state.get( id ) ) ) {
@@ -51,6 +51,12 @@ const { isContentBlock } = unlock( blocksPrivateApis );
51
51
  /**
52
52
  * A block selection object.
53
53
  *
54
+ * This type is duplicated to avoid creating circular dependencies.
55
+ *
56
+ * @see {import("@wordpress/block-editor/src/store/actions").WPBlockSelection}
57
+ * @see {import("@wordpress/core-data/src/types").WPBlockSelection}
58
+ * @see {import("@wordpress/editor/src/store/selectors").WPBlockSelection}
59
+ *
54
60
  * @typedef {Object} WPBlockSelection
55
61
  *
56
62
  * @property {string} clientId A block client ID.
@@ -2196,6 +2196,45 @@ describe( 'state', () => {
2196
2196
  expect( state.isPersistentChange ).toBe( true );
2197
2197
  } );
2198
2198
 
2199
+ it( 'should flag only the next change as not persistent', () => {
2200
+ let original = deepFreeze(
2201
+ blocks( undefined, {
2202
+ type: 'RESET_BLOCKS',
2203
+ blocks: [
2204
+ {
2205
+ clientId: 'kumquat',
2206
+ attributes: {},
2207
+ innerBlocks: [],
2208
+ },
2209
+ ],
2210
+ } )
2211
+ );
2212
+ original = blocks( original, {
2213
+ type: 'MARK_NEXT_CHANGE_AS_NOT_PERSISTENT',
2214
+ } );
2215
+
2216
+ const nextState = blocks( original, {
2217
+ type: 'UPDATE_BLOCK_ATTRIBUTES',
2218
+ clientIds: [ 'kumquat' ],
2219
+ attributes: {
2220
+ updated: true,
2221
+ },
2222
+ } );
2223
+
2224
+ expect( nextState.isPersistentChange ).toBe( false );
2225
+
2226
+ // A subsequent change should revert to persistent.
2227
+ const subsequentState = blocks( nextState, {
2228
+ type: 'UPDATE_BLOCK_ATTRIBUTES',
2229
+ clientIds: [ 'kumquat' ],
2230
+ attributes: {
2231
+ other: true,
2232
+ },
2233
+ } );
2234
+
2235
+ expect( subsequentState.isPersistentChange ).toBe( true );
2236
+ } );
2237
+
2199
2238
  it( 'should retain reference for same state, same persistence', () => {
2200
2239
  const original = deepFreeze(
2201
2240
  blocks( undefined, {
package/src/utils/dom.js CHANGED
@@ -80,14 +80,14 @@ export function rectUnion( rect1, rect2 ) {
80
80
  * @param {Element} element Element.
81
81
  * @return {boolean} Whether the element is visible.
82
82
  */
83
- function isElementVisible( element ) {
83
+ export function isElementVisible( element ) {
84
84
  const viewport = element.ownerDocument.defaultView;
85
85
  if ( ! viewport ) {
86
86
  return false;
87
87
  }
88
88
 
89
- // Check for <VisuallyHidden> component.
90
- if ( element.classList.contains( 'components-visually-hidden' ) ) {
89
+ // Check for <VisuallyHidden> components.
90
+ if ( element.hasAttribute( 'data-visually-hidden' ) ) {
91
91
  return false;
92
92
  }
93
93