import { useRef, useState } from "react"; const ACCEPTED = ["image/jpeg", "image/png", "image/webp"]; const MAX_BYTES = 10 * 1024 * 1024; export default function UploadZone({ onFileSelected, disabled = false }) { const inputRef = useRef(null); const [dragActive, setDragActive] = useState(false); const validate = (file) => { if (!file) return "No file selected."; if (!ACCEPTED.includes(file.type)) { return "Unsupported format. Use JPG, PNG, or WEBP."; } if (file.size > MAX_BYTES) { return "File exceeds 10 MB limit."; } return null; }; const handleFile = (file) => { const error = validate(file); onFileSelected(file ?? null, error); }; const onDrop = (e) => { e.preventDefault(); setDragActive(false); if (disabled) return; const file = e.dataTransfer?.files?.[0]; if (file) handleFile(file); }; const onDragOver = (e) => { e.preventDefault(); if (!disabled) setDragActive(true); }; const onDragLeave = (e) => { e.preventDefault(); setDragActive(false); }; const onChange = (e) => { const file = e.target.files?.[0]; if (file) handleFile(file); e.target.value = ""; }; return (
!disabled && inputRef.current?.click()} role="button" tabIndex={0} onKeyDown={(e) => { if ((e.key === "Enter" || e.key === " ") && !disabled) { e.preventDefault(); inputRef.current?.click(); } }} className={[ "relative w-full rounded-2xl border border-dashed transition-all duration-200 select-none", "flex flex-col items-center justify-center text-center px-6 py-16", disabled ? "cursor-not-allowed opacity-60" : "cursor-pointer", dragActive ? "border-violet-400/80 bg-violet-500/10 shadow-[0_0_0_4px_rgba(139,92,246,0.12)]" : "border-white/15 bg-white/[0.02] hover:border-white/25 hover:bg-white/[0.04]", ].join(" ")} >

{dragActive ? "Drop to upload" : "Drag & drop an image"}

or click to browse — JPG, PNG, WEBP · max 10 MB

); }