From 364e27a652820f2de3b76ce361275653b4ac13ae Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Fri, 26 Apr 2024 09:36:11 +0400 Subject: [PATCH 1/4] List View: Unify shortcut handlers --- .../block-settings-dropdown.js | 52 +---- .../list-view/block-select-button.js | 202 ----------------- .../src/components/list-view/block.js | 210 ++++++++++++++++-- 3 files changed, 198 insertions(+), 266 deletions(-) diff --git a/packages/block-editor/src/components/block-settings-menu/block-settings-dropdown.js b/packages/block-editor/src/components/block-settings-menu/block-settings-dropdown.js index 39e6af2eda511..5834f150136a8 100644 --- a/packages/block-editor/src/components/block-settings-menu/block-settings-dropdown.js +++ b/packages/block-editor/src/components/block-settings-menu/block-settings-dropdown.js @@ -12,10 +12,7 @@ import { moreVertical } from '@wordpress/icons'; import { Children, cloneElement } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; import { displayShortcut } from '@wordpress/keycodes'; -import { - store as keyboardShortcutsStore, - __unstableUseShortcutEventMatch, -} from '@wordpress/keyboard-shortcuts'; +import { store as keyboardShortcutsStore } from '@wordpress/keyboard-shortcuts'; import { pipe, useCopyToClipboard } from '@wordpress/compose'; /** @@ -125,7 +122,6 @@ export function BlockSettingsDropdown( { ), }; }, [] ); - const isMatch = __unstableUseShortcutEventMatch(); const hasSelectedBlocks = selectedBlockClientIds.length > 0; async function updateSelectionAfterDuplicate( clientIdsPromise ) { @@ -213,52 +209,6 @@ export function BlockSettingsDropdown( { open={ open } onToggle={ onToggle } noIcons - menuProps={ { - /** - * @param {KeyboardEvent} event - */ - onKeyDown( event ) { - if ( event.defaultPrevented ) return; - - if ( - isMatch( 'core/block-editor/remove', event ) && - canRemove - ) { - event.preventDefault(); - onRemove(); - updateSelectionAfterRemove(); - } else if ( - isMatch( - 'core/block-editor/duplicate', - event - ) && - canDuplicate - ) { - event.preventDefault(); - updateSelectionAfterDuplicate( onDuplicate() ); - } else if ( - isMatch( - 'core/block-editor/insert-after', - event - ) && - canInsertBlock - ) { - event.preventDefault(); - setOpenedBlockSettingsMenu( undefined ); - onInsertAfter(); - } else if ( - isMatch( - 'core/block-editor/insert-before', - event - ) && - canInsertBlock - ) { - event.preventDefault(); - setOpenedBlockSettingsMenu( undefined ); - onInsertBefore(); - } - }, - } } { ...props } > { ( { onClose } ) => ( diff --git a/packages/block-editor/src/components/list-view/block-select-button.js b/packages/block-editor/src/components/list-view/block-select-button.js index e52fc693afa79..8fec86847188f 100644 --- a/packages/block-editor/src/components/list-view/block-select-button.js +++ b/packages/block-editor/src/components/list-view/block-select-button.js @@ -6,7 +6,6 @@ import classnames from 'classnames'; /** * WordPress dependencies */ -import { hasBlockSupport } from '@wordpress/blocks'; import { Button, __experimentalHStack as HStack, @@ -15,11 +14,7 @@ import { } from '@wordpress/components'; import { forwardRef } from '@wordpress/element'; import { Icon, lockSmall as lock, pinSmall } from '@wordpress/icons'; -import { SPACE, ENTER, BACKSPACE, DELETE } from '@wordpress/keycodes'; -import { useSelect, useDispatch } from '@wordpress/data'; -import { __unstableUseShortcutEventMatch as useShortcutEventMatch } from '@wordpress/keyboard-shortcuts'; import { __, sprintf } from '@wordpress/i18n'; -import isShallowEqual from '@wordpress/is-shallow-equal'; /** * Internal dependencies @@ -29,9 +24,7 @@ import useBlockDisplayInformation from '../use-block-display-information'; import useBlockDisplayTitle from '../block-title/use-block-display-title'; import ListViewExpander from './expander'; import { useBlockLock } from '../block-lock'; -import { store as blockEditorStore } from '../../store'; import useListViewImages from './use-list-view-images'; -import { useListViewContext } from './context'; function ListViewBlockSelectButton( { @@ -48,7 +41,6 @@ function ListViewBlockSelectButton( draggable, isExpanded, ariaDescribedBy, - updateFocusAndSelection, }, ref ) { @@ -58,27 +50,8 @@ function ListViewBlockSelectButton( context: 'list-view', } ); const { isLocked } = useBlockLock( clientId ); - const { - canInsertBlockType, - getSelectedBlockClientIds, - getPreviousBlockClientId, - getBlockRootClientId, - getBlockOrder, - getBlockParents, - getBlocksByClientId, - canRemoveBlocks, - } = useSelect( blockEditorStore ); - const { - duplicateBlocks, - multiSelect, - removeBlocks, - insertAfterBlock, - insertBeforeBlock, - } = useDispatch( blockEditorStore ); - const isMatch = useShortcutEventMatch(); const isSticky = blockInformation?.positionType === 'sticky'; const images = useListViewImages( { clientId, isExpanded } ); - const { collapseAll, expand, rootClientId } = useListViewContext(); const positionLabel = blockInformation?.positionLabel ? sprintf( @@ -97,180 +70,6 @@ function ListViewBlockSelectButton( onDragStart?.( event ); }; - // Determine which blocks to update: - // If the current (focused) block is part of the block selection, use the whole selection. - // If the focused block is not part of the block selection, only update the focused block. - function getBlocksToUpdate() { - const selectedBlockClientIds = getSelectedBlockClientIds(); - const isUpdatingSelectedBlocks = - selectedBlockClientIds.includes( clientId ); - const firstBlockClientId = isUpdatingSelectedBlocks - ? selectedBlockClientIds[ 0 ] - : clientId; - const firstBlockRootClientId = - getBlockRootClientId( firstBlockClientId ); - - const blocksToUpdate = isUpdatingSelectedBlocks - ? selectedBlockClientIds - : [ clientId ]; - - return { - blocksToUpdate, - firstBlockClientId, - firstBlockRootClientId, - selectedBlockClientIds, - }; - } - - /** - * @param {KeyboardEvent} event - */ - async function onKeyDownHandler( event ) { - if ( event.keyCode === ENTER || event.keyCode === SPACE ) { - onClick( event ); - } else if ( - event.keyCode === BACKSPACE || - event.keyCode === DELETE || - isMatch( 'core/block-editor/remove', event ) - ) { - const { - blocksToUpdate: blocksToDelete, - firstBlockClientId, - firstBlockRootClientId, - selectedBlockClientIds, - } = getBlocksToUpdate(); - - // Don't update the selection if the blocks cannot be deleted. - if ( ! canRemoveBlocks( blocksToDelete, firstBlockRootClientId ) ) { - return; - } - - let blockToFocus = - getPreviousBlockClientId( firstBlockClientId ) ?? - // If the previous block is not found (when the first block is deleted), - // fallback to focus the parent block. - firstBlockRootClientId; - - removeBlocks( blocksToDelete, false ); - - // Update the selection if the original selection has been removed. - const shouldUpdateSelection = - selectedBlockClientIds.length > 0 && - getSelectedBlockClientIds().length === 0; - - // If there's no previous block nor parent block, focus the first block. - if ( ! blockToFocus ) { - blockToFocus = getBlockOrder()[ 0 ]; - } - - updateFocusAndSelection( blockToFocus, shouldUpdateSelection ); - } else if ( isMatch( 'core/block-editor/duplicate', event ) ) { - if ( event.defaultPrevented ) { - return; - } - event.preventDefault(); - - const { blocksToUpdate, firstBlockRootClientId } = - getBlocksToUpdate(); - - const canDuplicate = getBlocksByClientId( blocksToUpdate ).every( - ( block ) => { - return ( - !! block && - hasBlockSupport( block.name, 'multiple', true ) && - canInsertBlockType( block.name, firstBlockRootClientId ) - ); - } - ); - - if ( canDuplicate ) { - const updatedBlocks = await duplicateBlocks( - blocksToUpdate, - false - ); - - if ( updatedBlocks?.length ) { - // If blocks have been duplicated, focus the first duplicated block. - updateFocusAndSelection( updatedBlocks[ 0 ], false ); - } - } - } else if ( isMatch( 'core/block-editor/insert-before', event ) ) { - if ( event.defaultPrevented ) { - return; - } - event.preventDefault(); - - const { blocksToUpdate } = getBlocksToUpdate(); - await insertBeforeBlock( blocksToUpdate[ 0 ] ); - const newlySelectedBlocks = getSelectedBlockClientIds(); - - // Focus the first block of the newly inserted blocks, to keep focus within the list view. - updateFocusAndSelection( newlySelectedBlocks[ 0 ], false ); - } else if ( isMatch( 'core/block-editor/insert-after', event ) ) { - if ( event.defaultPrevented ) { - return; - } - event.preventDefault(); - - const { blocksToUpdate } = getBlocksToUpdate(); - await insertAfterBlock( blocksToUpdate.at( -1 ) ); - const newlySelectedBlocks = getSelectedBlockClientIds(); - - // Focus the first block of the newly inserted blocks, to keep focus within the list view. - updateFocusAndSelection( newlySelectedBlocks[ 0 ], false ); - } else if ( isMatch( 'core/block-editor/select-all', event ) ) { - if ( event.defaultPrevented ) { - return; - } - event.preventDefault(); - - const { firstBlockRootClientId, selectedBlockClientIds } = - getBlocksToUpdate(); - const blockClientIds = getBlockOrder( firstBlockRootClientId ); - if ( ! blockClientIds.length ) { - return; - } - - // If we have selected all sibling nested blocks, try selecting up a level. - // This is a similar implementation to that used by `useSelectAll`. - // `isShallowEqual` is used for the list view instead of a length check, - // as the array of siblings of the currently focused block may be a different - // set of blocks from the current block selection if the user is focused - // on a different part of the list view from the block selection. - if ( isShallowEqual( selectedBlockClientIds, blockClientIds ) ) { - // Only select up a level if the first block is not the root block. - // This ensures that the block selection can't break out of the root block - // used by the list view, if the list view is only showing a partial hierarchy. - if ( - firstBlockRootClientId && - firstBlockRootClientId !== rootClientId - ) { - updateFocusAndSelection( firstBlockRootClientId, true ); - return; - } - } - - // Select all while passing `null` to skip focusing to the editor canvas, - // and retain focus within the list view. - multiSelect( - blockClientIds[ 0 ], - blockClientIds[ blockClientIds.length - 1 ], - null - ); - } else if ( isMatch( 'core/block-editor/collapse-list-view', event ) ) { - if ( event.defaultPrevented ) { - return; - } - event.preventDefault(); - const { firstBlockClientId } = getBlocksToUpdate(); - const blockParents = getBlockParents( firstBlockClientId, false ); - // Collapse all blocks. - collapseAll(); - // Expand all parents of the current block. - expand( blockParents ); - } - } - return ( <> - + { blockInformation.anchor } + + + ) } + { positionLabel && isSticky && ( + + + + ) } + { images.length ? ( + + { images.map( ( image, index ) => ( + + ) ) } + + ) : null } + { isLocked && ( + + + + ) } + + ); } From 49c312c1bb29ac67db6ca4fbb20b739111f5a0e4 Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Fri, 26 Apr 2024 12:45:50 +0400 Subject: [PATCH 4/4] Close the dropdown when inserting block before|after --- packages/block-editor/src/components/list-view/block.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/block-editor/src/components/list-view/block.js b/packages/block-editor/src/components/list-view/block.js index 13baa44d4f66a..bb34c4f61b4ea 100644 --- a/packages/block-editor/src/components/list-view/block.js +++ b/packages/block-editor/src/components/list-view/block.js @@ -46,6 +46,7 @@ import { store as blockEditorStore } from '../../store'; import useBlockDisplayInformation from '../use-block-display-information'; import { useBlockLock } from '../block-lock'; import AriaReferencedText from './aria-referenced-text'; +import { unlock } from '../../lock-unlock'; function ListViewBlock( { block: { clientId }, @@ -87,7 +88,8 @@ function ListViewBlock( { removeBlocks, insertAfterBlock, insertBeforeBlock, - } = useDispatch( blockEditorStore ); + setOpenedBlockSettingsMenu, + } = unlock( useDispatch( blockEditorStore ) ); const { canInsertBlockType, @@ -263,6 +265,7 @@ function ListViewBlock( { const newlySelectedBlocks = getSelectedBlockClientIds(); // Focus the first block of the newly inserted blocks, to keep focus within the list view. + setOpenedBlockSettingsMenu( undefined ); updateFocusAndSelection( newlySelectedBlocks[ 0 ], false ); } else if ( isMatch( 'core/block-editor/insert-after', event ) ) { event.preventDefault(); @@ -272,6 +275,7 @@ function ListViewBlock( { const newlySelectedBlocks = getSelectedBlockClientIds(); // Focus the first block of the newly inserted blocks, to keep focus within the list view. + setOpenedBlockSettingsMenu( undefined ); updateFocusAndSelection( newlySelectedBlocks[ 0 ], false ); } else if ( isMatch( 'core/block-editor/select-all', event ) ) { event.preventDefault();