{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "progress",
  "title": "Progress",
  "description": "Progress bars: eased, segmented and indeterminate.",
  "dependencies": [
    "radix-ui"
  ],
  "registryDependencies": [
    "utils",
    "https://ui.cuelark.com/r/theme.json",
    "https://ui.cuelark.com/r/motion.json"
  ],
  "files": [
    {
      "path": "src/registry/cuelark/ui/progress.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { Progress as ProgressPrimitive } from \"radix-ui\";\n\nimport { cueTo, gsap, motionScale } from \"@/lib/motion\";\nimport { cn } from \"@/lib/utils\";\n\ntype ProgressProps = Omit<React.ComponentProps<typeof ProgressPrimitive.Root>, \"value\"> & {\n  /** 0–100, or `null` for an indeterminate bar. */\n  value?: number | null;\n  /** Splits the bar into this many cells that light up one by one. */\n  segments?: number;\n  size?: \"sm\" | \"md\" | \"lg\";\n};\n\nconst heights = { sm: \"h-1\", md: \"h-1.5\", lg: \"h-2.5\" };\n\n/** The fill eases to each new value with GSAP (no CSS width jumps); segmented bars light their cells in a cascade. */\nfunction Progress({ className, value = 0, max = 100, segments, size = \"md\", ...props }: ProgressProps) {\n  const ref = React.useRef<HTMLDivElement>(null);\n  const initial = React.useRef(value);\n  const pct = value === null ? null : Math.min(100, Math.max(0, (value / max) * 100));\n\n  React.useLayoutEffect(() => {\n    const root = ref.current;\n    if (!root || pct === null) return;\n    const scale = motionScale(root);\n    if (segments) {\n      const cells = Array.from(root.querySelectorAll<HTMLElement>('[data-slot=\"progress-cell\"]'));\n      const lit = Math.round((pct / 100) * segments);\n      cells.forEach((cell) => {\n        const on = Number(cell.dataset.index) < lit;\n        if (on === (cell.dataset.on === \"true\")) return;\n        cell.dataset.on = String(on);\n        if (scale && on) gsap.fromTo(cell, { scaleY: 1 + 0.8 * scale }, { scaleY: 1, duration: 0.4, ease: \"cue-snap\", delay: (Number(cell.dataset.index) % 4) * 0.03 });\n      });\n      return;\n    }\n    const fill = root.querySelector<HTMLElement>('[data-slot=\"progress-indicator\"]');\n    if (fill) cueTo(fill, { width: `${pct}%`, duration: 0.6 }, scale);\n  }, [pct, segments]);\n\n  return (\n    <ProgressPrimitive.Root\n      ref={ref}\n      data-slot=\"progress\"\n      value={value}\n      max={max}\n      className={cn(\"relative w-full overflow-hidden rounded-full\", segments ? \"flex gap-1 bg-transparent\" : \"bg-muted shadow-well\", heights[size], className)}\n      {...props}\n    >\n      {segments ? (\n        Array.from({ length: segments }, (_, i) => {\n          const on = pct !== null && i < Math.round(((initial.current ?? 0) / max) * 100 * (segments / 100));\n          return (\n            <span\n              key={i}\n              data-slot=\"progress-cell\"\n              data-index={i}\n              data-on={on}\n              className=\"h-full flex-1 rounded-full bg-muted shadow-well transition-colors duration-200 data-[on=true]:bg-primary data-[on=true]:shadow-none\"\n            />\n          );\n        })\n      ) : pct === null ? (\n        <span data-slot=\"progress-indicator\" className=\"absolute inset-y-0 w-full origin-left animate-[cue-indeterminate_1.4s_ease-in-out_infinite] rounded-full bg-primary\" />\n      ) : (\n        <ProgressPrimitive.Indicator\n          data-slot=\"progress-indicator\"\n          className=\"h-full rounded-full bg-primary\"\n          style={{ width: `${Math.min(100, Math.max(0, ((initial.current ?? 0) / max) * 100))}%` }}\n        />\n      )}\n    </ProgressPrimitive.Root>\n  );\n}\n\nexport { Progress };\nexport type { ProgressProps };\n",
      "type": "registry:ui"
    }
  ],
  "docs": "Docs and examples: https://ui.cuelark.com/components/progress",
  "categories": [
    "feedback"
  ],
  "type": "registry:ui"
}