@wordpress/block-editor
Version:
116 lines (105 loc) • 3.16 kB
JavaScript
/**
* WordPress dependencies
*/
import { cloneBlock } from '@wordpress/blocks';
import { useDispatch, useSelect } from '@wordpress/data';
/**
* Internal dependencies
*/
import { store as blockEditorStore } from '../../store';
/**
* A function that returns an event handler function for block drop events.
*
* @param {Function} getBlockIndex A function that gets the index of a block.
* @param {Function} getClientIdsOfDescendants A function that gets the client ids of descendant blocks.
* @param {Function} moveBlocksToPosition A function that moves blocks.
* @param {Function} insertBlocks A function that inserts blocks.
* @param {Function} clearSelectedBlock A function that clears block selection.
* @return {Function} The event handler for a block drop event.
*/
export function onBlockDrop(
getBlockIndex,
getClientIdsOfDescendants,
moveBlocksToPosition,
insertBlocks,
clearSelectedBlock
) {
return ( {
blocks,
srcClientIds: sourceClientIds,
srcRootClientId: sourceRootClientId,
targetBlockIndex,
targetRootClientId,
type: dropType,
} ) => {
// If the user is inserting a block.
if ( dropType === 'inserter' ) {
clearSelectedBlock();
const blocksToInsert = blocks.map( ( block ) =>
cloneBlock( block )
);
insertBlocks(
blocksToInsert,
targetBlockIndex,
targetRootClientId,
true,
null
);
}
// If the user is moving a block.
if ( dropType === 'block' ) {
const sourceBlockIndex = getBlockIndex( sourceClientIds[ 0 ] );
// If the user is dropping to the same position, return early.
if (
sourceRootClientId === targetRootClientId &&
sourceBlockIndex === targetBlockIndex
) {
return;
}
// If the user is attempting to drop a block within its own
// nested blocks, return early as this would create infinite
// recursion.
if (
sourceClientIds.includes( targetRootClientId ) ||
getClientIdsOfDescendants( sourceClientIds ).some(
( id ) => id === targetRootClientId
)
) {
return;
}
const isAtSameLevel = sourceRootClientId === targetRootClientId;
const draggedBlockCount = sourceClientIds.length;
// If the block is kept at the same level and moved downwards,
// subtract to take into account that the blocks being dragged
// were removed from the block list above the insertion point.
const insertIndex =
isAtSameLevel && sourceBlockIndex < targetBlockIndex
? targetBlockIndex - draggedBlockCount
: targetBlockIndex;
moveBlocksToPosition(
sourceClientIds,
sourceRootClientId,
targetRootClientId,
insertIndex
);
}
};
}
/**
* A React hook for handling block drop events.
*
* @return {Function} The event handler for a block drop event.
*/
export default function useOnBlockDrop() {
const { getBlockIndex, getClientIdsOfDescendants } =
useSelect( blockEditorStore );
const { insertBlocks, moveBlocksToPosition, clearSelectedBlock } =
useDispatch( blockEditorStore );
return onBlockDrop(
getBlockIndex,
getClientIdsOfDescendants,
moveBlocksToPosition,
insertBlocks,
clearSelectedBlock
);
}