diff --git a/packages/block-editor/src/components/writing-flow/use-home-end.js b/packages/block-editor/src/components/writing-flow/use-home-end.js index a3641dcccc4967..ce8d6a1b7a2369 100644 --- a/packages/block-editor/src/components/writing-flow/use-home-end.js +++ b/packages/block-editor/src/components/writing-flow/use-home-end.js @@ -12,10 +12,16 @@ import { getSelectionEditableElement } from '../../utils/dom'; import { store as blockEditorStore } from '../../store'; /** - * While the wrapper is the contentEditable editing host (a selected block - * supports `editableRoot`), browsers don't perform the default caret - * movement for Home and End. Perform the equivalent movement with - * `Selection.modify()`. + * Moves the caret to the start or end of the visual line for Home and End + * with `Selection.modify()`, because the browser's default caret movement + * cannot be relied on in two cases: + * + * - While the wrapper is the contentEditable editing host (a selected block + * supports `editableRoot`), browsers don't perform the default caret + * movement for Home and End. + * - Chromium on macOS maps Home and End to scroll commands, so it never + * moves the caret in editable content on that platform, including nested + * editable elements like the tab labels in the tab-list block. */ export default function useHomeEnd() { const { hasMultiSelection } = useSelect( blockEditorStore ); @@ -33,11 +39,13 @@ export default function useHomeEnd() { return; } - if ( - node.contentEditable !== 'true' || - node.ownerDocument.activeElement !== node || - hasMultiSelection() - ) { + // Only handle keys pressed in editable content, in both of the + // cases mentioned above: `event.target` is the focused element, + // and `isContentEditable` is true both for the wrapper as the + // editing host and for a nested editable element like a tab label. + // Anything else that takes focus like inputs and textareas keep + // default behavior. + if ( ! event.target.isContentEditable || hasMultiSelection() ) { return; } diff --git a/test/e2e/specs/editor/blocks/tabs.spec.js b/test/e2e/specs/editor/blocks/tabs.spec.js index 5935b98915fb16..48ee010574a013 100644 --- a/test/e2e/specs/editor/blocks/tabs.spec.js +++ b/test/e2e/specs/editor/blocks/tabs.spec.js @@ -164,8 +164,13 @@ test.describe( 'Tabs', () => { ).toBeFocused(); // The new tab's panel is the active one and is visible. + // Use `exact: true` to avoid matching the parent 'Block: Tab Panels' name. + // Use `includeHidden: true` to check the number of hidden panels. getByRole() + // only returns visible elements by default. const panels = editor.canvas.getByRole( 'document', { name: 'Block: Tab Panel', + exact: true, + includeHidden: true, } ); await expect( panels ).toHaveCount( 3 ); await expect( panels.nth( 2 ) ).toBeVisible();