{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "progress",
  "type": "registry:ui",
  "title": "Progress",
  "description": "@interlace/ui — progress primitive (shadcn-compatible).",
  "dependencies": [
    "@base-ui/react",
    "class-variance-authority"
  ],
  "registryDependencies": [
    "theme"
  ],
  "files": [
    {
      "path": "registry/interlace-ui/progress.tsx",
      "target": "components/ui/progress.tsx",
      "type": "registry:ui",
      "content": "'use client';\n\n/**\n * @interlace/ui — Progress\n *\n * Determinate progress indicator. Wraps the Base UI `Progress` compound — Root,\n * Track, Indicator, Label, Value — and re-exports DS-styled parts that consume\n * theme tokens (no raw px, no hex). The Track defines the rail height (`size`);\n * the Indicator carries the filled tone (`tone`). Width animation is\n * disabled when `prefers-reduced-motion: reduce` is set — per the MOTION\n * philosophy, a CSS `transition-[width]` would otherwise animate from 0 → value\n * on every render, including for users who opted out.\n *\n * ## Anatomy\n *\n *   <Progress value={62}>                  ← BaseProgress.Root, data-min-viewport\n *     <ProgressLabel>Uploading</ProgressLabel>\n *     <ProgressValue />                    ← \"62%\"\n *     <ProgressTrack size=\"md\">            ← rail\n *       <ProgressIndicator tone=\"default\" /> ← filled portion\n *     </ProgressTrack>\n *   </Progress>\n *\n * ## MIN_VIEWPORT — 320\n *\n * Progress bars are linear; the rail scales to whatever width the parent\n * offers, down to a 320 CSS-px iPhone SE column. The smallest size (`sm`,\n * h-1 = 4px) clears visibility at that width and reduced-motion is on by\n * default for OS-level \"reduce motion\" users (DESIGN_PRINCIPLES #14).\n *\n * | Rule | Concept                          | Where in this file                                          |\n * | ---- | -------------------------------- | ----------------------------------------------------------- |\n * | R4   | Extends Base UI part + VariantProps | `ComponentProps<typeof BaseProgress.Track> & VariantProps<...>` |\n * | R6   | data-slot on every part          | `data-slot=\"progress\" / \"-track\" / \"-indicator\" / \"-label\" / \"-value\"` |\n * | R7   | className merged + ...rest       | `cn(progressXVariants(...), className)` + `{...props}` on every part |\n * | R8   | No `isXxx`; enums for >2 states  | `size` (sm/md/lg) / `tone` (default/success/warning/danger) |\n * | R11  | One variable per part            | Track owns `size`; Indicator owns `tone` — orthogonal axes  |\n * | R13  | Ecosystem first                  | `@base-ui/react/progress` owns ARIA, value math, indeterminate |\n * | R14  | Declares min viewport            | `data-min-viewport={String(MIN_VIEWPORT)}` + exported const |\n * | R17  | API parity                       | Mirrors Base UI Progress part names (Root/Track/Indicator/Label/Value) |\n * | R18  | Tailwind only                    | Zero inline `style`; cva classes only                       |\n * | R19  | Tokens only                      | h-1/2/3 = 4/8/12px on Tailwind's spacing scale; tones from `--color-*` |\n * | R20  | AA contrast                      | Track on `bg-secondary`; Indicator on `bg-primary/success/warning/destructive` |\n * | R25  | Client component                 | useReducedMotion → matchMedia hook → 'use client' required  |\n * | R26  | A11y from Base UI part           | BaseProgress.Root owns role=\"progressbar\" + aria-value*     |\n *\n * Out of scope: this primitive does NOT ship the `<XCircle />` \"error\" leading\n * icon or the \"complete\" check — those belong one level up in a composed\n * `ProgressCard` block. The indicator transition is also intentionally simple\n * (width-only) so it composes inside any parent layout without bleeding motion.\n */\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';\nimport { useReducedMotion } from '@/hooks/use-reduced-motion';\n\n/**\n * Minimum viable viewport (CSS px) for this primitive. Below it, the\n * preflight contract draws a dev-mode outline; in prod the rail still renders.\n */\nexport const MIN_VIEWPORT = 320 as const;\n\n// ─────────────────────────────────────────────────────────────────\n// Progress (root) — BaseProgress.Root + data-min-viewport\n// ─────────────────────────────────────────────────────────────────\ntype ProgressProps = React.ComponentProps<typeof BaseProgress.Root>;\n\nconst Progress = React.forwardRef<\n  React.ElementRef<typeof BaseProgress.Root>,\n  ProgressProps\n>(function Progress({ className, ...props }, ref) {\n  return (\n    <BaseProgress.Root\n      ref={ref}\n      data-slot=\"progress\"\n      data-min-viewport={String(MIN_VIEWPORT)}\n      className={cn('w-full', className)}\n      {...props}\n    />\n  );\n});\nProgress.displayName = 'Progress';\n\n// ─────────────────────────────────────────────────────────────────\n// ProgressTrack — the rail. `size` controls height (4/8/12px).\n// ─────────────────────────────────────────────────────────────────\nconst progressTrackVariants = cva(\n  // Base — surface, radius, clipping for the indicator fill.\n  'relative w-full overflow-hidden rounded-full bg-secondary',\n  {\n    variants: {\n      /**\n       * Rail height. Maps to Tailwind's 4px spacing step:\n       *   sm = h-1 (4px), md = h-2 (8px), lg = h-3 (12px).\n       * No raw [px] values; sizes live on the canonical spacing scale.\n       */\n      size: {\n        sm: 'h-1',\n        md: 'h-2',\n        lg: 'h-3',\n      },\n    },\n    defaultVariants: { size: 'md' },\n  },\n);\n\ntype ProgressTrackProps = React.ComponentProps<typeof BaseProgress.Track> &\n  VariantProps<typeof progressTrackVariants>;\n\nconst ProgressTrack = React.forwardRef<\n  React.ElementRef<typeof BaseProgress.Track>,\n  ProgressTrackProps\n>(function ProgressTrack({ className, size, ...props }, ref) {\n  return (\n    <BaseProgress.Track\n      ref={ref}\n      data-slot=\"progress-track\"\n      data-size={size ?? undefined}\n      className={cn(progressTrackVariants({ size }), className)}\n      {...props}\n    />\n  );\n});\nProgressTrack.displayName = 'ProgressTrack';\n\n// ─────────────────────────────────────────────────────────────────\n// ProgressIndicator — filled portion. `tone` controls the bar color.\n// Width is driven by BaseProgress.Indicator (sets `style.width`); we\n// only animate the transition (and gate it on reduced-motion).\n// ─────────────────────────────────────────────────────────────────\nconst progressIndicatorVariants = cva(\n  // Base — absolute fill, inherits track radius. NO transition here:\n  // it's appended conditionally in JSX so reduced-motion users skip it.\n  'h-full w-full flex-1 rounded-full',\n  {\n    variants: {\n      /**\n       * Semantic tone. Maps to the DS color tokens. `danger` is the public\n       * spelling; under the hood it maps to `bg-destructive` (shadcn canon).\n       */\n      tone: {\n        default: 'bg-primary',\n        success: 'bg-success',\n        warning: 'bg-warning',\n        danger: 'bg-destructive',\n      },\n    },\n    defaultVariants: { tone: 'default' },\n  },\n);\n\ntype ProgressIndicatorProps = React.ComponentProps<\n  typeof BaseProgress.Indicator\n> &\n  VariantProps<typeof progressIndicatorVariants>;\n\nconst ProgressIndicator = React.forwardRef<\n  React.ElementRef<typeof BaseProgress.Indicator>,\n  ProgressIndicatorProps\n>(function ProgressIndicator({ className, tone, ...props }, ref) {\n  const reduceMotion = useReducedMotion();\n  return (\n    <BaseProgress.Indicator\n      ref={ref}\n      data-slot=\"progress-indicator\"\n      data-tone={tone ?? undefined}\n      className={cn(\n        progressIndicatorVariants({ tone }),\n        // Width-only transition. Omitted entirely when the user has\n        // prefers-reduced-motion: reduce — no easing, no duration.\n        reduceMotion ? undefined : 'transition-[width] duration-200 ease-out',\n        className,\n      )}\n      {...props}\n    />\n  );\n});\nProgressIndicator.displayName = 'ProgressIndicator';\n\n// ─────────────────────────────────────────────────────────────────\n// ProgressLabel — accessible label associated with the progressbar.\n// ─────────────────────────────────────────────────────────────────\ntype ProgressLabelProps = React.ComponentProps<typeof BaseProgress.Label>;\n\nconst ProgressLabel = React.forwardRef<\n  React.ElementRef<typeof BaseProgress.Label>,\n  ProgressLabelProps\n>(function ProgressLabel({ className, ...props }, ref) {\n  return (\n    <BaseProgress.Label\n      ref={ref}\n      data-slot=\"progress-label\"\n      className={cn('text-ui-sm font-medium text-foreground', className)}\n      {...props}\n    />\n  );\n});\nProgressLabel.displayName = 'ProgressLabel';\n\n// ─────────────────────────────────────────────────────────────────\n// ProgressValue — current value rendered as text (e.g. \"62%\").\n// ─────────────────────────────────────────────────────────────────\ntype ProgressValueProps = React.ComponentProps<typeof BaseProgress.Value>;\n\nconst ProgressValue = React.forwardRef<\n  React.ElementRef<typeof BaseProgress.Value>,\n  ProgressValueProps\n>(function ProgressValue({ className, ...props }, ref) {\n  return (\n    <BaseProgress.Value\n      ref={ref}\n      data-slot=\"progress-value\"\n      className={cn('text-ui-sm tabular-nums text-muted-foreground', className)}\n      {...props}\n    />\n  );\n});\nProgressValue.displayName = 'ProgressValue';\n\nexport {\n  Progress,\n  ProgressTrack,\n  ProgressIndicator,\n  ProgressLabel,\n  ProgressValue,\n  progressTrackVariants,\n  progressIndicatorVariants,\n};\nexport type {\n  ProgressProps,\n  ProgressTrackProps,\n  ProgressIndicatorProps,\n  ProgressLabelProps,\n  ProgressValueProps,\n};\n"
    }
  ]
}
