@wordpress/block-editor
Version:
292 lines (285 loc) • 11.9 kB
JavaScript
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
;