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

WIP: List View: Try alternate approach to modifying the shortcut to focus while open #47901

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/e2e-test-utils/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,10 @@ _Returns_

- `Promise`: Promise resolving with a boolean indicating if the focused block is the default block.

### isListViewOpen

Undocumented declaration.

### isOfflineMode

Undocumented declaration.
Expand Down
2 changes: 1 addition & 1 deletion packages/e2e-test-utils/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ export {
rest as __experimentalRest,
batch as __experimentalBatch,
} from './rest-api';
export { openListView, closeListView } from './list-view';
export { isListViewOpen, openListView, closeListView } from './list-view';
export {
disableSiteEditorWelcomeGuide,
getCurrentSiteEditorContent,
Expand Down
2 changes: 1 addition & 1 deletion packages/e2e-test-utils/src/list-view.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ async function toggleListView() {
);
}

async function isListViewOpen() {
export async function isListViewOpen() {
return await page.evaluate( () => {
// selector .edit-post-header-toolbar__list-view-toggle is still required because the performance tests also execute against older versions that still use that selector.
return !! document.querySelector(
Expand Down
84 changes: 84 additions & 0 deletions packages/e2e-tests/specs/editor/various/list-view.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
createNewPost,
insertBlock,
getEditedPostContent,
isListViewOpen,
openListView,
pressKeyWithModifier,
pressKeyTimes,
Expand Down Expand Up @@ -327,4 +328,87 @@ describe( 'List view', () => {
);
await expect( listViewGroupBlockRight ).toHaveFocus();
} );

async function getActiveElementLabel() {
return page.evaluate(
() =>
document.activeElement.getAttribute( 'aria-label' ) ||
document.activeElement.textContent
);
}

// If list view sidebar is open and focus is not inside the sidebar, move focus to the sidebar when using the shortcut. If focus is inside the sidebar, shortcut should close the sidebar.
it( 'ensures the list view global shortcut works properly', async () => {
// Insert some blocks of different types.
await insertBlock( 'Image' );
await insertBlock( 'Paragraph' );
await page.keyboard.type( 'Paragraph text.' );

// Open list view sidebar.
await pressKeyWithModifier( 'access', 'o' );

// Navigate to the image block.
await page.keyboard.press( 'ArrowUp' );
// Check if image block link in the list view has focus by XPath selector.
const listViewImageBlock = await page.waitForXPath(
'//a[contains(., "Image")]'
);
await expect( listViewImageBlock ).toHaveFocus();
// Select the image block in the list view to move focus to it in the canvas.
await page.keyboard.press( 'Enter' );

// Check if image block upload button has focus by XPath selector.
const imageBlockUploadButton = await page.waitForXPath(
'//button[contains(text(), "Upload")]'
);
await expect( imageBlockUploadButton ).toHaveFocus();

// Since focus is now at the image block upload button in the canvas, pressing the list view shortcut should bring focus back to the image block in the list view.
await pressKeyWithModifier( 'access', 'o' );
await expect( listViewImageBlock ).toHaveFocus();

// Since focus is now inside the list view, the shortcut should close the sidebar.
await pressKeyWithModifier( 'access', 'o' );
// Focus should now be on the paragraph block since that is where we opened the list view sidebar. This is not a perfect solution, but current functionality prevents a better way at the moment. Get the current block aria-label and compare.
await expect( await getActiveElementLabel() ).toEqual(
'Paragraph block'
);
// List view sidebar should be closed.
await expect( await isListViewOpen() ).toBeFalsy();

// Open list view sidebar.
await pressKeyWithModifier( 'access', 'o' );

// Focus the list view close button and make sure the shortcut will close the list view. This is to catch a bug where elements could be out of range of the sidebar region. Must shift+tab 3 times to reach cclose button before tabs.
await pressKeyWithModifier( 'shift', 'Tab' );
await pressKeyWithModifier( 'shift', 'Tab' );
await pressKeyWithModifier( 'shift', 'Tab' );
await expect( await getActiveElementLabel() ).toEqual(
'Close Document Overview Sidebar'
);

// Close the list view sidebar.
await pressKeyWithModifier( 'access', 'o' );
// List view sidebar should be closed.
await expect( await isListViewOpen() ).toBeFalsy();

// Open list view sidebar.
await pressKeyWithModifier( 'access', 'o' );

// Focus the outline tab and select it. This test ensures the outline tab receives similar focus events based on the shortcut.
await pressKeyWithModifier( 'shift', 'Tab' );
await expect( await getActiveElementLabel() ).toEqual( 'Outline' );
await page.keyboard.press( 'Enter' );

// From here, tab in to the editor so focus can be checked on return to the outline tab in the sidebar.
await pressKeyTimes( 'Tab', 2 );
// Focus should be placed on the outline tab button since there is nothing to focus inside the tab itself.
await pressKeyWithModifier( 'access', 'o' );
await expect( await getActiveElementLabel() ).toEqual( 'Outline' );

// Close the list view sidebar.
await pressKeyWithModifier( 'access', 'o' );
// List view sidebar should be closed.
await expect( await isListViewOpen() ).toBeFalsy();
} );
} );
8 changes: 5 additions & 3 deletions packages/edit-post/src/components/keyboard-shortcuts/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -250,9 +250,11 @@ function KeyboardShortcuts() {
}
} );

useShortcut( 'core/edit-post/toggle-list-view', () =>
setIsListViewOpened( ! isListViewOpened() )
);
useShortcut( 'core/edit-post/toggle-list-view', () => {
if ( ! isListViewOpened() ) {
setIsListViewOpened( true );
}
} );

useShortcut(
'core/block-editor/transform-heading-to-paragraph',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,22 @@ import classnames from 'classnames';
/**
* WordPress dependencies
*/
import { __experimentalListView as ListView } from '@wordpress/block-editor';
import {
__experimentalListView as ListView,
store as blockEditorStore,
} from '@wordpress/block-editor';
import { Button } from '@wordpress/components';
import {
useFocusOnMount,
useFocusReturn,
useMergeRefs,
} from '@wordpress/compose';
import { useDispatch } from '@wordpress/data';
import { useDispatch, useSelect } from '@wordpress/data';
import { __ } from '@wordpress/i18n';
import { closeSmall } from '@wordpress/icons';
import { useShortcut } from '@wordpress/keyboard-shortcuts';
import { ESCAPE } from '@wordpress/keycodes';
import { useState } from '@wordpress/element';
import { useCallback, useRef, useState } from '@wordpress/element';

/**
* Internal dependencies
Expand All @@ -28,6 +32,13 @@ import ListViewOutline from './list-view-outline';
export default function ListViewSidebar() {
const { setIsListViewOpened } = useDispatch( editPostStore );

const { clientId } = useSelect( ( select ) => {
const { getSelectedBlockClientIds } = select( blockEditorStore );
return {
clientId: getSelectedBlockClientIds()[ 0 ],
};
} );

const focusOnMountRef = useFocusOnMount( 'firstElement' );
const headerFocusReturnRef = useFocusReturn();
const contentFocusReturnRef = useFocusReturn();
Expand All @@ -40,12 +51,53 @@ export default function ListViewSidebar() {

const [ tab, setTab ] = useState( 'list-view' );

// This ref refers to the sidebar as a whole.
const sidebarRef = useRef();
const listViewButtonRef = useRef();
const listViewContainerRef = useRef();
const outlineButtonRef = useRef();

const handleSidebarFocus = useCallback( () => {
if ( tab === 'list-view' && listViewButtonRef?.current?.focus ) {
if ( clientId && listViewContainerRef?.current ) {
// If a block is selected, focus on the corresponding list view item.
const blockElement = listViewContainerRef.current.querySelector(
`[data-block="${ clientId }"] a`
);
if ( blockElement ) {
blockElement.focus();
}
} else {
// If a block is not selected, focus on the list view button.
listViewButtonRef.current.focus();
}
} else if ( tab === 'outline' && outlineButtonRef?.current?.focus ) {
// If the outline tab is selected, focus on the outline button.
outlineButtonRef.current.focus();
}
}, [ clientId ] );

useShortcut( 'core/edit-post/toggle-list-view', () => {
if (
sidebarRef.current.contains(
sidebarRef.current.ownerDocument.activeElement
)
) {
// If the sidebar has focus, it is safe to close.
setIsListViewOpened( false );
} else {
// If the list view or outline does not have focus, focus should be moved to it.
handleSidebarFocus();
}
} );

return (
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
<div
aria-label={ __( 'Document Overview' ) }
className="edit-post-editor__document-overview-panel"
onKeyDown={ closeOnEscape }
ref={ sidebarRef }
>
<div
className="edit-post-editor__document-overview-panel-header components-panel__header edit-post-sidebar__panel-tabs"
Expand All @@ -67,6 +119,7 @@ export default function ListViewSidebar() {
{ 'is-active': tab === 'list-view' }
) }
aria-current={ tab === 'list-view' }
ref={ listViewButtonRef }
>
{ __( 'List View' ) }
</Button>
Expand All @@ -81,6 +134,7 @@ export default function ListViewSidebar() {
{ 'is-active': tab === 'outline' }
) }
aria-current={ tab === 'outline' }
ref={ outlineButtonRef }
>
{ __( 'Outline' ) }
</Button>
Expand All @@ -91,6 +145,7 @@ export default function ListViewSidebar() {
ref={ useMergeRefs( [
contentFocusReturnRef,
focusOnMountRef,
listViewContainerRef,
] ) }
className="edit-post-editor__list-view-container"
>
Expand Down