Skip to content

Commit

Permalink
Move block focus to be performed only once at the root of the list vi…
Browse files Browse the repository at this point in the history
…ew, instead of within each block
  • Loading branch information
andrewserong committed Oct 3, 2023
1 parent aab67c8 commit d4f40db
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 55 deletions.
46 changes: 3 additions & 43 deletions packages/block-editor/src/components/list-view/block.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,9 @@ import {
} from '@wordpress/components';
import { useInstanceId } from '@wordpress/compose';
import { moreVertical } from '@wordpress/icons';
import {
useState,
useRef,
useEffect,
useCallback,
memo,
} from '@wordpress/element';
import { useState, useRef, useCallback, memo } from '@wordpress/element';
import { useDispatch, useSelect } from '@wordpress/data';
import { sprintf, __ } from '@wordpress/i18n';
import { focus } from '@wordpress/dom';
import { ESCAPE } from '@wordpress/keycodes';

/**
Expand All @@ -36,7 +29,7 @@ import {
} from '../block-mover/button';
import ListViewBlockContents from './block-contents';
import { useListViewContext } from './context';
import { getBlockPositionDescription } from './utils';
import { getBlockPositionDescription, focusListItem } from './utils';
import { store as blockEditorStore } from '../../store';
import useBlockDisplayInformation from '../use-block-display-information';
import { useBlockLock } from '../block-lock';
Expand Down Expand Up @@ -120,7 +113,6 @@ function ListViewBlock( {
);

const {
isTreeGridMounted,
expand,
collapse,
BlockSettingsMenu,
Expand All @@ -142,15 +134,6 @@ function ListViewBlock( {
{ 'is-visible': isHovered || isFirstSelectedBlock }
);

// If ListView has experimental features related to the Persistent List View,
// only focus the selected list item on mount; otherwise the list would always
// try to steal the focus from the editor canvas.
useEffect( () => {
if ( ! isTreeGridMounted && isSelected ) {
cellRef.current.focus();
}
}, [] );

// If multiple blocks are selected, deselect all blocks when the user
// presses the escape key.
const onKeyDown = ( event ) => {
Expand Down Expand Up @@ -188,30 +171,7 @@ function ListViewBlock( {
selectBlock( undefined, focusClientId, null, null );
}

const getFocusElement = () => {
const row = treeGridElementRef.current?.querySelector(
`[role=row][data-block="${ focusClientId }"]`
);
if ( ! row ) return null;
// Focus the first focusable in the row, which is the ListViewBlockSelectButton.
return focus.focusable.find( row )[ 0 ];
};

let focusElement = getFocusElement();
if ( focusElement ) {
focusElement.focus();
} else {
// The element hasn't been painted yet. Defer focusing on the next frame.
// This could happen when all blocks have been deleted and the default block
// hasn't been added to the editor yet.
window.requestAnimationFrame( () => {
focusElement = getFocusElement();
// Ignore if the element still doesn't exist.
if ( focusElement ) {
focusElement.focus();
}
} );
}
focusListItem( focusClientId, treeGridElementRef );
},
[ selectBlock, treeGridElementRef ]
);
Expand Down
15 changes: 7 additions & 8 deletions packages/block-editor/src/components/list-view/branch.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,6 @@ function ListViewBranch( props ) {
// The appender means an extra row in List View, so add 1 to the row count.
const rowCount = showAppender ? blockCount + 1 : blockCount;
let nextPosition = listPosition;
const isSingleBlockSelection = selectedClientIds?.length === 1;

return (
<>
Expand Down Expand Up @@ -170,17 +169,17 @@ function ListViewBranch( props ) {
const isSelectedBranch =
isBranchSelected || ( isSelected && hasNestedBlocks );

// To avoid performance issues, we only render blocks that are
// in view, or blocks that are selected or dragged.
// If a block is selected, it is only counted if it is the only
// block selected. This prevents the entire tree from being
// rendered when a branch is selected, or a user selects all blocks,
// while still enabling scroll into view behavior when selecting a block.
// To avoid performance issues, we only render blocks that are in view,
// or blocks that are selected or dragged. If a block is selected,
// it is only counted if it is the first of the block selection.
// This prevents the entire tree from being rendered when a branch is
// selected, or a user selects all blocks, while still enabling scroll
// into view behavior when selecting a block or opening the list view.
const showBlock =
isDragged ||
blockInView ||
isBranchDragged ||
( isSelected && isSingleBlockSelection );
( isSelected && clientId === selectedClientIds[ 0 ] );
return (
<AsyncModeProvider key={ clientId } value={ ! isSelected }>
{ showBlock && (
Expand Down
12 changes: 8 additions & 4 deletions packages/block-editor/src/components/list-view/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import useListViewDropZone from './use-list-view-drop-zone';
import useListViewExpandSelectedItem from './use-list-view-expand-selected-item';
import { store as blockEditorStore } from '../../store';
import { BlockSettingsDropdown } from '../block-settings-menu/block-settings-dropdown';
import { focusListItem } from './utils';

const expanded = ( state, action ) => {
if ( Array.isArray( action.clientIds ) ) {
Expand Down Expand Up @@ -132,8 +133,6 @@ function ListViewComponent(
const elementRef = useRef();
const treeGridRef = useMergeRefs( [ elementRef, dropZoneRef, ref ] );

const isMounted = useRef( false );

const [ insertedBlock, setInsertedBlock ] = useState( null );

const { setSelectedTreeId } = useListViewExpandSelectedItem( {
Expand All @@ -156,7 +155,13 @@ function ListViewComponent(
[ setSelectedTreeId, updateBlockSelection, onSelect, getBlock ]
);
useEffect( () => {
isMounted.current = true;
// If a blocks are already selected when the list view is initially
// mounted, shift focus to the first selected block.
if ( selectedClientIds?.length ) {
focusListItem( selectedClientIds[ 0 ], elementRef );
}
// Disable reason: Only focus on the selected item when the list view is mounted.
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [] );

const expand = useCallback(
Expand Down Expand Up @@ -204,7 +209,6 @@ function ListViewComponent(

const contextValue = useMemo(
() => ( {
isTreeGridMounted: isMounted.current,
draggedClientIds,
expandedState,
expand,
Expand Down
37 changes: 37 additions & 0 deletions packages/block-editor/src/components/list-view/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* WordPress dependencies
*/
import { __, sprintf } from '@wordpress/i18n';
import { focus } from '@wordpress/dom';

export const getBlockPositionDescription = ( position, siblingCount, level ) =>
sprintf(
Expand Down Expand Up @@ -56,3 +57,39 @@ export function getCommonDepthClientIds(
end,
};
}

/**
* Shift focus to the list view item associated with a particular clientId.
*
* @typedef {import('@wordpress/element').RefObject} RefObject
*
* @param {string} focusClientId The client ID of the block to focus.
* @param {RefObject<HTMLElement>} treeGridElementRef The container element to search within.
*/
export function focusListItem( focusClientId, treeGridElementRef ) {
const getFocusElement = () => {
const row = treeGridElementRef.current?.querySelector(
`[role=row][data-block="${ focusClientId }"]`
);
if ( ! row ) return null;
// Focus the first focusable in the row, which is the ListViewBlockSelectButton.
return focus.focusable.find( row )[ 0 ];
};

let focusElement = getFocusElement();
if ( focusElement ) {
focusElement.focus();
} else {
// The element hasn't been painted yet. Defer focusing on the next frame.
// This could happen when all blocks have been deleted and the default block
// hasn't been added to the editor yet.
window.requestAnimationFrame( () => {
focusElement = getFocusElement();

// Ignore if the element still doesn't exist.
if ( focusElement ) {
focusElement.focus();
}
} );
}
}

0 comments on commit d4f40db

Please sign in to comment.