{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "plan",
  "title": "Ai Plan",
  "description": "TODO: Add description",
  "dependencies": [],
  "registryDependencies": [],
  "files": [
    {
      "path": "registry/default/blocks/ai/ai-plan/components/elements/ai-plan.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\n\nimport * as CollapsiblePrimitive from \"@radix-ui/react-collapsible\";\nimport { ChevronDown, ClipboardList, Sparkles } from \"lucide-react\";\n\nimport { cn } from \"@/lib/utils\";\n\ninterface AiPlanContextValue {\n  isStreaming: boolean;\n  isOpen: boolean;\n}\n\nconst AiPlanContext = React.createContext<AiPlanContextValue | null>(null);\n\nfunction usePlanContext() {\n  const context = React.useContext(AiPlanContext);\n  if (!context) {\n    throw new Error(\"AiPlan components must be used within <AiPlan>\");\n  }\n  return context;\n}\n\ninterface AiPlanProps {\n  isStreaming?: boolean;\n  defaultOpen?: boolean;\n  open?: boolean;\n  onOpenChange?: (open: boolean) => void;\n  children?: React.ReactNode;\n  className?: string;\n}\n\nfunction AiPlan({\n  isStreaming = false,\n  defaultOpen = true,\n  open: controlledOpen,\n  onOpenChange,\n  children,\n  className,\n}: AiPlanProps) {\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  React.useEffect(() => {\n    if (isStreaming) {\n      handleOpenChange(true);\n    }\n  }, [isStreaming, handleOpenChange]);\n\n  const contextValue = React.useMemo(\n    () => ({ isStreaming, isOpen }),\n    [isStreaming, isOpen],\n  );\n\n  return (\n    <AiPlanContext.Provider value={contextValue}>\n      <CollapsiblePrimitive.Root\n        data-slot=\"ai-plan\"\n        data-streaming={isStreaming}\n        open={isOpen}\n        onOpenChange={handleOpenChange}\n        className={cn(\n          \"rounded-lg border bg-card text-card-foreground overflow-hidden transition-all\",\n          isStreaming\n            ? \"border-indigo-300 dark:border-indigo-800 shadow-lg shadow-indigo-100 dark:shadow-indigo-950/50\"\n            : \"border-border\",\n          className,\n        )}\n      >\n        {children}\n      </CollapsiblePrimitive.Root>\n    </AiPlanContext.Provider>\n  );\n}\n\ninterface AiPlanHeaderProps {\n  children?: React.ReactNode;\n  className?: string;\n}\n\nfunction AiPlanHeader({ children, className }: AiPlanHeaderProps) {\n  const { isStreaming, isOpen } = usePlanContext();\n\n  return (\n    <CollapsiblePrimitive.Trigger\n      data-slot=\"ai-plan-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\n        className={cn(\n          \"flex size-8 shrink-0 items-center justify-center rounded-md transition-colors\",\n          isStreaming ? \"bg-indigo-100 dark:bg-indigo-950\" : \"bg-muted\",\n        )}\n      >\n        {isStreaming ? (\n          <Sparkles className=\"size-4 text-indigo-600 dark:text-indigo-400 animate-pulse\" />\n        ) : (\n          <ClipboardList className=\"size-4 text-muted-foreground\" />\n        )}\n      </div>\n      <div className=\"flex flex-1 items-center text-left\">{children}</div>\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 AiPlanTitleProps {\n  children?: React.ReactNode;\n  className?: string;\n}\n\nfunction AiPlanTitle({ children, className }: AiPlanTitleProps) {\n  const { isStreaming } = usePlanContext();\n\n  return (\n    <h3\n      data-slot=\"ai-plan-title\"\n      className={cn(\n        \"font-semibold\",\n        isStreaming && \"text-indigo-700 dark:text-indigo-300\",\n        className,\n      )}\n    >\n      {children}\n      {isStreaming && (\n        <span className=\"ml-2 inline-flex items-center gap-1 rounded-full bg-indigo-100 dark:bg-indigo-950 px-2 py-0.5 text-xs font-medium text-indigo-700 dark:text-indigo-300\">\n          Generating...\n        </span>\n      )}\n    </h3>\n  );\n}\n\ninterface AiPlanDescriptionProps {\n  children?: React.ReactNode;\n  className?: string;\n}\n\nfunction AiPlanDescription({ children, className }: AiPlanDescriptionProps) {\n  return (\n    <p\n      data-slot=\"ai-plan-description\"\n      className={cn(\"text-xs text-muted-foreground mt-0.5\", className)}\n    >\n      {children}\n    </p>\n  );\n}\n\ninterface AiPlanContentProps {\n  children?: React.ReactNode;\n  className?: string;\n}\n\nfunction AiPlanContent({ children, className }: AiPlanContentProps) {\n  const { isStreaming } = usePlanContext();\n\n  return (\n    <CollapsiblePrimitive.Content\n      data-slot=\"ai-plan-content\"\n      className={cn(\n        \"border-t data-[state=closed]:animate-collapsible-up data-[state=open]:animate-collapsible-down\",\n        isStreaming\n          ? \"border-indigo-200 dark:border-indigo-900\"\n          : \"border-border\",\n        className,\n      )}\n    >\n      <div className={cn(\"p-4\", isStreaming && \"relative overflow-hidden\")}>\n        {isStreaming && (\n          <div className=\"pointer-events-none absolute inset-0 bg-gradient-to-r from-transparent via-indigo-100/50 dark:via-indigo-900/30 to-transparent animate-shimmer\" />\n        )}\n        {children}\n      </div>\n    </CollapsiblePrimitive.Content>\n  );\n}\n\ninterface AiPlanFooterProps {\n  children?: React.ReactNode;\n  className?: string;\n}\n\nfunction AiPlanFooter({ children, className }: AiPlanFooterProps) {\n  const { isStreaming } = usePlanContext();\n\n  return (\n    <div\n      data-slot=\"ai-plan-footer\"\n      className={cn(\n        \"flex items-center justify-end gap-2 border-t px-4 py-3\",\n        isStreaming\n          ? \"border-indigo-200 dark:border-indigo-900\"\n          : \"border-border\",\n        className,\n      )}\n    >\n      {children}\n    </div>\n  );\n}\n\ninterface AiPlanActionProps {\n  variant?: \"primary\" | \"secondary\" | \"destructive\";\n  disabled?: boolean;\n  onClick?: () => void;\n  children?: React.ReactNode;\n  className?: string;\n}\n\nfunction AiPlanAction({\n  variant = \"secondary\",\n  disabled = false,\n  onClick,\n  children,\n  className,\n}: AiPlanActionProps) {\n  const { isStreaming } = usePlanContext();\n\n  const variantStyles = React.useMemo(() => {\n    const styles: Record<string, string> = {\n      primary:\n        \"bg-primary text-primary-foreground hover:bg-primary/90 disabled:bg-primary/50\",\n      secondary:\n        \"bg-muted text-foreground hover:bg-muted/80 disabled:bg-muted/50\",\n      destructive:\n        \"bg-red-600 text-white hover:bg-red-700 disabled:bg-red-600/50\",\n    };\n    return styles[variant];\n  }, [variant]);\n\n  return (\n    <button\n      type=\"button\"\n      data-slot=\"ai-plan-action\"\n      data-variant={variant}\n      disabled={disabled || isStreaming}\n      onClick={onClick}\n      className={cn(\n        \"inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50\",\n        variantStyles,\n        className,\n      )}\n    >\n      {children}\n    </button>\n  );\n}\n\ninterface AiPlanStepProps {\n  number: number;\n  children?: React.ReactNode;\n  className?: string;\n}\n\nfunction AiPlanStep({ number, children, className }: AiPlanStepProps) {\n  return (\n    <div\n      data-slot=\"ai-plan-step\"\n      className={cn(\"flex gap-3 items-start\", className)}\n    >\n      <span className=\"flex size-6 shrink-0 items-center justify-center rounded-full bg-muted text-xs font-medium text-muted-foreground\">\n        {number}\n      </span>\n      <div className=\"flex-1 text-sm\">{children}</div>\n    </div>\n  );\n}\n\nexport {\n  AiPlan,\n  AiPlanHeader,\n  AiPlanTitle,\n  AiPlanDescription,\n  AiPlanContent,\n  AiPlanFooter,\n  AiPlanAction,\n  AiPlanStep,\n};\nexport type { AiPlanProps };\n",
      "type": "registry:component"
    }
  ],
  "docs": "TODO: Add documentation",
  "categories": [
    "ai"
  ],
  "type": "registry:ui"
}