@wordpress/block-editor
Version:
224 lines (220 loc) • 10.2 kB
JavaScript
"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