diff --git a/packages/block-editor/src/store/actions.js b/packages/block-editor/src/store/actions.js index 466a9cbeb96c26..a3e56b8d5e50b0 100644 --- a/packages/block-editor/src/store/actions.js +++ b/packages/block-editor/src/store/actions.js @@ -199,6 +199,17 @@ export function clearSelectedBlock() { }; } +/** + * Returns an action object used in restoring the previously cleared selected blocks. + * + * @return {Object} Action object. + */ +export function restoreSelectedBlock() { + return { + type: 'RESTORE_SELECTED_BLOCK', + }; +} + /** * Returns an action object that enables or disables block selection. * diff --git a/packages/block-editor/src/store/reducer.js b/packages/block-editor/src/store/reducer.js index d9d0ecbdd28b64..cf5c95e49cbdc5 100644 --- a/packages/block-editor/src/store/reducer.js +++ b/packages/block-editor/src/store/reducer.js @@ -718,7 +718,20 @@ const BLOCK_SELECTION_INITIAL_STATE = { export function blockSelection( state = BLOCK_SELECTION_INITIAL_STATE, action ) { switch ( action.type ) { case 'CLEAR_SELECTED_BLOCK': - return BLOCK_SELECTION_INITIAL_STATE; + return { + ...BLOCK_SELECTION_INITIAL_STATE, + previousSelection: { + start: state.start, + end: state.end, + isMultiSelecting: state.isMultiSelecting, + isEnabled: state.isEnabled, + initialPosition: state.initialPosition, + }, + }; + case 'RESTORE_SELECTED_BLOCK': + return { + ...state.previousSelection, + }; case 'START_MULTI_SELECT': if ( state.isMultiSelecting ) { return state; diff --git a/packages/e2e-tests/specs/a11y.test.js b/packages/e2e-tests/specs/a11y.test.js index 6f6cc960f204aa..05ec5446fff328 100644 --- a/packages/e2e-tests/specs/a11y.test.js +++ b/packages/e2e-tests/specs/a11y.test.js @@ -2,6 +2,7 @@ * WordPress dependencies */ import { + clickBlockAppender, createNewPost, pressKeyWithModifier, } from '@wordpress/e2e-test-utils'; @@ -29,6 +30,36 @@ describe( 'a11y', () => { expect( isFocusedToggle ).toBe( true ); } ); + it( 'checks persistent selection', async () => { + await clickBlockAppender(); + await page.keyboard.type( 'Testing editor selection persistence' ); + + await page.keyboard.down( 'Control' ); + await page.keyboard.down( 'Shift' ); + await page.keyboard.press( '`' ); + await page.keyboard.press( '`' ); + await page.keyboard.up( 'Control' ); + await page.keyboard.up( 'Shift' ); + + await page.keyboard.press( 'Tab' ); + await page.keyboard.press( 'Space' ); + + let isFocusedParagraphBlock = await page.$eval( ':focus', ( focusedElement ) => { + return focusedElement.classList.contains( 'block-editor-rich-text__editable' ); + } ); + + expect( isFocusedParagraphBlock ).toBe( false ); + + await page.keyboard.press( 'Tab' ); + await page.keyboard.press( 'Space' ); + + isFocusedParagraphBlock = await page.$eval( ':focus', ( focusedElement ) => { + return focusedElement.classList.contains( 'block-editor-rich-text__editable' ); + } ); + + expect( isFocusedParagraphBlock ).toBe( true ); + } ); + it( 'constrains focus to a modal when tabbing', async () => { // Open keyboard help modal. await pressKeyWithModifier( 'access', 'h' ); diff --git a/packages/edit-post/src/components/sidebar/settings-header/index.js b/packages/edit-post/src/components/sidebar/settings-header/index.js index eeb95a872166f5..47d00bce72048a 100644 --- a/packages/edit-post/src/components/sidebar/settings-header/index.js +++ b/packages/edit-post/src/components/sidebar/settings-header/index.js @@ -57,7 +57,8 @@ const SettingsHeader = ( { openDocumentSettings, openBlockSettings, sidebarName export default withDispatch( ( dispatch ) => { const { openGeneralSidebar } = dispatch( 'core/edit-post' ); - const { clearSelectedBlock } = dispatch( 'core/block-editor' ); + const { clearSelectedBlock, restoreSelectedBlock } = dispatch( 'core/block-editor' ); + return { openDocumentSettings() { openGeneralSidebar( 'edit-post/document' ); @@ -65,6 +66,7 @@ export default withDispatch( ( dispatch ) => { }, openBlockSettings() { openGeneralSidebar( 'edit-post/block' ); + restoreSelectedBlock(); }, }; } )( SettingsHeader );