{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "ai-chat-2",
  "title": "Chat With Suggested Prompt Start",
  "description": "AI chat opening on a suggested-prompt empty state, then switching to a message thread once a prompt is sent, with a multi-line composer.",
  "dependencies": [
    "@base-ui/react"
  ],
  "registryDependencies": [
    "avatar",
    "badge",
    "bubble",
    "button",
    "card",
    "kbd",
    "message",
    "message-scroller",
    "textarea"
  ],
  "files": [
    {
      "path": "registry/blocks/ai-chat/2/ai-chat-block.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Avatar, AvatarFallback } from \"@/components/ui/avatar\"\nimport { Badge } from \"@/components/ui/badge\"\nimport { Bubble, BubbleContent } from \"@/components/ui/bubble\"\nimport { Button } from \"@/components/ui/button\"\nimport { Card, CardContent, CardFooter, CardHeader } from \"@/components/ui/card\"\nimport { Kbd, KbdGroup } from \"@/components/ui/kbd\"\nimport { Message, MessageAvatar, MessageContent } from \"@/components/ui/message\"\nimport {\n  MessageScroller,\n  MessageScrollerButton,\n  MessageScrollerContent,\n  MessageScrollerItem,\n  MessageScrollerProvider,\n  MessageScrollerViewport,\n} from \"@/components/ui/message-scroller\"\nimport { Textarea } from \"@/components/ui/textarea\"\nimport { IconPlaceholder } from \"@/components/icons/icon-placeholder\"\n\n/** Props a call site may pass through to an icon. */\ntype IconProps = { className?: string; size?: number | string }\n\nconst suggestions = [\n  {\n    icon: (p: IconProps) => (\n      <IconPlaceholder\n        lucide=\"ChartBar\"\n        tabler=\"IconChartBar\"\n        hugeicons=\"BarChartIcon\"\n        phosphor=\"ChartBar\"\n        remixicon=\"RiBarChartBoxLine\"\n        {...p}\n      />\n    ),\n    label: \"Summarise last quarter's revenue\",\n  },\n  {\n    icon: (p: IconProps) => (\n      <IconPlaceholder\n        lucide=\"FileText\"\n        tabler=\"IconFileText\"\n        hugeicons=\"File01Icon\"\n        phosphor=\"FileText\"\n        remixicon=\"RiFileTextLine\"\n        {...p}\n      />\n    ),\n    label: \"Draft a status update for stakeholders\",\n  },\n  {\n    icon: (p: IconProps) => (\n      <IconPlaceholder\n        lucide=\"Lightbulb\"\n        tabler=\"IconBulb\"\n        hugeicons=\"Idea01Icon\"\n        phosphor=\"Lightbulb\"\n        remixicon=\"RiLightbulbLine\"\n        {...p}\n      />\n    ),\n    label: \"Suggest three ways to reduce churn\",\n  },\n  {\n    icon: (p: IconProps) => (\n      <IconPlaceholder\n        lucide=\"Sparkles\"\n        tabler=\"IconSparkles\"\n        hugeicons=\"SparklesIcon\"\n        phosphor=\"Sparkle\"\n        remixicon=\"RiSparklingLine\"\n        {...p}\n      />\n    ),\n    label: \"What are my top action items today?\",\n  },\n]\n\nconst CANNED_REPLIES = [\n  \"Here's what I found: the latest figures are trending up across your core segments, with no anomalies worth flagging.\",\n  \"Good ask. I've put together a concise summary you can drop straight into your update: headline metric, main driver, and current risk.\",\n  \"Based on the workspace data, the top three opportunities all tie back to onboarding and activation. Want me to expand on any of them?\",\n  \"Your priorities for today: two items need a decision, one is waiting on review. I can draft the follow-ups if that helps.\",\n]\n\ntype MessageRole = \"user\" | \"assistant\"\n\ninterface ChatMessage {\n  id: number\n  role: MessageRole\n  content: string\n}\n\nexport default function AiChatBlock() {\n  const [messages, setMessages] = React.useState<ChatMessage[]>([])\n  const [draft, setDraft] = React.useState(\"\")\n  const nextId = React.useRef(1)\n  const replyIdx = React.useRef(0)\n  const replyTimers = React.useRef<ReturnType<typeof setTimeout>[]>([])\n  const started = messages.length > 0\n\n  React.useEffect(() => {\n    const timers = replyTimers.current\n    return () => timers.forEach(clearTimeout)\n  }, [])\n\n  function sendMessage(text: string) {\n    const content = text.trim()\n    if (!content) return\n\n    setMessages((prev) => [\n      ...prev,\n      { id: nextId.current++, role: \"user\", content },\n    ])\n    setDraft(\"\")\n\n    const reply = CANNED_REPLIES[replyIdx.current % CANNED_REPLIES.length]\n    replyIdx.current += 1\n    const timer = setTimeout(() => {\n      setMessages((prev) => [\n        ...prev,\n        { id: nextId.current++, role: \"assistant\", content: reply },\n      ])\n    }, 600)\n    replyTimers.current.push(timer)\n  }\n\n  return (\n    <section className=\"flex w-full items-center justify-center bg-background px-6 py-12 text-foreground\">\n      <MessageScrollerProvider autoScroll defaultScrollPosition=\"end\">\n        <Card className=\"w-full max-w-lg\">\n          <CardHeader className=\"flex flex-col items-center gap-4 pt-8 pb-2\">\n            <div className=\"flex size-12 items-center justify-center rounded-lg bg-primary text-primary-foreground\">\n              <IconPlaceholder\n                lucide=\"Sparkles\"\n                tabler=\"IconSparkles\"\n                hugeicons=\"SparklesIcon\"\n                phosphor=\"Sparkle\"\n                remixicon=\"RiSparklingLine\"\n                className=\"size-6\"\n                aria-hidden=\"true\"\n              />\n            </div>\n            <div className=\"flex flex-col items-center gap-1 text-center\">\n              <h2 className=\"font-heading text-base font-semibold tracking-tight\">\n                Acme AI Assistant\n              </h2>\n              <p className=\"max-w-xs text-xs text-muted-foreground\">\n                Ask me anything about your workspace: reports, drafts, insights,\n                or next steps.\n              </p>\n            </div>\n            <Badge variant=\"secondary\" className=\"gap-1.5\">\n              <span className=\"size-1.5 bg-primary\" />\n              Ready\n            </Badge>\n          </CardHeader>\n\n          <CardContent className=\"flex flex-col gap-3 px-5 pb-0\">\n            {started ? (\n              <MessageScroller className=\"h-64\">\n                <MessageScrollerViewport>\n                  <MessageScrollerContent className=\"gap-4 pr-2.5\">\n                    {messages.map((msg) => (\n                      <MessageScrollerItem\n                        key={msg.id}\n                        messageId={String(msg.id)}\n                        scrollAnchor={msg.role === \"user\"}\n                      >\n                        <Message align={msg.role === \"user\" ? \"end\" : \"start\"}>\n                          {msg.role === \"assistant\" && (\n                            <MessageAvatar>\n                              <Avatar className=\"size-7 border border-border\">\n                                <AvatarFallback className=\"bg-primary text-primary-foreground\">\n                                  <IconPlaceholder\n                                    lucide=\"Sparkles\"\n                                    tabler=\"IconSparkles\"\n                                    hugeicons=\"SparklesIcon\"\n                                    phosphor=\"Sparkle\"\n                                    remixicon=\"RiSparklingFill\"\n                                    className=\"size-4\"\n                                    aria-hidden=\"true\"\n                                  />\n                                </AvatarFallback>\n                              </Avatar>\n                            </MessageAvatar>\n                          )}\n                          <MessageContent>\n                            <Bubble\n                              variant={\n                                msg.role === \"user\" ? \"default\" : \"muted\"\n                              }\n                            >\n                              <BubbleContent className=\"whitespace-pre-line\">\n                                {msg.content}\n                              </BubbleContent>\n                            </Bubble>\n                          </MessageContent>\n                        </Message>\n                      </MessageScrollerItem>\n                    ))}\n                  </MessageScrollerContent>\n                </MessageScrollerViewport>\n                <MessageScrollerButton />\n              </MessageScroller>\n            ) : (\n              <>\n                <p className=\"text-center text-[10px] font-medium tracking-widest text-muted-foreground uppercase\">\n                  Suggested Prompts\n                </p>\n                <div className=\"grid grid-cols-1 gap-2 sm:grid-cols-2\">\n                  {suggestions.map(({ icon: Icon, label }) => (\n                    <button\n                      key={label}\n                      type=\"button\"\n                      onClick={() => sendMessage(label)}\n                      className=\"flex cursor-pointer items-start gap-2.5 rounded-lg border border-border bg-muted/50 px-3 py-2.5 text-left transition-colors hover:bg-muted focus-visible:ring-1 focus-visible:ring-ring focus-visible:outline-none\"\n                    >\n                      <Icon className=\"mt-px size-3.5 shrink-0 text-muted-foreground\" />\n                      <span className=\"text-xs leading-snug text-foreground\">\n                        {label}\n                      </span>\n                    </button>\n                  ))}\n                </div>\n              </>\n            )}\n          </CardContent>\n\n          <CardFooter className=\"px-5 pt-4 pb-5\">\n            <form\n              onSubmit={(e) => {\n                e.preventDefault()\n                sendMessage(draft)\n              }}\n              className=\"flex w-full flex-col gap-2\"\n            >\n              <Textarea\n                value={draft}\n                onChange={(e) => setDraft(e.target.value)}\n                onKeyDown={(e) => {\n                  if (e.key === \"Enter\" && !e.shiftKey) {\n                    e.preventDefault()\n                    sendMessage(draft)\n                  }\n                }}\n                placeholder=\"Ask anything…\"\n                aria-label=\"Ask anything\"\n                className=\"resize-none\"\n                rows={3}\n              />\n              <div className=\"flex w-full items-center justify-between\">\n                <span className=\"flex items-center gap-1 text-[10px] text-muted-foreground\">\n                  <KbdGroup>\n                    <Kbd>Shift</Kbd>\n                    <Kbd>Enter</Kbd>\n                  </KbdGroup>\n                  New Line\n                </span>\n                <Button type=\"submit\" size=\"sm\" disabled={!draft.trim()}>\n                  <IconPlaceholder\n                    lucide=\"Send\"\n                    tabler=\"IconSend\"\n                    hugeicons=\"SentIcon\"\n                    phosphor=\"PaperPlane\"\n                    remixicon=\"RiSendPlaneLine\"\n                    data-icon=\"inline-start\"\n                  />\n                  Send\n                </Button>\n              </div>\n            </form>\n          </CardFooter>\n        </Card>\n      </MessageScrollerProvider>\n    </section>\n  )\n}\n",
      "type": "registry:component"
    }
  ],
  "meta": {
    "height": "635px",
    "tier": "free"
  },
  "categories": [
    "ai-chat"
  ],
  "type": "registry:block"
}