import React, { useState, useRef, useCallback } from 'react'; export interface DropAreaState { isHovering: boolean; fileList: File[] | []; text: string; uri: string; domContent: any; } export interface DropAreaOptions { onFile?: (file: File[], e: React.DragEvent) => void; onUri?: (uri: string, e: React.DragEvent) => void; onText?: (text: string, e: React.ClipboardEvent) => void; onDom?: (content: any, e: React.DragEvent) => void; } export interface DropProps { onDragEnter: (e: React.DragEvent) => void; onDragOver: (e: React.DragEvent) => void; onDragLeave: (e: React.DragEvent) => void; onPaste: (e: React.ClipboardEvent) => void; onDrop: (e: React.DragEvent) => void; } const getProps = ( callback: ( dataTransfer: DataTransfer, event: React.DragEvent | React.ClipboardEvent, ) => void, setIsHover: (over: boolean) => void, ): DropProps => ({ onDragEnter: (e: React.DragEvent) => { e.preventDefault(); setIsHover(true); }, onDragOver: (e: React.DragEvent) => { e.preventDefault(); setIsHover(true); }, onDragLeave: e => { setIsHover(false); }, onDrop: e => { e.preventDefault(); e.persist(); setIsHover(false); callback(e.dataTransfer, e); }, onPaste: e => { setIsHover(false); callback(e.clipboardData, e); }, }); const useDrop = (options: DropAreaOptions = {}): [DropProps, DropAreaState] => { const [isHovering, setIsHovering] = useState(false); const [fileList, setFileList] = useState([]); const [text, setText] = useState(''); const [domContent, setDomContent] = useState(''); const [uri, setUri] = useState(''); const optionRef = useRef(options); optionRef.current = options; const callback = useCallback( ( dataTransfer: DataTransfer, event: React.DragEvent | React.ClipboardEvent, ) => { const dom = dataTransfer.getData('custom'); const uri = dataTransfer.getData('text/uri-list'); if (dom && optionRef.current.onDom) { let data = dom; try { data = JSON.parse(data); } catch (e) { data = dom; } optionRef.current.onDom(dom, event as React.DragEvent); setDomContent(data); return; } if (uri && optionRef.current.onUri) { optionRef.current.onUri(uri, event as React.DragEvent); setUri(uri); return; } if ( dataTransfer.files && dataTransfer.files.length && optionRef.current.onFile ) { const list = Array.from(dataTransfer.files); optionRef.current.onFile(list, event as React.DragEvent); setFileList(list); return; } if ( dataTransfer.items && dataTransfer.items.length && optionRef.current.onText ) { dataTransfer.items[0].getAsString(text => { optionRef.current.onText!(text, event as React.ClipboardEvent); setText(text); }); } }, [], ); const props = getProps(callback, setIsHovering); return [props, { isHovering, fileList, text, uri, domContent }]; }; export default useDrop;