{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "progress",
  "title": "Progress",
  "description": "Horizontal progress bar with tone variants, built on Radix.",
  "dependencies": [
    "class-variance-authority@^0.7.1",
    "radix-ui@^1.6.7"
  ],
  "registryDependencies": [
    "@pestoui/style",
    "@pestoui/utils"
  ],
  "files": [
    {
      "path": "pestoui/ui/progress.tsx",
      "content": "import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { Progress as ProgressPrimitive } from \"radix-ui\"\n\nimport { cn } from \"@/lib/utils\"\n\n/* Only the fill carries the tone — the track stays --secondary in every tone so\n   a row of bars reads as one control rather than four unrelated ones.\n\n   The first four tones are verdicts on the work: ordinary progress, done, at\n   risk, failed. The rest mirror the scale UsageMeter and Sparkline already\n   carry, for a bar that is a series colour rather than a verdict — one goal of\n   several on a savings card, one project's share of a board — where the hue\n   identifies which thing is being measured and says nothing about how it is\n   going.\n\n   The indicator glides to its new value on the layout spring — slightly\n   overdamped, so it arrives without overshooting the number it is reporting. A\n   bar that jumps loses the sense of progress entirely. */\nconst progressIndicatorVariants = cva(\n  \"size-full flex-1 rounded-full transition-transform duration-spring-glide ease-spring-glide\",\n  {\n    variants: {\n      tone: {\n        selected: \"bg-selected\",\n        success: \"bg-success\",\n        warning: \"bg-warning\",\n        destructive: \"bg-destructive\",\n        info: \"bg-info\",\n        muted: \"bg-muted-foreground\",\n        \"chart-1\": \"bg-chart-1\",\n        \"chart-2\": \"bg-chart-2\",\n        \"chart-3\": \"bg-chart-3\",\n        \"chart-4\": \"bg-chart-4\",\n        \"chart-5\": \"bg-chart-5\",\n      },\n    },\n    defaultVariants: {\n      tone: \"selected\",\n    },\n  }\n)\n\ntype ProgressTone = NonNullable<VariantProps<typeof progressIndicatorVariants>[\"tone\"]>\n\ninterface ProgressProps extends React.ComponentProps<typeof ProgressPrimitive.Root> {\n  /** Split the bar into N equal cells filled from `value`. Omit for one continuous bar. */\n  segments?: number\n  tone?: ProgressTone\n  /**\n   * Decoration pinned to the current value — a knob, a rule, a \"24%\" flag.\n   * Rendered `aria-hidden` (the progressbar role already reports the value) in\n   * a zero-width box at `value / max` of the bar's width, spanning its height,\n   * with the content centred on that line on both axes. Give the content\n   * `self-start` to hang it from the top edge, `self-end` to stand it on the\n   * bottom edge. It may overflow the bar in any direction. Not drawn while the\n   * bar is indeterminate.\n   */\n  marker?: React.ReactNode\n}\n\nfunction Progress({\n  className,\n  value,\n  max = 100,\n  segments,\n  tone = \"selected\",\n  marker,\n  ...props\n}: ProgressProps) {\n  const segmented = typeof segments === \"number\" && segments > 0\n  /* Radix keeps ownership of role=\"progressbar\" and the aria-value* trio in\n     both modes; only what is painted inside the root changes. */\n  const state = value == null ? \"indeterminate\" : value >= max ? \"complete\" : \"loading\"\n\n  /* A marker has to be able to stick out of the bar — a knob taller than the\n     track, a flag hanging below it — and the continuous bar clips on x to hide\n     the translated-away part of its fill. `overflow-x: hidden` forces the other\n     axis to `auto`, so the marker would be cut off or, worse, scroll. With a\n     marker the root stops clipping and the fill gets a clipping box of its\n     own instead. Without one, nothing below changes.\n\n     Radix reads a value outside 0..max as indeterminate and drops the aria\n     value, so the marker follows the same test rather than pinning itself to\n     an edge for a number the bar is not reporting. */\n  const determinate =\n    typeof value === \"number\" && Number.isFinite(value) && value >= 0 && value <= max\n  const marked = determinate && marker != null && marker !== false\n\n  /* The fill's position, as a percentage of the bar. At the default max of 100\n     the value is used as-is, exactly as it always was — dividing and\n     multiplying by 100 would turn 0.29 into 28.999999999999996 and change the\n     inline style of every existing bar. Any other max is scaled, so a marker\n     and the fill it marks agree on where `value` is. */\n  const filled = max === 100 ? value || 0 : max > 0 ? ((value || 0) * 100) / max : 0\n\n  const indicator = (\n    <ProgressPrimitive.Indicator\n      data-slot=\"progress-indicator\"\n      className={cn(progressIndicatorVariants({ tone }))}\n      style={{ transform: `translateX(-${100 - filled}%)` }}\n    />\n  )\n\n  return (\n    <ProgressPrimitive.Root\n      data-slot=\"progress\"\n      data-tone={tone}\n      value={value}\n      max={max}\n      className={cn(\n        \"relative flex h-2 w-full items-center\",\n        segmented\n          ? \"gap-1 overflow-visible bg-transparent\"\n          : marked\n            ? \"overflow-visible rounded-full bg-secondary\"\n            : \"overflow-x-hidden rounded-full bg-secondary\",\n        className\n      )}\n      {...props}\n    >\n      {segmented ? (\n        Array.from({ length: segments }, (_, index) => {\n          /* Each cell reports the slice of the range it owns, so a value that\n             lands mid-cell part-fills it and the row still reads as one\n             continuous bar rather than a stack of on/off lamps. */\n          const span = max / segments\n          const fill = Math.min(1, Math.max(0, ((value ?? 0) - index * span) / span))\n\n          return (\n            <span\n              key={index}\n              data-slot=\"progress-segment\"\n              /* Mirrors what Indicator would have carried — consumers style off\n                 these, and in segmented mode there is no Indicator to read. */\n              data-state={state}\n              data-value={value ?? undefined}\n              data-max={max}\n              className=\"relative h-full flex-1 overflow-hidden rounded-full bg-secondary\"\n            >\n              <span\n                data-slot=\"progress-segment-indicator\"\n                /* A span is inline, and size-full does nothing to an inline\n                   box, so without `block` the fill paints no area at all. Kept\n                   off the shared variants: the continuous bar's Indicator is a\n                   div and is left exactly as it was. */\n                className={cn(progressIndicatorVariants({ tone }), \"block origin-left\")}\n                style={{ transform: `scaleX(${fill})` }}\n              />\n            </span>\n          )\n        })\n      ) : marked ? (\n        /* Inherits the root's radius, whatever a caller set it to, so the fill\n           is cut to the same shape the unmarked bar cuts it to. */\n        <span\n          data-slot=\"progress-clip\"\n          className=\"absolute inset-0 overflow-hidden\"\n          style={{ borderRadius: \"inherit\" }}\n        >\n          {indicator}\n        </span>\n      ) : (\n        indicator\n      )}\n      {marked ? (\n        /* Zero width, so whatever is passed centres on the value line however\n           wide it is — flex centring overflows evenly to both sides, and its\n           children are kept from shrinking to the box's zero width. It follows\n           the fill on the same spring, and comes after it in the DOM so it\n           paints on top without a z-index. */\n        <span\n          data-slot=\"progress-marker\"\n          aria-hidden=\"true\"\n          className=\"pointer-events-none absolute inset-y-0 flex w-0 items-center justify-center *:shrink-0 transition-[left] duration-spring-glide ease-spring-glide\"\n          style={{ left: `${filled}%` }}\n        >\n          {marker}\n        </span>\n      ) : null}\n    </ProgressPrimitive.Root>\n  )\n}\n\nexport { Progress, progressIndicatorVariants }\nexport type { ProgressProps, ProgressTone }\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}