From 5be2cb90e314caf0597aa5eb529eb1b74a84e684 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ella=20van=C2=A0Durpe?= Date: Sat, 20 Mar 2021 17:16:48 +0200 Subject: [PATCH 1/2] Writing flow: remove arrow nav limitations --- .../src/components/writing-flow/index.js | 52 +++---------------- packages/block-editor/src/utils/dom.js | 27 ---------- packages/block-editor/src/utils/test/dom.js | 35 ------------- 3 files changed, 6 insertions(+), 108 deletions(-) delete mode 100644 packages/block-editor/src/utils/test/dom.js diff --git a/packages/block-editor/src/components/writing-flow/index.js b/packages/block-editor/src/components/writing-flow/index.js index 03cb5858020789..045cdbfc84a533 100644 --- a/packages/block-editor/src/components/writing-flow/index.js +++ b/packages/block-editor/src/components/writing-flow/index.js @@ -12,7 +12,6 @@ import { computeCaretRect, focus, isHorizontalEdge, - isTextField, isVerticalEdge, placeCaretAtHorizontalEdge, placeCaretAtVerticalEdge, @@ -34,9 +33,7 @@ import { __ } from '@wordpress/i18n'; * Internal dependencies */ import { - isBlockFocusStop, isInSameBlock, - hasInnerBlocksContext, isInsideRootBlock, getBlockDOMNode, getBlockClientId, @@ -115,12 +112,17 @@ export function getClosestTabbable( targetRect = target.getBoundingClientRect(); } - function isTabCandidate( node, i, array ) { + function isTabCandidate( node ) { // Not a candidate if the node is not tabbable. if ( ! focus.tabbable.isTabbableIndex( node ) ) { return false; } + // Skip focusable elements such as links within content editable nodes. + if ( node.isContentEditable && node.contentEditable !== 'true' ) { + return false; + } + if ( onlyVertical ) { const nodeRect = node.getBoundingClientRect(); @@ -132,48 +134,6 @@ export function getClosestTabbable( } } - // Prefer text fields... - if ( isTextField( node ) ) { - return true; - } - - // ...but settle for block focus stop. - if ( ! isBlockFocusStop( node ) ) { - return false; - } - - // If element contains inner blocks, stop immediately at its focus - // wrapper. - if ( hasInnerBlocksContext( node ) ) { - return true; - } - - // If navigating out of a block (in reverse), don't consider its - // block focus stop. - if ( node.contains( target ) ) { - return false; - } - - // In case of block focus stop, check to see if there's a better - // text field candidate within. - for ( - let offset = 1, nextNode; - ( nextNode = array[ i + offset ] ); - offset++ - ) { - // Abort if no longer testing descendents of focus stop. - if ( ! node.contains( nextNode ) ) { - break; - } - - // Apply same tests by recursion. This is important to consider - // nestable blocks where we don't want to settle for the inner - // block focus stop. - if ( isTabCandidate( nextNode, i + offset, array ) ) { - return false; - } - } - return true; } diff --git a/packages/block-editor/src/utils/dom.js b/packages/block-editor/src/utils/dom.js index 4f9c971ccd0771..248587311d1d2b 100644 --- a/packages/block-editor/src/utils/dom.js +++ b/packages/block-editor/src/utils/dom.js @@ -31,18 +31,6 @@ export function getBlockPreviewContainerDOMNode( clientId, doc ) { return domNode.firstChild || domNode; } -/** - * Returns true if the given element is a block focus stop. Blocks without their - * own text fields rely on the focus stop to be keyboard navigable. - * - * @param {Element} element Element to test. - * - * @return {boolean} Whether element is a block focus stop. - */ -export function isBlockFocusStop( element ) { - return element.classList.contains( 'block-editor-block-list__block' ); -} - /** * Returns true if two elements are contained within the same block. * @@ -73,21 +61,6 @@ export function isInsideRootBlock( blockElement, element ) { return parentBlock === blockElement; } -/** - * Returns true if the given element contains inner blocks (an InnerBlocks - * element). - * - * @param {Element} element Element to test. - * - * @return {boolean} Whether element contains inner blocks. - */ -export function hasInnerBlocksContext( element ) { - return ( - element.classList.contains( 'block-editor-block-list__layout' ) || - !! element.querySelector( '.block-editor-block-list__layout' ) - ); -} - /** * Finds the block client ID given any DOM node inside the block. * diff --git a/packages/block-editor/src/utils/test/dom.js b/packages/block-editor/src/utils/test/dom.js deleted file mode 100644 index b755f74bcb899f..00000000000000 --- a/packages/block-editor/src/utils/test/dom.js +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Internal dependencies - */ -import { hasInnerBlocksContext } from '../dom'; - -describe( 'hasInnerBlocksContext()', () => { - it( 'should return false for a block node which has no inner blocks', () => { - const wrapper = document.createElement( 'div' ); - wrapper.innerHTML = - '
' + - '
' + - '

This is a test.

' + - '
' + - '
'; - - const blockNode = wrapper.firstChild; - expect( hasInnerBlocksContext( blockNode ) ).toBe( false ); - } ); - - it( 'should return true for a block node which contains inner blocks', () => { - const wrapper = document.createElement( 'div' ); - wrapper.innerHTML = - '
' + - '
' + - '
' + - '
' + - '
' + - '
' + - '
' + - '
'; - - const blockNode = wrapper.firstChild; - expect( hasInnerBlocksContext( blockNode ) ).toBe( true ); - } ); -} ); From 05bd07d0c03af901b9164b9a4e98a2f063e2b449 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ella=20van=C2=A0Durpe?= Date: Sat, 20 Mar 2021 17:47:50 +0200 Subject: [PATCH 2/2] Adjust e2e test --- packages/e2e-tests/specs/editor/blocks/quote.test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/e2e-tests/specs/editor/blocks/quote.test.js b/packages/e2e-tests/specs/editor/blocks/quote.test.js index e185c9e3c7cd70..5e71c3d4aaaf5b 100644 --- a/packages/e2e-tests/specs/editor/blocks/quote.test.js +++ b/packages/e2e-tests/specs/editor/blocks/quote.test.js @@ -237,6 +237,7 @@ describe( 'Quote', () => { await page.keyboard.press( 'ArrowLeft' ); await page.keyboard.press( 'ArrowDown' ); await page.keyboard.press( 'ArrowDown' ); + await page.keyboard.press( 'ArrowDown' ); await page.keyboard.press( 'Backspace' ); expect( await getEditedPostContent() ).toMatchSnapshot();