UNPKG

@wordpress/block-editor

Version:
270 lines (269 loc) 7.66 kB
// 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