@wordpress/block-editor
Version:
558 lines (556 loc) • 21.7 kB
JavaScript
;
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// packages/block-editor/src/components/list-view/block.js
var block_exports = {};
__export(block_exports, {
default: () => block_default
});
module.exports = __toCommonJS(block_exports);
var import_clsx = __toESM(require("clsx"));
var import_blocks = require("@wordpress/blocks");
var import_components = require("@wordpress/components");
var import_compose = require("@wordpress/compose");
var import_icons = require("@wordpress/icons");
var import_element = require("@wordpress/element");
var import_data = require("@wordpress/data");
var import_i18n = require("@wordpress/i18n");
var import_keycodes = require("@wordpress/keycodes");
var import_is_shallow_equal = __toESM(require("@wordpress/is-shallow-equal"));
var import_keyboard_shortcuts = require("@wordpress/keyboard-shortcuts");
var import_a11y = require("@wordpress/a11y");
var import_leaf = __toESM(require("./leaf"));
var import_use_list_view_scroll_into_view = __toESM(require("./use-list-view-scroll-into-view"));
var import_button = require("../block-mover/button");
var import_block_contents = __toESM(require("./block-contents"));
var import_context = require("./context");
var import_utils = require("./utils");
var import_store = require("../../store");
var import_use_block_display_information = __toESM(require("../use-block-display-information"));
var import_block_lock = require("../block-lock");
var import_aria_referenced_text = __toESM(require("./aria-referenced-text"));
var import_lock_unlock = require("../../lock-unlock");
var import_use_paste_styles = __toESM(require("../use-paste-styles"));
var import_utils2 = require("../../hooks/utils");
var import_jsx_runtime = require("react/jsx-runtime");
function ListViewBlock({
block: { clientId },
displacement,
isAfterDraggedBlocks,
isDragged,
isNesting,
isSelected,
isBranchSelected,
selectBlock,
position,
level,
rowCount,
siblingBlockCount,
showBlockMovers,
path,
isExpanded,
selectedClientIds,
isSyncedBranch
}) {
const cellRef = (0, import_element.useRef)(null);
const rowRef = (0, import_element.useRef)(null);
const settingsRef = (0, import_element.useRef)(null);
const [isHovered, setIsHovered] = (0, import_element.useState)(false);
const [settingsAnchorRect, setSettingsAnchorRect] = (0, import_element.useState)();
const { isLocked } = (0, import_block_lock.useBlockLock)(clientId);
const isFirstSelectedBlock = isSelected && selectedClientIds[0] === clientId;
const isLastSelectedBlock = isSelected && selectedClientIds[selectedClientIds.length - 1] === clientId;
const {
toggleBlockHighlight,
duplicateBlocks,
multiSelect,
replaceBlocks,
removeBlocks,
insertAfterBlock,
insertBeforeBlock,
setOpenedBlockSettingsMenu,
updateBlockAttributes
} = (0, import_lock_unlock.unlock)((0, import_data.useDispatch)(import_store.store));
const debouncedToggleBlockHighlight = (0, import_compose.useDebounce)(
toggleBlockHighlight,
50
);
const {
canInsertBlockType,
getSelectedBlockClientIds,
getPreviousBlockClientId,
getBlockRootClientId,
getBlockOrder,
getBlockParents,
getBlocksByClientId,
canEditBlock,
canMoveBlock,
canRemoveBlocks,
isGroupable
} = (0, import_data.useSelect)(import_store.store);
const { getGroupingBlockName } = (0, import_data.useSelect)(import_blocks.store);
const blockInformation = (0, import_use_block_display_information.default)(clientId);
const pasteStyles = (0, import_use_paste_styles.default)();
const { block, blockName, allowRightClickOverrides, isBlockHidden } = (0, import_data.useSelect)(
(select) => {
const { getBlock, getBlockName, getSettings } = select(import_store.store);
const { isBlockHidden: _isBlockHidden } = (0, import_lock_unlock.unlock)(
select(import_store.store)
);
return {
block: getBlock(clientId),
blockName: getBlockName(clientId),
allowRightClickOverrides: getSettings().allowRightClickOverrides,
isBlockHidden: _isBlockHidden(clientId)
};
},
[clientId]
);
const showBlockActions = (
// When a block hides its toolbar it also hides the block settings menu,
// since that menu is part of the toolbar in the editor canvas.
// List View respects this by also hiding the block settings menu.
(0, import_blocks.hasBlockSupport)(blockName, "__experimentalToolbar", true)
);
const instanceId = (0, import_compose.useInstanceId)(ListViewBlock);
const descriptionId = `list-view-block-select-button__description-${instanceId}`;
const {
expand,
collapse,
collapseAll,
BlockSettingsMenu,
listViewInstanceId,
expandedState,
setInsertedBlock,
treeGridElementRef,
rootClientId
} = (0, import_context.useListViewContext)();
const isMatch = (0, import_keyboard_shortcuts.__unstableUseShortcutEventMatch)();
function getBlocksToUpdate() {
const selectedBlockClientIds = getSelectedBlockClientIds();
const isUpdatingSelectedBlocks = selectedBlockClientIds.includes(clientId);
const firstBlockClientId = isUpdatingSelectedBlocks ? selectedBlockClientIds[0] : clientId;
const firstBlockRootClientId = getBlockRootClientId(firstBlockClientId);
const blocksToUpdate = isUpdatingSelectedBlocks ? selectedBlockClientIds : [clientId];
return {
blocksToUpdate,
firstBlockClientId,
firstBlockRootClientId,
selectedBlockClientIds
};
}
async function onKeyDown(event) {
if (event.defaultPrevented) {
return;
}
if (event.target.closest("[role=dialog]")) {
return;
}
const isDeleteKey = [import_keycodes.BACKSPACE, import_keycodes.DELETE].includes(event.keyCode);
if (isMatch("core/block-editor/unselect", event) && selectedClientIds.length > 0) {
event.stopPropagation();
event.preventDefault();
selectBlock(event, void 0);
} else if (isDeleteKey || isMatch("core/block-editor/remove", event)) {
const {
blocksToUpdate: blocksToDelete,
firstBlockClientId,
firstBlockRootClientId,
selectedBlockClientIds
} = getBlocksToUpdate();
if (!canRemoveBlocks(blocksToDelete)) {
return;
}
let blockToFocus = getPreviousBlockClientId(firstBlockClientId) ?? // If the previous block is not found (when the first block is deleted),
// fallback to focus the parent block.
firstBlockRootClientId;
removeBlocks(blocksToDelete, false);
const shouldUpdateSelection = selectedBlockClientIds.length > 0 && getSelectedBlockClientIds().length === 0;
if (!blockToFocus) {
blockToFocus = getBlockOrder()[0];
}
updateFocusAndSelection(blockToFocus, shouldUpdateSelection);
} else if (isMatch("core/block-editor/paste-styles", event)) {
event.preventDefault();
const { blocksToUpdate } = getBlocksToUpdate();
const blocks = getBlocksByClientId(blocksToUpdate);
pasteStyles(blocks);
} else if (isMatch("core/block-editor/duplicate", event)) {
event.preventDefault();
const { blocksToUpdate, firstBlockRootClientId } = getBlocksToUpdate();
const canDuplicate = getBlocksByClientId(blocksToUpdate).every(
(blockToUpdate) => {
return !!blockToUpdate && (0, import_blocks.hasBlockSupport)(
blockToUpdate.name,
"multiple",
true
) && canInsertBlockType(
blockToUpdate.name,
firstBlockRootClientId
);
}
);
if (canDuplicate) {
const updatedBlocks = await duplicateBlocks(
blocksToUpdate,
false
);
if (updatedBlocks?.length) {
updateFocusAndSelection(updatedBlocks[0], false);
}
}
} else if (isMatch("core/block-editor/insert-before", event)) {
event.preventDefault();
const { blocksToUpdate } = getBlocksToUpdate();
await insertBeforeBlock(blocksToUpdate[0]);
const newlySelectedBlocks = getSelectedBlockClientIds();
setOpenedBlockSettingsMenu(void 0);
updateFocusAndSelection(newlySelectedBlocks[0], false);
} else if (isMatch("core/block-editor/insert-after", event)) {
event.preventDefault();
const { blocksToUpdate } = getBlocksToUpdate();
await insertAfterBlock(blocksToUpdate.at(-1));
const newlySelectedBlocks = getSelectedBlockClientIds();
setOpenedBlockSettingsMenu(void 0);
updateFocusAndSelection(newlySelectedBlocks[0], false);
} else if (isMatch("core/block-editor/select-all", event)) {
event.preventDefault();
const { firstBlockRootClientId, selectedBlockClientIds } = getBlocksToUpdate();
const blockClientIds = getBlockOrder(firstBlockRootClientId);
if (!blockClientIds.length) {
return;
}
if ((0, import_is_shallow_equal.default)(selectedBlockClientIds, blockClientIds)) {
if (firstBlockRootClientId && firstBlockRootClientId !== rootClientId) {
updateFocusAndSelection(firstBlockRootClientId, true);
return;
}
}
multiSelect(
blockClientIds[0],
blockClientIds[blockClientIds.length - 1],
null
);
} else if (isMatch("core/block-editor/collapse-list-view", event)) {
event.preventDefault();
const { firstBlockClientId } = getBlocksToUpdate();
const blockParents = getBlockParents(firstBlockClientId, false);
collapseAll();
expand(blockParents);
} else if (isMatch("core/block-editor/group", event)) {
const { blocksToUpdate } = getBlocksToUpdate();
if (blocksToUpdate.length > 1 && isGroupable(blocksToUpdate)) {
event.preventDefault();
const blocks = getBlocksByClientId(blocksToUpdate);
const groupingBlockName = getGroupingBlockName();
const newBlocks = (0, import_blocks.switchToBlockType)(
blocks,
groupingBlockName
);
replaceBlocks(blocksToUpdate, newBlocks);
(0, import_a11y.speak)((0, import_i18n.__)("Selected blocks are grouped."));
const newlySelectedBlocks = getSelectedBlockClientIds();
setOpenedBlockSettingsMenu(void 0);
updateFocusAndSelection(newlySelectedBlocks[0], false);
}
} else if (isMatch("core/block-editor/toggle-block-visibility", event)) {
event.preventDefault();
const { blocksToUpdate } = getBlocksToUpdate();
const blocks = getBlocksByClientId(blocksToUpdate);
const canToggleVisibility = blocks.every(
(blockToUpdate) => (0, import_blocks.hasBlockSupport)(blockToUpdate.name, "visibility", true)
);
if (!canToggleVisibility) {
return;
}
const hasHiddenBlock = blocks.some(
(blockToUpdate) => blockToUpdate.attributes.metadata?.blockVisibility === false
);
const attributesByClientId = Object.fromEntries(
blocks.map(({ clientId: mapClientId, attributes }) => [
mapClientId,
{
metadata: (0, import_utils2.cleanEmptyObject)({
...attributes?.metadata,
blockVisibility: hasHiddenBlock ? void 0 : false
})
}
])
);
updateBlockAttributes(blocksToUpdate, attributesByClientId, {
uniqueByBlock: true
});
}
}
const onMouseEnter = (0, import_element.useCallback)(() => {
setIsHovered(true);
debouncedToggleBlockHighlight(clientId, true);
}, [clientId, setIsHovered, debouncedToggleBlockHighlight]);
const onMouseLeave = (0, import_element.useCallback)(() => {
setIsHovered(false);
debouncedToggleBlockHighlight(clientId, false);
}, [clientId, setIsHovered, debouncedToggleBlockHighlight]);
const selectEditorBlock = (0, import_element.useCallback)(
(event) => {
selectBlock(event, clientId);
event.preventDefault();
},
[clientId, selectBlock]
);
const updateFocusAndSelection = (0, import_element.useCallback)(
(focusClientId, shouldSelectBlock) => {
if (shouldSelectBlock) {
selectBlock(void 0, focusClientId, null, null);
}
(0, import_utils.focusListItem)(focusClientId, treeGridElementRef?.current);
},
[selectBlock, treeGridElementRef]
);
const toggleExpanded = (0, import_element.useCallback)(
(event) => {
event.preventDefault();
event.stopPropagation();
if (isExpanded === true) {
collapse(clientId);
} else if (isExpanded === false) {
expand(clientId);
}
},
[clientId, expand, collapse, isExpanded]
);
const onContextMenu = (0, import_element.useCallback)(
(event) => {
if (showBlockActions && allowRightClickOverrides) {
settingsRef.current?.click();
setSettingsAnchorRect(
new window.DOMRect(event.clientX, event.clientY, 0, 0)
);
event.preventDefault();
}
},
[allowRightClickOverrides, settingsRef, showBlockActions]
);
const onMouseDown = (0, import_element.useCallback)(
(event) => {
if (allowRightClickOverrides && event.button === 2) {
event.preventDefault();
}
},
[allowRightClickOverrides]
);
const settingsPopoverAnchor = (0, import_element.useMemo)(() => {
const { ownerDocument } = rowRef?.current || {};
if (!settingsAnchorRect || !ownerDocument) {
return void 0;
}
return {
ownerDocument,
getBoundingClientRect() {
return settingsAnchorRect;
}
};
}, [settingsAnchorRect]);
const clearSettingsAnchorRect = (0, import_element.useCallback)(() => {
setSettingsAnchorRect(void 0);
}, [setSettingsAnchorRect]);
(0, import_use_list_view_scroll_into_view.default)({
isSelected,
rowItemRef: rowRef,
selectedClientIds
});
if (!block) {
return null;
}
const blockPositionDescription = (0, import_utils.getBlockPositionDescription)(
position,
siblingBlockCount,
level
);
const blockPropertiesDescription = (0, import_utils.getBlockPropertiesDescription)(
blockInformation,
isLocked
);
const blockVisibilityDescription = isBlockHidden ? (0, import_i18n.__)("Block is hidden.") : null;
const hasSiblings = siblingBlockCount > 0;
const hasRenderedMovers = showBlockMovers && hasSiblings;
const moverCellClassName = (0, import_clsx.default)(
"block-editor-list-view-block__mover-cell",
{ "is-visible": isHovered || isSelected }
);
const listViewBlockSettingsClassName = (0, import_clsx.default)(
"block-editor-list-view-block__menu-cell",
{ "is-visible": isHovered || isFirstSelectedBlock }
);
let colSpan;
if (hasRenderedMovers) {
colSpan = 2;
} else if (!showBlockActions) {
colSpan = 3;
}
const classes = (0, import_clsx.default)({
"is-selected": isSelected,
"is-first-selected": isFirstSelectedBlock,
"is-last-selected": isLastSelectedBlock,
"is-branch-selected": isBranchSelected,
"is-synced-branch": isSyncedBranch,
"is-dragging": isDragged,
"has-single-cell": !showBlockActions,
"is-synced": blockInformation?.isSynced,
"is-draggable": canMoveBlock,
"is-displacement-normal": displacement === "normal",
"is-displacement-up": displacement === "up",
"is-displacement-down": displacement === "down",
"is-after-dragged-blocks": isAfterDraggedBlocks,
"is-nesting": isNesting
});
const dropdownClientIds = selectedClientIds.includes(clientId) ? selectedClientIds : [clientId];
const currentlyEditingBlockInCanvas = isSelected && selectedClientIds.length === 1;
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
import_leaf.default,
{
className: classes,
isDragged,
onKeyDown,
onMouseEnter,
onMouseLeave,
onFocus: onMouseEnter,
onBlur: onMouseLeave,
level,
position,
rowCount,
path,
id: `list-view-${listViewInstanceId}-block-${clientId}`,
"data-block": clientId,
"data-expanded": canEditBlock ? isExpanded : void 0,
ref: rowRef,
children: [
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
import_components.__experimentalTreeGridCell,
{
className: "block-editor-list-view-block__contents-cell",
colSpan,
ref: cellRef,
"aria-selected": !!isSelected,
children: ({ ref, tabIndex, onFocus }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "block-editor-list-view-block__contents-container", children: [
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
import_block_contents.default,
{
block,
onClick: selectEditorBlock,
onContextMenu,
onMouseDown,
onToggleExpanded: toggleExpanded,
isSelected,
position,
siblingBlockCount,
level,
ref,
tabIndex: currentlyEditingBlockInCanvas ? 0 : tabIndex,
onFocus,
isExpanded: canEditBlock ? isExpanded : void 0,
selectedClientIds,
ariaDescribedBy: descriptionId
}
),
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_aria_referenced_text.default, { id: descriptionId, children: [
blockPositionDescription,
blockPropertiesDescription,
blockVisibilityDescription
].filter(Boolean).join(" ") })
] })
}
),
hasRenderedMovers && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
import_components.__experimentalTreeGridCell,
{
className: moverCellClassName,
withoutGridItem: true,
children: [
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_components.__experimentalTreeGridItem, { children: ({ ref, tabIndex, onFocus }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
import_button.BlockMoverUpButton,
{
orientation: "vertical",
clientIds: [clientId],
ref,
tabIndex,
onFocus
}
) }),
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_components.__experimentalTreeGridItem, { children: ({ ref, tabIndex, onFocus }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
import_button.BlockMoverDownButton,
{
orientation: "vertical",
clientIds: [clientId],
ref,
tabIndex,
onFocus
}
) })
]
}
) }),
showBlockActions && BlockSettingsMenu && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
import_components.__experimentalTreeGridCell,
{
className: listViewBlockSettingsClassName,
"aria-selected": !!isSelected,
ref: settingsRef,
children: ({ ref, tabIndex, onFocus }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
BlockSettingsMenu,
{
clientIds: dropdownClientIds,
block,
icon: import_icons.moreVertical,
label: (0, import_i18n.__)("Options"),
popoverProps: {
anchor: settingsPopoverAnchor
// Used to position the settings at the cursor on right-click.
},
toggleProps: {
ref,
className: "block-editor-list-view-block__menu",
tabIndex,
onClick: clearSettingsAnchorRect,
onFocus,
size: "small"
},
disableOpenOnArrowDown: true,
expand,
expandedState,
setInsertedBlock,
__experimentalSelectBlock: updateFocusAndSelection
}
)
}
)
]
}
);
}
var block_default = (0, import_element.memo)(ListViewBlock);
//# sourceMappingURL=block.js.map