{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "progress-row",
  "type": "registry:ui",
  "dependencies": [
    "clsx",
    "tailwind-merge"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "progress-row.tsx",
      "target": "components/ui/progress-row.tsx",
      "type": "registry:ui",
      "content": "\"use client\";\nimport * as React from \"react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface ProgressRowProps\n  extends Omit<React.HTMLAttributes<HTMLDivElement>, \"children\"> {\n  label: React.ReactNode;\n  value: number;\n  max: number;\n  /** Trailing unit on the figures, e.g. \"cr\". */\n  unit?: string;\n  /** A slot, usually a Badge. ProgressRow never derives status from the ratio. */\n  status?: React.ReactNode;\n  /**\n   * Categorical key colour, any CSS colour, following StripeCard's stripeColor.\n   * It says which module this row is, not how it is doing.\n   */\n  barColor?: string;\n  /** Accessible name for the bar. Defaults to `label` when that is a string. */\n  \"aria-label\"?: string;\n}\n\nfunction ratio(value: number, max: number): number {\n  if (!(max > 0)) return 0;\n  return Math.min(Math.max(value / max, 0), 1);\n}\n\n/**\n * A labelled progress bar with mono figures and a status slot.\n *\n * Deliberately not a disclosure: sisu's SectionHeader wraps this shape in a\n * button with a chevron and aria-expanded. That accordion is a separate\n * concern and does not belong inside a progress row.\n */\nexport const ProgressRow = React.forwardRef<HTMLDivElement, ProgressRowProps>(\n  (\n    {\n      className,\n      label,\n      value,\n      max,\n      unit,\n      status,\n      barColor,\n      \"aria-label\": ariaLabel,\n      ...props\n    },\n    ref,\n  ) => {\n    const percent = ratio(value, max) * 100;\n    const name = ariaLabel ?? (typeof label === \"string\" ? label : undefined);\n\n    const [fill, setFill] = React.useState(0);\n    React.useEffect(() => {\n      setFill(percent);\n    }, [percent]);\n\n    return (\n      <div\n        ref={ref}\n        className={cn(\"flex items-center gap-4 py-3\", className)}\n        {...props}\n      >\n        <div className=\"min-w-0 flex-1\">\n          <div className=\"mb-2 truncate text-sm font-semibold text-ink\">\n            {label}\n          </div>\n          <div\n            role=\"progressbar\"\n            aria-label={name}\n            aria-valuenow={value}\n            aria-valuemin={0}\n            aria-valuemax={max}\n            className=\"block h-1.5 max-w-96 overflow-hidden rounded-full bg-surface-2\"\n          >\n            <span\n              data-testid=\"progress-row-fill\"\n              className={cn(\n                \"block h-full rounded-full transition-[width] duration-slow ease-soft motion-reduce:transition-none\",\n                barColor == null && \"bg-accent\",\n              )}\n              style={{\n                width: `${fill}%`,\n                backgroundColor: barColor,\n              }}\n            />\n          </div>\n        </div>\n\n        {status != null && <div className=\"shrink-0\">{status}</div>}\n\n        <div className=\"min-w-20 shrink-0 text-right font-mono text-sm tabular-nums\">\n          <span className=\"font-semibold text-ink\">{value}</span>\n          <span className=\"text-muted\">\n            {\" / \"}\n            {max}\n            {unit != null && ` ${unit}`}\n          </span>\n        </div>\n      </div>\n    );\n  },\n);\nProgressRow.displayName = \"ProgressRow\";\n"
    }
  ]
}