diff --git a/packages/block-editor/src/components/writing-flow/use-multi-selection.js b/packages/block-editor/src/components/writing-flow/use-multi-selection.js index c5b25b25caf64..ecb6858c7355f 100644 --- a/packages/block-editor/src/components/writing-flow/use-multi-selection.js +++ b/packages/block-editor/src/components/writing-flow/use-multi-selection.js @@ -6,7 +6,7 @@ import { first, last } from 'lodash'; /** * WordPress dependencies */ -import { useEffect, useRef } from '@wordpress/element'; +import { useRefEffect } from '@wordpress/compose'; import { useSelect } from '@wordpress/data'; /** @@ -70,7 +70,6 @@ function selector( select ) { } export default function useMultiSelection() { - const ref = useRef(); const { isMultiSelecting, multiSelectedBlockClientIds, @@ -86,70 +85,72 @@ export default function useMultiSelection() { * When the component updates, and there is multi selection, we need to * select the entire block contents. */ - useEffect( () => { - const { ownerDocument } = ref.current; - const { defaultView } = ownerDocument; - - if ( ! hasMultiSelection || isMultiSelecting ) { - if ( ! selectedBlockClientId || isMultiSelecting ) { - return; - } - - const selection = defaultView.getSelection(); + return useRefEffect( + ( node ) => { + const { ownerDocument } = node; + const { defaultView } = ownerDocument; - if ( selection.rangeCount && ! selection.isCollapsed ) { - const blockNode = selectedRef.current; - const { startContainer, endContainer } = selection.getRangeAt( - 0 - ); - - if ( - !! blockNode && - ( ! blockNode.contains( startContainer ) || - ! blockNode.contains( endContainer ) ) - ) { - selection.removeAllRanges(); + if ( ! hasMultiSelection || isMultiSelecting ) { + if ( ! selectedBlockClientId || isMultiSelecting ) { + return; } - } - - return; - } - - const { length } = multiSelectedBlockClientIds; - - if ( length < 2 ) { - return; - } - // For some browsers, like Safari, it is important that focus happens - // BEFORE selection. - ref.current.focus(); - - const selection = defaultView.getSelection(); - const range = ownerDocument.createRange(); + const selection = defaultView.getSelection(); + + if ( selection.rangeCount && ! selection.isCollapsed ) { + const blockNode = selectedRef.current; + const { + startContainer, + endContainer, + } = selection.getRangeAt( 0 ); + + if ( + !! blockNode && + ( ! blockNode.contains( startContainer ) || + ! blockNode.contains( endContainer ) ) + ) { + selection.removeAllRanges(); + } + } - // 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' ); - const endNode = getDeepestNode( endRef.current, 'end' ); + return; + } - // While rich text will be disabled with a delay when there is a multi - // selection, we must do it immediately because it's not possible to set - // selection across editable hosts. - toggleRichText( ref.current, false ); + const { length } = multiSelectedBlockClientIds; - range.setStartBefore( startNode ); - range.setEndAfter( endNode ); + if ( length < 2 ) { + return; + } - selection.removeAllRanges(); - selection.addRange( range ); - }, [ - hasMultiSelection, - isMultiSelecting, - multiSelectedBlockClientIds, - selectedBlockClientId, - ] ); + // For some browsers, like Safari, it is important that focus happens + // BEFORE selection. + node.focus(); - return ref; + 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' ); + const endNode = getDeepestNode( endRef.current, 'end' ); + + // While rich text will be disabled with a delay when there is a multi + // selection, we must do it immediately because it's not possible to set + // selection across editable hosts. + toggleRichText( node, false ); + + range.setStartBefore( startNode ); + range.setEndAfter( endNode ); + + selection.removeAllRanges(); + selection.addRange( range ); + }, + [ + hasMultiSelection, + isMultiSelecting, + multiSelectedBlockClientIds, + selectedBlockClientId, + ] + ); }