import { useMemo, useState, useRef, useCallback } from 'react'; export interface DropAreaState { isHovering: boolean; } export interface DropProps { onDragOver: React.DragEventHandler; onDragEnter: React.DragEventHandler; onDragLeave: React.DragEventHandler; onDrop: React.DragEventHandler; onPaste: React.ClipboardEventHandler; } export interface DropAreaOptions { onFiles?: (files: File[], event?: React.DragEvent) => void; onUri?: (url: string, event?: React.DragEvent) => void; onDom?: (content: any, event?: React.DragEvent) => void; onText?: (text: string, event?: React.ClipboardEvent) => void; } const getProps = ( callback: (dataTransfer: DataTransfer, event: React.DragEvent | React.ClipboardEvent) => void, setIsHovering: (over: boolean) => void ): DropProps => ({ onDragOver: (event: React.DragEvent) => { event.preventDefault(); }, onDragEnter: (event: React.DragEvent) => { event.preventDefault(); setIsHovering(true); }, onDragLeave: () => { setIsHovering(false); }, onDrop: (event: React.DragEvent) => { event.preventDefault(); event.persist(); setIsHovering(false); callback(event.dataTransfer, event); }, onPaste: (event: React.ClipboardEvent) => { event.persist(); callback(event.clipboardData, event); }, }); const useDrop = (options: DropAreaOptions = {}): [DropProps, DropAreaState] => { const optionsRef = useRef(options); optionsRef.current = options; const [isHovering, setIsHovering] = useState(false); const callback = useCallback((dataTransfer: DataTransfer, event: React.DragEvent | React.ClipboardEvent) => { const uri = dataTransfer.getData("text/uri-list"); const dom = dataTransfer.getData("custom"); if (dom && optionsRef.current.onDom) { optionsRef.current.onDom(JSON.parse(dom), event as React.DragEvent); return; } if (uri && optionsRef.current.onUri) { optionsRef.current.onUri(uri, event as React.DragEvent); return; } if (dataTransfer.files && dataTransfer.files.length && optionsRef.current.onFiles) { optionsRef.current.onFiles([...dataTransfer.files], event as React.DragEvent); return; } if (dataTransfer.items && dataTransfer.items.length && optionsRef.current.onText) { dataTransfer.items[0].getAsString((text) => { optionsRef.current.onText!(text, event as React.ClipboardEvent); }); } }, []); const props: DropProps = useMemo(() => getProps(callback, setIsHovering), [ callback, setIsHovering ]); return [props, { isHovering }]; }; export default useDrop;