"use strict";
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
