ds-markdown 0.0.10-beta.2 → 0.0.10-beta.3
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 +234 -67
- package/dist/cjs/MarkdownCMD/index.js +103 -233
- package/dist/cjs/MarkdownCMD/index.js.map +1 -1
- package/dist/cjs/defined.d.ts +14 -0
- package/dist/cjs/hooks/useTypingTask.d.ts +31 -0
- package/dist/cjs/hooks/useTypingTask.js +226 -0
- package/dist/cjs/hooks/useTypingTask.js.map +1 -0
- package/dist/cjs/utils/rule.js +0 -1
- package/dist/cjs/utils/rule.js.map +1 -1
- package/dist/esm/MarkdownCMD/index.js +104 -234
- package/dist/esm/MarkdownCMD/index.js.map +1 -1
- package/dist/esm/defined.d.ts +14 -0
- package/dist/esm/hooks/useTypingTask.d.ts +31 -0
- package/dist/esm/hooks/useTypingTask.js +222 -0
- package/dist/esm/hooks/useTypingTask.js.map +1 -0
- package/dist/esm/utils/rule.js +0 -1
- package/dist/esm/utils/rule.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,40 +1,108 @@
|
|
|
1
1
|
# ds-markdown
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> 🚀 一个高性能的 React Markdown 打字动画组件,完美复刻 DeepSeek 聊天界面效果
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
`ds-markdown` 是一个专为现代 Web 应用设计的 React 组件,提供流畅的打字动画效果和完整的 Markdown 渲染能力。
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
[](https://www.npmjs.com/package/ds-markdown)
|
|
8
|
+
[](https://www.npmjs.com/package/ds-markdown)
|
|
9
|
+
[](https://bundlephobia.com/package/ds-markdown)
|
|
10
|
+
[](https://react.dev)
|
|
8
11
|
|
|
9
|
-
-
|
|
10
|
-
- 🛠 自带打字效果
|
|
11
|
-
- 🦮 内部封装了常用的`markdown`格式的文本显示
|
|
12
|
-
- 🔤 对大文档进行了性能优化,进行分批处理,生成打字效果的时候不会对页面造成卡顿现象
|
|
12
|
+
[📖 在线演示](https://onshinpei.github.io/ds-markdown/) | [🔧 StackBlitz 体验](https://stackblitz.com/edit/vitejs-vite-ddfw8avb?file=src%2FApp.tsx)
|
|
13
13
|
|
|
14
|
-
##
|
|
14
|
+
## ✨ 特性
|
|
15
|
+
|
|
16
|
+
- 🎯 **1:1 还原** - 完美复刻 [DeepSeek 官网](https://chat.deepseek.com/) 聊天响应效果
|
|
17
|
+
- ⚡ **高性能** - 智能分批处理,大文档渲染无卡顿
|
|
18
|
+
- 🎬 **流畅动画** - 双模式定时器,支持高频打字效果
|
|
19
|
+
- 🎨 **完整渲染** - 内置常用 Markdown 格式支持
|
|
20
|
+
- 🔧 **灵活配置** - 声明式 + 命令式双重 API 设计
|
|
21
|
+
- 📱 **现代兼容** - 支持 React 16.8+ 和现代浏览器
|
|
22
|
+
|
|
23
|
+
## 📦 安装
|
|
15
24
|
|
|
16
25
|
```bash
|
|
17
26
|
npm install ds-markdown
|
|
27
|
+
# or
|
|
28
|
+
yarn add ds-markdown
|
|
29
|
+
# or
|
|
30
|
+
pnpm add ds-markdown
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## 🚀 快速开始
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
import DsMarkdown from 'ds-markdown';
|
|
37
|
+
import 'ds-markdown/style.css';
|
|
38
|
+
|
|
39
|
+
function App() {
|
|
40
|
+
return (
|
|
41
|
+
<DsMarkdown timerType="requestAnimationFrame" interval={20} answerType="answer">
|
|
42
|
+
# Hello World 这是一个**打字动画**示例!
|
|
43
|
+
</DsMarkdown>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## 📚 API 文档
|
|
49
|
+
|
|
50
|
+
### 默认导出 (声明式 API)
|
|
51
|
+
|
|
52
|
+
| 属性名 | 类型 | 说明 | 默认值 |
|
|
53
|
+
| ------------- | -------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
|
|
54
|
+
| `interval` | `number` | 打字间隔时间 (毫秒) | `30` |
|
|
55
|
+
| `timerType` | `'setTimeout'` \| `'requestAnimationFrame'` | 定时器类型,详见下方说明 | `'requestAnimationFrame'` |
|
|
56
|
+
| `answerType` | `'thinking'` \| `'answer'` | 内容类型,影响样式主题 | `'answer'` |
|
|
57
|
+
| `onEnd` | `(data: { str: string; answerType: AnswerType }) => void` | 打字结束回调 **(可能触发多次)** | - |
|
|
58
|
+
| `onStart` | `(data: { currentIndex: number; currentChar: string; answerType: AnswerType; prevStr: string }) => void` | 打字开始回调 **(可能触发多次)** | - |
|
|
59
|
+
| `onTypedChar` | `(data: { currentIndex: number; currentChar: string; answerType: AnswerType; prevStr: string }) => void` | 每个字符打字回调 | - |
|
|
60
|
+
|
|
61
|
+
#### 🎛️ timerType 模式详解
|
|
62
|
+
|
|
63
|
+
##### `requestAnimationFrame` 模式 (推荐) 🌟
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
// 特性
|
|
67
|
+
- 🎯 时间驱动:基于真实经过时间计算字符数量
|
|
68
|
+
- 📊 批量处理:单帧内可处理多个字符
|
|
69
|
+
- 🎬 帧同步:与浏览器 60fps 刷新率同步
|
|
70
|
+
- ⚡ 高频优化:完美支持 interval < 16ms 的高速打字
|
|
71
|
+
|
|
72
|
+
// 适用场景
|
|
73
|
+
- 追求流畅动画效果
|
|
74
|
+
- 高频打字 (interval: 5-15ms)
|
|
75
|
+
- 现代 Web 应用的默认选择
|
|
18
76
|
```
|
|
19
77
|
|
|
20
|
-
|
|
21
|
-
<img src="https://img.shields.io/npm/dm/ds-markdown.svg" alt="npm downloads"/> <img src="https://img.shields.io/bundlephobia/minzip/ds-markdown" alt="Min gzipped size"/>
|
|
78
|
+
##### `setTimeout` 模式 (传统) 📟
|
|
22
79
|
|
|
23
|
-
|
|
80
|
+
```typescript
|
|
81
|
+
// 特性
|
|
82
|
+
- ⚡ 单字符:每次精确处理一个字符
|
|
83
|
+
- 🕐 固定间隔:严格按设定时间执行
|
|
84
|
+
- 🎵 节拍感:经典打字机的节奏感
|
|
85
|
+
- 🎯 精确控制:适合特定时序要求
|
|
86
|
+
|
|
87
|
+
// 适用场景
|
|
88
|
+
- 需要精确时间控制
|
|
89
|
+
- 营造复古打字机效果
|
|
90
|
+
- 兼容性要求较高的场景
|
|
91
|
+
```
|
|
24
92
|
|
|
25
|
-
|
|
93
|
+
##### 📊 性能对比
|
|
26
94
|
|
|
27
|
-
|
|
|
28
|
-
|
|
|
29
|
-
|
|
|
30
|
-
|
|
|
31
|
-
|
|
|
32
|
-
|
|
|
33
|
-
|
|
|
95
|
+
| 特性 | requestAnimationFrame | setTimeout |
|
|
96
|
+
| ------------ | ---------------------------- | ---------------- |
|
|
97
|
+
| **字符处理** | 每帧可处理多个字符 | 每次处理一个字符 |
|
|
98
|
+
| **高频间隔** | ✅ 优秀 (5ms → 每帧3字符) | ❌ 可能卡顿 |
|
|
99
|
+
| **低频间隔** | ✅ 正常 (100ms → 6帧后1字符) | ✅ 精确 |
|
|
100
|
+
| **视觉效果** | 🎬 流畅动画感 | ⚡ 精确节拍感 |
|
|
101
|
+
| **性能开销** | 🟢 低 (帧同步) | 🟡 中等 (定时器) |
|
|
34
102
|
|
|
35
|
-
## 使用示例
|
|
103
|
+
## 💡 使用示例
|
|
36
104
|
|
|
37
|
-
|
|
105
|
+
### 📝 声明式用法 (推荐)
|
|
38
106
|
|
|
39
107
|
```tsx
|
|
40
108
|
import { useState } from 'react';
|
|
@@ -43,32 +111,33 @@ import 'ds-markdown/style.css';
|
|
|
43
111
|
|
|
44
112
|
const markdown = `# ds-markdown
|
|
45
113
|
|
|
46
|
-
\`ds-markdown
|
|
114
|
+
\`ds-markdown\` 是一个高性能的 React Markdown 打字动画组件
|
|
47
115
|
|
|
48
|
-
## 特性
|
|
116
|
+
## ✨ 特性
|
|
49
117
|
|
|
50
|
-
-
|
|
51
|
-
-
|
|
52
|
-
-
|
|
53
|
-
- 🔤 对大文档进行了性能优化,进行分批处理,生成打字效果的时候不会对页面造成卡顿现象
|
|
118
|
+
- 🎯 **1:1 还原** - 完美复刻 DeepSeek 聊天界面效果
|
|
119
|
+
- ⚡ **高性能** - 智能分批处理,大文档渲染无卡顿
|
|
120
|
+
- 🎬 **流畅动画** - 双模式定时器,支持高频打字效果
|
|
54
121
|
`;
|
|
55
122
|
|
|
56
123
|
function App() {
|
|
57
124
|
const [thinkingContent, setThinkingContent] = useState('');
|
|
58
125
|
const [answerContent, setAnswerContent] = useState('');
|
|
59
126
|
|
|
60
|
-
const
|
|
61
|
-
//
|
|
62
|
-
setThinkingContent('
|
|
127
|
+
const handleStart = () => {
|
|
128
|
+
// 清空之前的内容
|
|
129
|
+
setThinkingContent('🤔 正在分析您的问题...\n\n分析完成,准备回答');
|
|
63
130
|
};
|
|
64
131
|
|
|
65
|
-
console.log(answerContent);
|
|
66
132
|
return (
|
|
67
133
|
<div>
|
|
68
|
-
<button onClick={
|
|
134
|
+
<button onClick={handleStart}>开始演示</button>
|
|
135
|
+
|
|
136
|
+
{/* 思考过程 */}
|
|
69
137
|
<DsMarkdown
|
|
70
138
|
answerType="thinking"
|
|
71
|
-
interval={
|
|
139
|
+
interval={15}
|
|
140
|
+
timerType="requestAnimationFrame"
|
|
72
141
|
onEnd={() => {
|
|
73
142
|
console.log('思考完成');
|
|
74
143
|
setAnswerContent(markdown);
|
|
@@ -77,8 +146,9 @@ function App() {
|
|
|
77
146
|
{thinkingContent}
|
|
78
147
|
</DsMarkdown>
|
|
79
148
|
|
|
80
|
-
{
|
|
81
|
-
|
|
149
|
+
{/* 回答内容 */}
|
|
150
|
+
{answerContent && (
|
|
151
|
+
<DsMarkdown answerType="answer" interval={10} timerType="requestAnimationFrame">
|
|
82
152
|
{answerContent}
|
|
83
153
|
</DsMarkdown>
|
|
84
154
|
)}
|
|
@@ -89,58 +159,155 @@ function App() {
|
|
|
89
159
|
export default App;
|
|
90
160
|
```
|
|
91
161
|
|
|
92
|
-
|
|
162
|
+
[🔗 在线体验](https://stackblitz.com/edit/vitejs-vite-ddfw8avb?file=src%2FApp.tsx)
|
|
93
163
|
|
|
94
|
-
|
|
95
|
-
使用方式:
|
|
96
|
-
`import { MarkdownCMD } from 'ds-markdown';`
|
|
164
|
+
### ⚡ 命令式用法 (流式场景)
|
|
97
165
|
|
|
98
|
-
|
|
166
|
+
适用于实时流式数据场景,减少组件重渲染,提升性能。
|
|
99
167
|
|
|
100
168
|
```tsx
|
|
101
|
-
import { useRef
|
|
169
|
+
import { useRef } from 'react';
|
|
102
170
|
import { MarkdownCMD } from 'ds-markdown';
|
|
103
171
|
import 'ds-markdown/style.css';
|
|
104
172
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
\`ds-markdown\`是一个[React](https://react.dev)组件, 类似[deepseek官网](https://chat.deepseek.com/)风格的 \`Markdown\`
|
|
108
|
-
|
|
109
|
-
## 特性
|
|
173
|
+
function StreamingChat() {
|
|
174
|
+
const markdownRef = useRef<any>();
|
|
110
175
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
- 🔤 对大文档进行了性能优化,进行分批处理,生成打字效果的时候不会对页面造成卡顿现象
|
|
115
|
-
`;
|
|
116
|
-
|
|
117
|
-
function App() {
|
|
118
|
-
const ref = useRef();
|
|
176
|
+
// 模拟流式数据接收
|
|
177
|
+
const simulateStreaming = async () => {
|
|
178
|
+
markdownRef.current?.clear();
|
|
119
179
|
|
|
120
|
-
const onClick = () => {
|
|
121
|
-
// 如果重复点击,则会清空之前的效果
|
|
122
|
-
ref.current.clear();
|
|
123
180
|
// 显示思考过程
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
181
|
+
markdownRef.current?.push('🤔 正在分析您的问题...\n\n分析完成,准备回答', 'thinking');
|
|
182
|
+
|
|
183
|
+
// 模拟流式回答
|
|
184
|
+
const chunks = [
|
|
185
|
+
'# 关于 ds-markdown\n\n',
|
|
186
|
+
'`ds-markdown` 是一个专为现代 Web 应用设计的组件。\n\n',
|
|
187
|
+
'## 主要特性\n\n',
|
|
188
|
+
'- ⚡ 高性能渲染\n',
|
|
189
|
+
'- 🎬 流畅动画\n',
|
|
190
|
+
'- 🎯 精确控制\n\n',
|
|
191
|
+
'希望这个回答对您有帮助!',
|
|
192
|
+
];
|
|
193
|
+
|
|
194
|
+
for (const chunk of chunks) {
|
|
195
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
196
|
+
markdownRef.current?.push(chunk, 'answer');
|
|
197
|
+
}
|
|
127
198
|
};
|
|
128
199
|
|
|
129
200
|
return (
|
|
130
201
|
<div>
|
|
131
|
-
<button onClick={
|
|
132
|
-
<MarkdownCMD
|
|
202
|
+
<button onClick={simulateStreaming}>开始流式演示</button>
|
|
203
|
+
<MarkdownCMD
|
|
204
|
+
ref={markdownRef}
|
|
205
|
+
interval={10}
|
|
206
|
+
timerType="requestAnimationFrame"
|
|
207
|
+
onEnd={(data) => {
|
|
208
|
+
console.log('段落完成:', data);
|
|
209
|
+
}}
|
|
210
|
+
/>
|
|
133
211
|
</div>
|
|
134
212
|
);
|
|
135
213
|
}
|
|
214
|
+
```
|
|
136
215
|
|
|
137
|
-
|
|
216
|
+
[🔗 在线体验](https://stackblitz.com/edit/vitejs-vite-2ri8kex3?file=src%2FApp.tsx)
|
|
217
|
+
|
|
218
|
+
### 命令式 API
|
|
219
|
+
|
|
220
|
+
```typescript
|
|
221
|
+
interface MarkdownRef {
|
|
222
|
+
push: (content: string, answerType: 'thinking' | 'answer') => void;
|
|
223
|
+
clear: () => void;
|
|
224
|
+
triggerWholeEnd: () => void;
|
|
225
|
+
}
|
|
138
226
|
```
|
|
139
227
|
|
|
140
|
-
|
|
228
|
+
| 方法 | 参数 | 说明 |
|
|
229
|
+
| ----------------- | ------------------------------------------- | ------------------ |
|
|
230
|
+
| `push` | `(content: string, answerType: AnswerType)` | 添加内容并开始打字 |
|
|
231
|
+
| `clear` | - | 清空所有内容和状态 |
|
|
232
|
+
| `triggerWholeEnd` | - | 手动触发完成回调 |
|
|
233
|
+
|
|
234
|
+
## 🎨 样式定制
|
|
235
|
+
|
|
236
|
+
```css
|
|
237
|
+
/* 自定义思考区域样式 */
|
|
238
|
+
.ds-markdown-thinking {
|
|
239
|
+
background: rgba(255, 193, 7, 0.1);
|
|
240
|
+
border-left: 3px solid #ffc107;
|
|
241
|
+
padding: 12px;
|
|
242
|
+
border-radius: 4px;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/* 自定义回答区域样式 */
|
|
246
|
+
.ds-markdown-answer {
|
|
247
|
+
color: #333;
|
|
248
|
+
line-height: 1.6;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/* 自定义代码块样式 */
|
|
252
|
+
.ds-markdown pre {
|
|
253
|
+
background: #f8f9fa;
|
|
254
|
+
border-radius: 6px;
|
|
255
|
+
padding: 16px;
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
## 🔧 最佳实践
|
|
260
|
+
|
|
261
|
+
### 1. 性能优化建议
|
|
262
|
+
|
|
263
|
+
```tsx
|
|
264
|
+
// ✅ 推荐:使用 requestAnimationFrame + 适中的 interval
|
|
265
|
+
<DsMarkdown
|
|
266
|
+
timerType="requestAnimationFrame"
|
|
267
|
+
interval={15} // 15-30ms 为最佳体验
|
|
268
|
+
/>
|
|
269
|
+
|
|
270
|
+
// ❌ 避免:过小的 interval 值
|
|
271
|
+
<DsMarkdown interval={1} /> // 可能导致性能问题
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### 2. 流式数据处理
|
|
275
|
+
|
|
276
|
+
```tsx
|
|
277
|
+
// ✅ 推荐:使用命令式 API
|
|
278
|
+
const ref = useRef();
|
|
279
|
+
useEffect(() => {
|
|
280
|
+
// 实时接收数据时使用 push 方法
|
|
281
|
+
ref.current?.push(newChunk, 'answer');
|
|
282
|
+
}, [newChunk]);
|
|
283
|
+
|
|
284
|
+
// ❌ 避免:频繁更新 children prop
|
|
285
|
+
const [content, setContent] = useState('');
|
|
286
|
+
// 每次更新都会重新解析整个内容
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### 3. 类型安全
|
|
290
|
+
|
|
291
|
+
```tsx
|
|
292
|
+
import { MarkdownRef } from 'ds-markdown';
|
|
293
|
+
|
|
294
|
+
const ref = useRef<MarkdownRef>(null);
|
|
295
|
+
// 现在具有完整的类型提示
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
## 🌐 兼容性
|
|
299
|
+
|
|
300
|
+
- **React**: 16.8.0+
|
|
301
|
+
- **TypeScript**: 4.0+
|
|
302
|
+
- **浏览器**: Chrome 60+, Firefox 55+, Safari 12+
|
|
303
|
+
- **Node.js**: 14.0+
|
|
304
|
+
|
|
305
|
+
## 📄 License
|
|
141
306
|
|
|
142
|
-
|
|
307
|
+
MIT © [YourName](https://github.com/yourusername)
|
|
143
308
|
|
|
144
|
-
|
|
309
|
+
---
|
|
145
310
|
|
|
146
|
-
|
|
311
|
+
<div align="center">
|
|
312
|
+
<strong>如果这个项目对你有帮助,请给个 ⭐️ Star 支持一下!</strong>
|
|
313
|
+
</div>
|