JGuang

聊天界面

Chat · Astryx

交互预览
npm install @astryxdesign/core@0.7.1 @astryxdesign/theme-neutral@0.7.1 @stylexjs/stylex@0.19.0

聊天界面 · Chat

组合消息、输入、工具调用和聊天布局;示例不连接真实 AI 服务。

安装与前置条件

npm install @astryxdesign/core@0.7.1 @astryxdesign/theme-neutral@0.7.1 @stylexjs/stylex@0.19.0

需要 React 19+,按顺序导入基础 CSS 和主题,并设置 Theme Provider。参见开始使用。

示例与使用方式

  • 聊天界面 · 综合展示 1:首先体验这个示例,再查看代码理解组件的组合方式。
  • 聊天界面 · 综合展示 2:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 综合展示 3:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 综合展示 4:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 多种状态 5:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 综合展示 6:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 综合展示 7:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 综合展示 8:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 综合展示 9:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 综合展示 10:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 综合展示 11:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 综合展示 12:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 综合展示 13:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 综合展示 14:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 交互示例 15:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 交互示例 16:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 交互示例 17:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 交互示例 18:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 交互示例 19:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 交互示例 20:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 交互示例 21:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 交互示例 22:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 受控交互 23:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 禁用状态 24:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 交互示例 25:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 交互示例 26:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 交互示例 27:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 交互示例 28:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 交互示例 29:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 输入校验 30:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 基础用法 31:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 交互示例 32:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 多种状态 33:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 尺寸变化 / 尺寸 34:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 交互示例 35:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 交互示例 36:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 交互示例 37:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 自定义 38:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 交互示例 39:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 分组 40:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 交互示例 41:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 样式变化 / 样式 42:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 交互示例 43:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 交互示例 44:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 交互示例 45:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 交互示例 46:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 状态 47:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 交互示例 48:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 交互示例 49:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 自定义 50:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 交互示例 51:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 多种状态 52:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 状态 53:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 样式变化 / 样式 54:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 包含图标 55:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 基础用法 56:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 交互示例 57:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 交互示例 58:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 状态 59:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
  • 聊天界面 · 交互示例 60:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。

API 与上游详细参考

优先使用 0.7.1 官方中文说明;上游尚未提供中文的条目保留英文。属性名、类型及默认值保持原生 API,不把示例状态名称当成组件属性。

Chat

Chat 是一组用于构建 AI 和人工聊天体验的可组合基础组件。组合 ChatLayout、ChatMessageList、ChatMessage、气泡、系统消息、工具调用、标记文本和 ChatComposer,可构建完整对话,而无需重新实现发送者感知布局、密度、滚动或编写器行为。

使用建议

  • 使用 MessageList > Message > Bubble 组合来获得一致的发送者感知样式和密度。
  • 设置 density 属性来全局控制间距:compact 用于侧边栏,balanced 用于大多数视图,spacious 用于长篇阅读。
  • 当同一发送者发送多条连续消息时,使用气泡的 group 属性(first、middle、last)来视觉上连接相关消息。
  • 使用 ChatSystemMessage 的 variant="divider" 作为日期分隔线,使用 default 作为内联状态通知。
  • 将 name 放在第一个气泡上,metadata 放在最后一个气泡上,使其与气泡的内边距对齐。
  • 将自定义消息内容(卡片、附件、引用)包裹在 ghost 变体的气泡中,使其与气泡文本列对齐;需要占满消息列宽度时设置 width="100%"。
  • 提供 emptyState 属性,让新用户看到开始对话的提示,而不是空白屏幕。
  • 使用 ghost 气泡变体显示代码块或 Markdown 等富内容,无需可见边界。
  • 避免:不要将 ChatSystemMessage 用于发送者内容,它没有头像、对齐或气泡。请使用带有发送者角色的 ChatMessage。
  • 避免:不要在系统消息中放置冗长或多行内容,保持一句简短的话。如需更多内容,请使用气泡或卡片。
  • 避免:不要将 ChatMessage 嵌套在另一个 ChatMessage 内,每条消息都是独立的 article 元素。
  • 避免:不要直接在消息列表上应用固定高度,将其包裹在有尺寸的容器中,让列表以 flex: 1 填充。
  • 避免:不要在同一发送者的消息中混用 filled 和 ghost 气泡变体,每一侧选择一种样式并保持一致。
  • 避免:不要同时在气泡和消息包装器上放置 metadata 或 name,根据内容是否有气泡边界来选择。

主题 API

{
  "targets": [
    {
      "className": "astryx-chat-layout",
      "visualProps": [
        "density"
      ]
    },
    {
      "className": "astryx-chat-composer",
      "visualProps": [
        "density"
      ]
    },
    {
      "className": "astryx-chat-composer-input"
    },
    {
      "className": "astryx-chat-composer-drawer",
      "visualProps": [
        "collapsed"
      ]
    },
    {
      "className": "astryx-chat-message",
      "visualProps": [
        "sender",
        "density"
      ]
    },
    {
      "className": "astryx-chat-message-bubble",
      "visualProps": [
        "sender",
        "variant",
        "density"
      ]
    },
    {
      "className": "astryx-chat-message-list",
      "visualProps": [
        "density"
      ]
    },
    {
      "className": "astryx-chat-system-message",
      "visualProps": [
        "variant"
      ]
    },
    {
      "className": "astryx-chat-message-metadata"
    },
    {
      "className": "astryx-chat-send-button"
    },
    {
      "className": "astryx-chat-dictation-button"
    },
    {
      "className": "astryx-chat-layout-scroll-button"
    },
    {
      "className": "astryx-chat-tokenized-text"
    },
    {
      "className": "astryx-chat-tool-calls"
    },
    {
      "className": "astryx-trigger-menu"
    }
  ],
  "vars": [
    {
      "name": "--_chat-composer-radius",
      "description": "Border radius of the composer body. Inner elements derive their radius concentrically.",
      "default": "var(--radius-chat)",
      "private": true
    },
    {
      "name": "--_chat-composer-padding",
      "description": "Padding of the composer body. Used in the concentric radius calculation.",
      "default": "var(--spacing-3)",
      "private": true
    },
    {
      "name": "--_button-radius",
      "description": "Concentric button radius inside the composer.",
      "default": "max(var(--radius-element), calc(var(--_chat-composer-radius) - var(--_chat-composer-padding)))",
      "private": true,
      "derived": true,
      "formula": "max(var(--radius-element), calc(var(--_chat-composer-radius) - var(--_chat-composer-padding)))"
    }
  ],
  "derived": [
    {
      "property": "borderRadius",
      "vars": [
        "--_chat-composer-radius"
      ]
    },
    {
      "property": "padding",
      "vars": [
        "--_chat-composer-padding"
      ]
    }
  ]
}

ChatMessageList

ChatMessage

ChatMessageBubble

ChatMessageMetadata

ChatSystemMessage

ChatComposer

ChatComposerInput

ChatComposerDrawer

ChatSendButton

ChatToolCalls

ChatTokenizedText

ChatComposerTokenElement

ChatLayout

ChatLayoutScrollButton

组件结构

  • Message area: Scrollable region for messages. Renders children (typically ChatMessageList) in a flex column that pushes content to the bottom when the list is short.
  • Frosted glass dock: Sticky or fixed container at the bottom with a backdrop-blur layer. Houses the scroll button and composer.
  • Scroll-to-bottom button: Appears when the user scrolls up or new messages arrive. Defaults to ChatLayoutScrollButton; pass null to hide or a custom element to override.
  • Composer: The input area for sending messages, typically ChatComposer. Docked at the bottom inside the frosted glass layer.
  • Empty state: Centered placeholder shown when no messages exist. Use EmptyState for a consistent look.

Chat Composer

ChatComposer is the message-entry shell for a chat surface. It coordinates a controlled or uncontrolled draft, provides a default token-capable input and send/stop action, and arranges optional drawer, header, footer, and status content. Custom inputs and send controls can join the same value, submission, disabled, stop, and focus contract through useChatComposerContext().

属性类型默认值说明
onSubmit *(value: string) => void用户提交消息时调用。
onStop() => void用户请求停止生成时调用。
isStopShownbooleanfalse是否显示停止按钮。
valuestring受控输入值。
onChange(value: string) => void受控模式的输入值变更时调用。序列化字符串包含标记占位符。
placeholderstring'Type a message...'输入为空时显示的占位文本。
isDisabledbooleanfalse禁用编写器。
density'compact' | 'balanced' | 'spacious''balanced'视觉密度。
elevation'none' | 'low''low'编写器主体的静止高度。low(默认)保持当前的抬起外观——静止时 low,悬停/聚焦时升至 med。none 会将其扁平化并绘制边框。编辑器通过键盘获得焦点时,两种呈现方式都会显示共享焦点环;指针聚焦不会显示该焦点环。
drawerReactNode插槽:输入上方的可折叠抽屉——附件、上下文标签等。使用 ChatComposerDrawer。
headerActionsReactNode插槽:标题左侧操作按钮(附件、提及按钮)。使用仅图标 size="sm" 按钮。
headerContextReactNode插槽:标题右侧上下文信息(上下文窗口使用情况、ProgressBar、辅助文本)。
inputReactNode插槽:自定义输入元素。替换默认输入。使用 ChatComposerInput 实现触发菜单/标记,或通过 useChatComposerContext() 将任意输入(纯 textarea、富文本编辑器)接入组合契约——读取 value/onChange/onSubmit/canSend,并在 inputControlRef 上注册聚焦控制,使点击空白处聚焦生效。
footerActionsReactNode插槽:左对齐的页脚操作(模型选择器等)。
sendActionsReactNode插槽:发送按钮左侧的操作。
sendButtonReactNode插槽:自定义发送按钮。替换默认的发送/停止按钮。
status{ type: 'error' | 'warning'; message?: string }编写器下方(或上方)的状态消息。
statusPosition'top' | 'bottom''bottom'状态渲染位置。

组件结构

  • Composer frame: Outer composition root that groups the body with an optional status message above or below it.
  • Composer body: Rounded, elevated surface containing the header, input, and footer.
  • Drawer: Content before the body for attachments or other expandable context, typically ChatComposerDrawer.
  • Header: Row for start-aligned actions and end-aligned contextual information.
  • Input: Default ChatComposerInput or a custom editor connected through useChatComposerContext().
  • Footer: Row for caller-supplied footer and send actions plus the primary action.
  • Send or stop action: Default ChatSendButton or a custom sendButton; it submits the current draft or requests interruption.
  • Status message: Error or warning feedback rendered before or after the composer body.

Chat Composer Drawer

Use ChatComposerDrawer in the ChatComposer drawer slot for supplementary content such as attachments, context chips, or previews. Provide count only when people should be able to collapse that content.

属性类型默认值说明
children *ReactNode抽屉内渲染的内容——标记、标签、预览或任何 React 元素。
countnumber折叠徽章中显示的总数。提供时,抽屉获得折叠/展开切换。
labelstring'Items'默认折叠摘要中显示在数量旁边的标签,并用于命名展开/折叠操作。
collapsedSummaryReactNode折叠摘要解剖部分的自定义视觉内容。提供 count 时替换默认的徽章和标签;组件仍负责折叠行为与无障碍命名,该内容仅用于展示。
isCollapsedboolean受控折叠状态。与 onCollapsedChange 一起使用。
defaultIsCollapsedbooleanfalse非受控模式的初始折叠状态。
onCollapsedChange(isCollapsed: boolean) => void用户切换抽屉时触发的回调。

使用建议

  • Give label a concrete plural noun such as "Attachments" so the expand and collapse actions have a useful accessible name.
  • Use controlled isCollapsed with onCollapsedChange when another part of the page owns drawer state; otherwise use defaultIsCollapsed.
  • 避免:Put primary composer actions in the drawer; use ChatComposer footer or send-action slots so those controls remain available when the drawer is collapsed.

主题 API

{
  "targets": [
    {
      "className": "astryx-chat-composer-drawer",
      "visualProps": [
        "collapsed"
      ]
    }
  ]
}

组件结构

  • Root surface: The drawer surface that composes above the ChatComposer body.
  • Disclosure toggle: The keyboard- and pointer-operable collapse control rendered when count is provided.
  • Collapsed summary: The default count Badge and label, or caller-provided visual content, presented while the drawer is collapsed.
  • Content area: The caller-provided supplementary content; collapsed descendants are unavailable to keyboard and assistive technology.

Chat Composer Input

Pass ChatComposerInput to ChatComposer's input slot when the draft needs trigger menus, inline tokens, history recall, dictation insertion, or file intake.

属性类型默认值说明
handleRefReact.Ref<ChatComposerInputHandle>命令式句柄,用于编程式控制:insertToken、expandToken、insertText、focus 和 getValue。
valuestring受控输入值。与 onChange 配对实现双向绑定。
onChange(value: string) => void输入值变更时调用。序列化字符串包含标记占位符。
placeholderstring'Type a message...'输入为空时显示的占位文本。
maxRowsnumber8滚动前的最大可见行数。紧凑布局中使用较小值。
triggersChatComposerTrigger[]菜单的触发定义。每个触发器指定字符(@ 或 /)、搜索源和返回要插入标记的 onSelect 处理器。每个触发器的 emptySearchText(ReactNode)用于查询无匹配结果时的提示。
debounceMsnumber150异步搜索源的去抖动延迟,避免过多网络请求。
hasHistorybooleantrue启用 ArrowUp/Down 回溯之前提交的消息。
labelstring'Message input'屏幕阅读器播报的无障碍标签。
isDisabledbooleanfalse禁用输入。在流式输出期间或前置条件未满足时使用。
onPaste(event, text) => boolean | void粘贴纯文本时调用。自行处理后返回 true;否则由 ChatComposerInput 插入文本或应用粘贴转标记行为。
pasteAsTokenUseChatPasteAsTokenReturn | false粘贴转标记行为。默认将超过 200 个字符的纯文本粘贴转为可展开标记;传入 false 可始终内联粘贴,或传入 useChatPasteAsToken() 结果来自定义转换。
onFiles(files: File[]) => void粘贴或拖放文件到输入时调用。用于处理附件。
onSubmit(value: string) => void用户不按 Shift 按 Enter 时调用。序列化值包含标记占位符。
onKeyDown(event) => void在内置 Enter/历史处理之前(在打开的触发菜单之后)调用的按键处理器。平台特定按键的接缝:调用 event.preventDefault() 可抑制默认提交(例如触控键盘上插入换行),或自行处理事件以添加行为(例如 Cmd/Ctrl+Enter 提交)。始终尊重输入法组字状态——组字过程中 Enter 永不提交。

使用建议

  • Use handleRef for programmatic text or token insertion; inserted text follows the same onChange pipeline as typing.
  • Use onFiles for files pasted or dropped onto the editor, and keep file validation and upload progress in the product layer.
  • 避免:Use custom token rendering for ordinary mentions or commands; prefer the structured badge form so tokens remain predictable and themeable.

组件结构

  • Input root: The themed container that forwards the root ref and BaseProps styling seams.
  • Editable surface: The labeled contenteditable textbox or combobox that owns text, selection, keyboard, paste, and drop behavior.
  • Placeholder: Visual guidance shown only while the serialized draft is empty.
  • Trigger menu: The suggestion popup rendered while a configured trigger is active.
  • Inline token: A non-editable badge or custom rendering with a stable serialized value.

Chat Composer Token Element

在 contentEditable 外部渲染标记芯片。

属性类型默认值说明
token *ChatComposerToken徽章配置或自定义渲染。

Chat Dictation Button

ChatDictationButton is a toggle button that starts and stops voice dictation inside a chat composer. It pairs with useChatDictation to show a microphone icon when idle and animated frequency bars when listening. Place it in the sendActions slot of ChatComposer.

属性类型默认值说明
dictation *UseSpeechRecognitionReturnThe return value from useChatDictation or useSpeechRecognition. Controls all button state.
size'sm' | 'md''md'Button size.
isHiddenWhenUnsupportedbooleantrueWhen true, hides unsupported dictation; when false, keeps a disabled button visible.
labelstringAccessible label override.
xstyleStyleXStylesAdditional StyleX styles.

使用建议

  • Place the dictation button in the sendActions slot of ChatComposer so it sits next to the send button where users expect voice input controls.
  • Pass an inputRef to useChatDictation so interim transcripts appear as ghost text in the composer input while the user speaks.
  • Enable hasSounds on useChatDictation to give users audio feedback when dictation starts and stops. This is especially helpful when the button's visual change is subtle.
  • 避免:Don't use the dictation button outside a chat composer context. It's designed for the composer's send-action layout, not as a standalone recording control.
  • 避免:Don't forget to handle the unsupported case. The button hides itself by default when the browser lacks SpeechRecognition, but you should still design the composer to work without it.

组件结构

  • Microphone icon: Shown in the idle state. Indicates that tapping will start voice input.
  • Frequency bars: Animated equalizer bars that replace the icon during listening. React to real microphone volume.
  • Ghost button: The underlying Button with ghost variant and isIconOnly, providing the hit target and focus ring.

Chat Layout

ChatLayout is the layout shell for full-page chat interfaces. It renders messages in normal page flow and docks the composer to the bottom with a frosted glass blur layer. Set the density prop to control spacing; it defaults to balanced. Use it to wrap ChatMessageList and ChatComposer for a complete chat experience with built-in auto-scroll and a scroll-to-bottom button.

属性类型默认值说明
children *ReactNode消息内容,通常是 ChatMessageList。在页面中自然流动。
composer *ReactNode编写器元素,通常是 ChatComposer。固定在底部,带有毛玻璃底座。
emptyStateReactNode子元素为空时显示的内容。
scrollButtonReactNode | null编写器上方的滚动到底部按钮。默认使用 ChatLayoutScrollButton。传入 null 隐藏。
scrollRefReact.RefObject<HTMLElement | null>外部滚动容器引用。提供时,自动滚动和滚动到底部将目标指向此元素。
density'compact' | 'balanced' | 'spacious''balanced'视觉密度:控制底座内边距、消息区最大宽度和毛玻璃层高度。

使用建议

  • Pass ChatMessageList as children and ChatComposer as the composer prop for a complete chat interface.
  • Provide an emptyState so new conversations show a prompt instead of a blank screen.
  • Use scrollRef when the chat is embedded in a page where a parent element handles scrolling.
  • 避免:Don't apply a fixed height on the layout; let it fill its container with flex: 1.
  • 避免:Don't render multiple ChatLayout instances in the same scroll container; each expects to own its scroll context.

组件结构

  • Message area: Scrollable region for messages. Renders children (typically ChatMessageList) in a flex column that pushes content to the bottom when the list is short.
  • Frosted glass dock: Sticky or fixed container at the bottom with a backdrop-blur layer. Houses the scroll button and composer.
  • Scroll-to-bottom button: Appears when the user scrolls up or new messages arrive. Defaults to ChatLayoutScrollButton; pass null to hide or a custom element to override.
  • Composer: The input area for sending messages, typically ChatComposer. Docked at the bottom inside the frosted glass layer.
  • Empty state: Centered placeholder shown when no messages exist. Use EmptyState for a consistent look.

Chat Layout Scroll Button

可组合的滚动到底部按钮。可见时淡入,提供标签时展开。

属性类型默认值说明
isVisible *boolean按钮是否可见。
labelstring可选标签,展开按钮(如"新消息")。
onClick *() => void点击处理器。

Chat Message

发送者上下文包装器,根据发送者角色处理头像、名称、元数据和对齐方式。

属性类型默认值说明
sender *'user' | 'assistant' | 'system'消息发送者,控制对齐和布局。
children *ReactNode自由内容:气泡、资源列表、工具调用、图片。非气泡的自定义子内容默认与消息边缘齐平,可用 ghost 变体的 ChatMessageBubble 包裹使其与气泡文本列对齐。
avatarReactNode消息旁边渲染的头像元素。通常是 Avatar。null、布尔值和空字符串不会创建槽位;其他不渲染任何内容的值会让槽位折叠。
nameReactNode消息正文上方渲染的发送者名称,并作为消息的标签。null、布尔值和空字符串不会创建槽位,其他不渲染任何内容的值会让槽位折叠;两种情况都改用本地化发送者标签。当第一个子元素不是气泡时使用。
metadataReactNode消息正文下方渲染的元数据。null、布尔值和空字符串不会创建槽位;其他不渲染任何内容的值会让槽位折叠。当最后一个子元素不是气泡时使用。
density'compact' | 'balanced' | 'spacious''balanced'视觉密度。未设置时从列表上下文继承。

Chat Message Bubble

样式化的气泡容器,从父上下文读取发送者信息进行自动样式化。支持 name/metadata 插槽、多气泡分组和透明变体。

属性类型默认值说明
children *ReactNode气泡内容:文本、Markdown 或任何 ReactNode。
variant'filled' | 'ghost''filled'视觉变体。'filled' 渲染发送者颜色背景,'ghost' 渲染透明背景但保持填充对齐。
nameReactNode气泡上方渲染的发送者名称,与气泡文本内边距对齐。null、undefined、布尔值和空字符串会省略对齐容器;数字 0 仍保持对齐。用于消息中的第一个气泡。
metadataReactNode气泡下方渲染的元数据内容,与气泡文本内边距对齐。null、undefined、布尔值和空字符串会省略对齐容器;数字 0 仍保持对齐。用于消息中的最后一个气泡。
group'first' | 'middle' | 'last'多气泡组中的位置。控制发送者侧的圆角缩减。
widthSizeValue气泡宽度(数字 = 像素,字符串 = 按原样使用)。设置后替代默认的 max(80%, 280px) 宽度上限;与 ghost 变体组合可让自定义内容占满消息列宽度。

Chat Message List

消息展示容器,支持密度上下文和无限滚动。自动滚动由 ChatLayout 管理。

属性类型默认值说明
children *ReactNode消息元素,通常是 ChatMessage 或 ChatSystemMessage。
emptyStateReactNode列表无消息时显示的内容。
scrollToTopAction() => Promise<void>用户滚动到顶部时触发的异步操作。用于加载更早的消息。
density'compact' | 'balanced' | 'spacious''balanced'视觉密度,通过上下文传递给子消息。
gap0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10顶层消息行之间的间距。默认跟随密度;当 LLM 事件流等独立行需要不同间距时可覆盖。
align'top' | 'bottom''bottom'列表内容不足一屏时的垂直对齐方式。'bottom' 用占位块填满剩余空间,让简短对话贴近输入框;'top' 省略占位块,让消息从顶部开始。仅影响未填满的列表,溢出后两种模式滚动一致,保持自动滚动到底部。
isStreamingbooleanfalse是否有助手消息正在流式输出。标记日志为 aria-busy,让屏幕阅读器等待并在完成后一次性播报,而不是每个 token 都重复播报。

Chat Message Metadata

Place ChatMessageMetadata below a message or in the last ChatMessageBubble metadata slot to show a timestamp, footer content, and optional delivery status. Non-rendering scalar slots (booleans and empty strings) create no separator; numeric zero remains visible. Composite React content remains caller-owned.

属性类型默认值说明
timestampReactNode时间戳内容,字符串或 Timestamp 组件。
footerReactNode页脚内容:模型信息、反应按钮、复制按钮。
status'sending' | 'sent' | 'delivered' | 'read' | 'error'消息发送状态。显示图标和标签。

使用建议

  • Put metadata in the last bubble metadata slot when the message uses bubbles, so it follows the bubble content.
  • Pass timestamp and footer content independently; separators are omitted for non-rendering scalar slots. Composite React nodes are used as supplied.
  • 避免:Do not supply footer actions without their own accessible names and interaction behavior; the metadata row does not own those controls.
  • 避免:Do not put the same metadata on both a bubble and its enclosing message.

组件结构

  • Metadata row: Sender-aware line containing the visible metadata items.
  • Timestamp: Caller-supplied time content at the start of the logical sequence.
  • Footer: Caller-supplied information or actions between time and status.
  • Status: Localized delivery icon and text when a status is supplied.

Chat Send Button

Use ChatSendButton as ChatComposer’s send control when the action should switch between sending and stopping. Inside ChatComposer it reads readiness, streaming state, and action callbacks from context; standalone usage supplies those values explicitly.

属性类型默认值说明
isStopShownboolean是否显示停止按钮。默认使用上下文值。
isDisabledboolean发送按钮是否禁用。默认使用上下文的 !canSend。
onSend() => void用户点击发送时调用。默认使用上下文的 onSubmit。
onStop() => void流式响应期间用户点击停止时调用。默认使用上下文的 onStop。
sendIconReactNode发送状态的自定义图标。默认使用图标注册表的 arrowUp。
stopIconReactNode停止状态的自定义图标。默认使用图标注册表的 stop。
size'sm' | 'md''md'按钮大小。
xstyleStyleXStyles额外的 StyleX 样式。

使用建议

  • Place ChatSendButton inside ChatComposer when its readiness and send or stop lifecycle should follow composer context.
  • For standalone use, provide the state and matching onSend or onStop callback explicitly.
  • Keep the translated Send or Stop accessible name intact when supplying custom icon artwork; the icon is decorative and must not be the only name source.
  • 避免:Do not render the stop state without a working onStop callback from props or ChatComposer context.
  • 避免:Do not expect isDisabled to disable the stop action; it applies only to the send state.

组件结构

  • Action button: Circular icon-only Button that exposes the translated Send or Stop name and carries the chat-send-button theme target.

Chat System Message

Use ChatSystemMessage for concise, non-sender content inside a chat transcript. Choose the default variant for factual status notices and the divider variant for date or section breaks. Long default content wraps within the available width. The component exposes status semantics and the divider branch includes a labelled separator.

属性类型默认值说明
children *ReactNode事实性系统消息内容,如日期、加入/离开通知或状态变更;较长的 default 内容会在可用宽度内换行。
variant'default' | 'divider''default'视觉变体。'default' 渲染居中文本。'divider' 通过 Divider 在两侧添加水平线,用于日期分隔和段落分隔。
iconReactNode可选的调用方图标内容。default 变体会在消息前渲染;divider 变体当前不会渲染。使用 Icon 包裹以获得一致的尺寸。
xstyleStyleXStyles用于布局自定义的 StyleX 样式。

使用建议

  • Keep the visible message concise and self-contained so it remains understandable without an icon.
  • Use the divider variant for temporal or section boundaries and the default variant for factual status notices.
  • 避免:Use ChatSystemMessage for sender-authored content; use ChatMessage and ChatMessageBubble instead.
  • 避免:Use caller-provided icon artwork as the only source of meaning; the visible message must carry the same information.

主题 API

{
  "targets": [
    {
      "className": "astryx-chat-system-message",
      "visualProps": [
        "variant"
      ]
    }
  ]
}

组件结构

  • System message: The noninteractive status row that carries the chat-system-message theme target.
  • Content: The concise caller-provided message or divider label.
  • Icon content: Rendered before the message in the default variant; the divider variant currently does not render it.
  • Divider: A labelled horizontal Divider rendered by the divider variant.

Chat Tokenized Text

Use ChatTokenizedText inside a chat message when stored plain text contains serialized token values that should be projected as inline badges or caller-rendered token content. Unmatched text is preserved exactly and empty token values are ignored so rendering always finishes.

属性类型默认值说明
children *string包含序列化标记值的纯文本消息。匹配标记值的模式将被替换为内联标记内容。
tokensChatComposerToken[]标记定义,与输入组件使用相同类型。空值会被忽略;其他值按调用者提供的顺序进行匹配。
xstyleStyleXStyles用于根文本包装器的额外 StyleX 样式。

使用建议

  • Reuse the same token definitions for composer insertion and message rendering so serialized values and visible labels stay aligned.
  • Use non-empty, stable serialized values so every definition identifies real message text.
  • 避免:Use token labels as a substitute for the surrounding message text; the complete message must remain understandable in reading order.
  • 避免:Put component-owned interaction or accessibility behavior inside a custom token renderer; custom token content remains caller owned.

主题 API

{
  "targets": [
    {
      "className": "astryx-chat-tokenized-text"
    }
  ]
}

组件结构

  • Tokenized text: The inline root that preserves unmatched text and carries the chat-tokenized-text theme target.
  • Rendered token: Inline token content rendered by Badge for structured tokens or by the caller for custom tokens.

Chat Tool Calls

ChatToolCalls displays tool or function call invocations from an LLM response. Pass an array of calls and the component handles the rest: a single call renders inline, while multiple calls collapse into a summary with the latest call visible at the surface. Use it anywhere an AI agent shows what actions it took.

属性类型默认值说明
calls *ChatToolCallItem[]工具调用数据数组。每项包含 name、status、target、duration、node、additions、deletions、stats、resultDetail。
labelstring组的自定义摘要标签。省略时从数量自动生成。
isExpandedboolean受控展开状态。
defaultIsExpandedbooleanfalse默认展开状态(非受控)。
onExpandedChange(isExpanded: boolean) => void展开状态变更时的回调。
xstyleStyleXStylesStyleX styles for layout customization (margins, positioning, sizing). Must be a stylex.create() value, not an inline style object like style={{}}.

使用建议

  • Include a target string on every call so the user can see what the tool acted on: a file path, a shell command, or a search query.
  • Show a duration on completed calls so users can judge which tools are slow and understand why a response took time.
  • Provide a group label when the automatic count does not explain what the calls represent.
  • Provide resultDetail with a code block for calls that produce output (diffs for edits, terminal output for shell commands) so users can inspect results inline.
  • Set a unique key on each call item when streaming so React can animate additions without re-mounting completed rows.
  • 避免:Don't omit the status field. Without it the call defaults to complete, which is misleading for calls that are still running or have failed.
  • 避免:Don't display tool calls outside a chat message context; they are designed to sit inside an assistant message, not as standalone UI.
  • 避免:Don't use custom wrappers around individual calls; the component handles single vs. grouped layout automatically based on the array length.

组件结构

  • Status icon: A themed semantic success/error icon, or a spinner while the call is pending or running.
  • Tool name: The function or tool name displayed in monospace: bash, edit, read, web_search, etc.
  • Node badge: A neutral pill badge showing which sandbox or environment ran the tool, like cli:remote-server or workspace.
  • Target label: The target of the action (a file path, command, or search query) shown after the tool name.
  • Diff stats: Green additions and red deletions counts for edit operations, displayed inline after the target.
  • Duration: Execution time shown on the trailing edge for completed calls.
  • Group header: A wrench icon with a call count, shown when multiple calls are present. Clicking toggles between the summary and the full list.

完整示例的额外依赖

部分示例使用独立图标包。示例清单中的每条安装命令包含该示例实际需要的依赖;若要运行本页全部示例,还需安装:

npm install @heroicons/react@2.2.0