From a372a05f9e0c09f1f46681387b02effbe81a1971 Mon Sep 17 00:00:00 2001 From: Jerry Jones Date: Wed, 12 Jun 2024 15:28:36 -0500 Subject: [PATCH 1/5] Redo CSS for editor canvas outline. - moves selected-block-outline to base styles css so it can be used anywhere - renames the mixin to match mixin naming convention --- packages/base-styles/_mixins.scss | 14 ++++++++++++++ .../src/components/block-list/content.scss | 18 ++---------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/packages/base-styles/_mixins.scss b/packages/base-styles/_mixins.scss index 8c056905e64d8..c4d43e5b5f59f 100644 --- a/packages/base-styles/_mixins.scss +++ b/packages/base-styles/_mixins.scss @@ -597,3 +597,17 @@ } } } + +@mixin selected-block-outline() { + content: ""; + position: absolute; + pointer-events: none; + top: 0; + right: 0; + bottom: 0; + left: 0; + outline-color: var(--wp-admin-theme-color); + outline-style: solid; + outline-width: calc(var(--wp-admin-border-width-focus) / var(--wp-block-editor-iframe-zoom-out-scale, 1)); + outline-offset: calc((-1 * var(--wp-admin-border-width-focus)) / var(--wp-block-editor-iframe-zoom-out-scale, 1)); +} diff --git a/packages/block-editor/src/components/block-list/content.scss b/packages/block-editor/src/components/block-list/content.scss index 8d55617bea2f9..ecbe592b5b13f 100644 --- a/packages/block-editor/src/components/block-list/content.scss +++ b/packages/block-editor/src/components/block-list/content.scss @@ -17,20 +17,6 @@ } } -@mixin selectedOutline() { - content: ""; - position: absolute; - pointer-events: none; - top: 0; - right: 0; - bottom: 0; - left: 0; - outline-color: var(--wp-admin-theme-color); - outline-style: solid; - outline-width: calc(var(--wp-admin-border-width-focus) / var(--wp-block-editor-iframe-zoom-out-scale, 1)); - outline-offset: calc((-1 * var(--wp-admin-border-width-focus)) / var(--wp-block-editor-iframe-zoom-out-scale, 1)); -} - // Hide selections on this element, otherwise Safari will include it stacked // under your actual selection. // This uses a CSS hack to show the rules to Safari only. Failing here is okay, @@ -101,7 +87,7 @@ _::-webkit-full-page-media, _:future, :root .has-multi-selection .block-editor-b // We're using a pseudo element to overflow placeholder borders // and any border inside the block itself. &::after { - @include selectedOutline(); + @include selected-block-outline(); z-index: 1; // Show a light color for dark themes. @@ -281,7 +267,7 @@ _::-webkit-full-page-media, _:future, :root .has-multi-selection .block-editor-b &:not(.rich-text):not([contenteditable="true"]).is-selected { &::after { - @include selectedOutline(); + @include selected-block-outline(); } } } From 9c9a65c7386a3f4ad44593b07d9529ce7321fa33 Mon Sep 17 00:00:00 2001 From: Jerry Jones Date: Wed, 12 Jun 2024 15:33:04 -0500 Subject: [PATCH 2/5] Add a focusable wrapper for the block canvas --- .../src/components/block-canvas/index.js | 16 ++++++++++++++-- .../src/components/iframe/content.scss | 10 ++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/packages/block-editor/src/components/block-canvas/index.js b/packages/block-editor/src/components/block-canvas/index.js index c6a47b7b5533c..97c6fd95a32d4 100644 --- a/packages/block-editor/src/components/block-canvas/index.js +++ b/packages/block-editor/src/components/block-canvas/index.js @@ -16,6 +16,18 @@ import { useMouseMoveTypingReset } from '../observe-typing'; import { useBlockSelectionClearer } from '../block-selection-clearer'; import { useBlockCommands } from '../use-block-commands'; +function FocusableWrapper( { children } ) { + return ( +
+ { children } +
+ ); +} + export function ExperimentalBlockCanvas( { shouldIframe = true, height = '300px', @@ -49,7 +61,7 @@ export function ExperimentalBlockCanvas( { width: '100%', } } > - { children } + { children } ); @@ -70,7 +82,7 @@ export function ExperimentalBlockCanvas( { name="editor-canvas" > - { children } + { children } ); diff --git a/packages/block-editor/src/components/iframe/content.scss b/packages/block-editor/src/components/iframe/content.scss index 165cf70d24a71..59b9eed72d5be 100644 --- a/packages/block-editor/src/components/iframe/content.scss +++ b/packages/block-editor/src/components/iframe/content.scss @@ -65,3 +65,13 @@ } } } + +.block-editor-accessible-wrapper:focus-visible { + outline: none; + + &::after { + content: ""; + @include selected-block-outline(); + position: fixed; + } +} From bbf7408d0dcb7d958514106dd7b2ff721cbf9b70 Mon Sep 17 00:00:00 2001 From: Jerry Jones Date: Wed, 12 Jun 2024 15:33:25 -0500 Subject: [PATCH 3/5] Clear focus from template click to the focusable wrapper --- .../src/components/block-breadcrumb/index.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/block-editor/src/components/block-breadcrumb/index.js b/packages/block-editor/src/components/block-breadcrumb/index.js index b1fd13dbf3475..39d864db81dc8 100644 --- a/packages/block-editor/src/components/block-breadcrumb/index.js +++ b/packages/block-editor/src/components/block-breadcrumb/index.js @@ -12,6 +12,7 @@ import { chevronRightSmall, Icon } from '@wordpress/icons'; import BlockTitle from '../block-title'; import { store as blockEditorStore } from '../../store'; import { unlock } from '../../lock-unlock'; +import { __unstableUseBlockRef as useBlockRef } from '../block-list/use-block-props/use-block-refs'; /** * Block breadcrumb component, displaying the hierarchy of the current block selection as a breadcrumb. @@ -37,6 +38,10 @@ function BlockBreadcrumb( { rootLabelText } ) { }, [] ); const rootLabel = rootLabelText || __( 'Document' ); + // We don't care about this specific ref, but this is a way + // to get a ref within the editor canvas so we can focus it later. + const blockRef = useBlockRef( clientId ); + /* * Disable reason: The `list` ARIA role is redundant but * Safari+VoiceOver won't announce the list otherwise. @@ -60,7 +65,11 @@ function BlockBreadcrumb( { rootLabelText } ) { From 795350140178ab0fceb27560eb9e528bbbfe5a1f Mon Sep 17 00:00:00 2001 From: Jerry Jones Date: Wed, 12 Jun 2024 15:41:23 -0500 Subject: [PATCH 4/5] Fix wrapper selector --- .../block-editor/src/components/block-breadcrumb/index.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/block-editor/src/components/block-breadcrumb/index.js b/packages/block-editor/src/components/block-breadcrumb/index.js index 39d864db81dc8..0363ff1442c58 100644 --- a/packages/block-editor/src/components/block-breadcrumb/index.js +++ b/packages/block-editor/src/components/block-breadcrumb/index.js @@ -68,7 +68,9 @@ function BlockBreadcrumb( { rootLabelText } ) { onClick={ () => { clearSelectedBlock(); // Focus the editor iframe. - blockRef.current?.closest( 'body' )?.focus(); + blockRef.current + ?.closest( '[aria-label="Block canvas"]' ) + ?.focus(); } } > { rootLabel } From c69e82ac4e08d1bf2999f775e27ff644c9f9a055 Mon Sep 17 00:00:00 2001 From: Ben Dwyer Date: Wed, 19 Jun 2024 20:29:30 +0100 Subject: [PATCH 5/5] Focus the wrapper with a ref --- packages/block-editor/README.md | 1 + .../src/components/block-breadcrumb/index.js | 19 +++++++------------ .../src/components/block-canvas/index.js | 16 +++++++++++----- .../src/components/editor-interface/index.js | 11 +++++++++-- .../src/components/visual-editor/index.js | 2 ++ 5 files changed, 30 insertions(+), 19 deletions(-) diff --git a/packages/block-editor/README.md b/packages/block-editor/README.md index 7c70473430b31..2c7b511a5d376 100644 --- a/packages/block-editor/README.md +++ b/packages/block-editor/README.md @@ -108,6 +108,7 @@ _Parameters_ - _props_ `Object`: Component props. - _props.rootLabelText_ `string`: Translated label for the root element of the breadcrumb trail. +- _props.focusableWrapperRef_ `Object`: Ref of the element to focus when the breadcrumb is clicked. _Returns_ diff --git a/packages/block-editor/src/components/block-breadcrumb/index.js b/packages/block-editor/src/components/block-breadcrumb/index.js index 0363ff1442c58..49601323359d7 100644 --- a/packages/block-editor/src/components/block-breadcrumb/index.js +++ b/packages/block-editor/src/components/block-breadcrumb/index.js @@ -12,16 +12,16 @@ import { chevronRightSmall, Icon } from '@wordpress/icons'; import BlockTitle from '../block-title'; import { store as blockEditorStore } from '../../store'; import { unlock } from '../../lock-unlock'; -import { __unstableUseBlockRef as useBlockRef } from '../block-list/use-block-props/use-block-refs'; /** * Block breadcrumb component, displaying the hierarchy of the current block selection as a breadcrumb. * - * @param {Object} props Component props. - * @param {string} props.rootLabelText Translated label for the root element of the breadcrumb trail. - * @return {Element} Block Breadcrumb. + * @param {Object} props Component props. + * @param {string} props.rootLabelText Translated label for the root element of the breadcrumb trail. + * @param {Object} props.focusableWrapperRef Ref of the element to focus when the breadcrumb is clicked. + * @return {Element} Block Breadcrumb. */ -function BlockBreadcrumb( { rootLabelText } ) { +function BlockBreadcrumb( { rootLabelText, focusableWrapperRef } ) { const { selectBlock, clearSelectedBlock } = useDispatch( blockEditorStore ); const { clientId, parents, hasSelection } = useSelect( ( select ) => { const { @@ -38,10 +38,6 @@ function BlockBreadcrumb( { rootLabelText } ) { }, [] ); const rootLabel = rootLabelText || __( 'Document' ); - // We don't care about this specific ref, but this is a way - // to get a ref within the editor canvas so we can focus it later. - const blockRef = useBlockRef( clientId ); - /* * Disable reason: The `list` ARIA role is redundant but * Safari+VoiceOver won't announce the list otherwise. @@ -67,10 +63,9 @@ function BlockBreadcrumb( { rootLabelText } ) { variant="tertiary" onClick={ () => { clearSelectedBlock(); + // Focus the editor iframe. - blockRef.current - ?.closest( '[aria-label="Block canvas"]' ) - ?.focus(); + focusableWrapperRef.current?.focus(); } } > { rootLabel } diff --git a/packages/block-editor/src/components/block-canvas/index.js b/packages/block-editor/src/components/block-canvas/index.js index 97c6fd95a32d4..69a8fe0a84b15 100644 --- a/packages/block-editor/src/components/block-canvas/index.js +++ b/packages/block-editor/src/components/block-canvas/index.js @@ -2,7 +2,7 @@ * WordPress dependencies */ import { useMergeRefs } from '@wordpress/compose'; -import { useRef } from '@wordpress/element'; +import { useRef, forwardRef } from '@wordpress/element'; /** * Internal dependencies @@ -16,17 +16,18 @@ import { useMouseMoveTypingReset } from '../observe-typing'; import { useBlockSelectionClearer } from '../block-selection-clearer'; import { useBlockCommands } from '../use-block-commands'; -function FocusableWrapper( { children } ) { +const FocusableWrapper = forwardRef( ( { children }, ref ) => { return (
{ children }
); -} +} ); export function ExperimentalBlockCanvas( { shouldIframe = true, @@ -35,6 +36,7 @@ export function ExperimentalBlockCanvas( { styles, contentRef: contentRefProp, iframeProps, + focusableWrapperRef, } ) { useBlockCommands(); const resetTypingRef = useMouseMoveTypingReset(); @@ -61,7 +63,9 @@ export function ExperimentalBlockCanvas( { width: '100%', } } > - { children } + + { children } + ); @@ -82,7 +86,9 @@ export function ExperimentalBlockCanvas( { name="editor-canvas" > - { children } + + { children } + ); diff --git a/packages/editor/src/components/editor-interface/index.js b/packages/editor/src/components/editor-interface/index.js index 8d4bdfc00344a..ab587f15e34ea 100644 --- a/packages/editor/src/components/editor-interface/index.js +++ b/packages/editor/src/components/editor-interface/index.js @@ -17,7 +17,7 @@ import { } from '@wordpress/block-editor'; import { store as keyboardShortcutsStore } from '@wordpress/keyboard-shortcuts'; import { useViewportMatch } from '@wordpress/compose'; -import { useState, useCallback } from '@wordpress/element'; +import { useState, useCallback, useRef } from '@wordpress/element'; /** * Internal dependencies @@ -116,6 +116,7 @@ export default function EditorInterface( { }, [ entitiesSavedStatesCallback ] ); + const focusableWrapperRef = useRef(); return ( ) } { children } @@ -208,7 +212,10 @@ export default function EditorInterface( { isRichEditingEnabled && blockEditorMode !== 'zoom-out' && mode === 'visual' && ( - + ) } actions={ diff --git a/packages/editor/src/components/visual-editor/index.js b/packages/editor/src/components/visual-editor/index.js index 7d8f38ae7a0eb..3f1cb141f34b1 100644 --- a/packages/editor/src/components/visual-editor/index.js +++ b/packages/editor/src/components/visual-editor/index.js @@ -104,6 +104,7 @@ function VisualEditor( { iframeProps, contentRef, className, + focusableWrapperRef, } ) { const [ resizeObserver, sizes ] = useResizeObserver(); const isMobileViewport = useViewportMatch( 'small', '<' ); @@ -407,6 +408,7 @@ function VisualEditor( { ...deviceStyles, }, } } + focusableWrapperRef={ focusableWrapperRef } > { themeSupportsLayout && ! themeHasDisabledLayoutStyles &&