Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { useRefEffect } from '@wordpress/compose';
/**
* Internal dependencies
*/
import { getBlockClientId, isInSameBlock } from '../../utils/dom';
import { getBlockClientId } from '../../utils/dom';
import { store as blockEditorStore } from '../../store';

/**
Expand Down Expand Up @@ -114,18 +114,13 @@ export function getClosestTabbable(
}

function isTabCandidate( node ) {
if ( node.closest( '[inert]' ) ) {
return;
}

// Skip if there's only one child that is content editable (and thus a
// better candidate).
// If it's a block and there are nested focusable nodes, skip because
// there are better candidates.
if (
node.children.length === 1 &&
isInSameBlock( node, node.firstElementChild ) &&
node.firstElementChild.getAttribute( 'contenteditable' ) === 'true'
getBlockClientId( node ) &&
focus.focusable.find( node ).length !== 0
) {
return;
return false;
}

// Not a candidate if the node is not tabbable.
Expand Down
5 changes: 5 additions & 0 deletions packages/dom/src/focusable.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ export function find( context, { sequential = false } = {} ) {
return false;
}

// Elements inside an inert subtree are not focusable.
if ( element.closest( '[inert]' ) ) {
return false;
}

const { nodeName } = element;
if ( 'AREA' === nodeName ) {
return isValidFocusableArea(
Expand Down
30 changes: 30 additions & 0 deletions packages/dom/src/test/focusable.js
Original file line number Diff line number Diff line change
Expand Up @@ -157,5 +157,35 @@ describe( 'focusable', () => {

expect( find( node ) ).toEqual( [] );
} );

it( 'ignores elements inside inert containers', () => {
const node = createElement( 'div' );
const inertDiv = createElement( 'div' );
inertDiv.setAttribute( 'inert', '' );
const input = createElement( 'input' );
inertDiv.appendChild( input );
node.appendChild( inertDiv );

expect( find( node ) ).toEqual( [] );
} );

it( 'returns focusable elements outside inert containers', () => {
const node = createElement( 'div' );

// Inert container with input
const inertDiv = createElement( 'div' );
inertDiv.setAttribute( 'inert', '' );
const inertInput = createElement( 'input' );
inertDiv.appendChild( inertInput );
node.appendChild( inertDiv );

// Non-inert input
const visibleInput = createElement( 'input' );
node.appendChild( visibleInput );

const focusable = find( node );
expect( focusable ).toHaveLength( 1 );
expect( focusable[ 0 ] ).toBe( visibleInput );
} );
} );
} );
17 changes: 11 additions & 6 deletions test/e2e/specs/editor/blocks/navigation.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -426,8 +426,9 @@
await navigation.useLinkShortcut();

await navigation.addSubmenuPage( 'Dog' );
await pageUtils.pressKeys( 'ArrowUp' );
await pageUtils.pressKeys( 'ArrowRight' );
// Navigate to the Dog link content using ArrowLeft (ArrowUp skips
// blocks with nested focusables).
await pageUtils.pressKeys( 'ArrowLeft', { times: 2 } );
} );

await test.step( 'can use the shortcut to open the preview with the keyboard and escape keypress sends focus back to the navigation link block in the submenu', async () => {
Expand Down Expand Up @@ -512,8 +513,9 @@
*/
// Exit the toolbar
await page.keyboard.press( 'Escape' );
// Move to the submenu item
await pageUtils.pressKeys( 'ArrowUp', { times: 2 } );
// Move to the submenu item (only one ArrowUp needed - skips the
// submenu wrapper directly to Cat's content)
await page.keyboard.press( 'ArrowUp' );
await page.keyboard.press( 'Home' );

// Check we're on our submenu link
Expand Down Expand Up @@ -575,9 +577,12 @@
await navigation.addCustomURL( 'https://wordpress.org' );
await navigation.expectToHaveTextSelected( 'wordpress.org' );

await pageUtils.pressKeys( 'ArrowUp', { times: 2 } );
// One ArrowUp to get to Dog (skips wrapper)
await page.keyboard.press( 'ArrowUp' );
await navigation.checkLabelFocus( 'Dog' );
await pageUtils.pressKeys( 'ArrowUp', { times: 1 } );
// Use Cmd+A twice to select the block (since ArrowUp no longer goes to wrapper)
await pageUtils.pressKeys( 'primary+a' );
await pageUtils.pressKeys( 'primary+a' );
await pageUtils.pressKeys( 'access+z' );
await pageUtils.pressKeys( 'ArrowDown' );
await navigation.checkLabelFocus( 'example.com' );
Expand Down Expand Up @@ -2155,7 +2160,7 @@
await this.editor.canvas
.locator( ':root' )
.evaluate( () => window.getSelection().toString() )
).toBe( text );

Check failure on line 2163 in test/e2e/specs/editor/blocks/navigation.spec.js

View workflow job for this annotation

GitHub Actions / Playwright - 2

[chromium] › test/e2e/specs/editor/blocks/navigation.spec.js:535:3 › Navigation block › Focus management › Deleting items

1) [chromium] › test/e2e/specs/editor/blocks/navigation.spec.js:535:3 › Navigation block › Focus management › Deleting items Retry #2 ─────────────────────────────────────────────────────────────────────────────────────── Error: expect(received).toBe(expected) // Object.is equality Expected: "example.com" Received: "wordpress.org" 2161 | .locator( ':root' ) 2162 | .evaluate( () => window.getSelection().toString() ) > 2163 | ).toBe( text ); | ^ 2164 | } 2165 | 2166 | /** at Navigation.expectToHaveTextSelected (/home/runner/work/gutenberg/gutenberg/test/e2e/specs/editor/blocks/navigation.spec.js:2163:5) at Navigation.checkLabelFocus (/home/runner/work/gutenberg/gutenberg/test/e2e/specs/editor/blocks/navigation.spec.js:2189:3) at /home/runner/work/gutenberg/gutenberg/test/e2e/specs/editor/blocks/navigation.spec.js:588:4

Check failure on line 2163 in test/e2e/specs/editor/blocks/navigation.spec.js

View workflow job for this annotation

GitHub Actions / Playwright - 2

[chromium] › test/e2e/specs/editor/blocks/navigation.spec.js:535:3 › Navigation block › Focus management › Deleting items

1) [chromium] › test/e2e/specs/editor/blocks/navigation.spec.js:535:3 › Navigation block › Focus management › Deleting items Retry #1 ─────────────────────────────────────────────────────────────────────────────────────── Error: expect(received).toBe(expected) // Object.is equality Expected: "example.com" Received: "wordpress.org" 2161 | .locator( ':root' ) 2162 | .evaluate( () => window.getSelection().toString() ) > 2163 | ).toBe( text ); | ^ 2164 | } 2165 | 2166 | /** at Navigation.expectToHaveTextSelected (/home/runner/work/gutenberg/gutenberg/test/e2e/specs/editor/blocks/navigation.spec.js:2163:5) at Navigation.checkLabelFocus (/home/runner/work/gutenberg/gutenberg/test/e2e/specs/editor/blocks/navigation.spec.js:2189:3) at /home/runner/work/gutenberg/gutenberg/test/e2e/specs/editor/blocks/navigation.spec.js:588:4

Check failure on line 2163 in test/e2e/specs/editor/blocks/navigation.spec.js

View workflow job for this annotation

GitHub Actions / Playwright - 2

[chromium] › test/e2e/specs/editor/blocks/navigation.spec.js:535:3 › Navigation block › Focus management › Deleting items

1) [chromium] › test/e2e/specs/editor/blocks/navigation.spec.js:535:3 › Navigation block › Focus management › Deleting items Error: expect(received).toBe(expected) // Object.is equality Expected: "example.com" Received: "wordpress.org" 2161 | .locator( ':root' ) 2162 | .evaluate( () => window.getSelection().toString() ) > 2163 | ).toBe( text ); | ^ 2164 | } 2165 | 2166 | /** at Navigation.expectToHaveTextSelected (/home/runner/work/gutenberg/gutenberg/test/e2e/specs/editor/blocks/navigation.spec.js:2163:5) at Navigation.checkLabelFocus (/home/runner/work/gutenberg/gutenberg/test/e2e/specs/editor/blocks/navigation.spec.js:2189:3) at /home/runner/work/gutenberg/gutenberg/test/e2e/specs/editor/blocks/navigation.spec.js:588:4
}

/**
Expand Down
29 changes: 29 additions & 0 deletions test/e2e/specs/editor/various/writing-flow.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
// Arrow up in inner blocks should navigate through (1) column wrapper,
// (2) text fields.
await page.keyboard.press( 'ArrowUp' );
await expect

Check failure on line 48 in test/e2e/specs/editor/various/writing-flow.spec.js

View workflow job for this annotation

GitHub Actions / Playwright - 7

[webkit] › test/e2e/specs/editor/various/writing-flow.spec.js:24:2 › Writing Flow (@firefox

2) [webkit] › test/e2e/specs/editor/various/writing-flow.spec.js:24:2 › Writing Flow (@Firefox, @WebKit) › Should navigate inner blocks with arrow keys Retry #2 ─────────────────────────────────────────────────────────────────────────────────────── Error: expect(received).toBe(expected) // Object.is equality Expected: "core/column" Received: "core/paragraph" Call Log: - Timeout 5000ms exceeded while waiting on the predicate 46 | // (2) text fields. 47 | await page.keyboard.press( 'ArrowUp' ); > 48 | await expect | ^ 49 | .poll( writingFlowUtils.getActiveBlockName ) 50 | .toBe( 'core/column' ); 51 | await page.keyboard.press( 'ArrowUp' ); at /home/runner/work/gutenberg/gutenberg/test/e2e/specs/editor/various/writing-flow.spec.js:48:3

Check failure on line 48 in test/e2e/specs/editor/various/writing-flow.spec.js

View workflow job for this annotation

GitHub Actions / Playwright - 7

[webkit] › test/e2e/specs/editor/various/writing-flow.spec.js:24:2 › Writing Flow (@firefox

2) [webkit] › test/e2e/specs/editor/various/writing-flow.spec.js:24:2 › Writing Flow (@Firefox, @WebKit) › Should navigate inner blocks with arrow keys Retry #1 ─────────────────────────────────────────────────────────────────────────────────────── Error: expect(received).toBe(expected) // Object.is equality Expected: "core/column" Received: "core/paragraph" Call Log: - Timeout 5000ms exceeded while waiting on the predicate 46 | // (2) text fields. 47 | await page.keyboard.press( 'ArrowUp' ); > 48 | await expect | ^ 49 | .poll( writingFlowUtils.getActiveBlockName ) 50 | .toBe( 'core/column' ); 51 | await page.keyboard.press( 'ArrowUp' ); at /home/runner/work/gutenberg/gutenberg/test/e2e/specs/editor/various/writing-flow.spec.js:48:3

Check failure on line 48 in test/e2e/specs/editor/various/writing-flow.spec.js

View workflow job for this annotation

GitHub Actions / Playwright - 7

[webkit] › test/e2e/specs/editor/various/writing-flow.spec.js:24:2 › Writing Flow (@firefox

2) [webkit] › test/e2e/specs/editor/various/writing-flow.spec.js:24:2 › Writing Flow (@Firefox, @WebKit) › Should navigate inner blocks with arrow keys Error: expect(received).toBe(expected) // Object.is equality Expected: "core/column" Received: "core/paragraph" Call Log: - Timeout 5000ms exceeded while waiting on the predicate 46 | // (2) text fields. 47 | await page.keyboard.press( 'ArrowUp' ); > 48 | await expect | ^ 49 | .poll( writingFlowUtils.getActiveBlockName ) 50 | .toBe( 'core/column' ); 51 | await page.keyboard.press( 'ArrowUp' ); at /home/runner/work/gutenberg/gutenberg/test/e2e/specs/editor/various/writing-flow.spec.js:48:3

Check failure on line 48 in test/e2e/specs/editor/various/writing-flow.spec.js

View workflow job for this annotation

GitHub Actions / Playwright - 5

[chromium] › test/e2e/specs/editor/various/writing-flow.spec.js:24:2 › Writing Flow (@firefox

3) [chromium] › test/e2e/specs/editor/various/writing-flow.spec.js:24:2 › Writing Flow (@Firefox, @WebKit) › Should navigate inner blocks with arrow keys Retry #2 ─────────────────────────────────────────────────────────────────────────────────────── Error: expect(received).toBe(expected) // Object.is equality Expected: "core/column" Received: "core/paragraph" Call Log: - Timeout 5000ms exceeded while waiting on the predicate 46 | // (2) text fields. 47 | await page.keyboard.press( 'ArrowUp' ); > 48 | await expect | ^ 49 | .poll( writingFlowUtils.getActiveBlockName ) 50 | .toBe( 'core/column' ); 51 | await page.keyboard.press( 'ArrowUp' ); at /home/runner/work/gutenberg/gutenberg/test/e2e/specs/editor/various/writing-flow.spec.js:48:3

Check failure on line 48 in test/e2e/specs/editor/various/writing-flow.spec.js

View workflow job for this annotation

GitHub Actions / Playwright - 5

[chromium] › test/e2e/specs/editor/various/writing-flow.spec.js:24:2 › Writing Flow (@firefox

3) [chromium] › test/e2e/specs/editor/various/writing-flow.spec.js:24:2 › Writing Flow (@Firefox, @WebKit) › Should navigate inner blocks with arrow keys Retry #1 ─────────────────────────────────────────────────────────────────────────────────────── Error: expect(received).toBe(expected) // Object.is equality Expected: "core/column" Received: "core/paragraph" Call Log: - Timeout 5000ms exceeded while waiting on the predicate 46 | // (2) text fields. 47 | await page.keyboard.press( 'ArrowUp' ); > 48 | await expect | ^ 49 | .poll( writingFlowUtils.getActiveBlockName ) 50 | .toBe( 'core/column' ); 51 | await page.keyboard.press( 'ArrowUp' ); at /home/runner/work/gutenberg/gutenberg/test/e2e/specs/editor/various/writing-flow.spec.js:48:3

Check failure on line 48 in test/e2e/specs/editor/various/writing-flow.spec.js

View workflow job for this annotation

GitHub Actions / Playwright - 5

[chromium] › test/e2e/specs/editor/various/writing-flow.spec.js:24:2 › Writing Flow (@firefox

3) [chromium] › test/e2e/specs/editor/various/writing-flow.spec.js:24:2 › Writing Flow (@Firefox, @WebKit) › Should navigate inner blocks with arrow keys Error: expect(received).toBe(expected) // Object.is equality Expected: "core/column" Received: "core/paragraph" Call Log: - Timeout 5000ms exceeded while waiting on the predicate 46 | // (2) text fields. 47 | await page.keyboard.press( 'ArrowUp' ); > 48 | await expect | ^ 49 | .poll( writingFlowUtils.getActiveBlockName ) 50 | .toBe( 'core/column' ); 51 | await page.keyboard.press( 'ArrowUp' ); at /home/runner/work/gutenberg/gutenberg/test/e2e/specs/editor/various/writing-flow.spec.js:48:3
.poll( writingFlowUtils.getActiveBlockName )
.toBe( 'core/column' );
await page.keyboard.press( 'ArrowUp' );
Expand Down Expand Up @@ -106,6 +106,35 @@
] );
} );

test( 'should not select list wrapper when pressing arrow up from list', async ( {
editor,
page,
writingFlowUtils,
} ) => {
// Insert a paragraph block first.
await editor.insertBlock( {
name: 'core/paragraph',
attributes: { content: 'First paragraph' },
} );

// Insert a list block.
await editor.insertBlock( { name: 'core/list' } );
await page.keyboard.type( 'List item' );

// The caret is now inside the list item.
// Press ArrowUp - should skip the list wrapper and go to the paragraph.
await page.keyboard.press( 'ArrowUp' );

// Verify we're in the paragraph, NOT the list wrapper.
await expect
.poll( writingFlowUtils.getActiveBlockName )
.toBe( 'core/paragraph' );

// Verify the focused element has the paragraph content.
const activeElementLocator = editor.canvas.locator( ':focus' );
await expect( activeElementLocator ).toHaveText( 'First paragraph' );
} );

test( 'should navigate around inline boundaries', async ( {
editor,
page,
Expand Down Expand Up @@ -879,7 +908,7 @@
await page.mouse.move( x, y );

const inserter = page.locator( 'role=button[name="Add block"i]' );
await expect( inserter ).toBeVisible();

Check failure on line 911 in test/e2e/specs/editor/various/writing-flow.spec.js

View workflow job for this annotation

GitHub Actions / Playwright - 7

[webkit] › test/e2e/specs/editor/various/writing-flow.spec.js:861:2 › Writing Flow (@firefox

3) [webkit] › test/e2e/specs/editor/various/writing-flow.spec.js:861:2 › Writing Flow (@Firefox, @WebKit) › should not have a dead zone above an aligned block Retry #2 ─────────────────────────────────────────────────────────────────────────────────────── Error: expect(locator).toBeVisible() failed Locator: locator('role=button[name="Add block"i]') Expected: visible Timeout: 5000ms Error: element(s) not found Call log: - Expect "toBeVisible" with timeout 5000ms - waiting for locator('role=button[name="Add block"i]') 909 | 910 | const inserter = page.locator( 'role=button[name="Add block"i]' ); > 911 | await expect( inserter ).toBeVisible(); | ^ 912 | 913 | // Find the space between the inserter and the image block. 914 | const inserterRect = await inserter.boundingBox(); at /home/runner/work/gutenberg/gutenberg/test/e2e/specs/editor/various/writing-flow.spec.js:911:28

Check failure on line 911 in test/e2e/specs/editor/various/writing-flow.spec.js

View workflow job for this annotation

GitHub Actions / Playwright - 7

[webkit] › test/e2e/specs/editor/various/writing-flow.spec.js:861:2 › Writing Flow (@firefox

3) [webkit] › test/e2e/specs/editor/various/writing-flow.spec.js:861:2 › Writing Flow (@Firefox, @WebKit) › should not have a dead zone above an aligned block Retry #1 ─────────────────────────────────────────────────────────────────────────────────────── Error: expect(locator).toBeVisible() failed Locator: locator('role=button[name="Add block"i]') Expected: visible Timeout: 5000ms Error: element(s) not found Call log: - Expect "toBeVisible" with timeout 5000ms - waiting for locator('role=button[name="Add block"i]') 909 | 910 | const inserter = page.locator( 'role=button[name="Add block"i]' ); > 911 | await expect( inserter ).toBeVisible(); | ^ 912 | 913 | // Find the space between the inserter and the image block. 914 | const inserterRect = await inserter.boundingBox(); at /home/runner/work/gutenberg/gutenberg/test/e2e/specs/editor/various/writing-flow.spec.js:911:28

Check failure on line 911 in test/e2e/specs/editor/various/writing-flow.spec.js

View workflow job for this annotation

GitHub Actions / Playwright - 7

[webkit] › test/e2e/specs/editor/various/writing-flow.spec.js:861:2 › Writing Flow (@firefox

3) [webkit] › test/e2e/specs/editor/various/writing-flow.spec.js:861:2 › Writing Flow (@Firefox, @WebKit) › should not have a dead zone above an aligned block Error: expect(locator).toBeVisible() failed Locator: locator('role=button[name="Add block"i]') Expected: visible Timeout: 5000ms Error: element(s) not found Call log: - Expect "toBeVisible" with timeout 5000ms - waiting for locator('role=button[name="Add block"i]') 909 | 910 | const inserter = page.locator( 'role=button[name="Add block"i]' ); > 911 | await expect( inserter ).toBeVisible(); | ^ 912 | 913 | // Find the space between the inserter and the image block. 914 | const inserterRect = await inserter.boundingBox(); at /home/runner/work/gutenberg/gutenberg/test/e2e/specs/editor/various/writing-flow.spec.js:911:28

Check failure on line 911 in test/e2e/specs/editor/various/writing-flow.spec.js

View workflow job for this annotation

GitHub Actions / Playwright - 5

[chromium] › test/e2e/specs/editor/various/writing-flow.spec.js:861:2 › Writing Flow (@firefox

4) [chromium] › test/e2e/specs/editor/various/writing-flow.spec.js:861:2 › Writing Flow (@Firefox, @WebKit) › should not have a dead zone above an aligned block Error: expect(locator).toBeVisible() failed Locator: locator('role=button[name="Add block"i]') Expected: visible Timeout: 5000ms Error: element(s) not found Call log: - Expect "toBeVisible" with timeout 5000ms - waiting for locator('role=button[name="Add block"i]') 909 | 910 | const inserter = page.locator( 'role=button[name="Add block"i]' ); > 911 | await expect( inserter ).toBeVisible(); | ^ 912 | 913 | // Find the space between the inserter and the image block. 914 | const inserterRect = await inserter.boundingBox(); at /home/runner/work/gutenberg/gutenberg/test/e2e/specs/editor/various/writing-flow.spec.js:911:28

// Find the space between the inserter and the image block.
const inserterRect = await inserter.boundingBox();
Expand Down
Loading