1 import type { DragEvent } from 'react';
3 import useDragOver from '@proton/components/hooks/useDragOver';
5 import { DRAG_ITEM_ID_KEY, DRAG_ITEM_KEY } from './constants';
8 * Implement the logic of receiving the drop of items from the item list
9 * Prepare all drag handlers for receiving zones and parse events to get items ids
10 * @param dragFilter Filter to accept or not drop on this zone
11 * @param dropEffect Drop effect type to use
12 * @param dropCallback Drop callback to run when a drop event occurs with parsed items ids
13 * @returns All drag handler to use
15 const useItemsDroppable = (
16 dragFilter: (event: DragEvent) => boolean,
17 dropEffect: 'none' | 'copy' | 'link' | 'move' = 'move',
18 dropCallback: (itemIDs: string[]) => void | Promise<void>
20 const [dragOver, dragProps] = useDragOver(
21 (event: DragEvent) => event.dataTransfer.types.includes(DRAG_ITEM_KEY) && dragFilter(event),
25 const handleDrop = async (event: DragEvent) => {
26 dragProps.onDrop(event);
28 const data = event.dataTransfer.getData(DRAG_ITEM_KEY);
30 // If no data dont handle drop
32 // Manual trigger of the dragend event on the drag element because native event is not reliable
33 const dragElement = document.getElementById(event.dataTransfer.getData(DRAG_ITEM_ID_KEY));
34 const dragendEvent = new Event('dragend') as any;
35 dragendEvent.dataTransfer = event.dataTransfer;
36 dragendEvent.dataTransfer.dropEffect = dropEffect; // Chrome is losing the original dropEffect
37 dragElement?.dispatchEvent(dragendEvent);
38 const itemIDs = JSON.parse(data) as string[];
39 void dropCallback(itemIDs);
43 return { dragOver, dragProps, handleDrop };
46 export default useItemsDroppable;