@wordpress/block-editor 11.6.0 → 11.8.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 (350) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +46 -55
  3. package/build/components/block-list/block-html.js +1 -3
  4. package/build/components/block-list/block-html.js.map +1 -1
  5. package/build/components/block-list/block.native.js +4 -3
  6. package/build/components/block-list/block.native.js.map +1 -1
  7. package/build/components/block-list/index.native.js +11 -21
  8. package/build/components/block-list/index.native.js.map +1 -1
  9. package/build/components/block-list/use-in-between-inserter.js +3 -1
  10. package/build/components/block-list/use-in-between-inserter.js.map +1 -1
  11. package/build/components/block-popover/inbetween.js +2 -9
  12. package/build/components/block-popover/inbetween.js.map +1 -1
  13. package/build/components/block-preview/auto.js +6 -23
  14. package/build/components/block-preview/auto.js.map +1 -1
  15. package/build/components/block-settings-menu/block-settings-dropdown.js +1 -10
  16. package/build/components/block-settings-menu/block-settings-dropdown.js.map +1 -1
  17. package/build/components/caption/index.native.js +0 -1
  18. package/build/components/caption/index.native.js.map +1 -1
  19. package/build/components/date-format-picker/index.js +1 -1
  20. package/build/components/date-format-picker/index.js.map +1 -1
  21. package/build/components/editor-styles/index.js +20 -2
  22. package/build/components/editor-styles/index.js.map +1 -1
  23. package/build/components/global-styles/border-panel.js +15 -29
  24. package/build/components/global-styles/border-panel.js.map +1 -1
  25. package/build/components/global-styles/color-panel.js +583 -0
  26. package/build/components/global-styles/color-panel.js.map +1 -0
  27. package/build/components/global-styles/dimensions-panel.js +23 -44
  28. package/build/components/global-styles/dimensions-panel.js.map +1 -1
  29. package/build/components/global-styles/effects-panel.js +244 -0
  30. package/build/components/global-styles/effects-panel.js.map +1 -0
  31. package/build/components/global-styles/filters-panel.js +151 -0
  32. package/build/components/global-styles/filters-panel.js.map +1 -0
  33. package/build/components/global-styles/get-block-css-selector.js +118 -0
  34. package/build/components/global-styles/get-block-css-selector.js.map +1 -0
  35. package/build/components/global-styles/hooks.js +60 -1
  36. package/build/components/global-styles/hooks.js.map +1 -1
  37. package/build/components/global-styles/index.js +46 -2
  38. package/build/components/global-styles/index.js.map +1 -1
  39. package/build/components/global-styles/typography-panel.js +9 -35
  40. package/build/components/global-styles/typography-panel.js.map +1 -1
  41. package/build/components/global-styles/use-global-styles-output.js +173 -91
  42. package/build/components/global-styles/use-global-styles-output.js.map +1 -1
  43. package/build/components/global-styles/utils.js +2 -1
  44. package/build/components/global-styles/utils.js.map +1 -1
  45. package/build/components/iframe/index.js +1 -1
  46. package/build/components/iframe/index.js.map +1 -1
  47. package/build/components/image-size-control/index.js +8 -5
  48. package/build/components/image-size-control/index.js.map +1 -1
  49. package/build/components/image-size-control/use-dimension-handler.js +5 -3
  50. package/build/components/image-size-control/use-dimension-handler.js.map +1 -1
  51. package/build/components/index.js +16 -0
  52. package/build/components/index.js.map +1 -1
  53. package/build/components/inserter/block-patterns-tab.js +4 -2
  54. package/build/components/inserter/block-patterns-tab.js.map +1 -1
  55. package/build/components/inspector-controls-tabs/position-controls-panel.js +43 -7
  56. package/build/components/inspector-controls-tabs/position-controls-panel.js.map +1 -1
  57. package/build/components/inspector-controls-tabs/utils.js +5 -3
  58. package/build/components/inspector-controls-tabs/utils.js.map +1 -1
  59. package/build/components/line-height-control/index.js +15 -1
  60. package/build/components/line-height-control/index.js.map +1 -1
  61. package/build/components/list-view/appender.js +105 -0
  62. package/build/components/list-view/appender.js.map +1 -0
  63. package/build/components/list-view/block.js +6 -5
  64. package/build/components/list-view/block.js.map +1 -1
  65. package/build/components/list-view/branch.js +25 -5
  66. package/build/components/list-view/branch.js.map +1 -1
  67. package/build/components/list-view/index.js +56 -14
  68. package/build/components/list-view/index.js.map +1 -1
  69. package/build/components/list-view/use-list-view-client-ids.js +7 -3
  70. package/build/components/list-view/use-list-view-client-ids.js.map +1 -1
  71. package/build/components/list-view/use-list-view-drop-zone.js +8 -2
  72. package/build/components/list-view/use-list-view-drop-zone.js.map +1 -1
  73. package/build/components/media-replace-flow/index.js +13 -4
  74. package/build/components/media-replace-flow/index.js.map +1 -1
  75. package/build/components/off-canvas-editor/block-contents.js +6 -1
  76. package/build/components/off-canvas-editor/block-contents.js.map +1 -1
  77. package/build/components/off-canvas-editor/index.js +17 -14
  78. package/build/components/off-canvas-editor/index.js.map +1 -1
  79. package/build/components/resizable-box-popover/index.js +38 -0
  80. package/build/components/resizable-box-popover/index.js.map +1 -0
  81. package/build/components/rich-text/format-edit.js +2 -30
  82. package/build/components/rich-text/format-edit.js.map +1 -1
  83. package/build/components/rich-text/index.js +0 -1
  84. package/build/components/rich-text/index.js.map +1 -1
  85. package/build/components/rich-text/index.native.js +7 -11
  86. package/build/components/rich-text/index.native.js.map +1 -1
  87. package/build/components/spacing-sizes-control/spacing-input-control.js +8 -0
  88. package/build/components/spacing-sizes-control/spacing-input-control.js.map +1 -1
  89. package/build/components/writing-flow/use-input.js +4 -8
  90. package/build/components/writing-flow/use-input.js.map +1 -1
  91. package/build/hooks/anchor.js +1 -1
  92. package/build/hooks/anchor.js.map +1 -1
  93. package/build/hooks/border.js +1 -2
  94. package/build/hooks/border.js.map +1 -1
  95. package/build/hooks/color.js +92 -229
  96. package/build/hooks/color.js.map +1 -1
  97. package/build/hooks/content-lock-ui.js +4 -2
  98. package/build/hooks/content-lock-ui.js.map +1 -1
  99. package/build/hooks/{color-panel.js → contrast-checker.js} +11 -49
  100. package/build/hooks/contrast-checker.js.map +1 -0
  101. package/build/hooks/dimensions.js +0 -1
  102. package/build/hooks/dimensions.js.map +1 -1
  103. package/build/hooks/duotone.js +92 -64
  104. package/build/hooks/duotone.js.map +1 -1
  105. package/build/hooks/margin.js +27 -17
  106. package/build/hooks/margin.js.map +1 -1
  107. package/build/hooks/padding.js +19 -9
  108. package/build/hooks/padding.js.map +1 -1
  109. package/build/hooks/position.js +2 -2
  110. package/build/hooks/position.js.map +1 -1
  111. package/build/hooks/style.js +23 -26
  112. package/build/hooks/style.js.map +1 -1
  113. package/build/hooks/typography.js +0 -1
  114. package/build/hooks/typography.js.map +1 -1
  115. package/build/hooks/utils.js +28 -76
  116. package/build/hooks/utils.js.map +1 -1
  117. package/build/layouts/grid.js +165 -0
  118. package/build/layouts/grid.js.map +1 -0
  119. package/build/layouts/index.js +3 -1
  120. package/build/layouts/index.js.map +1 -1
  121. package/build/layouts/utils.js +3 -2
  122. package/build/layouts/utils.js.map +1 -1
  123. package/build/private-apis.js +7 -1
  124. package/build/private-apis.js.map +1 -1
  125. package/build/store/actions.js +1 -1
  126. package/build/store/actions.js.map +1 -1
  127. package/build/utils/object.js +76 -0
  128. package/build/utils/object.js.map +1 -0
  129. package/build-module/components/block-list/block-html.js +1 -3
  130. package/build-module/components/block-list/block-html.js.map +1 -1
  131. package/build-module/components/block-list/block.native.js +4 -3
  132. package/build-module/components/block-list/block.native.js.map +1 -1
  133. package/build-module/components/block-list/index.native.js +11 -19
  134. package/build-module/components/block-list/index.native.js.map +1 -1
  135. package/build-module/components/block-list/use-in-between-inserter.js +2 -1
  136. package/build-module/components/block-list/use-in-between-inserter.js.map +1 -1
  137. package/build-module/components/block-popover/inbetween.js +2 -9
  138. package/build-module/components/block-popover/inbetween.js.map +1 -1
  139. package/build-module/components/block-preview/auto.js +6 -22
  140. package/build-module/components/block-preview/auto.js.map +1 -1
  141. package/build-module/components/block-settings-menu/block-settings-dropdown.js +1 -9
  142. package/build-module/components/block-settings-menu/block-settings-dropdown.js.map +1 -1
  143. package/build-module/components/caption/index.native.js +0 -1
  144. package/build-module/components/caption/index.native.js.map +1 -1
  145. package/build-module/components/date-format-picker/index.js +1 -1
  146. package/build-module/components/date-format-picker/index.js.map +1 -1
  147. package/build-module/components/editor-styles/index.js +19 -2
  148. package/build-module/components/editor-styles/index.js.map +1 -1
  149. package/build-module/components/global-styles/border-panel.js +15 -29
  150. package/build-module/components/global-styles/border-panel.js.map +1 -1
  151. package/build-module/components/global-styles/color-panel.js +554 -0
  152. package/build-module/components/global-styles/color-panel.js.map +1 -0
  153. package/build-module/components/global-styles/dimensions-panel.js +22 -44
  154. package/build-module/components/global-styles/dimensions-panel.js.map +1 -1
  155. package/build-module/components/global-styles/effects-panel.js +228 -0
  156. package/build-module/components/global-styles/effects-panel.js.map +1 -0
  157. package/build-module/components/global-styles/filters-panel.js +139 -0
  158. package/build-module/components/global-styles/filters-panel.js.map +1 -0
  159. package/build-module/components/global-styles/get-block-css-selector.js +109 -0
  160. package/build-module/components/global-styles/get-block-css-selector.js.map +1 -0
  161. package/build-module/components/global-styles/hooks.js +58 -1
  162. package/build-module/components/global-styles/hooks.js.map +1 -1
  163. package/build-module/components/global-styles/index.js +5 -1
  164. package/build-module/components/global-styles/index.js.map +1 -1
  165. package/build-module/components/global-styles/typography-panel.js +8 -35
  166. package/build-module/components/global-styles/typography-panel.js.map +1 -1
  167. package/build-module/components/global-styles/use-global-styles-output.js +175 -93
  168. package/build-module/components/global-styles/use-global-styles-output.js.map +1 -1
  169. package/build-module/components/global-styles/utils.js +2 -1
  170. package/build-module/components/global-styles/utils.js.map +1 -1
  171. package/build-module/components/iframe/index.js +1 -1
  172. package/build-module/components/iframe/index.js.map +1 -1
  173. package/build-module/components/image-size-control/index.js +8 -5
  174. package/build-module/components/image-size-control/index.js.map +1 -1
  175. package/build-module/components/image-size-control/use-dimension-handler.js +5 -3
  176. package/build-module/components/image-size-control/use-dimension-handler.js.map +1 -1
  177. package/build-module/components/index.js +1 -0
  178. package/build-module/components/index.js.map +1 -1
  179. package/build-module/components/inserter/block-patterns-tab.js +5 -2
  180. package/build-module/components/inserter/block-patterns-tab.js.map +1 -1
  181. package/build-module/components/inspector-controls-tabs/position-controls-panel.js +42 -7
  182. package/build-module/components/inspector-controls-tabs/position-controls-panel.js.map +1 -1
  183. package/build-module/components/inspector-controls-tabs/utils.js +4 -3
  184. package/build-module/components/inspector-controls-tabs/utils.js.map +1 -1
  185. package/build-module/components/line-height-control/index.js +15 -1
  186. package/build-module/components/line-height-control/index.js.map +1 -1
  187. package/build-module/components/list-view/appender.js +88 -0
  188. package/build-module/components/list-view/appender.js.map +1 -0
  189. package/build-module/components/list-view/block.js +6 -4
  190. package/build-module/components/list-view/block.js.map +1 -1
  191. package/build-module/components/list-view/branch.js +22 -5
  192. package/build-module/components/list-view/branch.js.map +1 -1
  193. package/build-module/components/list-view/index.js +50 -13
  194. package/build-module/components/list-view/index.js.map +1 -1
  195. package/build-module/components/list-view/use-list-view-client-ids.js +7 -3
  196. package/build-module/components/list-view/use-list-view-client-ids.js.map +1 -1
  197. package/build-module/components/list-view/use-list-view-drop-zone.js +8 -4
  198. package/build-module/components/list-view/use-list-view-drop-zone.js.map +1 -1
  199. package/build-module/components/media-replace-flow/index.js +12 -4
  200. package/build-module/components/media-replace-flow/index.js.map +1 -1
  201. package/build-module/components/off-canvas-editor/block-contents.js +5 -1
  202. package/build-module/components/off-canvas-editor/block-contents.js.map +1 -1
  203. package/build-module/components/off-canvas-editor/index.js +17 -14
  204. package/build-module/components/off-canvas-editor/index.js.map +1 -1
  205. package/build-module/components/resizable-box-popover/index.js +26 -0
  206. package/build-module/components/resizable-box-popover/index.js.map +1 -0
  207. package/build-module/components/rich-text/format-edit.js +3 -31
  208. package/build-module/components/rich-text/format-edit.js.map +1 -1
  209. package/build-module/components/rich-text/index.js +0 -1
  210. package/build-module/components/rich-text/index.js.map +1 -1
  211. package/build-module/components/rich-text/index.native.js +7 -10
  212. package/build-module/components/rich-text/index.native.js.map +1 -1
  213. package/build-module/components/spacing-sizes-control/spacing-input-control.js +7 -0
  214. package/build-module/components/spacing-sizes-control/spacing-input-control.js.map +1 -1
  215. package/build-module/components/writing-flow/use-input.js +4 -8
  216. package/build-module/components/writing-flow/use-input.js.map +1 -1
  217. package/build-module/hooks/anchor.js +1 -1
  218. package/build-module/hooks/anchor.js.map +1 -1
  219. package/build-module/hooks/border.js +1 -2
  220. package/build-module/hooks/border.js.map +1 -1
  221. package/build-module/hooks/color.js +90 -232
  222. package/build-module/hooks/color.js.map +1 -1
  223. package/build-module/hooks/content-lock-ui.js +4 -2
  224. package/build-module/hooks/content-lock-ui.js.map +1 -1
  225. package/build-module/hooks/{color-panel.js → contrast-checker.js} +10 -44
  226. package/build-module/hooks/contrast-checker.js.map +1 -0
  227. package/build-module/hooks/dimensions.js +0 -1
  228. package/build-module/hooks/dimensions.js.map +1 -1
  229. package/build-module/hooks/duotone.js +91 -65
  230. package/build-module/hooks/duotone.js.map +1 -1
  231. package/build-module/hooks/margin.js +29 -18
  232. package/build-module/hooks/margin.js.map +1 -1
  233. package/build-module/hooks/padding.js +21 -10
  234. package/build-module/hooks/padding.js.map +1 -1
  235. package/build-module/hooks/position.js +3 -3
  236. package/build-module/hooks/position.js.map +1 -1
  237. package/build-module/hooks/style.js +23 -26
  238. package/build-module/hooks/style.js.map +1 -1
  239. package/build-module/hooks/typography.js +0 -1
  240. package/build-module/hooks/typography.js.map +1 -1
  241. package/build-module/hooks/utils.js +27 -74
  242. package/build-module/hooks/utils.js.map +1 -1
  243. package/build-module/layouts/grid.js +151 -0
  244. package/build-module/layouts/grid.js.map +1 -0
  245. package/build-module/layouts/index.js +2 -1
  246. package/build-module/layouts/index.js.map +1 -1
  247. package/build-module/layouts/utils.js +3 -2
  248. package/build-module/layouts/utils.js.map +1 -1
  249. package/build-module/private-apis.js +5 -1
  250. package/build-module/private-apis.js.map +1 -1
  251. package/build-module/store/actions.js +1 -1
  252. package/build-module/store/actions.js.map +1 -1
  253. package/build-module/utils/object.js +69 -0
  254. package/build-module/utils/object.js.map +1 -0
  255. package/build-style/style-rtl.css +77 -16
  256. package/build-style/style.css +77 -16
  257. package/package.json +31 -31
  258. package/src/components/block-draggable/content.scss +1 -1
  259. package/src/components/block-inspector/style.scss +6 -4
  260. package/src/components/block-list/block-html.js +1 -1
  261. package/src/components/block-list/block.native.js +3 -2
  262. package/src/components/block-list/index.native.js +19 -38
  263. package/src/components/block-list/use-in-between-inserter.js +4 -1
  264. package/src/components/block-popover/inbetween.js +2 -13
  265. package/src/components/block-preview/auto.js +2 -17
  266. package/src/components/block-settings-menu/block-settings-dropdown.js +2 -12
  267. package/src/components/caption/index.native.js +0 -1
  268. package/src/components/colors-gradients/style.scss +8 -8
  269. package/src/components/date-format-picker/index.js +1 -1
  270. package/src/components/editor-styles/index.js +29 -1
  271. package/src/components/global-styles/README.md +129 -16
  272. package/src/components/global-styles/border-panel.js +13 -32
  273. package/src/components/global-styles/color-panel.js +706 -0
  274. package/src/components/global-styles/dimensions-panel.js +43 -55
  275. package/src/components/global-styles/effects-panel.js +228 -0
  276. package/src/components/global-styles/filters-panel.js +157 -0
  277. package/src/components/global-styles/get-block-css-selector.js +118 -0
  278. package/src/components/global-styles/hooks.js +90 -0
  279. package/src/components/global-styles/index.js +4 -1
  280. package/src/components/global-styles/style.scss +42 -0
  281. package/src/components/global-styles/test/use-global-styles-output.js +34 -5
  282. package/src/components/global-styles/typography-panel.js +26 -51
  283. package/src/components/global-styles/use-global-styles-output.js +188 -89
  284. package/src/components/global-styles/utils.js +3 -0
  285. package/src/components/iframe/index.js +1 -1
  286. package/src/components/image-size-control/index.js +4 -3
  287. package/src/components/image-size-control/test/index.js +2 -2
  288. package/src/components/image-size-control/use-dimension-handler.js +4 -3
  289. package/src/components/index.js +4 -1
  290. package/src/components/inner-blocks/README.md +1 -1
  291. package/src/components/inserter/block-patterns-tab.js +3 -1
  292. package/src/components/inspector-controls-tabs/position-controls-panel.js +40 -9
  293. package/src/components/inspector-controls-tabs/utils.js +4 -3
  294. package/src/components/line-height-control/index.js +10 -1
  295. package/src/components/list-view/README.md +2 -0
  296. package/src/components/list-view/appender.js +101 -0
  297. package/src/components/list-view/block.js +6 -4
  298. package/src/components/list-view/branch.js +30 -1
  299. package/src/components/list-view/index.js +60 -11
  300. package/src/components/list-view/style.scss +22 -1
  301. package/src/components/list-view/test/use-list-view-drop-zone.js +188 -0
  302. package/src/components/list-view/use-list-view-client-ids.js +5 -3
  303. package/src/components/list-view/use-list-view-drop-zone.js +9 -3
  304. package/src/components/media-replace-flow/index.js +36 -24
  305. package/src/components/media-replace-flow/style.scss +5 -2
  306. package/src/components/off-canvas-editor/block-contents.js +4 -0
  307. package/src/components/off-canvas-editor/index.js +15 -11
  308. package/src/components/resizable-box-popover/index.js +27 -0
  309. package/src/components/rich-text/format-edit.js +2 -32
  310. package/src/components/rich-text/index.js +0 -1
  311. package/src/components/rich-text/index.native.js +2 -5
  312. package/src/components/spacing-sizes-control/spacing-input-control.js +10 -0
  313. package/src/components/spacing-sizes-control/style.scss +7 -7
  314. package/src/components/writing-flow/use-input.js +4 -5
  315. package/src/hooks/anchor.js +1 -1
  316. package/src/hooks/border.js +1 -2
  317. package/src/hooks/color.js +120 -296
  318. package/src/hooks/content-lock-ui.js +6 -2
  319. package/src/hooks/{color-panel.js → contrast-checker.js} +10 -46
  320. package/src/hooks/dimensions.js +0 -1
  321. package/src/hooks/duotone.js +121 -76
  322. package/src/hooks/margin.js +31 -26
  323. package/src/hooks/padding.js +24 -18
  324. package/src/hooks/position.js +3 -3
  325. package/src/hooks/style.js +29 -28
  326. package/src/hooks/test/utils.js +0 -104
  327. package/src/hooks/typography.js +0 -1
  328. package/src/hooks/utils.js +31 -74
  329. package/src/layouts/grid.js +172 -0
  330. package/src/layouts/index.js +2 -1
  331. package/src/layouts/test/grid.js +21 -0
  332. package/src/layouts/utils.js +2 -2
  333. package/src/private-apis.js +4 -0
  334. package/src/store/actions.js +1 -1
  335. package/src/style.scss +1 -0
  336. package/src/utils/object.js +69 -0
  337. package/src/utils/test/object.js +145 -0
  338. package/tsconfig.tsbuildinfo +1 -1
  339. package/build/components/rich-text/use-native-props.js +0 -11
  340. package/build/components/rich-text/use-native-props.js.map +0 -1
  341. package/build/components/rich-text/use-native-props.native.js +0 -24
  342. package/build/components/rich-text/use-native-props.native.js.map +0 -1
  343. package/build/hooks/color-panel.js.map +0 -1
  344. package/build-module/components/rich-text/use-native-props.js +0 -4
  345. package/build-module/components/rich-text/use-native-props.js.map +0 -1
  346. package/build-module/components/rich-text/use-native-props.native.js +0 -15
  347. package/build-module/components/rich-text/use-native-props.native.js.map +0 -1
  348. package/build-module/hooks/color-panel.js.map +0 -1
  349. package/src/components/rich-text/use-native-props.js +0 -3
  350. package/src/components/rich-text/use-native-props.native.js +0 -17
@@ -0,0 +1,101 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useInstanceId } from '@wordpress/compose';
5
+ import { speak } from '@wordpress/a11y';
6
+ import { useSelect } from '@wordpress/data';
7
+ import { forwardRef, useState, useEffect } from '@wordpress/element';
8
+ import { __, sprintf } from '@wordpress/i18n';
9
+
10
+ /**
11
+ * Internal dependencies
12
+ */
13
+ import { store as blockEditorStore } from '../../store';
14
+ import useBlockDisplayTitle from '../block-title/use-block-display-title';
15
+ import Inserter from '../inserter';
16
+
17
+ export const Appender = forwardRef(
18
+ ( { nestingLevel, blockCount, clientId, ...props }, ref ) => {
19
+ const [ insertedBlock, setInsertedBlock ] = useState( null );
20
+
21
+ const instanceId = useInstanceId( Appender );
22
+ const { hideInserter } = useSelect(
23
+ ( select ) => {
24
+ const { getTemplateLock, __unstableGetEditorMode } =
25
+ select( blockEditorStore );
26
+
27
+ return {
28
+ hideInserter:
29
+ !! getTemplateLock( clientId ) ||
30
+ __unstableGetEditorMode() === 'zoom-out',
31
+ };
32
+ },
33
+ [ clientId ]
34
+ );
35
+
36
+ const blockTitle = useBlockDisplayTitle( {
37
+ clientId,
38
+ context: 'list-view',
39
+ } );
40
+
41
+ const insertedBlockTitle = useBlockDisplayTitle( {
42
+ clientId: insertedBlock?.clientId,
43
+ context: 'list-view',
44
+ } );
45
+
46
+ useEffect( () => {
47
+ if ( ! insertedBlockTitle?.length ) {
48
+ return;
49
+ }
50
+
51
+ speak(
52
+ sprintf(
53
+ // translators: %s: name of block being inserted (i.e. Paragraph, Image, Group etc)
54
+ __( '%s block inserted' ),
55
+ insertedBlockTitle
56
+ ),
57
+ 'assertive'
58
+ );
59
+ }, [ insertedBlockTitle ] );
60
+
61
+ if ( hideInserter ) {
62
+ return null;
63
+ }
64
+
65
+ const descriptionId = `list-view-appender__${ instanceId }`;
66
+ const description = sprintf(
67
+ /* translators: 1: The name of the block. 2: The numerical position of the block. 3: The level of nesting for the block. */
68
+ __( 'Append to %1$s block at position %2$d, Level %3$d' ),
69
+ blockTitle,
70
+ blockCount + 1,
71
+ nestingLevel
72
+ );
73
+
74
+ return (
75
+ <div className="list-view-appender">
76
+ <Inserter
77
+ ref={ ref }
78
+ rootClientId={ clientId }
79
+ position="bottom right"
80
+ isAppender
81
+ selectBlockOnInsert={ false }
82
+ shouldDirectInsert={ false }
83
+ __experimentalIsQuick
84
+ { ...props }
85
+ toggleProps={ { 'aria-describedby': descriptionId } }
86
+ onSelectOrClose={ ( maybeInsertedBlock ) => {
87
+ if ( maybeInsertedBlock?.clientId ) {
88
+ setInsertedBlock( maybeInsertedBlock );
89
+ }
90
+ } }
91
+ />
92
+ <div
93
+ className="list-view-appender__description"
94
+ id={ descriptionId }
95
+ >
96
+ { description }
97
+ </div>
98
+ </div>
99
+ );
100
+ }
101
+ );
@@ -33,7 +33,6 @@ import {
33
33
  BlockMoverDownButton,
34
34
  } from '../block-mover/button';
35
35
  import ListViewBlockContents from './block-contents';
36
- import BlockSettingsDropdown from '../block-settings-menu/block-settings-dropdown';
37
36
  import { useListViewContext } from './context';
38
37
  import { getBlockPositionDescription } from './utils';
39
38
  import { store as blockEditorStore } from '../../store';
@@ -135,7 +134,8 @@ function ListViewBlock( {
135
134
  )
136
135
  : __( 'Options' );
137
136
 
138
- const { isTreeGridMounted, expand, collapse } = useListViewContext();
137
+ const { isTreeGridMounted, expand, collapse, BlockSettingsMenu } =
138
+ useListViewContext();
139
139
 
140
140
  const hasSiblings = siblingBlockCount > 0;
141
141
  const hasRenderedMovers = showBlockMovers && hasSiblings;
@@ -248,6 +248,7 @@ function ListViewBlock( {
248
248
  path={ path }
249
249
  id={ `list-view-block-${ clientId }` }
250
250
  data-block={ clientId }
251
+ data-expanded={ canExpand ? isExpanded : undefined }
251
252
  isExpanded={ canExpand ? isExpanded : undefined }
252
253
  aria-selected={ !! isSelected || forceSelectionContentLock }
253
254
  ref={ rowRef }
@@ -321,14 +322,15 @@ function ListViewBlock( {
321
322
  </>
322
323
  ) }
323
324
 
324
- { showBlockActions && (
325
+ { showBlockActions && BlockSettingsMenu && (
325
326
  <TreeGridCell
326
327
  className={ listViewBlockSettingsClassName }
327
328
  aria-selected={ !! isSelected || forceSelectionContentLock }
328
329
  >
329
330
  { ( { ref, tabIndex, onFocus } ) => (
330
- <BlockSettingsDropdown
331
+ <BlockSettingsMenu
331
332
  clientIds={ dropdownClientIds }
333
+ block={ block }
332
334
  icon={ moreVertical }
333
335
  label={ settingsAriaLabel }
334
336
  toggleProps={ {
@@ -1,12 +1,17 @@
1
1
  /**
2
2
  * WordPress dependencies
3
3
  */
4
+ import {
5
+ __experimentalTreeGridRow as TreeGridRow,
6
+ __experimentalTreeGridCell as TreeGridCell,
7
+ } from '@wordpress/components';
4
8
  import { memo } from '@wordpress/element';
5
9
  import { AsyncModeProvider, useSelect } from '@wordpress/data';
6
10
 
7
11
  /**
8
12
  * Internal dependencies
9
13
  */
14
+ import { Appender } from './appender';
10
15
  import ListViewBlock from './block';
11
16
  import { useListViewContext } from './context';
12
17
  import { isClientIdSelected } from './utils';
@@ -93,6 +98,7 @@ function ListViewBranch( props ) {
93
98
  parentId,
94
99
  shouldShowInnerBlocks = true,
95
100
  isSyncedBranch = false,
101
+ showAppender: showAppenderProp = true,
96
102
  } = props;
97
103
 
98
104
  const parentBlockInformation = useBlockDisplayInformation( parentId );
@@ -120,8 +126,12 @@ function ListViewBranch( props ) {
120
126
  return null;
121
127
  }
122
128
 
129
+ // Only show the appender at the first level.
130
+ const showAppender = showAppenderProp && level === 1;
123
131
  const filteredBlocks = blocks.filter( Boolean );
124
132
  const blockCount = filteredBlocks.length;
133
+ // The appender means an extra row in List View, so add 1 to the row count.
134
+ const rowCount = showAppender ? blockCount + 1 : blockCount;
125
135
  let nextPosition = listPosition;
126
136
 
127
137
  return (
@@ -175,7 +185,7 @@ function ListViewBranch( props ) {
175
185
  isDragged={ isDragged }
176
186
  level={ level }
177
187
  position={ position }
178
- rowCount={ blockCount }
188
+ rowCount={ rowCount }
179
189
  siblingBlockCount={ blockCount }
180
190
  showBlockMovers={ showBlockMovers }
181
191
  path={ updatedPath }
@@ -209,6 +219,25 @@ function ListViewBranch( props ) {
209
219
  </AsyncModeProvider>
210
220
  );
211
221
  } ) }
222
+ { showAppender && (
223
+ <TreeGridRow
224
+ level={ level }
225
+ setSize={ rowCount }
226
+ positionInSet={ rowCount }
227
+ isExpanded={ true }
228
+ >
229
+ <TreeGridCell>
230
+ { ( treeGridCellProps ) => (
231
+ <Appender
232
+ clientId={ parentId }
233
+ nestingLevel={ level }
234
+ blockCount={ blockCount }
235
+ { ...treeGridCellProps }
236
+ />
237
+ ) }
238
+ </TreeGridCell>
239
+ </TreeGridRow>
240
+ ) }
212
241
  </>
213
242
  );
214
243
  }
@@ -7,6 +7,7 @@ import {
7
7
  } from '@wordpress/compose';
8
8
  import { __experimentalTreeGrid as TreeGrid } from '@wordpress/components';
9
9
  import { AsyncModeProvider, useSelect } from '@wordpress/data';
10
+ import deprecated from '@wordpress/deprecated';
10
11
  import {
11
12
  useCallback,
12
13
  useEffect,
@@ -28,6 +29,7 @@ import useListViewClientIds from './use-list-view-client-ids';
28
29
  import useListViewDropZone from './use-list-view-drop-zone';
29
30
  import useListViewExpandSelectedItem from './use-list-view-expand-selected-item';
30
31
  import { store as blockEditorStore } from '../../store';
32
+ import { BlockSettingsDropdown } from '../block-settings-menu/block-settings-dropdown';
31
33
 
32
34
  const expanded = ( state, action ) => {
33
35
  if ( Array.isArray( action.clientIds ) ) {
@@ -47,22 +49,47 @@ const expanded = ( state, action ) => {
47
49
 
48
50
  export const BLOCK_LIST_ITEM_HEIGHT = 36;
49
51
 
52
+ /** @typedef {import('react').ComponentType} ComponentType */
53
+ /** @typedef {import('react').Ref<HTMLElement>} Ref */
54
+
50
55
  /**
51
56
  * Show a hierarchical list of blocks.
52
57
  *
53
- * @param {Object} props Components props.
54
- * @param {string} props.id An HTML element id for the root element of ListView.
55
- * @param {Array} props.blocks Custom subset of block client IDs to be used instead of the default hierarchy.
56
- * @param {boolean} props.showBlockMovers Flag to enable block movers
57
- * @param {boolean} props.isExpanded Flag to determine whether nested levels are expanded by default.
58
- * @param {Object} ref Forwarded ref
58
+ * @param {Object} props Components props.
59
+ * @param {string} props.id An HTML element id for the root element of ListView.
60
+ * @param {Array} props.blocks _deprecated_ Custom subset of block client IDs to be used instead of the default hierarchy.
61
+ * @param {?boolean} props.showBlockMovers Flag to enable block movers. Defaults to `false`.
62
+ * @param {?boolean} props.isExpanded Flag to determine whether nested levels are expanded by default. Defaults to `false`.
63
+ * @param {?boolean} props.showAppender Flag to show or hide the block appender. Defaults to `false`.
64
+ * @param {?ComponentType} props.blockSettingsMenu Optional more menu substitution. Defaults to the standard `BlockSettingsDropdown` component.
65
+ * @param {string} props.rootClientId The client id of the root block from which we determine the blocks to show in the list.
66
+ * @param {Ref} ref Forwarded ref
59
67
  */
60
- function ListView(
61
- { id, blocks, showBlockMovers = false, isExpanded = false },
68
+ function ListViewComponent(
69
+ {
70
+ id,
71
+ blocks,
72
+ showBlockMovers = false,
73
+ isExpanded = false,
74
+ showAppender = false,
75
+ blockSettingsMenu: BlockSettingsMenu = BlockSettingsDropdown,
76
+ rootClientId,
77
+ },
62
78
  ref
63
79
  ) {
80
+ // This can be removed once we no longer need to support the blocks prop.
81
+ if ( blocks ) {
82
+ deprecated(
83
+ '`blocks` property in `wp.blockEditor.__experimentalListView`',
84
+ {
85
+ since: '6.3',
86
+ alternative: '`rootClientId` property',
87
+ }
88
+ );
89
+ }
90
+
64
91
  const { clientIdsTree, draggedClientIds, selectedClientIds } =
65
- useListViewClientIds( blocks );
92
+ useListViewClientIds( { blocks, rootClientId } );
66
93
 
67
94
  const { visibleBlockCount, shouldShowInnerBlocks } = useSelect(
68
95
  ( select ) => {
@@ -170,8 +197,16 @@ function ListView(
170
197
  expandedState,
171
198
  expand,
172
199
  collapse,
200
+ BlockSettingsMenu,
173
201
  } ),
174
- [ isMounted.current, draggedClientIds, expandedState, expand, collapse ]
202
+ [
203
+ isMounted.current,
204
+ draggedClientIds,
205
+ expandedState,
206
+ expand,
207
+ collapse,
208
+ BlockSettingsMenu,
209
+ ]
175
210
  );
176
211
 
177
212
  // If there are no blocks to show, do not render the list view.
@@ -198,16 +233,30 @@ function ListView(
198
233
  <ListViewContext.Provider value={ contextValue }>
199
234
  <ListViewBranch
200
235
  blocks={ clientIdsTree }
236
+ parentId={ rootClientId }
201
237
  selectBlock={ selectEditorBlock }
202
238
  showBlockMovers={ showBlockMovers }
203
239
  fixedListWindow={ fixedListWindow }
204
240
  selectedClientIds={ selectedClientIds }
205
241
  isExpanded={ isExpanded }
206
242
  shouldShowInnerBlocks={ shouldShowInnerBlocks }
243
+ showAppender={ showAppender }
207
244
  />
208
245
  </ListViewContext.Provider>
209
246
  </TreeGrid>
210
247
  </AsyncModeProvider>
211
248
  );
212
249
  }
213
- export default forwardRef( ListView );
250
+ export const PrivateListView = forwardRef( ListViewComponent );
251
+
252
+ export default forwardRef( ( props, ref ) => {
253
+ return (
254
+ <PrivateListView
255
+ ref={ ref }
256
+ { ...props }
257
+ showAppender={ false }
258
+ blockSettingsMenu={ BlockSettingsDropdown }
259
+ rootClientId={ null }
260
+ />
261
+ );
262
+ } );
@@ -400,7 +400,9 @@ $block-navigation-max-indent: 8;
400
400
 
401
401
  .block-editor-list-view-drop-indicator__line {
402
402
  background: var(--wp-admin-theme-color);
403
- height: $border-width;
403
+ height: 6px;
404
+ border: 1px solid $white;
405
+ border-radius: 4px;
404
406
  }
405
407
  }
406
408
 
@@ -410,3 +412,22 @@ $block-navigation-max-indent: 8;
410
412
  height: 36px;
411
413
  }
412
414
 
415
+ .list-view-appender .block-editor-inserter__toggle {
416
+ background-color: #1e1e1e;
417
+ color: #fff;
418
+ margin: $grid-unit-10 0 0 24px;
419
+ border-radius: 2px;
420
+ height: 24px;
421
+ min-width: 24px;
422
+ padding: 0;
423
+
424
+ &:hover,
425
+ &:focus {
426
+ background: var(--wp-admin-theme-color);
427
+ color: #fff;
428
+ }
429
+ }
430
+
431
+ .list-view-appender__description {
432
+ display: none;
433
+ }
@@ -0,0 +1,188 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import { getListViewDropTarget } from '../use-list-view-drop-zone';
5
+
6
+ describe( 'getListViewDropTarget', () => {
7
+ const blocksData = [
8
+ {
9
+ blockIndex: 0,
10
+ canInsertDraggedBlocksAsChild: true,
11
+ canInsertDraggedBlocksAsSibling: true,
12
+ clientId: 'block-1',
13
+ element: {
14
+ getBoundingClientRect: () => ( {
15
+ top: 50,
16
+ bottom: 100,
17
+ left: 10,
18
+ right: 100,
19
+ x: 10,
20
+ y: 50,
21
+ width: 90,
22
+ height: 50,
23
+ } ),
24
+ },
25
+ innerBlockCount: 1,
26
+ isDraggedBlock: false,
27
+ isExpanded: true,
28
+ rootClientId: '',
29
+ },
30
+ {
31
+ blockIndex: 0,
32
+ canInsertDraggedBlocksAsChild: true,
33
+ canInsertDraggedBlocksAsSibling: true,
34
+ clientId: 'block-2',
35
+ element: {
36
+ getBoundingClientRect: () => ( {
37
+ top: 100,
38
+ bottom: 150,
39
+ left: 10,
40
+ right: 100,
41
+ x: 10,
42
+ y: 100,
43
+ width: 90,
44
+ height: 50,
45
+ } ),
46
+ },
47
+ innerBlockCount: 0,
48
+ isDraggedBlock: false,
49
+ isExpanded: false,
50
+ rootClientId: 'block-1',
51
+ },
52
+ {
53
+ blockIndex: 1,
54
+ canInsertDraggedBlocksAsChild: true,
55
+ canInsertDraggedBlocksAsSibling: true,
56
+ clientId: 'block-3',
57
+ element: {
58
+ getBoundingClientRect: () => ( {
59
+ top: 150,
60
+ bottom: 150,
61
+ left: 10,
62
+ right: 100,
63
+ x: 10,
64
+ y: 150,
65
+ width: 90,
66
+ height: 50,
67
+ } ),
68
+ },
69
+ innerBlockCount: 0,
70
+ isDraggedBlock: false,
71
+ isExpanded: false,
72
+ rootClientId: '',
73
+ },
74
+ ];
75
+
76
+ it( 'should return the correct target when dragging a block over the top half of the first block', () => {
77
+ const position = { x: 50, y: 70 };
78
+ const target = getListViewDropTarget( blocksData, position );
79
+
80
+ expect( target ).toEqual( {
81
+ blockIndex: 0,
82
+ clientId: 'block-1',
83
+ dropPosition: 'top',
84
+ rootClientId: '',
85
+ } );
86
+ } );
87
+
88
+ it( 'should nest when dragging a block over the bottom half of an expanded block', () => {
89
+ const position = { x: 50, y: 90 };
90
+ const target = getListViewDropTarget( blocksData, position );
91
+
92
+ expect( target ).toEqual( {
93
+ blockIndex: 0,
94
+ dropPosition: 'inside',
95
+ rootClientId: 'block-1',
96
+ } );
97
+ } );
98
+
99
+ it( 'should nest when dragging a block over the right side and bottom half of a collapsed block with children', () => {
100
+ const position = { x: 70, y: 90 };
101
+
102
+ const collapsedBlockData = [ ...blocksData ];
103
+
104
+ // Set the first block to be collapsed.
105
+ collapsedBlockData[ 0 ] = {
106
+ ...collapsedBlockData[ 0 ],
107
+ isExpanded: false,
108
+ };
109
+
110
+ // Hide the first block's children.
111
+ collapsedBlockData.splice( 1, 1 );
112
+
113
+ const target = getListViewDropTarget( collapsedBlockData, position );
114
+
115
+ expect( target ).toEqual( {
116
+ blockIndex: 0,
117
+ dropPosition: 'inside',
118
+ rootClientId: 'block-1',
119
+ } );
120
+ } );
121
+
122
+ it( 'should drag below when dragging a block over the left side and bottom half of a collapsed block with children', () => {
123
+ const position = { x: 30, y: 90 };
124
+
125
+ const collapsedBlockData = [ ...blocksData ];
126
+
127
+ // Set the first block to be collapsed.
128
+ collapsedBlockData[ 0 ] = {
129
+ ...collapsedBlockData[ 0 ],
130
+ isExpanded: false,
131
+ };
132
+
133
+ // Hide the first block's children.
134
+ collapsedBlockData.splice( 1, 1 );
135
+
136
+ const target = getListViewDropTarget( collapsedBlockData, position );
137
+
138
+ expect( target ).toEqual( {
139
+ blockIndex: 1,
140
+ clientId: 'block-1',
141
+ dropPosition: 'bottom',
142
+ rootClientId: '',
143
+ } );
144
+ } );
145
+
146
+ it( 'should drag below when attempting to nest but the dragged block is not allowed as a child', () => {
147
+ const position = { x: 70, y: 90 };
148
+
149
+ const childNotAllowedBlockData = [ ...blocksData ];
150
+
151
+ // Set the first block to not be allowed as a child.
152
+ childNotAllowedBlockData[ 0 ] = {
153
+ ...childNotAllowedBlockData[ 0 ],
154
+ canInsertDraggedBlocksAsChild: false,
155
+ };
156
+
157
+ const target = getListViewDropTarget(
158
+ childNotAllowedBlockData,
159
+ position
160
+ );
161
+
162
+ expect( target ).toEqual( {
163
+ blockIndex: 1,
164
+ clientId: 'block-1',
165
+ dropPosition: 'bottom',
166
+ rootClientId: '',
167
+ } );
168
+ } );
169
+
170
+ it( 'should return undefined when the dragged block cannot be inserted as a sibling', () => {
171
+ const position = { x: 50, y: 70 };
172
+
173
+ const siblingNotAllowedBlockData = [ ...blocksData ];
174
+
175
+ // Set the first block to not be allowed as a sibling.
176
+ siblingNotAllowedBlockData[ 0 ] = {
177
+ ...siblingNotAllowedBlockData[ 0 ],
178
+ canInsertDraggedBlocksAsSibling: false,
179
+ };
180
+
181
+ const target = getListViewDropTarget(
182
+ siblingNotAllowedBlockData,
183
+ position
184
+ );
185
+
186
+ expect( target ).toBeUndefined();
187
+ } );
188
+ } );
@@ -9,7 +9,7 @@ import { useSelect } from '@wordpress/data';
9
9
  */
10
10
  import { store as blockEditorStore } from '../../store';
11
11
 
12
- export default function useListViewClientIds( blocks ) {
12
+ export default function useListViewClientIds( { blocks, rootClientId } ) {
13
13
  return useSelect(
14
14
  ( select ) => {
15
15
  const {
@@ -21,9 +21,11 @@ export default function useListViewClientIds( blocks ) {
21
21
  return {
22
22
  selectedClientIds: getSelectedBlockClientIds(),
23
23
  draggedClientIds: getDraggedBlockClientIds(),
24
- clientIdsTree: blocks ? blocks : __unstableGetClientIdsTree(),
24
+ clientIdsTree: blocks
25
+ ? blocks
26
+ : __unstableGetClientIdsTree( rootClientId ),
25
27
  };
26
28
  },
27
- [ blocks ]
29
+ [ blocks, rootClientId ]
28
30
  );
29
31
  }
@@ -36,6 +36,7 @@ import { store as blockEditorStore } from '../../store';
36
36
  * @property {Element} element The DOM element representing the block.
37
37
  * @property {number} innerBlockCount The number of inner blocks the block has.
38
38
  * @property {boolean} isDraggedBlock Whether the block is currently being dragged.
39
+ * @property {boolean} isExpanded Whether the block is expanded in the UI.
39
40
  * @property {boolean} canInsertDraggedBlocksAsSibling Whether the dragged block can be a sibling of this block.
40
41
  * @property {boolean} canInsertDraggedBlocksAsChild Whether the dragged block can be a child of this block.
41
42
  */
@@ -78,7 +79,7 @@ const ALLOWED_DROP_EDGES = [ 'top', 'bottom' ];
78
79
  *
79
80
  * @return {WPListViewDropZoneTarget | undefined} An object containing data about the drop target.
80
81
  */
81
- function getListViewDropTarget( blocksData, position ) {
82
+ export function getListViewDropTarget( blocksData, position ) {
82
83
  let candidateEdge;
83
84
  let candidateBlockData;
84
85
  let candidateDistance;
@@ -146,12 +147,15 @@ function getListViewDropTarget( blocksData, position ) {
146
147
 
147
148
  // If the user is dragging towards the bottom of the block check whether
148
149
  // they might be trying to nest the block as a child.
149
- // If the block already has inner blocks, this should always be treated
150
+ // If the block already has inner blocks, and is expanded, this should be treated
150
151
  // as nesting since the next block in the tree will be the first child.
152
+ // However, if the block is collapsed, dragging beneath the block should
153
+ // still be allowed, as the next visible block in the tree will be a sibling.
151
154
  if (
152
155
  isDraggingBelow &&
153
156
  candidateBlockData.canInsertDraggedBlocksAsChild &&
154
- ( candidateBlockData.innerBlockCount > 0 ||
157
+ ( ( candidateBlockData.innerBlockCount > 0 &&
158
+ candidateBlockData.isExpanded ) ||
155
159
  isNestingGesture( position, candidateRect ) )
156
160
  ) {
157
161
  return {
@@ -208,10 +212,12 @@ export default function useListViewDropZone() {
208
212
 
209
213
  const blocksData = blockElements.map( ( blockElement ) => {
210
214
  const clientId = blockElement.dataset.block;
215
+ const isExpanded = blockElement.dataset.expanded === 'true';
211
216
  const rootClientId = getBlockRootClientId( clientId );
212
217
 
213
218
  return {
214
219
  clientId,
220
+ isExpanded,
215
221
  rootClientId,
216
222
  blockIndex: getBlockIndex( clientId ),
217
223
  element: blockElement,