@wordpress/block-editor
Version:
395 lines (393 loc) • 14.4 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/use-block-drop-zone/index.js
var use_block_drop_zone_exports = {};
__export(use_block_drop_zone_exports, {
default: () => useBlockDropZone,
getDropTargetPosition: () => getDropTargetPosition,
isDropTargetValid: () => isDropTargetValid
});
module.exports = __toCommonJS(use_block_drop_zone_exports);
var import_data = require("@wordpress/data");
var import_element = require("@wordpress/element");
var import_compose = require("@wordpress/compose");
var import_i18n = require("@wordpress/i18n");
var import_blocks = require("@wordpress/blocks");
var import_use_on_block_drop = __toESM(require("../use-on-block-drop"));
var import_math = require("../../utils/math");
var import_store = require("../../store");
var import_lock_unlock = require("../../lock-unlock");
var THRESHOLD_DISTANCE = 30;
var MINIMUM_HEIGHT_FOR_THRESHOLD = 120;
var MINIMUM_WIDTH_FOR_THRESHOLD = 120;
function getDropTargetPosition(blocksData, position, orientation = "vertical", options = {}) {
const allowedEdges = orientation === "horizontal" ? ["left", "right"] : ["top", "bottom"];
let nearestIndex = 0;
let insertPosition = "before";
let minDistance = Infinity;
let targetBlockIndex = null;
let nearestSide = "right";
const {
dropZoneElement,
parentBlockOrientation,
rootBlockIndex = 0
} = options;
if (dropZoneElement && parentBlockOrientation !== "horizontal") {
const rect = dropZoneElement.getBoundingClientRect();
const [distance, edge] = (0, import_math.getDistanceToNearestEdge)(position, rect, [
"top",
"bottom"
]);
if (rect.height > MINIMUM_HEIGHT_FOR_THRESHOLD && distance < THRESHOLD_DISTANCE) {
if (edge === "top") {
return [rootBlockIndex, "before"];
}
if (edge === "bottom") {
return [rootBlockIndex + 1, "after"];
}
}
}
const isRightToLeft = (0, import_i18n.isRTL)();
if (dropZoneElement && parentBlockOrientation === "horizontal") {
const rect = dropZoneElement.getBoundingClientRect();
const [distance, edge] = (0, import_math.getDistanceToNearestEdge)(position, rect, [
"left",
"right"
]);
if (rect.width > MINIMUM_WIDTH_FOR_THRESHOLD && distance < THRESHOLD_DISTANCE) {
if (isRightToLeft && edge === "right" || !isRightToLeft && edge === "left") {
return [rootBlockIndex, "before"];
}
if (isRightToLeft && edge === "left" || !isRightToLeft && edge === "right") {
return [rootBlockIndex + 1, "after"];
}
}
}
blocksData.forEach(
({
isUnmodifiedDefaultBlock,
getBoundingClientRect,
blockIndex,
blockOrientation
}) => {
const rect = getBoundingClientRect();
if (!rect) {
return;
}
let [distance, edge] = (0, import_math.getDistanceToNearestEdge)(
position,
rect,
allowedEdges
);
const [sideDistance, sideEdge] = (0, import_math.getDistanceToNearestEdge)(
position,
rect,
["left", "right"]
);
const isPointInsideRect = (0, import_math.isPointContainedByRect)(position, rect);
if (isUnmodifiedDefaultBlock && isPointInsideRect) {
distance = 0;
} else if (orientation === "vertical" && blockOrientation !== "horizontal" && (isPointInsideRect && sideDistance < THRESHOLD_DISTANCE || !isPointInsideRect && (0, import_math.isPointWithinTopAndBottomBoundariesOfRect)(
position,
rect
))) {
targetBlockIndex = blockIndex;
nearestSide = sideEdge;
}
if (distance < minDistance) {
insertPosition = edge === "bottom" || !isRightToLeft && edge === "right" || isRightToLeft && edge === "left" ? "after" : "before";
minDistance = distance;
nearestIndex = blockIndex;
}
}
);
const adjacentIndex = nearestIndex + (insertPosition === "after" ? 1 : -1);
const isNearestBlockUnmodifiedDefaultBlock = !!blocksData[nearestIndex]?.isUnmodifiedDefaultBlock;
const isAdjacentBlockUnmodifiedDefaultBlock = !!blocksData[adjacentIndex]?.isUnmodifiedDefaultBlock;
if (targetBlockIndex !== null) {
return [targetBlockIndex, "group", nearestSide];
}
if (!isNearestBlockUnmodifiedDefaultBlock && !isAdjacentBlockUnmodifiedDefaultBlock) {
const insertionIndex = insertPosition === "after" ? nearestIndex + 1 : nearestIndex;
return [insertionIndex, "insert"];
}
return [
isNearestBlockUnmodifiedDefaultBlock ? nearestIndex : adjacentIndex,
"replace"
];
}
function isDropTargetValid(getBlockType, allowedBlocks, draggedBlockNames, targetBlockName) {
let areBlocksAllowed = true;
if (allowedBlocks) {
const allowedBlockNames = allowedBlocks?.map(({ name }) => name);
areBlocksAllowed = draggedBlockNames.every(
(name) => allowedBlockNames?.includes(name)
);
}
const draggedBlockTypes = draggedBlockNames.map(
(name) => getBlockType(name)
);
const targetMatchesDraggedBlockParents = draggedBlockTypes.every(
(block) => {
const [allowedParentName] = block?.parent || [];
if (!allowedParentName) {
return true;
}
return allowedParentName === targetBlockName;
}
);
return areBlocksAllowed && targetMatchesDraggedBlockParents;
}
function isInsertionPoint(targetToCheck, ownerDocument) {
const { defaultView } = ownerDocument;
return !!(defaultView && targetToCheck instanceof defaultView.HTMLElement && targetToCheck.closest("[data-is-insertion-point]"));
}
function useBlockDropZone({
dropZoneElement,
// An undefined value represents a top-level block. Default to an empty
// string for this so that `targetRootClientId` can be easily compared to
// values returned by the `getRootBlockClientId` selector, which also uses
// an empty string to represent top-level blocks.
rootClientId: targetRootClientId = "",
parentClientId: parentBlockClientId = "",
isDisabled = false
} = {}) {
const registry = (0, import_data.useRegistry)();
const [dropTarget, setDropTarget] = (0, import_element.useState)({
index: null,
operation: "insert"
});
const { getBlockType, getBlockVariations, getGroupingBlockName } = (0, import_data.useSelect)(import_blocks.store);
const {
canInsertBlockType,
getBlockListSettings,
getBlocks,
getBlockIndex,
getDraggedBlockClientIds,
getBlockNamesByClientId,
getAllowedBlocks,
isDragging,
isGroupable,
isZoomOut,
getSectionRootClientId,
getBlockParents
} = (0, import_lock_unlock.unlock)((0, import_data.useSelect)(import_store.store));
const {
showInsertionPoint,
hideInsertionPoint,
startDragging,
stopDragging
} = (0, import_lock_unlock.unlock)((0, import_data.useDispatch)(import_store.store));
const onBlockDrop = (0, import_use_on_block_drop.default)(
dropTarget.operation === "before" || dropTarget.operation === "after" ? parentBlockClientId : targetRootClientId,
dropTarget.index,
{
operation: dropTarget.operation,
nearestSide: dropTarget.nearestSide
}
);
const throttled = (0, import_compose.useThrottle)(
(0, import_element.useCallback)(
(event, ownerDocument) => {
if (!isDragging()) {
startDragging();
}
const draggedBlockClientIds = getDraggedBlockClientIds();
const targetParents = [
targetRootClientId,
...getBlockParents(targetRootClientId, true)
];
const isTargetWithinDraggedBlocks = draggedBlockClientIds.some(
(clientId) => targetParents.includes(clientId)
);
if (isTargetWithinDraggedBlocks) {
return;
}
const allowedBlocks = getAllowedBlocks(targetRootClientId);
const targetBlockName = getBlockNamesByClientId([
targetRootClientId
])[0];
const draggedBlockNames = getBlockNamesByClientId(
draggedBlockClientIds
);
const isBlockDroppingAllowed = isDropTargetValid(
getBlockType,
allowedBlocks,
draggedBlockNames,
targetBlockName
);
if (!isBlockDroppingAllowed) {
return;
}
const sectionRootClientId = getSectionRootClientId();
if (isZoomOut() && sectionRootClientId !== targetRootClientId) {
return;
}
const blocks = getBlocks(targetRootClientId).filter((block) => {
return !((0, import_blocks.hasBlockSupport)(block.name, "visibility", true) && block.attributes?.metadata?.blockVisibility === false);
});
if (blocks.length === 0) {
registry.batch(() => {
setDropTarget({
index: 0,
operation: "insert"
});
showInsertionPoint(targetRootClientId, 0, {
operation: "insert"
});
});
return;
}
const blocksData = blocks.map((block) => {
const clientId = block.clientId;
return {
isUnmodifiedDefaultBlock: (0, import_blocks.isUnmodifiedDefaultBlock)(block),
getBoundingClientRect: () => {
const blockElement = ownerDocument.getElementById(
`block-${clientId}`
);
return blockElement ? blockElement.getBoundingClientRect() : null;
},
blockIndex: getBlockIndex(clientId),
blockOrientation: getBlockListSettings(clientId)?.orientation
};
});
const dropTargetPosition = getDropTargetPosition(
blocksData,
{ x: event.clientX, y: event.clientY },
getBlockListSettings(targetRootClientId)?.orientation,
{
dropZoneElement,
parentBlockClientId,
parentBlockOrientation: parentBlockClientId ? getBlockListSettings(parentBlockClientId)?.orientation : void 0,
rootBlockIndex: getBlockIndex(targetRootClientId)
}
);
const [targetIndex, operation, nearestSide] = dropTargetPosition;
const isTargetIndexEmptyDefaultBlock = blocksData[targetIndex]?.isUnmodifiedDefaultBlock;
if (isZoomOut() && !isTargetIndexEmptyDefaultBlock && operation !== "insert") {
return;
}
if (operation === "group") {
const targetBlock = blocks[targetIndex];
const areAllImages = [
targetBlock.name,
...draggedBlockNames
].every((name) => name === "core/image");
const canInsertGalleryBlock = canInsertBlockType(
"core/gallery",
targetRootClientId
);
const areGroupableBlocks = isGroupable([
targetBlock.clientId,
getDraggedBlockClientIds()
]);
const groupBlockVariations = getBlockVariations(
getGroupingBlockName(),
"block"
);
const canInsertRow = groupBlockVariations && groupBlockVariations.find(
({ name }) => name === "group-row"
);
if (areAllImages && !canInsertGalleryBlock && (!areGroupableBlocks || !canInsertRow)) {
return;
}
if (!areAllImages && (!areGroupableBlocks || !canInsertRow)) {
return;
}
}
registry.batch(() => {
setDropTarget({
index: targetIndex,
operation,
nearestSide
});
const insertionPointClientId = [
"before",
"after"
].includes(operation) ? parentBlockClientId : targetRootClientId;
showInsertionPoint(insertionPointClientId, targetIndex, {
operation,
nearestSide
});
});
},
[
isDragging,
getAllowedBlocks,
targetRootClientId,
getBlockNamesByClientId,
getDraggedBlockClientIds,
getBlockType,
getSectionRootClientId,
isZoomOut,
getBlocks,
getBlockListSettings,
dropZoneElement,
parentBlockClientId,
getBlockIndex,
registry,
startDragging,
showInsertionPoint,
canInsertBlockType,
isGroupable,
getBlockVariations,
getGroupingBlockName
]
),
200
);
return (0, import_compose.__experimentalUseDropZone)({
dropZoneElement,
isDisabled,
onDrop: onBlockDrop,
onDragOver(event) {
throttled(event, event.currentTarget.ownerDocument);
},
onDragLeave(event) {
const { ownerDocument } = event.currentTarget;
if (isInsertionPoint(event.relatedTarget, ownerDocument) || isInsertionPoint(event.target, ownerDocument)) {
return;
}
throttled.cancel();
hideInsertionPoint();
},
onDragEnd() {
throttled.cancel();
stopDragging();
hideInsertionPoint();
}
});
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
getDropTargetPosition,
isDropTargetValid
});
//# sourceMappingURL=index.js.map