"use client"; import { pickSourceDirectory, resolveSourceDirectoryFromDataTransfer, resolveSourceDirectoryFromFileList, type SourceDirectoryPick, } from "@prototype/lib/prototypes/resolve-source-directory-pick"; import { cn } from "@prototype/lib/utils"; import { FolderOpen } from "lucide-react"; import { useCallback, useId, useRef, useState } from "react"; import { toast } from "sonner"; export type PrototypeSourceDirectoryPickerProps = { value: SourceDirectoryPick | null; onChange: (value: SourceDirectoryPick | null) => void; className?: string; }; export function PrototypeSourceDirectoryPicker({ value, onChange, className, }: PrototypeSourceDirectoryPickerProps) { const inputId = useId(); const inputRef = useRef(null); const [isDragging, setIsDragging] = useState(false); const [isOpeningPicker, setIsOpeningPicker] = useState(false); const applyPick = useCallback( (pick: SourceDirectoryPick | null) => { if (!pick) return; onChange(pick); }, [onChange], ); const handleBrowse = useCallback(async () => { if (isOpeningPicker) return; setIsOpeningPicker(true); try { const pick = await pickSourceDirectory(); applyPick(pick); } catch { inputRef.current?.click(); } finally { setIsOpeningPicker(false); } }, [applyPick, isOpeningPicker]); const handleInputChange = useCallback(() => { const pick = resolveSourceDirectoryFromFileList(inputRef.current?.files ?? null); applyPick(pick); if (inputRef.current) { inputRef.current.value = ""; } }, [applyPick]); const handleDragEnter = useCallback((event: React.DragEvent) => { event.preventDefault(); event.stopPropagation(); setIsDragging(true); }, []); const handleDragLeave = useCallback((event: React.DragEvent) => { event.preventDefault(); event.stopPropagation(); if (event.currentTarget.contains(event.relatedTarget as Node | null)) return; setIsDragging(false); }, []); const handleDragOver = useCallback((event: React.DragEvent) => { event.preventDefault(); event.stopPropagation(); event.dataTransfer.dropEffect = "copy"; }, []); const handleDrop = useCallback( async (event: React.DragEvent) => { event.preventDefault(); event.stopPropagation(); setIsDragging(false); const pick = await resolveSourceDirectoryFromDataTransfer(event.dataTransfer); if (!pick) { toast.error("Drop a folder", { description: "Choose the product codebase directory, not an individual file.", }); return; } applyPick(pick); }, [applyPick], ); const hasSelection = Boolean(value?.name.trim()); const emptyHintText = "Drop your product repo folder. Proto links it and pulls the design system directly from source."; const selectedHintText = "Drop another folder or click to change the selection."; return (
); }