{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "progress-summary",
  "title": "Progress Summary",
  "description": "Progress, elapsed time, remaining work, and cancellation in one composable summary.",
  "dependencies": [
    "class-variance-authority"
  ],
  "registryDependencies": [
    "button",
    "progress",
    "https://uaiblocks.dev/r/uai-theme.json",
    "https://uaiblocks.dev/r/uai-utils.json"
  ],
  "files": [
    {
      "path": "src/registry/uai/components/progress-summary.tsx",
      "content": "\"use client\";\n\nimport { cva } from \"class-variance-authority\";\nimport { type ComponentProps, createContext, useContext, useId } from \"react\";\nimport { Button } from \"@/components/ui/button\";\nimport { Progress } from \"@/components/ui/progress\";\nimport { cn } from \"@/lib/uai-utils\";\n\nexport const PROGRESS_SUMMARY_VARIANTS = [\"card\", \"inline\", \"compact\"] as const;\nexport type ProgressSummaryVariant = (typeof PROGRESS_SUMMARY_VARIANTS)[number];\nexport type ProgressSummaryStatus = \"running\" | \"paused\" | \"complete\" | \"cancelled\" | \"error\";\nexport type ProgressSummaryProps = ComponentProps<\"section\"> & {\n  variant?: ProgressSummaryVariant;\n  /** Completed units. Omit for indeterminate progress. */\n  value?: number;\n  max?: number;\n  status?: ProgressSummaryStatus;\n};\ntype SummaryContext = {\n  id: string;\n  variant: ProgressSummaryVariant;\n  value?: number;\n  max: number;\n  percent?: number;\n  status: ProgressSummaryStatus;\n};\nconst Context = createContext<SummaryContext | null>(null);\nfunction useSummary(part: string) {\n  const context = useContext(Context);\n  if (!context) throw new Error(`${part} must be used within ProgressSummary`);\n  return context;\n}\nconst statusCopy: Record<ProgressSummaryStatus, string> = {\n  running: \"In progress\",\n  paused: \"Paused\",\n  complete: \"Complete\",\n  cancelled: \"Cancelled\",\n  error: \"Failed\",\n};\nconst progressSummaryVariants = cva(\n  \"grid min-w-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-x-3 text-[13px]/[18px] text-foreground\",\n  {\n    variants: {\n      variant: {\n        card: \"gap-y-3.5 rounded-[14px] border bg-card p-4.5\",\n        inline: \"gap-y-3.5 rounded-[14px] border-0 bg-transparent p-0\",\n        compact: \"gap-y-2 rounded-xl border bg-card px-3 py-2.5\",\n      },\n    },\n  },\n);\nconst statusTextClass: Record<ProgressSummaryStatus, string> = {\n  running: \"shimmer-text motion-reduce:text-muted-foreground\",\n  paused: \"text-subtle-foreground\",\n  complete: \"text-success-ink\",\n  cancelled: \"text-subtle-foreground\",\n  error: \"text-destructive-ink\",\n};\nconst fillClass: Record<ProgressSummaryStatus, string> = {\n  running:\n    \"*:data-[slot=progress-indicator]:bg-primary *:data-[slot=progress-indicator]:opacity-100\",\n  paused:\n    \"*:data-[slot=progress-indicator]:bg-muted-foreground *:data-[slot=progress-indicator]:opacity-50\",\n  complete:\n    \"*:data-[slot=progress-indicator]:bg-success *:data-[slot=progress-indicator]:opacity-100\",\n  cancelled:\n    \"*:data-[slot=progress-indicator]:bg-muted-foreground *:data-[slot=progress-indicator]:opacity-50\",\n  error:\n    \"*:data-[slot=progress-indicator]:bg-destructive *:data-[slot=progress-indicator]:opacity-100\",\n};\n\nexport function ProgressSummary({\n  variant = \"card\",\n  value,\n  max = 100,\n  status = \"running\",\n  children,\n  className,\n  ...props\n}: ProgressSummaryProps) {\n  const id = useId();\n  const clamped = value === undefined ? undefined : Math.min(Math.max(value, 0), max);\n  const percent =\n    clamped === undefined ? undefined : Math.round((clamped / Math.max(max, 1)) * 100);\n  return (\n    <Context.Provider value={{ id, variant, value: clamped, max, percent, status }}>\n      <section\n        aria-labelledby={`${id}-title`}\n        data-slot=\"progress-summary\"\n        className={cn(progressSummaryVariants({ variant }), className)}\n        {...props}\n        data-variant={variant}\n        data-status={status}\n      >\n        {children}\n      </section>\n    </Context.Provider>\n  );\n}\n\nexport function ProgressSummaryHeader({ className, ...props }: ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"progress-summary-header\"\n      className={cn(\"grid min-w-0 gap-0.5\", className)}\n      {...props}\n    />\n  );\n}\n\nexport function ProgressSummaryTitle({ className, ...props }: ComponentProps<\"h3\">) {\n  const context = useSummary(\"ProgressSummaryTitle\");\n  return (\n    <h3\n      data-slot=\"progress-summary-title\"\n      className={cn(\"m-0 text-[13px]/[18px] font-medium wrap-anywhere\", className)}\n      {...props}\n      id={`${context.id}-title`}\n    />\n  );\n}\n\nexport function ProgressSummaryStatusText({ children, className, ...props }: ComponentProps<\"p\">) {\n  const context = useSummary(\"ProgressSummaryStatusText\");\n  return (\n    <p\n      role=\"status\"\n      data-slot=\"progress-summary-status-text\"\n      className={cn(\n        \"m-0 justify-self-start text-xs/4 tabular-nums\",\n        statusTextClass[context.status],\n        className,\n      )}\n      {...props}\n    >\n      {children ?? statusCopy[context.status]}\n    </p>\n  );\n}\n\nexport function ProgressSummaryValue({ children, className, ...props }: ComponentProps<\"span\">) {\n  const context = useSummary(\"ProgressSummaryValue\");\n  return (\n    <span\n      aria-hidden=\"true\"\n      data-slot=\"progress-summary-value\"\n      className={cn(\n        \"justify-self-end tabular-nums\",\n        context.variant === \"compact\"\n          ? \"text-[13px]/[18px] font-medium\"\n          : \"text-[22px]/[26px] font-semibold tracking-[-0.02em]\",\n        className,\n      )}\n      {...props}\n    >\n      {children ?? (context.percent === undefined ? \"—\" : `${context.percent}%`)}\n    </span>\n  );\n}\n\nexport function ProgressSummaryBar({\n  \"aria-valuetext\": valueText,\n  className,\n  ...props\n}: ComponentProps<\"div\">) {\n  const context = useSummary(\"ProgressSummaryBar\");\n  const indeterminate = context.percent === undefined;\n  return (\n    <Progress\n      aria-labelledby={`${context.id}-title`}\n      aria-valuemax={context.max}\n      aria-valuenow={context.value}\n      aria-valuetext={\n        valueText ??\n        (context.percent === undefined\n          ? statusCopy[context.status]\n          : `${context.percent}% · ${statusCopy[context.status]}`)\n      }\n      data-slot=\"progress-summary-bar\"\n      data-indeterminate={indeterminate || undefined}\n      value={context.percent ?? null}\n      className={cn(\n        \"col-span-full bg-muted\",\n        \"*:data-[slot=progress-indicator]:rounded-full *:data-[slot=progress-indicator]:[transition:transform_300ms_cubic-bezier(0.23,1,0.32,1),background-color_200ms_ease-out,opacity_200ms_ease-out] motion-reduce:*:data-[slot=progress-indicator]:transition-none\",\n        \"data-indeterminate:*:data-[slot=progress-indicator]:w-[35%] data-indeterminate:*:data-[slot=progress-indicator]:animate-indeterminate motion-reduce:data-indeterminate:*:data-[slot=progress-indicator]:animate-none motion-reduce:data-indeterminate:*:data-[slot=progress-indicator]:transform-none!\",\n        fillClass[context.status],\n        context.variant === \"compact\" ? \"h-1\" : \"h-1.5\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nexport function ProgressSummaryStats({ className, ...props }: ComponentProps<\"dl\">) {\n  const context = useSummary(\"ProgressSummaryStats\");\n  return (\n    <dl\n      data-slot=\"progress-summary-stats\"\n      className={cn(\n        \"col-span-full m-0\",\n        context.variant === \"compact\"\n          ? \"flex flex-wrap gap-x-3.5 gap-y-1\"\n          : \"grid grid-cols-[repeat(auto-fit,minmax(96px,1fr))] gap-3\",\n        context.variant === \"card\" ? \"pt-0.5\" : \"pt-0\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nexport function ProgressSummaryStat({ className, ...props }: ComponentProps<\"div\">) {\n  const context = useSummary(\"ProgressSummaryStat\");\n  return (\n    <div\n      data-slot=\"progress-summary-stat\"\n      className={cn(\n        \"min-w-0 items-baseline\",\n        context.variant === \"compact\" ? \"flex gap-1\" : \"grid gap-0.5\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nexport function ProgressSummaryStatLabel({ className, ...props }: ComponentProps<\"dt\">) {\n  return (\n    <dt\n      data-slot=\"progress-summary-stat-label\"\n      className={cn(\"text-[11.5px]/4 text-subtle-foreground\", className)}\n      {...props}\n    />\n  );\n}\n\nexport function ProgressSummaryStatValue({ className, ...props }: ComponentProps<\"dd\">) {\n  return (\n    <dd\n      data-slot=\"progress-summary-stat-value\"\n      className={cn(\"m-0 font-medium tabular-nums\", className)}\n      {...props}\n    />\n  );\n}\n\nexport function ProgressSummaryActions({ className, ...props }: ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"progress-summary-actions\"\n      className={cn(\"col-span-full flex flex-wrap justify-end gap-1.5\", className)}\n      {...props}\n    />\n  );\n}\n\nexport function ProgressSummaryCancel({\n  children = \"Cancel\",\n  disabled,\n  className,\n  ...props\n}: ComponentProps<\"button\">) {\n  const context = useSummary(\"ProgressSummaryCancel\");\n  const finished = context.status !== \"running\" && context.status !== \"paused\";\n  return (\n    <Button\n      data-slot=\"progress-summary-cancel\"\n      variant=\"secondary\"\n      className={cn(\n        \"cursor-pointer rounded-full py-0 text-foreground [transition:background-color_120ms_ease-out,scale_140ms_cubic-bezier(0.23,1,0.32,1)] hover:bg-[color-mix(in_oklab,var(--secondary)_85%,var(--foreground))] not-disabled:active:scale-[0.97] focus-visible:ring-0 focus-visible:outline-2 focus-visible:outline-solid focus-visible:outline-offset-2 focus-visible:outline-ring disabled:cursor-not-allowed disabled:text-subtle-foreground disabled:opacity-100 motion-reduce:transition-none\",\n        context.variant === \"compact\"\n          ? \"h-6 px-2.5 text-xs/4 has-[>svg]:px-2.5\"\n          : \"h-7 px-3 text-[12.5px]/4 has-[>svg]:px-3\",\n        className,\n      )}\n      {...props}\n      type=\"button\"\n      disabled={disabled ?? finished}\n    >\n      {children}\n    </Button>\n  );\n}\n",
      "type": "registry:ui",
      "target": "@ui/uai/progress-summary.tsx"
    }
  ],
  "categories": [
    "feedback",
    "progress"
  ],
  "type": "registry:ui"
}