diff --git a/docs/designers-developers/developers/data/data-core-block-editor.md b/docs/designers-developers/developers/data/data-core-block-editor.md index 23e48402fb1cbd..3c0d6eca4901f6 100644 --- a/docs/designers-developers/developers/data/data-core-block-editor.md +++ b/docs/designers-developers/developers/data/data-core-block-editor.md @@ -733,6 +733,18 @@ _Returns_ - `boolean`: Whether an ancestor of the block is in multi-selection set. +# **isAutoFocusEnabled** + +Returns whether the automatic focus is enabled. + +_Parameters_ + +- _state_ `Object`: Editor state. + +_Returns_ + +- `boolean`: Is automatic focus enabled. + # **isBlockHighlighted** Returns true if the current highlighted block matches the block clientId. @@ -1255,6 +1267,14 @@ _Parameters_ - _clientId_ `string`: Block client ID. +# **setAutoFocusEnabled** + +Generators that triggers an action used to enable or disable the automatic focus. + +_Parameters_ + +- _isAutoFocusEnabled_ `boolean`: Enable/Disable navigation mode. + # **setHasControlledInnerBlocks** Returns an action object that sets whether the block has controlled innerblocks. diff --git a/packages/block-editor/src/components/block-list/block-wrapper.js b/packages/block-editor/src/components/block-list/block-wrapper.js index ec638ee132128d..2fcc4e9b0f43e9 100644 --- a/packages/block-editor/src/components/block-list/block-wrapper.js +++ b/packages/block-editor/src/components/block-list/block-wrapper.js @@ -30,6 +30,7 @@ const BlockComponent = forwardRef( const { clientId, rootClientId, + isAutoFocusEnabled, isSelected, isFirstMultiSelected, isLastMultiSelected, @@ -124,10 +125,20 @@ const BlockComponent = forwardRef( }; useEffect( () => { - if ( ! isMultiSelecting && ! isNavigationMode && isSelected ) { + if ( + ! isMultiSelecting && + ! isNavigationMode && + isSelected && + isAutoFocusEnabled + ) { focusTabbable(); } - }, [ isSelected, isMultiSelecting, isNavigationMode ] ); + }, [ + isSelected, + isMultiSelecting, + isNavigationMode, + isAutoFocusEnabled, + ] ); // Block Reordering animation const animationStyle = useMovingAnimation( diff --git a/packages/block-editor/src/components/block-list/block.js b/packages/block-editor/src/components/block-list/block.js index 6e8cb32daff44e..ae806c65db625a 100644 --- a/packages/block-editor/src/components/block-list/block.js +++ b/packages/block-editor/src/components/block-list/block.js @@ -64,6 +64,7 @@ function BlockListBlock( { toggleSelection, index, enableAnimation, + isAutoFocusEnabled, isNavigationMode, isMultiSelecting, } ) { @@ -159,6 +160,7 @@ function BlockListBlock( { const value = { clientId, rootClientId, + isAutoFocusEnabled, isSelected, isFirstMultiSelected, isLastMultiSelected, @@ -218,6 +220,7 @@ const applyWithSelect = withSelect( const { isBlockSelected, isAncestorMultiSelected, + isAutoFocusEnabled, isBlockMultiSelected, isFirstMultiSelectedBlock, getLastMultiSelectedBlockClientId, @@ -251,6 +254,7 @@ const applyWithSelect = withSelect( // Do not add new properties here, use `useSelect` instead to avoid // leaking new props to the public API (editor.BlockListBlock filter). return { + isAutoFocusEnabled: isAutoFocusEnabled(), isMultiSelected: isBlockMultiSelected( clientId ), isPartOfMultiSelection: isBlockMultiSelected( clientId ) || diff --git a/packages/block-editor/src/components/block-navigation/block-contents.js b/packages/block-editor/src/components/block-navigation/block-contents.js index f7d46f53af80db..5619370929b9aa 100644 --- a/packages/block-editor/src/components/block-navigation/block-contents.js +++ b/packages/block-editor/src/components/block-navigation/block-contents.js @@ -21,7 +21,6 @@ const BlockNavigationBlockContents = forwardRef( return withBlockNavigationSlots ? ( ) : ( ); } diff --git a/packages/block-editor/src/components/block-navigation/block.js b/packages/block-editor/src/components/block-navigation/block.js index 50b8ad407c6b4a..833e6460ff21fe 100644 --- a/packages/block-editor/src/components/block-navigation/block.js +++ b/packages/block-editor/src/components/block-navigation/block.js @@ -8,7 +8,8 @@ import classnames from 'classnames'; */ import { __experimentalTreeGridCell as TreeGridCell } from '@wordpress/components'; import { moreVertical } from '@wordpress/icons'; -import { useState } from '@wordpress/element'; +import { useState, useEffect, useRef } from '@wordpress/element'; +import { useSelect } from '@wordpress/data'; /** * Internal dependencies @@ -34,6 +35,7 @@ export default function BlockNavigationBlock( { terminatedLevels, path, } ) { + const ref = useRef(); const [ isHovered, setIsHovered ] = useState( false ); const [ isFocused, setIsFocused ] = useState( false ); const { clientId } = block; @@ -51,11 +53,34 @@ export default function BlockNavigationBlock( { __experimentalWithEllipsisMenu: withEllipsisMenu, __experimentalWithEllipsisMenuMinLevel: ellipsisMenuMinLevel, } = useBlockNavigationContext(); + const ellipsisMenuClassName = classnames( 'block-editor-block-navigation-block__menu-cell', { 'is-visible': hasVisibleMovers } ); + const { isEditorAutoFocusEnabled } = useSelect( ( select ) => ( { + isEditorAutoFocusEnabled: select( + 'core/block-editor' + ).isAutoFocusEnabled(), + } ) ); + useEffect( () => { + let timeout; + if ( ! isEditorAutoFocusEnabled && isSelected ) { + // Give slots time to settle down + timeout = setTimeout( function() { + // Select the new block + onClick(); + + // Move focus to the new block + if ( ref.current ) { + ref.current.focus(); + } + } ); + } + return () => clearTimeout( timeout ); + }, [ isEditorAutoFocusEnabled, isSelected ] ); + return ( ) } diff --git a/packages/block-editor/src/store/actions.js b/packages/block-editor/src/store/actions.js index 5aef9e4ce2dd6c..93fef4169f11ec 100644 --- a/packages/block-editor/src/store/actions.js +++ b/packages/block-editor/src/store/actions.js @@ -883,6 +883,18 @@ export function* setNavigationMode( isNavigationMode = true ) { } } +/** + * Generators that triggers an action used to enable or disable the automatic focus. + * + * @param {boolean} isAutoFocusEnabled Enable/Disable navigation mode. + */ +export function* setAutoFocusEnabled( isAutoFocusEnabled = true ) { + yield { + type: 'SET_AUTO_FOCUS_ENABLED', + isAutoFocusEnabled, + }; +} + /** * Generator that triggers an action used to duplicate a list of blocks. * diff --git a/packages/block-editor/src/store/reducer.js b/packages/block-editor/src/store/reducer.js index 223fe269508841..759608409ccf3f 100644 --- a/packages/block-editor/src/store/reducer.js +++ b/packages/block-editor/src/store/reducer.js @@ -1519,6 +1519,22 @@ export function isNavigationMode( state = false, action ) { return state; } +/** + * Reducer returning whether the automatic focus should be enabled or not. + * + * @param {boolean} state Current state. + * @param {Object} action Dispatched action. + * + * @return {string} Updated state. + */ +export function isAutoFocusEnabled( state = true, action ) { + if ( action.type === 'SET_AUTO_FOCUS_ENABLED' ) { + return action.isAutoFocusEnabled; + } + + return state; +} + /** * Reducer return an updated state representing the most recent block attribute * update. The state is structured as an object where the keys represent the @@ -1621,6 +1637,7 @@ export default combineReducers( { preferences, lastBlockAttributesChange, isNavigationMode, + isAutoFocusEnabled, automaticChangeStatus, highlightedBlock, } ); diff --git a/packages/block-editor/src/store/selectors.js b/packages/block-editor/src/store/selectors.js index 183210fc14c79f..adc84d8797bb81 100644 --- a/packages/block-editor/src/store/selectors.js +++ b/packages/block-editor/src/store/selectors.js @@ -1627,6 +1627,17 @@ export function isNavigationMode( state ) { return state.isNavigationMode; } +/** + * Returns whether the automatic focus is enabled. + * + * @param {Object} state Editor state. + * + * @return {boolean} Is automatic focus enabled. + */ +export function isAutoFocusEnabled( state ) { + return state.isAutoFocusEnabled; +} + /** * Returns true if the last change was an automatic change, false otherwise. * diff --git a/packages/components/src/panel/index.js b/packages/components/src/panel/index.js index 96e9daf8e647b3..d6e85fd43bea08 100644 --- a/packages/components/src/panel/index.js +++ b/packages/components/src/panel/index.js @@ -8,10 +8,10 @@ import classnames from 'classnames'; */ import PanelHeader from './header'; -function Panel( { header, className, children } ) { +function Panel( { header, className, children, ...props } ) { const classNames = classnames( className, 'components-panel' ); return ( -
+
{ header && } { children }
diff --git a/packages/edit-navigation/src/components/menu-editor/block-editor-panel.js b/packages/edit-navigation/src/components/menu-editor/block-editor-panel.js index 1706bff5ed20d1..209b763f8b18b3 100644 --- a/packages/edit-navigation/src/components/menu-editor/block-editor-panel.js +++ b/packages/edit-navigation/src/components/menu-editor/block-editor-panel.js @@ -26,6 +26,7 @@ export default function BlockEditorPanel( { onDeleteMenu, menuId, saveBlocks, + ...props } ) { const { isNavigationModeActive, hasSelectedBlock } = useSelect( ( select ) => { @@ -48,7 +49,10 @@ export default function BlockEditorPanel( { ); return ( - +