@wordpress/block-library 9.40.2-next.v.202602271551.0 → 9.40.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (250) hide show
  1. package/build/accordion/view.cjs +34 -0
  2. package/build/accordion/view.cjs.map +2 -2
  3. package/build/comment-reply-link/edit.cjs +2 -1
  4. package/build/comment-reply-link/edit.cjs.map +2 -2
  5. package/build/comments/edit/placeholder.cjs +2 -1
  6. package/build/comments/edit/placeholder.cjs.map +2 -2
  7. package/build/cover/edit/index.cjs +39 -26
  8. package/build/cover/edit/index.cjs.map +2 -2
  9. package/build/cover/embed-video-utils.cjs +8 -6
  10. package/build/cover/embed-video-utils.cjs.map +2 -2
  11. package/build/embed/embed-preview.cjs +2 -1
  12. package/build/embed/embed-preview.cjs.map +2 -2
  13. package/build/html/block.json +2 -1
  14. package/build/html/modal.cjs +147 -230
  15. package/build/html/modal.cjs.map +3 -3
  16. package/build/icon/block.json +3 -12
  17. package/build/image/image.cjs +1 -1
  18. package/build/image/image.cjs.map +2 -2
  19. package/build/latest-comments/deprecated.cjs +33 -0
  20. package/build/latest-comments/deprecated.cjs.map +2 -2
  21. package/build/navigation/edit/index.cjs +125 -123
  22. package/build/navigation/edit/index.cjs.map +3 -3
  23. package/build/navigation/edit/leaf-more-menu.cjs +6 -68
  24. package/build/navigation/edit/leaf-more-menu.cjs.map +3 -3
  25. package/build/navigation/edit/menu-inspector-controls.cjs +91 -20
  26. package/build/navigation/edit/menu-inspector-controls.cjs.map +3 -3
  27. package/build/navigation/edit/navigation-menu-selector.cjs +4 -5
  28. package/build/navigation/edit/navigation-menu-selector.cjs.map +3 -3
  29. package/build/navigation/edit/placeholder/index.cjs +2 -2
  30. package/build/navigation/edit/placeholder/index.cjs.map +3 -3
  31. package/build/navigation/use-navigation-entities.cjs +67 -0
  32. package/build/navigation/use-navigation-entities.cjs.map +7 -0
  33. package/build/navigation/view.cjs +9 -2
  34. package/build/navigation/view.cjs.map +2 -2
  35. package/build/navigation-link/edit.cjs +2 -1
  36. package/build/navigation-link/edit.cjs.map +2 -2
  37. package/build/navigation-link/shared/use-handle-link-change.cjs +19 -3
  38. package/build/navigation-link/shared/use-handle-link-change.cjs.map +3 -3
  39. package/build/navigation-link/shared/use-link-preview.cjs +2 -2
  40. package/build/navigation-link/shared/use-link-preview.cjs.map +2 -2
  41. package/build/navigation-submenu/edit.cjs +8 -22
  42. package/build/navigation-submenu/edit.cjs.map +2 -2
  43. package/build/nextpage/block.json +0 -1
  44. package/build/paragraph/edit.cjs +1 -1
  45. package/build/paragraph/edit.cjs.map +1 -1
  46. package/build/post-navigation-link/block.json +3 -1
  47. package/build/post-navigation-link/edit.cjs +36 -2
  48. package/build/post-navigation-link/edit.cjs.map +3 -3
  49. package/build/post-navigation-link/index.cjs +0 -2
  50. package/build/post-navigation-link/index.cjs.map +3 -3
  51. package/build/post-title/block.json +3 -1
  52. package/build/post-title/deprecated.cjs +1 -82
  53. package/build/post-title/deprecated.cjs.map +3 -3
  54. package/build/post-title/edit.cjs +36 -10
  55. package/build/post-title/edit.cjs.map +3 -3
  56. package/build/query-title/block.json +3 -1
  57. package/build/query-title/deprecated.cjs +1 -70
  58. package/build/query-title/deprecated.cjs.map +3 -3
  59. package/build/query-title/edit.cjs +35 -17
  60. package/build/query-title/edit.cjs.map +3 -3
  61. package/build/shortcode/block.json +2 -1
  62. package/build/site-tagline/block.json +4 -6
  63. package/build/site-tagline/deprecated.cjs +1 -66
  64. package/build/site-tagline/deprecated.cjs.map +3 -3
  65. package/build/site-tagline/edit.cjs +28 -14
  66. package/build/site-tagline/edit.cjs.map +3 -3
  67. package/build/site-title/block.json +3 -1
  68. package/build/site-title/deprecated.cjs +1 -79
  69. package/build/site-title/deprecated.cjs.map +3 -3
  70. package/build/site-title/edit.cjs +30 -14
  71. package/build/site-title/edit.cjs.map +3 -3
  72. package/build/tabs-menu-item/block.json +26 -1
  73. package/build/tabs-menu-item/controls.cjs +100 -2
  74. package/build/tabs-menu-item/controls.cjs.map +3 -3
  75. package/build/tabs-menu-item/edit.cjs +65 -6
  76. package/build/tabs-menu-item/edit.cjs.map +2 -2
  77. package/build/tabs-menu-item/save.cjs +15 -1
  78. package/build/tabs-menu-item/save.cjs.map +2 -2
  79. package/build-module/accordion/view.mjs +35 -1
  80. package/build-module/accordion/view.mjs.map +2 -2
  81. package/build-module/comment-reply-link/edit.mjs +3 -2
  82. package/build-module/comment-reply-link/edit.mjs.map +2 -2
  83. package/build-module/comments/edit/placeholder.mjs +3 -2
  84. package/build-module/comments/edit/placeholder.mjs.map +2 -2
  85. package/build-module/cover/edit/index.mjs +47 -29
  86. package/build-module/cover/edit/index.mjs.map +2 -2
  87. package/build-module/cover/embed-video-utils.mjs +7 -5
  88. package/build-module/cover/embed-video-utils.mjs.map +2 -2
  89. package/build-module/embed/embed-preview.mjs +2 -1
  90. package/build-module/embed/embed-preview.mjs.map +2 -2
  91. package/build-module/html/block.json +2 -1
  92. package/build-module/html/modal.mjs +149 -232
  93. package/build-module/html/modal.mjs.map +2 -2
  94. package/build-module/icon/block.json +3 -12
  95. package/build-module/image/image.mjs +1 -1
  96. package/build-module/image/image.mjs.map +2 -2
  97. package/build-module/latest-comments/deprecated.mjs +33 -0
  98. package/build-module/latest-comments/deprecated.mjs.map +2 -2
  99. package/build-module/navigation/edit/index.mjs +125 -123
  100. package/build-module/navigation/edit/index.mjs.map +2 -2
  101. package/build-module/navigation/edit/leaf-more-menu.mjs +7 -73
  102. package/build-module/navigation/edit/leaf-more-menu.mjs.map +2 -2
  103. package/build-module/navigation/edit/menu-inspector-controls.mjs +101 -21
  104. package/build-module/navigation/edit/menu-inspector-controls.mjs.map +2 -2
  105. package/build-module/navigation/edit/navigation-menu-selector.mjs +5 -6
  106. package/build-module/navigation/edit/navigation-menu-selector.mjs.map +2 -2
  107. package/build-module/navigation/edit/placeholder/index.mjs +2 -2
  108. package/build-module/navigation/edit/placeholder/index.mjs.map +2 -2
  109. package/build-module/navigation/use-navigation-entities.mjs +46 -0
  110. package/build-module/navigation/use-navigation-entities.mjs.map +7 -0
  111. package/build-module/navigation/view.mjs +9 -2
  112. package/build-module/navigation/view.mjs.map +2 -2
  113. package/build-module/navigation-link/edit.mjs +2 -1
  114. package/build-module/navigation-link/edit.mjs.map +2 -2
  115. package/build-module/navigation-link/shared/use-handle-link-change.mjs +19 -3
  116. package/build-module/navigation-link/shared/use-handle-link-change.mjs.map +2 -2
  117. package/build-module/navigation-link/shared/use-link-preview.mjs +2 -2
  118. package/build-module/navigation-link/shared/use-link-preview.mjs.map +2 -2
  119. package/build-module/navigation-submenu/edit.mjs +9 -23
  120. package/build-module/navigation-submenu/edit.mjs.map +2 -2
  121. package/build-module/nextpage/block.json +0 -1
  122. package/build-module/paragraph/edit.mjs +2 -2
  123. package/build-module/paragraph/edit.mjs.map +1 -1
  124. package/build-module/post-navigation-link/block.json +3 -1
  125. package/build-module/post-navigation-link/edit.mjs +30 -3
  126. package/build-module/post-navigation-link/edit.mjs.map +2 -2
  127. package/build-module/post-navigation-link/index.mjs +0 -2
  128. package/build-module/post-navigation-link/index.mjs.map +2 -2
  129. package/build-module/post-title/block.json +3 -1
  130. package/build-module/post-title/deprecated.mjs +1 -82
  131. package/build-module/post-title/deprecated.mjs.map +2 -2
  132. package/build-module/post-title/edit.mjs +27 -10
  133. package/build-module/post-title/edit.mjs.map +2 -2
  134. package/build-module/query-title/block.json +3 -1
  135. package/build-module/query-title/deprecated.mjs +1 -70
  136. package/build-module/query-title/deprecated.mjs.map +2 -2
  137. package/build-module/query-title/edit.mjs +36 -17
  138. package/build-module/query-title/edit.mjs.map +2 -2
  139. package/build-module/shortcode/block.json +2 -1
  140. package/build-module/site-tagline/block.json +4 -6
  141. package/build-module/site-tagline/deprecated.mjs +1 -66
  142. package/build-module/site-tagline/deprecated.mjs.map +2 -2
  143. package/build-module/site-tagline/edit.mjs +29 -14
  144. package/build-module/site-tagline/edit.mjs.map +2 -2
  145. package/build-module/site-title/block.json +3 -1
  146. package/build-module/site-title/deprecated.mjs +1 -79
  147. package/build-module/site-title/deprecated.mjs.map +2 -2
  148. package/build-module/site-title/edit.mjs +31 -14
  149. package/build-module/site-title/edit.mjs.map +2 -2
  150. package/build-module/tabs-menu-item/block.json +26 -1
  151. package/build-module/tabs-menu-item/controls.mjs +104 -3
  152. package/build-module/tabs-menu-item/controls.mjs.map +2 -2
  153. package/build-module/tabs-menu-item/edit.mjs +66 -6
  154. package/build-module/tabs-menu-item/edit.mjs.map +2 -2
  155. package/build-module/tabs-menu-item/save.mjs +15 -1
  156. package/build-module/tabs-menu-item/save.mjs.map +2 -2
  157. package/build-style/editor-rtl.css +20 -6
  158. package/build-style/editor.css +20 -6
  159. package/build-style/html/editor-rtl.css +10 -6
  160. package/build-style/html/editor.css +10 -6
  161. package/build-style/icon/editor-rtl.css +5 -0
  162. package/build-style/icon/editor.css +5 -0
  163. package/build-style/navigation/style-rtl.css +15 -1
  164. package/build-style/navigation/style.css +15 -1
  165. package/build-style/navigation-overlay-close/style-rtl.css +3 -3
  166. package/build-style/navigation-overlay-close/style.css +3 -3
  167. package/build-style/style-rtl.css +30 -7
  168. package/build-style/style.css +30 -7
  169. package/build-style/tabs-menu-item/editor-rtl.css +5 -0
  170. package/build-style/tabs-menu-item/editor.css +5 -0
  171. package/build-style/tabs-menu-item/style-rtl.css +12 -3
  172. package/build-style/tabs-menu-item/style.css +12 -3
  173. package/package.json +38 -38
  174. package/src/accordion/view.js +44 -1
  175. package/src/accordion-item/index.php +18 -5
  176. package/src/comment-reply-link/edit.js +5 -2
  177. package/src/comments/edit/placeholder.js +5 -2
  178. package/src/cover/edit/index.js +72 -35
  179. package/src/cover/embed-video-utils.js +9 -7
  180. package/src/cover/index.php +12 -4
  181. package/src/details/index.php +47 -0
  182. package/src/embed/embed-preview.js +6 -5
  183. package/src/html/block.json +2 -1
  184. package/src/html/editor.scss +15 -5
  185. package/src/html/modal.js +32 -99
  186. package/src/icon/block.json +3 -12
  187. package/src/icon/editor.scss +5 -0
  188. package/src/icon/index.php +3 -1
  189. package/src/image/image.js +14 -15
  190. package/src/image/index.php +7 -5
  191. package/src/latest-comments/deprecated.js +33 -0
  192. package/src/navigation/edit/index.js +136 -134
  193. package/src/navigation/edit/leaf-more-menu.js +11 -86
  194. package/src/navigation/edit/menu-inspector-controls.js +142 -23
  195. package/src/navigation/edit/navigation-menu-selector.js +5 -6
  196. package/src/navigation/edit/placeholder/index.js +2 -3
  197. package/src/navigation/edit/test/navigation-menu-selector.js +20 -23
  198. package/src/navigation/index.php +62 -9
  199. package/src/navigation/style.scss +17 -1
  200. package/src/navigation/use-navigation-entities.js +72 -0
  201. package/src/navigation/view.js +14 -2
  202. package/src/navigation-link/edit.js +1 -0
  203. package/src/navigation-link/shared/test/use-handle-link-change.test.js +212 -0
  204. package/src/navigation-link/shared/test/use-link-preview.test.js +9 -0
  205. package/src/navigation-link/shared/use-handle-link-change.js +36 -9
  206. package/src/navigation-link/shared/use-link-preview.js +6 -9
  207. package/src/navigation-overlay-close/style.scss +3 -3
  208. package/src/navigation-submenu/edit.js +11 -28
  209. package/src/nextpage/block.json +0 -1
  210. package/src/page-list/index.php +1 -1
  211. package/src/paragraph/edit.js +2 -2
  212. package/src/post-featured-image/index.php +4 -2
  213. package/src/post-navigation-link/block.json +3 -1
  214. package/src/post-navigation-link/edit.js +35 -2
  215. package/src/post-navigation-link/index.js +0 -2
  216. package/src/post-title/block.json +3 -1
  217. package/src/post-title/deprecated.js +1 -86
  218. package/src/post-title/edit.js +18 -2
  219. package/src/query-title/block.json +3 -1
  220. package/src/query-title/deprecated.js +1 -74
  221. package/src/query-title/edit.js +27 -11
  222. package/src/query-title/index.php +1 -1
  223. package/src/shortcode/block.json +2 -1
  224. package/src/site-tagline/block.json +4 -6
  225. package/src/site-tagline/deprecated.js +1 -70
  226. package/src/site-tagline/edit.js +22 -9
  227. package/src/site-title/block.json +3 -1
  228. package/src/site-title/deprecated.js +1 -83
  229. package/src/site-title/edit.js +22 -9
  230. package/src/tabs-menu-item/block.json +26 -1
  231. package/src/tabs-menu-item/controls.js +108 -0
  232. package/src/tabs-menu-item/edit.js +79 -6
  233. package/src/tabs-menu-item/editor.scss +6 -0
  234. package/src/tabs-menu-item/save.js +26 -1
  235. package/src/tabs-menu-item/style.scss +14 -3
  236. package/build/navigation/edit/navigation-link-ui.cjs +0 -97
  237. package/build/navigation/edit/navigation-link-ui.cjs.map +0 -7
  238. package/build/navigation/edit/navigation-list-view-header.cjs +0 -86
  239. package/build/navigation/edit/navigation-list-view-header.cjs.map +0 -7
  240. package/build/post-navigation-link/deprecated.cjs +0 -100
  241. package/build/post-navigation-link/deprecated.cjs.map +0 -7
  242. package/build-module/navigation/edit/navigation-link-ui.mjs +0 -76
  243. package/build-module/navigation/edit/navigation-link-ui.mjs.map +0 -7
  244. package/build-module/navigation/edit/navigation-list-view-header.mjs +0 -58
  245. package/build-module/navigation/edit/navigation-list-view-header.mjs.map +0 -7
  246. package/build-module/post-navigation-link/deprecated.mjs +0 -69
  247. package/build-module/post-navigation-link/deprecated.mjs.map +0 -7
  248. package/src/navigation/edit/navigation-link-ui.js +0 -115
  249. package/src/navigation/edit/navigation-list-view-header.js +0 -62
  250. package/src/post-navigation-link/deprecated.js +0 -72
@@ -7,8 +7,13 @@ import clsx from 'clsx';
7
7
  * WordPress dependencies
8
8
  */
9
9
  import { useEntityProp, store as coreStore } from '@wordpress/core-data';
10
- import { useEffect, useMemo, useRef } from '@wordpress/element';
11
- import { Placeholder, Spinner } from '@wordpress/components';
10
+ import {
11
+ useEffect,
12
+ useLayoutEffect,
13
+ useMemo,
14
+ useRef,
15
+ } from '@wordpress/element';
16
+ import { Placeholder, SandBox, Spinner } from '@wordpress/components';
12
17
  import { compose, useResizeObserver } from '@wordpress/compose';
13
18
  import {
14
19
  withColors,
@@ -49,7 +54,7 @@ import {
49
54
  DEFAULT_OVERLAY_COLOR,
50
55
  } from './color-utils';
51
56
  import { DEFAULT_MEDIA_SIZE_SLUG } from '../constants';
52
- import { getIframeSrc, getBackgroundVideoSrc } from '../embed-video-utils';
57
+ import { getBackgroundEmbedHtml } from '../embed-video-utils';
53
58
 
54
59
  function getInnerBlocksTemplate( attributes ) {
55
60
  return [
@@ -121,6 +126,14 @@ function CoverEdit( {
121
126
 
122
127
  const { __unstableMarkNextChangeAsNotPersistent } =
123
128
  useDispatch( blockEditorStore );
129
+
130
+ // Ref to access latest values after async operations (e.g. getMediaColor),
131
+ // avoiding stale values that could overwrite concurrent remote changes.
132
+ const propsRef = useRef( { attributes, overlayColor } );
133
+ useLayoutEffect( () => {
134
+ propsRef.current = { attributes, overlayColor };
135
+ } );
136
+
124
137
  const { media } = useSelect(
125
138
  ( select ) => {
126
139
  return {
@@ -155,26 +168,37 @@ function CoverEdit( {
155
168
 
156
169
  const averageBackgroundColor = await getMediaColor( mediaUrl );
157
170
 
158
- let newOverlayColor = overlayColor.color;
159
- if ( ! isUserOverlayColor ) {
171
+ // Read latest values after await to avoid stale closures.
172
+ const { attributes: currentAttrs, overlayColor: currentOverlay } =
173
+ propsRef.current;
174
+
175
+ let newOverlayColor = currentOverlay.color;
176
+ if ( ! currentAttrs.isUserOverlayColor ) {
160
177
  newOverlayColor = averageBackgroundColor;
161
178
  __unstableMarkNextChangeAsNotPersistent();
162
179
  setOverlayColor( newOverlayColor );
163
180
  }
164
181
 
165
182
  const newIsDark = compositeIsDark(
166
- dimRatio,
183
+ currentAttrs.dimRatio,
167
184
  newOverlayColor,
168
185
  averageBackgroundColor
169
186
  );
170
187
  __unstableMarkNextChangeAsNotPersistent();
171
188
  setAttributes( {
172
189
  isDark: newIsDark,
173
- isUserOverlayColor: isUserOverlayColor || false,
190
+ isUserOverlayColor: currentAttrs.isUserOverlayColor || false,
174
191
  } );
175
192
  } )();
176
193
  // Update the block only when the featured image changes.
177
- }, [ mediaUrl ] );
194
+ // The other dependencies are stable references (dispatch actions / setters).
195
+ }, [
196
+ mediaUrl,
197
+ __unstableMarkNextChangeAsNotPersistent,
198
+ setAttributes,
199
+ setOverlayColor,
200
+ useFeaturedImage,
201
+ ] );
178
202
 
179
203
  // instead of destructuring the attributes
180
204
  // we define the url and background type
@@ -201,8 +225,12 @@ function CoverEdit( {
201
225
  isImage ? newMedia?.url : undefined
202
226
  );
203
227
 
204
- let newOverlayColor = overlayColor.color;
205
- if ( ! isUserOverlayColor ) {
228
+ // Read latest values to avoid stale closures.
229
+ const { attributes: currentAttrs, overlayColor: currentOverlay } =
230
+ propsRef.current;
231
+
232
+ let newOverlayColor = currentOverlay.color;
233
+ if ( ! currentAttrs.isUserOverlayColor ) {
206
234
  newOverlayColor = averageBackgroundColor;
207
235
  setOverlayColor( newOverlayColor );
208
236
 
@@ -214,7 +242,9 @@ function CoverEdit( {
214
242
  // to avoid resetting to 50 if it has been explicitly set to 100.
215
243
  // See issue #52835 for context.
216
244
  const newDimRatio =
217
- originalUrl === undefined && dimRatio === 100 ? 50 : dimRatio;
245
+ currentAttrs.url === undefined && currentAttrs.dimRatio === 100
246
+ ? 50
247
+ : currentAttrs.dimRatio;
218
248
 
219
249
  const newIsDark = compositeIsDark(
220
250
  newDimRatio,
@@ -256,7 +286,7 @@ function CoverEdit( {
256
286
  useFeaturedImage: undefined,
257
287
  dimRatio: newDimRatio,
258
288
  isDark: newIsDark,
259
- isUserOverlayColor: isUserOverlayColor || false,
289
+ isUserOverlayColor: currentAttrs.isUserOverlayColor || false,
260
290
  } );
261
291
  };
262
292
 
@@ -290,8 +320,12 @@ function CoverEdit( {
290
320
 
291
321
  const onSetOverlayColor = async ( newOverlayColor ) => {
292
322
  const averageBackgroundColor = await getMediaColor( url );
323
+
324
+ // Read latest dimRatio after await to avoid stale closure.
325
+ const { attributes: currentAttrs } = propsRef.current;
326
+
293
327
  const newIsDark = compositeIsDark(
294
- dimRatio,
328
+ currentAttrs.dimRatio,
295
329
  newOverlayColor,
296
330
  averageBackgroundColor
297
331
  );
@@ -309,9 +343,13 @@ function CoverEdit( {
309
343
 
310
344
  const onUpdateDimRatio = async ( newDimRatio ) => {
311
345
  const averageBackgroundColor = await getMediaColor( url );
346
+
347
+ // Read latest overlayColor after await to avoid stale closure.
348
+ const { overlayColor: currentOverlay } = propsRef.current;
349
+
312
350
  const newIsDark = compositeIsDark(
313
351
  newDimRatio,
314
- overlayColor.color,
352
+ currentOverlay.color,
315
353
  averageBackgroundColor
316
354
  );
317
355
 
@@ -365,23 +403,15 @@ function CoverEdit( {
365
403
  [ url, backgroundType ]
366
404
  );
367
405
 
368
- // Compute embedSrc on-the-fly from embed preview for editor display
369
- const embedSrc = useMemo( () => {
406
+ // Compute embed HTML for editor display via SandBox
407
+ const embedHtml = useMemo( () => {
370
408
  if (
371
409
  backgroundType !== EMBED_VIDEO_BACKGROUND_TYPE ||
372
410
  ! embedPreview?.html
373
411
  ) {
374
412
  return null;
375
413
  }
376
-
377
- // Extract iframe src from embed HTML
378
- const iframeSrc = getIframeSrc( embedPreview.html );
379
- if ( ! iframeSrc ) {
380
- return null;
381
- }
382
-
383
- // Modify the src to add background video parameters (provider auto-detected)
384
- return getBackgroundVideoSrc( iframeSrc );
414
+ return getBackgroundEmbedHtml( embedPreview.html );
385
415
  }, [ embedPreview, backgroundType ] );
386
416
 
387
417
  const isUploadingMedia = isTemporaryMedia( id, url );
@@ -477,11 +507,15 @@ function CoverEdit( {
477
507
  ? await getMediaColor( mediaUrl )
478
508
  : DEFAULT_BACKGROUND_COLOR;
479
509
 
480
- const newOverlayColor = ! isUserOverlayColor
510
+ // Read latest values after await to avoid stale closures.
511
+ const { attributes: currentAttrs, overlayColor: currentOverlay } =
512
+ propsRef.current;
513
+
514
+ const newOverlayColor = ! currentAttrs.isUserOverlayColor
481
515
  ? averageBackgroundColor
482
- : overlayColor.color;
516
+ : currentOverlay.color;
483
517
 
484
- if ( ! isUserOverlayColor ) {
518
+ if ( ! currentAttrs.isUserOverlayColor ) {
485
519
  if ( newUseFeaturedImage ) {
486
520
  setOverlayColor( newOverlayColor );
487
521
  } else {
@@ -492,7 +526,8 @@ function CoverEdit( {
492
526
  __unstableMarkNextChangeAsNotPersistent();
493
527
  }
494
528
 
495
- const newDimRatio = dimRatio === 100 ? 50 : dimRatio;
529
+ const newDimRatio =
530
+ currentAttrs.dimRatio === 100 ? 50 : currentAttrs.dimRatio;
496
531
  const newIsDark = compositeIsDark(
497
532
  newDimRatio,
498
533
  newOverlayColor,
@@ -668,21 +703,23 @@ function CoverEdit( {
668
703
  style={ mediaStyle }
669
704
  />
670
705
  ) }
671
- { isEmbedVideoBackground && embedSrc && (
706
+ { isEmbedVideoBackground && embedHtml && (
672
707
  <div
673
708
  ref={ mediaElement }
674
709
  className="wp-block-cover__video-background wp-block-cover__embed-background"
675
710
  style={ mediaStyle }
676
711
  >
677
- <iframe
678
- src={ embedSrc }
712
+ <SandBox
713
+ allowSameOrigin
714
+ html={ embedHtml }
679
715
  title="Background video"
680
- frameBorder="0"
681
- allow="autoplay; fullscreen"
716
+ styles={ [
717
+ 'iframe{position:fixed;top:0;left:0;width:100%;height:100%;}',
718
+ ] }
682
719
  />
683
720
  </div>
684
721
  ) }
685
- { isEmbedVideoBackground && ! embedSrc && isFetchingEmbed && (
722
+ { isEmbedVideoBackground && ! embedHtml && isFetchingEmbed && (
686
723
  <Spinner />
687
724
  ) }
688
725
 
@@ -74,18 +74,20 @@ function findVideoEmbedProvider( url ) {
74
74
  }
75
75
 
76
76
  /**
77
- * Extracts iframe src from embed HTML.
77
+ * Modifies embed HTML to use background video parameters.
78
78
  *
79
- * @param {string} html The embed HTML.
80
- * @return {string|null} The iframe src URL or null if not found.
79
+ * @param {string} html The original embed HTML.
80
+ * @return {string|null} The modified embed HTML, or null if not possible.
81
81
  */
82
- export function getIframeSrc( html ) {
83
- if ( ! html ) {
82
+ export function getBackgroundEmbedHtml( html ) {
83
+ const srcMatch = html?.match( /src=["']([^"']+)["']/ );
84
+ if ( ! srcMatch ) {
84
85
  return null;
85
86
  }
86
87
 
87
- const srcMatch = html.match( /src=["']([^"']+)["']/ );
88
- return srcMatch ? srcMatch[ 1 ] : null;
88
+ const iframeSrc = srcMatch[ 1 ];
89
+ const backgroundSrc = getBackgroundVideoSrc( iframeSrc );
90
+ return html.replace( iframeSrc, backgroundSrc );
89
91
  }
90
92
 
91
93
  /**
@@ -39,13 +39,13 @@ function render_block_core_cover( $attributes, $content ) {
39
39
  $lower_src = strtolower( $iframe_src );
40
40
  $provider = null;
41
41
 
42
- if ( str_contains( $lower_src, 'youtube.com' ) || str_contains( $lower_src, 'youtu.be' ) ) {
42
+ if ( strpos( $lower_src, 'youtube.com' ) !== false || strpos( $lower_src, 'youtu.be' ) !== false ) {
43
43
  $provider = 'youtube';
44
- } elseif ( str_contains( $lower_src, 'vimeo.com' ) ) {
44
+ } elseif ( strpos( $lower_src, 'vimeo.com' ) !== false ) {
45
45
  $provider = 'vimeo';
46
- } elseif ( str_contains( $lower_src, 'videopress.com' ) ) {
46
+ } elseif ( strpos( $lower_src, 'videopress.com' ) !== false ) {
47
47
  $provider = 'videopress';
48
- } elseif ( str_contains( $lower_src, 'wordpress.tv' ) ) {
48
+ } elseif ( strpos( $lower_src, 'wordpress.tv' ) !== false ) {
49
49
  $provider = 'wordpress-tv';
50
50
  }
51
51
 
@@ -66,6 +66,14 @@ function render_block_core_cover( $attributes, $content ) {
66
66
  $query_params['controls'] = '0';
67
67
  $query_params['modestbranding'] = '1';
68
68
  $query_params['playsinline'] = '1';
69
+
70
+ // For loop to work, we need the playlist parameter.
71
+ $path = $parsed_url['path'] ?? '';
72
+ $path_segments = explode( '/', $path );
73
+ $video_id = end( $path_segments );
74
+ if ( $video_id ) {
75
+ $query_params['playlist'] = $video_id;
76
+ }
69
77
  } elseif ( 'vimeo' === $provider ) {
70
78
  $query_params['autoplay'] = '1';
71
79
  $query_params['muted'] = '1';
@@ -0,0 +1,47 @@
1
+ <?php
2
+ /**
3
+ * Server-side rendering of the `core/details` block.
4
+ *
5
+ * @package WordPress
6
+ */
7
+
8
+ /**
9
+ * Sets fetchpriority="low" on all IMG tags within the collapsed Details block.
10
+ *
11
+ * Images in a collapsed Details block are hidden until the block is expanded, so they should
12
+ * not compete with any resources in the critical rendering path, such as the LCP element image.
13
+ *
14
+ * @since 7.0.0
15
+ *
16
+ * @param string $block_content The block content.
17
+ * @param array $block The full block, including name and attributes.
18
+ * @return string Modified HTML with fetchpriority="low" on all IMG tags when the showContent attribute is false.
19
+ */
20
+ function block_core_details_set_img_fetchpriority_low( $block_content, array $block ): string {
21
+ if ( ! is_string( $block_content ) ) {
22
+ return '';
23
+ }
24
+
25
+ // If the Details block is open by default, short-circuit to let core add fetchpriority=high if appropriate.
26
+ if ( $block['attrs']['showContent'] ?? false ) {
27
+ return $block_content;
28
+ }
29
+
30
+ $tags = new WP_HTML_Tag_Processor( $block_content );
31
+ while ( $tags->next_tag( 'IMG' ) ) {
32
+ $tags->set_attribute( 'fetchpriority', 'low' );
33
+ }
34
+ return $tags->get_updated_html();
35
+ }
36
+
37
+ add_filter( 'render_block_core/details', 'block_core_details_set_img_fetchpriority_low', 10, 2 );
38
+
39
+ /**
40
+ * Registers the `core/details` block on server.
41
+ *
42
+ * @since 7.0.0
43
+ */
44
+ function register_block_core_details() {
45
+ register_block_type_from_metadata( __DIR__ . '/details' );
46
+ }
47
+ add_action( 'init', 'register_block_core_details' );
@@ -1,8 +1,3 @@
1
- /**
2
- * Internal dependencies
3
- */
4
- import { getPhotoHtml } from './util';
5
-
6
1
  /**
7
2
  * External dependencies
8
3
  */
@@ -17,6 +12,11 @@ import { BlockIcon } from '@wordpress/block-editor';
17
12
  import { useState } from '@wordpress/element';
18
13
  import { getAuthority } from '@wordpress/url';
19
14
 
15
+ /**
16
+ * Internal dependencies
17
+ */
18
+ import { getPhotoHtml } from './util';
19
+
20
20
  /**
21
21
  * Internal dependencies
22
22
  */
@@ -75,6 +75,7 @@ export default function EmbedPreview( {
75
75
  ) : (
76
76
  <div className="wp-block-embed__wrapper">
77
77
  <SandBox
78
+ allowSameOrigin
78
79
  html={ html }
79
80
  scripts={ scripts }
80
81
  title={ iframeTitle }
@@ -21,7 +21,8 @@
21
21
  "interactivity": {
22
22
  "clientNavigation": true
23
23
  },
24
- "customCSS": false
24
+ "customCSS": false,
25
+ "visibility": false
25
26
  },
26
27
  "editorStyle": "wp-block-html-editor"
27
28
  }
@@ -14,7 +14,14 @@
14
14
 
15
15
  // Modal styles
16
16
  .block-library-html__modal {
17
- height: 100%;
17
+
18
+ // On medium and large screens, the modal component sets a max-height.
19
+ // We want the modal to be as tall as possible also when the content is short.
20
+ @include break-small() {
21
+ &:not(.is-full-screen) {
22
+ height: 9999rem;
23
+ }
24
+ }
18
25
 
19
26
  .components-modal__children-container {
20
27
  height: 100%;
@@ -22,12 +29,11 @@
22
29
  }
23
30
 
24
31
  .block-library-html__modal-tabs {
25
- overflow-y: auto;
32
+ flex: 1;
26
33
  }
27
34
 
28
35
  .block-library-html__modal-content {
29
36
  flex: 1;
30
- min-height: 0;
31
37
  }
32
38
 
33
39
  .block-library-html__modal-tab {
@@ -71,7 +77,11 @@
71
77
  display: flex;
72
78
  align-items: center;
73
79
  justify-content: center;
74
- padding: $grid-unit-20;
75
- flex: 1;
76
80
  min-height: 0;
81
+ overflow-y: auto;
82
+ flex: 1;
83
+
84
+ iframe {
85
+ height: 100%;
86
+ }
77
87
  }
package/src/html/modal.js CHANGED
@@ -10,11 +10,12 @@ import {
10
10
  Flex,
11
11
  Notice,
12
12
  privateApis as componentsPrivateApis,
13
+ __experimentalVStack as VStack,
13
14
  __experimentalHStack as HStack,
14
- __experimentalGrid as Grid,
15
15
  } from '@wordpress/components';
16
16
  import { PlainText, store as blockEditorStore } from '@wordpress/block-editor';
17
17
  import { fullscreen, square } from '@wordpress/icons';
18
+ import { useViewportMatch } from '@wordpress/compose';
18
19
 
19
20
  /**
20
21
  * Internal dependencies
@@ -36,10 +37,10 @@ export default function HTMLEditModal( {
36
37
  const [ editedHtml, setEditedHtml ] = useState( html );
37
38
  const [ editedCss, setEditedCss ] = useState( css );
38
39
  const [ editedJs, setEditedJs ] = useState( js );
39
- const [ isDirty, setIsDirty ] = useState( false );
40
- const [ showUnsavedWarning, setShowUnsavedWarning ] = useState( false );
41
40
  const [ isFullscreen, setIsFullscreen ] = useState( false );
42
41
 
42
+ const isMobileViewport = useViewportMatch( 'small', '<' );
43
+
43
44
  // Check if user has permission to save scripts and get editor styles
44
45
  const { canUserUseUnfilteredHTML } = useSelect( ( select ) => {
45
46
  const settings = select( blockEditorStore ).getSettings();
@@ -57,18 +58,6 @@ export default function HTMLEditModal( {
57
58
  return null;
58
59
  }
59
60
 
60
- const handleHtmlChange = ( value ) => {
61
- setEditedHtml( value );
62
- setIsDirty( true );
63
- };
64
- const handleCssChange = ( value ) => {
65
- setEditedCss( value );
66
- setIsDirty( true );
67
- };
68
- const handleJsChange = ( value ) => {
69
- setEditedJs( value );
70
- setIsDirty( true );
71
- };
72
61
  const handleUpdate = () => {
73
62
  // For users without unfiltered_html capability, strip CSS and JS content
74
63
  // to prevent kses from leaving broken content
@@ -79,25 +68,6 @@ export default function HTMLEditModal( {
79
68
  js: canUserUseUnfilteredHTML ? editedJs : '',
80
69
  } ),
81
70
  } );
82
- setIsDirty( false );
83
- };
84
- const handleCancel = () => {
85
- setIsDirty( false );
86
- onRequestClose();
87
- };
88
- const handleRequestClose = () => {
89
- if ( isDirty ) {
90
- setShowUnsavedWarning( true );
91
- } else {
92
- onRequestClose();
93
- }
94
- };
95
- const handleDiscardChanges = () => {
96
- setShowUnsavedWarning( false );
97
- onRequestClose();
98
- };
99
- const handleContinueEditing = () => {
100
- setShowUnsavedWarning( false );
101
71
  };
102
72
  const handleUpdateAndClose = () => {
103
73
  handleUpdate();
@@ -111,22 +81,16 @@ export default function HTMLEditModal( {
111
81
  <>
112
82
  <Modal
113
83
  title={ __( 'Edit HTML' ) }
114
- onRequestClose={ handleRequestClose }
84
+ onRequestClose={ onRequestClose }
115
85
  className="block-library-html__modal"
116
86
  size="large"
117
87
  isDismissible={ false }
118
- shouldCloseOnClickOutside={ ! isDirty }
119
- shouldCloseOnEsc={ ! isDirty }
88
+ shouldCloseOnClickOutside={ false }
120
89
  isFullScreen={ isFullscreen }
121
90
  __experimentalHideHeader
122
91
  >
123
92
  <Tabs orientation="horizontal" defaultTabId="html">
124
- <Grid
125
- columns={ 1 }
126
- templateRows="auto 1fr auto"
127
- gap={ 4 }
128
- style={ { height: '100%' } }
129
- >
93
+ <VStack expanded>
130
94
  <HStack
131
95
  justify="space-between"
132
96
  className="block-library-html__modal-header"
@@ -144,15 +108,21 @@ export default function HTMLEditModal( {
144
108
  ) }
145
109
  </Tabs.TabList>
146
110
  </div>
147
- <div>
148
- <Button
149
- __next40pxDefaultSize
150
- icon={ isFullscreen ? square : fullscreen }
151
- label={ __( 'Enable/disable fullscreen' ) }
152
- onClick={ toggleFullscreen }
153
- variant="tertiary"
154
- />
155
- </div>
111
+ { ! isMobileViewport && (
112
+ <div>
113
+ <Button
114
+ __next40pxDefaultSize
115
+ icon={
116
+ isFullscreen ? square : fullscreen
117
+ }
118
+ label={ __(
119
+ 'Enable/disable fullscreen'
120
+ ) }
121
+ onClick={ toggleFullscreen }
122
+ variant="tertiary"
123
+ />
124
+ </div>
125
+ ) }
156
126
  </HStack>
157
127
  { hasRestrictedContent && (
158
128
  <Notice
@@ -165,11 +135,11 @@ export default function HTMLEditModal( {
165
135
  ) }
166
136
  </Notice>
167
137
  ) }
168
- <HStack
169
- alignment="stretch"
170
- justify="flex-start"
171
- spacing={ 4 }
138
+ <Flex
139
+ direction={ isMobileViewport ? 'column' : 'row' }
172
140
  className="block-library-html__modal-tabs"
141
+ align="stretch"
142
+ gap={ 8 }
173
143
  >
174
144
  <div className="block-library-html__modal-content">
175
145
  <Tabs.TabPanel
@@ -179,7 +149,7 @@ export default function HTMLEditModal( {
179
149
  >
180
150
  <PlainText
181
151
  value={ editedHtml }
182
- onChange={ handleHtmlChange }
152
+ onChange={ setEditedHtml }
183
153
  placeholder={ __( 'Write HTML…' ) }
184
154
  aria-label={ __( 'HTML' ) }
185
155
  className="block-library-html__modal-editor"
@@ -193,7 +163,7 @@ export default function HTMLEditModal( {
193
163
  >
194
164
  <PlainText
195
165
  value={ editedCss }
196
- onChange={ handleCssChange }
166
+ onChange={ setEditedCss }
197
167
  placeholder={ __( 'Write CSS…' ) }
198
168
  aria-label={ __( 'CSS' ) }
199
169
  className="block-library-html__modal-editor"
@@ -208,7 +178,7 @@ export default function HTMLEditModal( {
208
178
  >
209
179
  <PlainText
210
180
  value={ editedJs }
211
- onChange={ handleJsChange }
181
+ onChange={ setEditedJs }
212
182
  placeholder={ __(
213
183
  'Write JavaScript…'
214
184
  ) }
@@ -227,7 +197,7 @@ export default function HTMLEditModal( {
227
197
  } ) }
228
198
  />
229
199
  </div>
230
- </HStack>
200
+ </Flex>
231
201
  <HStack
232
202
  alignment="center"
233
203
  justify="flex-end"
@@ -237,7 +207,7 @@ export default function HTMLEditModal( {
237
207
  <Button
238
208
  __next40pxDefaultSize
239
209
  variant="tertiary"
240
- onClick={ handleCancel }
210
+ onClick={ onRequestClose }
241
211
  >
242
212
  { __( 'Cancel' ) }
243
213
  </Button>
@@ -249,46 +219,9 @@ export default function HTMLEditModal( {
249
219
  { __( 'Update' ) }
250
220
  </Button>
251
221
  </HStack>
252
- </Grid>
222
+ </VStack>
253
223
  </Tabs>
254
224
  </Modal>
255
-
256
- { showUnsavedWarning && (
257
- <Modal
258
- title={ __( 'Unsaved changes' ) }
259
- onRequestClose={ handleContinueEditing }
260
- size="medium"
261
- >
262
- <p>
263
- { __(
264
- 'You have unsaved changes. What would you like to do?'
265
- ) }
266
- </p>
267
- <Flex direction="row" justify="flex-end" gap={ 2 }>
268
- <Button
269
- __next40pxDefaultSize
270
- variant="secondary"
271
- onClick={ handleDiscardChanges }
272
- >
273
- { __( 'Discard unsaved changes' ) }
274
- </Button>
275
- <Button
276
- __next40pxDefaultSize
277
- variant="secondary"
278
- onClick={ handleContinueEditing }
279
- >
280
- { __( 'Continue editing' ) }
281
- </Button>
282
- <Button
283
- __next40pxDefaultSize
284
- variant="primary"
285
- onClick={ handleUpdateAndClose }
286
- >
287
- { __( 'Update and close' ) }
288
- </Button>
289
- </Flex>
290
- </Modal>
291
- ) }
292
225
  </>
293
226
  );
294
227
  }
@@ -59,19 +59,10 @@
59
59
  }
60
60
  },
61
61
  "selectors": {
62
- "root": ".wp-block-icon",
63
- "color": {
64
- "root": ".wp-block-icon svg"
65
- },
66
- "border": {
67
- "root": ".wp-block-icon svg"
68
- },
62
+ "root": ".wp-block-icon svg",
63
+ "css": ".wp-block-icon",
69
64
  "spacing": {
70
- "padding": ".wp-block-icon svg"
71
- },
72
- "dimensions": {
73
- "root": ".wp-block-icon svg",
74
- "width": ".wp-block-icon svg"
65
+ "margin": ".wp-block-icon"
75
66
  }
76
67
  },
77
68
  "style": "wp-block-icon",
@@ -1,6 +1,11 @@
1
1
  @use "@wordpress/base-styles/variables" as *;
2
2
  @use "@wordpress/base-styles/colors" as *;
3
3
 
4
+ .wp-block[data-align="center"] > .wp-block-icon {
5
+ display: flex;
6
+ justify-content: center;
7
+ }
8
+
4
9
  // Style for the icon library modal.
5
10
  .wp-block-icon__inserter {
6
11
  padding: 0 $grid-unit-30;