@wordpress/block-editor 10.4.0 → 10.5.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 (254) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +0 -1
  3. package/build/components/block-lock/menu-item.js +1 -1
  4. package/build/components/block-lock/menu-item.js.map +1 -1
  5. package/build/components/block-lock/modal.js +16 -9
  6. package/build/components/block-lock/modal.js.map +1 -1
  7. package/build/components/block-styles/utils.js +3 -3
  8. package/build/components/block-styles/utils.js.map +1 -1
  9. package/build/components/block-switcher/index.js +19 -4
  10. package/build/components/block-switcher/index.js.map +1 -1
  11. package/build/components/block-tools/selected-block-popover.js +27 -4
  12. package/build/components/block-tools/selected-block-popover.js.map +1 -1
  13. package/build/components/colors/with-colors.js +4 -3
  14. package/build/components/colors/with-colors.js.map +1 -1
  15. package/build/components/font-sizes/fluid-utils.js +24 -40
  16. package/build/components/font-sizes/fluid-utils.js.map +1 -1
  17. package/build/components/font-sizes/with-font-sizes.js +7 -5
  18. package/build/components/font-sizes/with-font-sizes.js.map +1 -1
  19. package/build/components/index.js +9 -0
  20. package/build/components/index.js.map +1 -1
  21. package/build/components/inner-blocks/index.js +5 -3
  22. package/build/components/inner-blocks/index.js.map +1 -1
  23. package/build/components/inserter/reusable-blocks-tab.js +4 -1
  24. package/build/components/inserter/reusable-blocks-tab.js.map +1 -1
  25. package/build/components/link-control/index.js +18 -34
  26. package/build/components/link-control/index.js.map +1 -1
  27. package/build/components/link-control/search-input.js +1 -1
  28. package/build/components/link-control/search-input.js.map +1 -1
  29. package/build/components/link-control/use-internal-input-value.js +26 -0
  30. package/build/components/link-control/use-internal-input-value.js.map +1 -0
  31. package/build/components/list-view/block.js +5 -3
  32. package/build/components/list-view/block.js.map +1 -1
  33. package/build/components/list-view/branch.js +9 -3
  34. package/build/components/list-view/branch.js.map +1 -1
  35. package/build/components/off-canvas-editor/block-contents.js +100 -0
  36. package/build/components/off-canvas-editor/block-contents.js.map +1 -0
  37. package/build/components/off-canvas-editor/block-select-button.js +119 -0
  38. package/build/components/off-canvas-editor/block-select-button.js.map +1 -0
  39. package/build/components/off-canvas-editor/block.js +292 -0
  40. package/build/components/off-canvas-editor/block.js.map +1 -0
  41. package/build/components/off-canvas-editor/branch.js +181 -0
  42. package/build/components/off-canvas-editor/branch.js.map +1 -0
  43. package/build/components/off-canvas-editor/context.js +19 -0
  44. package/build/components/off-canvas-editor/context.js.map +1 -0
  45. package/build/components/off-canvas-editor/drop-indicator.js +118 -0
  46. package/build/components/off-canvas-editor/drop-indicator.js.map +1 -0
  47. package/build/components/off-canvas-editor/expander.js +41 -0
  48. package/build/components/off-canvas-editor/expander.js.map +1 -0
  49. package/build/components/off-canvas-editor/index.js +204 -0
  50. package/build/components/off-canvas-editor/index.js.map +1 -0
  51. package/build/components/off-canvas-editor/leaf.js +60 -0
  52. package/build/components/off-canvas-editor/leaf.js.map +1 -0
  53. package/build/components/off-canvas-editor/use-block-selection.js +139 -0
  54. package/build/components/off-canvas-editor/use-block-selection.js.map +1 -0
  55. package/build/components/off-canvas-editor/use-list-view-client-ids.js +33 -0
  56. package/build/components/off-canvas-editor/use-list-view-client-ids.js.map +1 -0
  57. package/build/components/off-canvas-editor/use-list-view-drop-zone.js +235 -0
  58. package/build/components/off-canvas-editor/use-list-view-drop-zone.js.map +1 -0
  59. package/build/components/off-canvas-editor/use-list-view-expand-selected-item.js +60 -0
  60. package/build/components/off-canvas-editor/use-list-view-expand-selected-item.js.map +1 -0
  61. package/build/components/off-canvas-editor/utils.js +60 -0
  62. package/build/components/off-canvas-editor/utils.js.map +1 -0
  63. package/build/components/url-popover/index.js +31 -2
  64. package/build/components/url-popover/index.js.map +1 -1
  65. package/build/components/use-setting/index.js +1 -1
  66. package/build/components/use-setting/index.js.map +1 -1
  67. package/build/hooks/color-panel.js +17 -1
  68. package/build/hooks/color-panel.js.map +1 -1
  69. package/build/hooks/color.js +1 -1
  70. package/build/hooks/color.js.map +1 -1
  71. package/build/hooks/content-lock-ui.js +13 -6
  72. package/build/hooks/content-lock-ui.js.map +1 -1
  73. package/build/hooks/dimensions.js +44 -13
  74. package/build/hooks/dimensions.js.map +1 -1
  75. package/build/hooks/layout.js +2 -2
  76. package/build/hooks/layout.js.map +1 -1
  77. package/build/hooks/margin.js +4 -2
  78. package/build/hooks/margin.js.map +1 -1
  79. package/build/hooks/min-height.js +145 -0
  80. package/build/hooks/min-height.js.map +1 -0
  81. package/build/hooks/padding.js +4 -2
  82. package/build/hooks/padding.js.map +1 -1
  83. package/build/hooks/style.js +3 -2
  84. package/build/hooks/style.js.map +1 -1
  85. package/build/layouts/flex.js +22 -21
  86. package/build/layouts/flex.js.map +1 -1
  87. package/build/store/actions.js +26 -0
  88. package/build/store/actions.js.map +1 -1
  89. package/build/store/reducer.js +46 -14
  90. package/build/store/reducer.js.map +1 -1
  91. package/build/store/selectors.js +16 -2
  92. package/build/store/selectors.js.map +1 -1
  93. package/build-module/components/block-lock/menu-item.js +2 -2
  94. package/build-module/components/block-lock/menu-item.js.map +1 -1
  95. package/build-module/components/block-lock/modal.js +17 -10
  96. package/build-module/components/block-lock/modal.js.map +1 -1
  97. package/build-module/components/block-styles/utils.js +3 -3
  98. package/build-module/components/block-styles/utils.js.map +1 -1
  99. package/build-module/components/block-switcher/index.js +19 -4
  100. package/build-module/components/block-switcher/index.js.map +1 -1
  101. package/build-module/components/block-tools/selected-block-popover.js +27 -5
  102. package/build-module/components/block-tools/selected-block-popover.js.map +1 -1
  103. package/build-module/components/colors/with-colors.js +5 -4
  104. package/build-module/components/colors/with-colors.js.map +1 -1
  105. package/build-module/components/font-sizes/fluid-utils.js +24 -40
  106. package/build-module/components/font-sizes/fluid-utils.js.map +1 -1
  107. package/build-module/components/font-sizes/with-font-sizes.js +8 -6
  108. package/build-module/components/font-sizes/with-font-sizes.js.map +1 -1
  109. package/build-module/components/index.js +1 -0
  110. package/build-module/components/index.js.map +1 -1
  111. package/build-module/components/inner-blocks/index.js +5 -3
  112. package/build-module/components/inner-blocks/index.js.map +1 -1
  113. package/build-module/components/inserter/reusable-blocks-tab.js +3 -1
  114. package/build-module/components/inserter/reusable-blocks-tab.js.map +1 -1
  115. package/build-module/components/link-control/index.js +17 -34
  116. package/build-module/components/link-control/index.js.map +1 -1
  117. package/build-module/components/link-control/search-input.js +1 -1
  118. package/build-module/components/link-control/search-input.js.map +1 -1
  119. package/build-module/components/link-control/use-internal-input-value.js +18 -0
  120. package/build-module/components/link-control/use-internal-input-value.js.map +1 -0
  121. package/build-module/components/list-view/block.js +5 -3
  122. package/build-module/components/list-view/block.js.map +1 -1
  123. package/build-module/components/list-view/branch.js +9 -3
  124. package/build-module/components/list-view/branch.js.map +1 -1
  125. package/build-module/components/off-canvas-editor/block-contents.js +85 -0
  126. package/build-module/components/off-canvas-editor/block-contents.js.map +1 -0
  127. package/build-module/components/off-canvas-editor/block-select-button.js +101 -0
  128. package/build-module/components/off-canvas-editor/block-select-button.js.map +1 -0
  129. package/build-module/components/off-canvas-editor/block.js +268 -0
  130. package/build-module/components/off-canvas-editor/block.js.map +1 -0
  131. package/build-module/components/off-canvas-editor/branch.js +165 -0
  132. package/build-module/components/off-canvas-editor/branch.js.map +1 -0
  133. package/build-module/components/off-canvas-editor/context.js +7 -0
  134. package/build-module/components/off-canvas-editor/context.js.map +1 -0
  135. package/build-module/components/off-canvas-editor/drop-indicator.js +111 -0
  136. package/build-module/components/off-canvas-editor/drop-indicator.js.map +1 -0
  137. package/build-module/components/off-canvas-editor/expander.js +32 -0
  138. package/build-module/components/off-canvas-editor/expander.js.map +1 -0
  139. package/build-module/components/off-canvas-editor/index.js +181 -0
  140. package/build-module/components/off-canvas-editor/index.js.map +1 -0
  141. package/build-module/components/off-canvas-editor/leaf.js +45 -0
  142. package/build-module/components/off-canvas-editor/leaf.js.map +1 -0
  143. package/build-module/components/off-canvas-editor/use-block-selection.js +124 -0
  144. package/build-module/components/off-canvas-editor/use-block-selection.js.map +1 -0
  145. package/build-module/components/off-canvas-editor/use-list-view-client-ids.js +24 -0
  146. package/build-module/components/off-canvas-editor/use-list-view-client-ids.js.map +1 -0
  147. package/build-module/components/off-canvas-editor/use-list-view-drop-zone.js +220 -0
  148. package/build-module/components/off-canvas-editor/use-list-view-drop-zone.js.map +1 -0
  149. package/build-module/components/off-canvas-editor/use-list-view-expand-selected-item.js +50 -0
  150. package/build-module/components/off-canvas-editor/use-list-view-expand-selected-item.js.map +1 -0
  151. package/build-module/components/off-canvas-editor/utils.js +44 -0
  152. package/build-module/components/off-canvas-editor/utils.js.map +1 -0
  153. package/build-module/components/url-popover/index.js +30 -3
  154. package/build-module/components/url-popover/index.js.map +1 -1
  155. package/build-module/components/use-setting/index.js +1 -1
  156. package/build-module/components/use-setting/index.js.map +1 -1
  157. package/build-module/hooks/color-panel.js +17 -1
  158. package/build-module/hooks/color-panel.js.map +1 -1
  159. package/build-module/hooks/color.js +1 -1
  160. package/build-module/hooks/color.js.map +1 -1
  161. package/build-module/hooks/content-lock-ui.js +15 -8
  162. package/build-module/hooks/content-lock-ui.js.map +1 -1
  163. package/build-module/hooks/dimensions.js +39 -12
  164. package/build-module/hooks/dimensions.js.map +1 -1
  165. package/build-module/hooks/layout.js +2 -2
  166. package/build-module/hooks/layout.js.map +1 -1
  167. package/build-module/hooks/margin.js +4 -2
  168. package/build-module/hooks/margin.js.map +1 -1
  169. package/build-module/hooks/min-height.js +122 -0
  170. package/build-module/hooks/min-height.js.map +1 -0
  171. package/build-module/hooks/padding.js +4 -2
  172. package/build-module/hooks/padding.js.map +1 -1
  173. package/build-module/hooks/style.js +4 -3
  174. package/build-module/hooks/style.js.map +1 -1
  175. package/build-module/layouts/flex.js +23 -22
  176. package/build-module/layouts/flex.js.map +1 -1
  177. package/build-module/store/actions.js +22 -0
  178. package/build-module/store/actions.js.map +1 -1
  179. package/build-module/store/reducer.js +44 -14
  180. package/build-module/store/reducer.js.map +1 -1
  181. package/build-module/store/selectors.js +13 -2
  182. package/build-module/store/selectors.js.map +1 -1
  183. package/build-style/style-rtl.css +39 -26
  184. package/build-style/style.css +39 -26
  185. package/package.json +28 -28
  186. package/src/components/alignment-control/README.md +1 -1
  187. package/src/components/block-alignment-control/test/index.native.js +4 -4
  188. package/src/components/block-draggable/test/helpers.native.js +3 -3
  189. package/src/components/block-draggable/test/index.native.js +27 -27
  190. package/src/components/block-list/style.scss +10 -5
  191. package/src/components/block-lock/menu-item.js +5 -2
  192. package/src/components/block-lock/modal.js +19 -36
  193. package/src/components/block-lock/style.scss +8 -17
  194. package/src/components/block-mover/style.scss +0 -1
  195. package/src/components/block-popover/style.scss +1 -1
  196. package/src/components/block-styles/utils.js +3 -3
  197. package/src/components/block-switcher/index.js +19 -4
  198. package/src/components/block-tools/selected-block-popover.js +80 -34
  199. package/src/components/block-tools/style.scss +15 -0
  200. package/src/components/colors/with-colors.js +13 -23
  201. package/src/components/default-block-appender/style.scss +1 -0
  202. package/src/components/font-sizes/fluid-utils.js +37 -64
  203. package/src/components/font-sizes/test/fluid-utils.js +5 -5
  204. package/src/components/font-sizes/with-font-sizes.js +14 -11
  205. package/src/components/index.js +1 -0
  206. package/src/components/inner-blocks/index.js +7 -4
  207. package/src/components/inserter/reusable-blocks-tab.js +4 -2
  208. package/src/components/inserter/style.scss +8 -7
  209. package/src/components/inserter/test/reusable-blocks-tab.js +14 -57
  210. package/src/components/link-control/index.js +23 -39
  211. package/src/components/link-control/search-input.js +1 -1
  212. package/src/components/link-control/test/index.js +272 -241
  213. package/src/components/link-control/use-internal-input-value.js +22 -0
  214. package/src/components/list-view/block.js +4 -3
  215. package/src/components/list-view/branch.js +11 -6
  216. package/src/components/off-canvas-editor/README.md +5 -0
  217. package/src/components/off-canvas-editor/block-contents.js +89 -0
  218. package/src/components/off-canvas-editor/block-select-button.js +113 -0
  219. package/src/components/off-canvas-editor/block.js +335 -0
  220. package/src/components/off-canvas-editor/branch.js +210 -0
  221. package/src/components/off-canvas-editor/context.js +8 -0
  222. package/src/components/off-canvas-editor/drop-indicator.js +126 -0
  223. package/src/components/off-canvas-editor/expander.js +26 -0
  224. package/src/components/off-canvas-editor/index.js +216 -0
  225. package/src/components/off-canvas-editor/leaf.js +48 -0
  226. package/src/components/off-canvas-editor/style.scss +397 -0
  227. package/src/components/off-canvas-editor/test/utils.js +50 -0
  228. package/src/components/off-canvas-editor/use-block-selection.js +169 -0
  229. package/src/components/off-canvas-editor/use-list-view-client-ids.js +29 -0
  230. package/src/components/off-canvas-editor/use-list-view-drop-zone.js +260 -0
  231. package/src/components/off-canvas-editor/use-list-view-expand-selected-item.js +58 -0
  232. package/src/components/off-canvas-editor/utils.js +58 -0
  233. package/src/components/responsive-block-control/test/index.js +69 -92
  234. package/src/components/url-popover/README.md +12 -3
  235. package/src/components/url-popover/index.js +33 -3
  236. package/src/components/use-setting/index.js +7 -1
  237. package/src/hooks/color-panel.js +13 -1
  238. package/src/hooks/color.js +2 -0
  239. package/src/hooks/content-lock-ui.js +46 -34
  240. package/src/hooks/dimensions.js +76 -16
  241. package/src/hooks/layout.js +2 -3
  242. package/src/hooks/margin.js +4 -3
  243. package/src/hooks/min-height.js +121 -0
  244. package/src/hooks/padding.js +4 -3
  245. package/src/hooks/style.js +10 -2
  246. package/src/hooks/test/style.js +4 -0
  247. package/src/hooks/test/use-typography-props.js +1 -1
  248. package/src/layouts/flex.js +43 -38
  249. package/src/store/actions.js +22 -0
  250. package/src/store/reducer.js +50 -40
  251. package/src/store/selectors.js +16 -9
  252. package/src/store/test/actions.js +18 -0
  253. package/src/store/test/reducer.js +40 -0
  254. package/src/store/test/selectors.js +19 -0
@@ -0,0 +1,260 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useSelect } from '@wordpress/data';
5
+ import { useState, useCallback } from '@wordpress/element';
6
+ import {
7
+ useThrottle,
8
+ __experimentalUseDropZone as useDropZone,
9
+ } from '@wordpress/compose';
10
+
11
+ /**
12
+ * Internal dependencies
13
+ */
14
+ import {
15
+ getDistanceToNearestEdge,
16
+ isPointContainedByRect,
17
+ } from '../../utils/math';
18
+ import useOnBlockDrop from '../use-on-block-drop';
19
+ import { store as blockEditorStore } from '../../store';
20
+
21
+ /** @typedef {import('../../utils/math').WPPoint} WPPoint */
22
+
23
+ /**
24
+ * The type of a drag event.
25
+ *
26
+ * @typedef {'default'|'file'|'html'} WPDragEventType
27
+ */
28
+
29
+ /**
30
+ * An array representing data for blocks in the DOM used by drag and drop.
31
+ *
32
+ * @typedef {Object} WPListViewDropZoneBlocks
33
+ * @property {string} clientId The client id for the block.
34
+ * @property {string} rootClientId The root client id for the block.
35
+ * @property {number} blockIndex The block's index.
36
+ * @property {Element} element The DOM element representing the block.
37
+ * @property {number} innerBlockCount The number of inner blocks the block has.
38
+ * @property {boolean} isDraggedBlock Whether the block is currently being dragged.
39
+ * @property {boolean} canInsertDraggedBlocksAsSibling Whether the dragged block can be a sibling of this block.
40
+ * @property {boolean} canInsertDraggedBlocksAsChild Whether the dragged block can be a child of this block.
41
+ */
42
+
43
+ /**
44
+ * An object containing details of a drop target.
45
+ *
46
+ * @typedef {Object} WPListViewDropZoneTarget
47
+ * @property {string} blockIndex The insertion index.
48
+ * @property {string} rootClientId The root client id for the block.
49
+ * @property {string|undefined} clientId The client id for the block.
50
+ * @property {'top'|'bottom'|'inside'} dropPosition The position relative to the block that the user is dropping to.
51
+ * 'inside' refers to nesting as an inner block.
52
+ */
53
+
54
+ /**
55
+ * Determines whether the user positioning the dragged block to nest as an
56
+ * inner block.
57
+ *
58
+ * Presently this is determined by whether the cursor is on the right hand side
59
+ * of the block.
60
+ *
61
+ * @param {WPPoint} point The point representing the cursor position when dragging.
62
+ * @param {DOMRect} rect The rectangle.
63
+ */
64
+ function isNestingGesture( point, rect ) {
65
+ const blockCenterX = rect.left + rect.width / 2;
66
+ return point.x > blockCenterX;
67
+ }
68
+
69
+ // Block navigation is always a vertical list, so only allow dropping
70
+ // to the above or below a block.
71
+ const ALLOWED_DROP_EDGES = [ 'top', 'bottom' ];
72
+
73
+ /**
74
+ * Given blocks data and the cursor position, compute the drop target.
75
+ *
76
+ * @param {WPListViewDropZoneBlocks} blocksData Data about the blocks in list view.
77
+ * @param {WPPoint} position The point representing the cursor position when dragging.
78
+ *
79
+ * @return {WPListViewDropZoneTarget} An object containing data about the drop target.
80
+ */
81
+ function getListViewDropTarget( blocksData, position ) {
82
+ let candidateEdge;
83
+ let candidateBlockData;
84
+ let candidateDistance;
85
+ let candidateRect;
86
+
87
+ for ( const blockData of blocksData ) {
88
+ if ( blockData.isDraggedBlock ) {
89
+ continue;
90
+ }
91
+
92
+ const rect = blockData.element.getBoundingClientRect();
93
+ const [ distance, edge ] = getDistanceToNearestEdge(
94
+ position,
95
+ rect,
96
+ ALLOWED_DROP_EDGES
97
+ );
98
+
99
+ const isCursorWithinBlock = isPointContainedByRect( position, rect );
100
+ if (
101
+ candidateDistance === undefined ||
102
+ distance < candidateDistance ||
103
+ isCursorWithinBlock
104
+ ) {
105
+ candidateDistance = distance;
106
+
107
+ const index = blocksData.indexOf( blockData );
108
+ const previousBlockData = blocksData[ index - 1 ];
109
+
110
+ // If dragging near the top of a block and the preceding block
111
+ // is at the same level, use the preceding block as the candidate
112
+ // instead, as later it makes determining a nesting drop easier.
113
+ if (
114
+ edge === 'top' &&
115
+ previousBlockData &&
116
+ previousBlockData.rootClientId === blockData.rootClientId &&
117
+ ! previousBlockData.isDraggedBlock
118
+ ) {
119
+ candidateBlockData = previousBlockData;
120
+ candidateEdge = 'bottom';
121
+ candidateRect =
122
+ previousBlockData.element.getBoundingClientRect();
123
+ } else {
124
+ candidateBlockData = blockData;
125
+ candidateEdge = edge;
126
+ candidateRect = rect;
127
+ }
128
+
129
+ // If the mouse position is within the block, break early
130
+ // as the user would intend to drop either before or after
131
+ // this block.
132
+ //
133
+ // This solves an issue where some rows in the list view
134
+ // tree overlap slightly due to sub-pixel rendering.
135
+ if ( isCursorWithinBlock ) {
136
+ break;
137
+ }
138
+ }
139
+ }
140
+
141
+ if ( ! candidateBlockData ) {
142
+ return;
143
+ }
144
+
145
+ const isDraggingBelow = candidateEdge === 'bottom';
146
+
147
+ // If the user is dragging towards the bottom of the block check whether
148
+ // 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
+ // as nesting since the next block in the tree will be the first child.
151
+ if (
152
+ isDraggingBelow &&
153
+ candidateBlockData.canInsertDraggedBlocksAsChild &&
154
+ ( candidateBlockData.innerBlockCount > 0 ||
155
+ isNestingGesture( position, candidateRect ) )
156
+ ) {
157
+ return {
158
+ rootClientId: candidateBlockData.clientId,
159
+ blockIndex: 0,
160
+ dropPosition: 'inside',
161
+ };
162
+ }
163
+
164
+ // If dropping as a sibling, but block cannot be inserted in
165
+ // this context, return early.
166
+ if ( ! candidateBlockData.canInsertDraggedBlocksAsSibling ) {
167
+ return;
168
+ }
169
+
170
+ const offset = isDraggingBelow ? 1 : 0;
171
+ return {
172
+ rootClientId: candidateBlockData.rootClientId,
173
+ clientId: candidateBlockData.clientId,
174
+ blockIndex: candidateBlockData.blockIndex + offset,
175
+ dropPosition: candidateEdge,
176
+ };
177
+ }
178
+
179
+ /**
180
+ * A react hook for implementing a drop zone in list view.
181
+ *
182
+ * @return {WPListViewDropZoneTarget} The drop target.
183
+ */
184
+ export default function useListViewDropZone() {
185
+ const {
186
+ getBlockRootClientId,
187
+ getBlockIndex,
188
+ getBlockCount,
189
+ getDraggedBlockClientIds,
190
+ canInsertBlocks,
191
+ } = useSelect( blockEditorStore );
192
+ const [ target, setTarget ] = useState();
193
+ const { rootClientId: targetRootClientId, blockIndex: targetBlockIndex } =
194
+ target || {};
195
+
196
+ const onBlockDrop = useOnBlockDrop( targetRootClientId, targetBlockIndex );
197
+
198
+ const draggedBlockClientIds = getDraggedBlockClientIds();
199
+ const throttled = useThrottle(
200
+ useCallback(
201
+ ( event, currentTarget ) => {
202
+ const position = { x: event.clientX, y: event.clientY };
203
+ const isBlockDrag = !! draggedBlockClientIds?.length;
204
+
205
+ const blockElements = Array.from(
206
+ currentTarget.querySelectorAll( '[data-block]' )
207
+ );
208
+
209
+ const blocksData = blockElements.map( ( blockElement ) => {
210
+ const clientId = blockElement.dataset.block;
211
+ const rootClientId = getBlockRootClientId( clientId );
212
+
213
+ return {
214
+ clientId,
215
+ rootClientId,
216
+ blockIndex: getBlockIndex( clientId ),
217
+ element: blockElement,
218
+ isDraggedBlock: isBlockDrag
219
+ ? draggedBlockClientIds.includes( clientId )
220
+ : false,
221
+ innerBlockCount: getBlockCount( clientId ),
222
+ canInsertDraggedBlocksAsSibling: isBlockDrag
223
+ ? canInsertBlocks(
224
+ draggedBlockClientIds,
225
+ rootClientId
226
+ )
227
+ : true,
228
+ canInsertDraggedBlocksAsChild: isBlockDrag
229
+ ? canInsertBlocks( draggedBlockClientIds, clientId )
230
+ : true,
231
+ };
232
+ } );
233
+
234
+ const newTarget = getListViewDropTarget( blocksData, position );
235
+
236
+ if ( newTarget ) {
237
+ setTarget( newTarget );
238
+ }
239
+ },
240
+ [ draggedBlockClientIds ]
241
+ ),
242
+ 200
243
+ );
244
+
245
+ const ref = useDropZone( {
246
+ onDrop: onBlockDrop,
247
+ onDragOver( event ) {
248
+ // `currentTarget` is only available while the event is being
249
+ // handled, so get it now and pass it to the thottled function.
250
+ // https://developer.mozilla.org/en-US/docs/Web/API/Event/currentTarget
251
+ throttled( event, event.currentTarget );
252
+ },
253
+ onDragEnd() {
254
+ throttled.cancel();
255
+ setTarget( null );
256
+ },
257
+ } );
258
+
259
+ return { ref, target };
260
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useEffect, useState } from '@wordpress/element';
5
+ import { useSelect } from '@wordpress/data';
6
+
7
+ /**
8
+ * Internal dependencies
9
+ */
10
+ import { store as blockEditorStore } from '../../store';
11
+
12
+ export default function useListViewExpandSelectedItem( {
13
+ firstSelectedBlockClientId,
14
+ setExpandedState,
15
+ } ) {
16
+ const [ selectedTreeId, setSelectedTreeId ] = useState( null );
17
+ const { selectedBlockParentClientIds } = useSelect(
18
+ ( select ) => {
19
+ const { getBlockParents } = select( blockEditorStore );
20
+ return {
21
+ selectedBlockParentClientIds: getBlockParents(
22
+ firstSelectedBlockClientId,
23
+ false
24
+ ),
25
+ };
26
+ },
27
+ [ firstSelectedBlockClientId ]
28
+ );
29
+
30
+ const parentClientIds =
31
+ Array.isArray( selectedBlockParentClientIds ) &&
32
+ selectedBlockParentClientIds.length
33
+ ? selectedBlockParentClientIds
34
+ : null;
35
+
36
+ // Expand tree when a block is selected.
37
+ useEffect( () => {
38
+ // If the selectedTreeId is the same as the selected block,
39
+ // it means that the block was selected using the block list tree.
40
+ if ( selectedTreeId === firstSelectedBlockClientId ) {
41
+ return;
42
+ }
43
+
44
+ // If the selected block has parents, get the top-level parent.
45
+ if ( parentClientIds ) {
46
+ // If the selected block has parents,
47
+ // expand the tree branch.
48
+ setExpandedState( {
49
+ type: 'expand',
50
+ clientIds: selectedBlockParentClientIds,
51
+ } );
52
+ }
53
+ }, [ firstSelectedBlockClientId ] );
54
+
55
+ return {
56
+ setSelectedTreeId,
57
+ };
58
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { __, sprintf } from '@wordpress/i18n';
5
+
6
+ export const getBlockPositionDescription = ( position, siblingCount, level ) =>
7
+ sprintf(
8
+ /* translators: 1: The numerical position of the block. 2: The total number of blocks. 3. The level of nesting for the block. */
9
+ __( 'Block %1$d of %2$d, Level %3$d' ),
10
+ position,
11
+ siblingCount,
12
+ level
13
+ );
14
+
15
+ /**
16
+ * Returns true if the client ID occurs within the block selection or multi-selection,
17
+ * or false otherwise.
18
+ *
19
+ * @param {string} clientId Block client ID.
20
+ * @param {string|string[]} selectedBlockClientIds Selected block client ID, or an array of multi-selected blocks client IDs.
21
+ *
22
+ * @return {boolean} Whether the block is in multi-selection set.
23
+ */
24
+ export const isClientIdSelected = ( clientId, selectedBlockClientIds ) =>
25
+ Array.isArray( selectedBlockClientIds ) && selectedBlockClientIds.length
26
+ ? selectedBlockClientIds.indexOf( clientId ) !== -1
27
+ : selectedBlockClientIds === clientId;
28
+
29
+ /**
30
+ * From a start and end clientId of potentially different nesting levels,
31
+ * return the nearest-depth ids that have a common level of depth in the
32
+ * nesting hierarchy. For multiple block selection, this ensure that the
33
+ * selection is always at the same nesting level, and not split across
34
+ * separate levels.
35
+ *
36
+ * @param {string} startId The first id of a selection.
37
+ * @param {string} endId The end id of a selection, usually one that has been clicked on.
38
+ * @param {string[]} startParents An array of ancestor ids for the start id, in descending order.
39
+ * @param {string[]} endParents An array of ancestor ids for the end id, in descending order.
40
+ * @return {Object} An object containing the start and end ids.
41
+ */
42
+ export function getCommonDepthClientIds(
43
+ startId,
44
+ endId,
45
+ startParents,
46
+ endParents
47
+ ) {
48
+ const startPath = [ ...startParents, startId ];
49
+ const endPath = [ ...endParents, endId ];
50
+ const depth = Math.min( startPath.length, endPath.length ) - 1;
51
+ const start = startPath[ depth ];
52
+ const end = endPath[ depth ];
53
+
54
+ return {
55
+ start,
56
+ end,
57
+ };
58
+ }
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * External dependencies
3
3
  */
4
- import { render } from '@testing-library/react';
4
+ import { render, screen } from '@testing-library/react';
5
5
  import userEvent from '@testing-library/user-event';
6
6
 
7
7
  /**
@@ -48,6 +48,20 @@ const renderTestDefaultControlComponent = ( labelComponent, device ) => {
48
48
  );
49
49
  };
50
50
 
51
+ function getDefaultControlGroup( container ) {
52
+ // TODO: Use a user-facing query to fetch this.
53
+ return container.querySelector(
54
+ '.block-editor-responsive-block-control__group:not(.is-responsive)'
55
+ );
56
+ }
57
+
58
+ function getResponsiveControlGroup( container ) {
59
+ // TODO: Use a user-facing query to fetch this.
60
+ return container.querySelector(
61
+ '.block-editor-responsive-block-control__group.is-responsive'
62
+ );
63
+ }
64
+
51
65
  describe( 'Basic rendering', () => {
52
66
  it( 'should render with required props', () => {
53
67
  const { container } = render(
@@ -58,48 +72,30 @@ describe( 'Basic rendering', () => {
58
72
  />
59
73
  );
60
74
 
61
- const activePropertyLabel = Array.from(
62
- container.querySelectorAll( 'legend' )
63
- ).find( ( legend ) => legend.innerHTML === 'Padding' );
64
-
65
- const activeViewportLabel = Array.from(
66
- container.querySelectorAll( 'label' )
67
- ).find( ( label ) => label.innerHTML.includes( 'All' ) );
68
-
69
- const defaultControl = container.querySelector(
70
- `#${ activeViewportLabel.getAttribute( 'for' ) }`
71
- );
72
-
73
- const toggleLabel = Array.from(
74
- container.querySelectorAll( 'label' )
75
- ).filter( ( label ) =>
76
- label.innerHTML.includes(
77
- 'Use the same padding on all screensizes'
78
- )
79
- );
75
+ const activePropertyLabel = screen.getByRole( 'group', {
76
+ name: 'Padding',
77
+ } );
80
78
 
81
- const toggleState = container.querySelector(
82
- 'input[type="checkbox"]'
83
- ).checked;
79
+ const defaultControl = screen.getByRole( 'combobox', {
80
+ name: 'All Controls the padding property for All viewports.',
81
+ } );
84
82
 
85
- const defaultControlGroup = container.querySelector(
86
- '.block-editor-responsive-block-control__group:not(.is-responsive)'
87
- );
83
+ const toggleState = screen.getByRole( 'checkbox', {
84
+ name: 'Use the same padding on all screensizes.',
85
+ checked: true,
86
+ } );
88
87
 
89
- const responsiveControlGroup = container.querySelector(
90
- '.block-editor-responsive-block-control__group.is-responsive'
91
- );
88
+ const defaultControlGroup = getDefaultControlGroup( container );
89
+ const responsiveControlGroup = getResponsiveControlGroup( container );
92
90
 
93
91
  expect( container ).not.toBeEmptyDOMElement();
94
92
 
95
93
  expect( defaultControlGroup ).not.toBeNull();
96
94
  expect( responsiveControlGroup ).toBeNull();
97
95
 
98
- expect( activeViewportLabel ).not.toBeNull();
99
- expect( activePropertyLabel ).not.toBeNull();
100
- expect( defaultControl ).not.toBeNull();
101
- expect( toggleLabel ).not.toBeNull();
102
- expect( toggleState ).toBe( true );
96
+ expect( activePropertyLabel ).toBeVisible();
97
+ expect( defaultControl ).toBeVisible();
98
+ expect( toggleState ).toBeVisible();
103
99
  } );
104
100
 
105
101
  it( 'should not render without valid legend', () => {
@@ -135,7 +131,7 @@ describe( 'Basic rendering', () => {
135
131
  it( 'should render with custom label for toggle control when provided', () => {
136
132
  const customToggleLabel =
137
133
  'Utilise a matching padding value on all viewports';
138
- const { container } = render(
134
+ render(
139
135
  <ResponsiveBlockControl
140
136
  title="Padding"
141
137
  property="padding"
@@ -144,17 +140,21 @@ describe( 'Basic rendering', () => {
144
140
  />
145
141
  );
146
142
 
147
- const actualToggleLabel = container.querySelector(
148
- 'label.components-toggle-control__label'
149
- ).innerHTML;
150
-
151
- expect( actualToggleLabel ).toEqual( customToggleLabel );
143
+ expect(
144
+ screen.getByRole( 'checkbox', {
145
+ name: customToggleLabel,
146
+ checked: true,
147
+ } )
148
+ ).toBeVisible();
152
149
  } );
153
150
 
154
151
  it( 'should pass custom label for default control group to the renderDefaultControl function when provided', () => {
155
- const customDefaultControlGroupLabel = 'Everything';
152
+ const customDefaultControlGroupLabel = {
153
+ id: 'everything',
154
+ label: 'Everything',
155
+ };
156
156
 
157
- const { container } = render(
157
+ render(
158
158
  <ResponsiveBlockControl
159
159
  title="Padding"
160
160
  property="padding"
@@ -163,11 +163,11 @@ describe( 'Basic rendering', () => {
163
163
  />
164
164
  );
165
165
 
166
- const defaultControlLabel = Array.from(
167
- container.querySelectorAll( 'label' )
168
- ).find( ( label ) => label.innerHTML.includes( 'Everything' ) );
166
+ const defaultControlLabel = screen.getByRole( 'combobox', {
167
+ name: 'Everything Controls the padding property for Everything viewports.',
168
+ } );
169
169
 
170
- expect( defaultControlLabel ).not.toBeNull();
170
+ expect( defaultControlLabel ).toBeVisible();
171
171
  } );
172
172
  } );
173
173
 
@@ -182,12 +182,8 @@ describe( 'Default and Responsive modes', () => {
182
182
  />
183
183
  );
184
184
 
185
- const defaultControlGroup = container.querySelector(
186
- '.block-editor-responsive-block-control__group:not(.is-responsive)'
187
- );
188
- const responsiveControlGroup = container.querySelector(
189
- '.block-editor-responsive-block-control__group.is-responsive'
190
- );
185
+ const defaultControlGroup = getDefaultControlGroup( container );
186
+ const responsiveControlGroup = getResponsiveControlGroup( container );
191
187
 
192
188
  expect( defaultControlGroup ).toBeNull();
193
189
  expect( responsiveControlGroup ).not.toBeNull();
@@ -217,7 +213,7 @@ describe( 'Default and Responsive modes', () => {
217
213
  renderTestDefaultControlComponent
218
214
  );
219
215
 
220
- const { container } = render(
216
+ render(
221
217
  <ResponsiveBlockControl
222
218
  title="Padding"
223
219
  property="padding"
@@ -230,13 +226,12 @@ describe( 'Default and Responsive modes', () => {
230
226
  const defaultRenderControlCall = 1;
231
227
 
232
228
  // Get array of labels which match those in the custom viewports provided
233
- const responsiveViewportsLabels = Array.from(
234
- container.querySelectorAll( 'label' )
235
- ).filter( ( label ) => {
236
- const labelText = label.innerHTML;
237
- // Is the label one of those in the custom device set?
238
- return !! customViewportSet.find( ( deviceName ) =>
239
- labelText.includes( deviceName.label )
229
+ const responsiveViewportsLabels = [];
230
+ customViewportSet.forEach( ( { label } ) => {
231
+ responsiveViewportsLabels.push(
232
+ screen.getByRole( 'combobox', {
233
+ name: `${ label } Controls the padding property for ${ label } viewports.`,
234
+ } )
240
235
  );
241
236
  } );
242
237
 
@@ -270,24 +265,14 @@ describe( 'Default and Responsive modes', () => {
270
265
 
271
266
  const { container } = render( <ResponsiveBlockControlConsumer /> );
272
267
 
273
- let defaultControlGroup = container.querySelector(
274
- '.block-editor-responsive-block-control__group:not(.is-responsive)'
275
- );
276
- let responsiveControlGroup = container.querySelector(
277
- '.block-editor-responsive-block-control__group.is-responsive'
278
- );
268
+ let defaultControlGroup = getDefaultControlGroup( container );
269
+ let responsiveControlGroup = getResponsiveControlGroup( container );
279
270
 
280
271
  // Select elements based on what the user can see.
281
- const toggleLabel = Array.from(
282
- container.querySelectorAll( 'label' )
283
- ).find( ( label ) =>
284
- label.innerHTML.includes(
285
- 'Use the same padding on all screensizes'
286
- )
287
- );
288
- const toggleInput = container.querySelector(
289
- `#${ toggleLabel.getAttribute( 'for' ) }`
290
- );
272
+ const toggleInput = screen.getByRole( 'checkbox', {
273
+ name: 'Use the same padding on all screensizes.',
274
+ checked: true,
275
+ } );
291
276
 
292
277
  // Initial mode (default)
293
278
  expect( defaultControlGroup ).not.toBeNull();
@@ -296,12 +281,8 @@ describe( 'Default and Responsive modes', () => {
296
281
  // Toggle to "responsive" mode.
297
282
  await user.click( toggleInput );
298
283
 
299
- defaultControlGroup = container.querySelector(
300
- '.block-editor-responsive-block-control__group:not(.is-responsive)'
301
- );
302
- responsiveControlGroup = container.querySelector(
303
- '.block-editor-responsive-block-control__group.is-responsive'
304
- );
284
+ defaultControlGroup = getDefaultControlGroup( container );
285
+ responsiveControlGroup = getResponsiveControlGroup( container );
305
286
 
306
287
  expect( defaultControlGroup ).toBeNull();
307
288
  expect( responsiveControlGroup ).not.toBeNull();
@@ -309,12 +290,8 @@ describe( 'Default and Responsive modes', () => {
309
290
  // Toggle back to "default" mode.
310
291
  await user.click( toggleInput );
311
292
 
312
- defaultControlGroup = container.querySelector(
313
- '.block-editor-responsive-block-control__group:not(.is-responsive)'
314
- );
315
- responsiveControlGroup = container.querySelector(
316
- '.block-editor-responsive-block-control__group.is-responsive'
317
- );
293
+ defaultControlGroup = getDefaultControlGroup( container );
294
+ responsiveControlGroup = getResponsiveControlGroup( container );
318
295
 
319
296
  expect( defaultControlGroup ).not.toBeNull();
320
297
  expect( responsiveControlGroup ).toBeNull();
@@ -340,7 +317,7 @@ describe( 'Default and Responsive modes', () => {
340
317
  } );
341
318
  } );
342
319
 
343
- const { container } = render(
320
+ render(
344
321
  <ResponsiveBlockControl
345
322
  title="Padding"
346
323
  property="padding"
@@ -351,9 +328,9 @@ describe( 'Default and Responsive modes', () => {
351
328
  );
352
329
 
353
330
  // The user should see "range" controls so we can legitimately query for them here.
354
- const customControls = Array.from(
355
- container.querySelectorAll( 'input[type="range"]' )
356
- );
331
+ const customControls = screen.getAllByRole( 'slider', {
332
+ name: /\w+ screens$/,
333
+ } );
357
334
 
358
335
  // Also called because default control rendeer function is always called
359
336
  // (for convenience) even though it's not displayed in output.
@@ -94,13 +94,13 @@ class MyURLPopover extends Component {
94
94
 
95
95
  The component accepts the following props. Any other props are passed through to the underlying `Popover` component ([refer to props documentation](/packages/components/src/popover/README.md)).
96
96
 
97
- ### position
97
+ ### placement
98
98
 
99
- Where the Popover should be positioned relative to its parent. Defaults to "bottom center".
99
+ Where the Popover should be positioned relative to its parent. Defaults to "bottom".
100
100
 
101
101
  - Type: `String`
102
102
  - Required: No
103
- - Default: "bottom center"
103
+ - Default: "bottom"
104
104
 
105
105
  ### focusOnMount
106
106
 
@@ -194,3 +194,12 @@ Reference passed to the auto complete element of the ([URLInput component](/pack
194
194
 
195
195
  - Type: `Object`
196
196
  - Required: no
197
+
198
+ ### position
199
+
200
+ _Note: this prop is deprecated. Please use the `placement` prop instead._
201
+
202
+ Where the Popover should be positioned relative to its parent.
203
+
204
+ - Type: `String`
205
+ - Required: No