{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "ai-web-preview",
  "type": "registry:ui",
  "description": "AI web-preview component",
  "files": [
    {
      "path": "packages/ai/web-preview.tsx",
      "content": "'use client';\n\nimport { ChevronDownIcon } from 'lucide-react';\nimport type { ComponentProps, ReactNode } from 'react';\nimport { createContext, useContext, useState } from 'react';\nimport { Button } from '@repo/shadcn-ui/components/ui/button';\nimport {\n  Collapsible,\n  CollapsibleContent,\n  CollapsibleTrigger,\n} from '@repo/shadcn-ui/components/ui/collapsible';\nimport { Input } from '@repo/shadcn-ui/components/ui/input';\nimport {\n  Tooltip,\n  TooltipContent,\n  TooltipProvider,\n  TooltipTrigger,\n} from '@repo/shadcn-ui/components/ui/tooltip';\nimport { cn } from '@repo/shadcn-ui/lib/utils';\n\nexport type AIWebPreviewContextValue = {\n  url: string;\n  setUrl: (url: string) => void;\n  consoleOpen: boolean;\n  setConsoleOpen: (open: boolean) => void;\n};\n\nconst AIWebPreviewContext = createContext<AIWebPreviewContextValue | null>(null);\n\nconst useAIWebPreview = () => {\n  const context = useContext(AIWebPreviewContext);\n  if (!context) {\n    throw new Error('AIWebPreview components must be used within a AIWebPreview');\n  }\n  return context;\n};\n\nexport type AIWebPreviewProps = ComponentProps<'div'> & {\n  defaultUrl?: string;\n  onUrlChange?: (url: string) => void;\n};\n\nexport const AIWebPreview = ({\n  className,\n  children,\n  defaultUrl = '',\n  onUrlChange,\n  ...props\n}: AIWebPreviewProps) => {\n  const [url, setUrl] = useState(defaultUrl);\n  const [consoleOpen, setConsoleOpen] = useState(false);\n\n  const handleUrlChange = (newUrl: string) => {\n    setUrl(newUrl);\n    onUrlChange?.(newUrl);\n  };\n\n  const contextValue: AIWebPreviewContextValue = {\n    url,\n    setUrl: handleUrlChange,\n    consoleOpen,\n    setConsoleOpen,\n  };\n\n  return (\n    <AIWebPreviewContext.Provider value={contextValue}>\n      <div\n        className={cn('flex size-full flex-col rounded-lg border bg-card', className)}\n        {...props}\n      >\n        {children}\n      </div>\n    </AIWebPreviewContext.Provider>\n  );\n};\n\nexport type AIWebPreviewNavigationProps = ComponentProps<'div'>;\n\nexport const AIWebPreviewNavigation = ({ className, children, ...props }: AIWebPreviewNavigationProps) => (\n  <div className={cn('flex items-center gap-1 border-b p-2', className)} {...props}>\n    {children}\n  </div>\n);\n\nexport type AIWebPreviewNavigationButtonProps = ComponentProps<typeof Button> & {\n  tooltip?: string;\n};\n\nexport const AIWebPreviewNavigationButton = ({\n  onClick,\n  disabled,\n  tooltip,\n  children,\n  ...props\n}: AIWebPreviewNavigationButtonProps) => (\n  <TooltipProvider>\n    <Tooltip>\n      <TooltipTrigger asChild>\n        <Button\n          variant=\"ghost\"\n          size=\"sm\"\n          className=\"h-8 w-8 p-0 hover:text-foreground\"\n          onClick={onClick}\n          disabled={disabled}\n          {...props}\n        >\n          {children}\n        </Button>\n      </TooltipTrigger>\n      <TooltipContent>\n        <p>{tooltip}</p>\n      </TooltipContent>\n    </Tooltip>\n  </TooltipProvider>\n);\n\nexport type AIWebPreviewUrlProps = ComponentProps<typeof Input>;\n\nexport const AIWebPreviewUrl = ({ value, onChange, onKeyDown, ...props }: AIWebPreviewUrlProps) => {\n  const { url, setUrl } = useAIWebPreview();\n\n  const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {\n    if (event.key === 'Enter') {\n      const target = event.target as HTMLInputElement;\n      setUrl(target.value);\n    }\n    onKeyDown?.(event);\n  };\n\n  return (\n    <Input\n      className=\"flex-1 h-8 text-sm\"\n      placeholder=\"Enter URL...\"\n      value={value ?? url}\n      onChange={onChange}\n      onKeyDown={handleKeyDown}\n      {...props}\n    />\n  );\n};\n\nexport type AIWebPreviewBodyProps = ComponentProps<'iframe'> & {\n  loading?: ReactNode;\n};\n\nexport const AIWebPreviewBody = ({ className, loading, src, ...props }: AIWebPreviewBodyProps) => {\n  const { url } = useAIWebPreview();\n\n  return (\n    <div className=\"flex-1\">\n      <iframe\n        className={cn('size-full', className)}\n        src={src ?? url}\n        title=\"Preview\"\n        sandbox=\"allow-scripts allow-same-origin allow-forms allow-popups allow-presentation\"\n        {...props}\n      />\n      {loading}\n    </div>\n  );\n};\n\nexport type AIWebPreviewConsoleProps = ComponentProps<'div'> & {\n  logs?: Array<{\n    level: 'log' | 'warn' | 'error';\n    message: string;\n    timestamp: Date;\n  }>;\n};\n\nexport const AIWebPreviewConsole = ({\n  className,\n  logs = [],\n  children,\n  ...props\n}: AIWebPreviewConsoleProps) => {\n  const { consoleOpen, setConsoleOpen } = useAIWebPreview();\n\n  return (\n    <Collapsible\n      open={consoleOpen}\n      onOpenChange={setConsoleOpen}\n      className={cn('border-t bg-muted/50 font-mono text-sm', className)}\n      {...props}\n    >\n      <CollapsibleTrigger asChild>\n        <Button\n          variant=\"ghost\"\n          className=\"flex w-full items-center justify-between p-4 text-left font-medium hover:bg-muted/50\"\n        >\n          Console\n          <ChevronDownIcon\n            className={cn('h-4 w-4 transition-transform duration-200', consoleOpen && 'rotate-180')}\n          />\n        </Button>\n      </CollapsibleTrigger>\n      <CollapsibleContent\n        className={cn(\n          'px-4 pb-4',\n          'outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',\n        )}\n      >\n        <div className=\"space-y-1 max-h-48 overflow-y-auto\">\n          {logs.length === 0 ? (\n            <p className=\"text-muted-foreground\">No console output</p>\n          ) : (\n            logs.map((log, index) => (\n              <div\n                key={`${log.timestamp.getTime()}-${index}`}\n                className={cn(\n                  'text-xs',\n                  log.level === 'error' && 'text-destructive',\n                  log.level === 'warn' && 'text-yellow-600',\n                  log.level === 'log' && 'text-foreground',\n                )}\n              >\n                <span className=\"text-muted-foreground\">{log.timestamp.toLocaleTimeString()}</span>{' '}\n                {log.message}\n              </div>\n            ))\n          )}\n          {children}\n        </div>\n      </CollapsibleContent>\n    </Collapsible>\n  );\n};\n",
      "type": "registry:component"
    }
  ]
}