diff --git a/packages/editor/src/components/writing-flow/index.js b/packages/editor/src/components/writing-flow/index.js index e13b81eaf6dfd..6f85e5ed1e8af 100644 --- a/packages/editor/src/components/writing-flow/index.js +++ b/packages/editor/src/components/writing-flow/index.js @@ -49,6 +49,29 @@ const isTabbableTextField = overEvery( [ focus.tabbable.isTabbableIndex, ] ); +/** + * Returns true if the element should consider edge navigation upon a keyboard + * event of the given directional key code, or false otherwise. + * + * @param {Element} element HTML element to test. + * @param {number} keyCode KeyboardEvent keyCode to test. + * @param {boolean} hasModifier Whether a modifier is pressed. + * + * @return {boolean} Whether element should consider edge navigation. + */ +export function isNavigationCandidate( element, keyCode, hasModifier ) { + const isVertical = ( keyCode === UP || keyCode === DOWN ); + + // Currently, all elements support unmodified vertical navigation. + if ( isVertical && ! hasModifier ) { + return true; + } + + // Native inputs should not navigate horizontally. + const { tagName } = element; + return tagName !== 'INPUT' && tagName !== 'TEXTAREA'; +} + class WritingFlow extends Component { constructor() { super( ...arguments ); @@ -209,6 +232,7 @@ class WritingFlow extends Component { const isVertical = isUp || isDown; const isNav = isHorizontal || isVertical; const isShift = event.shiftKey; + const hasModifier = isShift || event.ctrlKey || event.altKey || event.metaKey; const isNavEdge = isVertical ? isVerticalEdge : isHorizontalEdge; // This logic inside this condition needs to be checked before @@ -243,6 +267,12 @@ class WritingFlow extends Component { return; } + // Abort if our current target is not a candidate for navigation (e.g. + // preserve native input behaviors). + if ( ! isNavigationCandidate( target, keyCode, hasModifier ) ) { + return; + } + if ( ! isVertical ) { this.verticalRect = null; } else if ( ! this.verticalRect ) { diff --git a/packages/editor/src/components/writing-flow/test/index.js b/packages/editor/src/components/writing-flow/test/index.js new file mode 100644 index 0000000000000..88ff30f107a72 --- /dev/null +++ b/packages/editor/src/components/writing-flow/test/index.js @@ -0,0 +1,51 @@ +/** + * WordPress dependencies + */ +import { UP, DOWN, LEFT, RIGHT } from '@wordpress/keycodes'; + +/** + * Internal dependencies + */ +import { isNavigationCandidate } from '../'; + +describe( 'isNavigationCandidate', () => { + let elements; + beforeAll( () => { + elements = {}; + elements.input = document.createElement( 'input' ); + elements.contentEditable = document.createElement( 'p' ); + elements.contentEditable.contentEditable = true; + } ); + + it( 'should return true if vertically navigating input without modifier', () => { + [ UP, DOWN ].forEach( ( keyCode ) => { + const result = isNavigationCandidate( elements.input, keyCode, false ); + + expect( result ).toBe( true ); + } ); + } ); + + it( 'should return false if vertically navigating input with modifier', () => { + [ UP, DOWN ].forEach( ( keyCode ) => { + const result = isNavigationCandidate( elements.input, keyCode, true ); + + expect( result ).toBe( false ); + } ); + } ); + + it( 'should return false if horizontally navigating input', () => { + [ LEFT, RIGHT ].forEach( ( keyCode ) => { + const result = isNavigationCandidate( elements.input, keyCode, false ); + + expect( result ).toBe( false ); + } ); + } ); + + it( 'should return true if horizontally navigating non-input', () => { + [ LEFT, RIGHT ].forEach( ( keyCode ) => { + const result = isNavigationCandidate( elements.contentEditable, keyCode, false ); + + expect( result ).toBe( true ); + } ); + } ); +} ); diff --git a/test/e2e/specs/writing-flow.test.js b/test/e2e/specs/writing-flow.test.js index 2d484b958b416..67c91280ba410 100644 --- a/test/e2e/specs/writing-flow.test.js +++ b/test/e2e/specs/writing-flow.test.js @@ -195,4 +195,32 @@ describe( 'adding blocks', () => { await pressWithModifier( 'Shift', 'Enter' ); expect( await getEditedPostContent() ).toMatchSnapshot(); } ); + + it( 'should navigate native inputs vertically, not horizontally', async () => { + // See: https://github.com/WordPress/gutenberg/issues/9626 + + // Title is within the editor's writing flow, and is a