ai-chat-waterfall
v1.0.1
Published
专为AI聊天界面设计的瀑布流核心逻辑包,跨框架兼容、流式渲染、无样式耦合
Maintainers
Readme
ai-chat-waterfall
专为 AI 聊天界面设计的瀑布流核心逻辑包,跨框架兼容、流式渲染、无样式耦合
✨ 核心特性
- 🎯 逻辑与样式完全解耦:仅输出布局数值/渲染时机控制,样式由开发者完全自定义
- 🔄 跨框架通用:基于原生 JS 封装核心逻辑,支持 React/Vue3/原生 JS/其他框架
- 🤖 AI 场景深度适配:支持打字机式流式渲染、按块追加、动态高度计算、自动滚动
- 🚀 生产级健壮性:包含错误处理、内存泄漏防护、大数据量性能优化(虚拟列表)
- 🎨 完整组件生态:提供 ProChat、ChatList、MessageInput 等开箱即用组件
- 🎭 对标 pro-chat:API 设计对标
@ant-design/pro-chat,支持流式推送、消息管理等 - 📦 体积小巧:核心逻辑仅 2.5KB (gzip),React 适配层 5.4KB,Vue 适配层 5.9KB
- 🎨 样式系统:提供默认样式和 CSS 变量,支持主题定制
📦 安装
npm install ai-chat-waterfall
# 可选:安装 marked 以获得完整的 Markdown 支持
npm install marked💡 提示:如果不安装
marked,包会使用内置的简单 Markdown 渲染器。安装marked后会自动使用,获得更完整的 Markdown 支持(表格、任务列表、GFM 等)。
🚀 快速开始
方式一:React 接入(推荐)
使用 ProChat 组件(完整功能)
import { ProChat } from 'ai-chat-waterfall/react';
import 'ai-chat-waterfall/dist/styles/index.css'; // 引入默认样式
function App() {
const chatRef = useRef();
const handleSend = async (content) => {
// 发送用户消息后,处理 AI 回复
const messageId = chatRef.current?.sendMessage(content, 'user');
// 模拟 API 调用
const response = await fetch('/api/chat', {
method: 'POST',
body: JSON.stringify({ message: content })
});
// 流式推送 AI 回复
const reader = response.body.getReader();
const decoder = new TextDecoder();
let aiMessageId = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
if (!aiMessageId) {
// 创建 AI 消息
chatRef.current?.pushChat({
content: chunk,
role: 'assistant'
});
aiMessageId = chatRef.current?.getChatLoadingId();
} else {
// 追加内容
chatRef.current?.pushChat({
id: aiMessageId,
content: chunk,
role: 'assistant'
});
}
}
};
return (
<div style={{ height: '600px' }}>
<ProChat
ref={chatRef}
initialMessages={[]}
onMessageSend={handleSend}
renderMessage={(msg) => (
<div style={{
padding: '12px',
background: msg.role === 'user' ? '#e3f2fd' : '#f5f5f5',
borderRadius: '8px'
}}>
{msg.content}
</div>
)}
/>
</div>
);
}使用独立组件
import { ChatList, MessageInput } from 'ai-chat-waterfall/react';
import { useState } from 'react';
function CustomChat() {
const [messages, setMessages] = useState([]);
const [loadingId, setLoadingId] = useState(null);
const handleSend = async (text) => {
// 添加用户消息
const userMsg = {
id: `user-${Date.now()}`,
role: 'user',
content: text,
createAt: Date.now(),
updateAt: Date.now()
};
setMessages(prev => [...prev, userMsg]);
// 添加 AI 消息(流式)
const aiMsgId = `ai-${Date.now()}`;
setMessages(prev => [...prev, {
id: aiMsgId,
role: 'assistant',
content: '',
isStreaming: true,
createAt: Date.now(),
updateAt: Date.now()
}]);
setLoadingId(aiMsgId);
// 模拟流式响应
// ... 处理流式数据
};
return (
<div style={{ display: 'flex', flexDirection: 'column', height: '600px' }}>
<ChatList
data={messages}
loadingId={loadingId}
renderMessage={(msg) => <div>{msg.content}</div>}
/>
<MessageInput
onConfirm={handleSend}
placeholder="输入消息..."
/>
</div>
);
}方式二:Vue 3 接入(推荐)
使用 ProChat 组件
<template>
<div style="height: 600px">
<ProChat
ref="chatRef"
:initial-messages="[]"
@message-send="handleSend"
@messages-change="handleMessagesChange"
/>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { ProChat } from 'ai-chat-waterfall/vue';
import 'ai-chat-waterfall/dist/styles/index.css';
const chatRef = ref();
const handleSend = async (content: string) => {
// 发送用户消息
chatRef.value?.sendMessage(content, 'user');
// 模拟流式推送
const chunks = ['这是', '一段', '流式', '回复内容。'];
for (const chunk of chunks) {
await new Promise(resolve => setTimeout(resolve, 100));
chatRef.value?.pushChat({
id: 'ai-response',
content: chunk,
role: 'assistant'
});
}
};
const handleMessagesChange = (messages: ChatMessage[]) => {
console.log('消息更新:', messages);
};
</script>使用独立组件
<template>
<div style="display: flex; flex-direction: column; height: 600px">
<ChatList
:data="messages"
:loading-id="loadingId"
/>
<MessageInput
v-model="inputText"
@confirm="handleSend"
placeholder="输入消息..."
/>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { ChatList, MessageInput } from 'ai-chat-waterfall/vue';
import type { ChatMessage } from 'ai-chat-waterfall';
const messages = ref<ChatMessage[]>([]);
const loadingId = ref<string | undefined>();
const inputText = ref('');
const handleSend = (text: string) => {
// 处理发送逻辑
messages.value.push({
id: `user-${Date.now()}`,
role: 'user',
content: text,
createAt: Date.now(),
updateAt: Date.now()
});
inputText.value = '';
};
</script>方式三:原生 JavaScript 接入
基础使用
<!DOCTYPE html>
<html>
<head>
<title>AI Chat Waterfall Demo</title>
</head>
<body>
<div id="chat-container" style="width: 100%; height: 500px; overflow-y: auto; display: flex; flex-direction: column; padding: 16px;"></div>
<script src="https://unpkg.com/ai-chat-waterfall/dist/ai-chat-waterfall.umd.js"></script>
<script>
const container = document.getElementById('chat-container');
const waterfall = new AIChatWaterfall(container, {
typewriterSpeed: 50,
autoScroll: true,
autoDetectHtml: true
});
// 添加用户消息
function addUserMessage(content) {
const messageEl = document.createElement('div');
messageEl.dataset.msgId = `user-${Date.now()}`;
messageEl.dataset.msgRole = 'user';
const layout = waterfall.calculateBubbleLayout(messageEl, 'user');
Object.assign(messageEl.style, {
...layout,
background: '#e3f2fd',
padding: '12px',
borderRadius: '8px',
marginBottom: layout.marginBottom
});
messageEl.textContent = content;
container.appendChild(messageEl);
}
// 添加 AI 消息(流式渲染)
function addAIMessage(content) {
const messageId = `ai-${Date.now()}`;
const messageEl = document.createElement('div');
messageEl.dataset.msgId = messageId;
messageEl.dataset.msgRole = 'ai';
const layout = waterfall.calculateBubbleLayout(messageEl, 'ai');
Object.assign(messageEl.style, {
...layout,
background: '#f5f5f5',
padding: '12px',
borderRadius: '8px',
marginBottom: layout.marginBottom
});
const contentEl = document.createElement('div');
messageEl.appendChild(contentEl);
container.appendChild(messageEl);
// 启动流式渲染
waterfall.streamRenderContent(messageId, contentEl, content);
}
// 使用示例
addUserMessage('你好!');
setTimeout(() => {
addAIMessage('你好!有什么可以帮助你的吗?');
}, 500);
</script>
</body>
</html>按块追加(适用于 SSE/WebSocket)
// 当 API 返回的是段落块时,使用 appendChunk
const contentEl = document.querySelector('#ai-message-content');
const messageId = 'ai-1';
// 模拟 SSE 事件流
const eventSource = new EventSource('/api/stream');
eventSource.onmessage = (event) => {
const chunk = event.data;
waterfall.appendChunk(messageId, contentEl, chunk);
};
eventSource.onclose = () => {
waterfall.finishChunkAppend(messageId);
};瀑布流布局(多列布局)
// 启用瀑布流布局
const waterfall = new AIChatWaterfall(container, {
waterfallLayout: true, // 启用瀑布流
waterfallColumns: 2, // 2列布局
waterfallColumnGap: 16, // 列间距16px
gap: 12 // 消息间距
});
// 创建消息时,布局会自动分配到最短的列
const layout = waterfall.calculateBubbleLayout(bubbleEl, 'ai');
// layout.columnIndex 会返回分配的列索引(0 或 1)
// layout.columnWidth 会返回列宽度
// 应用样式
bubbleEl.style.width = layout.columnWidth;
bubbleEl.style.position = 'absolute';
bubbleEl.style.left = `${layout.columnIndex * (parseInt(layout.columnWidth) + 16)}px`;📖 API 文档
核心类:AIChatWaterfall
构造函数
new AIChatWaterfall(container: HTMLElement, options?: AIChatWaterfallOptions)参数:
container: 容器 DOM 节点(必须)options: 配置选项(可选)
配置选项
interface AIChatWaterfallOptions {
// 基础配置
gap?: number; // 消息项间距(px),默认 12
typewriterSpeed?: number; // 打字机速度(ms/字),0 关闭逐字渲染,默认 50
autoScroll?: boolean; // 是否自动滚动到底部,默认 true
autoDetectHtml?: boolean; // 是否自动检测并渲染 HTML/Markdown,默认 true
// 虚拟列表配置
virtualScroll?: boolean; // 是否开启虚拟列表,默认 false
virtualItemHeight?: number; // 虚拟列表默认占位高度(px),默认 60
// 瀑布流布局配置
waterfallLayout?: boolean; // 是否启用瀑布流布局(多列布局),默认 false
waterfallColumns?: number; // 瀑布流列数,默认 2(仅在 waterfallLayout=true 时生效)
waterfallColumnGap?: number; // 瀑布流列间距(px),默认 16
// Markdown 配置
markdownRenderer?: (content: string) => string; // 自定义 Markdown 渲染器
// 回调函数
onStreamStart?: (streamId: string) => void; // 流式渲染开始回调
onStreamEnd?: (streamId: string) => void; // 流式渲染结束回调
onChunkAppended?: (streamId: string, chunk: string, totalContent: string) => void; // 块追加回调
onError?: (error: Error) => void; // 错误回调
onVirtualRangeChange?: (range: [number, number]) => void; // 虚拟列表可视区域变化回调
}核心方法
calculateBubbleLayout
计算单个聊天气泡的布局数值。
calculateBubbleLayout(bubbleEl: HTMLElement | null, role: 'user' | 'ai'): BubbleLayout返回:
interface BubbleLayout {
maxWidth: string; // 最大宽度(70% 容器宽度,瀑布流模式下为列宽度)
alignSelf: 'flex-start' | 'flex-end'; // 对齐方式
marginBottom: string; // 底部间距
height?: string; // 高度(如果传入了 DOM 节点)
columnIndex?: number; // 瀑布流布局中的列索引(0-based)
columnWidth?: string; // 瀑布流布局中的列宽度
}示例:
const layout = waterfall.calculateBubbleLayout(bubbleEl, 'user');
// 只应用必要的样式,保留 CSS 类的 align-self
bubbleEl.style.maxWidth = layout.maxWidth;
bubbleEl.style.marginBottom = layout.marginBottom;streamRenderContent
AI 消息流式渲染(打字机效果)。
streamRenderContent(streamId: string, contentEl: HTMLElement, fullContent: string): Promise<void>参数:
streamId: 流式渲染唯一ID(建议用消息ID)contentEl: 消息内容 DOM 节点fullContent: 完整 AI 回复内容
示例:
await waterfall.streamRenderContent('ai-1', contentEl, '这是完整的 AI 回复内容...');appendChunk
按块追加内容(适用于 API 一段一段返回的场景)。
appendChunk(streamId: string, contentEl: HTMLElement, chunk: string): Promise<void>使用场景:
- SSE (Server-Sent Events) 流式响应
- WebSocket 实时推送
- 分块 API 响应
示例:
// SSE 示例
const eventSource = new EventSource('/api/stream');
eventSource.onmessage = (event) => {
waterfall.appendChunk('ai-1', contentEl, event.data);
};
eventSource.onclose = () => {
waterfall.finishChunkAppend('ai-1');
};finishChunkAppend
完成块追加,标记流式渲染结束。
finishChunkAppend(streamId: string): voidpauseStream / resumeStream / stopStream
控制流式渲染的暂停、恢复和停止。
pauseStream(streamId?: string): void
resumeStream(streamId: string, contentEl: HTMLElement, fullContent: string, resumeIndex?: number): void
stopStream(streamId: string): voidautoScrollToBottom
自动滚动到底部。
autoScrollToBottom(force?: boolean): voidgetMessageState
获取消息当前渲染状态。
getMessageState(msgId: string): AIChatMessageState | null返回:
interface AIChatMessageState {
realHeight?: number; // 消息气泡真实高度
isStreaming?: boolean; // 是否正在流式渲染
streamProgress?: number; // 流式渲染进度(0-1)
}destroy
销毁实例,清理所有状态/事件/定时器。
destroy(): voidChatStore:消息状态管理
消息状态管理核心类,提供完整的消息 CRUD 操作。
import { ChatStore } from 'ai-chat-waterfall';
const store = new ChatStore({
initialMessages: [],
onMessagesChange: (messages) => {
console.log('消息更新:', messages);
}
});
// 发送消息
const messageId = store.sendMessage('你好', 'user');
// 推送流式消息
store.pushChat({
id: 'ai-1',
content: 'AI 回复...',
role: 'assistant'
});
// 获取所有消息
const messages = store.getChats();
// 更新消息
store.setMessageContent('ai-1', '更新后的内容');
// 删除消息
store.deleteMessage('ai-1');
// 清空所有消息
store.clearMessage();ProChat 组件(对标 @ant-design/pro-chat)
完整的聊天组件,包含消息列表和输入框。
React 版本
import { ProChat, ProChatRef } from 'ai-chat-waterfall/react';
interface ProChatProps {
initialMessages?: ChatMessage[]; // 初始消息列表
messages?: ChatMessage[]; // 受控模式的消息列表
controlled?: boolean; // 是否受控模式
onMessageSend?: (content: string, role?: string) => void | Promise<void>; // 发送消息回调
onMessagesChange?: (messages: ChatMessage[]) => void; // 消息变化回调
inputAreaRender?: (defaultDom: ReactNode, onMessageSend: (content: string) => void) => ReactNode; // 自定义输入区域
inputRender?: (defaultDom: ReactNode, onMessageSend: (content: string) => void) => ReactNode; // 自定义输入框
renderMessage?: (message: ChatMessage) => ReactNode; // 自定义消息渲染
renderErrorMessage?: (message: ChatMessage) => ReactNode; // 自定义错误消息渲染
renderItem?: (message: ChatMessage, index: number) => ReactNode; // 自定义消息项渲染
style?: CSSProperties; // 样式
className?: string; // 类名
waterfallOptions?: AIChatWaterfallOptions; // 核心配置选项
}Vue 版本
import { ProChat } from 'ai-chat-waterfall/vue';
interface ProChatProps {
initialMessages?: ChatMessage[];
messages?: ChatMessage[];
controlled?: boolean;
onMessageSend?: (content: string, role?: string) => void | Promise<void>;
onMessagesChange?: (messages: ChatMessage[]) => void;
// ... 其他属性同 React 版本
}实例方法(通过 ref 访问)
interface ProChatRef {
// 消息查询
getChats: () => ChatMessage[]; // 获取所有消息
getChatById: (id: string) => ChatMessage | undefined; // 根据ID获取消息
getChatLoadingId: () => string | undefined; // 获取正在加载的消息ID
// 消息操作
sendMessage: (content: string, role?: AIChatMessageRole) => string; // 发送消息
pushChat: (chat: Partial<ChatMessage> & { content: string; role: string }) => void; // 推送新消息(流式)
setChat: (id: string, chat: Partial<ChatMessage>) => void; // 设置/更新消息
setMessageContent: (id: string, content: string) => void; // 设置消息内容
setMessageValue: <K extends keyof ChatMessage>(id: string, key: K, value: ChatMessage[K]) => void; // 设置消息属性
// 消息控制
resendMessage: (id: string) => void; // 重试消息
stopGenerateMessage: () => void; // 停止生成
deleteMessage: (id: string) => void; // 删除消息
clearMessage: () => void; // 清空所有消息
// 视图控制
scrollToBottom: () => void; // 滚动到底部
// 实例访问
getWaterfallInstance: () => AIChatWaterfall | null; // 获取核心实例
getStoreInstance: () => ChatStore | null; // 获取 Store 实例
}ChatList 组件
独立的聊天列表组件,用于显示消息列表。
React 版本
import { ChatList } from 'ai-chat-waterfall/react';
interface ChatListProps {
data: ChatMessage[]; // 消息数据
loadingId?: string; // 正在加载的消息ID
showTitle?: boolean; // 是否显示标题
renderMessage?: (message: ChatMessage) => ReactNode; // 自定义消息渲染
renderErrorMessage?: (message: ChatMessage) => ReactNode; // 自定义错误消息渲染
renderItem?: (message: ChatMessage, index: number) => ReactNode; // 自定义消息项渲染
renderActions?: (message: ChatMessage) => ReactNode; // 自定义操作按钮渲染
onMessageChange?: (id: string, content: string) => void; // 消息内容变化回调
onActionClick?: (action: string, message: ChatMessage) => void; // 操作按钮点击回调
style?: CSSProperties; // 样式
className?: string; // 类名
waterfallOptions?: AIChatWaterfallOptions; // 核心配置选项
}Vue 版本
import { ChatList } from 'ai-chat-waterfall/vue';
// Props 同 React 版本,使用 Vue 的 props 定义方式MessageInput 组件
独立的输入框组件,用于输入聊天消息。
React 版本
import { MessageInput } from 'ai-chat-waterfall/react';
interface MessageInputProps {
defaultValue?: string; // 默认值
value?: string; // 受控值
onChange?: (value: string) => void; // 值变化回调
onConfirm?: (text: string) => void; // 确认回调(点击发送或按 Enter)
onCancel?: () => void; // 取消回调
height?: number | 'auto' | string; // 高度
placeholder?: string; // 占位符
disabled?: boolean; // 是否禁用
renderButtons?: (text: string) => ReactNode; // 自定义按钮渲染
text?: { cancel?: string; confirm?: string }; // 按钮文本配置
style?: CSSProperties; // 样式
className?: string; // 类名
textareaClassName?: string; // 文本域类名
textareaStyle?: CSSProperties; // 文本域样式
}Vue 版本
import { MessageInput } from 'ai-chat-waterfall/vue';
// 使用 v-model 绑定值
<MessageInput
v-model="inputText"
@confirm="handleSend"
placeholder="输入消息..."
/>🎨 样式系统
引入默认样式
// React/Vue 项目
import 'ai-chat-waterfall/dist/styles/index.css';CSS 变量定制
所有样式都使用 CSS 变量,可以通过覆盖变量来定制主题:
:root {
/* 颜色变量 */
--ai-chat-primary-color: #1890ff;
--ai-chat-primary-hover: #40a9ff;
--ai-chat-primary-active: #096dd9;
--ai-chat-text-color: #333;
--ai-chat-text-secondary: #999;
--ai-chat-border-color: #e0e0e0;
--ai-chat-background: #fff;
--ai-chat-user-bubble-bg: #e3f2fd;
--ai-chat-ai-bubble-bg: #f5f5f5;
--ai-chat-error-color: #ff4d4f;
/* 间距变量 */
--ai-chat-gap: 12px;
--ai-chat-padding: 16px;
--ai-chat-padding-small: 8px;
/* 圆角变量 */
--ai-chat-border-radius: 8px;
--ai-chat-border-radius-small: 4px;
/* 字体变量 */
--ai-chat-font-size: 14px;
--ai-chat-font-size-small: 12px;
--ai-chat-line-height: 1.5;
/* 阴影变量 */
--ai-chat-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}自定义样式
所有组件都支持通过 className 和 style 属性自定义样式:
<ProChat
className="my-custom-chat"
style={{ height: '600px' }}
renderMessage={(msg) => (
<div className="my-custom-message">
{msg.content}
</div>
)}
/>💡 使用场景
场景一:OpenAI API 流式响应
// 使用 fetch 处理流式响应
const response = await fetch('/api/openai', {
method: 'POST',
body: JSON.stringify({ message: userMessage })
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
let fullContent = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
fullContent += chunk;
// 使用 appendChunk 实时更新
await waterfall.appendChunk('ai-1', contentEl, chunk);
}
waterfall.finishChunkAppend('ai-1');场景二:WebSocket 实时聊天
const ws = new WebSocket('wss://api.example.com/chat');
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.type === 'chunk') {
// 流式追加
waterfall.appendChunk(data.messageId, contentEl, data.content);
} else if (data.type === 'done') {
// 完成
waterfall.finishChunkAppend(data.messageId);
}
};场景三:SSE (Server-Sent Events)
const eventSource = new EventSource('/api/stream');
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);
waterfall.appendChunk(data.messageId, contentEl, data.chunk);
};
eventSource.addEventListener('done', (event) => {
const data = JSON.parse(event.data);
waterfall.finishChunkAppend(data.messageId);
eventSource.close();
});🔧 最佳实践
1. 消息 ID 管理
// ✅ 推荐:使用唯一且可预测的 ID
const messageId = `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
// ❌ 不推荐:使用简单的递增数字
let messageId = 1; // 可能导致 ID 冲突2. 流式渲染性能优化
// ✅ 推荐:使用 appendChunk 处理大块内容
for (const chunk of largeChunks) {
await waterfall.appendChunk(messageId, contentEl, chunk);
}
// ❌ 不推荐:逐字渲染超长内容
await waterfall.streamRenderContent(messageId, contentEl, veryLongContent); // 可能很慢3. 内存管理
// ✅ 推荐:组件卸载时销毁实例
useEffect(() => {
const waterfall = new AIChatWaterfall(container, options);
return () => {
waterfall.destroy(); // 清理资源
};
}, []);4. 错误处理
const waterfall = new AIChatWaterfall(container, {
onError: (error) => {
// 统一错误处理
console.error('Chat error:', error);
// 可以发送到错误监控服务
}
});📊 性能优化
虚拟列表
对于大量消息(> 100 条),建议开启虚拟列表:
const waterfall = new AIChatWaterfall(container, {
virtualScroll: true,
virtualItemHeight: 80, // 根据实际消息高度调整
onVirtualRangeChange: (range) => {
// 只渲染可视区域的消息
console.log('可视区域:', range);
}
});流式渲染优化
// 对于快速到达的流式数据,可以批量处理
let buffer = '';
const flushBuffer = () => {
if (buffer) {
waterfall.appendChunk(messageId, contentEl, buffer);
buffer = '';
}
};
// 每 100ms 刷新一次
setInterval(flushBuffer, 100);🆚 与 @ant-design/pro-chat 对比
| 特性 | ai-chat-waterfall | @ant-design/pro-chat | |------|-------------------|---------------------| | 框架支持 | React + Vue + 原生 JS | 仅 React | | 样式耦合 | 完全解耦 | 依赖 Ant Design | | 体积 | 核心 2.5KB (gzip) | 较大(包含 Ant Design) | | 自定义能力 | 完全自定义 | 有限的自定义 | | 学习成本 | 低(API 简单) | 中等(需要了解 Ant Design) | | 适用场景 | 所有框架项目 | React + Ant Design 项目 |
🔧 开发
# 安装依赖
npm install
# 开发构建(包含 source map)
npm run build:dev
# 生产构建(无 source map,体积更小)
npm run build
# 类型检查
npm run type-check📝 版本历史
v1.0.0 (当前版本)
- ✅ 核心逻辑(布局计算 + 流式渲染 + 自动滚动)
- ✅ React 适配层(ProChat、ChatList、MessageInput)
- ✅ Vue 3 适配层(ProChat、ChatList、MessageInput)
- ✅ 消息状态管理(ChatStore)
- ✅ 按块追加支持(appendChunk)
- ✅ 瀑布流布局支持
- ✅ 默认样式系统
- ✅ 虚拟列表支持
计划中的功能
- 🔄 消息折叠/展开
- 🔄 多语言适配
- 🔄 更多 UI 组件(工具栏、操作按钮等)
- 🔄 消息搜索功能
- 🔄 消息导出功能
🤝 贡献
欢迎提交 Issue 和 Pull Request!
📄 许可证
MIT
Made with ❤️ for AI Chat Applications
