// packages/block-editor/src/components/use-on-block-drop/index.js
import { useCallback } from "@wordpress/element";
import {
  cloneBlock,
  createBlock,
  findTransform,
  getBlockTransforms,
  pasteHandler,
  store as blocksStore
} from "@wordpress/blocks";
import { useDispatch, useSelect, useRegistry } from "@wordpress/data";
import { getFilesFromDataTransfer } from "@wordpress/dom";
import { store as blockEditorStore } from "../../store";
function parseDropEvent(event) {
  let result = {
    srcRootClientId: null,
    srcClientIds: null,
    srcIndex: null,
    type: null,
    blocks: null
  };
  if (!event.dataTransfer) {
    return result;
  }
  try {
    result = Object.assign(
      result,
      JSON.parse(event.dataTransfer.getData("wp-blocks"))
    );
  } catch (err) {
    return result;
  }
  return result;
}
function onBlockDrop(targetRootClientId, targetBlockIndex, getBlockIndex, getClientIdsOfDescendants, moveBlocks, insertOrReplaceBlocks, clearSelectedBlock, operation, getBlock) {
  return (event) => {
    const {
      srcRootClientId: sourceRootClientId,
      srcClientIds: sourceClientIds,
      type: dropType,
      blocks
    } = parseDropEvent(event);
    if (dropType === "inserter") {
      clearSelectedBlock();
      const blocksToInsert = blocks.map(
        (block) => cloneBlock(block)
      );
      insertOrReplaceBlocks(blocksToInsert, true, null);
    }
    if (dropType === "block") {
      const sourceBlockIndex = getBlockIndex(sourceClientIds[0]);
      if (sourceRootClientId === targetRootClientId && sourceBlockIndex === targetBlockIndex) {
        return;
      }
      if (sourceClientIds.includes(targetRootClientId) || getClientIdsOfDescendants(sourceClientIds).some(
        (id) => id === targetRootClientId
      )) {
        return;
      }
      if (operation === "group") {
        const blocksToInsert = sourceClientIds.map(
          (clientId) => getBlock(clientId)
        );
        insertOrReplaceBlocks(
          blocksToInsert,
          true,
          null,
          sourceClientIds
        );
        return;
      }
      const isAtSameLevel = sourceRootClientId === targetRootClientId;
      const draggedBlockCount = sourceClientIds.length;
      const insertIndex = isAtSameLevel && sourceBlockIndex < targetBlockIndex ? targetBlockIndex - draggedBlockCount : targetBlockIndex;
      moveBlocks(sourceClientIds, sourceRootClientId, insertIndex);
    }
  };
}
function onFilesDrop(targetRootClientId, getSettings, updateBlockAttributes, canInsertBlockType, insertOrReplaceBlocks) {
  return (files) => {
    if (!getSettings().mediaUpload) {
      return;
    }
    const transformation = findTransform(
      getBlockTransforms("from"),
      (transform) => transform.type === "files" && canInsertBlockType(transform.blockName, targetRootClientId) && transform.isMatch(files)
    );
    if (transformation) {
      const blocks = transformation.transform(
        files,
        updateBlockAttributes
      );
      insertOrReplaceBlocks(blocks);
    }
  };
}
function onHTMLDrop(insertOrReplaceBlocks) {
  return (HTML) => {
    const blocks = pasteHandler({ HTML, mode: "BLOCKS" });
    if (blocks.length) {
      insertOrReplaceBlocks(blocks);
    }
  };
}
function useOnBlockDrop(targetRootClientId, targetBlockIndex, options = {}) {
  const { operation = "insert", nearestSide = "right" } = options;
  const {
    canInsertBlockType,
    getBlockIndex,
    getClientIdsOfDescendants,
    getBlockOrder,
    getBlocksByClientId,
    getSettings,
    getBlock
  } = useSelect(blockEditorStore);
  const { getGroupingBlockName } = useSelect(blocksStore);
  const {
    insertBlocks,
    moveBlocksToPosition,
    updateBlockAttributes,
    clearSelectedBlock,
    replaceBlocks,
    removeBlocks
  } = useDispatch(blockEditorStore);
  const registry = useRegistry();
  const insertOrReplaceBlocks = useCallback(
    (blocks, updateSelection = true, initialPosition = 0, clientIdsToReplace = []) => {
      if (!Array.isArray(blocks)) {
        blocks = [blocks];
      }
      const clientIds = getBlockOrder(targetRootClientId);
      const clientId = clientIds[targetBlockIndex];
      if (operation === "replace") {
        replaceBlocks(clientId, blocks, void 0, initialPosition);
      } else if (operation === "group") {
        const targetBlock = getBlock(clientId);
        if (nearestSide === "left") {
          blocks.push(targetBlock);
        } else {
          blocks.unshift(targetBlock);
        }
        const groupInnerBlocks = blocks.map((block) => {
          return createBlock(
            block.name,
            block.attributes,
            block.innerBlocks
          );
        });
        const areAllImages = blocks.every((block) => {
          return block.name === "core/image";
        });
        const galleryBlock = canInsertBlockType(
          "core/gallery",
          targetRootClientId
        );
        const wrappedBlocks = createBlock(
          areAllImages && galleryBlock ? "core/gallery" : getGroupingBlockName(),
          {
            layout: {
              type: "flex",
              flexWrap: areAllImages && galleryBlock ? null : "nowrap"
            }
          },
          groupInnerBlocks
        );
        replaceBlocks(
          [clientId, ...clientIdsToReplace],
          wrappedBlocks,
          void 0,
          initialPosition
        );
      } else {
        insertBlocks(
          blocks,
          targetBlockIndex,
          targetRootClientId,
          updateSelection,
          initialPosition
        );
      }
    },
    [
      getBlockOrder,
      targetRootClientId,
      targetBlockIndex,
      operation,
      replaceBlocks,
      getBlock,
      nearestSide,
      canInsertBlockType,
      getGroupingBlockName,
      insertBlocks
    ]
  );
  const moveBlocks = useCallback(
    (sourceClientIds, sourceRootClientId, insertIndex) => {
      if (operation === "replace") {
        const sourceBlocks = getBlocksByClientId(sourceClientIds);
        const targetBlockClientIds = getBlockOrder(targetRootClientId);
        const targetBlockClientId = targetBlockClientIds[targetBlockIndex];
        registry.batch(() => {
          removeBlocks(sourceClientIds, false);
          replaceBlocks(
            targetBlockClientId,
            sourceBlocks,
            void 0,
            0
          );
        });
      } else {
        moveBlocksToPosition(
          sourceClientIds,
          sourceRootClientId,
          targetRootClientId,
          insertIndex
        );
      }
    },
    [
      operation,
      getBlockOrder,
      getBlocksByClientId,
      moveBlocksToPosition,
      registry,
      removeBlocks,
      replaceBlocks,
      targetBlockIndex,
      targetRootClientId
    ]
  );
  const _onDrop = onBlockDrop(
    targetRootClientId,
    targetBlockIndex,
    getBlockIndex,
    getClientIdsOfDescendants,
    moveBlocks,
    insertOrReplaceBlocks,
    clearSelectedBlock,
    operation,
    getBlock
  );
  const _onFilesDrop = onFilesDrop(
    targetRootClientId,
    getSettings,
    updateBlockAttributes,
    canInsertBlockType,
    insertOrReplaceBlocks
  );
  const _onHTMLDrop = onHTMLDrop(insertOrReplaceBlocks);
  return (event) => {
    const files = getFilesFromDataTransfer(event.dataTransfer);
    const html = event.dataTransfer.getData("text/html");
    if (html) {
      _onHTMLDrop(html);
    } else if (files.length) {
      _onFilesDrop(files);
    } else {
      _onDrop(event);
    }
  };
}
export {
  useOnBlockDrop as default,
  onBlockDrop,
  onFilesDrop,
  onHTMLDrop,
  parseDropEvent
};
//# sourceMappingURL=index.js.map
