import { MutableRefObject, useEffect, useRef, useState } from 'react'; export type SilkeDragState = 'none' | 'dragging'; type DragData = MutableRefObject; let dragData: DragData; export function getDragData(): DragData { return dragData; } export function useDrag({ data, disabled, isolated, ref, }: { data: T; disabled?: boolean; isolated?: boolean; ref: MutableRefObject; }): SilkeDragState { const [state, setState] = useState('none'); const dataRef = useRef(data); dataRef.current = data; useEffect(() => { const el = ref.current; if (el && !disabled) { const dragHandle = (el.querySelector('*[data-drag-handle]') || el) as HTMLElement; dragHandle.setAttribute('draggable', 'true'); const handleDragStart = (e: DragEvent) => { e.stopPropagation(); setState('dragging'); const { dataTransfer } = e; if (dataTransfer) { dataTransfer.effectAllowed = 'move'; dataTransfer.setDragImage(el as HTMLElement, 10, el.clientHeight / 2); dragData = dataRef; dataTransfer.setData('application/json', JSON.stringify(dragData)); // Mark as isolated dnd so generic drop zones can ignore it if (isolated) dataTransfer.setData('vev/isolated-dnd', 'true'); } }; const handleDragEnd = (e: DragEvent) => { e.stopPropagation(); setState('none'); }; dragHandle.addEventListener('dragstart', handleDragStart); dragHandle.addEventListener('dragend', handleDragEnd); return () => { dragHandle.removeEventListener('dragstart', handleDragStart); dragHandle.removeEventListener('dragend', handleDragStart); dragHandle.removeAttribute('draggable'); }; } }, [ref, disabled]); return state; }