import { PaperclipIcon } from "lucide-react"; import { useCallback, useEffect, useRef, useState, type DragEvent, type ReactNode } from "react"; import { cn } from "../../lib/utils"; function carriesFiles(event: { dataTransfer: DataTransfer | null }): boolean { return event.dataTransfer !== null && [...event.dataTransfer.types].includes("Files"); } export function ChatViewportFileDropTarget({ children, enabled, onFiles, className, "data-workspace-scroll-owner": scrollOwner, }: { children: ReactNode; enabled: boolean; onFiles: (files: FileList) => void; className?: string | undefined; "data-workspace-scroll-owner": "self-managed"; }) { const [dragging, setDragging] = useState(false); const dragDepth = useRef(0); const reset = useCallback(() => { dragDepth.current = 0; setDragging(false); }, []); useEffect(() => { if (!enabled) reset(); }, [enabled, reset]); useEffect(() => { if (!dragging) return; globalThis.addEventListener("dragend", reset); globalThis.addEventListener("drop", reset); globalThis.addEventListener("blur", reset); return () => { globalThis.removeEventListener("dragend", reset); globalThis.removeEventListener("drop", reset); globalThis.removeEventListener("blur", reset); }; }, [dragging, reset]); const onDragEnter = useCallback( (event: DragEvent) => { if (!enabled || !carriesFiles(event)) return; event.preventDefault(); dragDepth.current += 1; setDragging(true); }, [enabled], ); const onDragOver = useCallback( (event: DragEvent) => { if (!enabled || !carriesFiles(event)) return; event.preventDefault(); if (event.dataTransfer) event.dataTransfer.dropEffect = "copy"; setDragging(true); }, [enabled], ); const onDragLeave = useCallback( (event: DragEvent) => { if (!enabled || dragDepth.current === 0) return; event.preventDefault(); dragDepth.current = Math.max(0, dragDepth.current - 1); if (dragDepth.current === 0) setDragging(false); }, [enabled], ); const onDrop = useCallback( (event: DragEvent) => { const handledByChild = event.defaultPrevented; const dataTransfer = event.dataTransfer; const files = dataTransfer && carriesFiles(event) ? dataTransfer.files : null; reset(); if (!enabled || !files) return; event.preventDefault(); if (!handledByChild && files.length > 0) onFiles(files); }, [enabled, onFiles, reset], ); return (
{children} {dragging ? ( ) : null}
); }