{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "progress",
  "title": "Progress",
  "description": "A thin bar with an optional label and value.",
  "dependencies": [
    "@base-ui/react"
  ],
  "registryDependencies": [
    "https://ui.ndekocode.dev/r/theme.json",
    "https://ui.ndekocode.dev/r/utils.json"
  ],
  "files": [
    {
      "path": "registry/ndeko/ui/progress.tsx",
      "content": "'use client';\n\nimport { Progress as ProgressPrimitive } from '@base-ui/react/progress';\n\nimport { cn } from '@/registry/ndeko/lib/utils';\n\ntype WithClassName<Props> = Omit<Props, 'className'> & { className?: string };\n\nconst DEFAULT_MIN = 0;\nconst DEFAULT_MAX = 100;\n\nconst FILL = [\n  'bg-primary h-full rounded-full',\n  '-translate-x-(--progress-remaining) rtl:translate-x-(--progress-remaining)',\n  'transition-[translate] duration-500 ease-(--ease-out-strong)',\n  'data-indeterminate:w-1/3 data-indeterminate:translate-x-0 data-indeterminate:animate-pulse',\n].join(' ');\n\nfunction remainingShareOf(value: number, min: number, max: number) {\n  const span = max - min;\n  const hasRange = span > 0;\n  if (!hasRange) {\n    return 0;\n  }\n  const share = ((value - min) * 100) / span;\n  const boundedShare = Math.min(100, Math.max(0, share));\n  return 100 - boundedShare;\n}\n\nfunction isMeasurable(value: number | null | undefined): value is number {\n  return Number.isFinite(value);\n}\n\n/** Moves a full-width fill instead of resizing it, so the fill travels on the compositor. */\nfunction fillStyleOf(\n  value: number | null | undefined,\n  min: number,\n  max: number\n): React.CSSProperties | undefined {\n  if (!isMeasurable(value)) {\n    return undefined;\n  }\n  const remainingShare = remainingShareOf(value, min, max);\n  return {\n    width: '100%',\n    '--progress-remaining': `${remainingShare}%`,\n  } as React.CSSProperties;\n}\n\nfunction Progress({\n  className,\n  children,\n  value,\n  min = DEFAULT_MIN,\n  max = DEFAULT_MAX,\n  ...props\n}: WithClassName<ProgressPrimitive.Root.Props>) {\n  const fillStyle = fillStyleOf(value, min, max);\n\n  return (\n    <ProgressPrimitive.Root\n      data-slot='progress'\n      value={value}\n      min={min}\n      max={max}\n      className={cn('flex w-full flex-col gap-2', className)}\n      {...props}\n    >\n      {children}\n      <ProgressPrimitive.Track className='bg-foreground/10 h-1.5 w-full overflow-hidden rounded-full'>\n        <ProgressPrimitive.Indicator className={FILL} style={fillStyle} />\n      </ProgressPrimitive.Track>\n    </ProgressPrimitive.Root>\n  );\n}\n\nfunction ProgressLabel({\n  className,\n  ...props\n}: WithClassName<ProgressPrimitive.Label.Props>) {\n  return (\n    <ProgressPrimitive.Label\n      data-slot='progress-label'\n      className={cn('text-[13px] font-medium', className)}\n      {...props}\n    />\n  );\n}\n\nfunction ProgressValue({\n  className,\n  ...props\n}: WithClassName<ProgressPrimitive.Value.Props>) {\n  return (\n    <ProgressPrimitive.Value\n      data-slot='progress-value'\n      className={cn('text-muted-foreground text-xs tabular-nums', className)}\n      {...props}\n    />\n  );\n}\n\nexport { Progress, ProgressLabel, ProgressValue };\n",
      "type": "registry:ui"
    }
  ],
  "categories": [
    "primitives"
  ],
  "type": "registry:ui"
}