ds-markdown 1.0.0-beta.1 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +335 -512
- package/README.zh.md +938 -0
- package/es/Markdown/index.d.ts +1 -1
- package/es/MarkdownCMD/index.d.ts +1 -1
- package/es/components/CodeComponent/BlockWrap/index.d.ts +1 -1
- package/es/components/CodeComponent/index.d.ts +1 -1
- package/es/components/TableComponent/index.d.ts +1 -1
- package/es/components/ui/IconButton/index.d.ts +1 -1
- package/es/components/ui/Segmented/index.d.ts +1 -1
- package/es/components/ui/SuccessButton/index.d.ts +1 -1
- package/es/context/ConfigProvider/index.d.ts +2 -2
- package/es/context/MarkdownProvider.d.ts +1 -1
- package/es/context/MarkdownThemeProvider.d.ts +1 -1
- package/es/defined/index.d.ts +1 -1
- package/es/i18n/index.d.ts +6 -6
- package/es/index.d.ts +18 -18
- package/es/plugins/index.d.ts +2 -2
- package/es/utils/compiler.d.ts +1 -1
- package/package.json +3 -4
- package/README.en.md +0 -753
package/README.zh.md
ADDED
|
@@ -0,0 +1,938 @@
|
|
|
1
|
+
# ds-markdown
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src="./assets/images/favicon.png" alt="ds-markdown logo" width="120" />
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
> 🚀 React Markdown 打字动画组件,提供现代聊天界面效果
|
|
8
|
+
|
|
9
|
+
**🇨🇳 中文 | [🇺🇸 English](./README.en.md)**
|
|
10
|
+
|
|
11
|
+
一个专为现代 AI 应用设计的 React 组件,提供流畅的实时打字动画和完整的 Markdown 渲染能力。
|
|
12
|
+
|
|
13
|
+
[](https://www.npmjs.com/package/ds-markdown)
|
|
14
|
+
[](https://www.npmjs.com/package/ds-markdown)
|
|
15
|
+
[](https://bundlephobia.com/package/ds-markdown)
|
|
16
|
+
[](https://react.dev)
|
|
17
|
+
[](https://www.typescriptlang.org/)
|
|
18
|
+
|
|
19
|
+
- [使用文档](https://onshinpei.github.io/ds-markdown/)
|
|
20
|
+
- 使用示例
|
|
21
|
+
- [基本用法](https://stackblitz.com/edit/vitejs-vite-ddfw8avb?file=src%2FApp.tsx)
|
|
22
|
+
- [流式数据用法](https://stackblitz.com/edit/vitejs-vite-2ri8kex3?file=src%2FApp.tsx)
|
|
23
|
+
- [mermaid图表](https://stackblitz.com/edit/vitejs-vite-iqbyta3j?file=index.html)
|
|
24
|
+
- [数学公式demo1](https://stackblitz.com/edit/vitejs-vite-iqbyta3j?file=index.html)
|
|
25
|
+
- [数学公式demo2](https://stackblitz.com/edit/vitejs-vite-xk9lxagc?file=src%2FApp.tsx)
|
|
26
|
+
|
|
27
|
+
如果你想要一个纯净的`react markdown` 打字组件,可以使用[react-markdown-typer](https://github.com/onshinpei/react-markdown-typer)
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## 为什么要用 ds-markdown?
|
|
32
|
+
|
|
33
|
+
### 🎯 **解决的核心问题**
|
|
34
|
+
|
|
35
|
+
- **流式数据打字卡顿问题**
|
|
36
|
+
传统打字机组件在处理 AI 后端流式数据时,由于每个 chunk 包含多个字符,会出现卡顿、跳字等问题。ds-markdown 智能拆分每个 chunk,确保每个字符都流畅打字。
|
|
37
|
+
|
|
38
|
+
- **Markdown 渲染与打字动画割裂**
|
|
39
|
+
大多数打字机组件只支持纯文本,无法在打字过程中实时渲染 Markdown 语法、数学公式、图表等富媒体内容。
|
|
40
|
+
|
|
41
|
+
### 🚀 **带来的价值**
|
|
42
|
+
|
|
43
|
+
- **提升用户沉浸感**
|
|
44
|
+
提供专业级 AI 聊天体验,让用户感受到真实的 AI 交互过程,极大提升产品专业度和用户满意度。
|
|
45
|
+
|
|
46
|
+
- **开箱即用,降低开发复杂度**
|
|
47
|
+
完整的解决方案,无需额外配置即可支持流式数据、Markdown 渲染、数学公式、图表等复杂功能。
|
|
48
|
+
|
|
49
|
+
- **适配多种应用场景**
|
|
50
|
+
从 AI 聊天机器人到教育内容展示,从技术文档到产品演示,一个组件满足多种需求。
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## 目录
|
|
55
|
+
|
|
56
|
+
- [核心特性](#-核心特性)
|
|
57
|
+
- [快速安装](#-快速安装)
|
|
58
|
+
- [5分钟上手](#-5分钟上手)
|
|
59
|
+
- [基础用法](#基础用法)
|
|
60
|
+
- [禁用打字动画](#禁用打字动画)
|
|
61
|
+
- [数学公式支持](#数学公式支持)
|
|
62
|
+
- [AI 对话场景](#ai-对话场景)
|
|
63
|
+
- [代码块功能 🆕](#代码块功能-)
|
|
64
|
+
- [Mermaid图表支持](#mermaid图表支持)
|
|
65
|
+
- [完整 API 文档](#-完整-api-文档)
|
|
66
|
+
- [插件系统](#-插件系统)
|
|
67
|
+
- [内置插件](#内置插件)
|
|
68
|
+
- [KaTeX 数学公式插件](#katex-数学公式插件)
|
|
69
|
+
- [Mermaid 图表插件 🆕](#mermaid-图表插件-)
|
|
70
|
+
- [自定义插件](#自定义插件)
|
|
71
|
+
- [多语言配置](#多语言配置)
|
|
72
|
+
- [实战示例](#-实战示例)
|
|
73
|
+
- [最佳实践](#-最佳实践)
|
|
74
|
+
|
|
75
|
+
## 核心特性
|
|
76
|
+
|
|
77
|
+
### 🤖 **AI 对话场景**
|
|
78
|
+
|
|
79
|
+
- 专业级 AI 聊天响应效果,媲美主流 AI 平台体验
|
|
80
|
+
- 支持思考过程 (`thinking`) 和回答内容 (`answer`) 双模式
|
|
81
|
+
- 流式数据完美适配,零延迟响应用户输入
|
|
82
|
+
|
|
83
|
+
### 📊 **内容展示场景**
|
|
84
|
+
|
|
85
|
+
- 完整 Markdown 语法支持,包括代码高亮、表格、列表等
|
|
86
|
+
- 数学公式渲染 (KaTeX),支持 `$...$` 和 `\[...\]` 语法
|
|
87
|
+
- Mermaid 图表支持,包括流程图、序列图、甘特图、类图等 🆕
|
|
88
|
+
- 支持亮色/暗色主题,适配不同产品风格
|
|
89
|
+
- 插件化架构,支持 remark/rehype 插件扩展
|
|
90
|
+
|
|
91
|
+
### 🎨 **UI组件系统** 🆕
|
|
92
|
+
|
|
93
|
+
- 代码块、图表增强功能:复制、下载、语言等
|
|
94
|
+
- 内置丰富的UI组件:Button、IconButton、ToolTip、Segmented等
|
|
95
|
+
- 完整的交互体验和无障碍支持
|
|
96
|
+
|
|
97
|
+
### 🔧 **开发体验**
|
|
98
|
+
|
|
99
|
+
- 丰富的命令式API:`start`、`stop`、`resume`、`restart` 等
|
|
100
|
+
- 支持打字中断与继续,灵活控制动画状态
|
|
101
|
+
- 支持打字关闭与开启,满足不同场景需求
|
|
102
|
+
- 完整的TypeScript类型支持
|
|
103
|
+
|
|
104
|
+
### 🎬 **流畅动画**
|
|
105
|
+
|
|
106
|
+
- 双模式定时器优化,支持`requestAnimationFrame`和`setTimeout`模式
|
|
107
|
+
- 高频打字支持(`requestAnimationFrame`模式下打字间隔最低可接近于`0ms`)
|
|
108
|
+
- 帧同步渲染,与浏览器刷新完美配合
|
|
109
|
+
- 智能字符批量处理,视觉效果更自然
|
|
110
|
+
- **动态速度控制** 🆕:根据剩余字符数量自动调整打字速度,流式数据场景下提供更自然的阅读体验
|
|
111
|
+
|
|
112
|
+
### ⚡ **性能优化**
|
|
113
|
+
|
|
114
|
+
- 轻量级设计,体积小、性能优
|
|
115
|
+
- 核心依赖 [react-markdown](https://github.com/remarkjs/react-markdown),无重量级依赖
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## 📦 快速安装
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
# npm
|
|
123
|
+
npm install ds-markdown
|
|
124
|
+
|
|
125
|
+
# yarn
|
|
126
|
+
yarn add ds-markdown
|
|
127
|
+
|
|
128
|
+
# pnpm
|
|
129
|
+
pnpm add ds-markdown
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## 🚀 5分钟上手
|
|
133
|
+
|
|
134
|
+
> ✅ v1.0+版本开始,无需再手动 `import 'ds-markdown/style.css'`,组件会自动注入所需的基础样式。
|
|
135
|
+
|
|
136
|
+
### 基础用法
|
|
137
|
+
|
|
138
|
+
[DEMO](https://stackblitz.com/edit/vitejs-vite-z94syu8j?file=src%2FApp.tsx)
|
|
139
|
+
|
|
140
|
+
```tsx
|
|
141
|
+
import DsMarkdown from 'ds-markdown';
|
|
142
|
+
|
|
143
|
+
function App() {
|
|
144
|
+
return (
|
|
145
|
+
<DsMarkdown interval={20} answerType="answer">
|
|
146
|
+
# Hello ds-markdown 这是一个**高性能**的打字动画组件! ## 特性 - ⚡ 零延迟流式处理 - 🎬 流畅打字动画 - 🎯 完美语法支持
|
|
147
|
+
</DsMarkdown>
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### 禁用打字动画
|
|
153
|
+
|
|
154
|
+
```tsx
|
|
155
|
+
import DsMarkdown from 'ds-markdown';
|
|
156
|
+
|
|
157
|
+
function StaticDemo() {
|
|
158
|
+
const [disableTyping, setDisableTyping] = useState(false);
|
|
159
|
+
|
|
160
|
+
return (
|
|
161
|
+
<div>
|
|
162
|
+
<button onClick={() => setDisableTyping(!disableTyping)}>{disableTyping ? '开启' : '关闭'}打字机效果</button>
|
|
163
|
+
|
|
164
|
+
<DsMarkdown interval={20} answerType="answer" disableTyping={disableTyping}>
|
|
165
|
+
# 静态展示模式 当 `disableTyping` 为 `true` 时,内容会立即全部显示,无打字动画效果。 这在某些场景下非常有用: - 📄 静态文档展示 - 🔄 切换显示模式 - ⚡ 快速预览内容
|
|
166
|
+
</DsMarkdown>
|
|
167
|
+
</div>
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### 数学公式支持
|
|
173
|
+
|
|
174
|
+
```tsx
|
|
175
|
+
import DsMarkdown from 'ds-markdown';
|
|
176
|
+
// 如果需要展示公式,则需要引入公式转换插件
|
|
177
|
+
import { katexPlugin } from 'ds-markdown/plugins';
|
|
178
|
+
import 'ds-markdown/style.css';
|
|
179
|
+
// 如果需要展示公式,则需要引入数学公式样式
|
|
180
|
+
import 'ds-markdown/katex.css';
|
|
181
|
+
|
|
182
|
+
function MathDemo() {
|
|
183
|
+
return (
|
|
184
|
+
<DsMarkdown interval={20} answerType="answer" plugins={[katexPlugin]} math={{ splitSymbol: 'dollar' }}>
|
|
185
|
+
# 勾股定理 在直角三角形中,斜边的平方等于两条直角边的平方和: $a^2 + b^2 = c^2$ 其中: - $a$ 和 $b$ 是直角边 - $c$ 是斜边 对于经典的"勾三股四弦五": $c = \sqrt{3 ^ (2 + 4) ^ 2} = \sqrt{25} = 5$
|
|
186
|
+
</DsMarkdown>
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### AI 对话场景
|
|
192
|
+
|
|
193
|
+
```tsx
|
|
194
|
+
function ChatDemo() {
|
|
195
|
+
const [thinking, setThinking] = useState('');
|
|
196
|
+
const [answer, setAnswer] = useState('');
|
|
197
|
+
|
|
198
|
+
const handleAsk = () => {
|
|
199
|
+
setThinking('🤔 正在思考您的问题...');
|
|
200
|
+
|
|
201
|
+
setTimeout(() => {
|
|
202
|
+
setAnswer(`# 关于 React 19
|
|
203
|
+
|
|
204
|
+
React 19 带来了许多激动人心的新特性:
|
|
205
|
+
|
|
206
|
+
## 🚀 主要更新
|
|
207
|
+
1. **React Compiler** - 自动优化性能
|
|
208
|
+
2. **Actions** - 简化表单处理
|
|
209
|
+
3. **Document Metadata** - 内置 SEO 支持
|
|
210
|
+
|
|
211
|
+
让我们一起探索这些新功能!`);
|
|
212
|
+
}, 2000);
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
return (
|
|
216
|
+
<div>
|
|
217
|
+
<button onClick={handleAsk}>询问 AI</button>
|
|
218
|
+
|
|
219
|
+
{thinking && (
|
|
220
|
+
<DsMarkdown answerType="thinking" interval={30}>
|
|
221
|
+
{thinking}
|
|
222
|
+
</DsMarkdown>
|
|
223
|
+
)}
|
|
224
|
+
|
|
225
|
+
{answer && (
|
|
226
|
+
<DsMarkdown answerType="answer" interval={15}>
|
|
227
|
+
{answer}
|
|
228
|
+
</DsMarkdown>
|
|
229
|
+
)}
|
|
230
|
+
</div>
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### 代码块功能 🆕
|
|
236
|
+
|
|
237
|
+
```tsx
|
|
238
|
+
import DsMarkdown from 'ds-markdown';
|
|
239
|
+
|
|
240
|
+
function CodeBlockDemo() {
|
|
241
|
+
const codeContent = `# Hello World
|
|
242
|
+
|
|
243
|
+
\`\`\`javascript
|
|
244
|
+
function greet(name) {
|
|
245
|
+
console.log(\`Hello, \${name}!\`);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
greet('ds-markdown');
|
|
249
|
+
\`\`\`
|
|
250
|
+
|
|
251
|
+
支持代码高亮、复制和下载功能!`;
|
|
252
|
+
|
|
253
|
+
return (
|
|
254
|
+
<DsMarkdown
|
|
255
|
+
interval={20}
|
|
256
|
+
answerType="answer"
|
|
257
|
+
codeBlock={{
|
|
258
|
+
headerActions: true, // 启用代码块头部操作按钮
|
|
259
|
+
}}
|
|
260
|
+
>
|
|
261
|
+
{codeContent}
|
|
262
|
+
</DsMarkdown>
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### Mermaid图表支持
|
|
268
|
+
|
|
269
|
+
[DEMO](https://stackblitz.com/edit/vitejs-vite-iqbyta3j?file=README.md)
|
|
270
|
+
|
|
271
|
+
```tsx
|
|
272
|
+
import DsMarkdown from 'ds-markdown';
|
|
273
|
+
import { ConfigProvider } from 'ds-markdown';
|
|
274
|
+
import mermaidPlugin from 'ds-markdown-mermaid-plugin';
|
|
275
|
+
import 'ds-markdown/style.css';
|
|
276
|
+
|
|
277
|
+
function MermaidDemo() {
|
|
278
|
+
const chartContent = `以下是简化版的学习开车流程图,仅保留 **最核心步骤**,适合快速掌握关键节点:
|
|
279
|
+
|
|
280
|
+
\`\`\`mermaid
|
|
281
|
+
graph TD
|
|
282
|
+
A[开始] --> B[科目一: 理论考试]
|
|
283
|
+
B --> C[科目二: 场地五项]
|
|
284
|
+
C --> D[科目三: 路考]
|
|
285
|
+
D --> E[科目四: 安全笔试]
|
|
286
|
+
E --> F[拿驾照]
|
|
287
|
+
F --> G[实际驾驶练习]
|
|
288
|
+
\`\`\`
|
|
289
|
+
|
|
290
|
+
### 极简说明:
|
|
291
|
+
1. **理论先行**:先通过交通规则笔试(科目一)。
|
|
292
|
+
2. **场地基础**:练习倒车、坡起等(科目二)。
|
|
293
|
+
3. **上路实战**:实际道路驾驶考试(科目三)。
|
|
294
|
+
4. **安全收尾**:通过科目四即可领证。
|
|
295
|
+
5. **持续熟练**:拿证后继续练习适应真实路况。
|
|
296
|
+
|
|
297
|
+
### 可视化建议:
|
|
298
|
+
- 用手机备忘录或白纸手绘时,按 **箭头顺序** 写步骤即可。
|
|
299
|
+
- 想更直观?用圆形便签贴出每个科目,连线成流程。`;
|
|
300
|
+
|
|
301
|
+
return (
|
|
302
|
+
<ConfigProvider>
|
|
303
|
+
<DsMarkdown interval={20} answerType="answer" plugins={[mermaidPlugin]}>
|
|
304
|
+
{chartContent}
|
|
305
|
+
</DsMarkdown>
|
|
306
|
+
</ConfigProvider>
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+

|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
## 📚 完整 API 文档
|
|
316
|
+
|
|
317
|
+
### 默认导出 DsMarkdown 和 MarkdownCMD 的 props
|
|
318
|
+
|
|
319
|
+
```js
|
|
320
|
+
import DsMarkdown, { MarkdownCMD } from 'ds-markdown';
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
| 属性 | 类型 | 说明 | 默认值 |
|
|
324
|
+
| ------------------- | ------------------------------------------- | ------------------------------------------------------------- | ----------------------------------------------------------- |
|
|
325
|
+
| `interval` | `number` \| `IntervalConfig` | 打字间隔配置,支持固定间隔或动态速度控制 | `30` |
|
|
326
|
+
| `timerType` | `'setTimeout'` \| `'requestAnimationFrame'` | 定时器类型,不支持动态修改 | 当前默认值是`setTimeout`,后期会改为`requestAnimationFrame` |
|
|
327
|
+
| `answerType` | `'thinking'` \| `'answer'` | 内容类型 (影响样式主题),不支持动态修改 | `'answer'` |
|
|
328
|
+
| `theme` | `'light'` \| `'dark'` | 主题类型 | `'light'` |
|
|
329
|
+
| `plugins` | `IMarkdownPlugin[]` | 插件配置 | `[]` |
|
|
330
|
+
| `math` | [IMarkdownMath](#IMarkdownMath) | 数学公式配置 | `{ splitSymbol: 'dollar' }` |
|
|
331
|
+
| `onEnd` | `(data: EndData) => void` | 打字结束回调 | - |
|
|
332
|
+
| `onStart` | `(data: StartData) => void` | 打字开始回调 | - |
|
|
333
|
+
| `onBeforeTypedChar` | `(data: IBeforeTypedChar) => Promise<void>` | 字符打字前的回调,支持异步操作,会阻塞之后的打字 | - |
|
|
334
|
+
| `onTypedChar` | `(data: ITypedChar) => void` | 每字符打字后的回调 | - |
|
|
335
|
+
| `disableTyping` | `boolean` | 禁用打字动画效果 | `false` |
|
|
336
|
+
| `autoStartTyping` | `boolean` | 是否自动开始打字动画,设为 false 时需手动触发,不支持动态修改 | `true` |
|
|
337
|
+
| `codeBlock` | `IMarkdownCode` | 代码块配置 | `{headerActions: true}` |
|
|
338
|
+
|
|
339
|
+
> 注意:打字进行中将 `disableTyping` 从 `true` 改为 `false` 只会从当前位置继续,不会回放已跳过的动画;若需从头播放,请调用实例方法 `restart()`。
|
|
340
|
+
|
|
341
|
+
### IBeforeTypedChar
|
|
342
|
+
|
|
343
|
+
| 属性 | 类型 | 说明 | 默认值 |
|
|
344
|
+
| -------------- | ------------ | ---------------------------- | ------ |
|
|
345
|
+
| `currentIndex` | `number` | 当前字符在整个字符串中的索引 | `0` |
|
|
346
|
+
| `currentChar` | `string` | 当前即将打字的字符 | - |
|
|
347
|
+
| `answerType` | `AnswerType` | 内容类型 (thinking/answer) | - |
|
|
348
|
+
| `prevStr` | `string` | 当前类型内容的前缀字符串 | - |
|
|
349
|
+
| `percent` | `number` | 打字进度百分比 (0-100) | `0` |
|
|
350
|
+
|
|
351
|
+
### ITypedChar
|
|
352
|
+
|
|
353
|
+
| 属性 | 类型 | 说明 | 默认值 |
|
|
354
|
+
| -------------- | ------------ | ---------------------------- | ------ |
|
|
355
|
+
| `currentIndex` | `number` | 当前字符在整个字符串中的索引 | `0` |
|
|
356
|
+
| `currentChar` | `string` | 当前已打字的字符 | - |
|
|
357
|
+
| `answerType` | `AnswerType` | 内容类型 (thinking/answer) | - |
|
|
358
|
+
| `prevStr` | `string` | 当前类型内容的前缀字符串 | - |
|
|
359
|
+
| `currentStr` | `string` | 当前类型内容的完整字符串 | - |
|
|
360
|
+
| `percent` | `number` | 打字进度百分比 (0-100) | `0` |
|
|
361
|
+
|
|
362
|
+
#### IntervalConfig 🆕
|
|
363
|
+
|
|
364
|
+
| 属性 | 类型 | 说明 | 默认值 |
|
|
365
|
+
| --------- | ---------------------------------------------------------------------------------------------------------- | -------------------------------------- | -------- |
|
|
366
|
+
| `max` | `number` | 最大间隔时间 (毫秒),剩余字符多时使用 | - |
|
|
367
|
+
| `min` | `number` | 最小间隔时间 (毫秒),剩余字符少时使用 | - |
|
|
368
|
+
| `curveFn` | `(x: number) => number` | 自定义曲线函数,x 为剩余字符占比 [0,1] | - |
|
|
369
|
+
| `curve` | `'ease'` \| `'ease-in'` \| `'ease-out'` \| `'ease-in-out'` \| `'linear'` \| `'step-start'` \| `'step-end'` | 预设曲线函数,curveFn 存在时无效 | `'ease'` |
|
|
370
|
+
|
|
371
|
+
**动态速度控制说明:**
|
|
372
|
+
|
|
373
|
+
- **剩余字符越多,打字越快**:当后端流式推送大量字符时,组件会自动加快打字速度
|
|
374
|
+
- **剩余字符越少,打字越慢**:接近完成时,打字速度会逐渐放缓,提供更好的阅读体验
|
|
375
|
+
- **流式数据适配**:自动适应流式场景中字符数量的动态变化
|
|
376
|
+
- **曲线函数**:通过 `curve` 或 `curveFn` 控制速度变化曲线
|
|
377
|
+
|
|
378
|
+
**使用示例:**
|
|
379
|
+
|
|
380
|
+
```tsx
|
|
381
|
+
// 固定间隔
|
|
382
|
+
<DsMarkdown interval={20}>内容</DsMarkdown>
|
|
383
|
+
|
|
384
|
+
// 动态速度控制
|
|
385
|
+
<DsMarkdown
|
|
386
|
+
interval={{
|
|
387
|
+
min: 10, // 最快 10ms
|
|
388
|
+
max: 50, // 最慢 50ms
|
|
389
|
+
curve: 'ease-out' // 减速曲线
|
|
390
|
+
}}
|
|
391
|
+
>
|
|
392
|
+
内容
|
|
393
|
+
</DsMarkdown>
|
|
394
|
+
|
|
395
|
+
// 自定义曲线
|
|
396
|
+
<DsMarkdown
|
|
397
|
+
interval={{
|
|
398
|
+
min: 5,
|
|
399
|
+
max: 100,
|
|
400
|
+
curveFn: (x) => x * x // 二次函数曲线
|
|
401
|
+
}}
|
|
402
|
+
>
|
|
403
|
+
内容
|
|
404
|
+
</DsMarkdown>
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
#### IMarkdownMath
|
|
408
|
+
|
|
409
|
+
| 属性 | 类型 | 说明 | 默认值 |
|
|
410
|
+
| ------------- | ------------------------- | ------------------ | ---------- |
|
|
411
|
+
| `splitSymbol` | `'dollar'` \| `'bracket'` | 数学公式分隔符类型 | `'dollar'` |
|
|
412
|
+
|
|
413
|
+
**分隔符说明:**
|
|
414
|
+
|
|
415
|
+
- `'dollar'`:使用 `$...$` 和 `$$...$$` 语法
|
|
416
|
+
- `'bracket'`:使用 `\(...\)` 和 `\[...\]` 语法
|
|
417
|
+
|
|
418
|
+
#### IMarkdownCode 🆕
|
|
419
|
+
|
|
420
|
+
| 属性 | 类型 | 说明 | 默认值 |
|
|
421
|
+
| --------------- | --------- | -------------------- | ------ |
|
|
422
|
+
| `headerActions` | `boolean` | 是否显示头部操作按钮 | `true` |
|
|
423
|
+
|
|
424
|
+
#### IMarkdownPlugin
|
|
425
|
+
|
|
426
|
+
| 属性 | 类型 | 说明 | 默认值 |
|
|
427
|
+
| -------------- | ---------------------------------------------- | ----------------- | ------ |
|
|
428
|
+
| `remarkPlugin` | `Pluggable` | remark 插件 | - |
|
|
429
|
+
| `rehypePlugin` | `Pluggable` | rehype 插件 | - |
|
|
430
|
+
| `type` | `'buildIn'` \| `'custom'` | 插件类型 | - |
|
|
431
|
+
| `id` | `any` | 插件唯一标识 | - |
|
|
432
|
+
| `components` | `Record<string, React.ComponentType<unknown>>` | 自定义组件映射 🆕 | - |
|
|
433
|
+
|
|
434
|
+
### 组件暴露的方法
|
|
435
|
+
|
|
436
|
+
#### 默认导出 DsMarkdown
|
|
437
|
+
|
|
438
|
+
| 方法 | 参数 | 说明 |
|
|
439
|
+
| --------- | ---- | -------------------------------------- |
|
|
440
|
+
| `start` | - | 开始打字动画 |
|
|
441
|
+
| `stop` | - | 暂停打字动画 |
|
|
442
|
+
| `resume` | - | 恢复打字动画 |
|
|
443
|
+
| `restart` | - | 重新开始打字动画,从头开始播放当前内容 |
|
|
444
|
+
|
|
445
|
+
#### MarkdownCMD 暴露的方法
|
|
446
|
+
|
|
447
|
+
| 方法 | 参数 | 说明 |
|
|
448
|
+
| ----------------- | ------------------------------------------- | -------------------------------------- |
|
|
449
|
+
| `push` | `(content: string, answerType: AnswerType)` | 添加内容并开始打字 |
|
|
450
|
+
| `clear` | - | 清空所有内容和状态 |
|
|
451
|
+
| `triggerWholeEnd` | - | 手动触发完成回调 |
|
|
452
|
+
| `start` | - | 开始打字动画 |
|
|
453
|
+
| `stop` | - | 暂停打字动画 |
|
|
454
|
+
| `resume` | - | 恢复打字动画 |
|
|
455
|
+
| `restart` | - | 重新开始打字动画,从头开始播放当前内容 |
|
|
456
|
+
|
|
457
|
+
**用法示例:**
|
|
458
|
+
|
|
459
|
+
```tsx
|
|
460
|
+
markdownRef.current?.start(); // 开始动画
|
|
461
|
+
markdownRef.current?.stop(); // 暂停动画
|
|
462
|
+
markdownRef.current?.resume(); // 恢复动画
|
|
463
|
+
markdownRef.current?.restart(); // 重新开始动画
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
---
|
|
467
|
+
|
|
468
|
+
## 🔌 插件系统
|
|
469
|
+
|
|
470
|
+
### 内置插件
|
|
471
|
+
|
|
472
|
+
#### KaTeX 数学公式插件
|
|
473
|
+
|
|
474
|
+
[DEMO](https://stackblitz.com/edit/vitejs-vite-iqbyta3j?file=index.html)
|
|
475
|
+
|
|
476
|
+
```tsx
|
|
477
|
+
import { katexPlugin } from 'ds-markdown/plugins';
|
|
478
|
+
|
|
479
|
+
// 启用数学公式支持
|
|
480
|
+
<DsMarkdown plugins={[katexPlugin]}>数学公式:$E = mc^2$</DsMarkdown>;
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
#### Mermaid 图表插件 🆕
|
|
484
|
+
|
|
485
|
+
**安装 Mermaid 插件:**
|
|
486
|
+
|
|
487
|
+
```bash
|
|
488
|
+
npm install ds-markdown-mermaid-plugin
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
**基础用法:**
|
|
492
|
+
|
|
493
|
+
```tsx
|
|
494
|
+
import { ConfigProvider, Markdown } from 'ds-markdown';
|
|
495
|
+
import mermaidPlugin from 'ds-markdown-mermaid-plugin';
|
|
496
|
+
|
|
497
|
+
function App() {
|
|
498
|
+
const content = `
|
|
499
|
+
# 流程图示例
|
|
500
|
+
|
|
501
|
+
\`\`\`mermaid
|
|
502
|
+
flowchart TD
|
|
503
|
+
A[开始] --> B{判断条件}
|
|
504
|
+
B -->|是| C[处理A]
|
|
505
|
+
B -->|否| D[处理B]
|
|
506
|
+
C --> E[结束]
|
|
507
|
+
D --> E
|
|
508
|
+
\`\`\`
|
|
509
|
+
`;
|
|
510
|
+
|
|
511
|
+
return (
|
|
512
|
+
<ConfigProvider>
|
|
513
|
+
<Markdown plugins={[mermaidPlugin]}>{content}</Markdown>
|
|
514
|
+
</ConfigProvider>
|
|
515
|
+
);
|
|
516
|
+
}
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
**支持的图表类型:**
|
|
520
|
+
|
|
521
|
+
- 🔄 **流程图** (Flowchart) - 展示流程和决策路径
|
|
522
|
+
- 📋 **序列图** (Sequence Diagram) - 展示对象间的交互时序
|
|
523
|
+
- 📅 **甘特图** (Gantt Chart) - 项目计划和时间线
|
|
524
|
+
- 🏗️ **类图** (Class Diagram) - 面向对象设计
|
|
525
|
+
- 🥧 **饼图** (Pie Chart) - 数据比例展示
|
|
526
|
+
- 🔀 **状态图** (State Diagram) - 状态转换流程
|
|
527
|
+
- 📊 **Git图** (Git Graph) - 代码分支历史
|
|
528
|
+
- 🗺️ **用户旅程图** (User Journey) - 用户体验流程
|
|
529
|
+
|
|
530
|
+
**配置 Mermaid:**
|
|
531
|
+
|
|
532
|
+
```tsx
|
|
533
|
+
import { ConfigProvider } from 'ds-markdown';
|
|
534
|
+
|
|
535
|
+
const mermaidConfig = {
|
|
536
|
+
theme: 'default', // 主题:default, neutral, dark, forest
|
|
537
|
+
flowchart: {
|
|
538
|
+
useMaxWidth: true,
|
|
539
|
+
htmlLabels: true,
|
|
540
|
+
},
|
|
541
|
+
sequence: {
|
|
542
|
+
diagramMarginX: 50,
|
|
543
|
+
diagramMarginY: 10,
|
|
544
|
+
},
|
|
545
|
+
};
|
|
546
|
+
|
|
547
|
+
return (
|
|
548
|
+
<ConfigProvider mermaidConfig={mermaidConfig}>
|
|
549
|
+
<Markdown plugins={[mermaidPlugin]}>{chartContent}</Markdown>
|
|
550
|
+
</ConfigProvider>
|
|
551
|
+
);
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
**相关链接:**
|
|
555
|
+
|
|
556
|
+
- [ds-markdown-mermaid-plugin GitHub](https://github.com/onshinpei/ds-markdown-mermaid-plugin)
|
|
557
|
+
- [Mermaid 官方文档](https://mermaid.js.org/)
|
|
558
|
+
|
|
559
|
+
### 自定义插件
|
|
560
|
+
|
|
561
|
+
```tsx
|
|
562
|
+
import { createBuildInPlugin } from 'ds-markdown/plugins';
|
|
563
|
+
|
|
564
|
+
// 创建自定义插件
|
|
565
|
+
const customPlugin = createBuildInPlugin({
|
|
566
|
+
remarkPlugin: yourRemarkPlugin,
|
|
567
|
+
rehypePlugin: yourRehypePlugin,
|
|
568
|
+
id: Symbol('custom-plugin'),
|
|
569
|
+
components: {
|
|
570
|
+
// 自定义组件映射 🆕
|
|
571
|
+
CustomComponent: MyCustomComponent,
|
|
572
|
+
},
|
|
573
|
+
});
|
|
574
|
+
|
|
575
|
+
// 使用自定义插件
|
|
576
|
+
<DsMarkdown plugins={[katexPlugin, customPlugin]}>内容</DsMarkdown>;
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
---
|
|
580
|
+
|
|
581
|
+
## 🎨 UI组件系统 🆕
|
|
582
|
+
|
|
583
|
+
ds-markdown 提供了丰富的UI组件,可以单独使用或与markdown组件配合。
|
|
584
|
+
|
|
585
|
+
### 核心组件
|
|
586
|
+
|
|
587
|
+
```tsx
|
|
588
|
+
import {
|
|
589
|
+
Button,
|
|
590
|
+
IconButton,
|
|
591
|
+
ToolTip,
|
|
592
|
+
Segmented,
|
|
593
|
+
CopyButton,
|
|
594
|
+
DownloadButton
|
|
595
|
+
} from 'ds-markdown';
|
|
596
|
+
|
|
597
|
+
// 按钮组件
|
|
598
|
+
<Button icon={<span>📄</span>} onClick={() => {}}>
|
|
599
|
+
点击按钮
|
|
600
|
+
</Button>
|
|
601
|
+
|
|
602
|
+
// 工具提示
|
|
603
|
+
<ToolTip title="提示信息">
|
|
604
|
+
<IconButton icon={<span>📋</span>} onClick={() => {}} />
|
|
605
|
+
</ToolTip>
|
|
606
|
+
|
|
607
|
+
// 分段控制器
|
|
608
|
+
<Segmented
|
|
609
|
+
Segmented={[
|
|
610
|
+
{ label: '图表', value: 'diagram' },
|
|
611
|
+
{ label: '代码', value: 'code' }
|
|
612
|
+
]}
|
|
613
|
+
value={value}
|
|
614
|
+
onChange={setValue}
|
|
615
|
+
/>
|
|
616
|
+
|
|
617
|
+
// 代码块操作
|
|
618
|
+
<CopyButton codeContent="console.log('Hello')" />
|
|
619
|
+
<DownloadButton codeContent="console.log('Hello')" language="javascript" />
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
### 样式定制
|
|
623
|
+
|
|
624
|
+
```css
|
|
625
|
+
:root {
|
|
626
|
+
--ds-button-bg-color: #f5f5f5;
|
|
627
|
+
--ds-button-hover-color: #e0e0e0;
|
|
628
|
+
--ds-tooltip-bg-color: rgba(0, 0, 0, 0.8);
|
|
629
|
+
}
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
---
|
|
633
|
+
|
|
634
|
+
## 多语言配置
|
|
635
|
+
|
|
636
|
+
```tsx
|
|
637
|
+
import { ConfigProvider } from 'ds-markdown';
|
|
638
|
+
import zhCN from 'ds-markdown/i18n/zh';
|
|
639
|
+
import enUS from 'ds-markdown/i18n/en';
|
|
640
|
+
|
|
641
|
+
// 中文
|
|
642
|
+
<ConfigProvider locale={zhCN}>
|
|
643
|
+
<DsMarkdown {...props} />
|
|
644
|
+
</ConfigProvider>
|
|
645
|
+
|
|
646
|
+
// 英文
|
|
647
|
+
<ConfigProvider locale={enUS}>
|
|
648
|
+
<DsMarkdown {...props} />
|
|
649
|
+
</ConfigProvider>
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
---
|
|
653
|
+
|
|
654
|
+
## 📚 ConfigProvider API
|
|
655
|
+
|
|
656
|
+
`ConfigProvider` 是一个全局配置提供者,用于为 ds-markdown 组件提供多语言、Mermaid 图表和 KaTeX 数学公式的配置。
|
|
657
|
+
|
|
658
|
+
### Props 类型
|
|
659
|
+
|
|
660
|
+
```tsx
|
|
661
|
+
interface ConfigProviderProps {
|
|
662
|
+
locale?: Locale; // 语言包配置
|
|
663
|
+
mermaidConfig?: IMarkdownMermaidConfig; // Mermaid 图表配置
|
|
664
|
+
katexConfig?: IMarkdownKatexConfig; // KaTeX 数学公式配置
|
|
665
|
+
children: React.ReactNode; // 子组件
|
|
666
|
+
}
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
### 配置选项详解
|
|
670
|
+
|
|
671
|
+
#### 1. 多语言配置 (locale)
|
|
672
|
+
|
|
673
|
+
```tsx
|
|
674
|
+
import { ConfigProvider } from 'ds-markdown';
|
|
675
|
+
import zhCN from 'ds-markdown/i18n/zh';
|
|
676
|
+
import enUS from 'ds-markdown/i18n/en';
|
|
677
|
+
|
|
678
|
+
<ConfigProvider locale={zhCN}>
|
|
679
|
+
<DsMarkdown {...props} />
|
|
680
|
+
</ConfigProvider>;
|
|
681
|
+
```
|
|
682
|
+
|
|
683
|
+
#### 2. Mermaid 图表配置 (mermaidConfig)
|
|
684
|
+
|
|
685
|
+
```tsx
|
|
686
|
+
const mermaidConfig = {
|
|
687
|
+
theme: 'dark', // 主题:'default' | 'forest' | 'dark' | 'neutral'
|
|
688
|
+
fontFamily: 'Arial', // 字体
|
|
689
|
+
logLevel: 'warn', // 日志级别
|
|
690
|
+
securityLevel: 'strict', // 安全级别
|
|
691
|
+
startOnLoad: true, // 页面加载时自动启动
|
|
692
|
+
// ... 更多 Mermaid 配置选项
|
|
693
|
+
};
|
|
694
|
+
|
|
695
|
+
<ConfigProvider mermaidConfig={mermaidConfig}>
|
|
696
|
+
<DsMarkdown {...props} />
|
|
697
|
+
</ConfigProvider>;
|
|
698
|
+
```
|
|
699
|
+
|
|
700
|
+
#### 3. KaTeX 数学公式配置 (katexConfig)
|
|
701
|
+
|
|
702
|
+
```tsx
|
|
703
|
+
const katexConfig = {
|
|
704
|
+
throwOnError: false, // 错误时不抛出异常
|
|
705
|
+
errorColor: '#cc0000', // 错误颜色
|
|
706
|
+
macros: {
|
|
707
|
+
// 自定义宏
|
|
708
|
+
'\\RR': '\\mathbb{R}',
|
|
709
|
+
'\\NN': '\\mathbb{N}',
|
|
710
|
+
},
|
|
711
|
+
minRuleThickness: 0.05, // 最小规则厚度
|
|
712
|
+
colorIsTextColor: false, // 颜色是否为文本颜色
|
|
713
|
+
// ... 更多 KaTeX 配置选项
|
|
714
|
+
};
|
|
715
|
+
|
|
716
|
+
<ConfigProvider katexConfig={katexConfig}>
|
|
717
|
+
<DsMarkdown {...props} />
|
|
718
|
+
</ConfigProvider>;
|
|
719
|
+
```
|
|
720
|
+
|
|
721
|
+
### 使用 Hooks
|
|
722
|
+
|
|
723
|
+
#### useConfig
|
|
724
|
+
|
|
725
|
+
获取完整的配置上下文:
|
|
726
|
+
|
|
727
|
+
```tsx
|
|
728
|
+
import { useConfig } from 'ds-markdown';
|
|
729
|
+
|
|
730
|
+
function MyComponent() {
|
|
731
|
+
const { locale, mermaidConfig, katexConfig } = useConfig();
|
|
732
|
+
|
|
733
|
+
return (
|
|
734
|
+
<div>
|
|
735
|
+
<p>当前语言: {locale.language}</p>
|
|
736
|
+
<p>Mermaid 主题: {mermaidConfig?.theme}</p>
|
|
737
|
+
</div>
|
|
738
|
+
);
|
|
739
|
+
}
|
|
740
|
+
```
|
|
741
|
+
|
|
742
|
+
#### useLocale
|
|
743
|
+
|
|
744
|
+
仅获取语言包配置:
|
|
745
|
+
|
|
746
|
+
```tsx
|
|
747
|
+
import { useLocale } from 'ds-markdown';
|
|
748
|
+
|
|
749
|
+
function MyComponent() {
|
|
750
|
+
const locale = useLocale();
|
|
751
|
+
|
|
752
|
+
return (
|
|
753
|
+
<div>
|
|
754
|
+
<p>当前语言: {locale.language}</p>
|
|
755
|
+
<p>复制按钮文本: {locale.copyButton}</p>
|
|
756
|
+
</div>
|
|
757
|
+
);
|
|
758
|
+
}
|
|
759
|
+
```
|
|
760
|
+
|
|
761
|
+
### 完整配置示例
|
|
762
|
+
|
|
763
|
+
```tsx
|
|
764
|
+
import { ConfigProvider } from 'ds-markdown';
|
|
765
|
+
import zhCN from 'ds-markdown/i18n/zh';
|
|
766
|
+
|
|
767
|
+
const mermaidConfig = {
|
|
768
|
+
theme: 'dark',
|
|
769
|
+
fontFamily: 'Consolas, monospace',
|
|
770
|
+
logLevel: 'warn',
|
|
771
|
+
};
|
|
772
|
+
|
|
773
|
+
const katexConfig = {
|
|
774
|
+
throwOnError: false,
|
|
775
|
+
errorColor: '#cc0000',
|
|
776
|
+
macros: {
|
|
777
|
+
'\\RR': '\\mathbb{R}',
|
|
778
|
+
},
|
|
779
|
+
};
|
|
780
|
+
|
|
781
|
+
function App() {
|
|
782
|
+
return (
|
|
783
|
+
<ConfigProvider locale={zhCN} mermaidConfig={mermaidConfig} katexConfig={katexConfig}>
|
|
784
|
+
<DsMarkdown content="# Hello World" />
|
|
785
|
+
</ConfigProvider>
|
|
786
|
+
);
|
|
787
|
+
}
|
|
788
|
+
```
|
|
789
|
+
|
|
790
|
+
---
|
|
791
|
+
|
|
792
|
+
## 💡 实战示例
|
|
793
|
+
|
|
794
|
+
### 🚀 动态速度控制 🆕
|
|
795
|
+
|
|
796
|
+
```tsx
|
|
797
|
+
import DsMarkdown from 'ds-markdown';
|
|
798
|
+
|
|
799
|
+
function DynamicSpeedDemo() {
|
|
800
|
+
const content = `# 动态速度控制示例
|
|
801
|
+
|
|
802
|
+
这是一个演示动态速度控制的示例。当剩余字符较多时,打字速度会加快;
|
|
803
|
+
当剩余字符较少时,打字速度会放缓,提供更好的阅读体验。
|
|
804
|
+
|
|
805
|
+
## 流式数据场景
|
|
806
|
+
|
|
807
|
+
在 AI 流式对话中,后端可能会一次性推送大量文本,使用动态速度控制可以:
|
|
808
|
+
- 快速处理大量文本,减少等待时间
|
|
809
|
+
- 在接近完成时放缓速度,让用户有时间阅读
|
|
810
|
+
- 提供更自然的打字体验`;
|
|
811
|
+
|
|
812
|
+
return (
|
|
813
|
+
<DsMarkdown
|
|
814
|
+
interval={{
|
|
815
|
+
min: 8, // 最快 8ms(剩余字符多时)
|
|
816
|
+
max: 80, // 最慢 80ms(剩余字符少时)
|
|
817
|
+
curve: 'ease-out', // 减速曲线
|
|
818
|
+
}}
|
|
819
|
+
timerType="requestAnimationFrame"
|
|
820
|
+
>
|
|
821
|
+
{content}
|
|
822
|
+
</DsMarkdown>
|
|
823
|
+
);
|
|
824
|
+
}
|
|
825
|
+
```
|
|
826
|
+
|
|
827
|
+
### 📝 AI 流式对话
|
|
828
|
+
|
|
829
|
+
[DEMO: 🔧 StackBlitz 体验](https://stackblitz.com/edit/vitejs-vite-2ri8kex3?file=src%2FApp.tsx)
|
|
830
|
+
|
|
831
|
+
```tsx
|
|
832
|
+
import { useRef } from 'react';
|
|
833
|
+
import { MarkdownCMD, MarkdownCMDRef } from 'ds-markdown';
|
|
834
|
+
|
|
835
|
+
function StreamingChat() {
|
|
836
|
+
const markdownRef = useRef<MarkdownCMDRef>(null);
|
|
837
|
+
const answerRef = useRef<MarkdownCMDRef>(null);
|
|
838
|
+
const [isShowAnswer, setIsShowAnswer] = useState(false);
|
|
839
|
+
|
|
840
|
+
// 模拟 AI 流式响应
|
|
841
|
+
const simulateAIResponse = async () => {
|
|
842
|
+
markdownRef.current?.clear();
|
|
843
|
+
answerRef.current?.clear();
|
|
844
|
+
|
|
845
|
+
// 思考阶段
|
|
846
|
+
markdownRef.current?.push('🤔 正在分析您的问题...', 'thinking');
|
|
847
|
+
await delay(1000);
|
|
848
|
+
markdownRef.current?.push('\n\n✅ 分析完成,开始回答', 'thinking');
|
|
849
|
+
setIsShowAnswer(true);
|
|
850
|
+
// 流式回答
|
|
851
|
+
const chunks = [
|
|
852
|
+
'# React 19 新特性解析\n\n',
|
|
853
|
+
'## 🚀 React Compiler\n',
|
|
854
|
+
'React 19 最大的亮点是引入了 **React Compiler**:\n\n',
|
|
855
|
+
'- 🎯 **自动优化**:无需手动 memo 和 useMemo\n',
|
|
856
|
+
'- ⚡ **性能提升**:编译时优化,运行时零开销\n',
|
|
857
|
+
'- 🔧 **向后兼容**:现有代码无需修改\n\n',
|
|
858
|
+
'希望这个解答对您有帮助!🎉',
|
|
859
|
+
];
|
|
860
|
+
|
|
861
|
+
for (const chunk of chunks) {
|
|
862
|
+
await delay(100);
|
|
863
|
+
answerRef.current?.push(chunk, 'answer');
|
|
864
|
+
}
|
|
865
|
+
};
|
|
866
|
+
|
|
867
|
+
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
868
|
+
|
|
869
|
+
return (
|
|
870
|
+
<div className="chat-container">
|
|
871
|
+
<button onClick={simulateAIResponse}>🤖 询问 React 19 新特性</button>
|
|
872
|
+
<MarkdownCMD answerType="thinking" ref={markdownRef} interval={10} timerType="requestAnimationFrame" />
|
|
873
|
+
{isShowAnswer && <MarkdownCMD answerType="answer" ref={answerRef} interval={10} timerType="requestAnimationFrame" />}
|
|
874
|
+
</div>
|
|
875
|
+
);
|
|
876
|
+
}
|
|
877
|
+
```
|
|
878
|
+
|
|
879
|
+
## 🔧 最佳实践
|
|
880
|
+
|
|
881
|
+
### 1. 性能优化
|
|
882
|
+
|
|
883
|
+
```tsx
|
|
884
|
+
// ✅ 推荐配置
|
|
885
|
+
<DsMarkdown
|
|
886
|
+
timerType="requestAnimationFrame"
|
|
887
|
+
interval={15} // 15-30ms 为最佳体验
|
|
888
|
+
/>
|
|
889
|
+
|
|
890
|
+
// ✅ 流式数据推荐配置
|
|
891
|
+
<DsMarkdown
|
|
892
|
+
timerType="requestAnimationFrame"
|
|
893
|
+
interval={{
|
|
894
|
+
min: 8, // 快速处理大量文本
|
|
895
|
+
max: 60, // 接近完成时放缓
|
|
896
|
+
curve: 'ease-out' // 自然减速
|
|
897
|
+
}}
|
|
898
|
+
/>
|
|
899
|
+
```
|
|
900
|
+
|
|
901
|
+
### 2. 流式数据处理
|
|
902
|
+
|
|
903
|
+
```tsx
|
|
904
|
+
// ✅ 推荐:命令式 API
|
|
905
|
+
const ref = useRef<MarkdownCMDRef>(null);
|
|
906
|
+
useEffect(() => {
|
|
907
|
+
ref.current?.push(newChunk);
|
|
908
|
+
}, [newChunk]);
|
|
909
|
+
```
|
|
910
|
+
|
|
911
|
+
### 3. 数学公式优化
|
|
912
|
+
|
|
913
|
+
```tsx
|
|
914
|
+
// ✅ 推荐:按需加载
|
|
915
|
+
import { katexPlugin } from 'ds-markdown/plugins';
|
|
916
|
+
import 'ds-markdown/katex.css'; // 仅在需要时引入
|
|
917
|
+
|
|
918
|
+
<DsMarkdown plugins={[katexPlugin]}>数学公式内容</DsMarkdown>;
|
|
919
|
+
```
|
|
920
|
+
|
|
921
|
+
### 4. Mermaid图表最佳实践 🆕
|
|
922
|
+
|
|
923
|
+
```tsx
|
|
924
|
+
// ✅ 推荐:独立安装插件
|
|
925
|
+
npm install ds-markdown-mermaid-plugin
|
|
926
|
+
|
|
927
|
+
// ✅ 推荐:配置适合的主题
|
|
928
|
+
const mermaidConfig = {
|
|
929
|
+
theme: 'default', // 根据应用主题选择
|
|
930
|
+
flowchart: { useMaxWidth: true },
|
|
931
|
+
};
|
|
932
|
+
|
|
933
|
+
<ConfigProvider mermaidConfig={mermaidConfig}>
|
|
934
|
+
<DsMarkdown plugins={[mermaidPlugin]} />
|
|
935
|
+
</ConfigProvider>
|
|
936
|
+
```
|
|
937
|
+
|
|
938
|
+
[](https://visitorbadge.io/status?path=https%3A%2F%2Fgithub.com%2Fonshinpei%2Fds-markdown)
|