diff --git a/packages/block-editor/src/components/block-lock/modal.js b/packages/block-editor/src/components/block-lock/modal.js index e0884300f1b37..cfafa6c031bbd 100644 --- a/packages/block-editor/src/components/block-lock/modal.js +++ b/packages/block-editor/src/components/block-lock/modal.js @@ -41,7 +41,7 @@ function getTemplateLockValue( lock ) { return false; } -export default function BlockLockModal( { clientId, onClose, onFocusReturn } ) { +export default function BlockLockModal( { clientId, onClose } ) { const [ lock, setLock ] = useState( { move: false, remove: false } ); const { canEdit, canMove, canRemove } = useBlockLock( clientId ); const { allowsEditLocking, templateLock, hasTemplateLock } = useSelect( @@ -89,7 +89,6 @@ export default function BlockLockModal( { clientId, onClose, onFocusReturn } ) { ) } overlayClassName="block-editor-block-lock-modal" onRequestClose={ onClose } - onFocusReturn={ onFocusReturn } >

{ __( diff --git a/packages/block-editor/src/components/block-lock/toolbar.js b/packages/block-editor/src/components/block-lock/toolbar.js index 41fccbdbe5611..2dcbb18a20223 100644 --- a/packages/block-editor/src/components/block-lock/toolbar.js +++ b/packages/block-editor/src/components/block-lock/toolbar.js @@ -4,7 +4,7 @@ import { __ } from '@wordpress/i18n'; import { ToolbarButton, ToolbarGroup } from '@wordpress/components'; import { focus } from '@wordpress/dom'; -import { useReducer, useRef } from '@wordpress/element'; +import { useReducer, useRef, useEffect } from '@wordpress/element'; import { lock } from '@wordpress/icons'; /** @@ -22,12 +22,33 @@ export default function BlockLockToolbar( { clientId, wrapperRef } ) { ); const lockButtonRef = useRef( null ); + const isFirstRender = useRef( true ); - if ( ! canLock ) { - return null; - } + const shouldHideBlockLockUI = + ! canLock || ( canEdit && canMove && canRemove ); + + useEffect( () => { + if ( isFirstRender.current ) { + isFirstRender.current = false; + return; + } - if ( canEdit && canMove && canRemove ) { + if ( ! isModalOpen && shouldHideBlockLockUI ) { + focus.focusable + .find( wrapperRef.current, { + sequential: false, + } ) + .find( + ( element ) => + element.tagName === 'BUTTON' && + element !== lockButtonRef.current + ) + ?.focus(); + } + // wrapperRef is a reference object and should be stable + }, [ isModalOpen, shouldHideBlockLockUI, wrapperRef ] ); + + if ( shouldHideBlockLockUI ) { return null; } @@ -42,39 +63,7 @@ export default function BlockLockToolbar( { clientId, wrapperRef } ) { /> { isModalOpen && ( - { - // Try to focus the element that should have received - // focus by default. - if ( defaultFocusReturnElement ) { - defaultFocusReturnElement.focus(); - } - - // Check if the element that should have received focus is effectively - // the current active element. This check is useful when the element - // that should have received focus is not being rendered in the DOM. - if ( - defaultFocusReturnElement.ownerDocument - .activeElement !== defaultFocusReturnElement && - wrapperRef.current - ) { - // As a fallback, focus the first focusable button - // found in the toolbar - focus.focusable - .find( wrapperRef.current, { - sequential: false, - } ) - .find( - ( element ) => - element.tagName === 'BUTTON' && - element !== lockButtonRef.current - ) - ?.focus(); - } - } } - /> + ) } ); diff --git a/packages/components/src/modal/index.tsx b/packages/components/src/modal/index.tsx index 75d5bd1043ee0..d9c7b602b8392 100644 --- a/packages/components/src/modal/index.tsx +++ b/packages/components/src/modal/index.tsx @@ -67,7 +67,6 @@ function UnforwardedModal( onKeyDown, isFullScreen = false, __experimentalHideHeader = false, - onFocusReturn, } = props; const ref = useRef< HTMLDivElement >(); @@ -77,7 +76,7 @@ function UnforwardedModal( : aria.labelledby; const focusOnMountRef = useFocusOnMount( focusOnMount ); const constrainedTabbingRef = useConstrainedTabbing(); - const focusReturnRef = useFocusReturn( onFocusReturn ); + const focusReturnRef = useFocusReturn(); const focusOutsideProps = useFocusOutside( onRequestClose ); const contentRef = useRef< HTMLDivElement >( null ); const childrenContainerRef = useRef< HTMLDivElement >( null ); diff --git a/packages/components/src/modal/types.ts b/packages/components/src/modal/types.ts index 46497471ab0e3..6169e42a8a2d4 100644 --- a/packages/components/src/modal/types.ts +++ b/packages/components/src/modal/types.ts @@ -143,9 +143,4 @@ export type ModalProps = { * @default false */ __experimentalHideHeader?: boolean; - /** - * Callback called when the modal is dismissed. Used to implement custom - * focus restoration behavior. - */ - onFocusReturn?: ( defaultFocusReturnElement: Element | null ) => void; }; diff --git a/packages/compose/src/hooks/use-focus-return/index.js b/packages/compose/src/hooks/use-focus-return/index.js index e588f653e90b8..66751b7028d32 100644 --- a/packages/compose/src/hooks/use-focus-return/index.js +++ b/packages/compose/src/hooks/use-focus-return/index.js @@ -9,7 +9,7 @@ import { useRef, useEffect, useCallback } from '@wordpress/element'; * previously focused element when closed. * The current hook implements the returning behavior. * - * @param {( defaultElementToFocus: Element | null ) => void} [onFocusReturn] Overrides the default return behavior. + * @param {() => void} [onFocusReturn] Overrides the default return behavior. * @return {import('react').RefCallback} Element Ref. * * @example @@ -62,14 +62,12 @@ function useFocusReturn( onFocusReturn ) { // decides to allow the default behavior to occur under some // conditions. if ( onFocusReturnRef.current ) { - onFocusReturnRef.current( focusedBeforeMount.current ); + onFocusReturnRef.current(); } else { /** @type {null | HTMLElement} */ ( focusedBeforeMount.current )?.focus(); } - } else if ( onFocusReturnRef.current ) { - onFocusReturnRef.current( focusedBeforeMount.current ); } }, [] ); }