UNPKG

@wordpress/block-editor

Version:
292 lines (285 loc) 11.9 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.BlockSettingsDropdown = BlockSettingsDropdown; exports.default = void 0; var _blocks = require("@wordpress/blocks"); var _components = require("@wordpress/components"); var _data = require("@wordpress/data"); var _icons = require("@wordpress/icons"); var _element = require("@wordpress/element"); var _i18n = require("@wordpress/i18n"); var _keyboardShortcuts = require("@wordpress/keyboard-shortcuts"); var _compose = require("@wordpress/compose"); var _blockActions = _interopRequireDefault(require("../block-actions")); var _blockCommentIconSlot = _interopRequireDefault(require("../../components/collab/block-comment-icon-slot")); var _blockHtmlConvertButton = _interopRequireDefault(require("./block-html-convert-button")); var _blockSettingsMenuFirstItem = _interopRequireDefault(require("./block-settings-menu-first-item")); var _blockSettingsMenuControls = _interopRequireDefault(require("../block-settings-menu-controls")); var _blockParentSelectorMenuItem = _interopRequireDefault(require("./block-parent-selector-menu-item")); var _store = require("../../store"); var _lockUnlock = require("../../lock-unlock"); var _useNotifyCopy = require("../../utils/use-notify-copy"); var _jsxRuntime = require("react/jsx-runtime"); /** * WordPress dependencies */ /** * Internal dependencies */ const POPOVER_PROPS = { className: 'block-editor-block-settings-menu__popover', placement: 'bottom-start' }; function CopyMenuItem({ clientIds, onCopy, label, shortcut, eventType = 'copy', __experimentalUpdateSelection: updateSelection = false }) { const { getBlocksByClientId } = (0, _data.useSelect)(_store.store); const { removeBlocks } = (0, _data.useDispatch)(_store.store); const notifyCopy = (0, _useNotifyCopy.useNotifyCopy)(); const ref = (0, _compose.useCopyToClipboard)(() => (0, _blocks.serialize)(getBlocksByClientId(clientIds)), () => { switch (eventType) { case 'copy': case 'copyStyles': onCopy(); notifyCopy(eventType, clientIds); break; case 'cut': notifyCopy(eventType, clientIds); removeBlocks(clientIds, updateSelection); break; default: break; } }); const copyMenuItemLabel = label ? label : (0, _i18n.__)('Copy'); return /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.MenuItem, { ref: ref, shortcut: shortcut, children: copyMenuItemLabel }); } function BlockSettingsDropdown({ block, clientIds, children, __experimentalSelectBlock, ...props }) { // Get the client id of the current block for this menu, if one is set. const currentClientId = block?.clientId; const count = clientIds.length; const firstBlockClientId = clientIds[0]; const { firstParentClientId, parentBlockType, previousBlockClientId, selectedBlockClientIds, openedBlockSettingsMenu, isContentOnly } = (0, _data.useSelect)(select => { const { getBlockName, getBlockRootClientId, getPreviousBlockClientId, getSelectedBlockClientIds, getBlockAttributes, getOpenedBlockSettingsMenu, getBlockEditingMode } = (0, _lockUnlock.unlock)(select(_store.store)); const { getActiveBlockVariation } = select(_blocks.store); const _firstParentClientId = getBlockRootClientId(firstBlockClientId); const parentBlockName = _firstParentClientId && getBlockName(_firstParentClientId); return { firstParentClientId: _firstParentClientId, parentBlockType: _firstParentClientId && (getActiveBlockVariation(parentBlockName, getBlockAttributes(_firstParentClientId)) || (0, _blocks.getBlockType)(parentBlockName)), previousBlockClientId: getPreviousBlockClientId(firstBlockClientId), selectedBlockClientIds: getSelectedBlockClientIds(), openedBlockSettingsMenu: getOpenedBlockSettingsMenu(), isContentOnly: getBlockEditingMode(firstBlockClientId) === 'contentOnly' }; }, [firstBlockClientId]); const { getBlockOrder, getSelectedBlockClientIds } = (0, _data.useSelect)(_store.store); const { setOpenedBlockSettingsMenu } = (0, _lockUnlock.unlock)((0, _data.useDispatch)(_store.store)); const shortcuts = (0, _data.useSelect)(select => { const { getShortcutRepresentation } = select(_keyboardShortcuts.store); return { copy: getShortcutRepresentation('core/block-editor/copy'), cut: getShortcutRepresentation('core/block-editor/cut'), 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 hasSelectedBlocks = selectedBlockClientIds.length > 0; async function updateSelectionAfterDuplicate(clientIdsPromise) { if (!__experimentalSelectBlock) { return; } const ids = await clientIdsPromise; if (ids && ids[0]) { __experimentalSelectBlock(ids[0], false); } } function updateSelectionAfterRemove() { if (!__experimentalSelectBlock) { return; } 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); } // This can occur when the selected block (the parent) // displays child blocks within a List View. const parentBlockIsSelected = selectedBlockClientIds?.includes(firstParentClientId); // When a currentClientId is in use, treat the menu as a controlled component. // This ensures that only one block settings menu is open at a time. // This is a temporary solution to work around an issue with `onFocusOutside` // where it does not allow a dropdown to be closed if focus was never within // the dropdown to begin with. Examples include a user either CMD+Clicking or // right clicking into an inactive window. // See: https://github.com/WordPress/gutenberg/pull/54083 const open = !currentClientId ? undefined : openedBlockSettingsMenu === currentClientId || false; function onToggle(localOpen) { if (localOpen && openedBlockSettingsMenu !== currentClientId) { setOpenedBlockSettingsMenu(currentClientId); } else if (!localOpen && openedBlockSettingsMenu && openedBlockSettingsMenu === currentClientId) { setOpenedBlockSettingsMenu(undefined); } } const shouldShowBlockParentMenuItem = !parentBlockIsSelected && !!firstParentClientId; return /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockActions.default, { clientIds: clientIds, __experimentalUpdateSelection: !__experimentalSelectBlock, children: ({ canCopyStyles, canDuplicate, canInsertBlock, canRemove, onDuplicate, onInsertAfter, onInsertBefore, onRemove, onCopy, onPasteStyles }) => { // It is possible that some plugins register fills for this menu // even if Core doesn't render anything in the block settings menu. // in which case, we may want to render the menu anyway. // That said for now, we can start more conservative. const isEmpty = !canRemove && !canDuplicate && !canInsertBlock && isContentOnly; if (isEmpty) { return null; } return /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.DropdownMenu, { icon: _icons.moreVertical, label: (0, _i18n.__)('Options'), className: "block-editor-block-settings-menu", popoverProps: POPOVER_PROPS, open: open, onToggle: onToggle, noIcons: true, ...props, children: ({ onClose }) => /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, { children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_components.MenuGroup, { children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_blockSettingsMenuFirstItem.default.Slot, { fillProps: { onClose } }), shouldShowBlockParentMenuItem && /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockParentSelectorMenuItem.default, { parentClientId: firstParentClientId, parentBlockType: parentBlockType }), count === 1 && /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockHtmlConvertButton.default, { clientId: firstBlockClientId }), /*#__PURE__*/(0, _jsxRuntime.jsx)(CopyMenuItem, { clientIds: clientIds, onCopy: onCopy, shortcut: shortcuts.copy }), /*#__PURE__*/(0, _jsxRuntime.jsx)(CopyMenuItem, { clientIds: clientIds, label: (0, _i18n.__)('Cut'), eventType: "cut", shortcut: shortcuts.cut, __experimentalUpdateSelection: !__experimentalSelectBlock }), canDuplicate && /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.MenuItem, { onClick: (0, _compose.pipe)(onClose, onDuplicate, updateSelectionAfterDuplicate), shortcut: shortcuts.duplicate, children: (0, _i18n.__)('Duplicate') }), canInsertBlock && !isContentOnly && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, { children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_components.MenuItem, { onClick: (0, _compose.pipe)(onClose, onInsertBefore), shortcut: shortcuts.insertBefore, children: (0, _i18n.__)('Add before') }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.MenuItem, { onClick: (0, _compose.pipe)(onClose, onInsertAfter), shortcut: shortcuts.insertAfter, children: (0, _i18n.__)('Add after') })] }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockCommentIconSlot.default.Slot, { fillProps: { onClose } })] }), canCopyStyles && !isContentOnly && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_components.MenuGroup, { children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(CopyMenuItem, { clientIds: clientIds, onCopy: onCopy, label: (0, _i18n.__)('Copy styles'), eventType: "copyStyles" }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.MenuItem, { onClick: onPasteStyles, children: (0, _i18n.__)('Paste styles') })] }), !isContentOnly && /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockSettingsMenuControls.default.Slot, { fillProps: { onClose, count, firstBlockClientId }, clientIds: clientIds }), typeof children === 'function' ? children({ onClose }) : _element.Children.map(child => (0, _element.cloneElement)(child, { onClose })), canRemove && /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.MenuGroup, { children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.MenuItem, { onClick: (0, _compose.pipe)(onClose, onRemove, updateSelectionAfterRemove), shortcut: shortcuts.remove, children: (0, _i18n.__)('Delete') }) })] }) }); } }); } var _default = exports.default = BlockSettingsDropdown; //# sourceMappingURL=block-settings-dropdown.js.map