diff --git a/packages/edit-site/src/components/keyboard-shortcuts/edit-mode.js b/packages/edit-site/src/components/keyboard-shortcuts/edit-mode.js index 7d491d54932f53..7b8befdd414a6b 100644 --- a/packages/edit-site/src/components/keyboard-shortcuts/edit-mode.js +++ b/packages/edit-site/src/components/keyboard-shortcuts/edit-mode.js @@ -77,7 +77,10 @@ function KeyboardShortcutsEditMode() { } ); useShortcut( 'core/edit-site/toggle-list-view', () => { - setIsListViewOpened( ! isListViewOpen ); + if ( isListViewOpen ) { + return; + } + setIsListViewOpened( true ); } ); useShortcut( 'core/edit-site/toggle-block-settings-sidebar', ( event ) => { diff --git a/packages/edit-site/src/components/keyboard-shortcuts/index.js b/packages/edit-site/src/components/keyboard-shortcuts/index.js index fa4b1aa6833dc3..a2f06b85d6082b 100644 --- a/packages/edit-site/src/components/keyboard-shortcuts/index.js +++ b/packages/edit-site/src/components/keyboard-shortcuts/index.js @@ -94,7 +94,10 @@ function KeyboardShortcuts() { } ); useShortcut( 'core/edit-site/toggle-list-view', () => { - setIsListViewOpened( ! isListViewOpen ); + if ( ! isListViewOpen ) { + return; + } + setIsListViewOpened( true ); } ); useShortcut( 'core/edit-site/toggle-block-settings-sidebar', ( event ) => { diff --git a/packages/edit-site/src/components/secondary-sidebar/list-view-sidebar.js b/packages/edit-site/src/components/secondary-sidebar/list-view-sidebar.js index 7a19cdc08db114..0e46e99decd2f5 100644 --- a/packages/edit-site/src/components/secondary-sidebar/list-view-sidebar.js +++ b/packages/edit-site/src/components/secondary-sidebar/list-view-sidebar.js @@ -9,10 +9,12 @@ import { useMergeRefs, } from '@wordpress/compose'; import { useDispatch } from '@wordpress/data'; -import { useState } from '@wordpress/element'; +import { useRef, useState } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; import { closeSmall } from '@wordpress/icons'; import { ESCAPE } from '@wordpress/keycodes'; +import { focus } from '@wordpress/dom'; +import { useShortcut } from '@wordpress/keyboard-shortcuts'; /** * Internal dependencies @@ -25,11 +27,9 @@ const { PrivateListView } = unlock( blockEditorPrivateApis ); export default function ListViewSidebar() { const { setIsListViewOpened } = useDispatch( editSiteStore ); - // Use internal state instead of a ref to make sure that the component - // re-renders when the dropZoneElement updates. - const [ dropZoneElement, setDropZoneElement ] = useState( null ); - + // This hook handles focus when the sidebar first renders. const focusOnMountRef = useFocusOnMount( 'firstElement' ); + // The next 2 hooks handle focus for when the sidebar closes and returning focus to the element that had focus before sidebar opened. const headerFocusReturnRef = useFocusReturn(); const contentFocusReturnRef = useFocusReturn(); @@ -39,11 +39,56 @@ export default function ListViewSidebar() { } } + // Use internal state instead of a ref to make sure that the component + // re-renders when the dropZoneElement updates. + const [ dropZoneElement, setDropZoneElement ] = useState( null ); + + // This ref refers to the sidebar as a whole. + const sidebarRef = useRef(); + // This ref refers to the close button. + const sidebarCloseButtonRef = useRef(); + // This ref refers to the list view application area. + const listViewRef = useRef(); + + /* + * Callback function to handle list view or close button focus. + * + * @return void + */ + function handleSidebarFocus() { + // Either focus the list view or the sidebar close button. Must have a fallback because the list view does not render when there are no blocks. + const listViewApplicationFocus = focus.tabbable.find( + listViewRef.current + )[ 0 ]; + const listViewFocusArea = sidebarRef.current.contains( + listViewApplicationFocus + ) + ? listViewApplicationFocus + : sidebarCloseButtonRef.current; + listViewFocusArea.focus(); + } + + // This only fires when the sidebar is open because of the conditional rendering. It is the same shortcut to open but that is defined as a global shortcut and only fires when the sidebar is closed. + useShortcut( 'core/edit-site/toggle-list-view', () => { + // If the sidebar has focus, it is safe to close. + if ( + sidebarRef.current.contains( + sidebarRef.current.ownerDocument.activeElement + ) + ) { + setIsListViewOpened( false ); + // If the list view or close button does not have focus, focus should be moved to it. + } else { + handleSidebarFocus(); + } + } ); + return ( // eslint-disable-next-line jsx-a11y/no-static-element-interactions