@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,22 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useState, useEffect } from '@wordpress/element';
5
+
6
+ export default function useInternalInputValue( value ) {
7
+ const [ internalInputValue, setInternalInputValue ] = useState(
8
+ value || ''
9
+ );
10
+
11
+ useEffect( () => {
12
+ /**
13
+ * If the value's `text` property changes then sync this
14
+ * back up with state.
15
+ */
16
+ if ( value?.title && value.title !== internalInputValue ) {
17
+ setInternalInputValue( value.title );
18
+ }
19
+ }, [ value ] );
20
+
21
+ return [ internalInputValue, setInternalInputValue ];
22
+ }
@@ -59,7 +59,7 @@ function ListViewBlock( {
59
59
  const [ isHovered, setIsHovered ] = useState( false );
60
60
  const { clientId } = block;
61
61
 
62
- const { isLocked, isContentLocked } = useBlockLock( clientId );
62
+ const { isLocked, isContentLocked, canEdit } = useBlockLock( clientId );
63
63
  const forceSelectionContentLock = useSelect(
64
64
  ( select ) => {
65
65
  if ( isSelected ) {
@@ -76,6 +76,7 @@ function ListViewBlock( {
76
76
  [ isContentLocked, clientId, isSelected ]
77
77
  );
78
78
 
79
+ const canExpand = isContentLocked ? false : canEdit;
79
80
  const isFirstSelectedBlock =
80
81
  forceSelectionContentLock ||
81
82
  ( isSelected && selectedClientIds[ 0 ] === clientId );
@@ -229,7 +230,7 @@ function ListViewBlock( {
229
230
  path={ path }
230
231
  id={ `list-view-block-${ clientId }` }
231
232
  data-block={ clientId }
232
- isExpanded={ isContentLocked ? undefined : isExpanded }
233
+ isExpanded={ canExpand ? isExpanded : undefined }
233
234
  aria-selected={ !! isSelected || forceSelectionContentLock }
234
235
  >
235
236
  <TreeGridCell
@@ -238,7 +239,7 @@ function ListViewBlock( {
238
239
  ref={ cellRef }
239
240
  aria-label={ blockAriaLabel }
240
241
  aria-selected={ !! isSelected || forceSelectionContentLock }
241
- aria-expanded={ isContentLocked ? undefined : isExpanded }
242
+ aria-expanded={ canExpand ? isExpanded : undefined }
242
243
  aria-describedby={ descriptionId }
243
244
  >
244
245
  { ( { ref, tabIndex, onFocus } ) => (
@@ -94,20 +94,25 @@ function ListViewBranch( props ) {
94
94
  shouldShowInnerBlocks = true,
95
95
  } = props;
96
96
 
97
- const isContentLocked = useSelect(
97
+ const canParentExpand = useSelect(
98
98
  ( select ) => {
99
- return !! (
100
- parentId &&
99
+ if ( ! parentId ) {
100
+ return true;
101
+ }
102
+
103
+ const isContentLocked =
101
104
  select( blockEditorStore ).getTemplateLock( parentId ) ===
102
- 'contentOnly'
103
- );
105
+ 'contentOnly';
106
+ const canEdit = select( blockEditorStore ).canEditBlock( parentId );
107
+
108
+ return isContentLocked ? false : canEdit;
104
109
  },
105
110
  [ parentId ]
106
111
  );
107
112
 
108
113
  const { expandedState, draggedClientIds } = useListViewContext();
109
114
 
110
- if ( isContentLocked ) {
115
+ if ( ! canParentExpand ) {
111
116
  return null;
112
117
  }
113
118
 
@@ -0,0 +1,5 @@
1
+ # Experimental Off Canvas Editor
2
+
3
+ The __ExperimentalOffCanvasEditor component is a modified ListView compoent. It provides an overview of the hierarchical structure of all blocks in the editor. The blocks are presented vertically one below the other. It enables editing of hierarchy and addition of elements in the block tree without selecting the block instance on the canvas.
4
+
5
+ It is an experimental component which may end up completely merged into the ListView component via configuration props.
@@ -0,0 +1,89 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import classnames from 'classnames';
5
+
6
+ /**
7
+ * WordPress dependencies
8
+ */
9
+ import { useSelect } from '@wordpress/data';
10
+ import { forwardRef } from '@wordpress/element';
11
+
12
+ /**
13
+ * Internal dependencies
14
+ */
15
+ import ListViewBlockSelectButton from './block-select-button';
16
+ import BlockDraggable from '../block-draggable';
17
+ import { store as blockEditorStore } from '../../store';
18
+
19
+ const ListViewBlockContents = forwardRef(
20
+ (
21
+ {
22
+ onClick,
23
+ onToggleExpanded,
24
+ block,
25
+ isSelected,
26
+ position,
27
+ siblingBlockCount,
28
+ level,
29
+ isExpanded,
30
+ selectedClientIds,
31
+ ...props
32
+ },
33
+ ref
34
+ ) => {
35
+ const { clientId } = block;
36
+
37
+ const { blockMovingClientId, selectedBlockInBlockEditor } = useSelect(
38
+ ( select ) => {
39
+ const { hasBlockMovingClientId, getSelectedBlockClientId } =
40
+ select( blockEditorStore );
41
+ return {
42
+ blockMovingClientId: hasBlockMovingClientId(),
43
+ selectedBlockInBlockEditor: getSelectedBlockClientId(),
44
+ };
45
+ },
46
+ [ clientId ]
47
+ );
48
+
49
+ const isBlockMoveTarget =
50
+ blockMovingClientId && selectedBlockInBlockEditor === clientId;
51
+
52
+ const className = classnames( 'block-editor-list-view-block-contents', {
53
+ 'is-dropping-before': isBlockMoveTarget,
54
+ } );
55
+
56
+ // Only include all selected blocks if the currently clicked on block
57
+ // is one of the selected blocks. This ensures that if a user attempts
58
+ // to drag a block that isn't part of the selection, they're still able
59
+ // to drag it and rearrange its position.
60
+ const draggableClientIds = selectedClientIds.includes( clientId )
61
+ ? selectedClientIds
62
+ : [ clientId ];
63
+
64
+ return (
65
+ <BlockDraggable clientIds={ draggableClientIds }>
66
+ { ( { draggable, onDragStart, onDragEnd } ) => (
67
+ <ListViewBlockSelectButton
68
+ ref={ ref }
69
+ className={ className }
70
+ block={ block }
71
+ onClick={ onClick }
72
+ onToggleExpanded={ onToggleExpanded }
73
+ isSelected={ isSelected }
74
+ position={ position }
75
+ siblingBlockCount={ siblingBlockCount }
76
+ level={ level }
77
+ draggable={ draggable }
78
+ onDragStart={ onDragStart }
79
+ onDragEnd={ onDragEnd }
80
+ isExpanded={ isExpanded }
81
+ { ...props }
82
+ />
83
+ ) }
84
+ </BlockDraggable>
85
+ );
86
+ }
87
+ );
88
+
89
+ export default ListViewBlockContents;
@@ -0,0 +1,113 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import classnames from 'classnames';
5
+
6
+ /**
7
+ * WordPress dependencies
8
+ */
9
+ import {
10
+ Button,
11
+ __experimentalHStack as HStack,
12
+ __experimentalTruncate as Truncate,
13
+ } from '@wordpress/components';
14
+ import { forwardRef } from '@wordpress/element';
15
+ import { Icon, lock } from '@wordpress/icons';
16
+ import { SPACE, ENTER } from '@wordpress/keycodes';
17
+
18
+ /**
19
+ * Internal dependencies
20
+ */
21
+ import BlockIcon from '../block-icon';
22
+ import useBlockDisplayInformation from '../use-block-display-information';
23
+ import useBlockDisplayTitle from '../block-title/use-block-display-title';
24
+ import ListViewExpander from './expander';
25
+ import { useBlockLock } from '../block-lock';
26
+
27
+ function ListViewBlockSelectButton(
28
+ {
29
+ className,
30
+ block: { clientId },
31
+ onClick,
32
+ onToggleExpanded,
33
+ tabIndex,
34
+ onFocus,
35
+ onDragStart,
36
+ onDragEnd,
37
+ draggable,
38
+ },
39
+ ref
40
+ ) {
41
+ const blockInformation = useBlockDisplayInformation( clientId );
42
+ const blockTitle = useBlockDisplayTitle( {
43
+ clientId,
44
+ context: 'list-view',
45
+ } );
46
+ const { isLocked } = useBlockLock( clientId );
47
+
48
+ // The `href` attribute triggers the browser's native HTML drag operations.
49
+ // When the link is dragged, the element's outerHTML is set in DataTransfer object as text/html.
50
+ // We need to clear any HTML drag data to prevent `pasteHandler` from firing
51
+ // inside the `useOnBlockDrop` hook.
52
+ const onDragStartHandler = ( event ) => {
53
+ event.dataTransfer.clearData();
54
+ onDragStart?.( event );
55
+ };
56
+
57
+ function onKeyDownHandler( event ) {
58
+ if ( event.keyCode === ENTER || event.keyCode === SPACE ) {
59
+ onClick( event );
60
+ }
61
+ }
62
+
63
+ return (
64
+ <>
65
+ <Button
66
+ className={ classnames(
67
+ 'block-editor-list-view-block-select-button',
68
+ className
69
+ ) }
70
+ onClick={ onClick }
71
+ onKeyDown={ onKeyDownHandler }
72
+ ref={ ref }
73
+ tabIndex={ tabIndex }
74
+ onFocus={ onFocus }
75
+ onDragStart={ onDragStartHandler }
76
+ onDragEnd={ onDragEnd }
77
+ draggable={ draggable }
78
+ href={ `#block-${ clientId }` }
79
+ aria-hidden={ true }
80
+ >
81
+ <ListViewExpander onClick={ onToggleExpanded } />
82
+ <BlockIcon icon={ blockInformation?.icon } showColors />
83
+ <HStack
84
+ alignment="center"
85
+ className="block-editor-list-view-block-select-button__label-wrapper"
86
+ justify="flex-start"
87
+ spacing={ 1 }
88
+ >
89
+ <span className="block-editor-list-view-block-select-button__title">
90
+ <Truncate ellipsizeMode="auto">{ blockTitle }</Truncate>
91
+ </span>
92
+ { blockInformation?.anchor && (
93
+ <span className="block-editor-list-view-block-select-button__anchor-wrapper">
94
+ <Truncate
95
+ className="block-editor-list-view-block-select-button__anchor"
96
+ ellipsizeMode="auto"
97
+ >
98
+ { blockInformation.anchor }
99
+ </Truncate>
100
+ </span>
101
+ ) }
102
+ { isLocked && (
103
+ <span className="block-editor-list-view-block-select-button__lock">
104
+ <Icon icon={ lock } />
105
+ </span>
106
+ ) }
107
+ </HStack>
108
+ </Button>
109
+ </>
110
+ );
111
+ }
112
+
113
+ export default forwardRef( ListViewBlockSelectButton );
@@ -0,0 +1,335 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import classnames from 'classnames';
5
+
6
+ /**
7
+ * WordPress dependencies
8
+ */
9
+ import { hasBlockSupport } from '@wordpress/blocks';
10
+ import {
11
+ __experimentalTreeGridCell as TreeGridCell,
12
+ __experimentalTreeGridItem as TreeGridItem,
13
+ } from '@wordpress/components';
14
+ import { useInstanceId } from '@wordpress/compose';
15
+ import { moreVertical } from '@wordpress/icons';
16
+ import {
17
+ useState,
18
+ useRef,
19
+ useEffect,
20
+ useCallback,
21
+ memo,
22
+ } from '@wordpress/element';
23
+ import { useDispatch, useSelect } from '@wordpress/data';
24
+ import { sprintf, __ } from '@wordpress/i18n';
25
+
26
+ /**
27
+ * Internal dependencies
28
+ */
29
+ import ListViewLeaf from './leaf';
30
+ import {
31
+ BlockMoverUpButton,
32
+ BlockMoverDownButton,
33
+ } from '../block-mover/button';
34
+ import ListViewBlockContents from './block-contents';
35
+ import BlockSettingsDropdown from '../block-settings-menu/block-settings-dropdown';
36
+ import { useListViewContext } from './context';
37
+ import { getBlockPositionDescription } from './utils';
38
+ import { store as blockEditorStore } from '../../store';
39
+ import useBlockDisplayInformation from '../use-block-display-information';
40
+ import { useBlockLock } from '../block-lock';
41
+
42
+ function ListViewBlock( {
43
+ block,
44
+ isDragged,
45
+ isSelected,
46
+ isBranchSelected,
47
+ selectBlock,
48
+ position,
49
+ level,
50
+ rowCount,
51
+ siblingBlockCount,
52
+ showBlockMovers,
53
+ path,
54
+ isExpanded,
55
+ selectedClientIds,
56
+ preventAnnouncement,
57
+ selectBlockInCanvas,
58
+ } ) {
59
+ const cellRef = useRef( null );
60
+ const [ isHovered, setIsHovered ] = useState( false );
61
+ const { clientId } = block;
62
+
63
+ const { isLocked, isContentLocked } = useBlockLock( clientId );
64
+ const forceSelectionContentLock = useSelect(
65
+ ( select ) => {
66
+ if ( isSelected ) {
67
+ return false;
68
+ }
69
+ if ( ! isContentLocked ) {
70
+ return false;
71
+ }
72
+ return select( blockEditorStore ).hasSelectedInnerBlock(
73
+ clientId,
74
+ true
75
+ );
76
+ },
77
+ [ isContentLocked, clientId, isSelected ]
78
+ );
79
+
80
+ const isFirstSelectedBlock =
81
+ forceSelectionContentLock ||
82
+ ( isSelected && selectedClientIds[ 0 ] === clientId );
83
+ const isLastSelectedBlock =
84
+ forceSelectionContentLock ||
85
+ ( isSelected &&
86
+ selectedClientIds[ selectedClientIds.length - 1 ] === clientId );
87
+
88
+ const { toggleBlockHighlight } = useDispatch( blockEditorStore );
89
+
90
+ const blockInformation = useBlockDisplayInformation( clientId );
91
+ const blockName = useSelect(
92
+ ( select ) => select( blockEditorStore ).getBlockName( clientId ),
93
+ [ clientId ]
94
+ );
95
+
96
+ // When a block hides its toolbar it also hides the block settings menu,
97
+ // since that menu is part of the toolbar in the editor canvas.
98
+ // List View respects this by also hiding the block settings menu.
99
+ const showBlockActions = hasBlockSupport(
100
+ blockName,
101
+ '__experimentalToolbar',
102
+ true
103
+ );
104
+ const instanceId = useInstanceId( ListViewBlock );
105
+ const descriptionId = `list-view-block-select-button__${ instanceId }`;
106
+ const blockPositionDescription = getBlockPositionDescription(
107
+ position,
108
+ siblingBlockCount,
109
+ level
110
+ );
111
+
112
+ let blockAriaLabel = __( 'Link' );
113
+ if ( blockInformation ) {
114
+ blockAriaLabel = isLocked
115
+ ? sprintf(
116
+ // translators: %s: The title of the block. This string indicates a link to select the locked block.
117
+ __( '%s link (locked)' ),
118
+ blockInformation.title
119
+ )
120
+ : sprintf(
121
+ // translators: %s: The title of the block. This string indicates a link to select the block.
122
+ __( '%s link' ),
123
+ blockInformation.title
124
+ );
125
+ }
126
+
127
+ const settingsAriaLabel = blockInformation
128
+ ? sprintf(
129
+ // translators: %s: The title of the block.
130
+ __( 'Options for %s block' ),
131
+ blockInformation.title
132
+ )
133
+ : __( 'Options' );
134
+
135
+ const { isTreeGridMounted, expand, collapse } = useListViewContext();
136
+
137
+ const hasSiblings = siblingBlockCount > 0;
138
+ const hasRenderedMovers = showBlockMovers && hasSiblings;
139
+ const moverCellClassName = classnames(
140
+ 'block-editor-list-view-block__mover-cell',
141
+ { 'is-visible': isHovered || isSelected }
142
+ );
143
+
144
+ const listViewBlockSettingsClassName = classnames(
145
+ 'block-editor-list-view-block__menu-cell',
146
+ { 'is-visible': isHovered || isFirstSelectedBlock }
147
+ );
148
+
149
+ // If ListView has experimental features related to the Persistent List View,
150
+ // only focus the selected list item on mount; otherwise the list would always
151
+ // try to steal the focus from the editor canvas.
152
+ useEffect( () => {
153
+ if ( ! isTreeGridMounted && isSelected ) {
154
+ cellRef.current.focus();
155
+ }
156
+ }, [] );
157
+
158
+ const onMouseEnter = useCallback( () => {
159
+ setIsHovered( true );
160
+ toggleBlockHighlight( clientId, true );
161
+ }, [ clientId, setIsHovered, toggleBlockHighlight ] );
162
+ const onMouseLeave = useCallback( () => {
163
+ setIsHovered( false );
164
+ toggleBlockHighlight( clientId, false );
165
+ }, [ clientId, setIsHovered, toggleBlockHighlight ] );
166
+
167
+ const selectEditorBlock = useCallback(
168
+ ( event ) => {
169
+ selectBlock( event, clientId );
170
+ event.preventDefault();
171
+ },
172
+ [ clientId, selectBlock ]
173
+ );
174
+
175
+ const updateSelection = useCallback(
176
+ ( newClientId ) => {
177
+ selectBlock( undefined, newClientId );
178
+ },
179
+ [ selectBlock ]
180
+ );
181
+
182
+ const toggleExpanded = useCallback(
183
+ ( event ) => {
184
+ // Prevent shift+click from opening link in a new window when toggling.
185
+ event.preventDefault();
186
+ event.stopPropagation();
187
+ if ( isExpanded === true ) {
188
+ collapse( clientId );
189
+ } else if ( isExpanded === false ) {
190
+ expand( clientId );
191
+ }
192
+ },
193
+ [ clientId, expand, collapse, isExpanded ]
194
+ );
195
+
196
+ let colSpan;
197
+ if ( hasRenderedMovers ) {
198
+ colSpan = 2;
199
+ } else if ( ! showBlockActions ) {
200
+ colSpan = 3;
201
+ }
202
+
203
+ const classes = classnames( {
204
+ 'is-selected': isSelected || forceSelectionContentLock,
205
+ 'is-first-selected': isFirstSelectedBlock,
206
+ 'is-last-selected': isLastSelectedBlock,
207
+ 'is-branch-selected': isBranchSelected,
208
+ 'is-dragging': isDragged,
209
+ 'has-single-cell': ! showBlockActions,
210
+ } );
211
+
212
+ // Only include all selected blocks if the currently clicked on block
213
+ // is one of the selected blocks. This ensures that if a user attempts
214
+ // to alter a block that isn't part of the selection, they're still able
215
+ // to do so.
216
+ const dropdownClientIds = selectedClientIds.includes( clientId )
217
+ ? selectedClientIds
218
+ : [ clientId ];
219
+
220
+ return (
221
+ <ListViewLeaf
222
+ className={ classes }
223
+ onMouseEnter={ onMouseEnter }
224
+ onMouseLeave={ onMouseLeave }
225
+ onFocus={ onMouseEnter }
226
+ onBlur={ onMouseLeave }
227
+ level={ level }
228
+ position={ position }
229
+ rowCount={ rowCount }
230
+ path={ path }
231
+ id={ `list-view-block-${ clientId }` }
232
+ data-block={ clientId }
233
+ isExpanded={ isContentLocked ? undefined : isExpanded }
234
+ aria-selected={ !! isSelected || forceSelectionContentLock }
235
+ >
236
+ <TreeGridCell
237
+ className="block-editor-list-view-block__contents-cell"
238
+ colSpan={ colSpan }
239
+ ref={ cellRef }
240
+ aria-label={ blockAriaLabel }
241
+ aria-selected={ !! isSelected || forceSelectionContentLock }
242
+ aria-expanded={ isContentLocked ? undefined : isExpanded }
243
+ aria-describedby={ descriptionId }
244
+ >
245
+ { ( { ref, tabIndex, onFocus } ) => (
246
+ <div className="block-editor-list-view-block__contents-container">
247
+ <ListViewBlockContents
248
+ block={ block }
249
+ onClick={
250
+ selectBlockInCanvas
251
+ ? selectEditorBlock
252
+ : ( event ) => {
253
+ event.preventDefault();
254
+ }
255
+ }
256
+ onToggleExpanded={ toggleExpanded }
257
+ isSelected={ isSelected }
258
+ position={ position }
259
+ siblingBlockCount={ siblingBlockCount }
260
+ level={ level }
261
+ ref={ ref }
262
+ tabIndex={ tabIndex }
263
+ onFocus={ onFocus }
264
+ isExpanded={ isExpanded }
265
+ selectedClientIds={ selectedClientIds }
266
+ preventAnnouncement={ preventAnnouncement }
267
+ />
268
+ <div
269
+ className="block-editor-list-view-block-select-button__description"
270
+ id={ descriptionId }
271
+ >
272
+ { blockPositionDescription }
273
+ </div>
274
+ </div>
275
+ ) }
276
+ </TreeGridCell>
277
+ { hasRenderedMovers && (
278
+ <>
279
+ <TreeGridCell
280
+ className={ moverCellClassName }
281
+ withoutGridItem
282
+ >
283
+ <TreeGridItem>
284
+ { ( { ref, tabIndex, onFocus } ) => (
285
+ <BlockMoverUpButton
286
+ orientation="vertical"
287
+ clientIds={ [ clientId ] }
288
+ ref={ ref }
289
+ tabIndex={ tabIndex }
290
+ onFocus={ onFocus }
291
+ />
292
+ ) }
293
+ </TreeGridItem>
294
+ <TreeGridItem>
295
+ { ( { ref, tabIndex, onFocus } ) => (
296
+ <BlockMoverDownButton
297
+ orientation="vertical"
298
+ clientIds={ [ clientId ] }
299
+ ref={ ref }
300
+ tabIndex={ tabIndex }
301
+ onFocus={ onFocus }
302
+ />
303
+ ) }
304
+ </TreeGridItem>
305
+ </TreeGridCell>
306
+ </>
307
+ ) }
308
+
309
+ { showBlockActions && (
310
+ <TreeGridCell
311
+ className={ listViewBlockSettingsClassName }
312
+ aria-selected={ !! isSelected || forceSelectionContentLock }
313
+ >
314
+ { ( { ref, tabIndex, onFocus } ) => (
315
+ <BlockSettingsDropdown
316
+ clientIds={ dropdownClientIds }
317
+ icon={ moreVertical }
318
+ label={ settingsAriaLabel }
319
+ toggleProps={ {
320
+ ref,
321
+ className: 'block-editor-list-view-block__menu',
322
+ tabIndex,
323
+ onFocus,
324
+ } }
325
+ disableOpenOnArrowDown
326
+ __experimentalSelectBlock={ updateSelection }
327
+ />
328
+ ) }
329
+ </TreeGridCell>
330
+ ) }
331
+ </ListViewLeaf>
332
+ );
333
+ }
334
+
335
+ export default memo( ListViewBlock );