{
  "title": "Chat Header",
  "description": "Renders the header with the assistant name/icon, model load status, and token usage counter",
  "name": "native-ai-chat-header",
  "dependencies": [],
  "registryDependencies": [
    "badge",
    "button",
    "popover",
    "spinner"
  ],
  "type": "registry:ui",
  "files": [
    {
      "path": "components/paceui/native-ai/chat-header/index.tsx",
      "type": "registry:ui",
      "content": "import type { ReactNode } from \"react\";\n\nimport { RotateCcw, Sparkles } from \"lucide-react\";\n\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"@/components/ui/popover\";\nimport { Spinner } from \"@/components/ui/spinner\";\n\nexport type AIStatus = \"loading\" | \"ready\" | \"lazy\" | string;\n\nexport interface ContextInfo {\n    used: number;\n    window: number;\n}\n\nexport interface ChatHeaderProps {\n    title?: string;\n    logo?: ReactNode;\n    icon?: ReactNode;\n    isSupported?: boolean;\n    contextInfo?: ContextInfo | null;\n    status?: AIStatus;\n    loadingPercentage?: number | null;\n    onReset?: () => void;\n}\n\ninterface ContextProgressRingProps {\n    used: number;\n    window: number;\n    size?: number;\n    strokeWidth?: number;\n}\n\nexport function ContextProgressRing({\n    used,\n    window: contextWindow,\n    size = 18,\n    strokeWidth = 2.5,\n}: ContextProgressRingProps) {\n    const percentage = contextWindow ? Math.min(100, Math.max(0, Math.round((used / contextWindow) * 100))) : 0;\n\n    const radius = (size - strokeWidth) / 2;\n    const circumference = 2 * Math.PI * radius;\n    const strokeDashoffset = circumference - (percentage / 100) * circumference;\n\n    return (\n        <Popover>\n            <PopoverTrigger\n                openOnHover\n                render={\n                    <button\n                        type=\"button\"\n                        aria-label=\"View context window usage\"\n                        className=\"relative inline-flex cursor-pointer items-center justify-center focus:outline-none\">\n                        <svg width={size} height={size} className=\"-rotate-90 transform\">\n                            <circle\n                                cx={size / 2}\n                                cy={size / 2}\n                                r={radius}\n                                className=\"stroke-muted-foreground/20\"\n                                strokeWidth={strokeWidth}\n                                fill=\"transparent\"\n                            />\n                            <circle\n                                cx={size / 2}\n                                cy={size / 2}\n                                r={radius}\n                                className=\"stroke-primary transition-all duration-300 ease-in-out\"\n                                strokeWidth={strokeWidth}\n                                strokeDasharray={circumference}\n                                strokeDashoffset={strokeDashoffset}\n                                strokeLinecap=\"round\"\n                                fill=\"transparent\"\n                            />\n                        </svg>\n                    </button>\n                }\n            />\n            <PopoverContent side=\"bottom\" align=\"center\" className=\"w-auto p-3 text-xs\">\n                <div className=\"space-y-1.5\">\n                    <p className=\"font-medium\">Context Window Usage ({percentage}%)</p>\n                    <p className=\"font-mono opacity-85\">\n                        {used.toLocaleString()} / {contextWindow.toLocaleString()} tokens\n                    </p>\n                </div>\n            </PopoverContent>\n        </Popover>\n    );\n}\n\nexport const ChatHeader = ({\n    title = \"AI Assistant\",\n    logo,\n    icon,\n    isSupported = false,\n    contextInfo,\n    status = \"ready\",\n    loadingPercentage,\n    onReset,\n}: ChatHeaderProps) => {\n    const renderIcon = logo ?? icon ?? <Sparkles className=\"size-5\" />;\n    const normalizedStatus = typeof status === \"string\" ? status.toLowerCase() : \"ready\";\n\n    return (\n        <div className=\"flex items-center justify-between\">\n            <div className=\"flex items-center gap-3\">\n                <div className=\"bg-muted flex items-center justify-center rounded-md p-2\">{renderIcon}</div>\n                <p className=\"font-medium\">{title}</p>\n            </div>\n\n            <div className=\"flex items-center gap-1.5\">\n                {contextInfo && <ContextProgressRing used={contextInfo.used} window={contextInfo.window} />}\n                {onReset && (\n                    <Popover>\n                        <PopoverTrigger\n                            render={\n                                <Button\n                                    variant=\"ghost\"\n                                    size=\"icon-sm\"\n                                    className=\"group\"\n                                    onClick={onReset}\n                                    aria-label=\"Reset chat\">\n                                    <RotateCcw className=\"size-4 transition-all duration-300 group-hover:-rotate-30\" />\n                                </Button>\n                            }\n                        />\n                        <PopoverContent side=\"bottom\" align=\"center\" className=\"w-auto p-2 text-xs\">\n                            Reset chat\n                        </PopoverContent>\n                    </Popover>\n                )}\n                {isSupported && (\n                    <div className=\"ms-auto flex items-center gap-2\">\n                        {normalizedStatus === \"loading\" && (\n                            <Badge variant=\"outline\" className=\"h-6.5 gap-1.5 px-2.5\">\n                                <Spinner className=\"size-3\" />\n                                Loading\n                                {typeof loadingPercentage === \"number\" && loadingPercentage > 0\n                                    ? ` ${loadingPercentage}%`\n                                    : \"\"}\n                            </Badge>\n                        )}\n                        {normalizedStatus === \"ready\" && (\n                            <Badge variant=\"outline\" className=\"h-6.5 gap-1.5 px-2.5\">\n                                <span className=\"bg-primary size-1.5 rounded-full\" />\n                                Ready\n                            </Badge>\n                        )}\n                        {normalizedStatus === \"lazy\" && (\n                            <Badge variant=\"outline\" className=\"h-6.5 gap-1.5 px-2.5\">\n                                <span className=\"size-1.5 rounded-full\" />\n                                Lazy\n                            </Badge>\n                        )}\n                        {![\"loading\", \"ready\", \"lazy\"].includes(normalizedStatus) && (\n                            <Badge variant=\"outline\" className=\"h-6.5 gap-1.5 px-2.5\">\n                                {status}\n                            </Badge>\n                        )}\n                    </div>\n                )}\n            </div>\n        </div>\n    );\n};\n"
    }
  ],
  "mcp": {
    "description": "Device-local AI-powered functionality. Renders the header with the assistant name/icon, model load status, and token usage counter Ideal for privacy-first AI interfaces, streaming text responses, and Chrome Gemini Nano integrations.",
    "tags": [
      "native-ai",
      "chat"
    ]
  }
}