{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "progress",
  "title": "Progress",
  "description": "A progress component.",
  "dependencies": [
    "class-variance-authority"
  ],
  "files": [
    {
      "path": "registry/default/progress/progress.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { Progress as BaseProgress } from \"@base-ui/react/progress\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\n\nimport { cn } from \"@/lib/utils\";\n\nimport \"./progress.css\";\n\nconst progressRootVariants = cva(\n  [\n    // Label and value share row one; everything else spans below\n    \"group/progress grid w-full grid-flow-row-dense grid-cols-[minmax(0,1fr)_auto] items-baseline gap-x-3 gap-y-2\",\n    \"[&>:not([data-slot=progress-label],[data-slot=progress-value])]:col-span-full\",\n    \"[&>[data-slot=progress-value]]:col-start-2 [&>[data-slot=progress-value]]:justify-self-end\",\n    // With a ring: one inline row\n    \"has-[>[data-slot=progress-circle]]:flex has-[>[data-slot=progress-circle]]:w-auto has-[>[data-slot=progress-circle]]:items-center has-[>[data-slot=progress-circle]]:gap-x-2\",\n  ],\n  {\n    variants: {\n      variant: {\n        default: \"[--progress-color:var(--primary)]\",\n        neutral: \"[--progress-color:var(--neutral)]\",\n        success: \"[--progress-color:var(--success-foreground)]\",\n        warning: \"[--progress-color:var(--warning-foreground)]\",\n        danger: \"[--progress-color:var(--danger-foreground)]\",\n        info: \"[--progress-color:var(--info-foreground)]\",\n      },\n    },\n    defaultVariants: {\n      variant: \"default\",\n    },\n  },\n);\n\n// Remounts the indicator and ring when value toggles null, so neither tweens\n// between the indeterminate state and a real value.\nconst ProgressIndeterminateContext = React.createContext(false);\n\nexport interface ProgressRootProps\n  extends\n    React.ComponentProps<typeof BaseProgress.Root>,\n    VariantProps<typeof progressRootVariants> {\n  /** Track thickness. */\n  size?: \"sm\" | \"md\" | \"lg\";\n  /** Secondary value drawn behind the indicator, like loaded media. */\n  buffer?: number;\n}\n\nfunction ProgressRoot({\n  className,\n  style,\n  variant,\n  size = \"md\",\n  buffer,\n  value,\n  min = 0,\n  max = 100,\n  ...props\n}: ProgressRootProps) {\n  const percent = value === null ? undefined : toPercent(value, min, max);\n\n  // Unitless so ProgressCircle can use it directly as a stroke length\n  const vars = {\n    \"--progress-percent\": percent,\n    \"--progress-buffer\":\n      buffer !== undefined ? `${toPercent(buffer, min, max)}%` : undefined,\n  } as React.CSSProperties;\n\n  return (\n    <ProgressIndeterminateContext.Provider value={value === null}>\n      <BaseProgress.Root\n        data-slot=\"progress\"\n        data-size={size}\n        data-empty={percent === 0 || undefined}\n        value={value}\n        min={min}\n        max={max}\n        className={cn(progressRootVariants({ variant }), className)}\n        style={(state) => ({\n          ...vars,\n          ...(typeof style === \"function\" ? style(state) : style),\n        })}\n        {...props}\n      />\n    </ProgressIndeterminateContext.Provider>\n  );\n}\n\nfunction toPercent(value: number, min: number, max: number): number {\n  if (max <= min) return 0;\n  return Math.min(100, Math.max(0, ((value - min) / (max - min)) * 100));\n}\n\nfunction ProgressTrack({\n  className,\n  ...props\n}: React.ComponentProps<typeof BaseProgress.Track>) {\n  return (\n    <BaseProgress.Track\n      data-slot=\"progress-track\"\n      className={cn(\n        \"bg-foreground/9 relative w-full overflow-hidden rounded-full\",\n        // The sweep runs left to right; mirroring the track reverses it in RTL\n        \"rtl:data-indeterminate:-scale-x-100\",\n        \"group-data-[size=lg]/progress:h-2.5 group-data-[size=md]/progress:h-1.5 group-data-[size=sm]/progress:h-1\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction ProgressIndicator({\n  className,\n  ...props\n}: React.ComponentProps<typeof BaseProgress.Indicator>) {\n  const indeterminate = React.useContext(ProgressIndeterminateContext);\n\n  return (\n    <BaseProgress.Indicator\n      key={indeterminate ? \"indeterminate\" : \"determinate\"}\n      data-slot=\"progress-indicator\"\n      className={cn(\n        \"relative h-full rounded-full bg-(--progress-color)\",\n        \"ease-out-expo transition-[width,background-color] duration-500 motion-reduce:transition-none\",\n        // Indeterminate: a 40% sweep, or a full-width breathe under reduced motion\n        \"data-indeterminate:absolute data-indeterminate:inset-y-0 data-indeterminate:left-0 data-indeterminate:w-2/5\",\n        \"data-indeterminate:animate-[progress-indeterminate_1.6s_var(--ease-in-out-cubic)_infinite]\",\n        \"motion-reduce:data-indeterminate:w-full motion-reduce:data-indeterminate:animate-[progress-breathe_2.4s_ease-in-out_infinite]\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\n/** Draws the root's `buffer`. Place it before `ProgressIndicator` in the track. */\nfunction ProgressBuffer({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      aria-hidden\n      data-slot=\"progress-buffer\"\n      className={cn(\n        \"absolute inset-y-0 start-0 w-(--progress-buffer,0%) rounded-full bg-(--progress-color) opacity-25\",\n        \"ease-out-expo transition-[width] duration-500 motion-reduce:transition-none\",\n        \"group-data-indeterminate/progress:hidden\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nexport interface ProgressCircleProps extends Omit<\n  React.ComponentProps<\"span\">,\n  \"children\"\n> {\n  /** Diameter in px. */\n  size?: number;\n  /** Stroke width in px. Defaults to a tenth of `size`, at least 2. */\n  thickness?: number;\n  /** Content centered inside the ring, typically `ProgressValue`. */\n  children?: React.ReactNode;\n}\n\n/** A ring used in place of `ProgressTrack`, driven by the same root. */\nfunction ProgressCircle({\n  className,\n  style,\n  size = 20,\n  thickness,\n  children,\n  ...props\n}: ProgressCircleProps) {\n  const indeterminate = React.useContext(ProgressIndeterminateContext);\n  const stroke = thickness ?? Math.max(2, size / 10);\n  const radius = (size - stroke) / 2;\n  const center = size / 2;\n\n  return (\n    <span\n      data-slot=\"progress-circle\"\n      className={cn(\n        \"relative inline-grid shrink-0 place-items-center\",\n        // A centered ProgressValue scales with the ring\n        \"[&>[data-slot=progress-value]]:text-foreground [&>[data-slot=progress-value]]:text-[length:inherit] [&>[data-slot=progress-value]]:leading-none [&>[data-slot=progress-value]]:font-medium\",\n        className,\n      )}\n      style={{\n        width: size,\n        height: size,\n        fontSize: Math.max(10, size * 0.24),\n        ...style,\n      }}\n      {...props}\n    >\n      <svg\n        aria-hidden\n        width={size}\n        height={size}\n        viewBox={`0 0 ${size} ${size}`}\n        className={cn(\n          \"absolute inset-0 -rotate-90\",\n          // Indeterminate: a spinning quarter arc, or a breathe under reduced motion\n          \"group-data-indeterminate/progress:animate-spin motion-reduce:group-data-indeterminate/progress:animate-none\",\n        )}\n      >\n        <circle\n          cx={center}\n          cy={center}\n          r={radius}\n          fill=\"none\"\n          strokeWidth={stroke}\n          className=\"stroke-foreground/9\"\n        />\n        <circle\n          key={indeterminate ? \"indeterminate\" : \"determinate\"}\n          cx={center}\n          cy={center}\n          r={radius}\n          fill=\"none\"\n          strokeWidth={stroke}\n          strokeLinecap=\"round\"\n          pathLength={100}\n          strokeDasharray=\"100 100\"\n          className={cn(\n            \"stroke-(--progress-color) [stroke-dashoffset:calc(100_-_var(--progress-percent,0))]\",\n            \"ease-out-expo transition-[stroke-dashoffset,stroke,opacity] duration-500 motion-reduce:transition-none\",\n            // Round caps paint a dot at zero length; fade once the arc drains\n            \"group-data-empty/progress:opacity-0 group-data-empty/progress:[transition-delay:0s,0s,300ms]\",\n            \"group-data-indeterminate/progress:[stroke-dashoffset:75]\",\n            \"motion-reduce:group-data-indeterminate/progress:animate-[progress-breathe_2.4s_ease-in-out_infinite]\",\n          )}\n        />\n      </svg>\n      {children}\n    </span>\n  );\n}\n\nfunction ProgressLabel({\n  className,\n  ...props\n}: React.ComponentProps<typeof BaseProgress.Label>) {\n  return (\n    <BaseProgress.Label\n      data-slot=\"progress-label\"\n      className={cn(\n        \"text-foreground col-start-1 text-sm font-medium\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction ProgressValue({\n  className,\n  ...props\n}: React.ComponentProps<typeof BaseProgress.Value>) {\n  return (\n    <BaseProgress.Value\n      data-slot=\"progress-value\"\n      className={cn(\n        \"text-muted-foreground text-sm tabular-nums\",\n        // Base UI prints \"indeterminate\" when value is null\n        \"data-indeterminate:hidden\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\n/** Root, track, and indicator in one. Children render above the track. */\nfunction Progress({ children, buffer, ...props }: ProgressRootProps) {\n  return (\n    <ProgressRoot buffer={buffer} {...props}>\n      {children}\n      <ProgressTrack>\n        {buffer !== undefined && <ProgressBuffer />}\n        <ProgressIndicator />\n      </ProgressTrack>\n    </ProgressRoot>\n  );\n}\n\nexport {\n  Progress,\n  ProgressRoot,\n  ProgressTrack,\n  ProgressIndicator,\n  ProgressBuffer,\n  ProgressCircle,\n  ProgressLabel,\n  ProgressValue,\n  progressRootVariants,\n};\n",
      "type": "registry:ui",
      "target": "components/ui/cubby-ui/progress/progress.tsx"
    },
    {
      "path": "registry/default/progress/progress.css",
      "content": "/* The indicator is 40% of the track, so -100% to 250% of its own width\n * carries it fully off both edges. */\n\n@keyframes progress-indeterminate {\n  from {\n    translate: -100% 0;\n  }\n  to {\n    translate: 250% 0;\n  }\n}\n\n@keyframes progress-breathe {\n  0%,\n  100% {\n    opacity: 0.35;\n  }\n  50% {\n    opacity: 0.7;\n  }\n}\n",
      "type": "registry:file",
      "target": "components/ui/cubby-ui/progress/progress.css"
    }
  ],
  "type": "registry:ui"
}