UNPKG

@wordpress/block-editor

Version:
256 lines (235 loc) 9.1 kB
import _extends from "@babel/runtime/helpers/esm/extends"; import { createElement, Fragment } from "@wordpress/element"; /** * WordPress dependencies */ import { getBlockType, serialize, store as blocksStore } from '@wordpress/blocks'; import { DropdownMenu, MenuGroup, MenuItem } from '@wordpress/components'; import { useDispatch, useSelect } from '@wordpress/data'; import { moreVertical } from '@wordpress/icons'; import { Children, cloneElement, useCallback, useRef } from '@wordpress/element'; import { __, sprintf } from '@wordpress/i18n'; import { store as keyboardShortcutsStore, __unstableUseShortcutEventMatch } from '@wordpress/keyboard-shortcuts'; import { pipe, useCopyToClipboard } from '@wordpress/compose'; /** * Internal dependencies */ import BlockActions from '../block-actions'; import BlockIcon from '../block-icon'; import BlockHTMLConvertButton from './block-html-convert-button'; import __unstableBlockSettingsMenuFirstItem from './block-settings-menu-first-item'; import BlockSettingsMenuControls from '../block-settings-menu-controls'; import { store as blockEditorStore } from '../../store'; import { useShowMoversGestures } from '../block-toolbar/utils'; const POPOVER_PROPS = { className: 'block-editor-block-settings-menu__popover', position: 'bottom right', variant: 'toolbar' }; function CopyMenuItem({ blocks, onCopy, label }) { const ref = useCopyToClipboard(() => serialize(blocks), onCopy); const copyMenuItemBlocksLabel = blocks.length > 1 ? __('Copy blocks') : __('Copy block'); const copyMenuItemLabel = label ? label : copyMenuItemBlocksLabel; return createElement(MenuItem, { ref: ref }, copyMenuItemLabel); } export function BlockSettingsDropdown({ clientIds, __experimentalSelectBlock, children, __unstableDisplayLocation, ...props }) { const blockClientIds = Array.isArray(clientIds) ? clientIds : [clientIds]; const count = blockClientIds.length; const firstBlockClientId = blockClientIds[0]; const { firstParentClientId, isDistractionFree, onlyBlock, parentBlockType, previousBlockClientId, selectedBlockClientIds } = useSelect(select => { const { getBlockCount, getBlockName, getBlockRootClientId, getPreviousBlockClientId, getSelectedBlockClientIds, getSettings, getBlockAttributes } = select(blockEditorStore); const { getActiveBlockVariation } = select(blocksStore); const _firstParentClientId = getBlockRootClientId(firstBlockClientId); const parentBlockName = _firstParentClientId && getBlockName(_firstParentClientId); return { firstParentClientId: _firstParentClientId, isDistractionFree: getSettings().isDistractionFree, onlyBlock: 1 === getBlockCount(_firstParentClientId), parentBlockType: _firstParentClientId && (getActiveBlockVariation(parentBlockName, getBlockAttributes(_firstParentClientId)) || getBlockType(parentBlockName)), previousBlockClientId: getPreviousBlockClientId(firstBlockClientId), selectedBlockClientIds: getSelectedBlockClientIds() }; }, [firstBlockClientId]); const { getBlockOrder, getSelectedBlockClientIds } = useSelect(blockEditorStore); const shortcuts = useSelect(select => { const { getShortcutRepresentation } = select(keyboardShortcutsStore); return { duplicate: getShortcutRepresentation('core/block-editor/duplicate'), remove: getShortcutRepresentation('core/block-editor/remove'), insertAfter: getShortcutRepresentation('core/block-editor/insert-after'), insertBefore: getShortcutRepresentation('core/block-editor/insert-before') }; }, []); const isMatch = __unstableUseShortcutEventMatch(); const { selectBlock, toggleBlockHighlight } = useDispatch(blockEditorStore); const hasSelectedBlocks = selectedBlockClientIds.length > 0; const updateSelectionAfterDuplicate = useCallback(async clientIdsPromise => { if (__experimentalSelectBlock) { const ids = await clientIdsPromise; if (ids && ids[0]) { __experimentalSelectBlock(ids[0], false); } } }, [__experimentalSelectBlock]); const updateSelectionAfterRemove = useCallback(() => { if (__experimentalSelectBlock) { let blockToFocus = previousBlockClientId || firstParentClientId; // Focus the first block if there's no previous block nor parent block. if (!blockToFocus) { blockToFocus = getBlockOrder()[0]; } // Only update the selection if the original selection is removed. const shouldUpdateSelection = hasSelectedBlocks && getSelectedBlockClientIds().length === 0; __experimentalSelectBlock(blockToFocus, shouldUpdateSelection); } }, [__experimentalSelectBlock, previousBlockClientId, firstParentClientId, getBlockOrder, hasSelectedBlocks, getSelectedBlockClientIds]); const removeBlockLabel = count === 1 ? __('Delete') : __('Delete blocks'); // Allows highlighting the parent block outline when focusing or hovering // the parent block selector within the child. const selectParentButtonRef = useRef(); const { gestures: showParentOutlineGestures } = useShowMoversGestures({ ref: selectParentButtonRef, onChange(isFocused) { if (isFocused && isDistractionFree) { return; } toggleBlockHighlight(firstParentClientId, isFocused); } }); // This can occur when the selected block (the parent) // displays child blocks within a List View. const parentBlockIsSelected = selectedBlockClientIds?.includes(firstParentClientId); return createElement(BlockActions, { clientIds: clientIds, __experimentalUpdateSelection: !__experimentalSelectBlock }, ({ canDuplicate, canInsertDefaultBlock, canMove, canRemove, onDuplicate, onInsertAfter, onInsertBefore, onRemove, onCopy, onPasteStyles, onMoveTo, blocks }) => createElement(DropdownMenu, _extends({ icon: moreVertical, label: __('Options'), className: "block-editor-block-settings-menu", popoverProps: POPOVER_PROPS, noIcons: true, menuProps: { /** * @param {KeyboardEvent} event */ onKeyDown(event) { if (event.defaultPrevented) return; if (isMatch('core/block-editor/remove', event) && canRemove) { event.preventDefault(); updateSelectionAfterRemove(onRemove()); } else if (isMatch('core/block-editor/duplicate', event) && canDuplicate) { event.preventDefault(); updateSelectionAfterDuplicate(onDuplicate()); } else if (isMatch('core/block-editor/insert-after', event) && canInsertDefaultBlock) { event.preventDefault(); onInsertAfter(); } else if (isMatch('core/block-editor/insert-before', event) && canInsertDefaultBlock) { event.preventDefault(); onInsertBefore(); } } } }, props), ({ onClose }) => createElement(Fragment, null, createElement(MenuGroup, null, createElement(__unstableBlockSettingsMenuFirstItem.Slot, { fillProps: { onClose } }), !parentBlockIsSelected && !!firstParentClientId && createElement(MenuItem, _extends({}, showParentOutlineGestures, { ref: selectParentButtonRef, icon: createElement(BlockIcon, { icon: parentBlockType.icon }), onClick: () => selectBlock(firstParentClientId) }), sprintf( /* translators: %s: Name of the block's parent. */ __('Select parent block (%s)'), parentBlockType.title)), count === 1 && createElement(BlockHTMLConvertButton, { clientId: firstBlockClientId }), createElement(CopyMenuItem, { blocks: blocks, onCopy: onCopy }), canDuplicate && createElement(MenuItem, { onClick: pipe(onClose, onDuplicate, updateSelectionAfterDuplicate), shortcut: shortcuts.duplicate }, __('Duplicate')), canInsertDefaultBlock && createElement(Fragment, null, createElement(MenuItem, { onClick: pipe(onClose, onInsertBefore), shortcut: shortcuts.insertBefore }, __('Add before')), createElement(MenuItem, { onClick: pipe(onClose, onInsertAfter), shortcut: shortcuts.insertAfter }, __('Add after')))), createElement(MenuGroup, null, createElement(CopyMenuItem, { blocks: blocks, onCopy: onCopy, label: __('Copy styles') }), createElement(MenuItem, { onClick: onPasteStyles }, __('Paste styles'))), createElement(BlockSettingsMenuControls.Slot, { fillProps: { onClose, canMove, onMoveTo, onlyBlock, count, firstBlockClientId }, clientIds: clientIds, __unstableDisplayLocation: __unstableDisplayLocation }), typeof children === 'function' ? children({ onClose }) : Children.map(child => cloneElement(child, { onClose })), canRemove && createElement(MenuGroup, null, createElement(MenuItem, { onClick: pipe(onClose, onRemove, updateSelectionAfterRemove), shortcut: shortcuts.remove }, removeBlockLabel))))); } export default BlockSettingsDropdown; //# sourceMappingURL=block-settings-dropdown.js.map