{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "progress",
  "title": "Progress",
  "description": "A progress bar on Base UI Progress: the bar rides a spring and its value rolls; an unknown length sweeps with an accelerate–decelerate curve and hands over to the bar when a value arrives.",
  "dependencies": [
    "motion",
    "@base-ui/react"
  ],
  "registryDependencies": [
    "https://eased.dev/r/eased-tokens.json",
    "https://eased.dev/r/eased-motion.json",
    "https://eased.dev/r/eased-number-roll.json"
  ],
  "files": [
    {
      "path": "src/registry/eased/progress/progress.tsx",
      "content": "\"use client\";\n\nimport { Progress as BaseProgress } from \"@base-ui/react/progress\";\nimport { AnimatePresence, motion, useInView } from \"motion/react\";\nimport { useRef, type ReactNode } from \"react\";\nimport { NumberRoll } from \"../_primitives/number-roll/number-roll\";\nimport { enter, exit, instant, reducedFade, smooth, useSafeReducedMotion } from \"../lib/motion\";\n\nexport type ProgressProps = {\n  /** Current value, from `min` to `max`. `null` is indeterminate: the length of the task is unknown. */\n  value: number | null;\n  min?: number;\n  max?: number;\n  /** Visible label, also the progressbar's accessible name. Without one, pass `aria-label`. */\n  label?: ReactNode;\n  \"aria-label\"?: string;\n  /** Show the rolling value on the right of the label row. Default true; hidden while indeterminate. */\n  showValue?: boolean;\n  /** Formats the value, e.g. `{ style: \"unit\", unit: \"megabyte\" }`. Default: the percentage. */\n  format?: Intl.NumberFormatOptions;\n  locale?: Intl.LocalesArgument;\n  /** Spoken value, e.g. `(formatted) => \\`${formatted} uploaded\\``. */\n  getAriaValueText?: (formattedValue: string, value: number | null) => string;\n  /** Track thickness: 4px (`sm`) or 6px (`md`). Default `md`. */\n  size?: \"sm\" | \"md\";\n  /** Turn the bar success-green when it reaches `max`. Default true. */\n  successOnComplete?: boolean;\n  className?: string;\n};\n\nconst TRACK = { sm: \"h-1\", md: \"h-1.5\" } as const;\n\n/**\n * A progress bar on Base UI's Progress. The determinate bar rides a spring (no overshoot, so it\n * never reads past the real value) and its value rolls; an unknown length sweeps with an\n * accelerate–decelerate curve, then hands over to the bar the moment a value arrives.\n */\nexport function Progress({\n  value,\n  min = 0,\n  max = 100,\n  label,\n  \"aria-label\": ariaLabel,\n  showValue = true,\n  format,\n  locale,\n  getAriaValueText,\n  size = \"md\",\n  successOnComplete = true,\n  className = \"\",\n}: ProgressProps) {\n  const reduced = useSafeReducedMotion();\n  const track = useRef<HTMLDivElement>(null);\n  const inView = useInView(track);\n  const known = value != null && Number.isFinite(value);\n  const clamped = known ? Math.min(max, Math.max(min, value)) : min;\n  const fraction = max > min ? (clamped - min) / (max - min) : 0;\n  const complete = known && clamped === max;\n\n  return (\n    <BaseProgress.Root\n      value={value}\n      min={min}\n      max={max}\n      format={format}\n      locale={locale}\n      getAriaValueText={getAriaValueText}\n      aria-label={label ? undefined : ariaLabel}\n      className={`flex w-full min-w-0 flex-col gap-2 ${className}`}\n    >\n      {(label || (showValue && known)) && (\n        <div className=\"flex min-w-0 items-baseline justify-between gap-3 text-ui-sm\">\n          {label ? <BaseProgress.Label className=\"min-w-0 truncate text-text-secondary\">{label}</BaseProgress.Label> : <span />}\n          {showValue && (\n            <span className=\"shrink-0 text-text-muted tabular-nums\">\n              <AnimatePresence initial={false}>\n                {known && (\n                  <motion.span\n                    className=\"inline-block\"\n                    initial={{ opacity: 0 }}\n                    animate={{ opacity: 1, transition: reduced ? reducedFade : enter }}\n                    exit={{ opacity: 0, transition: reduced ? reducedFade : exit }}\n                  >\n                    <NumberRoll\n                      aria-hidden\n                      value={format ? clamped : fraction}\n                      locale={locale}\n                      format={format ?? { style: \"percent\", maximumFractionDigits: 0 }}\n                    />\n                  </motion.span>\n                )}\n              </AnimatePresence>\n            </span>\n          )}\n        </div>\n      )}\n\n      <BaseProgress.Track\n        ref={track}\n        className={`relative w-full overflow-clip rounded-pill bg-surface-sunken inset-shadow-well ${TRACK[size]}`}\n      >\n        {/* Determinate: a full-width bar slid in from the left, so its rounded end never squashes. */}\n        <motion.div\n          className={`absolute inset-0 rounded-pill transition-colors duration-150 ease-standard ${\n            complete && successOnComplete ? \"bg-success\" : \"bg-brand\"\n          }`}\n          initial={false}\n          animate={{ x: `${(fraction - 1) * 100}%`, opacity: known ? 1 : 0 }}\n          transition={reduced ? instant : { ...smooth, opacity: known ? enter : exit }}\n        />\n        {/* Indeterminate: a 40% segment that accelerates in and decelerates out, then repeats. */}\n        <AnimatePresence initial={false}>\n          {!known && (\n            <motion.div\n              key=\"sweep\"\n              className=\"absolute inset-y-0 left-0 w-2/5 animate-[eased-progress-sweep_1600ms_var(--eased-ease-in-out)_infinite] rounded-pill bg-brand reduced:w-full reduced:animate-none\"\n              style={{ animationPlayState: inView ? \"running\" : \"paused\" }}\n              initial={{ opacity: 0 }}\n              animate={{ opacity: reduced ? 0.4 : 1, transition: reduced ? reducedFade : enter }}\n              exit={{ opacity: 0, transition: reduced ? reducedFade : exit }}\n            />\n          )}\n        </AnimatePresence>\n        <style href=\"eased-progress\" precedence=\"default\">\n          {\"@keyframes eased-progress-sweep { from { translate: -100% 0; } to { translate: 250% 0; } }\"}\n        </style>\n      </BaseProgress.Track>\n    </BaseProgress.Root>\n  );\n}\n",
      "type": "registry:ui",
      "target": "@components/eased/progress/progress.tsx"
    }
  ],
  "docs": "Import Progress from components/eased/progress/progress. The Eased tokens were merged into your global CSS; nothing to import. Dark mode follows .dark or data-theme=\"dark\".",
  "type": "registry:ui"
}