{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "file-drop",
  "title": "File Drop",
  "description": "Upload zone that lifts and glows while a file is over it.",
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "src/components/velora/file-drop.tsx",
      "content": "\"use client\";\n\nimport { useState } from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\ninterface FileDropProps {\n  onFiles?: (files: File[]) => void;\n  /** Passed straight to the underlying input */\n  accept?: string;\n  multiple?: boolean;\n  className?: string;\n}\n\nconst formatSize = (bytes: number) => {\n  if (bytes < 1024) return `${bytes} B`;\n  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n  return `${(bytes / 1024 / 1024).toFixed(1)} MB`;\n};\n\n/**\n * Drag-and-drop upload zone that lifts and glows while a file is over it.\n * The zone is a `label` wrapping a real file input, so clicking, keyboard and\n * screen readers all work.\n */\nexport function FileDrop({\n  onFiles,\n  accept,\n  multiple = true,\n  className,\n}: FileDropProps) {\n  const [over, setOver] = useState(false);\n  const [files, setFiles] = useState<File[]>([]);\n\n  const accept_ = (list: FileList | null) => {\n    if (!list?.length) return;\n    const next = Array.from(list);\n    setFiles(next);\n    onFiles?.(next);\n  };\n\n  return (\n    <div className={cn(\"w-full\", className)} data-slot=\"file-drop\">\n      <label\n        onDragOver={(event) => {\n          event.preventDefault();\n          setOver(true);\n        }}\n        onDragLeave={() => setOver(false)}\n        onDrop={(event) => {\n          event.preventDefault();\n          setOver(false);\n          accept_(event.dataTransfer.files);\n        }}\n        className={cn(\n          \"flex cursor-pointer flex-col items-center justify-center gap-2 rounded-2xl border-2 border-dashed p-10 text-center transition-all duration-200 motion-reduce:transition-none has-[input:focus-visible]:ring-2 has-[input:focus-visible]:ring-ring\",\n          over\n            ? \"-translate-y-0.5 border-brand bg-brand/5 shadow-lg shadow-brand/10\"\n            : \"border-border hover:border-muted-foreground/50 hover:bg-muted/40\"\n        )}\n      >\n        <svg\n          width=\"28\"\n          height=\"28\"\n          viewBox=\"0 0 24 24\"\n          fill=\"none\"\n          stroke=\"currentColor\"\n          strokeWidth=\"1.5\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n          aria-hidden\n          className={cn(\n            \"transition-colors\",\n            over ? \"text-brand\" : \"text-muted-foreground\"\n          )}\n        >\n          <path d=\"M12 15V3M8 7l4-4 4 4\" />\n          <path d=\"M3 15v4a2 2 0 002 2h14a2 2 0 002-2v-4\" />\n        </svg>\n        {/* Spans, not paragraphs: a label only allows phrasing content. */}\n        <span className=\"block text-sm font-medium\">\n          {over ? \"Drop to upload\" : \"Drag files here, or click to browse\"}\n        </span>\n        <span className=\"block text-xs text-muted-foreground\">\n          {accept ? accept.replace(/,/g, \", \") : \"Any file type\"}\n        </span>\n\n        <input\n          type=\"file\"\n          accept={accept}\n          multiple={multiple}\n          onChange={(event) => accept_(event.target.files)}\n          className=\"sr-only\"\n        />\n      </label>\n\n      {files.length > 0 && (\n        <ul className=\"mt-3 flex flex-col gap-1.5\">\n          {files.map((file) => (\n            <li\n              key={`${file.name}-${file.size}`}\n              className=\"flex items-center justify-between gap-3 rounded-lg border bg-card px-3 py-2 text-sm\"\n            >\n              <span className=\"truncate\">{file.name}</span>\n              <span className=\"shrink-0 text-xs tabular-nums text-muted-foreground\">\n                {formatSize(file.size)}\n              </span>\n            </li>\n          ))}\n        </ul>\n      )}\n    </div>\n  );\n}\n",
      "type": "registry:ui",
      "target": "components/velora/file-drop.tsx"
    }
  ],
  "cssVars": {
    "theme": {
      "color-brand": "var(--brand)",
      "color-brand-from": "var(--brand-from)",
      "color-brand-via": "var(--brand-via)",
      "color-brand-to": "var(--brand-to)"
    },
    "light": {
      "brand": "oklch(0.546 0.245 263)",
      "brand-from": "oklch(0.546 0.245 263)",
      "brand-via": "oklch(0.623 0.214 260)",
      "brand-to": "oklch(0.685 0.169 237)"
    },
    "dark": {
      "brand": "oklch(0.623 0.214 260)",
      "brand-from": "oklch(0.623 0.214 260)",
      "brand-via": "oklch(0.707 0.165 255)",
      "brand-to": "oklch(0.746 0.16 233)"
    }
  },
  "type": "registry:ui"
}