ds-markdown 0.1.10-beta.1 โ 0.1.10-beta.2
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.en.md +272 -758
- package/README.md +7 -7
- package/dist/cjs/i18n/en/index.d.ts +17 -10
- package/dist/cjs/i18n/en/index.js +7 -0
- package/dist/cjs/i18n/en/index.js.map +1 -1
- package/dist/cjs/i18n/zh/index.d.ts +17 -10
- package/dist/cjs/i18n/zh/index.js +7 -0
- package/dist/cjs/i18n/zh/index.js.map +1 -1
- package/dist/cjs/index.d.ts +68 -35
- package/dist/cjs/index.js +127 -267
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/i18n/en/index.d.ts +17 -10
- package/dist/esm/i18n/en/index.js +7 -0
- package/dist/esm/i18n/en/index.js.map +1 -1
- package/dist/esm/i18n/zh/index.d.ts +17 -10
- package/dist/esm/i18n/zh/index.js +7 -0
- package/dist/esm/i18n/zh/index.js.map +1 -1
- package/dist/esm/index.d.ts +68 -35
- package/dist/esm/index.js +82 -225
- package/dist/esm/index.js.map +1 -1
- package/dist/style.css +4 -87
- package/package.json +1 -1
package/README.en.md
CHANGED
|
@@ -9,66 +9,72 @@ A React component designed specifically for modern AI applications, providing sm
|
|
|
9
9
|
[](https://www.npmjs.com/package/ds-markdown)
|
|
10
10
|
[](https://www.npmjs.com/package/ds-markdown)
|
|
11
11
|
[](https://bundlephobia.com/package/ds-markdown)
|
|
12
|
-
[](https://react.dev)
|
|
13
13
|
[](https://www.typescriptlang.org/)
|
|
14
14
|
|
|
15
|
-
[
|
|
15
|
+
- [Documentation](https://onshinpei.github.io/ds-markdown/)
|
|
16
|
+
- Usage Examples
|
|
17
|
+
- [Basic Usage](https://stackblitz.com/edit/vitejs-vite-ddfw8avb?file=src%2FApp.tsx)
|
|
18
|
+
- [Streaming Data Usage](https://stackblitz.com/edit/vitejs-vite-2ri8kex3?file=src%2FApp.tsx)
|
|
19
|
+
- [Mermaid Charts](https://stackblitz.com/edit/vitejs-vite-iqbyta3j?file=index.html)
|
|
20
|
+
- [Math Formula Demo 1](https://stackblitz.com/edit/vitejs-vite-iqbyta3j?file=index.html)
|
|
21
|
+
- [Math Formula Demo 2](https://stackblitz.com/edit/vitejs-vite-xk9lxagc?file=src%2FApp.tsx)
|
|
16
22
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
**If you want a pure react markdown typing component, you can use [react-markdown-typer](https://github.com/onshinpei/react-markdown-typer)**
|
|
20
|
-
|
|
21
|
-
---
|
|
22
|
-
|
|
23
|
-
## ๐ Table of Contents
|
|
24
|
-
|
|
25
|
-
- [โจ Core Features](#-core-features)
|
|
26
|
-
- [๐ฆ Quick Installation](#-quick-installation)
|
|
27
|
-
- [๐ 5-Minute Quick Start](#-5-minute-quick-start)
|
|
28
|
-
- [Basic Usage](#basic-usage)
|
|
29
|
-
- [Disable Typing Animation](#disable-typing-animation)
|
|
30
|
-
- [Mathematical Formula Support](#mathematical-formula-support)
|
|
31
|
-
- [AI Conversation Scenario](#ai-conversation-scenario)
|
|
32
|
-
- [๐ฏ Advanced Callback Control](#-advanced-callback-control)
|
|
33
|
-
- [๐ Restart Animation Demo](#-restart-animation-demo)
|
|
34
|
-
- [โถ๏ธ Manual Start Animation Demo](#๏ธ-manual-start-animation-demo)
|
|
35
|
-
- [๐ Complete API Documentation](#-complete-api-documentation)
|
|
36
|
-
- [๐งฎ Mathematical Formula Usage Guide](#-mathematical-formula-usage-guide)
|
|
37
|
-
- [๐ Plugin System](#-plugin-system)
|
|
38
|
-
- [๐๏ธ Timer Mode Details](#๏ธ-timer-mode-details)
|
|
39
|
-
- [๐ก Practical Examples](#-practical-examples)
|
|
40
|
-
- [๐ง Best Practices](#-best-practices)
|
|
41
|
-
- [ConfigProvider Internationalization (i18n)](<#ConfigProvider-Internationalization-(i18n)>)
|
|
23
|
+
If you want a pure `react markdown` typing component, you can use [react-markdown-typer](https://github.com/onshinpei/react-markdown-typer)
|
|
42
24
|
|
|
43
25
|
---
|
|
44
26
|
|
|
45
27
|
## โ Why use ds-markdown?
|
|
46
28
|
|
|
47
29
|
- **Ultimate AI Chat Experience**
|
|
48
|
-
|
|
30
|
+
1:1 recreation of DeepSeek and other mainstream AI chat interface typing animations and streaming responses, delivering an authentic "AI is thinking/answering" experience that greatly enhances user immersion.
|
|
49
31
|
|
|
50
32
|
- **Perfect for Streaming Backend Data**
|
|
51
|
-
Many AI/LLM
|
|
52
|
-
**ds-markdown automatically splits each chunk into single characters and
|
|
33
|
+
Many AI/LLM backend interfaces (like OpenAI, DeepSeek, etc.) push data chunks containing multiple characters at once, which can cause stuttering and character jumping issues with ordinary typewriter implementations.
|
|
34
|
+
**ds-markdown automatically splits each chunk into single characters and renders them one by one with smooth animations, ensuring fluent typing regardless of how many characters the backend pushes at once.**
|
|
35
|
+
|
|
36
|
+
- **Complete Markdown & Math Formula, Diagram Support**
|
|
53
37
|
|
|
54
|
-
-
|
|
55
|
-
|
|
38
|
+
- Built-in KaTeX, supporting all mainstream Markdown syntax and math formulas, suitable for technical Q&A, education, knowledge bases, and other content-rich applications.
|
|
39
|
+
- Support for `Diagram` rendering through the [mermaid-plugin](https://github.com/onshinpei/ds-markdown-mermaid-plugin)
|
|
56
40
|
|
|
57
41
|
- **Excellent Developer Experience**
|
|
58
|
-
Rich imperative API,
|
|
42
|
+
Rich imperative API, supporting streaming data, async callbacks, and plugin extensions, allowing developers to flexibly control animations and content.
|
|
59
43
|
|
|
60
44
|
- **Lightweight & High Performance**
|
|
61
|
-
Small
|
|
45
|
+
Small size, excellent performance, compatible with mobile and desktop. Core dependency is [react-markdown](https://github.com/remarkjs/react-markdown) (industry mainstream, mature Markdown rendering library), with no other heavyweight dependencies - works out of the box.
|
|
62
46
|
|
|
63
47
|
- **Multi-theme & Plugin Architecture**
|
|
64
|
-
|
|
48
|
+
Support for light/dark theme switching, compatible with remark/rehype plugins, meeting personalized and advanced extension needs.
|
|
49
|
+
|
|
50
|
+
- **Rich UI Component System** ๐
|
|
51
|
+
Built-in UI components: Button, IconButton, ToolTip, Segmented, etc., supporting code block copy, download, and other interactive features.
|
|
65
52
|
|
|
66
53
|
- **Wide Range of Use Cases**
|
|
67
54
|
- AI chatbots/assistants
|
|
68
55
|
- Real-time Q&A/knowledge bases
|
|
69
|
-
- Education/math/programming content
|
|
70
|
-
- Product demos, interactive
|
|
71
|
-
- Any scenario
|
|
56
|
+
- Education/math/programming content display
|
|
57
|
+
- Product demos, interactive documentation
|
|
58
|
+
- Any scenario requiring "typewriter" animation and streaming Markdown rendering
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## ๐ Table of Contents
|
|
63
|
+
|
|
64
|
+
- [โจ Core Features](#-core-features)
|
|
65
|
+
- [๐ฆ Quick Installation](#-quick-installation)
|
|
66
|
+
- [๐ 5-Minute Quick Start](#-5-minute-quick-start)
|
|
67
|
+
- [Basic Usage](#basic-usage)
|
|
68
|
+
- [Disable Typing Animation](#disable-typing-animation)
|
|
69
|
+
- [Mathematical Formula Support](#mathematical-formula-support)
|
|
70
|
+
- [AI Conversation Scenario](#ai-conversation-scenario)
|
|
71
|
+
- [Code Block Features](#code-block-features) ๐
|
|
72
|
+
- [Mermaid Chart Support](#mermaid-chart-support) ๐
|
|
73
|
+
- [๐ Complete API Documentation](#-complete-api-documentation)
|
|
74
|
+
- [๐ Plugin System](#-plugin-system)
|
|
75
|
+
- [๐จ UI Component System](#-ui-component-system) ๐
|
|
76
|
+
- [๐ก Practical Examples](#-practical-examples)
|
|
77
|
+
- [๐ง Best Practices](#-best-practices)
|
|
72
78
|
|
|
73
79
|
---
|
|
74
80
|
|
|
@@ -84,13 +90,21 @@ A React component designed specifically for modern AI applications, providing sm
|
|
|
84
90
|
|
|
85
91
|
- Complete Markdown syntax support, including code highlighting, tables, lists, etc.
|
|
86
92
|
- Mathematical formula rendering (KaTeX), supporting `$...$` and `\[...\]` syntax
|
|
87
|
-
-
|
|
93
|
+
- Mermaid chart support, including flowcharts, sequence diagrams, Gantt charts, class diagrams, etc. ๐
|
|
94
|
+
- Support for light/dark themes, adapting to different product styles
|
|
88
95
|
- Plugin architecture supporting remark/rehype plugin extensions
|
|
89
96
|
|
|
97
|
+
### ๐จ **UI Component System** ๐
|
|
98
|
+
|
|
99
|
+
- Built-in rich UI components: Button, IconButton, ToolTip, Segmented, etc.
|
|
100
|
+
- Code block enhancement features: copy, download, language identification
|
|
101
|
+
- Complete interactive experience and accessibility support
|
|
102
|
+
|
|
90
103
|
### ๐ง **Developer Experience**
|
|
91
104
|
|
|
92
105
|
- Support for typing interruption `stop` and resume `resume`
|
|
93
|
-
- Support for
|
|
106
|
+
- Support for enabling and disabling typing
|
|
107
|
+
- Complete TypeScript type support
|
|
94
108
|
|
|
95
109
|
### ๐ฌ **Smooth Animation**
|
|
96
110
|
|
|
@@ -238,223 +252,81 @@ Let's explore these new features together!`);
|
|
|
238
252
|
}
|
|
239
253
|
```
|
|
240
254
|
|
|
241
|
-
###
|
|
255
|
+
### Code Block Features ๐
|
|
242
256
|
|
|
243
257
|
```tsx
|
|
244
|
-
import
|
|
245
|
-
import
|
|
246
|
-
|
|
247
|
-
function AdvancedCallbackDemo() {
|
|
248
|
-
const markdownRef = useRef<MarkdownCMDRef>(null);
|
|
249
|
-
const [typingStats, setTypingStats] = useState({ progress: 0, currentChar: '', totalChars: 0 });
|
|
250
|
-
|
|
251
|
-
const handleBeforeTypedChar = async (data) => {
|
|
252
|
-
// Perform async operations before character typing
|
|
253
|
-
console.log('About to type:', data.currentChar);
|
|
254
|
-
|
|
255
|
-
// Can perform network requests, data validation, etc.
|
|
256
|
-
if (data.currentChar === '!') {
|
|
257
|
-
await new Promise((resolve) => setTimeout(resolve, 500)); // Simulate delay
|
|
258
|
-
}
|
|
259
|
-
};
|
|
260
|
-
|
|
261
|
-
const handleTypedChar = (data) => {
|
|
262
|
-
// Update typing statistics
|
|
263
|
-
setTypingStats({
|
|
264
|
-
progress: Math.round(data.percent),
|
|
265
|
-
currentChar: data.currentChar,
|
|
266
|
-
totalChars: data.currentIndex + 1,
|
|
267
|
-
});
|
|
268
|
-
|
|
269
|
-
// Can add sound effects, animations, etc.
|
|
270
|
-
if (data.currentChar === '.') {
|
|
271
|
-
// Play period sound effect
|
|
272
|
-
console.log('Play period sound effect');
|
|
273
|
-
}
|
|
274
|
-
};
|
|
275
|
-
|
|
276
|
-
const handleStart = (data) => {
|
|
277
|
-
console.log('Start typing:', data.currentChar);
|
|
278
|
-
};
|
|
279
|
-
|
|
280
|
-
const handleEnd = (data) => {
|
|
281
|
-
console.log('Typing complete:', data.str);
|
|
282
|
-
};
|
|
283
|
-
|
|
284
|
-
const startDemo = () => {
|
|
285
|
-
markdownRef.current?.clear();
|
|
286
|
-
markdownRef.current?.push(
|
|
287
|
-
'# Advanced Callback Demo\n\n' +
|
|
288
|
-
'This example shows how to use `onBeforeTypedChar` and `onTypedChar` callbacks:\n\n' +
|
|
289
|
-
'- ๐ฏ **Pre-typing callback**: Can perform async operations before character display\n' +
|
|
290
|
-
'- ๐ **Post-typing callback**: Can update progress in real-time and add effects\n' +
|
|
291
|
-
'- โก **Performance optimization**: Supports async operations without affecting typing smoothness\n\n' +
|
|
292
|
-
'Current progress: ' +
|
|
293
|
-
typingStats.progress +
|
|
294
|
-
'%\n' +
|
|
295
|
-
'Characters typed: ' +
|
|
296
|
-
typingStats.totalChars +
|
|
297
|
-
'\n\n' +
|
|
298
|
-
'This is a very powerful feature!',
|
|
299
|
-
'answer',
|
|
300
|
-
);
|
|
301
|
-
};
|
|
302
|
-
|
|
303
|
-
return (
|
|
304
|
-
<div>
|
|
305
|
-
<button onClick={startDemo}>๐ Start Advanced Demo</button>
|
|
258
|
+
import DsMarkdown from 'ds-markdown';
|
|
259
|
+
import 'ds-markdown/style.css';
|
|
306
260
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
</div>
|
|
261
|
+
function CodeBlockDemo() {
|
|
262
|
+
const codeContent = `# Hello World
|
|
310
263
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
);
|
|
264
|
+
\`\`\`javascript
|
|
265
|
+
function greet(name) {
|
|
266
|
+
console.log(\`Hello, \${name}!\`);
|
|
314
267
|
}
|
|
315
|
-
```
|
|
316
|
-
|
|
317
|
-
### ๐ Restart Animation Demo
|
|
318
|
-
|
|
319
|
-
```tsx
|
|
320
|
-
import { useRef, useState } from 'react';
|
|
321
|
-
import { MarkdownCMD, MarkdownCMDRef } from 'ds-markdown';
|
|
322
|
-
|
|
323
|
-
function RestartDemo() {
|
|
324
|
-
const markdownRef = useRef<MarkdownCMDRef>(null);
|
|
325
|
-
const [isPlaying, setIsPlaying] = useState(false);
|
|
326
|
-
const [hasStarted, setHasStarted] = useState(false);
|
|
327
|
-
|
|
328
|
-
const startContent = () => {
|
|
329
|
-
markdownRef.current?.clear();
|
|
330
|
-
markdownRef.current?.push(
|
|
331
|
-
'# Restart Animation Demo\n\n' +
|
|
332
|
-
'This example shows how to use the `restart()` method:\n\n' +
|
|
333
|
-
'- ๐ **Restart**: Play current content from the beginning\n' +
|
|
334
|
-
'- โธ๏ธ **Pause/Resume**: Can pause and resume at any time\n' +
|
|
335
|
-
'- ๐ฏ **Precise Control**: Complete control over animation playback state\n\n' +
|
|
336
|
-
'Current state: ' +
|
|
337
|
-
(isPlaying ? 'Playing' : 'Paused') +
|
|
338
|
-
'\n\n' +
|
|
339
|
-
'This is a very practical feature!',
|
|
340
|
-
'answer',
|
|
341
|
-
);
|
|
342
|
-
setIsPlaying(true);
|
|
343
|
-
};
|
|
344
268
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
// If already started, restart
|
|
348
|
-
markdownRef.current?.restart();
|
|
349
|
-
} else {
|
|
350
|
-
// First time start
|
|
351
|
-
markdownRef.current?.start();
|
|
352
|
-
setHasStarted(true);
|
|
353
|
-
}
|
|
354
|
-
setIsPlaying(true);
|
|
355
|
-
};
|
|
356
|
-
|
|
357
|
-
const handleStop = () => {
|
|
358
|
-
markdownRef.current?.stop();
|
|
359
|
-
setIsPlaying(false);
|
|
360
|
-
};
|
|
361
|
-
|
|
362
|
-
const handleResume = () => {
|
|
363
|
-
markdownRef.current?.resume();
|
|
364
|
-
setIsPlaying(true);
|
|
365
|
-
};
|
|
269
|
+
greet('ds-markdown');
|
|
270
|
+
\`\`\`
|
|
366
271
|
|
|
367
|
-
|
|
368
|
-
markdownRef.current?.restart();
|
|
369
|
-
setIsPlaying(true);
|
|
370
|
-
};
|
|
371
|
-
|
|
372
|
-
const handleEnd = () => {
|
|
373
|
-
setIsPlaying(false);
|
|
374
|
-
};
|
|
272
|
+
Supports code highlighting, copy, and download features!`;
|
|
375
273
|
|
|
376
274
|
return (
|
|
377
|
-
<
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
<button onClick={handleResume} disabled={isPlaying}>
|
|
387
|
-
โถ๏ธ Resume
|
|
388
|
-
</button>
|
|
389
|
-
<button onClick={handleRestart}>๐ Restart</button>
|
|
390
|
-
</div>
|
|
391
|
-
|
|
392
|
-
<div style={{ margin: '10px 0', padding: '10px', background: '#f5f5f5', borderRadius: '4px' }}>
|
|
393
|
-
<strong>Animation State:</strong> {isPlaying ? '๐ข Playing' : '๐ด Paused'}
|
|
394
|
-
</div>
|
|
395
|
-
|
|
396
|
-
<MarkdownCMD ref={markdownRef} interval={25} onEnd={handleEnd} />
|
|
397
|
-
</div>
|
|
275
|
+
<DsMarkdown
|
|
276
|
+
interval={20}
|
|
277
|
+
answerType="answer"
|
|
278
|
+
codeBlock={{
|
|
279
|
+
headerActions: true, // Enable code block header action buttons
|
|
280
|
+
}}
|
|
281
|
+
>
|
|
282
|
+
{codeContent}
|
|
283
|
+
</DsMarkdown>
|
|
398
284
|
);
|
|
399
285
|
}
|
|
400
286
|
```
|
|
401
287
|
|
|
402
|
-
###
|
|
288
|
+
### Mermaid Chart Support ๐
|
|
403
289
|
|
|
404
290
|
```tsx
|
|
405
|
-
import
|
|
406
|
-
import {
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
const markdownRef = useRef<MarkdownCMDRef>(null);
|
|
410
|
-
const [isPlaying, setIsPlaying] = useState(false);
|
|
411
|
-
const [hasStarted, setHasStarted] = useState(false);
|
|
412
|
-
|
|
413
|
-
const loadContent = () => {
|
|
414
|
-
markdownRef.current?.clear();
|
|
415
|
-
markdownRef.current?.push(
|
|
416
|
-
'# Manual Start Animation Demo\n\n' +
|
|
417
|
-
'This example shows how to use the `start()` method:\n\n' +
|
|
418
|
-
'- ๐ฏ **Manual Control**: When `autoStartTyping=false`, need to manually call `start()`\n' +
|
|
419
|
-
'- โฑ๏ธ **Delayed Start**: Can start animation after user interaction\n' +
|
|
420
|
-
'- ๐ฎ **Gamification**: Suitable for scenarios requiring user initiative\n\n' +
|
|
421
|
-
'Click the "Start Animation" button to manually trigger the typing effect!',
|
|
422
|
-
'answer',
|
|
423
|
-
);
|
|
424
|
-
setIsPlaying(false);
|
|
425
|
-
};
|
|
426
|
-
|
|
427
|
-
const handleStart = () => {
|
|
428
|
-
if (hasStarted) {
|
|
429
|
-
// If already started, restart
|
|
430
|
-
markdownRef.current?.restart();
|
|
431
|
-
} else {
|
|
432
|
-
// First time start
|
|
433
|
-
markdownRef.current?.start();
|
|
434
|
-
setHasStarted(true);
|
|
435
|
-
}
|
|
436
|
-
setIsPlaying(true);
|
|
437
|
-
};
|
|
291
|
+
import DsMarkdown from 'ds-markdown';
|
|
292
|
+
import { ConfigProvider } from 'ds-markdown';
|
|
293
|
+
import mermaidPlugin from 'ds-markdown-mermaid-plugin';
|
|
294
|
+
import 'ds-markdown/style.css';
|
|
438
295
|
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
296
|
+
function MermaidDemo() {
|
|
297
|
+
const chartContent = `# Flowchart Example
|
|
298
|
+
|
|
299
|
+
\`\`\`mermaid
|
|
300
|
+
flowchart TD
|
|
301
|
+
A[Start] --> B{Decision}
|
|
302
|
+
B -->|Yes| C[Process A]
|
|
303
|
+
B -->|No| D[Process B]
|
|
304
|
+
C --> E[End]
|
|
305
|
+
D --> E
|
|
306
|
+
\`\`\`
|
|
307
|
+
|
|
308
|
+
## Sequence Diagram Example
|
|
309
|
+
|
|
310
|
+
\`\`\`mermaid
|
|
311
|
+
sequenceDiagram
|
|
312
|
+
participant User
|
|
313
|
+
participant System
|
|
314
|
+
participant Database
|
|
315
|
+
|
|
316
|
+
User->>System: Login Request
|
|
317
|
+
System->>Database: Verify User
|
|
318
|
+
Database-->>System: Return Result
|
|
319
|
+
System-->>User: Login Response
|
|
320
|
+
\`\`\`
|
|
321
|
+
|
|
322
|
+
Supports flowcharts, sequence diagrams, Gantt charts, class diagrams, and many other chart types!`;
|
|
442
323
|
|
|
443
324
|
return (
|
|
444
|
-
<
|
|
445
|
-
<
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
</button>
|
|
450
|
-
</div>
|
|
451
|
-
|
|
452
|
-
<div style={{ margin: '10px 0', padding: '10px', background: '#f5f5f5', borderRadius: '4px' }}>
|
|
453
|
-
<strong>State:</strong> {isPlaying ? '๐ข Animation Playing' : '๐ด Waiting to Start'}
|
|
454
|
-
</div>
|
|
455
|
-
|
|
456
|
-
<MarkdownCMD ref={markdownRef} interval={30} autoStartTyping={false} onEnd={handleEnd} />
|
|
457
|
-
</div>
|
|
325
|
+
<ConfigProvider>
|
|
326
|
+
<DsMarkdown interval={20} answerType="answer" plugins={[mermaidPlugin]}>
|
|
327
|
+
{chartContent}
|
|
328
|
+
</DsMarkdown>
|
|
329
|
+
</ConfigProvider>
|
|
458
330
|
);
|
|
459
331
|
}
|
|
460
332
|
```
|
|
@@ -472,8 +344,8 @@ import DsMarkdown, { MarkdownCMD } from 'ds-markdown';
|
|
|
472
344
|
| Property | Type | Description | Default |
|
|
473
345
|
| ------------------- | ------------------------------------------- | ---------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
|
|
474
346
|
| `interval` | `number` | Typing interval (milliseconds) | `30` |
|
|
475
|
-
| `timerType` | `'setTimeout'` \| `'requestAnimationFrame'` | Timer type
|
|
476
|
-
| `answerType` | `'thinking'` \| `'answer'` | Content type (affects styling)
|
|
347
|
+
| `timerType` | `'setTimeout'` \| `'requestAnimationFrame'` | Timer type, cannot be modified dynamically | Current default is `setTimeout`, will change to `requestAnimationFrame` later |
|
|
348
|
+
| `answerType` | `'thinking'` \| `'answer'` | Content type (affects styling), cannot be modified dynamically | `'answer'` |
|
|
477
349
|
| `theme` | `'light'` \| `'dark'` | Theme type | `'light'` |
|
|
478
350
|
| `plugins` | `IMarkdownPlugin[]` | Plugin configuration | `[]` |
|
|
479
351
|
| `math` | [IMarkdownMath](#IMarkdownMath) | Mathematical formula config | `{ splitSymbol: 'dollar' }` |
|
|
@@ -483,6 +355,7 @@ import DsMarkdown, { MarkdownCMD } from 'ds-markdown';
|
|
|
483
355
|
| `onTypedChar` | `(data: ITypedChar) => void` | Character typing post-callback | - |
|
|
484
356
|
| `disableTyping` | `boolean` | Disable typing animation | `false` |
|
|
485
357
|
| `autoStartTyping` | `boolean` | Whether to auto-start typing animation, set to false for manual trigger | `true` |
|
|
358
|
+
| `codeBlock` | `IMarkdownCode` | Code block configuration | `{headerActions: true}` |
|
|
486
359
|
|
|
487
360
|
> Note: If `disableTyping` changes from `true` to `false` during typing, all remaining characters will be displayed at once on the next typing trigger.
|
|
488
361
|
|
|
@@ -518,14 +391,21 @@ import DsMarkdown, { MarkdownCMD } from 'ds-markdown';
|
|
|
518
391
|
- `'dollar'`: Uses `$...$` and `$$...$$` syntax
|
|
519
392
|
- `'bracket'`: Uses `\(...\)` and `\[...\]` syntax
|
|
520
393
|
|
|
394
|
+
#### IMarkdownCode ๐
|
|
395
|
+
|
|
396
|
+
| Property | Type | Description | Default |
|
|
397
|
+
| --------------- | --------- | -------------------------- | ------- |
|
|
398
|
+
| `headerActions` | `boolean` | Show header action buttons | `true` |
|
|
399
|
+
|
|
521
400
|
#### IMarkdownPlugin
|
|
522
401
|
|
|
523
|
-
| Property | Type
|
|
524
|
-
| -------------- |
|
|
525
|
-
| `remarkPlugin` | `
|
|
526
|
-
| `rehypePlugin` | `
|
|
527
|
-
| `type` | `'buildIn'` \| `'custom'`
|
|
528
|
-
| `id` | `any`
|
|
402
|
+
| Property | Type | Description | Default |
|
|
403
|
+
| -------------- | ---------------------------------------------- | --------------------------- | ------- |
|
|
404
|
+
| `remarkPlugin` | `Pluggable` | remark plugin | - |
|
|
405
|
+
| `rehypePlugin` | `Pluggable` | rehype plugin | - |
|
|
406
|
+
| `type` | `'buildIn'` \| `'custom'` | Plugin type | - |
|
|
407
|
+
| `id` | `any` | Plugin unique identifier | - |
|
|
408
|
+
| `components` | `Record<string, React.ComponentType<unknown>>` | Custom component mapping ๐ | - |
|
|
529
409
|
|
|
530
410
|
### Component Exposed Methods
|
|
531
411
|
|
|
@@ -561,106 +441,97 @@ markdownRef.current?.restart(); // Restart animation
|
|
|
561
441
|
|
|
562
442
|
---
|
|
563
443
|
|
|
564
|
-
##
|
|
444
|
+
## ๐ Plugin System
|
|
565
445
|
|
|
566
|
-
|
|
446
|
+
### Built-in Plugins
|
|
567
447
|
|
|
568
|
-
|
|
448
|
+
#### KaTeX Mathematical Formula Plugin
|
|
569
449
|
|
|
570
|
-
|
|
450
|
+
[DEMO](https://stackblitz.com/edit/vitejs-vite-iqbyta3j?file=index.html)
|
|
571
451
|
|
|
572
452
|
```tsx
|
|
573
453
|
import { katexPlugin } from 'ds-markdown/plugins';
|
|
574
454
|
|
|
575
|
-
//
|
|
576
|
-
<DsMarkdown plugins={[katexPlugin]}>
|
|
577
|
-
# Mathematical Formula Example
|
|
578
|
-
|
|
579
|
-
// Inline formula
|
|
580
|
-
This is an inline formula: $E = mc^2$
|
|
581
|
-
|
|
582
|
-
// Block formula
|
|
583
|
-
$$\int_{-\infty}^{\infty} e^{-x^2} dx = \sqrt{\pi}$$
|
|
584
|
-
</DsMarkdown>
|
|
455
|
+
// Enable mathematical formula support
|
|
456
|
+
<DsMarkdown plugins={[katexPlugin]}>Mathematical formula: $E = mc^2$</DsMarkdown>;
|
|
585
457
|
```
|
|
586
458
|
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
```tsx
|
|
590
|
-
// Using dollar sign delimiters (default)
|
|
591
|
-
<DsMarkdown
|
|
592
|
-
plugins={[katexPlugin]}
|
|
593
|
-
math={{ splitSymbol: 'dollar' }}
|
|
594
|
-
>
|
|
595
|
-
Inline: $a + b = c$
|
|
596
|
-
Block: $$\sum_{i=1}^{n} x_i = x_1 + x_2 + \cdots + x_n$$
|
|
597
|
-
</DsMarkdown>
|
|
598
|
-
|
|
599
|
-
// Using bracket delimiters
|
|
600
|
-
<DsMarkdown
|
|
601
|
-
plugins={[katexPlugin]}
|
|
602
|
-
math={{ splitSymbol: 'bracket' }}
|
|
603
|
-
>
|
|
604
|
-
Inline: \(a + b = c\)
|
|
605
|
-
Block: \[\sum_{i=1}^{n} x_i = x_1 + x_2 + \cdots + x_n\]
|
|
606
|
-
</DsMarkdown>
|
|
607
|
-
```
|
|
459
|
+
#### Mermaid Chart Plugin ๐
|
|
608
460
|
|
|
609
|
-
|
|
461
|
+
**Install Mermaid plugin:**
|
|
610
462
|
|
|
611
|
-
```
|
|
612
|
-
|
|
613
|
-
const mathContent = [
|
|
614
|
-
'Pythagorean Theorem:',
|
|
615
|
-
'$a^2 + b^2 = c^2$',
|
|
616
|
-
'\n\n',
|
|
617
|
-
'Where:',
|
|
618
|
-
'- $a$ and $b$ are the legs\n',
|
|
619
|
-
'- $c$ is the hypotenuse\n\n',
|
|
620
|
-
'For the classic "3-4-5" triangle:\n',
|
|
621
|
-
'$c = \\sqrt{3^2 + 4^2} = \\sqrt{25} = 5$\n\n',
|
|
622
|
-
'This theorem has wide applications in geometry!',
|
|
623
|
-
];
|
|
624
|
-
|
|
625
|
-
mathContent.forEach((chunk) => {
|
|
626
|
-
markdownRef.current?.push(chunk, 'answer');
|
|
627
|
-
});
|
|
463
|
+
```bash
|
|
464
|
+
npm install ds-markdown-mermaid-plugin
|
|
628
465
|
```
|
|
629
466
|
|
|
630
|
-
|
|
467
|
+
**Basic usage:**
|
|
631
468
|
|
|
632
|
-
```
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
font-size: 1.1em;
|
|
636
|
-
}
|
|
469
|
+
```tsx
|
|
470
|
+
import { ConfigProvider, Markdown } from 'ds-markdown';
|
|
471
|
+
import mermaidPlugin from 'ds-markdown-mermaid-plugin';
|
|
637
472
|
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
473
|
+
function App() {
|
|
474
|
+
const content = `
|
|
475
|
+
# Flowchart Example
|
|
476
|
+
|
|
477
|
+
\`\`\`mermaid
|
|
478
|
+
flowchart TD
|
|
479
|
+
A[Start] --> B{Decision}
|
|
480
|
+
B -->|Yes| C[Process A]
|
|
481
|
+
B -->|No| D[Process B]
|
|
482
|
+
C --> E[End]
|
|
483
|
+
D --> E
|
|
484
|
+
\`\`\`
|
|
485
|
+
`;
|
|
642
486
|
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
487
|
+
return (
|
|
488
|
+
<ConfigProvider>
|
|
489
|
+
<Markdown plugins={[mermaidPlugin]}>{content}</Markdown>
|
|
490
|
+
</ConfigProvider>
|
|
491
|
+
);
|
|
646
492
|
}
|
|
647
493
|
```
|
|
648
494
|
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
## ๐ Plugin System
|
|
495
|
+
**Supported chart types:**
|
|
652
496
|
|
|
653
|
-
|
|
497
|
+
- ๐ **Flowchart** - Display processes and decision paths
|
|
498
|
+
- ๐ **Sequence Diagram** - Display interaction timing between objects
|
|
499
|
+
- ๐
**Gantt Chart** - Project planning and timelines
|
|
500
|
+
- ๐๏ธ **Class Diagram** - Object-oriented design
|
|
501
|
+
- ๐ฅง **Pie Chart** - Data proportion display
|
|
502
|
+
- ๐ **State Diagram** - State transition processes
|
|
503
|
+
- ๐ **Git Graph** - Code branch history
|
|
504
|
+
- ๐บ๏ธ **User Journey** - User experience processes
|
|
654
505
|
|
|
655
|
-
|
|
506
|
+
**Configure Mermaid:**
|
|
656
507
|
|
|
657
508
|
```tsx
|
|
658
|
-
import {
|
|
509
|
+
import { ConfigProvider } from 'ds-markdown';
|
|
659
510
|
|
|
660
|
-
|
|
661
|
-
|
|
511
|
+
const mermaidConfig = {
|
|
512
|
+
theme: 'default', // Themes: default, neutral, dark, forest
|
|
513
|
+
flowchart: {
|
|
514
|
+
useMaxWidth: true,
|
|
515
|
+
htmlLabels: true,
|
|
516
|
+
},
|
|
517
|
+
sequence: {
|
|
518
|
+
diagramMarginX: 50,
|
|
519
|
+
diagramMarginY: 10,
|
|
520
|
+
},
|
|
521
|
+
};
|
|
522
|
+
|
|
523
|
+
return (
|
|
524
|
+
<ConfigProvider mermaidConfig={mermaidConfig}>
|
|
525
|
+
<Markdown plugins={[mermaidPlugin]}>{chartContent}</Markdown>
|
|
526
|
+
</ConfigProvider>
|
|
527
|
+
);
|
|
662
528
|
```
|
|
663
529
|
|
|
530
|
+
**Related links:**
|
|
531
|
+
|
|
532
|
+
- [ds-markdown-mermaid-plugin GitHub](https://github.com/onshinpei/ds-markdown-mermaid-plugin)
|
|
533
|
+
- [Mermaid Official Documentation](https://mermaid.js.org/)
|
|
534
|
+
|
|
664
535
|
### Custom Plugins
|
|
665
536
|
|
|
666
537
|
```tsx
|
|
@@ -671,6 +542,10 @@ const customPlugin = createBuildInPlugin({
|
|
|
671
542
|
remarkPlugin: yourRemarkPlugin,
|
|
672
543
|
rehypePlugin: yourRehypePlugin,
|
|
673
544
|
id: Symbol('custom-plugin'),
|
|
545
|
+
components: {
|
|
546
|
+
// Custom component mapping ๐
|
|
547
|
+
CustomComponent: MyCustomComponent,
|
|
548
|
+
},
|
|
674
549
|
});
|
|
675
550
|
|
|
676
551
|
// Use custom plugin
|
|
@@ -679,50 +554,76 @@ const customPlugin = createBuildInPlugin({
|
|
|
679
554
|
|
|
680
555
|
---
|
|
681
556
|
|
|
682
|
-
##
|
|
557
|
+
## ๐จ UI Component System ๐
|
|
683
558
|
|
|
684
|
-
|
|
559
|
+
ds-markdown provides rich UI components that can be used independently or in combination with markdown components.
|
|
685
560
|
|
|
686
|
-
|
|
687
|
-
// ๐ฏ Features
|
|
688
|
-
- Time-driven: Calculates character count based on actual elapsed time
|
|
689
|
-
- Batch processing: Can process multiple characters in a single frame
|
|
690
|
-
- Frame-synchronized: Syncs with browser 60fps refresh rate
|
|
691
|
-
- High-frequency optimized: Perfect support for interval < 16ms high-speed typing
|
|
561
|
+
### Core Components
|
|
692
562
|
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
563
|
+
```tsx
|
|
564
|
+
import {
|
|
565
|
+
Button,
|
|
566
|
+
IconButton,
|
|
567
|
+
ToolTip,
|
|
568
|
+
Segmented,
|
|
569
|
+
CopyButton,
|
|
570
|
+
DownloadButton
|
|
571
|
+
} from 'ds-markdown';
|
|
572
|
+
|
|
573
|
+
// Button component
|
|
574
|
+
<Button icon={<span>๐</span>} onClick={() => {}}>
|
|
575
|
+
Click Button
|
|
576
|
+
</Button>
|
|
577
|
+
|
|
578
|
+
// Tooltip
|
|
579
|
+
<ToolTip title="Tooltip information">
|
|
580
|
+
<IconButton icon={<span>๐</span>} onClick={() => {}} />
|
|
581
|
+
</ToolTip>
|
|
582
|
+
|
|
583
|
+
// Segmented controller
|
|
584
|
+
<Segmented
|
|
585
|
+
Segmented={[
|
|
586
|
+
{ label: 'Chart', value: 'diagram' },
|
|
587
|
+
{ label: 'Code', value: 'code' }
|
|
588
|
+
]}
|
|
589
|
+
value={value}
|
|
590
|
+
onChange={setValue}
|
|
591
|
+
/>
|
|
699
592
|
|
|
700
|
-
|
|
593
|
+
// Code block operations
|
|
594
|
+
<CopyButton codeContent="console.log('Hello')" />
|
|
595
|
+
<DownloadButton codeContent="console.log('Hello')" language="javascript" />
|
|
596
|
+
```
|
|
701
597
|
|
|
702
|
-
|
|
703
|
-
// ๐ฏ Features
|
|
704
|
-
- Single character: Precisely processes one character at a time
|
|
705
|
-
- Fixed interval: Strictly executes at set time intervals
|
|
706
|
-
- Rhythmic: Classic typewriter rhythm feel
|
|
707
|
-
- Precise control: Suitable for specific timing requirements
|
|
598
|
+
### Style Customization
|
|
708
599
|
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
-
|
|
712
|
-
-
|
|
600
|
+
```css
|
|
601
|
+
:root {
|
|
602
|
+
--ds-button-bg-color: #f5f5f5;
|
|
603
|
+
--ds-button-hover-color: #e0e0e0;
|
|
604
|
+
--ds-tooltip-bg-color: rgba(0, 0, 0, 0.8);
|
|
605
|
+
}
|
|
713
606
|
```
|
|
714
607
|
|
|
715
|
-
|
|
608
|
+
---
|
|
609
|
+
|
|
610
|
+
## Internationalization Configuration
|
|
611
|
+
|
|
612
|
+
```tsx
|
|
613
|
+
import { ConfigProvider } from 'ds-markdown';
|
|
614
|
+
import zhCN from 'ds-markdown/i18n/zh';
|
|
615
|
+
import enUS from 'ds-markdown/i18n/en';
|
|
716
616
|
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
| **Low Frequency** | โ
Normal (100ms โ 1 char/6 frames) | โ
Precise |
|
|
722
|
-
| **Visual Effect** | ๐ฌ Smooth animation feel | โก Precise rhythm feel |
|
|
723
|
-
| **Performance Overhead** | ๐ข Low (frame-synced) | ๐ก Medium (timer) |
|
|
617
|
+
// Chinese
|
|
618
|
+
<ConfigProvider locale={zhCN}>
|
|
619
|
+
<DsMarkdown {...props} />
|
|
620
|
+
</ConfigProvider>
|
|
724
621
|
|
|
725
|
-
|
|
622
|
+
// English
|
|
623
|
+
<ConfigProvider locale={enUS}>
|
|
624
|
+
<DsMarkdown {...props} />
|
|
625
|
+
</ConfigProvider>
|
|
626
|
+
```
|
|
726
627
|
|
|
727
628
|
---
|
|
728
629
|
|
|
@@ -732,7 +633,7 @@ High frequency recommended `requestAnimationFrame`, low frequency recommended `s
|
|
|
732
633
|
|
|
733
634
|
[DEMO: ๐ง StackBlitz Experience](https://stackblitz.com/edit/vitejs-vite-2ri8kex3?file=src%2FApp.tsx)
|
|
734
635
|
|
|
735
|
-
|
|
636
|
+
```tsx
|
|
736
637
|
import { useRef } from 'react';
|
|
737
638
|
import { MarkdownCMD, MarkdownCMDRef } from 'ds-markdown';
|
|
738
639
|
|
|
@@ -756,19 +657,6 @@ function StreamingChat() {
|
|
|
756
657
|
'- ๐ฏ **Automatic optimization**: No need for manual memo and useMemo\n',
|
|
757
658
|
'- โก **Performance boost**: Compile-time optimization, zero runtime overhead\n',
|
|
758
659
|
'- ๐ง **Backward compatible**: Existing code needs no modification\n\n',
|
|
759
|
-
'## ๐ Actions Simplify Forms\n',
|
|
760
|
-
'The new Actions API makes form handling simpler:\n\n',
|
|
761
|
-
'```tsx\n',
|
|
762
|
-
'function ContactForm({ action }) {\n',
|
|
763
|
-
' const [state, formAction] = useActionState(action, null);\n',
|
|
764
|
-
' return (\n',
|
|
765
|
-
' <form action={formAction}>\n',
|
|
766
|
-
' <input name="email" type="email" />\n',
|
|
767
|
-
' <button>Submit</button>\n',
|
|
768
|
-
' </form>\n',
|
|
769
|
-
' );\n',
|
|
770
|
-
'}\n',
|
|
771
|
-
'```\n\n',
|
|
772
660
|
'Hope this answer helps you! ๐',
|
|
773
661
|
];
|
|
774
662
|
|
|
@@ -778,273 +666,12 @@ function StreamingChat() {
|
|
|
778
666
|
}
|
|
779
667
|
};
|
|
780
668
|
|
|
669
|
+
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
670
|
+
|
|
781
671
|
return (
|
|
782
672
|
<div className="chat-container">
|
|
783
673
|
<button onClick={simulateAIResponse}>๐ค Ask about React 19 features</button>
|
|
784
|
-
|
|
785
|
-
<MarkdownCMD ref={markdownRef} interval={10} timerType="requestAnimationFrame" onEnd={(data) => console.log('Section complete:', data)} />
|
|
786
|
-
</div>
|
|
787
|
-
);
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
791
|
-
````
|
|
792
|
-
|
|
793
|
-
### ๐งฎ Mathematical Formula Streaming Rendering
|
|
794
|
-
|
|
795
|
-
```tsx
|
|
796
|
-
import { katexPlugin } from 'ds-markdown/plugins';
|
|
797
|
-
|
|
798
|
-
function MathStreamingDemo() {
|
|
799
|
-
const markdownRef = useRef<MarkdownCMDRef>(null);
|
|
800
|
-
|
|
801
|
-
const simulateMathResponse = async () => {
|
|
802
|
-
markdownRef.current?.clear();
|
|
803
|
-
|
|
804
|
-
const mathChunks = [
|
|
805
|
-
'# Pythagorean Theorem Explained\n\n',
|
|
806
|
-
'In a right triangle, the square of the hypotenuse equals the sum of squares of the two legs:\n\n',
|
|
807
|
-
'$a^2 + b^2 = c^2$\n\n',
|
|
808
|
-
'Where:\n',
|
|
809
|
-
'- $a$ and $b$ are the legs\n',
|
|
810
|
-
'- $c$ is the hypotenuse\n\n',
|
|
811
|
-
'For the classic "3-4-5" triangle:\n',
|
|
812
|
-
'$c = \\sqrt{3^2 + 4^2} = \\sqrt{25} = 5$\n\n',
|
|
813
|
-
'This theorem has wide applications in geometry!',
|
|
814
|
-
];
|
|
815
|
-
|
|
816
|
-
for (const chunk of mathChunks) {
|
|
817
|
-
await delay(150);
|
|
818
|
-
markdownRef.current?.push(chunk, 'answer');
|
|
819
|
-
}
|
|
820
|
-
};
|
|
821
|
-
|
|
822
|
-
return (
|
|
823
|
-
<div>
|
|
824
|
-
<button onClick={simulateMathResponse}>๐ Explain Pythagorean Theorem</button>
|
|
825
|
-
|
|
826
|
-
<MarkdownCMD ref={markdownRef} interval={20} timerType="requestAnimationFrame" plugins={[katexPlugin]} math={{ splitSymbol: 'dollar' }} />
|
|
827
|
-
</div>
|
|
828
|
-
);
|
|
829
|
-
}
|
|
830
|
-
```
|
|
831
|
-
|
|
832
|
-
### ๐ฏ Advanced Callback Control
|
|
833
|
-
|
|
834
|
-
```tsx
|
|
835
|
-
import { useRef, useState } from 'react';
|
|
836
|
-
import { MarkdownCMD, MarkdownCMDRef } from 'ds-markdown';
|
|
837
|
-
|
|
838
|
-
function AdvancedCallbackDemo() {
|
|
839
|
-
const markdownRef = useRef<MarkdownCMDRef>(null);
|
|
840
|
-
const [typingStats, setTypingStats] = useState({ progress: 0, currentChar: '', totalChars: 0 });
|
|
841
|
-
|
|
842
|
-
const handleBeforeTypedChar = async (data) => {
|
|
843
|
-
// Perform async operations before character typing
|
|
844
|
-
console.log('About to type:', data.currentChar);
|
|
845
|
-
|
|
846
|
-
// Can perform network requests, data validation, etc.
|
|
847
|
-
if (data.currentChar === '!') {
|
|
848
|
-
await new Promise((resolve) => setTimeout(resolve, 500)); // Simulate delay
|
|
849
|
-
}
|
|
850
|
-
};
|
|
851
|
-
|
|
852
|
-
const handleTypedChar = (data) => {
|
|
853
|
-
// Update typing statistics
|
|
854
|
-
setTypingStats({
|
|
855
|
-
progress: Math.round(data.percent),
|
|
856
|
-
currentChar: data.currentChar,
|
|
857
|
-
totalChars: data.currentIndex + 1,
|
|
858
|
-
});
|
|
859
|
-
|
|
860
|
-
// Can add sound effects, animations, etc.
|
|
861
|
-
if (data.currentChar === '.') {
|
|
862
|
-
// Play period sound effect
|
|
863
|
-
console.log('Play period sound effect');
|
|
864
|
-
}
|
|
865
|
-
};
|
|
866
|
-
|
|
867
|
-
const handleStart = (data) => {
|
|
868
|
-
console.log('Start typing:', data.currentChar);
|
|
869
|
-
};
|
|
870
|
-
|
|
871
|
-
const handleEnd = (data) => {
|
|
872
|
-
console.log('Typing complete:', data.str);
|
|
873
|
-
};
|
|
874
|
-
|
|
875
|
-
const startDemo = () => {
|
|
876
|
-
markdownRef.current?.clear();
|
|
877
|
-
markdownRef.current?.push(
|
|
878
|
-
'# Advanced Callback Demo\n\n' +
|
|
879
|
-
'This example shows how to use `onBeforeTypedChar` and `onTypedChar` callbacks:\n\n' +
|
|
880
|
-
'- ๐ฏ **Pre-typing callback**: Can perform async operations before character display\n' +
|
|
881
|
-
'- ๐ **Post-typing callback**: Can update progress in real-time and add effects\n' +
|
|
882
|
-
'- โก **Performance optimization**: Supports async operations without affecting typing smoothness\n\n' +
|
|
883
|
-
'Current progress: ' +
|
|
884
|
-
typingStats.progress +
|
|
885
|
-
'%\n' +
|
|
886
|
-
'Characters typed: ' +
|
|
887
|
-
typingStats.totalChars +
|
|
888
|
-
'\n\n' +
|
|
889
|
-
'This is a very powerful feature!',
|
|
890
|
-
'answer',
|
|
891
|
-
);
|
|
892
|
-
};
|
|
893
|
-
|
|
894
|
-
return (
|
|
895
|
-
<div>
|
|
896
|
-
<button onClick={startDemo}>๐ Start Advanced Demo</button>
|
|
897
|
-
|
|
898
|
-
<div style={{ margin: '10px 0', padding: '10px', background: '#f5f5f5', borderRadius: '4px' }}>
|
|
899
|
-
<strong>Typing Stats:</strong> Progress {typingStats.progress}% | Current char: "{typingStats.currentChar}" | Total chars: {typingStats.totalChars}
|
|
900
|
-
</div>
|
|
901
|
-
|
|
902
|
-
<MarkdownCMD ref={markdownRef} interval={30} onBeforeTypedChar={handleBeforeTypedChar} onTypedChar={handleTypedChar} onStart={handleStart} onEnd={handleEnd} />
|
|
903
|
-
</div>
|
|
904
|
-
);
|
|
905
|
-
}
|
|
906
|
-
```
|
|
907
|
-
|
|
908
|
-
### ๐ Restart Animation Demo
|
|
909
|
-
|
|
910
|
-
```tsx
|
|
911
|
-
import { useRef, useState } from 'react';
|
|
912
|
-
import { MarkdownCMD, MarkdownCMDRef } from 'ds-markdown';
|
|
913
|
-
|
|
914
|
-
function RestartDemo() {
|
|
915
|
-
const markdownRef = useRef<MarkdownCMDRef>(null);
|
|
916
|
-
const [isPlaying, setIsPlaying] = useState(false);
|
|
917
|
-
const [hasStarted, setHasStarted] = useState(false);
|
|
918
|
-
|
|
919
|
-
const startContent = () => {
|
|
920
|
-
markdownRef.current?.clear();
|
|
921
|
-
markdownRef.current?.push(
|
|
922
|
-
'# Restart Animation Demo\n\n' +
|
|
923
|
-
'This example shows how to use the `restart()` method:\n\n' +
|
|
924
|
-
'- ๐ **Restart**: Play current content from the beginning\n' +
|
|
925
|
-
'- โธ๏ธ **Pause/Resume**: Can pause and resume at any time\n' +
|
|
926
|
-
'- ๐ฏ **Precise Control**: Complete control over animation playback state\n\n' +
|
|
927
|
-
'Current state: ' +
|
|
928
|
-
(isPlaying ? 'Playing' : 'Paused') +
|
|
929
|
-
'\n\n' +
|
|
930
|
-
'This is a very practical feature!',
|
|
931
|
-
'answer',
|
|
932
|
-
);
|
|
933
|
-
setIsPlaying(true);
|
|
934
|
-
};
|
|
935
|
-
|
|
936
|
-
const handleStart = () => {
|
|
937
|
-
if (hasStarted) {
|
|
938
|
-
// If already started, restart
|
|
939
|
-
markdownRef.current?.restart();
|
|
940
|
-
} else {
|
|
941
|
-
// First time start
|
|
942
|
-
markdownRef.current?.start();
|
|
943
|
-
setHasStarted(true);
|
|
944
|
-
}
|
|
945
|
-
setIsPlaying(true);
|
|
946
|
-
};
|
|
947
|
-
|
|
948
|
-
const handleStop = () => {
|
|
949
|
-
markdownRef.current?.stop();
|
|
950
|
-
setIsPlaying(false);
|
|
951
|
-
};
|
|
952
|
-
|
|
953
|
-
const handleResume = () => {
|
|
954
|
-
markdownRef.current?.resume();
|
|
955
|
-
setIsPlaying(true);
|
|
956
|
-
};
|
|
957
|
-
|
|
958
|
-
const handleRestart = () => {
|
|
959
|
-
markdownRef.current?.restart();
|
|
960
|
-
setIsPlaying(true);
|
|
961
|
-
};
|
|
962
|
-
|
|
963
|
-
const handleEnd = () => {
|
|
964
|
-
setIsPlaying(false);
|
|
965
|
-
};
|
|
966
|
-
|
|
967
|
-
return (
|
|
968
|
-
<div>
|
|
969
|
-
<div style={{ marginBottom: '10px', display: 'flex', gap: '10px', flexWrap: 'wrap' }}>
|
|
970
|
-
<button onClick={startContent}>๐ Start Content</button>
|
|
971
|
-
<button onClick={handleStart} disabled={isPlaying}>
|
|
972
|
-
{hasStarted ? '๐ Restart' : 'โถ๏ธ Start'}
|
|
973
|
-
</button>
|
|
974
|
-
<button onClick={handleStop} disabled={!isPlaying}>
|
|
975
|
-
โธ๏ธ Pause
|
|
976
|
-
</button>
|
|
977
|
-
<button onClick={handleResume} disabled={isPlaying}>
|
|
978
|
-
โถ๏ธ Resume
|
|
979
|
-
</button>
|
|
980
|
-
<button onClick={handleRestart}>๐ Restart</button>
|
|
981
|
-
</div>
|
|
982
|
-
|
|
983
|
-
<div style={{ margin: '10px 0', padding: '10px', background: '#f5f5f5', borderRadius: '4px' }}>
|
|
984
|
-
<strong>Animation State:</strong> {isPlaying ? '๐ข Playing' : '๐ด Paused'}
|
|
985
|
-
</div>
|
|
986
|
-
|
|
987
|
-
<MarkdownCMD ref={markdownRef} interval={25} onEnd={handleEnd} />
|
|
988
|
-
</div>
|
|
989
|
-
);
|
|
990
|
-
}
|
|
991
|
-
```
|
|
992
|
-
|
|
993
|
-
### โถ๏ธ Manual Start Animation Demo
|
|
994
|
-
|
|
995
|
-
```tsx
|
|
996
|
-
import { useRef, useState } from 'react';
|
|
997
|
-
import { MarkdownCMD, MarkdownCMDRef } from 'ds-markdown';
|
|
998
|
-
|
|
999
|
-
function StartDemo() {
|
|
1000
|
-
const markdownRef = useRef<MarkdownCMDRef>(null);
|
|
1001
|
-
const [isPlaying, setIsPlaying] = useState(false);
|
|
1002
|
-
const [hasStarted, setHasStarted] = useState(false);
|
|
1003
|
-
|
|
1004
|
-
const loadContent = () => {
|
|
1005
|
-
markdownRef.current?.clear();
|
|
1006
|
-
markdownRef.current?.push(
|
|
1007
|
-
'# Manual Start Animation Demo\n\n' +
|
|
1008
|
-
'This example shows how to use the `start()` method:\n\n' +
|
|
1009
|
-
'- ๐ฏ **Manual Control**: When `autoStartTyping=false`, need to manually call `start()`\n' +
|
|
1010
|
-
'- โฑ๏ธ **Delayed Start**: Can start animation after user interaction\n' +
|
|
1011
|
-
'- ๐ฎ **Gamification**: Suitable for scenarios requiring user initiative\n\n' +
|
|
1012
|
-
'Click the "Start Animation" button to manually trigger the typing effect!',
|
|
1013
|
-
'answer',
|
|
1014
|
-
);
|
|
1015
|
-
setIsPlaying(false);
|
|
1016
|
-
};
|
|
1017
|
-
|
|
1018
|
-
const handleStart = () => {
|
|
1019
|
-
if (hasStarted) {
|
|
1020
|
-
// If already started, restart
|
|
1021
|
-
markdownRef.current?.restart();
|
|
1022
|
-
} else {
|
|
1023
|
-
// First time start
|
|
1024
|
-
markdownRef.current?.start();
|
|
1025
|
-
setHasStarted(true);
|
|
1026
|
-
}
|
|
1027
|
-
setIsPlaying(true);
|
|
1028
|
-
};
|
|
1029
|
-
|
|
1030
|
-
const handleEnd = () => {
|
|
1031
|
-
setIsPlaying(false);
|
|
1032
|
-
};
|
|
1033
|
-
|
|
1034
|
-
return (
|
|
1035
|
-
<div>
|
|
1036
|
-
<div style={{ marginBottom: '10px', display: 'flex', gap: '10px', flexWrap: 'wrap' }}>
|
|
1037
|
-
<button onClick={loadContent}>๐ Load Content</button>
|
|
1038
|
-
<button onClick={handleStart} disabled={isPlaying}>
|
|
1039
|
-
{hasStarted ? '๐ Restart' : 'โถ๏ธ Start Animation'}
|
|
1040
|
-
</button>
|
|
1041
|
-
</div>
|
|
1042
|
-
|
|
1043
|
-
<div style={{ margin: '10px 0', padding: '10px', background: '#f5f5f5', borderRadius: '4px' }}>
|
|
1044
|
-
<strong>State:</strong> {isPlaying ? '๐ข Animation Playing' : '๐ด Waiting to Start'}
|
|
1045
|
-
</div>
|
|
1046
|
-
|
|
1047
|
-
<MarkdownCMD ref={markdownRef} interval={30} autoStartTyping={false} onEnd={handleEnd} />
|
|
674
|
+
<MarkdownCMD ref={markdownRef} interval={10} timerType="requestAnimationFrame" />
|
|
1048
675
|
</div>
|
|
1049
676
|
);
|
|
1050
677
|
}
|
|
@@ -1060,9 +687,6 @@ function StartDemo() {
|
|
|
1060
687
|
timerType="requestAnimationFrame"
|
|
1061
688
|
interval={15} // 15-30ms for best experience
|
|
1062
689
|
/>
|
|
1063
|
-
|
|
1064
|
-
// โ Avoid too small intervals
|
|
1065
|
-
<DsMarkdown interval={1} /> // May cause performance issues
|
|
1066
690
|
```
|
|
1067
691
|
|
|
1068
692
|
### 2. Streaming Data Processing
|
|
@@ -1073,141 +697,31 @@ const ref = useRef<MarkdownCMDRef>(null);
|
|
|
1073
697
|
useEffect(() => {
|
|
1074
698
|
ref.current?.push(newChunk, 'answer');
|
|
1075
699
|
}, [newChunk]);
|
|
1076
|
-
|
|
1077
|
-
// โ Avoid: Frequent children updates
|
|
1078
|
-
const [content, setContent] = useState('');
|
|
1079
|
-
// Each update re-parses the entire content
|
|
1080
700
|
```
|
|
1081
701
|
|
|
1082
702
|
### 3. Mathematical Formula Optimization
|
|
1083
703
|
|
|
1084
704
|
```tsx
|
|
1085
|
-
// โ
Recommended: Load
|
|
1086
|
-
import 'ds-markdown/
|
|
705
|
+
// โ
Recommended: Load on demand
|
|
706
|
+
import { katexPlugin } from 'ds-markdown/plugins';
|
|
1087
707
|
import 'ds-markdown/katex.css'; // Only import when needed
|
|
1088
708
|
|
|
1089
|
-
// โ
Recommended: Use delimiters appropriately
|
|
1090
|
-
// For simple formulas, use $...$ for simplicity
|
|
1091
|
-
// For complex formulas, use $$...$$ for clarity
|
|
1092
|
-
|
|
1093
|
-
// โ
Recommended: Plugin configuration
|
|
1094
|
-
import { katexPlugin } from 'ds-markdown/plugins';
|
|
1095
709
|
<DsMarkdown plugins={[katexPlugin]}>Mathematical formula content</DsMarkdown>;
|
|
1096
710
|
```
|
|
1097
711
|
|
|
1098
|
-
### 4.
|
|
712
|
+
### 4. Mermaid Chart Best Practices ๐
|
|
1099
713
|
|
|
1100
714
|
```tsx
|
|
1101
|
-
|
|
715
|
+
// โ
Recommended: Install plugin separately
|
|
716
|
+
npm install ds-markdown-mermaid-plugin
|
|
1102
717
|
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
## ConfigProvider Internationalization (i18n)
|
|
1108
|
-
|
|
1109
|
-
ConfigProvider is a component provided by ds-markdown for managing internationalized text in your application.
|
|
1110
|
-
|
|
1111
|
-
### Basic Usage
|
|
1112
|
-
|
|
1113
|
-
```tsx
|
|
1114
|
-
import React from 'react';
|
|
1115
|
-
import { ConfigProvider } from 'ds-markdown';
|
|
1116
|
-
import zhCN from 'ds-markdown/i18n/zh';
|
|
1117
|
-
|
|
1118
|
-
const App: React.FC = () => {
|
|
1119
|
-
return (
|
|
1120
|
-
<ConfigProvider locale={zhCN}>
|
|
1121
|
-
<YourApp />
|
|
1122
|
-
</ConfigProvider>
|
|
1123
|
-
);
|
|
718
|
+
// โ
Recommended: Configure suitable theme
|
|
719
|
+
const mermaidConfig = {
|
|
720
|
+
theme: 'default', // Choose based on application theme
|
|
721
|
+
flowchart: { useMaxWidth: true },
|
|
1124
722
|
};
|
|
1125
|
-
```
|
|
1126
|
-
|
|
1127
|
-
### Available Locales
|
|
1128
|
-
|
|
1129
|
-
#### Chinese (zhCN)
|
|
1130
723
|
|
|
1131
|
-
|
|
1132
|
-
|
|
724
|
+
<ConfigProvider mermaidConfig={mermaidConfig}>
|
|
725
|
+
<DsMarkdown plugins={[mermaidPlugin]} />
|
|
726
|
+
</ConfigProvider>
|
|
1133
727
|
```
|
|
1134
|
-
|
|
1135
|
-
#### English (enUS)
|
|
1136
|
-
|
|
1137
|
-
```tsx
|
|
1138
|
-
import enUS from 'ds-markdown/i18n/en';
|
|
1139
|
-
```
|
|
1140
|
-
|
|
1141
|
-
### Using Locale in Components
|
|
1142
|
-
|
|
1143
|
-
Use the `useLocale` hook to get the current locale:
|
|
1144
|
-
|
|
1145
|
-
```tsx
|
|
1146
|
-
import React from 'react';
|
|
1147
|
-
import { useLocale } from 'ds-markdown';
|
|
1148
|
-
|
|
1149
|
-
const MyComponent: React.FC = () => {
|
|
1150
|
-
const locale = useLocale();
|
|
1151
|
-
|
|
1152
|
-
return (
|
|
1153
|
-
<div>
|
|
1154
|
-
<button>{locale.codeBlock.copy}</button>
|
|
1155
|
-
<span>{locale.codeBlock.copied}</span>
|
|
1156
|
-
<button>{locale.codeBlock.download}</button>
|
|
1157
|
-
</div>
|
|
1158
|
-
);
|
|
1159
|
-
};
|
|
1160
|
-
```
|
|
1161
|
-
|
|
1162
|
-
### Locale Structure
|
|
1163
|
-
|
|
1164
|
-
Currently supported locale fields:
|
|
1165
|
-
|
|
1166
|
-
```typescript
|
|
1167
|
-
interface Locale {
|
|
1168
|
-
codeBlock: {
|
|
1169
|
-
copy: string;
|
|
1170
|
-
copied: string;
|
|
1171
|
-
download: string;
|
|
1172
|
-
};
|
|
1173
|
-
[key: string]: string;
|
|
1174
|
-
}
|
|
1175
|
-
```
|
|
1176
|
-
|
|
1177
|
-
### Full Example
|
|
1178
|
-
|
|
1179
|
-
```tsx
|
|
1180
|
-
import React from 'react';
|
|
1181
|
-
import { ConfigProvider, useLocale } from 'ds-markdown';
|
|
1182
|
-
import zhCN from 'ds-markdown/i18n/zh';
|
|
1183
|
-
|
|
1184
|
-
const ExampleComponent: React.FC = () => {
|
|
1185
|
-
const locale = useLocale();
|
|
1186
|
-
|
|
1187
|
-
return (
|
|
1188
|
-
<div>
|
|
1189
|
-
<h2>i18n Example</h2>
|
|
1190
|
-
<p>Copy button: {locale.codeBlock.copy}</p>
|
|
1191
|
-
<p>Copied tip: {locale.codeBlock.copied}</p>
|
|
1192
|
-
<p>Download button: {locale.codeBlock.download}</p>
|
|
1193
|
-
</div>
|
|
1194
|
-
);
|
|
1195
|
-
};
|
|
1196
|
-
|
|
1197
|
-
const App: React.FC = () => {
|
|
1198
|
-
return (
|
|
1199
|
-
<ConfigProvider locale={zhCN}>
|
|
1200
|
-
<ExampleComponent />
|
|
1201
|
-
</ConfigProvider>
|
|
1202
|
-
);
|
|
1203
|
-
};
|
|
1204
|
-
|
|
1205
|
-
export default App;
|
|
1206
|
-
```
|
|
1207
|
-
|
|
1208
|
-
### Notes
|
|
1209
|
-
|
|
1210
|
-
1. `ConfigProvider` must wrap components that use `useLocale`.
|
|
1211
|
-
2. The locale object is memoized to avoid unnecessary re-renders.
|
|
1212
|
-
3. You can extend the locale object with custom fields.
|
|
1213
|
-
4. If `ConfigProvider` is not provided, the default locale is Chinese.
|