Skip to content

Commit

Permalink
Fix navigation in inserter menu triggering writing flow (#11088)
Browse files Browse the repository at this point in the history
* Stop propagation of keyboard events from the block inserter

Preventing propagation ensures that ObserveTyping will no longer trigger the
startTyping action, which transfers focus back to the block level.

* Update comment to reflect that this functionality is now in the ObserveTyping component.

* Add e2e tests to catch regressions
  • Loading branch information
talldan committed Oct 26, 2018
1 parent ccdefc0 commit 5f0ee02
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 9 deletions.
29 changes: 22 additions & 7 deletions packages/editor/src/components/inserter/menu.js
Expand Up @@ -26,6 +26,7 @@ import { withSpokenMessages, PanelBody } from '@wordpress/components';
import { getCategories, isReusableBlock } from '@wordpress/blocks';
import { withDispatch, withSelect } from '@wordpress/data';
import { withInstanceId, compose, withSafeTimeout } from '@wordpress/compose';
import { LEFT, RIGHT, UP, DOWN, BACKSPACE, ENTER } from '@wordpress/keycodes';

/**
* Internal dependencies
Expand All @@ -37,6 +38,8 @@ import InserterInlineElements from './inline-elements';

const MAX_SUGGESTED_ITEMS = 9;

const stopKeyPropagation = ( event ) => event.stopPropagation();

/**
* Filters an item list given a search term.
*
Expand Down Expand Up @@ -218,19 +221,31 @@ export class InserterMenu extends Component {
debouncedSpeak( resultsFoundMessage, 'assertive' );
}

onKeyDown( event ) {
if ( includes( [ LEFT, DOWN, RIGHT, UP, BACKSPACE, ENTER ], event.keyCode ) ) {
// Stop the key event from propagating up to ObserveTyping.startTypingInTextField.
event.stopPropagation();
}
}

render() {
const { instanceId, onSelect, rootClientId } = this.props;
const { childItems, filterValue, hoveredItem, suggestedItems, reusableItems, itemsPerCategory, openPanels } = this.state;
const isPanelOpen = ( panel ) => openPanels.indexOf( panel ) !== -1;
const isSearching = !! filterValue;

// Disable reason: The inserter menu is a modal display, not one which
// is always visible, and one which already incurs this behavior of
// autoFocus via Popover's focusOnMount.

/* eslint-disable jsx-a11y/no-autofocus */
// Disable reason (no-autofocus): The inserter menu is a modal display, not one which
// is always visible, and one which already incurs this behavior of autoFocus via
// Popover's focusOnMount.
// Disable reason (no-static-element-interactions): Navigational key-presses within
// the menu are prevented from triggering WritingFlow and ObserveTyping interactions.
/* eslint-disable jsx-a11y/no-autofocus, jsx-a11y/no-static-element-interactions */
return (
<div className="editor-inserter__menu">
<div
className="editor-inserter__menu"
onKeyPress={ stopKeyPropagation }
onKeyDown={ this.onKeyDown }
>
<label htmlFor={ `editor-inserter__search-${ instanceId }` } className="screen-reader-text">
{ __( 'Search for a block' ) }
</label>
Expand Down Expand Up @@ -317,7 +332,7 @@ export class InserterMenu extends Component {
}
</div>
);
/* eslint-enable jsx-a11y/no-autofocus */
/* eslint-enable jsx-a11y/no-autofocus, jsx-a11y/no-noninteractive-element-interactions */
}
}

Expand Down
2 changes: 1 addition & 1 deletion packages/format-library/src/link/inline.js
Expand Up @@ -123,7 +123,7 @@ class InlineLinkUI extends Component {
}

if ( [ LEFT, DOWN, RIGHT, UP, BACKSPACE, ENTER ].indexOf( event.keyCode ) > -1 ) {
// Stop the key event from propagating up to maybeStartTyping in BlockListBlock.
// Stop the key event from propagating up to ObserveTyping.startTypingInTextField.
event.stopPropagation();
}
}
Expand Down
41 changes: 40 additions & 1 deletion test/e2e/specs/adding-blocks.test.js
Expand Up @@ -9,7 +9,7 @@ import {
} from '../support/utils';

describe( 'adding blocks', () => {
beforeAll( async () => {
beforeEach( async () => {
await newPost();
} );

Expand Down Expand Up @@ -81,4 +81,43 @@ describe( 'adding blocks', () => {

expect( await getEditedPostContent() ).toMatchSnapshot();
} );

// Check for regression of https://github.com/WordPress/gutenberg/issues/9583
it( 'should not allow transfer of focus outside of the block-insertion menu once open', async () => {
// Enter the default block and click the inserter toggle button to the left of it.
await page.keyboard.press( 'ArrowDown' );
await page.click( '.editor-block-list__empty-block-inserter .editor-inserter__toggle' );

// Expect the inserter search input to be the active element.
let activeElementClassList = await page.evaluate( () => document.activeElement.classList );
expect( Object.values( activeElementClassList ) ).toContain( 'editor-inserter__search' );

// Try using the up arrow key (vertical navigation triggers the issue described in #9583).
await page.keyboard.press( 'ArrowUp' );

// Expect the inserter search input to still be the active element.
activeElementClassList = await page.evaluate( () => document.activeElement.classList );
expect( Object.values( activeElementClassList ) ).toContain( 'editor-inserter__search' );

// Tab to the block search results
await page.keyboard.press( 'Tab' );

// Expect the search results to be the active element.
activeElementClassList = await page.evaluate( () => document.activeElement.classList );
expect( Object.values( activeElementClassList ) ).toContain( 'editor-inserter__results' );

// Try using the up arrow key
await page.keyboard.press( 'ArrowUp' );

// Expect the search results to still be the active element.
activeElementClassList = await page.evaluate( () => document.activeElement.classList );
expect( Object.values( activeElementClassList ) ).toContain( 'editor-inserter__results' );

// Press escape to close the block inserter.
await page.keyboard.press( 'Escape' );

// Expect focus to have transferred back to the inserter toggle button.
activeElementClassList = await page.evaluate( () => document.activeElement.classList );
expect( Object.values( activeElementClassList ) ).toContain( 'editor-inserter__toggle' );
} );
} );

0 comments on commit 5f0ee02

Please sign in to comment.