{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "autoscale-chart",
  "title": "AutoscaleChart",
  "description": "Autoscaling compute units over time against the min/max bounds, with a scrubable readout.",
  "dependencies": [
    "recharts"
  ],
  "registryDependencies": [
    "utils",
    "https://ui.neon.com/r/skeleton.json",
    "https://ui.neon.com/r/neon-tokens.json",
    "https://ui.neon.com/r/chart.json"
  ],
  "files": [
    {
      "path": "src/components/autoscale-chart/autoscale-chart.tsx",
      "content": "\"use client\";\n\nimport { useId } from \"react\";\nimport type { ComponentProps } from \"react\";\nimport {\n  Area,\n  AreaChart,\n  ReferenceArea,\n  ReferenceLine,\n  XAxis,\n  YAxis,\n} from \"recharts\";\n\nimport type { ChartConfig } from \"@/components/ui/chart\";\nimport {\n  ChartContainer,\n  ChartTooltip,\n  ChartTooltipContent,\n} from \"@/components/ui/chart\";\nimport { Skeleton } from \"@/components/ui/skeleton\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface AutoscalePoint {\n  /** Short time label, e.g. \"12:00\". */\n  label: string;\n  /** Compute units in use at this moment. */\n  cu: number;\n}\n\nconst HEADROOM = 1.08;\nconst NICE_STEPS = [1, 2, 2.5, 5, 10] as const;\n\n/**\n * Rounds the top of the scale to a readable number. Left at peak x 1.08\n * the axis reads 4.32, which is a number nobody asked for.\n */\nconst niceCeiling = (peak: number) => {\n  const raw = peak * HEADROOM;\n\n  if (raw <= 0) {\n    return 1;\n  }\n\n  const magnitude = 10 ** Math.floor(Math.log10(raw));\n  const normalized = raw / magnitude;\n  const step = NICE_STEPS.find((candidate) => normalized <= candidate) ?? 10;\n\n  return step * magnitude;\n};\n\nconst formatCu = (cu: number) => {\n  const rounded = Math.round(cu * 100) / 100;\n\n  return Number.isInteger(rounded) ? String(rounded) : rounded.toFixed(2);\n};\n\nexport type AutoscaleChartProps = Omit<ComponentProps<\"div\">, \"children\"> & {\n  /** Compute-unit readings over time, oldest first. */\n  data: AutoscalePoint[];\n  /** Autoscale lower bound (CU); the compute never scales below it. */\n  min: number;\n  /** Autoscale upper bound (CU); the compute never scales above it. */\n  max: number;\n  /** Panel heading. */\n  title?: string;\n  isLoading?: boolean;\n};\n\n/* ─────────────────────────────────────────────────────────\n * AUTOSCALE STORYBOARD\n *\n *  envelope  the band between min and max is drawn first,\n *            so the reading is always seen against the\n *            room it has to move in\n *  bounds    dashed lines with mono labels at both edges;\n *            a ceiling you can't see is a ceiling you'll\n *            hit without knowing\n *  scrub     Recharts' accessibility layer gives the plot\n *            focus and arrow keys; the tooltip names the\n *            moment and its CU\n * ───────────────────────────────────────────────────────── */\n\nconst cuTooltipFormatter = (\n  value: unknown,\n  _name: unknown,\n  entry: { color?: string }\n) => (\n  <>\n    <span\n      aria-hidden=\"true\"\n      className=\"size-2.5 shrink-0 translate-y-[1px] rounded-[2px]\"\n      style={{ background: String(entry?.color ?? \"var(--primary)\") }}\n    />\n    <div className=\"flex flex-1 items-center justify-between gap-3 leading-none\">\n      <span className=\"text-muted-foreground\">Compute</span>\n      <span className=\"font-medium font-mono text-foreground tabular-nums\">\n        {formatCu(Number(value))}\n        <span className=\"ml-1 font-normal text-muted-foreground/70\">CU</span>\n      </span>\n    </div>\n  </>\n);\n\nexport const AutoscaleChart = ({\n  className,\n  data,\n  isLoading = false,\n  max,\n  min,\n  title = \"Autoscaling\",\n  ...props\n}: AutoscaleChartProps) => {\n  const gradientId = `autoscale-fill-${useId().replaceAll(\":\", \"\")}`;\n\n  if (isLoading) {\n    return (\n      <div\n        className={cn(\n          \"rounded-lg border border-border/60 bg-card p-4\",\n          className\n        )}\n        data-slot=\"autoscale-chart\"\n        {...props}\n      >\n        <Skeleton className=\"h-4 w-28\" />\n        <Skeleton className=\"mt-4 h-[150px] w-full\" />\n      </div>\n    );\n  }\n\n  const current = data.at(-1)?.cu ?? 0;\n  const ceiling = niceCeiling(Math.max(max, ...data.map((point) => point.cu)));\n\n  const config: ChartConfig = {\n    cu: { color: \"var(--primary)\", label: \"Compute units\" },\n  };\n\n  return (\n    <div\n      className={cn(\n        \"rounded-lg border border-border/60 bg-card p-4\",\n        className\n      )}\n      data-slot=\"autoscale-chart\"\n      {...props}\n    >\n      <header className=\"mb-3 flex items-baseline justify-between gap-3\">\n        <span className=\"font-mono text-muted-foreground text-xs\">{title}</span>\n        <span className=\"flex items-baseline gap-1.5 font-mono tabular-nums\">\n          <span className=\"font-medium text-foreground text-sm\">\n            {formatCu(current)}\n          </span>\n          <span className=\"text-muted-foreground text-xs\">CU</span>\n          <span className=\"text-muted-foreground/50 text-[10px]\">\n            / {formatCu(min)}–{formatCu(max)}\n          </span>\n        </span>\n      </header>\n\n      <ChartContainer className=\"aspect-auto h-[170px] w-full\" config={config}>\n        <AreaChart\n          accessibilityLayer\n          data={data}\n          margin={{ left: 4, right: 76, top: 4 }}\n        >\n          <defs>\n            <linearGradient id={gradientId} x1=\"0\" x2=\"0\" y1=\"0\" y2=\"1\">\n              <stop offset=\"0%\" stopColor=\"var(--primary)\" stopOpacity={0.2} />\n              <stop offset=\"100%\" stopColor=\"var(--primary)\" stopOpacity={0} />\n            </linearGradient>\n          </defs>\n\n          {/* The band the compute may move within. */}\n          <ReferenceArea\n            fill=\"var(--muted-foreground)\"\n            fillOpacity={0.06}\n            ifOverflow=\"extendDomain\"\n            y1={min}\n            y2={max}\n          />\n          <ReferenceLine\n            label={{\n              className: \"fill-muted-foreground/80 font-mono text-[10px]\",\n              position: \"right\",\n              value: `max ${formatCu(max)} CU`,\n            }}\n            stroke=\"var(--border)\"\n            strokeDasharray=\"3 3\"\n            y={max}\n          />\n          <ReferenceLine\n            label={{\n              className: \"fill-muted-foreground/80 font-mono text-[10px]\",\n              position: \"right\",\n              value: `min ${formatCu(min)} CU`,\n            }}\n            stroke=\"var(--border)\"\n            strokeDasharray=\"3 3\"\n            y={min}\n          />\n\n          <XAxis\n            axisLine={false}\n            dataKey=\"label\"\n            interval=\"preserveStartEnd\"\n            minTickGap={24}\n            tickLine={false}\n            tickMargin={8}\n          />\n          <YAxis\n            axisLine={false}\n            domain={[0, ceiling]}\n            tickFormatter={formatCu}\n            tickLine={false}\n            width={36}\n          />\n          <ChartTooltip\n            content={<ChartTooltipContent formatter={cuTooltipFormatter} />}\n            cursor={{ stroke: \"var(--border)\", strokeDasharray: \"2 3\" }}\n          />\n\n          <Area\n            dataKey=\"cu\"\n            fill={`url(#${gradientId})`}\n            stroke=\"var(--primary)\"\n            strokeWidth={1.75}\n            type=\"monotone\"\n          />\n        </AreaChart>\n      </ChartContainer>\n    </div>\n  );\n};\n",
      "type": "registry:component"
    }
  ],
  "type": "registry:component"
}