@wordpress/block-editor
Version:
8 lines (7 loc) • 7.79 kB
Source Map (JSON)
{
"version": 3,
"sources": ["../../../src/components/list-view/use-block-selection.js"],
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { speak } from '@wordpress/a11y';\nimport { __, sprintf } from '@wordpress/i18n';\nimport { useDispatch, useSelect } from '@wordpress/data';\nimport { useCallback } from '@wordpress/element';\nimport { UP, DOWN, HOME, END, ESCAPE } from '@wordpress/keycodes';\nimport { store as blocksStore } from '@wordpress/blocks';\n\n/**\n * Internal dependencies\n */\nimport { store as blockEditorStore } from '../../store';\nimport { getCommonDepthClientIds } from './utils';\n\nexport default function useBlockSelection() {\n\tconst { clearSelectedBlock, multiSelect, selectBlock } =\n\t\tuseDispatch( blockEditorStore );\n\tconst {\n\t\tgetBlockName,\n\t\tgetBlockParents,\n\t\tgetBlockSelectionStart,\n\t\tgetSelectedBlockClientIds,\n\t\thasMultiSelection,\n\t\thasSelectedBlock,\n\t} = useSelect( blockEditorStore );\n\n\tconst { getBlockType } = useSelect( blocksStore );\n\n\tconst updateBlockSelection = useCallback(\n\t\tasync ( event, clientId, destinationClientId, focusPosition ) => {\n\t\t\tif ( ! event?.shiftKey && event?.keyCode !== ESCAPE ) {\n\t\t\t\tselectBlock( clientId, focusPosition );\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// To handle multiple block selection via the `SHIFT` key, prevent\n\t\t\t// the browser default behavior of opening the link in a new window.\n\t\t\tevent.preventDefault();\n\n\t\t\tconst isOnlyDeselection =\n\t\t\t\tevent.type === 'keydown' && event.keyCode === ESCAPE;\n\t\t\tconst isKeyPress =\n\t\t\t\tevent.type === 'keydown' &&\n\t\t\t\t( event.keyCode === UP ||\n\t\t\t\t\tevent.keyCode === DOWN ||\n\t\t\t\t\tevent.keyCode === HOME ||\n\t\t\t\t\tevent.keyCode === END );\n\n\t\t\t// Handle clicking on a block when no blocks are selected, and return early.\n\t\t\tif (\n\t\t\t\t! isKeyPress &&\n\t\t\t\t! hasSelectedBlock() &&\n\t\t\t\t! hasMultiSelection()\n\t\t\t) {\n\t\t\t\tselectBlock( clientId, null );\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst selectedBlocks = getSelectedBlockClientIds();\n\t\t\tconst clientIdWithParents = [\n\t\t\t\t...getBlockParents( clientId ),\n\t\t\t\tclientId,\n\t\t\t];\n\n\t\t\tif (\n\t\t\t\tisOnlyDeselection ||\n\t\t\t\t( isKeyPress &&\n\t\t\t\t\t! selectedBlocks.some( ( blockId ) =>\n\t\t\t\t\t\tclientIdWithParents.includes( blockId )\n\t\t\t\t\t) )\n\t\t\t) {\n\t\t\t\t// Ensure that shift-selecting blocks via the keyboard only\n\t\t\t\t// expands the current selection if focusing over already\n\t\t\t\t// selected blocks. Otherwise, clear the selection so that\n\t\t\t\t// a user can create a new selection entirely by keyboard.\n\t\t\t\tawait clearSelectedBlock();\n\t\t\t}\n\n\t\t\t// Update selection, if not only clearing the selection.\n\t\t\tif ( ! isOnlyDeselection ) {\n\t\t\t\tlet startTarget = getBlockSelectionStart();\n\t\t\t\tlet endTarget = clientId;\n\n\t\t\t\t// Handle keyboard behavior for selecting multiple blocks.\n\t\t\t\tif ( isKeyPress ) {\n\t\t\t\t\tif ( ! hasSelectedBlock() && ! hasMultiSelection() ) {\n\t\t\t\t\t\t// Set the starting point of the selection to the currently\n\t\t\t\t\t\t// focused block, if there are no blocks currently selected.\n\t\t\t\t\t\t// This ensures that as the selection is expanded or contracted,\n\t\t\t\t\t\t// the starting point of the selection is anchored to that block.\n\t\t\t\t\t\tstartTarget = clientId;\n\t\t\t\t\t}\n\t\t\t\t\tif ( destinationClientId ) {\n\t\t\t\t\t\t// If the user presses UP or DOWN, we want to ensure that the block they're\n\t\t\t\t\t\t// moving to is the target for selection, and not the currently focused one.\n\t\t\t\t\t\tendTarget = destinationClientId;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst startParents = getBlockParents( startTarget );\n\t\t\t\tconst endParents = getBlockParents( endTarget );\n\n\t\t\t\tconst { start, end } = getCommonDepthClientIds(\n\t\t\t\t\tstartTarget,\n\t\t\t\t\tendTarget,\n\t\t\t\t\tstartParents,\n\t\t\t\t\tendParents\n\t\t\t\t);\n\t\t\t\tawait multiSelect( start, end, null );\n\t\t\t}\n\n\t\t\t// Announce deselected block, or number of deselected blocks if\n\t\t\t// the total number of blocks deselected is greater than one.\n\t\t\tconst updatedSelectedBlocks = getSelectedBlockClientIds();\n\n\t\t\t// If the selection is greater than 1 and the Home or End keys\n\t\t\t// were used to generate the selection, then skip announcing the\n\t\t\t// deselected blocks.\n\t\t\tif (\n\t\t\t\t( event.keyCode === HOME || event.keyCode === END ) &&\n\t\t\t\tupdatedSelectedBlocks.length > 1\n\t\t\t) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst selectionDiff = selectedBlocks.filter(\n\t\t\t\t( blockId ) => ! updatedSelectedBlocks.includes( blockId )\n\t\t\t);\n\n\t\t\tlet label;\n\t\t\tif ( selectionDiff.length === 1 ) {\n\t\t\t\tconst title = getBlockType(\n\t\t\t\t\tgetBlockName( selectionDiff[ 0 ] )\n\t\t\t\t)?.title;\n\t\t\t\tif ( title ) {\n\t\t\t\t\tlabel = sprintf(\n\t\t\t\t\t\t/* translators: %s: block name */\n\t\t\t\t\t\t__( '%s deselected.' ),\n\t\t\t\t\t\ttitle\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} else if ( selectionDiff.length > 1 ) {\n\t\t\t\tlabel = sprintf(\n\t\t\t\t\t/* translators: %s: number of deselected blocks */\n\t\t\t\t\t__( '%s blocks deselected.' ),\n\t\t\t\t\tselectionDiff.length\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif ( label ) {\n\t\t\t\tspeak( label, 'assertive' );\n\t\t\t}\n\t\t},\n\t\t[\n\t\t\tclearSelectedBlock,\n\t\t\tgetBlockName,\n\t\t\tgetBlockType,\n\t\t\tgetBlockParents,\n\t\t\tgetBlockSelectionStart,\n\t\t\tgetSelectedBlockClientIds,\n\t\t\thasMultiSelection,\n\t\t\thasSelectedBlock,\n\t\t\tmultiSelect,\n\t\t\tselectBlock,\n\t\t]\n\t);\n\n\treturn {\n\t\tupdateBlockSelection,\n\t};\n}\n"],
"mappings": "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",
"names": ["blockEditorStore", "blocksStore"]
}