Skip to content

Commit

Permalink
Multi-select: use ref callback for focus out, merge native selection …
Browse files Browse the repository at this point in the history
…hooks (#31618)
  • Loading branch information
ellatrix authored May 14, 2021
1 parent 61fd7b2 commit f21f09d
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 38 deletions.
50 changes: 15 additions & 35 deletions packages/block-editor/src/components/writing-flow/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { find, reverse, first, last } from 'lodash';
/**
* WordPress dependencies
*/
import { useRef, useEffect } from '@wordpress/element';
import { useRef } from '@wordpress/element';
import {
computeCaretRect,
focus,
Expand All @@ -28,12 +28,14 @@ import {
} from '@wordpress/keycodes';
import { useSelect, useDispatch } from '@wordpress/data';
import { __ } from '@wordpress/i18n';
import { useMergeRefs } from '@wordpress/compose';

/**
* Internal dependencies
*/
import { isInSameBlock } from '../../utils/dom';
import useMultiSelection from './use-multi-selection';
import useLastFocus from './use-last-focus';
import { store as blockEditorStore } from '../../store';

/**
Expand Down Expand Up @@ -167,17 +169,13 @@ export default function WritingFlow( { children } ) {
// browser behaviour across blocks.
const verticalRect = useRef();

const { hasMultiSelection, isMultiSelecting, isNavigationMode } = useSelect(
( select ) => {
const selectors = select( blockEditorStore );
return {
hasMultiSelection: selectors.hasMultiSelection(),
isMultiSelecting: selectors.isMultiSelecting(),
isNavigationMode: selectors.isNavigationMode(),
};
},
[]
);
const { hasMultiSelection, isNavigationMode } = useSelect( ( select ) => {
const selectors = select( blockEditorStore );
return {
hasMultiSelection: selectors.hasMultiSelection(),
isNavigationMode: selectors.isNavigationMode(),
};
}, [] );
const {
getSelectedBlockClientId,
getMultiSelectedBlocksStartClientId,
Expand Down Expand Up @@ -461,30 +459,8 @@ export default function WritingFlow( { children } ) {
}
}

useEffect( () => {
if ( hasMultiSelection && ! isMultiSelecting ) {
container.current.focus();
}
}, [ hasMultiSelection, isMultiSelecting ] );

// This hook sets the selection after the user makes a multi-selection. For
// some browsers, like Safari, it is important that this happens AFTER
// setting focus on the multi-selection container above.
useMultiSelection( container );

const lastFocus = useRef();

useEffect( () => {
function onFocusOut( event ) {
lastFocus.current = event.target;
}

container.current.addEventListener( 'focusout', onFocusOut );
return () => {
container.current.removeEventListener( 'focusout', onFocusOut );
};
}, [] );

function onFocusCapture( event ) {
// Do not capture incoming focus if set by us in WritingFlow.
if ( noCapture.current ) {
Expand Down Expand Up @@ -521,7 +497,11 @@ export default function WritingFlow( { children } ) {
style={ PREVENT_SCROLL_ON_FOCUS }
/>
<div
ref={ container }
ref={ useMergeRefs( [
container,
useLastFocus( lastFocus ),
useMultiSelection(),
] ) }
className="block-editor-writing-flow"
onKeyDown={ onKeyDown }
onMouseDown={ onMouseDown }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* WordPress dependencies
*/
import { useRefEffect } from '@wordpress/compose';

export default function useLastFocus( lastFocus ) {
return useRefEffect( ( node ) => {
function onFocusOut( event ) {
lastFocus.current = event.target;
}

node.addEventListener( 'focusout', onFocusOut );
return () => {
node.removeEventListener( 'focusout', onFocusOut );
};
}, [] );
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { first, last } from 'lodash';
/**
* WordPress dependencies
*/
import { useEffect } from '@wordpress/element';
import { useEffect, useRef } from '@wordpress/element';
import { useSelect, useDispatch } from '@wordpress/data';

/**
Expand Down Expand Up @@ -57,7 +57,8 @@ function selector( select ) {
};
}

export default function useMultiSelection( ref ) {
export default function useMultiSelection() {
const ref = useRef();
const {
isMultiSelecting,
multiSelectedBlockClientIds,
Expand Down Expand Up @@ -109,11 +110,14 @@ export default function useMultiSelection( ref ) {
return;
}

// These must be in the right DOM order.
// For some browsers, like Safari, it is important that focus
// happens BEFORE selection.
ref.current.focus();

const selection = defaultView.getSelection();
const range = ownerDocument.createRange();

// These must be in the right DOM order.
// The most stable way to select the whole block contents is to start
// and end at the deepest points.
const startNode = getDeepestNode( startRef.current, 'start' );
Expand All @@ -131,4 +135,6 @@ export default function useMultiSelection( ref ) {
selectBlock,
selectedBlockClientId,
] );

return ref;
}

0 comments on commit f21f09d

Please sign in to comment.