import { useCallback, DragEventHandler, RefObject, useState, useEffect, useRef } from 'react'; import { getDataTransferFiles } from '../utils/dom'; export const useFileDropHandler = (onDrop: (file: File[]) => void): DragEventHandler => useCallback( (evt) => { const files = getDataTransferFiles(evt.dataTransfer); if (files) onDrop(files); }, [onDrop] ); export const useFileDropZone = ( zoneRef: RefObject, onDrop: (file: File[]) => void ): boolean => { const dragStateRef = useRef<'start' | 'leave' | 'over'>(); const [active, setActive] = useState(false); useEffect(() => { const target = zoneRef.current; const handleDrop = (evt: DragEvent) => { evt.preventDefault(); dragStateRef.current = undefined; setActive(false); if (!evt.dataTransfer) return; const files = getDataTransferFiles(evt.dataTransfer); if (files) onDrop(files); }; target?.addEventListener('drop', handleDrop); return () => { target?.removeEventListener('drop', handleDrop); }; }, [zoneRef, onDrop]); useEffect(() => { const target = zoneRef.current; const handleDragEnter = (evt: DragEvent) => { if (evt.dataTransfer?.types.includes('Files')) { dragStateRef.current = 'start'; setActive(true); } }; const handleDragLeave = () => { if (dragStateRef.current !== 'over') return; dragStateRef.current = 'leave'; setActive(false); }; const handleDragOver = (evt: DragEvent) => { evt.preventDefault(); dragStateRef.current = 'over'; }; target?.addEventListener('dragenter', handleDragEnter); target?.addEventListener('dragleave', handleDragLeave); target?.addEventListener('dragover', handleDragOver); return () => { target?.removeEventListener('dragenter', handleDragEnter); target?.removeEventListener('dragleave', handleDragLeave); target?.removeEventListener('dragover', handleDragOver); }; }, [zoneRef]); return active; };