diff --git a/packages/block-editor/src/components/list-view/index.js b/packages/block-editor/src/components/list-view/index.js index 8ce9f492b44ce2..f79eaeb58ccebd 100644 --- a/packages/block-editor/src/components/list-view/index.js +++ b/packages/block-editor/src/components/list-view/index.js @@ -24,6 +24,7 @@ import ListViewDropIndicator from './drop-indicator'; import useListViewClientIds from './use-list-view-client-ids'; import useListViewDropZone from './use-list-view-drop-zone'; import { store as blockEditorStore } from '../../store'; +import { hasFocusWithin } from './utils'; const noop = () => {}; const expanded = ( state, action ) => { @@ -65,7 +66,11 @@ function ListView( }, ref ) { - const { clientIdsTree, draggedClientIds } = useListViewClientIds( blocks ); + const { + clientIdsTree, + draggedClientIds, + selectedBlockParentIds, + } = useListViewClientIds( blocks ); const { selectBlock } = useDispatch( blockEditorStore ); const selectEditorBlock = useCallback( ( clientId ) => { @@ -75,12 +80,12 @@ function ListView( [ selectBlock, onSelect ] ); const [ expandedState, setExpandedState ] = useReducer( expanded, {} ); - const { ref: dropZoneRef, target: blockDropTarget } = useListViewDropZone(); const elementRef = useRef(); const treeGridRef = useMergeRefs( [ elementRef, dropZoneRef, ref ] ); - const isMounted = useRef( false ); + const hasFocus = hasFocusWithin( elementRef?.current ); + useEffect( () => { isMounted.current = true; }, [] ); @@ -139,6 +144,26 @@ function ListView( ] ); + // If a selection is made outside the block list, + // for example, in the Block Editor, + // try to expand the block list tree. + useEffect( () => { + if ( + ! hasFocus && + Array.isArray( selectedBlockParentIds ) && + selectedBlockParentIds.length + ) { + selectedBlockParentIds.forEach( ( clientId ) => { + if ( ! expandedState[ clientId ] ) { + setExpandedState( { + type: 'expand', + clientId, + } ); + } + } ); + } + }, [ hasFocus, selectedBlockParentIds ] ); + return ( isArray( selectedBlockClientIds ) && selectedBlockClientIds.length ? selectedBlockClientIds.indexOf( clientId ) !== -1 : selectedBlockClientIds === clientId; + +/** + * Returns true if the container contains the document active element. + * + * @param {HTMLElement} container An HTML element. + * + * @return {boolean} Whether the container contains the currently document active element. + */ +export const hasFocusWithin = ( container ) => { + return !! container?.contains( container?.ownerDocument?.activeElement ); +};