{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "progress-circle",
  "type": "registry:ui",
  "title": "Progress Circle",
  "description": "Circular progress indicator. Radial counterpart to Progress, common for KPI rings.",
  "dependencies": [
    "@saasflare/ui",
    "motion"
  ],
  "files": [
    {
      "path": "components/ui/progress-circle.tsx",
      "type": "registry:ui",
      "content": "// @draft\n\"use client\"\n\n/**\n * @fileoverview Saasflare ProgressCircle — circular progress indicator.\n * @author Saasflare™\n *\n * The radial counterpart to Progress. Sized via the `size` prop; stroke\n * width auto-scales but can be overridden. Renders an SVG ring with a\n * smooth spring animation from 0% to the current value. Optionally\n * displays a center label (the consumer's children).\n *\n * @module packages/ui/components/ui/progress-circle\n * @package ui\n * @layer core\n *\n * @example\n * <ProgressCircle value={72} />\n *\n * @example\n * <ProgressCircle value={45} size=\"lg\">\n *   <span className=\"text-sm font-semibold\">45%</span>\n * </ProgressCircle>\n */\n\nimport { type ReactNode } from \"react\"\nimport { m } from \"motion/react\"\nimport { cn } from \"@saasflare/ui\"\nimport { useSaasflareProps, type SaasflareComponentProps } from \"@saasflare/ui\"\nimport { useSaasflareMotion, springGentle } from \"@saasflare/ui\"\n\nconst SIZE_PX = {\n    sm: 48,\n    md: 64,\n    lg: 96,\n    xl: 128,\n} as const\n\n/** Size preset of a {@link ProgressCircle} — selects the outer diameter (`sm` 48px, `md` 64px, `lg` 96px, `xl` 128px). */\nexport type ProgressCircleSize = keyof typeof SIZE_PX\n\n/** Props for the ProgressCircle component. */\nexport interface ProgressCircleProps extends SaasflareComponentProps {\n    /** Current value in the range `[0, max]`. */\n    value: number\n    /** Maximum value. Default: `100`. */\n    max?: number\n    /** Size preset. Default: `\"md\"`. */\n    size?: ProgressCircleSize\n    /** Ring stroke width in pixels. Default: derived from `size`. */\n    strokeWidth?: number\n    /** Center content (e.g. the numeric label). */\n    children?: ReactNode\n    /** Additional class names on the outer wrapper. */\n    className?: string\n    /** Accessible label. Default: `\"<value>%\"`. */\n    \"aria-label\"?: string\n}\n\n/**\n * Circular progress indicator. Drop-in radial counterpart to Progress.\n *\n * @component\n * @layer core\n *\n * @example\n * <ProgressCircle value={72} />\n */\nexport function ProgressCircle({\n    value,\n    max = 100,\n    size = \"md\",\n    strokeWidth,\n    children,\n    className,\n    surface,\n    radius,\n    animated,\n    iconWeight,\n    \"aria-label\": ariaLabel,\n}: ProgressCircleProps) {\n    const sf = useSaasflareProps({ surface, radius, animated, iconWeight })\n    const motion = useSaasflareMotion(sf.animated, springGentle)\n\n    const px = SIZE_PX[size]\n    const sw = strokeWidth ?? Math.max(3, Math.round(px / 12))\n    const radiusPx = (px - sw) / 2\n    const circumference = 2 * Math.PI * radiusPx\n    const clamped = Math.min(Math.max(value, 0), max)\n    const percent = (clamped / max) * 100\n    const dashOffset = circumference * (1 - clamped / max)\n\n    return (\n        <div\n            data-slot=\"progress-circle\"\n            data-size={size}\n            data-surface={sf.surface}\n            data-radius={sf.radius}\n            data-animated={String(sf.animated)}\n            role=\"progressbar\"\n            aria-valuenow={clamped}\n            aria-valuemin={0}\n            aria-valuemax={max}\n            aria-label={ariaLabel ?? `${Math.round(percent)}%`}\n            className={cn(\"relative inline-flex items-center justify-center\", className)}\n            style={{ width: px, height: px }}\n        >\n            <svg\n                width={px}\n                height={px}\n                viewBox={`0 0 ${px} ${px}`}\n                className=\"-rotate-90\"\n            >\n                <circle\n                    data-slot=\"progress-circle-track\"\n                    cx={px / 2}\n                    cy={px / 2}\n                    r={radiusPx}\n                    fill=\"none\"\n                    strokeWidth={sw}\n                    className=\"stroke-primary/15\"\n                />\n                <m.circle\n                    data-slot=\"progress-circle-indicator\"\n                    cx={px / 2}\n                    cy={px / 2}\n                    r={radiusPx}\n                    fill=\"none\"\n                    strokeWidth={sw}\n                    strokeLinecap=\"round\"\n                    strokeDasharray={circumference}\n                    className=\"stroke-primary\"\n                    initial={motion.disabled ? false : { strokeDashoffset: circumference }}\n                    animate={{ strokeDashoffset: dashOffset }}\n                    transition={motion.transition}\n                />\n            </svg>\n            {children !== undefined && (\n                <div\n                    data-slot=\"progress-circle-label\"\n                    className=\"pointer-events-none absolute inset-0 flex items-center justify-center\"\n                >\n                    {children}\n                </div>\n            )}\n        </div>\n    )\n}\n",
      "target": "components/ui/progress-circle.tsx"
    }
  ],
  "$meta": {
    "source": "https://ui.saasflare.io/r/progress-circle.json"
  }
}
