Skip to content

Commit c1239e3

Browse files
committed
Create root container for block list
1 parent 90d30ca commit c1239e3

4 files changed

Lines changed: 97 additions & 74 deletions

File tree

packages/block-editor/src/components/block-list/block.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { animated } from 'react-spring/web.cjs';
88
/**
99
* WordPress dependencies
1010
*/
11-
import { useRef, useEffect, useLayoutEffect, useState, useCallback } from '@wordpress/element';
11+
import { useRef, useEffect, useLayoutEffect, useState, useCallback, useContext } from '@wordpress/element';
1212
import {
1313
focus,
1414
isTextField,
@@ -49,6 +49,7 @@ import Inserter from '../inserter';
4949
import { isInsideRootBlock } from '../../utils/dom';
5050
import useMovingAnimation from './moving-animation';
5151
import { ChildToolbar, ChildToolbarSlot } from './block-child-toolbar';
52+
import { Context } from './root-container';
5253

5354
function BlockListBlock( {
5455
mode,
@@ -84,7 +85,6 @@ function BlockListBlock( {
8485
onRemove,
8586
onInsertDefaultBlockAfter,
8687
toggleSelection,
87-
onSelectionStart,
8888
animateOnChange,
8989
enableAnimation,
9090
isNavigationMode,
@@ -93,6 +93,7 @@ function BlockListBlock( {
9393
hasSelectedUI = true,
9494
hasMovers = true,
9595
} ) {
96+
const onSelectionStart = useContext( Context );
9697
// In addition to withSelect, we should favor using useSelect in this component going forward
9798
// to avoid leaking new props to the public API (editor.BlockListBlock filter)
9899
const { isDraggingBlocks } = useSelect( ( select ) => {

packages/block-editor/src/components/block-list/index.js

Lines changed: 5 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,15 @@ import classnames from 'classnames';
66
/**
77
* WordPress dependencies
88
*/
9-
import { useRef } from '@wordpress/element';
10-
import { AsyncModeProvider, useSelect, useDispatch } from '@wordpress/data';
9+
import { AsyncModeProvider, useSelect } from '@wordpress/data';
1110

1211
/**
1312
* Internal dependencies
1413
*/
1514
import BlockListBlock from './block';
1615
import BlockListAppender from '../block-list-appender';
1716
import __experimentalBlockListFooter from '../block-list-footer';
18-
import useMultiSelection from './use-multi-selection';
19-
import { getBlockClientId } from '../../utils/dom';
20-
21-
/** @typedef {import('@wordpress/element').WPSyntheticEvent} WPSyntheticEvent */
17+
import RootContainer from './root-container';
2218

2319
/**
2420
* If the block count exceeds the threshold, we disable the reordering animation
@@ -74,64 +70,21 @@ function BlockList( {
7470
hasMultiSelection,
7571
enableAnimation,
7672
} = useSelect( selector, [ rootClientId ] );
77-
const { selectBlock } = useDispatch( 'core/block-editor' );
78-
const ref = useRef();
79-
const onSelectionStart = useMultiSelection( { ref, rootClientId } );
8073

8174
const uiParts = {
8275
hasMovers: true,
8376
hasSelectedUI: true,
8477
...__experimentalUIParts,
8578
};
8679

87-
let onFocus;
88-
let onDragStart;
89-
90-
if ( ! rootClientId ) {
91-
/**
92-
* Marks the block as selected when focused and not already selected. This
93-
* specifically handles the case where block does not set focus on its own
94-
* (via `setFocus`), typically if there is no focusable input in the block.
95-
*
96-
* @param {WPSyntheticEvent} event
97-
*/
98-
onFocus = ( event ) => {
99-
if ( hasMultiSelection ) {
100-
return;
101-
}
102-
103-
const clientId = getBlockClientId( event.target );
104-
105-
if ( clientId && clientId !== selectedBlockClientId ) {
106-
selectBlock( clientId );
107-
}
108-
};
109-
110-
/**
111-
* Prevents default dragging behavior within a block.
112-
* To do: we must handle this in the future and clean up the drag target.
113-
* Previously dragging was prevented for multi-selected, but this is no longer
114-
* needed.
115-
*
116-
* @param {WPSyntheticEvent} event Synthetic drag event.
117-
*/
118-
onDragStart = ( event ) => {
119-
// Ensure we target block content, not block controls.
120-
if ( getBlockClientId( event.target ) ) {
121-
event.preventDefault();
122-
}
123-
};
124-
}
80+
const Container = rootClientId ? 'div' : RootContainer;
12581

12682
return (
127-
<div
128-
ref={ ref }
83+
<Container
12984
className={ classnames(
13085
'block-editor-block-list__layout',
13186
className
13287
) }
133-
onFocus={ onFocus }
134-
onDragStart={ onDragStart }
13588
>
13689
{ blockClientIds.map( ( clientId, index ) => {
13790
const isBlockInSelection = hasMultiSelection ?
@@ -143,7 +96,6 @@ function BlockList( {
14396
<BlockListBlock
14497
rootClientId={ rootClientId }
14598
clientId={ clientId }
146-
onSelectionStart={ onSelectionStart }
14799
isDraggable={ isDraggable }
148100
moverDirection={ moverDirection }
149101
isMultiSelecting={ isMultiSelecting }
@@ -163,7 +115,7 @@ function BlockList( {
163115
renderAppender={ renderAppender }
164116
/>
165117
<__experimentalBlockListFooter.Slot />
166-
</div>
118+
</Container>
167119
);
168120
}
169121

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/**
2+
* WordPress dependencies
3+
*/
4+
import { useRef, createContext } from '@wordpress/element';
5+
import { useSelect, useDispatch } from '@wordpress/data';
6+
7+
/**
8+
* Internal dependencies
9+
*/
10+
import useMultiSelection from './use-multi-selection';
11+
import { getBlockClientId } from '../../utils/dom';
12+
13+
/** @typedef {import('@wordpress/element').WPSyntheticEvent} WPSyntheticEvent */
14+
15+
export const Context = createContext();
16+
17+
function selector( select ) {
18+
const {
19+
getSelectedBlockClientId,
20+
hasMultiSelection,
21+
} = select( 'core/block-editor' );
22+
23+
return {
24+
selectedBlockClientId: getSelectedBlockClientId(),
25+
hasMultiSelection: hasMultiSelection(),
26+
};
27+
}
28+
29+
/**
30+
* Prevents default dragging behavior within a block.
31+
* To do: we must handle this in the future and clean up the drag target.
32+
* Previously dragging was prevented for multi-selected, but this is no longer
33+
* needed.
34+
*
35+
* @param {WPSyntheticEvent} event Synthetic drag event.
36+
*/
37+
function onDragStart( event ) {
38+
// Ensure we target block content, not block controls.
39+
if ( getBlockClientId( event.target ) ) {
40+
event.preventDefault();
41+
}
42+
}
43+
44+
export default function RootContainer( { children, className } ) {
45+
const ref = useRef();
46+
const {
47+
selectedBlockClientId,
48+
hasMultiSelection,
49+
} = useSelect( selector, [] );
50+
const { selectBlock } = useDispatch( 'core/block-editor' );
51+
const onSelectionStart = useMultiSelection( ref );
52+
53+
/**
54+
* Marks the block as selected when focused and not already selected. This
55+
* specifically handles the case where block does not set focus on its own
56+
* (via `setFocus`), typically if there is no focusable input in the block.
57+
*
58+
* @param {WPSyntheticEvent} event
59+
*/
60+
function onFocus( event ) {
61+
if ( hasMultiSelection ) {
62+
return;
63+
}
64+
65+
const clientId = getBlockClientId( event.target );
66+
67+
if ( clientId && clientId !== selectedBlockClientId ) {
68+
selectBlock( clientId );
69+
}
70+
}
71+
72+
return (
73+
<div
74+
ref={ ref }
75+
className={ className }
76+
onFocus={ onFocus }
77+
onDragStart={ onDragStart }
78+
>
79+
<Context.Provider value={ onSelectionStart }>
80+
{ children }
81+
</Context.Provider>
82+
</div>
83+
);
84+
}

packages/block-editor/src/components/block-list/use-multi-selection.js

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { useSelect, useDispatch } from '@wordpress/data';
77
/**
88
* Internal dependencies
99
*/
10-
import { getBlockClientId } from '../../utils/dom';
10+
import { getBlockClientId, getBlockDOMNode } from '../../utils/dom';
1111

1212
/**
1313
* Returns for the deepest node at the start or end of a container node. Ignores
@@ -35,10 +35,9 @@ function getDeepestNode( node, type ) {
3535
return node;
3636
}
3737

38-
export default function useMultiSelection( { ref, rootClientId } ) {
38+
export default function useMultiSelection( ref ) {
3939
function selector( select ) {
4040
const {
41-
getBlockOrder,
4241
isSelectionEnabled,
4342
isMultiSelecting,
4443
getMultiSelectedBlockClientIds,
@@ -47,7 +46,6 @@ export default function useMultiSelection( { ref, rootClientId } ) {
4746
} = select( 'core/block-editor' );
4847

4948
return {
50-
blockClientIds: getBlockOrder( rootClientId ),
5149
isSelectionEnabled: isSelectionEnabled(),
5250
isMultiSelecting: isMultiSelecting(),
5351
multiSelectedBlockClientIds: getMultiSelectedBlockClientIds(),
@@ -57,13 +55,12 @@ export default function useMultiSelection( { ref, rootClientId } ) {
5755
}
5856

5957
const {
60-
blockClientIds,
6158
isSelectionEnabled,
6259
isMultiSelecting,
6360
multiSelectedBlockClientIds,
6461
hasMultiSelection,
6562
getBlockParents,
66-
} = useSelect( selector, [ rootClientId ] );
63+
} = useSelect( selector, [] );
6764
const {
6865
startMultiSelect,
6966
stopMultiSelect,
@@ -86,19 +83,9 @@ export default function useMultiSelection( { ref, rootClientId } ) {
8683
// These must be in the right DOM order.
8784
const start = multiSelectedBlockClientIds[ 0 ];
8885
const end = multiSelectedBlockClientIds[ length - 1 ];
89-
const startIndex = blockClientIds.indexOf( start );
9086

91-
// The selected block is not in this block list.
92-
if ( startIndex === -1 ) {
93-
return;
94-
}
95-
96-
let startNode = ref.current.querySelector(
97-
`[data-block="${ start }"]`
98-
);
99-
let endNode = ref.current.querySelector(
100-
`[data-block="${ end }"]`
101-
);
87+
let startNode = getBlockDOMNode( start );
88+
let endNode = getBlockDOMNode( end );
10289

10390
const selection = window.getSelection();
10491
const range = document.createRange();
@@ -117,7 +104,6 @@ export default function useMultiSelection( { ref, rootClientId } ) {
117104
hasMultiSelection,
118105
isMultiSelecting,
119106
multiSelectedBlockClientIds,
120-
blockClientIds,
121107
selectBlock,
122108
] );
123109

0 commit comments

Comments
 (0)