{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "chat-2",
  "title": "Inbox Messenger Layout",
  "description": "Two-pane chat messenger with a selectable conversation list beside the active thread, each conversation keeping its own messages, plus a composer.",
  "dependencies": [
    "@base-ui/react"
  ],
  "registryDependencies": [
    "avatar",
    "bubble",
    "button",
    "input",
    "message",
    "message-scroller"
  ],
  "files": [
    {
      "path": "registry/blocks/chat/2/chat-block.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Avatar, AvatarFallback, AvatarImage } from \"@/components/ui/avatar\"\nimport { Bubble, BubbleContent } from \"@/components/ui/bubble\"\nimport { Button } from \"@/components/ui/button\"\nimport { Input } from \"@/components/ui/input\"\nimport { Message, 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 { cn } from \"@/lib/utils\"\nimport { IconPlaceholder } from \"@/components/icons/icon-placeholder\"\n\ntype ChatMessage = { id: number; from: \"me\" | \"them\"; text: string }\n\ntype Conversation = {\n  id: string\n  name: string\n  avatar: string\n  preview: string\n  time: string\n}\n\nconst conversations: Conversation[] = [\n  {\n    id: \"mara\",\n    name: \"Mara Lin\",\n    avatar: \"https://i.pravatar.cc/80?img=32\",\n    preview: \"Anything you would change before we ship?\",\n    time: \"9:43 AM\",\n  },\n  {\n    id: \"leo\",\n    name: \"Leo Tanaka\",\n    avatar: \"https://i.pravatar.cc/80?img=12\",\n    preview: \"The API docs are live now.\",\n    time: \"Tue\",\n  },\n  {\n    id: \"owen\",\n    name: \"Owen Reyes\",\n    avatar: \"https://i.pravatar.cc/80?img=53\",\n    preview: \"Thanks for the quick review!\",\n    time: \"Mon\",\n  },\n]\n\nconst seed: Record<string, ChatMessage[]> = {\n  mara: [\n    { id: 1, from: \"them\", text: \"Did you look at the new onboarding flow?\" },\n    { id: 2, from: \"me\", text: \"Just did. The empty states are a nice touch.\" },\n    { id: 3, from: \"them\", text: \"Anything you would change before we ship?\" },\n  ],\n  leo: [\n    { id: 1, from: \"them\", text: \"Pushed the v2 API reference.\" },\n    { id: 2, from: \"them\", text: \"The API docs are live now.\" },\n  ],\n  owen: [\n    { id: 1, from: \"me\", text: \"Left a few notes on your PR.\" },\n    { id: 2, from: \"them\", text: \"Thanks for the quick review!\" },\n  ],\n}\n\nexport default function ChatBlock() {\n  const [threads, setThreads] = React.useState(seed)\n  const [activeId, setActiveId] = React.useState(conversations[0].id)\n  const [draft, setDraft] = React.useState(\"\")\n  const nextId = React.useRef(1000)\n\n  const active =\n    conversations.find((c) => c.id === activeId) ?? conversations[0]\n  const messages = threads[activeId]\n\n  const send = (e: React.FormEvent) => {\n    e.preventDefault()\n    const text = draft.trim()\n    if (!text) return\n    const id = nextId.current++\n    setThreads((prev) => ({\n      ...prev,\n      [activeId]: [...prev[activeId], { id, from: \"me\", text }],\n    }))\n    setDraft(\"\")\n  }\n\n  return (\n    <section className=\"flex w-full items-center justify-center bg-muted/30 px-6 py-16 text-foreground\">\n      <div className=\"grid h-[560px] w-full max-w-3xl grid-cols-1 overflow-hidden rounded-lg border border-border bg-background sm:grid-cols-[240px_1fr]\">\n        <div className=\"hidden flex-col border-r border-border sm:flex\">\n          <div className=\"border-b border-border p-4\">\n            <h2 className=\"font-heading text-sm font-semibold\">Messages</h2>\n          </div>\n          <ul className=\"flex flex-1 flex-col overflow-y-auto\">\n            {conversations.map((conversation) => (\n              <li key={conversation.id}>\n                <button\n                  type=\"button\"\n                  onClick={() => {\n                    setActiveId(conversation.id)\n                    setDraft(\"\")\n                  }}\n                  aria-pressed={conversation.id === activeId}\n                  className={cn(\n                    \"flex w-full items-center gap-3 border-b border-border p-3 text-left transition-colors\",\n                    conversation.id === activeId\n                      ? \"bg-muted\"\n                      : \"hover:bg-muted/50\"\n                  )}\n                >\n                  <Avatar className=\"size-9 shrink-0\">\n                    <AvatarImage\n                      src={conversation.avatar}\n                      alt={conversation.name}\n                      className=\"grayscale\"\n                    />\n                    <AvatarFallback>{conversation.name[0]}</AvatarFallback>\n                  </Avatar>\n                  <div className=\"flex min-w-0 flex-1 flex-col\">\n                    <div className=\"flex items-center justify-between gap-2\">\n                      <span className=\"truncate text-sm font-medium\">\n                        {conversation.name}\n                      </span>\n                      <span className=\"shrink-0 text-[11px] text-muted-foreground\">\n                        {conversation.time}\n                      </span>\n                    </div>\n                    <span className=\"truncate text-xs text-muted-foreground\">\n                      {conversation.preview}\n                    </span>\n                  </div>\n                </button>\n              </li>\n            ))}\n          </ul>\n        </div>\n\n        <div className=\"flex min-w-0 flex-col\">\n          <MessageScrollerProvider\n            key={activeId}\n            autoScroll\n            defaultScrollPosition=\"end\"\n          >\n            <div className=\"flex items-center gap-3 border-b border-border p-4\">\n              <Avatar className=\"size-8\">\n                <AvatarImage\n                  src={active.avatar}\n                  alt={active.name}\n                  className=\"grayscale\"\n                />\n                <AvatarFallback>{active.name[0]}</AvatarFallback>\n              </Avatar>\n              <span className=\"text-sm font-semibold\">{active.name}</span>\n            </div>\n\n            <MessageScroller className=\"flex-1\">\n              <MessageScrollerViewport>\n                <MessageScrollerContent className=\"gap-4 p-4\">\n                  {messages.map((message) => (\n                    <MessageScrollerItem\n                      key={message.id}\n                      messageId={String(message.id)}\n                      scrollAnchor={message.from === \"me\"}\n                    >\n                      <Message align={message.from === \"me\" ? \"end\" : \"start\"}>\n                        <MessageContent>\n                          <Bubble\n                            variant={\n                              message.from === \"me\" ? \"default\" : \"muted\"\n                            }\n                          >\n                            <BubbleContent>{message.text}</BubbleContent>\n                          </Bubble>\n                        </MessageContent>\n                      </Message>\n                    </MessageScrollerItem>\n                  ))}\n                </MessageScrollerContent>\n              </MessageScrollerViewport>\n              <MessageScrollerButton />\n            </MessageScroller>\n\n            <form\n              onSubmit={send}\n              className=\"flex items-center gap-2 border-t border-border p-3\"\n            >\n              <Input\n                value={draft}\n                onChange={(e) => setDraft(e.target.value)}\n                placeholder=\"Type a message...\"\n                aria-label=\"Message\"\n              />\n              <Button\n                type=\"submit\"\n                size=\"icon\"\n                disabled={!draft.trim()}\n                aria-label=\"Send message\"\n              >\n                <IconPlaceholder\n                  lucide=\"Send\"\n                  tabler=\"IconSend\"\n                  hugeicons=\"SentIcon\"\n                  phosphor=\"PaperPlane\"\n                  remixicon=\"RiSendPlane2Fill\"\n                  className=\"size-4\"\n                  aria-hidden=\"true\"\n                />\n              </Button>\n            </form>\n          </MessageScrollerProvider>\n        </div>\n      </div>\n    </section>\n  )\n}\n",
      "type": "registry:component",
      "target": "components/blocks/chat-2.tsx"
    }
  ],
  "meta": {
    "height": "696px",
    "tier": "free"
  },
  "categories": [
    "chat"
  ],
  "type": "registry:block"
}