diff --git a/packages/block-editor/src/components/list-view/block-select-button.js b/packages/block-editor/src/components/list-view/block-select-button.js index d36d0ca998654b..e52fc693afa79d 100644 --- a/packages/block-editor/src/components/list-view/block-select-button.js +++ b/packages/block-editor/src/components/list-view/block-select-button.js @@ -68,8 +68,13 @@ function ListViewBlockSelectButton( getBlocksByClientId, canRemoveBlocks, } = useSelect( blockEditorStore ); - const { duplicateBlocks, multiSelect, removeBlocks } = - useDispatch( blockEditorStore ); + const { + duplicateBlocks, + multiSelect, + removeBlocks, + insertAfterBlock, + insertBeforeBlock, + } = useDispatch( blockEditorStore ); const isMatch = useShortcutEventMatch(); const isSticky = blockInformation?.positionType === 'sticky'; const images = useListViewImages( { clientId, isExpanded } ); @@ -189,6 +194,30 @@ function ListViewBlockSelectButton( updateFocusAndSelection( updatedBlocks[ 0 ], false ); } } + } else if ( isMatch( 'core/block-editor/insert-before', event ) ) { + if ( event.defaultPrevented ) { + return; + } + event.preventDefault(); + + const { blocksToUpdate } = getBlocksToUpdate(); + await insertBeforeBlock( blocksToUpdate[ 0 ] ); + const newlySelectedBlocks = getSelectedBlockClientIds(); + + // Focus the first block of the newly inserted blocks, to keep focus within the list view. + updateFocusAndSelection( newlySelectedBlocks[ 0 ], false ); + } else if ( isMatch( 'core/block-editor/insert-after', event ) ) { + if ( event.defaultPrevented ) { + return; + } + event.preventDefault(); + + const { blocksToUpdate } = getBlocksToUpdate(); + await insertAfterBlock( blocksToUpdate.at( -1 ) ); + const newlySelectedBlocks = getSelectedBlockClientIds(); + + // Focus the first block of the newly inserted blocks, to keep focus within the list view. + updateFocusAndSelection( newlySelectedBlocks[ 0 ], false ); } else if ( isMatch( 'core/block-editor/select-all', event ) ) { if ( event.defaultPrevented ) { return; diff --git a/test/e2e/specs/editor/various/list-view.spec.js b/test/e2e/specs/editor/various/list-view.spec.js index 5a3ffbc8a3c96e..8c14711084389b 100644 --- a/test/e2e/specs/editor/various/list-view.spec.js +++ b/test/e2e/specs/editor/various/list-view.spec.js @@ -496,7 +496,7 @@ test.describe( 'List View', () => { ).toBeFocused(); } ); - test( 'should cut, copy, paste, select, duplicate, delete, and deselect blocks using keyboard', async ( { + test( 'should cut, copy, paste, select, duplicate, insert, delete, and deselect blocks using keyboard', async ( { editor, page, pageUtils, @@ -663,8 +663,44 @@ test.describe( 'List View', () => { { name: 'core/file', focused: true }, ] ); - // Move focus to the first file block, and then delete it. - await page.keyboard.press( 'ArrowUp' ); + // Test insert before. + await pageUtils.pressKeys( 'primaryAlt+t' ); + + await expect + .poll( + listViewUtils.getBlocksWithA11yAttributes, + 'Inserting a block before should move selection and focus to the inserted block.' + ) + .toMatchObject( [ + { name: 'core/group' }, + { name: 'core/columns' }, + { name: 'core/file', selected: false }, + { name: 'core/paragraph', focused: true, selected: true }, + { name: 'core/file', selected: false }, + ] ); + + // Test insert after. + await pageUtils.pressKeys( 'primaryAlt+y' ); + + await expect + .poll( + listViewUtils.getBlocksWithA11yAttributes, + 'Inserting a block before should move selection and focus to the inserted block.' + ) + .toMatchObject( [ + { name: 'core/group' }, + { name: 'core/columns' }, + { name: 'core/file', selected: false }, + { name: 'core/paragraph', focused: false, selected: false }, + { name: 'core/paragraph', focused: true, selected: true }, + { name: 'core/file', selected: false }, + ] ); + + // Remove the inserted blocks. + await page.keyboard.press( 'Delete' ); + await page.keyboard.press( 'Delete' ); + + // Delete the first File block. await page.keyboard.press( 'Delete' ); await expect .poll(