UNPKG

@wordpress/block-editor

Version:
224 lines (220 loc) 10.2 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = BlockTools; var _data = require("@wordpress/data"); var _dom = require("@wordpress/dom"); var _components = require("@wordpress/components"); var _keyboardShortcuts = require("@wordpress/keyboard-shortcuts"); var _element = require("@wordpress/element"); var _blocks = require("@wordpress/blocks"); var _a11y = require("@wordpress/a11y"); var _i18n = require("@wordpress/i18n"); var _emptyBlockInserter = _interopRequireDefault(require("./empty-block-inserter")); var _insertionPoint = _interopRequireWildcard(require("./insertion-point")); var _blockToolbarPopover = _interopRequireDefault(require("./block-toolbar-popover")); var _store = require("../../store"); var _usePopoverScroll = _interopRequireDefault(require("../block-popover/use-popover-scroll")); var _zoomOutModeInserters = _interopRequireDefault(require("./zoom-out-mode-inserters")); var _useShowBlockTools = require("./use-show-block-tools"); var _lockUnlock = require("../../lock-unlock"); var _usePasteStyles = _interopRequireDefault(require("../use-paste-styles")); var _jsxRuntime = require("react/jsx-runtime"); function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } /** * WordPress dependencies */ /** * Internal dependencies */ function selector(select) { const { getSelectedBlockClientId, getFirstMultiSelectedBlockClientId, getSettings, isTyping, isDragging, isZoomOut } = (0, _lockUnlock.unlock)(select(_store.store)); const clientId = getSelectedBlockClientId() || getFirstMultiSelectedBlockClientId(); return { clientId, hasFixedToolbar: getSettings().hasFixedToolbar, isTyping: isTyping(), isZoomOutMode: isZoomOut(), isDragging: isDragging() }; } /** * Renders block tools (the block toolbar, select/navigation mode toolbar, the * insertion point and a slot for the inline rich text toolbar). Must be wrapped * around the block content and editor styles wrapper or iframe. * * @param {Object} $0 Props. * @param {Object} $0.children The block content and style container. * @param {Object} $0.__unstableContentRef Ref holding the content scroll container. */ function BlockTools({ children, __unstableContentRef, ...props }) { const { clientId, hasFixedToolbar, isTyping, isZoomOutMode, isDragging } = (0, _data.useSelect)(selector, []); const isMatch = (0, _keyboardShortcuts.__unstableUseShortcutEventMatch)(); const { getBlocksByClientId, getSelectedBlockClientIds, getBlockRootClientId, isGroupable } = (0, _data.useSelect)(_store.store); const { getGroupingBlockName } = (0, _data.useSelect)(_blocks.store); const { showEmptyBlockSideInserter, showBlockToolbarPopover } = (0, _useShowBlockTools.useShowBlockTools)(); const pasteStyles = (0, _usePasteStyles.default)(); const { duplicateBlocks, removeBlocks, replaceBlocks, insertAfterBlock, insertBeforeBlock, selectBlock, moveBlocksUp, moveBlocksDown, expandBlock } = (0, _lockUnlock.unlock)((0, _data.useDispatch)(_store.store)); function onKeyDown(event) { if (event.defaultPrevented) { return; } if (isMatch('core/block-editor/move-up', event) || isMatch('core/block-editor/move-down', event)) { const clientIds = getSelectedBlockClientIds(); if (clientIds.length) { event.preventDefault(); const rootClientId = getBlockRootClientId(clientIds[0]); const direction = isMatch('core/block-editor/move-up', event) ? 'up' : 'down'; if (direction === 'up') { moveBlocksUp(clientIds, rootClientId); } else { moveBlocksDown(clientIds, rootClientId); } const blockLength = Array.isArray(clientIds) ? clientIds.length : 1; const message = (0, _i18n.sprintf)( // translators: %d: the name of the block that has been moved (0, _i18n._n)('%d block moved.', '%d blocks moved.', clientIds.length), blockLength); (0, _a11y.speak)(message); } } else if (isMatch('core/block-editor/duplicate', event)) { const clientIds = getSelectedBlockClientIds(); if (clientIds.length) { event.preventDefault(); duplicateBlocks(clientIds); } } else if (isMatch('core/block-editor/remove', event)) { const clientIds = getSelectedBlockClientIds(); if (clientIds.length) { event.preventDefault(); removeBlocks(clientIds); } } else if (isMatch('core/block-editor/paste-styles', event)) { const clientIds = getSelectedBlockClientIds(); if (clientIds.length) { event.preventDefault(); const blocks = getBlocksByClientId(clientIds); pasteStyles(blocks); } } else if (isMatch('core/block-editor/insert-after', event)) { const clientIds = getSelectedBlockClientIds(); if (clientIds.length) { event.preventDefault(); insertAfterBlock(clientIds[clientIds.length - 1]); } } else if (isMatch('core/block-editor/insert-before', event)) { const clientIds = getSelectedBlockClientIds(); if (clientIds.length) { event.preventDefault(); insertBeforeBlock(clientIds[0]); } } else if (isMatch('core/block-editor/unselect', event)) { if (event.target.closest('[role=toolbar]')) { // This shouldn't be necessary, but we have a combination of a few things all combining to create a situation where: // - Because the block toolbar uses createPortal to populate the block toolbar fills, we can't rely on the React event bubbling to hit the onKeyDown listener for the block toolbar // - Since we can't use the React tree, we use the DOM tree which _should_ handle the event bubbling correctly from a `createPortal` element. // - This bubbles via the React tree, which hits this `unselect` escape keypress before the block toolbar DOM event listener has access to it. // An alternative would be to remove the addEventListener on the navigableToolbar and use this event to handle it directly right here. That feels hacky too though. return; } const clientIds = getSelectedBlockClientIds(); if (clientIds.length > 1) { event.preventDefault(); // If there is more than one block selected, select the first // block so that focus is directed back to the beginning of the selection. // In effect, to the user this feels like deselecting the multi-selection. selectBlock(clientIds[0]); } } else if (isMatch('core/block-editor/collapse-list-view', event)) { // If focus is currently within a text field, such as a rich text block or other editable field, // skip collapsing the list view, and allow the keyboard shortcut to be handled by the text field. // This condition checks for both the active element and the active element within an iframed editor. if ((0, _dom.isTextField)(event.target) || (0, _dom.isTextField)(event.target?.contentWindow?.document?.activeElement)) { return; } event.preventDefault(); expandBlock(clientId); } else if (isMatch('core/block-editor/group', event)) { const clientIds = getSelectedBlockClientIds(); if (clientIds.length > 1 && isGroupable(clientIds)) { event.preventDefault(); const blocks = getBlocksByClientId(clientIds); const groupingBlockName = getGroupingBlockName(); const newBlocks = (0, _blocks.switchToBlockType)(blocks, groupingBlockName); replaceBlocks(clientIds, newBlocks); (0, _a11y.speak)((0, _i18n.__)('Selected blocks are grouped.')); } } } const blockToolbarRef = (0, _usePopoverScroll.default)(__unstableContentRef); const blockToolbarAfterRef = (0, _usePopoverScroll.default)(__unstableContentRef); return ( /*#__PURE__*/ // eslint-disable-next-line jsx-a11y/no-static-element-interactions (0, _jsxRuntime.jsx)("div", { ...props, onKeyDown: onKeyDown, children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_insertionPoint.InsertionPointOpenRef.Provider, { value: (0, _element.useRef)(false), children: [!isTyping && !isZoomOutMode && /*#__PURE__*/(0, _jsxRuntime.jsx)(_insertionPoint.default, { __unstableContentRef: __unstableContentRef }), showEmptyBlockSideInserter && /*#__PURE__*/(0, _jsxRuntime.jsx)(_emptyBlockInserter.default, { __unstableContentRef: __unstableContentRef, clientId: clientId }), showBlockToolbarPopover && /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockToolbarPopover.default, { __unstableContentRef: __unstableContentRef, clientId: clientId, isTyping: isTyping }), !isZoomOutMode && !hasFixedToolbar && /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Popover.Slot, { name: "block-toolbar", ref: blockToolbarRef }), children, /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Popover.Slot, { name: "__unstable-block-tools-after", ref: blockToolbarAfterRef }), isZoomOutMode && !isDragging && /*#__PURE__*/(0, _jsxRuntime.jsx)(_zoomOutModeInserters.default, { __unstableContentRef: __unstableContentRef })] }) }) ); } //# sourceMappingURL=index.js.map