{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "visible-file",
  "title": "Visible file",
  "description": "A Kardex visible-index tray: each record shows only its edge, and coloured signal clips slide along it to mark where it stands, so a whole tray reads at a glance. For pipelines, renewals and task stages.",
  "dependencies": [
    "cn"
  ],
  "registryDependencies": [
    "https://bevel-ui.vercel.app/r/bevel.json"
  ],
  "files": [
    {
      "path": "registry/bevel/ui/visible-file.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { cn } from \"cn\"\n\ntype VisibleFileContextValue = { scale: string[] }\n\nconst VisibleFileContext = React.createContext<VisibleFileContextValue | null>(null)\n\nfunction useVisibleFile() {\n  const context = React.useContext(VisibleFileContext)\n  if (!context) throw new Error(\"VisibleFile parts must be inside <VisibleFile>\")\n  return context\n}\n\ntype VisibleFileProps = React.ComponentProps<\"div\"> & {\n  /** The positions a signal can sit at, printed across the top: months, stages, grades. */\n  scale: string[]\n}\n\n/**\n * A visible-index file. Each record shows only its edge, and coloured\n * signals slide along it to mark where it stands, so a whole tray reads\n * at a glance. Give it an aria-label.\n */\nfunction VisibleFile({ className, scale, children, ...props }: VisibleFileProps) {\n  return (\n    <VisibleFileContext value={{ scale }}>\n      <div\n        role=\"group\"\n        data-slot=\"visible-file\"\n        className={cn(\n          \"bevel-metal bevel-object grid w-full grid-cols-[minmax(5rem,10rem)_minmax(0,1fr)] rounded-(--bevel-radius-md) p-3 pt-2\",\n          className\n        )}\n        {...props}\n      >\n        <span aria-hidden />\n        <span aria-hidden className=\"flex min-w-0 pb-1.5 text-(--bevel-ivory)\">\n          {scale.map((s) => (\n            <span key={s} className=\"min-w-0 flex-1 truncate text-center text-(length:--bevel-fine) font-bold tracking-(--bevel-tracking-label) uppercase\">\n              {s}\n            </span>\n          ))}\n        </span>\n        <ul className=\"col-span-2 grid grid-cols-subgrid\">{children}</ul>\n      </div>\n    </VisibleFileContext>\n  )\n}\n\ntype VisibleFileRowProps = React.ComponentProps<\"li\"> & {\n  /** The record's name, typed on the card edge. */\n  title: string\n  /** A second line, like an amount or an owner. */\n  detail?: string\n}\n\n/** One record's card edge, in its clear pocket. */\nfunction VisibleFileRow({ className, title, detail, children, ...props }: VisibleFileRowProps) {\n  return (\n    <li\n      data-slot=\"visible-file-row\"\n      className={cn(\n        // Shingled: each card edge overlaps the one above, casting a little shadow up onto it.\n        \"relative col-span-2 -mt-px grid grid-cols-subgrid bg-(--visible-file-card) text-(--visible-file-card-foreground) shadow-(--bevel-depth-sheet) first:rounded-t-(--bevel-radius-xs) last:rounded-b-(--bevel-radius-xs)\",\n        className\n      )}\n      {...props}\n    >\n      <span className=\"flex min-w-0 flex-col justify-center border-r border-(--visible-file-rule) px-2 py-1.5\">\n        <span className=\"truncate text-sm font-semibold\">{title}</span>\n        {detail && <span className=\"truncate text-xs opacity-70\">{detail}</span>}\n      </span>\n      <span className=\"relative min-h-10 overflow-hidden\">{children}</span>\n      <span aria-hidden className=\"bevel-glass pointer-events-none absolute inset-0\" />\n    </li>\n  )\n}\n\ntype VisibleFileSignalProps = Omit<React.ComponentProps<\"span\">, \"children\"> & {\n  /** Where it sits: an index into the file's scale. */\n  value: number\n  /** What it marks, for screen readers: “Renewal”, “Stage”. */\n  label: string\n  tone?: \"red\" | \"amber\" | \"green\" | \"blue\"\n}\n\n/** A signal clip on the card edge. Slides when its value changes. */\nfunction VisibleFileSignal({ className, value, label, tone = \"blue\", ...props }: VisibleFileSignalProps) {\n  const { scale } = useVisibleFile()\n  const at = Math.min(Math.max(Math.round(value), 0), scale.length - 1)\n  return (\n    <span\n      data-slot=\"visible-file-signal\"\n      data-tone={tone}\n      className={cn(\n        \"absolute inset-y-0 left-0 flex w-full items-center\",\n        \"transition-[translate] duration-(--bevel-duration-move) ease-(--bevel-ease-spring) motion-reduce:transition-none\",\n        className\n      )}\n      // A full-width rail, moved along by whole cells; the clip sits in the first cell.\n      style={{ translate: `${(at / scale.length) * 100}% 0` }}\n      {...props}\n    >\n      <span className=\"flex justify-center\" style={{ width: `${100 / scale.length}%` }}>\n        <span aria-hidden className=\"bevel-plastic h-5 w-3 rounded-(--bevel-radius-xs)\" />\n      </span>\n      <span className=\"sr-only\">\n        {label}: {scale[at]}.\n      </span>\n    </span>\n  )\n}\n\nexport { VisibleFile, VisibleFileRow, VisibleFileSignal }\nexport type { VisibleFileProps, VisibleFileRowProps, VisibleFileSignalProps }\n",
      "type": "registry:ui"
    }
  ],
  "css": {
    ":root": {
      "--visible-file-tray": "oklch(0.55 0.03 150)",
      "--visible-file-tray-edge": "oklch(0.38 0.03 150)",
      "--visible-file-card": "oklch(0.96 0.01 90)",
      "--visible-file-card-foreground": "oklch(0.25 0.02 260)",
      "--visible-file-rule": "oklch(0.85 0.02 90)",
      "--visible-file-red": "oklch(0.6 0.2 27)",
      "--visible-file-amber": "oklch(0.8 0.16 75)",
      "--visible-file-green": "oklch(0.65 0.16 150)",
      "--visible-file-blue": "oklch(0.6 0.15 250)"
    },
    "[data-slot=\"visible-file\"]": {
      "--bevel-material": "var(--visible-file-tray)",
      "--bevel-material-edge": "var(--visible-file-tray-edge)"
    },
    "[data-slot=\"visible-file-signal\"]": {
      "--bevel-material": "var(--visible-file-blue)"
    },
    "[data-slot=\"visible-file-signal\"][data-tone=\"red\"]": {
      "--bevel-material": "var(--visible-file-red)"
    },
    "[data-slot=\"visible-file-signal\"][data-tone=\"amber\"]": {
      "--bevel-material": "var(--visible-file-amber)"
    },
    "[data-slot=\"visible-file-signal\"][data-tone=\"green\"]": {
      "--bevel-material": "var(--visible-file-green)"
    }
  },
  "categories": [
    "records"
  ],
  "type": "registry:ui"
}