@wordpress/block-library 10.1.1-next.v.202607070741.0 → 10.3.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 (580) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/build/accordion/block.json +1 -0
  3. package/build/accordion-panel/block.json +1 -0
  4. package/build/button/edit.cjs +18 -8
  5. package/build/button/edit.cjs.map +2 -2
  6. package/build/code/edit.cjs +3 -1
  7. package/build/code/edit.cjs.map +2 -2
  8. package/build/cover/block.json +12 -0
  9. package/build/cover/edit/block-controls.cjs +14 -5
  10. package/build/cover/edit/block-controls.cjs.map +2 -2
  11. package/build/cover/edit/embed-video-url-input.cjs +5 -3
  12. package/build/cover/edit/embed-video-url-input.cjs.map +3 -3
  13. package/build/cover/edit/index.cjs +76 -32
  14. package/build/cover/edit/index.cjs.map +2 -2
  15. package/build/cover/embed-video-utils.cjs +17 -7
  16. package/build/cover/embed-video-utils.cjs.map +2 -2
  17. package/build/details/transforms.cjs +1 -3
  18. package/build/details/transforms.cjs.map +2 -2
  19. package/build/embed/edit.cjs +1 -1
  20. package/build/embed/edit.cjs.map +2 -2
  21. package/build/embed/embed-placeholder.cjs +1 -2
  22. package/build/embed/embed-placeholder.cjs.map +2 -2
  23. package/build/file/edit.cjs +4 -3
  24. package/build/file/edit.cjs.map +2 -2
  25. package/build/file/transforms.cjs +25 -60
  26. package/build/file/transforms.cjs.map +2 -2
  27. package/build/gallery/block.json +4 -2
  28. package/build/gallery/dynamic-gallery.cjs +104 -61
  29. package/build/gallery/dynamic-gallery.cjs.map +3 -3
  30. package/build/gallery/edit.cjs +1 -1
  31. package/build/gallery/edit.cjs.map +3 -3
  32. package/build/gallery/gap-styles.cjs +49 -13
  33. package/build/gallery/gap-styles.cjs.map +3 -3
  34. package/build/gallery/use-dynamic-gallery.cjs +15 -8
  35. package/build/gallery/use-dynamic-gallery.cjs.map +2 -2
  36. package/build/group/transforms.cjs +1 -1
  37. package/build/group/transforms.cjs.map +2 -2
  38. package/build/heading/edit.cjs +1 -1
  39. package/build/heading/edit.cjs.map +2 -2
  40. package/build/html/modal.cjs +63 -54
  41. package/build/html/modal.cjs.map +3 -3
  42. package/build/icon/block.json +5 -3
  43. package/build/icon/components/custom-inserter/icon-grid.cjs +25 -12
  44. package/build/icon/components/custom-inserter/icon-grid.cjs.map +2 -2
  45. package/build/icon/components/custom-inserter/index.cjs +100 -31
  46. package/build/icon/components/custom-inserter/index.cjs.map +3 -3
  47. package/build/icon/edit.cjs +11 -12
  48. package/build/icon/edit.cjs.map +2 -2
  49. package/build/image/block.json +1 -1
  50. package/build/image/edit.cjs +1 -35
  51. package/build/image/edit.cjs.map +2 -2
  52. package/build/image/image.cjs +23 -18
  53. package/build/image/image.cjs.map +3 -3
  54. package/build/image/transforms.cjs +78 -0
  55. package/build/image/transforms.cjs.map +3 -3
  56. package/build/image/use-open-image-media-editor-modal.cjs +6 -2
  57. package/build/image/use-open-image-media-editor-modal.cjs.map +2 -2
  58. package/build/index.cjs +18 -8
  59. package/build/index.cjs.map +2 -2
  60. package/build/latest-posts/edit.cjs +5 -8
  61. package/build/latest-posts/edit.cjs.map +2 -2
  62. package/build/list-item/edit.cjs +1 -1
  63. package/build/list-item/edit.cjs.map +2 -2
  64. package/build/list-item/hooks/use-enter.cjs +14 -17
  65. package/build/list-item/hooks/use-enter.cjs.map +3 -3
  66. package/build/list-item/hooks/use-indent-list-item.cjs +10 -2
  67. package/build/list-item/hooks/use-indent-list-item.cjs.map +2 -2
  68. package/build/list-item/hooks/use-space.cjs +3 -2
  69. package/build/list-item/hooks/use-space.cjs.map +3 -3
  70. package/build/math/edit.cjs +39 -56
  71. package/build/math/edit.cjs.map +3 -3
  72. package/build/media-text/edit.cjs +2 -1
  73. package/build/media-text/edit.cjs.map +2 -2
  74. package/build/more/edit.cjs +2 -2
  75. package/build/more/edit.cjs.map +2 -2
  76. package/build/navigation/edit/index.cjs +30 -16
  77. package/build/navigation/edit/index.cjs.map +3 -3
  78. package/build/navigation/edit/use-layout-custom-properties.cjs +72 -0
  79. package/build/navigation/edit/use-layout-custom-properties.cjs.map +7 -0
  80. package/build/navigation/view.cjs +9 -6
  81. package/build/navigation/view.cjs.map +2 -2
  82. package/build/navigation-link/edit.cjs +3 -3
  83. package/build/navigation-link/edit.cjs.map +2 -2
  84. package/build/navigation-link/link-ui/index.cjs +2 -2
  85. package/build/navigation-link/link-ui/index.cjs.map +2 -2
  86. package/build/paragraph/edit.cjs +5 -2
  87. package/build/paragraph/edit.cjs.map +3 -3
  88. package/build/paragraph/index.cjs +4 -1
  89. package/build/paragraph/index.cjs.map +2 -2
  90. package/build/paragraph/use-enter.cjs +3 -7
  91. package/build/paragraph/use-enter.cjs.map +3 -3
  92. package/build/playlist/block.json +29 -10
  93. package/build/playlist/context.cjs +2 -1
  94. package/build/playlist/context.cjs.map +2 -2
  95. package/build/playlist/edit.cjs +328 -39
  96. package/build/playlist/edit.cjs.map +3 -3
  97. package/build/playlist/index.cjs +1 -1
  98. package/build/playlist/index.cjs.map +2 -2
  99. package/build/playlist/utils.cjs +37 -8
  100. package/build/playlist/utils.cjs.map +2 -2
  101. package/build/playlist/view.cjs +83 -13
  102. package/build/playlist/view.cjs.map +2 -2
  103. package/build/playlist-track/block.json +4 -2
  104. package/build/playlist-track/edit.cjs +115 -70
  105. package/build/playlist-track/edit.cjs.map +2 -2
  106. package/build/post-content/block.json +1 -0
  107. package/build/post-content/edit.cjs +36 -15
  108. package/build/post-content/edit.cjs.map +2 -2
  109. package/build/post-featured-image/edit.cjs +3 -2
  110. package/build/post-featured-image/edit.cjs.map +2 -2
  111. package/build/post-template/block.json +2 -1
  112. package/build/post-template/edit.cjs +10 -1
  113. package/build/post-template/edit.cjs.map +2 -2
  114. package/build/post-terms/edit.cjs +2 -2
  115. package/build/post-terms/edit.cjs.map +2 -2
  116. package/build/post-title/edit.cjs +2 -2
  117. package/build/post-title/edit.cjs.map +2 -2
  118. package/build/preformatted/edit.cjs +3 -1
  119. package/build/preformatted/edit.cjs.map +2 -2
  120. package/build/pullquote/block.json +3 -1
  121. package/build/pullquote/edit.cjs +5 -3
  122. package/build/pullquote/edit.cjs.map +2 -2
  123. package/build/query/block.json +3 -2
  124. package/build/query/edit/inspector-controls/index.cjs +42 -5
  125. package/build/query/edit/inspector-controls/index.cjs.map +2 -2
  126. package/build/query/edit/inspector-controls/offset-controls.cjs +1 -2
  127. package/build/query/edit/inspector-controls/offset-controls.cjs.map +2 -2
  128. package/build/query/edit/inspector-controls/pages-control.cjs +0 -1
  129. package/build/query/edit/inspector-controls/pages-control.cjs.map +2 -2
  130. package/build/query/edit/query-content.cjs +10 -3
  131. package/build/query/edit/query-content.cjs.map +2 -2
  132. package/build/query/index.cjs +2 -1
  133. package/build/query/index.cjs.map +2 -2
  134. package/build/quote/block.json +3 -1
  135. package/build/quote/transforms.cjs +1 -3
  136. package/build/quote/transforms.cjs.map +2 -2
  137. package/build/read-more/edit.cjs +3 -1
  138. package/build/read-more/edit.cjs.map +2 -2
  139. package/build/rss/edit.cjs +0 -1
  140. package/build/rss/edit.cjs.map +2 -2
  141. package/build/site-tagline/edit.cjs +3 -1
  142. package/build/site-tagline/edit.cjs.map +2 -2
  143. package/build/site-title/edit.cjs +3 -1
  144. package/build/site-title/edit.cjs.map +2 -2
  145. package/build/social-links/edit.cjs +11 -4
  146. package/build/social-links/edit.cjs.map +2 -2
  147. package/build/tab-list/block.json +4 -3
  148. package/build/tab-list/edit.cjs +67 -11
  149. package/build/tab-list/edit.cjs.map +3 -3
  150. package/build/tab-list/tab-movers.cjs +87 -0
  151. package/build/tab-list/tab-movers.cjs.map +7 -0
  152. package/build/tab-panel/block.json +1 -6
  153. package/build/tab-panel/edit.cjs +16 -24
  154. package/build/tab-panel/edit.cjs.map +2 -2
  155. package/build/tab-panels/block.json +0 -1
  156. package/build/table/edit.cjs +1 -1
  157. package/build/table/edit.cjs.map +2 -2
  158. package/build/tabs/block.json +0 -5
  159. package/build/tabs/edit.cjs +4 -39
  160. package/build/tabs/edit.cjs.map +3 -3
  161. package/build/tabs/use-tab-actions.cjs +23 -1
  162. package/build/tabs/use-tab-actions.cjs.map +2 -2
  163. package/build/tabs/use-tab-list-items-sync.cjs +19 -1
  164. package/build/tabs/use-tab-list-items-sync.cjs.map +2 -2
  165. package/build/term-name/block.json +1 -3
  166. package/build/term-name/deprecated.cjs +105 -0
  167. package/build/term-name/deprecated.cjs.map +7 -0
  168. package/build/term-name/edit.cjs +11 -37
  169. package/build/term-name/edit.cjs.map +3 -3
  170. package/build/term-name/index.cjs +3 -1
  171. package/build/term-name/index.cjs.map +3 -3
  172. package/build/utils/caption.cjs +2 -2
  173. package/build/utils/caption.cjs.map +2 -2
  174. package/build/utils/waveform-player.cjs +138 -22
  175. package/build/utils/waveform-player.cjs.map +2 -2
  176. package/build/utils/waveform-utils.cjs +315 -17
  177. package/build/utils/waveform-utils.cjs.map +2 -2
  178. package/build/verse/edit.cjs +3 -1
  179. package/build/verse/edit.cjs.map +2 -2
  180. package/build/video/edit.cjs +2 -11
  181. package/build/video/edit.cjs.map +3 -3
  182. package/build/video/tracks-editor.cjs +0 -1
  183. package/build/video/tracks-editor.cjs.map +2 -2
  184. package/build-module/accordion/block.json +1 -0
  185. package/build-module/accordion-panel/block.json +1 -0
  186. package/build-module/button/edit.mjs +19 -14
  187. package/build-module/button/edit.mjs.map +2 -2
  188. package/build-module/code/edit.mjs +3 -1
  189. package/build-module/code/edit.mjs.map +2 -2
  190. package/build-module/cover/block.json +12 -0
  191. package/build-module/cover/edit/block-controls.mjs +14 -5
  192. package/build-module/cover/edit/block-controls.mjs.map +2 -2
  193. package/build-module/cover/edit/embed-video-url-input.mjs +5 -4
  194. package/build-module/cover/edit/embed-video-url-input.mjs.map +2 -2
  195. package/build-module/cover/edit/index.mjs +79 -35
  196. package/build-module/cover/edit/index.mjs.map +2 -2
  197. package/build-module/cover/embed-video-utils.mjs +16 -7
  198. package/build-module/cover/embed-video-utils.mjs.map +2 -2
  199. package/build-module/details/transforms.mjs +2 -7
  200. package/build-module/details/transforms.mjs.map +2 -2
  201. package/build-module/embed/edit.mjs +1 -1
  202. package/build-module/embed/edit.mjs.map +2 -2
  203. package/build-module/embed/embed-placeholder.mjs +1 -2
  204. package/build-module/embed/embed-placeholder.mjs.map +2 -2
  205. package/build-module/file/edit.mjs +4 -3
  206. package/build-module/file/edit.mjs.map +2 -2
  207. package/build-module/file/transforms.mjs +25 -60
  208. package/build-module/file/transforms.mjs.map +2 -2
  209. package/build-module/gallery/block.json +4 -2
  210. package/build-module/gallery/dynamic-gallery.mjs +104 -61
  211. package/build-module/gallery/dynamic-gallery.mjs.map +2 -2
  212. package/build-module/gallery/edit.mjs +3 -3
  213. package/build-module/gallery/edit.mjs.map +2 -2
  214. package/build-module/gallery/gap-styles.mjs +53 -14
  215. package/build-module/gallery/gap-styles.mjs.map +2 -2
  216. package/build-module/gallery/use-dynamic-gallery.mjs +16 -9
  217. package/build-module/gallery/use-dynamic-gallery.mjs.map +2 -2
  218. package/build-module/group/transforms.mjs +2 -5
  219. package/build-module/group/transforms.mjs.map +2 -2
  220. package/build-module/heading/edit.mjs +1 -1
  221. package/build-module/heading/edit.mjs.map +2 -2
  222. package/build-module/html/modal.mjs +68 -55
  223. package/build-module/html/modal.mjs.map +2 -2
  224. package/build-module/icon/block.json +5 -3
  225. package/build-module/icon/components/custom-inserter/icon-grid.mjs +25 -12
  226. package/build-module/icon/components/custom-inserter/icon-grid.mjs.map +2 -2
  227. package/build-module/icon/components/custom-inserter/index.mjs +102 -33
  228. package/build-module/icon/components/custom-inserter/index.mjs.map +2 -2
  229. package/build-module/icon/edit.mjs +11 -12
  230. package/build-module/icon/edit.mjs.map +2 -2
  231. package/build-module/image/block.json +1 -1
  232. package/build-module/image/edit.mjs +1 -35
  233. package/build-module/image/edit.mjs.map +2 -2
  234. package/build-module/image/image.mjs +23 -18
  235. package/build-module/image/image.mjs.map +2 -2
  236. package/build-module/image/transforms.mjs +78 -0
  237. package/build-module/image/transforms.mjs.map +2 -2
  238. package/build-module/image/use-open-image-media-editor-modal.mjs +6 -2
  239. package/build-module/image/use-open-image-media-editor-modal.mjs.map +2 -2
  240. package/build-module/index.mjs +18 -8
  241. package/build-module/index.mjs.map +2 -2
  242. package/build-module/latest-posts/edit.mjs +5 -8
  243. package/build-module/latest-posts/edit.mjs.map +2 -2
  244. package/build-module/list-item/edit.mjs +1 -1
  245. package/build-module/list-item/edit.mjs.map +2 -2
  246. package/build-module/list-item/hooks/use-enter.mjs +15 -21
  247. package/build-module/list-item/hooks/use-enter.mjs.map +2 -2
  248. package/build-module/list-item/hooks/use-indent-list-item.mjs +10 -2
  249. package/build-module/list-item/hooks/use-indent-list-item.mjs.map +2 -2
  250. package/build-module/list-item/hooks/use-space.mjs +4 -6
  251. package/build-module/list-item/hooks/use-space.mjs.map +2 -2
  252. package/build-module/math/edit.mjs +41 -60
  253. package/build-module/math/edit.mjs.map +2 -2
  254. package/build-module/media-text/edit.mjs +2 -1
  255. package/build-module/media-text/edit.mjs.map +2 -2
  256. package/build-module/more/edit.mjs +2 -2
  257. package/build-module/more/edit.mjs.map +2 -2
  258. package/build-module/navigation/edit/index.mjs +30 -16
  259. package/build-module/navigation/edit/index.mjs.map +2 -2
  260. package/build-module/navigation/edit/use-layout-custom-properties.mjs +51 -0
  261. package/build-module/navigation/edit/use-layout-custom-properties.mjs.map +7 -0
  262. package/build-module/navigation/view.mjs +9 -6
  263. package/build-module/navigation/view.mjs.map +2 -2
  264. package/build-module/navigation-link/edit.mjs +3 -3
  265. package/build-module/navigation-link/edit.mjs.map +2 -2
  266. package/build-module/navigation-link/link-ui/index.mjs +2 -2
  267. package/build-module/navigation-link/link-ui/index.mjs.map +2 -2
  268. package/build-module/paragraph/edit.mjs +6 -2
  269. package/build-module/paragraph/edit.mjs.map +2 -2
  270. package/build-module/paragraph/index.mjs +4 -1
  271. package/build-module/paragraph/index.mjs.map +2 -2
  272. package/build-module/paragraph/use-enter.mjs +4 -11
  273. package/build-module/paragraph/use-enter.mjs.map +2 -2
  274. package/build-module/playlist/block.json +29 -10
  275. package/build-module/playlist/context.mjs +2 -1
  276. package/build-module/playlist/context.mjs.map +2 -2
  277. package/build-module/playlist/edit.mjs +331 -41
  278. package/build-module/playlist/edit.mjs.map +2 -2
  279. package/build-module/playlist/index.mjs +1 -1
  280. package/build-module/playlist/index.mjs.map +2 -2
  281. package/build-module/playlist/utils.mjs +35 -7
  282. package/build-module/playlist/utils.mjs.map +2 -2
  283. package/build-module/playlist/view.mjs +89 -14
  284. package/build-module/playlist/view.mjs.map +2 -2
  285. package/build-module/playlist-track/block.json +4 -2
  286. package/build-module/playlist-track/edit.mjs +117 -71
  287. package/build-module/playlist-track/edit.mjs.map +2 -2
  288. package/build-module/post-content/block.json +1 -0
  289. package/build-module/post-content/edit.mjs +37 -15
  290. package/build-module/post-content/edit.mjs.map +2 -2
  291. package/build-module/post-featured-image/edit.mjs +3 -2
  292. package/build-module/post-featured-image/edit.mjs.map +2 -2
  293. package/build-module/post-template/block.json +2 -1
  294. package/build-module/post-template/edit.mjs +10 -1
  295. package/build-module/post-template/edit.mjs.map +2 -2
  296. package/build-module/post-terms/edit.mjs +2 -2
  297. package/build-module/post-terms/edit.mjs.map +2 -2
  298. package/build-module/post-title/edit.mjs +2 -2
  299. package/build-module/post-title/edit.mjs.map +2 -2
  300. package/build-module/preformatted/edit.mjs +3 -1
  301. package/build-module/preformatted/edit.mjs.map +2 -2
  302. package/build-module/pullquote/block.json +3 -1
  303. package/build-module/pullquote/edit.mjs +5 -3
  304. package/build-module/pullquote/edit.mjs.map +2 -2
  305. package/build-module/query/block.json +3 -2
  306. package/build-module/query/edit/inspector-controls/index.mjs +44 -6
  307. package/build-module/query/edit/inspector-controls/index.mjs.map +2 -2
  308. package/build-module/query/edit/inspector-controls/offset-controls.mjs +2 -3
  309. package/build-module/query/edit/inspector-controls/offset-controls.mjs.map +2 -2
  310. package/build-module/query/edit/inspector-controls/pages-control.mjs +0 -1
  311. package/build-module/query/edit/inspector-controls/pages-control.mjs.map +2 -2
  312. package/build-module/query/edit/query-content.mjs +10 -3
  313. package/build-module/query/edit/query-content.mjs.map +2 -2
  314. package/build-module/query/index.mjs +2 -1
  315. package/build-module/query/index.mjs.map +2 -2
  316. package/build-module/quote/block.json +3 -1
  317. package/build-module/quote/transforms.mjs +2 -4
  318. package/build-module/quote/transforms.mjs.map +2 -2
  319. package/build-module/read-more/edit.mjs +3 -1
  320. package/build-module/read-more/edit.mjs.map +2 -2
  321. package/build-module/rss/edit.mjs +0 -1
  322. package/build-module/rss/edit.mjs.map +2 -2
  323. package/build-module/site-tagline/edit.mjs +3 -1
  324. package/build-module/site-tagline/edit.mjs.map +2 -2
  325. package/build-module/site-title/edit.mjs +3 -1
  326. package/build-module/site-title/edit.mjs.map +2 -2
  327. package/build-module/social-links/edit.mjs +11 -4
  328. package/build-module/social-links/edit.mjs.map +2 -2
  329. package/build-module/tab-list/block.json +4 -3
  330. package/build-module/tab-list/edit.mjs +74 -13
  331. package/build-module/tab-list/edit.mjs.map +2 -2
  332. package/build-module/tab-list/tab-movers.mjs +59 -0
  333. package/build-module/tab-list/tab-movers.mjs.map +7 -0
  334. package/build-module/tab-panel/block.json +1 -6
  335. package/build-module/tab-panel/edit.mjs +17 -25
  336. package/build-module/tab-panel/edit.mjs.map +2 -2
  337. package/build-module/tab-panels/block.json +0 -1
  338. package/build-module/table/edit.mjs +1 -1
  339. package/build-module/table/edit.mjs.map +2 -2
  340. package/build-module/tabs/block.json +0 -5
  341. package/build-module/tabs/edit.mjs +5 -45
  342. package/build-module/tabs/edit.mjs.map +2 -2
  343. package/build-module/tabs/use-tab-actions.mjs +23 -1
  344. package/build-module/tabs/use-tab-actions.mjs.map +2 -2
  345. package/build-module/tabs/use-tab-list-items-sync.mjs +19 -1
  346. package/build-module/tabs/use-tab-list-items-sync.mjs.map +2 -2
  347. package/build-module/term-name/block.json +1 -3
  348. package/build-module/term-name/deprecated.mjs +74 -0
  349. package/build-module/term-name/deprecated.mjs.map +7 -0
  350. package/build-module/term-name/edit.mjs +11 -28
  351. package/build-module/term-name/edit.mjs.map +2 -2
  352. package/build-module/term-name/index.mjs +3 -1
  353. package/build-module/term-name/index.mjs.map +2 -2
  354. package/build-module/utils/caption.mjs +2 -2
  355. package/build-module/utils/caption.mjs.map +2 -2
  356. package/build-module/utils/waveform-player.mjs +144 -23
  357. package/build-module/utils/waveform-player.mjs.map +2 -2
  358. package/build-module/utils/waveform-utils.mjs +310 -16
  359. package/build-module/utils/waveform-utils.mjs.map +2 -2
  360. package/build-module/verse/edit.mjs +3 -1
  361. package/build-module/verse/edit.mjs.map +2 -2
  362. package/build-module/video/edit.mjs +2 -11
  363. package/build-module/video/edit.mjs.map +2 -2
  364. package/build-module/video/tracks-editor.mjs +0 -1
  365. package/build-module/video/tracks-editor.mjs.map +2 -2
  366. package/build-style/cover/editor-rtl.css +3 -0
  367. package/build-style/cover/editor.css +3 -0
  368. package/build-style/editor-rtl.css +61 -59
  369. package/build-style/editor.css +61 -59
  370. package/build-style/icon/editor-rtl.css +80 -10
  371. package/build-style/icon/editor.css +80 -10
  372. package/build-style/image/editor-rtl.css +3 -32
  373. package/build-style/image/editor.css +3 -32
  374. package/build-style/more/editor-rtl.css +2 -2
  375. package/build-style/more/editor.css +2 -2
  376. package/build-style/navigation/editor-rtl.css +3 -4
  377. package/build-style/navigation/editor.css +3 -4
  378. package/build-style/navigation-link/editor-rtl.css +1 -1
  379. package/build-style/navigation-link/editor.css +1 -1
  380. package/build-style/nextpage/editor-rtl.css +2 -2
  381. package/build-style/nextpage/editor.css +2 -2
  382. package/build-style/playlist/editor-rtl.css +4 -3
  383. package/build-style/playlist/editor.css +4 -3
  384. package/build-style/playlist/style-rtl.css +81 -5
  385. package/build-style/playlist/style.css +81 -5
  386. package/build-style/playlist-track/style-rtl.css +10 -0
  387. package/build-style/playlist-track/style.css +10 -0
  388. package/build-style/pullquote/editor-rtl.css +4 -0
  389. package/build-style/pullquote/editor.css +4 -0
  390. package/build-style/style-rtl.css +91 -5
  391. package/build-style/style.css +91 -5
  392. package/build-style/tab-list/editor-rtl.css +101 -0
  393. package/build-style/tab-list/editor.css +101 -0
  394. package/build-style/video/editor-rtl.css +1 -1
  395. package/build-style/video/editor.css +1 -1
  396. package/build-types/table-of-contents/list.d.ts +1 -1
  397. package/build-types/table-of-contents/list.d.ts.map +1 -1
  398. package/package.json +47 -45
  399. package/src/accordion/README.md +1 -0
  400. package/src/accordion/block.json +1 -0
  401. package/src/accordion-panel/block.json +1 -0
  402. package/src/breadcrumbs/index.php +3 -1
  403. package/src/button/edit.js +21 -15
  404. package/src/button/index.php +1 -1
  405. package/src/code/edit.js +7 -2
  406. package/src/cover/README.md +60 -0
  407. package/src/cover/block.json +12 -0
  408. package/src/cover/edit/block-controls.js +26 -11
  409. package/src/cover/edit/embed-video-url-input.js +5 -4
  410. package/src/cover/edit/index.js +109 -46
  411. package/src/cover/editor.scss +6 -0
  412. package/src/cover/embed-video-utils.js +38 -13
  413. package/src/cover/index.php +9 -2
  414. package/src/details/transforms.js +2 -7
  415. package/src/editor.scss +1 -0
  416. package/src/embed/edit.js +3 -1
  417. package/src/embed/embed-placeholder.js +9 -8
  418. package/src/file/edit.js +8 -8
  419. package/src/file/transforms.js +28 -60
  420. package/src/form/index.php +6 -4
  421. package/src/gallery/README.md +1 -1
  422. package/src/gallery/block.json +4 -2
  423. package/src/gallery/dynamic-gallery.js +133 -74
  424. package/src/gallery/edit.js +3 -3
  425. package/src/gallery/gap-styles.js +79 -20
  426. package/src/gallery/index.php +103 -43
  427. package/src/gallery/use-dynamic-gallery.js +27 -12
  428. package/src/group/transforms.js +2 -5
  429. package/src/heading/edit.js +1 -1
  430. package/src/html/modal.js +13 -2
  431. package/src/icon/README.md +1 -3
  432. package/src/icon/block.json +5 -3
  433. package/src/icon/components/custom-inserter/icon-grid.js +40 -11
  434. package/src/icon/components/custom-inserter/index.js +98 -25
  435. package/src/icon/edit.js +11 -17
  436. package/src/icon/editor.scss +33 -11
  437. package/src/image/README.md +1 -1
  438. package/src/image/block.json +1 -1
  439. package/src/image/edit.js +1 -57
  440. package/src/image/editor.scss +6 -44
  441. package/src/image/image.js +56 -27
  442. package/src/image/test/use-open-image-media-editor-modal.js +37 -1
  443. package/src/image/transforms.js +128 -0
  444. package/src/image/use-open-image-media-editor-modal.js +8 -1
  445. package/src/index.js +19 -7
  446. package/src/latest-posts/edit.js +5 -8
  447. package/src/latest-posts/index.php +49 -18
  448. package/src/list-item/edit.js +1 -1
  449. package/src/list-item/hooks/use-enter.js +15 -22
  450. package/src/list-item/hooks/use-indent-list-item.js +10 -1
  451. package/src/list-item/hooks/use-space.js +4 -6
  452. package/src/math/edit.js +42 -59
  453. package/src/media-text/edit.js +1 -0
  454. package/src/media-text/editor.scss +1 -0
  455. package/src/media-text/index.php +11 -2
  456. package/src/more/edit.js +7 -4
  457. package/src/more/editor.scss +1 -1
  458. package/src/navigation/edit/index.js +52 -36
  459. package/src/navigation/edit/test/layout-custom-properties.js +138 -0
  460. package/src/navigation/edit/use-layout-custom-properties.js +84 -0
  461. package/src/navigation/editor.scss +1 -2
  462. package/src/navigation/index.php +123 -12
  463. package/src/navigation/test/view.js +51 -0
  464. package/src/navigation/view.js +15 -14
  465. package/src/navigation-link/edit.js +11 -7
  466. package/src/navigation-link/editor.scss +1 -1
  467. package/src/navigation-link/index.php +70 -3
  468. package/src/navigation-link/link-ui/index.js +2 -1
  469. package/src/navigation-link/test/__snapshots__/hooks.js.snap +1 -1
  470. package/src/navigation-submenu/index.php +6 -3
  471. package/src/nextpage/editor.scss +1 -1
  472. package/src/page-list/index.php +4 -3
  473. package/src/paragraph/edit.js +9 -2
  474. package/src/paragraph/index.js +4 -1
  475. package/src/paragraph/use-enter.js +4 -11
  476. package/src/pattern/index.php +5 -5
  477. package/src/playlist/README.md +17 -18
  478. package/src/playlist/block.json +29 -10
  479. package/src/playlist/context.js +1 -0
  480. package/src/playlist/edit.js +395 -59
  481. package/src/playlist/editor.scss +4 -5
  482. package/src/playlist/index.js +1 -1
  483. package/src/playlist/index.php +71 -22
  484. package/src/playlist/style.scss +54 -1
  485. package/src/playlist/test/edit-component.js +139 -0
  486. package/src/playlist/test/edit.js +43 -2
  487. package/src/playlist/utils.js +49 -10
  488. package/src/playlist/view.js +97 -16
  489. package/src/playlist-track/README.md +3 -3
  490. package/src/playlist-track/block.json +4 -2
  491. package/src/playlist-track/edit.js +116 -75
  492. package/src/playlist-track/index.php +26 -11
  493. package/src/playlist-track/style.scss +10 -0
  494. package/src/playlist-track/test/edit.js +253 -0
  495. package/src/post-content/README.md +1 -0
  496. package/src/post-content/block.json +1 -0
  497. package/src/post-content/edit.js +45 -16
  498. package/src/post-excerpt/index.php +4 -1
  499. package/src/post-featured-image/edit.js +3 -2
  500. package/src/post-featured-image/index.php +4 -1
  501. package/src/post-template/README.md +1 -0
  502. package/src/post-template/block.json +2 -1
  503. package/src/post-template/edit.js +9 -0
  504. package/src/post-terms/edit.js +7 -4
  505. package/src/post-title/edit.js +5 -3
  506. package/src/preformatted/edit.js +7 -2
  507. package/src/pullquote/README.md +1 -0
  508. package/src/pullquote/block.json +3 -1
  509. package/src/pullquote/edit.js +9 -4
  510. package/src/pullquote/editor.scss +6 -0
  511. package/src/query/README.md +2 -1
  512. package/src/query/block.json +3 -2
  513. package/src/query/edit/inspector-controls/index.js +47 -4
  514. package/src/query/edit/inspector-controls/offset-controls.js +2 -3
  515. package/src/query/edit/inspector-controls/pages-control.js +0 -1
  516. package/src/query/edit/query-content.js +19 -3
  517. package/src/query/index.js +1 -0
  518. package/src/quote/README.md +1 -0
  519. package/src/quote/block.json +3 -1
  520. package/src/quote/transforms.js +2 -4
  521. package/src/read-more/edit.js +7 -2
  522. package/src/rss/edit.js +0 -1
  523. package/src/rss/index.php +10 -4
  524. package/src/site-tagline/edit.js +7 -2
  525. package/src/site-title/edit.js +7 -2
  526. package/src/social-link/index.php +19 -9
  527. package/src/social-links/edit.js +21 -12
  528. package/src/tab-list/README.md +4 -5
  529. package/src/tab-list/block.json +4 -3
  530. package/src/tab-list/edit.js +92 -28
  531. package/src/tab-list/editor.scss +9 -0
  532. package/src/tab-list/index.php +9 -4
  533. package/src/tab-list/tab-movers.js +72 -0
  534. package/src/tab-panel/README.md +4 -6
  535. package/src/tab-panel/block.json +1 -6
  536. package/src/tab-panel/edit.js +20 -33
  537. package/src/tab-panels/README.md +5 -3
  538. package/src/tab-panels/block.json +0 -1
  539. package/src/table/edit.js +1 -1
  540. package/src/table-of-contents/index.php +386 -1
  541. package/src/tabs/README.md +18 -9
  542. package/src/tabs/block.json +0 -5
  543. package/src/tabs/edit.js +7 -64
  544. package/src/tabs/use-tab-actions.js +32 -3
  545. package/src/tabs/use-tab-list-items-sync.js +24 -4
  546. package/src/tag-cloud/index.php +3 -2
  547. package/src/template-part/index.php +3 -17
  548. package/src/term-name/README.md +1 -1
  549. package/src/term-name/block.json +1 -3
  550. package/src/term-name/deprecated.js +74 -0
  551. package/src/term-name/edit.js +2 -18
  552. package/src/term-name/index.js +2 -0
  553. package/src/utils/caption.js +7 -4
  554. package/src/utils/media-control.scss +1 -5
  555. package/src/utils/test/waveform-player.js +297 -34
  556. package/src/utils/test/waveform-utils.js +473 -5
  557. package/src/utils/waveform-player.js +189 -59
  558. package/src/utils/waveform-utils.js +443 -40
  559. package/src/verse/edit.js +7 -2
  560. package/src/video/edit.js +0 -8
  561. package/src/video/editor.scss +1 -1
  562. package/src/video/index.php +2 -2
  563. package/src/video/tracks-editor.js +0 -1
  564. package/build/image/animated-gif-convert-control.cjs +0 -105
  565. package/build/image/animated-gif-convert-control.cjs.map +0 -7
  566. package/build/utils/gif-conversion-attributes.cjs +0 -40
  567. package/build/utils/gif-conversion-attributes.cjs.map +0 -7
  568. package/build/video/gif-restore-control.cjs +0 -73
  569. package/build/video/gif-restore-control.cjs.map +0 -7
  570. package/build-module/image/animated-gif-convert-control.mjs +0 -87
  571. package/build-module/image/animated-gif-convert-control.mjs.map +0 -7
  572. package/build-module/utils/gif-conversion-attributes.mjs +0 -15
  573. package/build-module/utils/gif-conversion-attributes.mjs.map +0 -7
  574. package/build-module/video/gif-restore-control.mjs +0 -55
  575. package/build-module/video/gif-restore-control.mjs.map +0 -7
  576. package/src/image/animated-gif-convert-control.js +0 -135
  577. package/src/image/test/animated-gif-convert-control.js +0 -276
  578. package/src/utils/gif-conversion-attributes.js +0 -30
  579. package/src/utils/test/gif-conversion-attributes.js +0 -60
  580. package/src/video/gif-restore-control.js +0 -92
@@ -1,3 +1,8 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import clsx from 'clsx';
5
+
1
6
  /**
2
7
  * WordPress dependencies
3
8
  */
@@ -69,7 +74,6 @@ import {
69
74
  getStyleStateKey,
70
75
  } from '../utils/style-state';
71
76
  import { useOpenImageMediaEditorModal } from './use-open-image-media-editor-modal';
72
- import AnimatedGifConvertControl from './animated-gif-convert-control';
73
77
  import {
74
78
  MIN_SIZE,
75
79
  ALLOWED_MEDIA_TYPES,
@@ -391,6 +395,12 @@ export default function Image( {
391
395
  );
392
396
  const { getBlock, getSettings } = useSelect( blockEditorStore );
393
397
  const cropButtonRef = useRef();
398
+ // URL of a freshly generated file (crop/rotate result) from the media
399
+ // editor that the browser may not have finished loading; cleared by the
400
+ // <img> load/error handlers, or by the settle effect below when the
401
+ // rendered image already shows it.
402
+ const [ pendingSwapUrl, setPendingSwapUrl ] = useState();
403
+ const isSwappingMedia = !! pendingSwapUrl;
394
404
  const handleMediaEditorModalClose = useCallback(
395
405
  () => cropButtonRef.current?.focus(),
396
406
  []
@@ -399,6 +409,7 @@ export default function Image( {
399
409
  attributes,
400
410
  setAttributes,
401
411
  onClose: handleMediaEditorModalClose,
412
+ onUrlChange: setPendingSwapUrl,
402
413
  } );
403
414
 
404
415
  const {
@@ -486,18 +497,34 @@ export default function Image( {
486
497
  };
487
498
  }, [ loadedNaturalWidth, loadedNaturalHeight, imageElement?.complete ] );
488
499
 
500
+ // A media editor update can be undone or superseded before its
501
+ // attributes land, leaving the rendered image untouched. No load event
502
+ // fires in that case, so clear the pending swap whenever the rendered
503
+ // image already shows the pending URL.
504
+ useEffect( () => {
505
+ if (
506
+ pendingSwapUrl &&
507
+ pendingSwapUrl === url &&
508
+ imageElement?.complete
509
+ ) {
510
+ setPendingSwapUrl( undefined );
511
+ }
512
+ }, [ pendingSwapUrl, url, imageElement ] );
513
+
489
514
  function onImageError() {
515
+ setPendingSwapUrl( undefined );
490
516
  setHasImageErrored( true );
491
517
 
492
518
  // Check if there's an embed block that handles this URL, e.g., instagram URL.
493
519
  // See: https://github.com/WordPress/gutenberg/pull/11472
494
520
  const embedBlock = createUpgradedEmbedBlock( { attributes: { url } } );
495
- if ( undefined !== embedBlock ) {
521
+ if ( undefined !== embedBlock && onReplace ) {
496
522
  onReplace( embedBlock );
497
523
  }
498
524
  }
499
525
 
500
526
  function onImageLoad( event ) {
527
+ setPendingSwapUrl( undefined );
501
528
  setHasImageErrored( false );
502
529
  setLoadedNaturalSize( {
503
530
  loadedNaturalWidth: event.target?.naturalWidth,
@@ -854,21 +881,23 @@ export default function Image( {
854
881
 
855
882
  const showBlockControls = showUrlInput || allowCrop || showCoverControls;
856
883
 
857
- const mediaReplaceFlow = isSingleSelected && ! lockUrlControls && (
858
- // For contentOnly mode, put this button in its own area so it has borders around it.
859
- <BlockControls group={ isContentOnlyMode ? 'inline' : 'other' }>
860
- <MediaReplaceFlow
861
- mediaId={ id }
862
- mediaURL={ url }
863
- allowedTypes={ ALLOWED_MEDIA_TYPES }
864
- onSelect={ onSelectImage }
865
- onSelectURL={ onSelectURL }
866
- onError={ onUploadError }
867
- name={ ! url ? __( 'Add image' ) : __( 'Replace' ) }
868
- onReset={ () => onSelectImage( undefined ) }
869
- variant="toolbar"
870
- />
871
- </BlockControls>
884
+ const mediaControls = isSingleSelected && ! lockUrlControls && (
885
+ <>
886
+ { /* For contentOnly mode, put this button in its own area so it has borders around it. */ }
887
+ <BlockControls group={ isContentOnlyMode ? 'inline' : 'other' }>
888
+ <MediaReplaceFlow
889
+ mediaId={ id }
890
+ mediaURL={ url }
891
+ allowedTypes={ ALLOWED_MEDIA_TYPES }
892
+ onSelect={ onSelectImage }
893
+ onSelectURL={ onSelectURL }
894
+ onError={ onUploadError }
895
+ name={ ! url ? __( 'Add image' ) : __( 'Replace' ) }
896
+ onReset={ () => onSelectImage( undefined ) }
897
+ variant="toolbar"
898
+ />
899
+ </BlockControls>
900
+ </>
872
901
  );
873
902
 
874
903
  const hasDataFormBlockFields =
@@ -901,6 +930,10 @@ export default function Image( {
901
930
  aria-haspopup="dialog"
902
931
  icon={ crop }
903
932
  label={ __( 'Crop' ) }
933
+ // Disable rather than hide while the edited image
934
+ // loads, so the button keeps focus when the modal
935
+ // closes instead of dropping it to the canvas.
936
+ disabled={ isSwappingMedia }
904
937
  />
905
938
  ) }
906
939
  { showCoverControls && (
@@ -1172,7 +1205,9 @@ export default function Image( {
1172
1205
  onError={ onImageError }
1173
1206
  onLoad={ onImageLoad }
1174
1207
  ref={ setRefs }
1175
- className={ borderProps.className }
1208
+ className={ clsx( borderProps.className, {
1209
+ 'is-swapping-media': isSwappingMedia,
1210
+ } ) }
1176
1211
  width={ naturalWidth }
1177
1212
  height={ naturalHeight }
1178
1213
  style={ {
@@ -1221,7 +1256,7 @@ export default function Image( {
1221
1256
  ...shadowProps.style,
1222
1257
  } }
1223
1258
  />
1224
- { isUploading && <Spinner /> }
1259
+ { ( isUploading || isSwappingMedia ) && <Spinner /> }
1225
1260
  </>
1226
1261
  ) }
1227
1262
  </ImageWrapper>
@@ -1355,7 +1390,7 @@ export default function Image( {
1355
1390
  if ( ! url && ! temporaryURL ) {
1356
1391
  return (
1357
1392
  <>
1358
- { mediaReplaceFlow }
1393
+ { mediaControls }
1359
1394
  { controls }
1360
1395
  </>
1361
1396
  );
@@ -1390,13 +1425,7 @@ export default function Image( {
1390
1425
 
1391
1426
  return (
1392
1427
  <>
1393
- { isSingleSelected && ! lockUrlControls && (
1394
- <AnimatedGifConvertControl
1395
- attributes={ attributes }
1396
- clientId={ clientId }
1397
- />
1398
- ) }
1399
- { mediaReplaceFlow }
1428
+ { mediaControls }
1400
1429
  { controls }
1401
1430
  { featuredImageControl }
1402
1431
  { img }
@@ -80,6 +80,7 @@ async function runModalUpdate( {
80
80
  attributes,
81
81
  registryOptions = {},
82
82
  updatePayload = { id: attributes.id, url: 'updated.jpg' },
83
+ hookOptions = {},
83
84
  } ) {
84
85
  const registry = createRegistry( registryOptions );
85
86
  useRegistry.mockReturnValue( registry );
@@ -87,7 +88,11 @@ async function runModalUpdate( {
87
88
  const openMediaEditorModal = jest.fn();
88
89
  mockMediaEditorModalSetting( openMediaEditorModal );
89
90
  const { result } = renderHook( () =>
90
- useOpenImageMediaEditorModal( { attributes, setAttributes } )
91
+ useOpenImageMediaEditorModal( {
92
+ attributes,
93
+ setAttributes,
94
+ ...hookOptions,
95
+ } )
91
96
  );
92
97
  await act( async () => {
93
98
  await result.current();
@@ -105,6 +110,37 @@ describe( 'useOpenImageMediaEditorModal', () => {
105
110
  jest.clearAllMocks();
106
111
  } );
107
112
 
113
+ it( 'notifies onUrlChange when the update switches to a new attachment URL', async () => {
114
+ const onUrlChange = jest.fn();
115
+ await runModalUpdate( {
116
+ attributes: { id: 1, url: 'original.jpg', alt: '', caption: '' },
117
+ updatePayload: { id: 2, url: 'updated.jpg' },
118
+ hookOptions: { onUrlChange },
119
+ } );
120
+ expect( onUrlChange ).toHaveBeenCalledTimes( 1 );
121
+ expect( onUrlChange ).toHaveBeenCalledWith( 'updated.jpg' );
122
+ } );
123
+
124
+ it( 'does not notify onUrlChange for a same-attachment update', async () => {
125
+ const onUrlChange = jest.fn();
126
+ await runModalUpdate( {
127
+ attributes: { id: 1, url: 'original.jpg', alt: '', caption: '' },
128
+ updatePayload: { id: 1, url: 'original.jpg' },
129
+ hookOptions: { onUrlChange },
130
+ } );
131
+ expect( onUrlChange ).not.toHaveBeenCalled();
132
+ } );
133
+
134
+ it( 'does not notify onUrlChange when the update carries no URL', async () => {
135
+ const onUrlChange = jest.fn();
136
+ await runModalUpdate( {
137
+ attributes: { id: 1, url: 'original.jpg', alt: '', caption: '' },
138
+ updatePayload: { id: 2 },
139
+ hookOptions: { onUrlChange },
140
+ } );
141
+ expect( onUrlChange ).not.toHaveBeenCalled();
142
+ } );
143
+
108
144
  it( 'returns no opener when the media editor modal setting is unavailable', () => {
109
145
  useRegistry.mockReturnValue( createRegistry() );
110
146
  mockMediaEditorModalSetting( undefined );
@@ -3,6 +3,95 @@
3
3
  */
4
4
  import { createBlobURL, isBlobURL } from '@wordpress/blob';
5
5
  import { createBlock, getBlockAttributes } from '@wordpress/blocks';
6
+ import { select } from '@wordpress/data';
7
+ import { store as coreStore } from '@wordpress/core-data';
8
+
9
+ /**
10
+ * Returns the subset of block attributes that should be carried over when
11
+ * converting an animated-GIF Image block into its converted Video block.
12
+ *
13
+ * The conversion swaps one block for another via `createBlock`, which would
14
+ * otherwise drop everything the author set on the original block. This carries
15
+ * the attributes both blocks support: block alignment, the HTML anchor, custom
16
+ * class names, and margin spacing.
17
+ *
18
+ * Image-only attributes such as links (`href`/`linkDestination`), sizing
19
+ * (`sizeSlug`/`scale`), and `border`/`shadow` styles are intentionally not
20
+ * carried: the Video block has no equivalent, so copying them would leave
21
+ * attributes the target block cannot represent.
22
+ *
23
+ * @param {Object} attributes Source block attributes.
24
+ * @return {Object} Attributes to spread into the converted block.
25
+ */
26
+ function getCarriedGifConversionAttributes( attributes ) {
27
+ const { align, anchor, className, style } = attributes;
28
+ const margin = style?.spacing?.margin;
29
+
30
+ return {
31
+ ...( align && { align } ),
32
+ ...( anchor && { anchor } ),
33
+ ...( className && { className } ),
34
+ ...( margin && { style: { spacing: { margin } } } ),
35
+ };
36
+ }
37
+
38
+ /**
39
+ * Returns the sideloaded video companion of an animated GIF image attachment,
40
+ * or `null` when the media is not a converted animated GIF.
41
+ *
42
+ * An animated GIF uploaded through the editor gets a muted, looping video
43
+ * transcode sideloaded next to it and recorded (as basenames) in the
44
+ * attachment's `media_details.animated_video` / `animated_video_poster`.
45
+ *
46
+ * Block transforms match and run synchronously, so this reads the attachment
47
+ * record straight from the core-data store: it only returns the companion once
48
+ * the record is resolved. The Image block resolves the record while the block
49
+ * is selected, which is also when the block switcher can offer the transform.
50
+ *
51
+ * @param {number} id Image attachment ID.
52
+ * @param {string} url Image block URL, used to cheaply skip non-GIF media.
53
+ * @return {Object|null} Companion details (absolute `src`/`poster` URLs and
54
+ * the GIF's intrinsic `width`/`height`), or `null`.
55
+ */
56
+ function getAnimatedGifVideoCompanion( id, url ) {
57
+ if ( ! id ) {
58
+ return null;
59
+ }
60
+ /*
61
+ * Only animated GIFs have a video companion. Gate on the `.gif` extension
62
+ * so an ordinary image never reaches into the attachment record just to
63
+ * discover it has no companion. Strip any query string or fragment first
64
+ * so a URL like `cat.gif?ver=2` still matches.
65
+ */
66
+ const urlPath = url?.split( /[?#]/ )[ 0 ];
67
+ if ( ! urlPath?.toLowerCase().endsWith( '.gif' ) ) {
68
+ return null;
69
+ }
70
+ const record = select( coreStore ).getEntityRecord(
71
+ 'postType',
72
+ 'attachment',
73
+ id,
74
+ { context: 'view' }
75
+ );
76
+ const details = record?.media_details;
77
+ if ( ! details?.animated_video || ! record?.source_url ) {
78
+ return null;
79
+ }
80
+ // Companion files are sideloaded next to the GIF, so they share its
81
+ // directory; build their URLs from the GIF's own source URL.
82
+ const dir = record.source_url.slice(
83
+ 0,
84
+ record.source_url.lastIndexOf( '/' ) + 1
85
+ );
86
+ return {
87
+ src: dir + details.animated_video,
88
+ poster: details.animated_video_poster
89
+ ? dir + details.animated_video_poster
90
+ : undefined,
91
+ width: details.width,
92
+ height: details.height,
93
+ };
94
+ }
6
95
 
7
96
  export function stripFirstImage( attributes, { shortcode } ) {
8
97
  const { body } = document.implementation.createHTMLDocument( '' );
@@ -253,6 +342,45 @@ const transforms = {
253
342
  },
254
343
  },
255
344
  ],
345
+ to: [
346
+ {
347
+ // Offer converting an animated GIF into the Video block's "GIF"
348
+ // variation: a muted, looping, autoplaying video transcoded from
349
+ // the GIF and sideloaded next to it when it was uploaded. Only
350
+ // matches when that companion video exists, so ordinary images
351
+ // never see this transform.
352
+ type: 'block',
353
+ blocks: [ 'core/video' ],
354
+ isMatch: ( { id, url } ) =>
355
+ !! getAnimatedGifVideoCompanion( id, url ),
356
+ transform( attributes ) {
357
+ const { id, url, caption } = attributes;
358
+ const companion = getAnimatedGifVideoCompanion( id, url );
359
+
360
+ return createBlock( 'core/video', {
361
+ ...getCarriedGifConversionAttributes( attributes ),
362
+ id,
363
+ src: companion.src,
364
+ poster: companion.poster,
365
+ caption,
366
+ controls: false,
367
+ loop: true,
368
+ autoplay: true,
369
+ muted: true,
370
+ playsInline: true,
371
+ /*
372
+ * Carry the GIF's intrinsic dimensions so the <video>
373
+ * keeps its aspect ratio from the first paint. Without
374
+ * them the element collapses to the browser-default size
375
+ * and then jumps once the poster/metadata load, which
376
+ * shows up as a brief duplicated image during the swap.
377
+ */
378
+ width: companion.width,
379
+ height: companion.height,
380
+ } );
381
+ },
382
+ },
383
+ ],
256
384
  };
257
385
 
258
386
  export default transforms;
@@ -137,6 +137,7 @@ export function useOpenImageMediaEditorModal( {
137
137
  attributes,
138
138
  setAttributes,
139
139
  onClose,
140
+ onUrlChange,
140
141
  } ) {
141
142
  // Keep this hook private to the Image block and pass the block attributes
142
143
  // object so the callsite stays compact. Destructure only the attributes
@@ -246,6 +247,12 @@ export function useOpenImageMediaEditorModal( {
246
247
  if ( newId !== currentBlockAttributes.id ) {
247
248
  nextAttributes.id = newId;
248
249
  nextAttributes.url = newUrl ?? currentBlockAttributes.url;
250
+ if ( nextAttributes.url !== currentBlockAttributes.url ) {
251
+ // The block is about to point at a freshly generated file
252
+ // the browser hasn't loaded yet; let the caller show a
253
+ // loading state until its <img> fires load/error.
254
+ onUrlChange?.( nextAttributes.url );
255
+ }
249
256
  blockAttributesRef.current = {
250
257
  ...blockAttributesRef.current,
251
258
  id: nextAttributes.id,
@@ -294,7 +301,7 @@ export function useOpenImageMediaEditorModal( {
294
301
  setAttributes( nextAttributes );
295
302
  }
296
303
  },
297
- [ resolveFreshAttachmentRecord, setAttributes ]
304
+ [ onUrlChange, resolveFreshAttachmentRecord, setAttributes ]
298
305
  );
299
306
 
300
307
  const openImageMediaEditorModal = useCallback( async () => {
package/src/index.js CHANGED
@@ -197,6 +197,8 @@ const getAllBlocks = () => {
197
197
  pageList,
198
198
  pageListItem,
199
199
  pattern,
200
+ playlist,
201
+ playlistTrack,
200
202
  preformatted,
201
203
  pullquote,
202
204
  reusableBlock,
@@ -208,6 +210,10 @@ const getAllBlocks = () => {
208
210
  socialLinks,
209
211
  spacer,
210
212
  table,
213
+ tabs,
214
+ tabList,
215
+ tabPanels,
216
+ tabPanel,
211
217
  tagCloud,
212
218
  textColumns,
213
219
  verse,
@@ -281,12 +287,8 @@ const getAllBlocks = () => {
281
287
  }
282
288
 
283
289
  if ( window?.__experimentalEnableBlockExperiments ) {
284
- blocks.push( tabList );
285
- blocks.push( tabs );
286
- blocks.push( tabPanel );
287
- blocks.push( tabPanels );
288
- blocks.push( playlist );
289
- blocks.push( playlistTrack );
290
+ // Blocks added here are only registered when the "Block experiments"
291
+ // option is enabled in the Gutenberg > Experiments settings page.
290
292
  }
291
293
 
292
294
  blocks.push( classic );
@@ -343,13 +345,23 @@ export const registerCoreBlocks = (
343
345
  ...( ( bootstrappedBlockType?.apiVersion ?? 0 ) < 3 && {
344
346
  apiVersion: 3,
345
347
  } ),
348
+ // Always pass the postId context so the server-side render can
349
+ // reproduce the same output as the front end, while preserving
350
+ // any context declared in the block's PHP registration.
351
+ usesContext: Array.from(
352
+ new Set( [
353
+ ...( bootstrappedBlockType?.usesContext ?? [] ),
354
+ 'postId',
355
+ ] )
356
+ ),
346
357
  // Inspector controls are rendered by the auto-register hook in block-editor
347
- edit: function Edit( { attributes } ) {
358
+ edit: function Edit( { attributes, context } ) {
348
359
  const disabledRef = useDisabled();
349
360
  const blockProps = useBlockProps( { ref: disabledRef } );
350
361
  const { content, status, error } = useServerSideRender( {
351
362
  block: blockName,
352
363
  attributes,
364
+ urlQueryArgs: { post_id: context?.postId },
353
365
  } );
354
366
 
355
367
  if ( status === 'loading' ) {
@@ -162,13 +162,10 @@ function Controls( { attributes, setAttributes } ) {
162
162
  label: name,
163
163
  } ) );
164
164
  const categorySuggestions =
165
- categoriesList?.reduce(
166
- ( accumulator, category ) => ( {
167
- ...accumulator,
168
- [ category.name ]: category,
169
- } ),
170
- {}
171
- ) ?? {};
165
+ categoriesList?.reduce( ( accumulator, category ) => {
166
+ accumulator[ category.name ] = category;
167
+ return accumulator;
168
+ }, {} ) ?? {};
172
169
  const selectCategories = ( tokens ) => {
173
170
  const hasNoSuggestion = tokens.some(
174
171
  ( token ) =>
@@ -807,7 +804,7 @@ export default function LatestPostsEdit( {
807
804
  <div
808
805
  className="wp-block-latest-posts__post-full-content"
809
806
  dangerouslySetInnerHTML={ {
810
- __html: post.content.raw.trim(),
807
+ __html: post.content.rendered.trim(),
811
808
  } }
812
809
  />
813
810
  ) }
@@ -44,6 +44,7 @@ function block_core_latest_posts_get_excerpt_length() {
44
44
  */
45
45
  function render_block_core_latest_posts( $attributes ) {
46
46
  global $post, $block_core_latest_posts_excerpt_length;
47
+ static $rendering_stack = array();
47
48
 
48
49
  $args = array(
49
50
  'posts_per_page' => $attributes['postsToShow'],
@@ -57,25 +58,31 @@ function render_block_core_latest_posts( $attributes ) {
57
58
  $block_core_latest_posts_excerpt_length = $attributes['excerptLength'];
58
59
  add_filter( 'excerpt_length', 'block_core_latest_posts_get_excerpt_length', 20 );
59
60
 
60
- if ( ! empty( $attributes['categories'] ) ) {
61
- $args['category__in'] = array_column( $attributes['categories'], 'id' );
61
+ $categories = $attributes['categories'] ?? null;
62
+ if ( ! empty( $categories ) && is_array( $categories ) ) {
63
+ $args['category__in'] = array_column( $categories, 'id' );
62
64
  }
63
65
  if ( isset( $attributes['selectedAuthor'] ) ) {
64
66
  $args['author'] = $attributes['selectedAuthor'];
65
67
  }
66
68
 
67
- $query = new WP_Query();
68
- $recent_posts = $query->query( $args );
69
+ $query = new WP_Query( $args );
69
70
 
70
71
  if ( isset( $attributes['displayFeaturedImage'] ) && $attributes['displayFeaturedImage'] ) {
71
72
  update_post_thumbnail_cache( $query );
72
73
  }
73
74
 
74
75
  $list_items_markup = '';
76
+ // Snapshot the current global post so it can be restored after the loop.
77
+ // We use have_posts()/the_post() rather than foreach so that setup_postdata()
78
+ // is called for each post, establishing the correct global context for
79
+ // do_blocks() and other filters that run during full-content rendering.
80
+ $previous_post = $post ?? null;
75
81
 
76
- foreach ( $recent_posts as $post ) {
77
- $post_link = esc_url( get_permalink( $post ) );
78
- $title = get_the_title( $post );
82
+ while ( $query->have_posts() ) {
83
+ $query->the_post();
84
+ $post_link = esc_url( get_permalink() );
85
+ $title = get_the_title();
79
86
 
80
87
  if ( ! $title ) {
81
88
  $title = __( '(no title)' );
@@ -83,7 +90,7 @@ function render_block_core_latest_posts( $attributes ) {
83
90
 
84
91
  $list_items_markup .= '<li>';
85
92
 
86
- if ( $attributes['displayFeaturedImage'] && has_post_thumbnail( $post ) ) {
93
+ if ( $attributes['displayFeaturedImage'] && has_post_thumbnail() ) {
87
94
  $image_style = '';
88
95
  if ( isset( $attributes['featuredImageSizeWidth'] ) ) {
89
96
  $image_style .= sprintf( 'max-width:%spx;', $attributes['featuredImageSizeWidth'] );
@@ -98,7 +105,7 @@ function render_block_core_latest_posts( $attributes ) {
98
105
  }
99
106
 
100
107
  $featured_image = get_the_post_thumbnail(
101
- $post,
108
+ null,
102
109
  $attributes['featuredImageSizeSlug'],
103
110
  array(
104
111
  'style' => esc_attr( $image_style ),
@@ -126,7 +133,7 @@ function render_block_core_latest_posts( $attributes ) {
126
133
  );
127
134
 
128
135
  if ( isset( $attributes['displayAuthor'] ) && $attributes['displayAuthor'] ) {
129
- $author_display_name = get_the_author_meta( 'display_name', $post->post_author );
136
+ $author_display_name = get_the_author_meta( 'display_name' );
130
137
 
131
138
  /* translators: byline. %s: author. */
132
139
  $byline = sprintf( __( 'by %s' ), $author_display_name );
@@ -142,15 +149,15 @@ function render_block_core_latest_posts( $attributes ) {
142
149
  if ( isset( $attributes['displayPostDate'] ) && $attributes['displayPostDate'] ) {
143
150
  $list_items_markup .= sprintf(
144
151
  '<time datetime="%1$s" class="wp-block-latest-posts__post-date">%2$s</time>',
145
- esc_attr( get_the_date( 'c', $post ) ),
146
- get_the_date( '', $post )
152
+ esc_attr( get_the_date( 'c' ) ),
153
+ get_the_date( '' )
147
154
  );
148
155
  }
149
156
 
150
157
  if ( isset( $attributes['displayPostContent'] ) && $attributes['displayPostContent']
151
158
  && isset( $attributes['displayPostContentRadio'] ) && 'excerpt' === $attributes['displayPostContentRadio'] ) {
152
159
 
153
- $trimmed_excerpt = get_the_excerpt( $post );
160
+ $trimmed_excerpt = get_the_excerpt();
154
161
 
155
162
  /*
156
163
  * Adds a "Read more" link with screen reader text.
@@ -170,7 +177,7 @@ function render_block_core_latest_posts( $attributes ) {
170
177
  }
171
178
  }
172
179
 
173
- if ( post_password_required( $post ) ) {
180
+ if ( post_password_required() ) {
174
181
  $trimmed_excerpt = __( 'This content is password protected.' );
175
182
  }
176
183
 
@@ -183,21 +190,45 @@ function render_block_core_latest_posts( $attributes ) {
183
190
  if ( isset( $attributes['displayPostContent'] ) && $attributes['displayPostContent']
184
191
  && isset( $attributes['displayPostContentRadio'] ) && 'full_post' === $attributes['displayPostContentRadio'] ) {
185
192
 
186
- $post_content = html_entity_decode( $post->post_content, ENT_QUOTES, get_option( 'blog_charset' ) );
187
-
188
- if ( post_password_required( $post ) ) {
193
+ if ( post_password_required() ) {
189
194
  $post_content = __( 'This content is password protected.' );
195
+ } else {
196
+ $post_id = get_the_ID();
197
+ $post_content = get_post_field( 'post_content', $post_id, 'raw' );
198
+ // Check if we're already rendering this post to prevent infinite recursion.
199
+ if ( in_array( $post_id, $rendering_stack, true ) ) {
200
+ $post_content = '';
201
+ } else {
202
+ $rendering_stack[] = $post_id;
203
+
204
+ try {
205
+ // Run through the actions that are typically taken on the_content.
206
+ $post_content = _wp_apply_block_content_filters( $post_content, 'latest-posts' );
207
+ } finally {
208
+ array_pop( $rendering_stack );
209
+ }
210
+ }
190
211
  }
191
212
 
213
+ $post_content = str_replace( ']]>', ']]&gt;', $post_content );
192
214
  $list_items_markup .= sprintf(
193
215
  '<div class="wp-block-latest-posts__post-full-content">%1$s</div>',
194
- wp_kses_post( $post_content )
216
+ $post_content
195
217
  );
196
218
  }
197
219
 
198
220
  $list_items_markup .= "</li>\n";
199
221
  }
200
222
 
223
+ // Restore the post context that was active before this secondary query.
224
+ // wp_reset_postdata() is intentionally not used here: when this block is
225
+ // rendered inside another post's content (e.g. via do_blocks()), it would
226
+ // restore to the main query post rather than the outer rendering post.
227
+ $post = $previous_post;
228
+ if ( $previous_post instanceof WP_Post ) {
229
+ setup_postdata( $previous_post );
230
+ }
231
+
201
232
  remove_filter( 'excerpt_length', 'block_core_latest_posts_get_excerpt_length', 20 );
202
233
 
203
234
  $layout = $attributes['layout'] ?? array();
@@ -83,7 +83,7 @@ export default function ListItemEdit( {
83
83
  renderAppender: false,
84
84
  __unstableDisableDropZone: true,
85
85
  } );
86
- const useEnterRef = useEnter( { content, clientId } );
86
+ const useEnterRef = useEnter( clientId );
87
87
  const useSpaceRef = useSpace( clientId );
88
88
  const onMerge = useMerge( clientId, mergeBlocks );
89
89
  return (