{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "chain-of-thought",
  "title": "AI Chain of Thought",
  "description": "Visualize AI reasoning steps with search results and images for step-by-step thinking display.",
  "dependencies": [
    "@radix-ui/react-collapsible",
    "lucide-react"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "registry/default/blocks/ai/ai-chain-of-thought/components/elements/ai-chain-of-thought.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\n\nimport * as CollapsiblePrimitive from \"@radix-ui/react-collapsible\";\nimport {\n  CheckCircle2,\n  ChevronDown,\n  Circle,\n  ExternalLink,\n  Image as ImageIcon,\n  Lightbulb,\n  Loader2,\n  Search,\n} from \"lucide-react\";\n\nimport { cn } from \"@/lib/utils\";\n\ntype StepStatus = \"pending\" | \"active\" | \"complete\";\n\ninterface AiChainOfThoughtContextValue {\n  isOpen: boolean;\n}\n\nconst AiChainOfThoughtContext =\n  React.createContext<AiChainOfThoughtContextValue | null>(null);\n\nfunction useChainOfThoughtContext() {\n  const context = React.useContext(AiChainOfThoughtContext);\n  if (!context) {\n    throw new Error(\n      \"AiChainOfThought components must be used within <AiChainOfThought>\",\n    );\n  }\n  return context;\n}\n\ninterface AiChainOfThoughtProps {\n  defaultOpen?: boolean;\n  open?: boolean;\n  onOpenChange?: (open: boolean) => void;\n  children?: React.ReactNode;\n  className?: string;\n}\n\nfunction AiChainOfThought({\n  defaultOpen = true,\n  open: controlledOpen,\n  onOpenChange,\n  children,\n  className,\n}: AiChainOfThoughtProps) {\n  const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen);\n\n  const isControlled = controlledOpen !== undefined;\n  const isOpen = isControlled ? controlledOpen : uncontrolledOpen;\n\n  const handleOpenChange = React.useCallback(\n    (open: boolean) => {\n      if (!isControlled) {\n        setUncontrolledOpen(open);\n      }\n      onOpenChange?.(open);\n    },\n    [isControlled, onOpenChange],\n  );\n\n  const contextValue = React.useMemo(() => ({ isOpen }), [isOpen]);\n\n  return (\n    <AiChainOfThoughtContext.Provider value={contextValue}>\n      <CollapsiblePrimitive.Root\n        data-slot=\"ai-chain-of-thought\"\n        open={isOpen}\n        onOpenChange={handleOpenChange}\n        className={cn(\n          \"rounded-lg border border-border bg-card text-card-foreground overflow-hidden\",\n          className,\n        )}\n      >\n        {children}\n      </CollapsiblePrimitive.Root>\n    </AiChainOfThoughtContext.Provider>\n  );\n}\n\ninterface AiChainOfThoughtHeaderProps {\n  title?: string;\n  stepCount?: number;\n  completedCount?: number;\n  children?: React.ReactNode;\n  className?: string;\n}\n\nfunction AiChainOfThoughtHeader({\n  title = \"Chain of Thought\",\n  stepCount,\n  completedCount,\n  children,\n  className,\n}: AiChainOfThoughtHeaderProps) {\n  const { isOpen } = useChainOfThoughtContext();\n\n  return (\n    <CollapsiblePrimitive.Trigger\n      data-slot=\"ai-chain-of-thought-header\"\n      className={cn(\n        \"flex w-full items-center gap-3 px-4 py-3 text-sm font-medium transition-colors hover:bg-muted/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\",\n        className,\n      )}\n    >\n      <div className=\"flex size-8 shrink-0 items-center justify-center rounded-md bg-amber-100 dark:bg-amber-950\">\n        <Lightbulb className=\"size-4 text-amber-600 dark:text-amber-400\" />\n      </div>\n      <div className=\"flex flex-1 items-center gap-2 text-left\">\n        <span className=\"font-medium\">{title}</span>\n        {stepCount !== undefined && (\n          <span className=\"inline-flex items-center rounded-full bg-muted px-2 py-0.5 text-xs font-medium text-muted-foreground\">\n            {completedCount !== undefined\n              ? `${completedCount}/${stepCount}`\n              : `${stepCount} steps`}\n          </span>\n        )}\n      </div>\n      {children}\n      <ChevronDown\n        className={cn(\n          \"size-4 shrink-0 text-muted-foreground transition-transform duration-200\",\n          isOpen && \"rotate-180\",\n        )}\n      />\n    </CollapsiblePrimitive.Trigger>\n  );\n}\n\ninterface AiChainOfThoughtContentProps {\n  children?: React.ReactNode;\n  className?: string;\n}\n\nfunction AiChainOfThoughtContent({\n  children,\n  className,\n}: AiChainOfThoughtContentProps) {\n  return (\n    <CollapsiblePrimitive.Content\n      data-slot=\"ai-chain-of-thought-content\"\n      className={cn(\n        \"border-t border-border data-[state=closed]:animate-collapsible-up data-[state=open]:animate-collapsible-down\",\n        className,\n      )}\n    >\n      <div className=\"p-4 space-y-4\">{children}</div>\n    </CollapsiblePrimitive.Content>\n  );\n}\n\ninterface AiChainOfThoughtStepProps {\n  status: StepStatus;\n  title: string;\n  description?: string;\n  children?: React.ReactNode;\n  className?: string;\n}\n\nfunction AiChainOfThoughtStep({\n  status,\n  title,\n  description,\n  children,\n  className,\n}: AiChainOfThoughtStepProps) {\n  const statusConfig = React.useMemo(() => {\n    const configs: Record<\n      StepStatus,\n      { icon: React.ReactNode; className: string; lineClassName: string }\n    > = {\n      pending: {\n        icon: <Circle className=\"size-4\" />,\n        className: \"text-muted-foreground\",\n        lineClassName: \"bg-muted\",\n      },\n      active: {\n        icon: <Loader2 className=\"size-4 animate-spin\" />,\n        className: \"text-blue-600 dark:text-blue-400\",\n        lineClassName: \"bg-blue-200 dark:bg-blue-900\",\n      },\n      complete: {\n        icon: <CheckCircle2 className=\"size-4\" />,\n        className: \"text-green-600 dark:text-green-400\",\n        lineClassName: \"bg-green-200 dark:bg-green-900\",\n      },\n    };\n    return configs[status];\n  }, [status]);\n\n  return (\n    <div\n      data-slot=\"ai-chain-of-thought-step\"\n      data-status={status}\n      className={cn(\"relative flex gap-3\", className)}\n    >\n      <div className=\"flex flex-col items-center\">\n        <div className={cn(\"shrink-0\", statusConfig.className)}>\n          {statusConfig.icon}\n        </div>\n        <div\n          className={cn(\n            \"mt-2 w-0.5 flex-1 rounded-full\",\n            statusConfig.lineClassName,\n          )}\n        />\n      </div>\n      <div className=\"flex-1 pb-6 min-w-0\">\n        <h4\n          className={cn(\n            \"font-medium text-sm\",\n            status === \"pending\" && \"text-muted-foreground\",\n          )}\n        >\n          {title}\n        </h4>\n        {description && (\n          <p className=\"mt-1 text-xs text-muted-foreground\">{description}</p>\n        )}\n        {children && <div className=\"mt-3\">{children}</div>}\n      </div>\n    </div>\n  );\n}\n\ninterface SearchResult {\n  title: string;\n  url: string;\n  snippet?: string;\n}\n\ninterface AiChainOfThoughtSearchResultsProps {\n  results: SearchResult[];\n  className?: string;\n}\n\nfunction AiChainOfThoughtSearchResults({\n  results,\n  className,\n}: AiChainOfThoughtSearchResultsProps) {\n  if (results.length === 0) return null;\n\n  return (\n    <div\n      data-slot=\"ai-chain-of-thought-search-results\"\n      className={cn(\"space-y-2\", className)}\n    >\n      <div className=\"flex items-center gap-1.5 text-xs text-muted-foreground\">\n        <Search className=\"size-3\" />\n        <span>Found {results.length} results</span>\n      </div>\n      <div className=\"space-y-2\">\n        {results.map((result, index) => (\n          <a\n            key={index}\n            href={result.url}\n            target=\"_blank\"\n            rel=\"noopener noreferrer\"\n            className=\"block rounded-md border border-border bg-muted/30 p-3 transition-colors hover:bg-muted/50\"\n          >\n            <div className=\"flex items-start justify-between gap-2\">\n              <div className=\"min-w-0\">\n                <h5 className=\"truncate text-sm font-medium text-foreground\">\n                  {result.title}\n                </h5>\n                {result.snippet && (\n                  <p className=\"mt-1 line-clamp-2 text-xs text-muted-foreground\">\n                    {result.snippet}\n                  </p>\n                )}\n              </div>\n              <ExternalLink className=\"size-3.5 shrink-0 text-muted-foreground\" />\n            </div>\n          </a>\n        ))}\n      </div>\n    </div>\n  );\n}\n\ninterface AiChainOfThoughtImageProps {\n  src: string;\n  alt: string;\n  caption?: string;\n  className?: string;\n}\n\nfunction AiChainOfThoughtImage({\n  src,\n  alt,\n  caption,\n  className,\n}: AiChainOfThoughtImageProps) {\n  const [isLoading, setIsLoading] = React.useState(true);\n  const [hasError, setHasError] = React.useState(false);\n\n  const handleLoad = React.useCallback(() => {\n    setIsLoading(false);\n  }, []);\n\n  const handleError = React.useCallback(() => {\n    setIsLoading(false);\n    setHasError(true);\n  }, []);\n\n  return (\n    <figure\n      data-slot=\"ai-chain-of-thought-image\"\n      className={cn(\"space-y-2\", className)}\n    >\n      <div className=\"relative overflow-hidden rounded-md border border-border bg-muted/30\">\n        {isLoading && (\n          <div className=\"absolute inset-0 flex items-center justify-center\">\n            <Loader2 className=\"size-6 animate-spin text-muted-foreground\" />\n          </div>\n        )}\n        {hasError ? (\n          <div className=\"flex aspect-video items-center justify-center\">\n            <div className=\"text-center\">\n              <ImageIcon className=\"mx-auto size-8 text-muted-foreground\" />\n              <p className=\"mt-2 text-xs text-muted-foreground\">\n                Failed to load image\n              </p>\n            </div>\n          </div>\n        ) : (\n          <img\n            src={src}\n            alt={alt}\n            onLoad={handleLoad}\n            onError={handleError}\n            className={cn(\n              \"w-full object-cover transition-opacity\",\n              isLoading ? \"opacity-0\" : \"opacity-100\",\n            )}\n          />\n        )}\n      </div>\n      {caption && (\n        <figcaption className=\"text-center text-xs text-muted-foreground\">\n          {caption}\n        </figcaption>\n      )}\n    </figure>\n  );\n}\n\nexport {\n  AiChainOfThought,\n  AiChainOfThoughtHeader,\n  AiChainOfThoughtContent,\n  AiChainOfThoughtStep,\n  AiChainOfThoughtSearchResults,\n  AiChainOfThoughtImage,\n};\nexport type { AiChainOfThoughtProps, StepStatus, SearchResult };\n",
      "type": "registry:component"
    }
  ],
  "docs": "Compound component with steps, search results, and image support. Each step has pending/active/complete states.",
  "categories": [
    "ai"
  ],
  "type": "registry:ui"
}