Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

List View: Allow Escape key to deselect blocks if blocks are selected #48708

Merged
16 changes: 16 additions & 0 deletions packages/block-editor/src/components/list-view/block.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
import { useDispatch, useSelect } from '@wordpress/data';
import { sprintf, __ } from '@wordpress/i18n';
import { focus } from '@wordpress/dom';
import { ESCAPE } from '@wordpress/keycodes';

/**
* Internal dependencies
Expand Down Expand Up @@ -148,6 +149,20 @@ function ListViewBlock( {
}
}, [] );

// If multiple blocks are selected, deselect all blocks when the user
// presses the escape key.
const onKeyDown = ( event ) => {
if (
event.keyCode === ESCAPE &&
! event.defaultPrevented &&
selectedClientIds.length > 0
) {
event.stopPropagation();
event.preventDefault();
selectBlock( event, undefined );
}
};

const onMouseEnter = useCallback( () => {
setIsHovered( true );
toggleBlockHighlight( clientId, true );
Expand Down Expand Up @@ -255,6 +270,7 @@ function ListViewBlock( {
return (
<ListViewLeaf
className={ classes }
onKeyDown={ onKeyDown }
onMouseEnter={ onMouseEnter }
onMouseLeave={ onMouseLeave }
onFocus={ onMouseEnter }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { speak } from '@wordpress/a11y';
import { __, sprintf } from '@wordpress/i18n';
import { useDispatch, useSelect } from '@wordpress/data';
import { useCallback } from '@wordpress/element';
import { UP, DOWN, HOME, END } from '@wordpress/keycodes';
import { UP, DOWN, HOME, END, ESCAPE } from '@wordpress/keycodes';
import { store as blocksStore } from '@wordpress/blocks';

/**
Expand All @@ -30,7 +30,7 @@ export default function useBlockSelection() {

const updateBlockSelection = useCallback(
async ( event, clientId, destinationClientId, focusPosition ) => {
if ( ! event?.shiftKey ) {
if ( ! event?.shiftKey && event?.keyCode !== ESCAPE ) {
selectBlock( clientId, focusPosition );
return;
}
Expand All @@ -39,6 +39,8 @@ export default function useBlockSelection() {
// the browser default behavior of opening the link in a new window.
event.preventDefault();

const isOnlyDeselection =
event.type === 'keydown' && event.keyCode === ESCAPE;
const isKeyPress =
event.type === 'keydown' &&
( event.keyCode === UP ||
Expand All @@ -63,10 +65,11 @@ export default function useBlockSelection() {
];

if (
isKeyPress &&
! selectedBlocks.some( ( blockId ) =>
clientIdWithParents.includes( blockId )
)
isOnlyDeselection ||
( isKeyPress &&
! selectedBlocks.some( ( blockId ) =>
clientIdWithParents.includes( blockId )
) )
) {
// Ensure that shift-selecting blocks via the keyboard only
// expands the current selection if focusing over already
Expand All @@ -75,35 +78,38 @@ export default function useBlockSelection() {
await clearSelectedBlock();
}

let startTarget = getBlockSelectionStart();
let endTarget = clientId;

// Handle keyboard behavior for selecting multiple blocks.
if ( isKeyPress ) {
if ( ! hasSelectedBlock() && ! hasMultiSelection() ) {
// Set the starting point of the selection to the currently
// focused block, if there are no blocks currently selected.
// This ensures that as the selection is expanded or contracted,
// the starting point of the selection is anchored to that block.
startTarget = clientId;
// Update selection, if not only clearing the selection.
if ( ! isOnlyDeselection ) {
let startTarget = getBlockSelectionStart();
let endTarget = clientId;

// Handle keyboard behavior for selecting multiple blocks.
if ( isKeyPress ) {
if ( ! hasSelectedBlock() && ! hasMultiSelection() ) {
// Set the starting point of the selection to the currently
// focused block, if there are no blocks currently selected.
// This ensures that as the selection is expanded or contracted,
// the starting point of the selection is anchored to that block.
startTarget = clientId;
}
if ( destinationClientId ) {
// If the user presses UP or DOWN, we want to ensure that the block they're
// moving to is the target for selection, and not the currently focused one.
endTarget = destinationClientId;
}
}
if ( destinationClientId ) {
// If the user presses UP or DOWN, we want to ensure that the block they're
// moving to is the target for selection, and not the currently focused one.
endTarget = destinationClientId;
}
}

const startParents = getBlockParents( startTarget );
const endParents = getBlockParents( endTarget );
const startParents = getBlockParents( startTarget );
const endParents = getBlockParents( endTarget );

const { start, end } = getCommonDepthClientIds(
startTarget,
endTarget,
startParents,
endParents
);
await multiSelect( start, end, null );
const { start, end } = getCommonDepthClientIds(
startTarget,
endTarget,
startParents,
endParents
);
await multiSelect( start, end, null );
}

// Announce deselected block, or number of deselected blocks if
// the total number of blocks deselected is greater than one.
Expand Down
15 changes: 14 additions & 1 deletion test/e2e/specs/editor/various/list-view.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,7 @@ test.describe( 'List View', () => {
).toBeFocused();
} );

test( 'should duplicate and delete blocks using keyboard', async ( {
test( 'should duplicate, delete, and deselect blocks using keyboard', async ( {
editor,
page,
pageUtils,
Expand Down Expand Up @@ -666,6 +666,19 @@ test.describe( 'List View', () => {
{ name: 'core/file', selected: false, focused: true },
] );
}

// Deselect blocks via Escape key.
await page.keyboard.press( 'Escape' );

await expect
.poll(
listViewUtils.getBlocksWithA11yAttributes,
'Pressing Escape should deselect blocks'
)
.toMatchObject( [
{ name: 'core/heading', selected: false, focused: false },
{ name: 'core/file', selected: false, focused: true },
] );
} );

test( 'block settings dropdown menu', async ( {
Expand Down