{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "chat",
  "title": "Chat",
  "description": "A whole conversation with an agent: messages, suggestions and the input. Type something to try it.",
  "registryDependencies": [
    "https://creance.pages.dev/r/creance-base.json",
    "https://creance.pages.dev/r/message.json",
    "https://creance.pages.dev/r/message-list.json",
    "https://creance.pages.dev/r/prompt-input.json",
    "https://creance.pages.dev/r/reasoning.json",
    "https://creance.pages.dev/r/sources.json",
    "https://creance.pages.dev/r/suggestions.json"
  ],
  "files": [
    {
      "path": "chat/Chat.css",
      "content": ".cr-chat {\n  display: flex;\n  flex-direction: column;\n  min-height: 0;\n  height: 100%;\n  color: var(--cr-color-text-default);\n  font-family: var(--cr-font-family-sans);\n}\n\n.cr-chat > .cr-message-list {\n  flex: 1;\n  height: auto;\n}\n\n.cr-chat__empty {\n  display: grid;\n  place-items: center;\n  min-height: 160px;\n  color: var(--cr-color-text-muted);\n  text-align: center;\n}\n\n/* The input lines up with the column of messages above it. */\n.cr-chat__composer {\n  display: flex;\n  flex-direction: column;\n  gap: var(--cr-space-3);\n  box-sizing: border-box;\n  width: 100%;\n  max-width: var(--cr-message-list-width, 760px);\n  margin-inline: auto;\n  padding: var(--cr-space-2) var(--cr-space-4) var(--cr-space-4);\n}\n",
      "type": "registry:file",
      "target": "@components/creance/chat/Chat.css"
    },
    {
      "path": "chat/Chat.tsx",
      "content": "'use client';\n\nimport type { ReactNode } from 'react';\nimport { cx } from '@/lib/creance/cx';\nimport { LiveRegion } from '@/lib/creance/LiveRegion';\nimport { Message } from '@/components/creance/message/Message';\nimport { MessageList } from '@/components/creance/message-list/MessageList';\nimport { PromptInput, type PromptInputProps } from '@/components/creance/prompt-input/PromptInput';\nimport { Reasoning } from '@/components/creance/reasoning/Reasoning';\nimport { Sources, type Source } from '@/components/creance/sources/Sources';\nimport { Suggestions } from '@/components/creance/suggestions/Suggestions';\nimport './Chat.css';\n\nexport interface ChatMessage {\n  id: string;\n  from: 'user' | 'assistant';\n  /** The message. Render markdown yourself; the kit does not parse it. */\n  content?: ReactNode;\n  /** `pending` shows dots before the first word, `streaming` a caret after the last. Default `done`. */\n  status?: 'pending' | 'streaming' | 'done';\n  /** The thinking behind an assistant message, shown folded above it. */\n  reasoning?: { content: ReactNode; seconds?: number; thinking?: boolean };\n  /** What the answer is based on, listed under it. */\n  sources?: Source[];\n  /** Under a finished assistant message: copy, try again, feedback. */\n  actions?: ReactNode;\n}\n\nexport interface ChatProps extends Pick<PromptInputProps, 'placeholder' | 'tools' | 'attachments' | 'onRemoveAttachment' | 'onAttach' | 'accept' | 'hint' | 'disabled'> {\n  /** Oldest first. You own the list: add the person's message in `onSend`, then the agent's as it arrives. */\n  messages: ChatMessage[];\n  /** Shown above the agent's messages and used in labels. Default \"Assistant\". */\n  agentName?: string;\n  /** Beside the agent's name, usually an Avatar. */\n  avatar?: ReactNode;\n  /** Called with the text when the person sends a message or chooses a suggestion. */\n  onSend?: (text: string) => void;\n  /** `working` turns Send into Stop. Default `ready`. */\n  status?: 'ready' | 'working';\n  onStop?: () => void;\n  /** Starting points above the input. Choosing one sends it. */\n  suggestions?: string[];\n  /** Shown in place of the messages when there are none. */\n  empty?: ReactNode;\n  /** After the last message, inside the scrolling list: an ApprovalPrompt, a DiffReview, a tool call. */\n  children?: ReactNode;\n  /** Height of the whole chat. Default fills its container. */\n  height?: number | string;\n  className?: string;\n}\n\n/**\n * A whole conversation with an agent: the messages, starting suggestions and the input. It follows new\n * messages until the person scrolls up, and announces each finished reply once, not every streamed word.\n */\nexport function Chat({\n  messages,\n  agentName = 'Assistant',\n  avatar,\n  onSend,\n  status = 'ready',\n  onStop,\n  suggestions,\n  empty,\n  children,\n  height,\n  className,\n  ...prompt\n}: ChatProps) {\n  const last = messages[messages.length - 1];\n  const replied = last?.from === 'assistant' && (last.status ?? 'done') === 'done' ? last.id : undefined;\n\n  return (\n    <div className={cx('cr-chat', className)} style={height === undefined ? undefined : { height }}>\n      <MessageList label={`Conversation with ${agentName}`}>\n        {messages.length === 0 && empty ? <div className=\"cr-chat__empty\">{empty}</div> : null}\n        {messages.map((m) => (\n          <Message key={m.id} from={m.from} name={m.from === 'assistant' ? agentName : undefined} avatar={avatar} status={m.status} actions={m.actions}>\n            {m.reasoning && (\n              <Reasoning seconds={m.reasoning.seconds} thinking={m.reasoning.thinking}>\n                {m.reasoning.content}\n              </Reasoning>\n            )}\n            {m.content}\n            {m.sources && m.sources.length > 0 && <Sources items={m.sources} />}\n          </Message>\n        ))}\n        {children}\n      </MessageList>\n      <div className=\"cr-chat__composer\">\n        {suggestions && suggestions.length > 0 && <Suggestions items={suggestions} onSelect={onSend} />}\n        <PromptInput label={`Message ${agentName}`} status={status} onSubmit={onSend} onStop={onStop} {...prompt} />\n      </div>\n      {/* Remounted for each finished reply, so the same words are announced again. */}\n      <LiveRegion key={replied ?? 'none'} message={replied ? `${agentName} replied` : ''} />\n    </div>\n  );\n}\n",
      "type": "registry:ui",
      "target": "@components/creance/chat/Chat.tsx"
    }
  ],
  "categories": [
    "organism",
    "chat"
  ],
  "type": "registry:ui"
}