{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "progress",
  "title": "Progress",
  "author": "AniBT <https://anibt.net>",
  "description": "AniBT progress bar: a sunk track with a glossy water (in progress), candy (your goal) or mint (done) fill, an indeterminate slide, and Base UI's label / value row.",
  "dependencies": [
    "class-variance-authority",
    "radix-ui"
  ],
  "registryDependencies": [
    "@anibt/theme"
  ],
  "files": [
    {
      "path": "registry/anibt/ui/progress.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { Progress as ProgressPrimitive } from \"radix-ui\"\n\nimport { cn } from \"@/lib/utils\"\n\n/**\n * Progress — the AniBT 「贴纸手账」 bar.\n *\n * A sunk track with a 1px edge and a glossy fill. Blue is A's colour for\n * \"in progress\", so the fill is `water` by default; `tone=\"candy\"` is for a\n * quota or a goal the reader is filling (pink = the reader's own action) and\n * `tone=\"ok\"` for work that is done. `value={null}` is indeterminate: a short\n * fill slides along the track (it holds still under reduced motion).\n *\n * `<Progress value={40} />` is shadcn's shape. Children turn it into Base UI's\n * shape — a label and a figure above the track:\n *\n *   <Progress value={3} max={5}>\n *     <ProgressLabel>同步目标</ProgressLabel>\n *     <ProgressValue />            → 3 / 5 (or a percentage, see `format`)\n *   </Progress>\n */\nconst trackVariants = cva(\n  \"relative w-full overflow-hidden rounded-full bg-muted shadow-[inset_0_0_0_1px_var(--border)]\",\n  {\n    variants: {\n      size: {\n        default: \"h-2.5\",\n        compact: \"h-1.5\",\n        lg: \"h-3.5\",\n      },\n    },\n    defaultVariants: {\n      size: \"default\",\n    },\n  }\n)\n\nconst indicatorVariants = cva(\n  \"h-full w-full rounded-full transition-transform duration-500 ease-anibt-out motion-reduce:transition-none\",\n  {\n    variants: {\n      tone: {\n        water: \"anibt-water shadow-[inset_0_1px_0_rgba(255,255,255,0.45)]\",\n        candy: \"anibt-candy shadow-[inset_0_1px_0_rgba(255,255,255,0.45)]\",\n        ok: \"bg-anibt-ok-fill shadow-[inset_0_1px_0_rgba(255,255,255,0.35)]\",\n      },\n    },\n    defaultVariants: {\n      tone: \"water\",\n    },\n  }\n)\n\ntype ProgressContextValue = { value: number | null; max: number }\n\nconst ProgressContext = React.createContext<ProgressContextValue>({ value: null, max: 100 })\n\ntype ProgressProps = Omit<React.ComponentProps<typeof ProgressPrimitive.Root>, \"value\" | \"max\"> &\n  VariantProps<typeof trackVariants> &\n  VariantProps<typeof indicatorVariants> & {\n    /** `null` (or leaving it out) is indeterminate. */\n    value?: number | null\n    max?: number\n    /** Classes for the track when the progress has children (label row). */\n    trackClassName?: string\n  }\n\nfunction Progress({\n  className,\n  trackClassName,\n  value = null,\n  max = 100,\n  size,\n  tone,\n  children,\n  ...props\n}: ProgressProps) {\n  const track = (\n    <ProgressPrimitive.Root\n      data-slot=\"progress\"\n      data-tone={tone ?? \"water\"}\n      value={value}\n      max={max}\n      className={cn(trackVariants({ size }), children ? trackClassName : className)}\n      {...props}\n    >\n      <ProgressIndicator tone={tone} />\n    </ProgressPrimitive.Root>\n  )\n\n  if (!children) {\n    return <ProgressContext.Provider value={{ value, max }}>{track}</ProgressContext.Provider>\n  }\n\n  return (\n    <ProgressContext.Provider value={{ value, max }}>\n      <div data-slot=\"progress-group\" className={cn(\"flex w-full flex-wrap items-baseline gap-x-3 gap-y-1.5\", className)}>\n        {children}\n        {track}\n      </div>\n    </ProgressContext.Provider>\n  )\n}\n\n/** The fill. Rendered by `Progress`; exported for shadcn parity. */\nfunction ProgressIndicator({\n  className,\n  tone,\n  style,\n  ...props\n}: React.ComponentProps<typeof ProgressPrimitive.Indicator> & VariantProps<typeof indicatorVariants>) {\n  const { value, max } = React.useContext(ProgressContext)\n  const indeterminate = value === null\n  const percent = indeterminate ? 0 : Math.min(100, Math.max(0, (value / max) * 100))\n\n  return (\n    <ProgressPrimitive.Indicator\n      data-slot=\"progress-indicator\"\n      className={cn(\n        indicatorVariants({ tone }),\n        indeterminate && \"w-2/5 animate-anibt-indeterminate motion-reduce:animate-none\",\n        className\n      )}\n      style={indeterminate ? style : { transform: `translateX(-${100 - percent}%)`, ...style }}\n      {...props}\n    />\n  )\n}\n\n/** The track on its own, for a hand-built layout (shadcn `base-*` parity). */\nfunction ProgressTrack({ className, size, ...props }: React.ComponentProps<\"div\"> & VariantProps<typeof trackVariants>) {\n  return <div data-slot=\"progress-track\" className={cn(trackVariants({ size }), className)} {...props} />\n}\n\n/** What is progressing: 13/600, the field-label voice. */\nfunction ProgressLabel({ className, ...props }: React.ComponentProps<\"span\">) {\n  return (\n    <span\n      data-slot=\"progress-label\"\n      className={cn(\"text-[13px] font-semibold text-anibt-ink2\", className)}\n      {...props}\n    />\n  )\n}\n\n/**\n * The figure at the right end of the label row, in the round face. Without\n * children it prints the value: `3 / 5`, or `60%` when `max` is 100 or\n * `format=\"percent\"`.\n */\nfunction ProgressValue({\n  className,\n  children,\n  format,\n  ...props\n}: React.ComponentProps<\"span\"> & { format?: \"fraction\" | \"percent\" }) {\n  const { value, max } = React.useContext(ProgressContext)\n  const asPercent = format ? format === \"percent\" : max === 100\n  const text =\n    value === null ? \"—\" : asPercent ? `${Math.round((value / max) * 100)}%` : `${value} / ${max}`\n  return (\n    <span\n      data-slot=\"progress-value\"\n      className={cn(\"anibt-num ml-auto text-[12px] font-semibold text-muted-foreground\", className)}\n      {...props}\n    >\n      {children ?? text}\n    </span>\n  )\n}\n\nexport { Progress, ProgressIndicator, ProgressTrack, ProgressLabel, ProgressValue }\nexport type { ProgressProps }\n",
      "type": "registry:ui"
    }
  ],
  "categories": [
    "feedback"
  ],
  "type": "registry:ui"
}