import { useCallback, useEffect, useRef, useState } from "react"; interface UseFileInputOptions { onFilesSelected: (files: File[]) => void; enabled: boolean; } export function useFileInput({ onFilesSelected, enabled }: UseFileInputOptions) { const [isDragging, setIsDragging] = useState(false); const inputRef = useRef(null); const dragCountRef = useRef(0); // Stable ref for the callback to avoid re-registering effects const onFilesRef = useRef(onFilesSelected); onFilesRef.current = onFilesSelected; // Hidden file input element useEffect(() => { const input = document.createElement("input"); input.type = "file"; input.multiple = true; input.style.display = "none"; input.addEventListener("change", () => { if (input.files?.length) { onFilesRef.current(Array.from(input.files)); input.value = ""; } }); document.body.appendChild(input); inputRef.current = input; return () => { document.body.removeChild(input); inputRef.current = null; }; }, []); const openFilePicker = useCallback(() => { inputRef.current?.click(); }, []); // Clipboard paste useEffect(() => { if (!enabled) return; const handlePaste = (e: ClipboardEvent) => { const files = Array.from(e.clipboardData?.files ?? []); if (files.length > 0) { e.preventDefault(); onFilesRef.current(files); } }; window.addEventListener("paste", handlePaste); return () => window.removeEventListener("paste", handlePaste); }, [enabled]); // Drag and drop handlers const onDragOver = useCallback( (e: React.DragEvent) => { if (!enabled) return; e.preventDefault(); e.stopPropagation(); }, [enabled], ); const onDragEnter = useCallback( (e: React.DragEvent) => { if (!enabled) return; e.preventDefault(); e.stopPropagation(); dragCountRef.current++; if (dragCountRef.current === 1) setIsDragging(true); }, [enabled], ); const onDragLeave = useCallback( (e: React.DragEvent) => { if (!enabled) return; e.preventDefault(); e.stopPropagation(); dragCountRef.current--; if (dragCountRef.current === 0) setIsDragging(false); }, [enabled], ); const onDrop = useCallback( (e: React.DragEvent) => { if (!enabled) return; e.preventDefault(); e.stopPropagation(); dragCountRef.current = 0; setIsDragging(false); const files = Array.from(e.dataTransfer.files); if (files.length > 0) { onFilesRef.current(files); } }, [enabled], ); return { openFilePicker, isDragging, dropZoneProps: { onDragOver, onDragEnter, onDragLeave, onDrop }, }; }