{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "task-list",
  "title": "Task List",
  "description": "A composable progress list with card, timeline, and compact variants.",
  "dependencies": [
    "class-variance-authority",
    "lucide-react"
  ],
  "registryDependencies": [
    "badge",
    "https://uaiblocks.dev/r/uai-theme.json",
    "https://uaiblocks.dev/r/uai-utils.json"
  ],
  "files": [
    {
      "path": "src/registry/uai/components/task-list.tsx",
      "content": "\"use client\";\n\nimport { cva } from \"class-variance-authority\";\nimport { Check, Circle, LoaderCircle } from \"lucide-react\";\nimport { type ComponentProps, createContext, type ReactNode, useContext } from \"react\";\n\nimport { Badge } from \"@/components/ui/badge\";\nimport { cn } from \"@/lib/uai-utils\";\n\nexport const TASK_LIST_VARIANTS = [\"card\", \"timeline\", \"compact\"] as const;\nexport const TASK_LIST_STATUSES = [\"complete\", \"active\", \"pending\"] as const;\n\nexport type TaskListVariant = (typeof TASK_LIST_VARIANTS)[number];\nexport type TaskStatus = (typeof TASK_LIST_STATUSES)[number];\n\nconst statusCopy: Record<TaskStatus, string> = {\n  complete: \"Complete\",\n  active: \"In progress\",\n  pending: \"Pending\",\n};\n\nconst statusIcons: Record<TaskStatus, typeof Check> = {\n  complete: Check,\n  active: LoaderCircle,\n  pending: Circle,\n};\n\nconst taskListVariants = cva(\"m-0 w-full list-none p-0 text-foreground\", {\n  variants: {\n    variant: {\n      card: \"rounded-[14px]\",\n      timeline: \"grid rounded-none bg-transparent\",\n      compact: \"rounded-xl\",\n    },\n  },\n  compoundVariants: [\n    {\n      variant: [\"card\", \"compact\"],\n      className: \"divide-y divide-border overflow-hidden border bg-card\",\n    },\n  ],\n});\n\nconst taskListItemVariants = cva(\n  \"animate-in duration-240 ease-out-quint fill-mode-backwards fade-in-0 slide-in-from-bottom-1 nth-2:[animation-delay:40ms] nth-3:[animation-delay:80ms] nth-4:[animation-delay:120ms] nth-5:[animation-delay:160ms] nth-6:[animation-delay:200ms] motion-reduce:animate-none [&:last-child>span:first-child]:hidden\",\n  {\n    variants: {\n      variant: {\n        card: \"grid min-h-16 grid-cols-[24px_minmax(0,1fr)_auto] items-center gap-3 px-4 py-3\",\n        timeline:\n          \"relative grid grid-cols-[24px_minmax(0,1fr)_auto] items-start gap-x-3 pb-6 last:pb-0\",\n        compact: \"grid min-h-12 grid-cols-[20px_minmax(0,1fr)_auto] items-center gap-2.5 px-3 py-2\",\n      },\n    },\n  },\n);\n\nconst taskListMarkerVariants = cva(\n  \"relative z-10 inline-flex shrink-0 items-center justify-center rounded-full border transition-colors duration-200\",\n  {\n    variants: {\n      status: {\n        complete: \"border-transparent bg-success/16 text-success-ink\",\n        active: \"border-transparent bg-muted text-foreground\",\n        pending: \"border-dashed border-subtle-foreground/70 bg-transparent text-transparent\",\n      },\n    },\n  },\n);\n\nconst taskListStatusVariants = cva(\n  \"shrink-0 gap-0 rounded-full border-0 py-0 font-medium whitespace-nowrap tabular-nums\",\n  {\n    variants: {\n      status: {\n        complete: \"bg-success/14 text-success-ink\",\n        active: \"bg-muted text-foreground\",\n        pending: \"bg-transparent text-subtle-foreground\",\n      },\n    },\n  },\n);\n\ntype TaskListContextValue = { variant: TaskListVariant };\n\nconst TaskListContext = createContext<TaskListContextValue | null>(null);\n\nfunction useTaskList(name: string) {\n  const context = useContext(TaskListContext);\n  if (!context) throw new Error(`${name} must be used within TaskList`);\n  return context;\n}\n\nexport type TaskListProps = ComponentProps<\"ol\"> & {\n  variant?: TaskListVariant;\n};\n\nexport function TaskList({ variant = \"card\", className, children, ...props }: TaskListProps) {\n  return (\n    <TaskListContext.Provider value={{ variant }}>\n      <ol\n        data-slot=\"task-list\"\n        data-variant={variant}\n        className={cn(taskListVariants({ variant }), className)}\n        {...props}\n      >\n        {children}\n      </ol>\n    </TaskListContext.Provider>\n  );\n}\n\nexport type TaskListItemProps = ComponentProps<\"li\"> & {\n  status: TaskStatus;\n  statusLabel?: ReactNode;\n};\n\nexport function TaskListItem({\n  status,\n  statusLabel,\n  className,\n  children,\n  \"aria-current\": ariaCurrent,\n  ...props\n}: TaskListItemProps) {\n  const { variant } = useTaskList(\"TaskListItem\");\n  const StatusIcon = statusIcons[status];\n  const compact = variant === \"compact\";\n  const timeline = variant === \"timeline\";\n\n  return (\n    <li\n      data-slot=\"task-list-item\"\n      data-status={status}\n      aria-current={ariaCurrent ?? (status === \"active\" ? \"step\" : undefined)}\n      className={cn(taskListItemVariants({ variant }), className)}\n      {...props}\n    >\n      <span\n        className={\n          timeline ? \"absolute top-8 bottom-1 left-[11.5px] block w-px bg-border\" : \"hidden\"\n        }\n        aria-hidden=\"true\"\n      />\n      <span\n        className={cn(taskListMarkerVariants({ status }), compact ? \"size-5\" : \"size-6\")}\n        aria-hidden=\"true\"\n      >\n        <StatusIcon\n          key={status}\n          strokeWidth={status === \"complete\" ? 2.5 : 2}\n          className={cn(\n            compact ? \"size-3\" : \"size-3.5\",\n            status === \"active\" && \"motion-safe:animate-spin\",\n            status === \"complete\" &&\n              \"animate-in duration-200 ease-out-quint fade-in-0 zoom-in-50 motion-reduce:animate-none\",\n          )}\n        />\n      </span>\n      <span className={timeline ? \"min-w-0 pt-0.75\" : \"min-w-0\"}>{children}</span>\n      <Badge\n        variant=\"secondary\"\n        className={cn(\n          taskListStatusVariants({ status }),\n          compact ? \"min-h-5 px-1.5 text-[11px]/4\" : \"min-h-5.5 px-2 text-[11.5px]/4\",\n        )}\n      >\n        {status === \"active\" ? (\n          <span className=\"shimmer-text\">{statusLabel ?? statusCopy[status]}</span>\n        ) : (\n          (statusLabel ?? statusCopy[status])\n        )}\n      </Badge>\n    </li>\n  );\n}\n\nexport type TaskListTitleProps = ComponentProps<\"span\"> & { children: ReactNode };\n\nexport function TaskListTitle({ className, children, ...props }: TaskListTitleProps) {\n  const { variant } = useTaskList(\"TaskListTitle\");\n\n  return (\n    <span\n      data-slot=\"task-list-title\"\n      className={cn(\n        \"block font-medium wrap-anywhere in-data-[status=pending]:text-muted-foreground\",\n        variant === \"compact\" ? \"text-[12.5px]/[17px]\" : \"text-[13px]/[18px]\",\n        className,\n      )}\n      {...props}\n    >\n      {children}\n    </span>\n  );\n}\n\nexport type TaskListDescriptionProps = ComponentProps<\"span\"> & { children: ReactNode };\n\nexport function TaskListDescription({ className, children, ...props }: TaskListDescriptionProps) {\n  const { variant } = useTaskList(\"TaskListDescription\");\n\n  return (\n    <span\n      data-slot=\"task-list-description\"\n      className={cn(\n        \"block text-subtle-foreground wrap-anywhere\",\n        variant === \"compact\" ? \"mt-px text-[11.5px]/4\" : \"mt-0.5 text-xs/[17px]\",\n        className,\n      )}\n      {...props}\n    >\n      {children}\n    </span>\n  );\n}\n",
      "type": "registry:ui",
      "target": "@ui/uai/task-list.tsx"
    }
  ],
  "categories": [
    "ai",
    "data-display"
  ],
  "type": "registry:ui"
}