ds-markdown 0.1.9 → 0.1.10-beta.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 +56 -879
- package/dist/cjs/index.d.ts +2 -0
- package/dist/cjs/index.js +33 -7
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.js +33 -7
- package/dist/esm/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -12,9 +12,13 @@
|
|
|
12
12
|
[](https://react.dev)
|
|
13
13
|
[](https://www.typescriptlang.org/)
|
|
14
14
|
|
|
15
|
-
[
|
|
15
|
+
[使用文档](https://onshinpei.github.io/ds-markdown/)
|
|
16
16
|
|
|
17
|
-
[
|
|
17
|
+
- [基本用法](https://stackblitz.com/edit/vitejs-vite-ddfw8avb?file=src%2FApp.tsx)
|
|
18
|
+
- [流式数据用法](https://stackblitz.com/edit/vitejs-vite-2ri8kex3?file=src%2FApp.tsx)
|
|
19
|
+
- [mermaid图表](https://stackblitz.com/edit/vitejs-vite-iqbyta3j?file=index.html)
|
|
20
|
+
- [数学公式demo1](https://stackblitz.com/edit/vitejs-vite-iqbyta3j?file=index.html)
|
|
21
|
+
- [数学公式demo2](https://stackblitz.com/edit/vitejs-vite-xk9lxagc?file=src%2FApp.tsx)
|
|
18
22
|
|
|
19
23
|
如果你想要一个纯净的`react markdown` 打字组件,可以使用[react-markdown-typer](https://github.com/onshinpei/react-markdown-typer)
|
|
20
24
|
|
|
@@ -67,18 +71,9 @@
|
|
|
67
71
|
- [代码块功能](#代码块功能) 🆕
|
|
68
72
|
- [Mermaid图表支持](#mermaid图表支持) 🆕
|
|
69
73
|
- [📚 完整 API 文档](#-完整-api-文档)
|
|
70
|
-
- [🧮 数学公式使用指南](#-数学公式使用指南)
|
|
71
74
|
- [🔌 插件系统](#-插件系统)
|
|
72
75
|
- [🎨 UI组件系统](#-ui组件系统) 🆕
|
|
73
|
-
- [🎛️ 定时器模式详解](#️-定时器模式详解)
|
|
74
76
|
- [💡 实战示例](#-实战示例)
|
|
75
|
-
- [🎯 高级回调控制](#-高级回调控制)
|
|
76
|
-
- [🔄 重新开始动画演示](#-重新开始动画演示)
|
|
77
|
-
- [▶️ 手动开始动画演示](#️-手动开始动画演示)
|
|
78
|
-
- [📝 AI 流式对话](#-ai-流式对话)
|
|
79
|
-
- [🧮 数学公式流式渲染](#-数学公式流式渲染)
|
|
80
|
-
- [📊 Mermaid图表流式渲染](#-mermaid图表流式渲染) 🆕
|
|
81
|
-
- [多语言配置](#多语言配置)
|
|
82
77
|
- [🔧 最佳实践](#-最佳实践)
|
|
83
78
|
|
|
84
79
|
---
|
|
@@ -444,99 +439,14 @@ markdownRef.current?.restart(); // 重新开始动画
|
|
|
444
439
|
|
|
445
440
|
---
|
|
446
441
|
|
|
447
|
-
## 🧮 数学公式使用指南
|
|
448
|
-
|
|
449
|
-
[DEMO1:勾股定理](https://stackblitz.com/edit/vitejs-vite-z94syu8j?file=src%2FApp.tsx)
|
|
450
|
-
|
|
451
|
-
[DEMO2:题目解答](https://stackblitz.com/edit/vitejs-vite-xk9lxagc?file=README.md)
|
|
452
|
-
|
|
453
|
-
### 基本语法
|
|
454
|
-
|
|
455
|
-
```tsx
|
|
456
|
-
import { katexPlugin } from 'ds-markdown/plugins';
|
|
457
|
-
|
|
458
|
-
// 1. 启用数学公式支持
|
|
459
|
-
<DsMarkdown plugins={[katexPlugin]}>
|
|
460
|
-
# 数学公式示例
|
|
461
|
-
|
|
462
|
-
// 行内公式
|
|
463
|
-
这是一个行内公式:$E = mc^2$
|
|
464
|
-
|
|
465
|
-
// 块级公式
|
|
466
|
-
$$\int_{-\infty}^{\infty} e^{-x^2} dx = \sqrt{\pi}$$
|
|
467
|
-
</DsMarkdown>
|
|
468
|
-
```
|
|
469
|
-
|
|
470
|
-
### 分隔符选择
|
|
471
|
-
|
|
472
|
-
```tsx
|
|
473
|
-
// 使用美元符号分隔符(默认)
|
|
474
|
-
<DsMarkdown
|
|
475
|
-
plugins={[katexPlugin]}
|
|
476
|
-
math={{ splitSymbol: 'dollar' }}
|
|
477
|
-
>
|
|
478
|
-
行内:$a + b = c$
|
|
479
|
-
块级:$$\sum_{i=1}^{n} x_i = x_1 + x_2 + \cdots + x_n$$
|
|
480
|
-
</DsMarkdown>
|
|
481
|
-
|
|
482
|
-
// 使用括号分隔符
|
|
483
|
-
<DsMarkdown
|
|
484
|
-
plugins={[katexPlugin]}
|
|
485
|
-
math={{ splitSymbol: 'bracket' }}
|
|
486
|
-
>
|
|
487
|
-
行内:\(a + b = c\)
|
|
488
|
-
块级:\[\sum_{i=1}^{n} x_i = x_1 + x_2 + \cdots + x_n\]
|
|
489
|
-
</DsMarkdown>
|
|
490
|
-
```
|
|
491
|
-
|
|
492
|
-
### 流式数学公式
|
|
493
|
-
|
|
494
|
-
```tsx
|
|
495
|
-
// 完美支持流式输出中的数学公式
|
|
496
|
-
const mathContent = [
|
|
497
|
-
'勾股定理:',
|
|
498
|
-
'$a^2 + b^2 = c^2$',
|
|
499
|
-
'\n\n',
|
|
500
|
-
'其中:',
|
|
501
|
-
'- $a$ 和 $b$ 是直角边\n',
|
|
502
|
-
'- $c$ 是斜边\n\n',
|
|
503
|
-
'对于经典的"勾三股四弦五":\n',
|
|
504
|
-
'$c = \\sqrt{3^2 + 4^2} = \\sqrt{25} = 5$\n\n',
|
|
505
|
-
'这个定理在几何学中有着广泛的应用!',
|
|
506
|
-
];
|
|
507
|
-
|
|
508
|
-
mathContent.forEach((chunk) => {
|
|
509
|
-
markdownRef.current?.push(chunk, 'answer');
|
|
510
|
-
});
|
|
511
|
-
```
|
|
512
|
-
|
|
513
|
-
### 样式定制
|
|
514
|
-
|
|
515
|
-
```css
|
|
516
|
-
/* 数学公式样式定制 */
|
|
517
|
-
.katex {
|
|
518
|
-
font-size: 1.1em;
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
.katex-display {
|
|
522
|
-
margin: 1em 0;
|
|
523
|
-
text-align: center;
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
/* 暗色主题适配 */
|
|
527
|
-
[data-theme='dark'] .katex {
|
|
528
|
-
color: #e1e1e1;
|
|
529
|
-
}
|
|
530
|
-
```
|
|
531
|
-
|
|
532
|
-
---
|
|
533
|
-
|
|
534
442
|
## 🔌 插件系统
|
|
535
443
|
|
|
536
444
|
### 内置插件
|
|
537
445
|
|
|
538
446
|
#### KaTeX 数学公式插件
|
|
539
447
|
|
|
448
|
+
[DEMO](https://stackblitz.com/edit/vitejs-vite-iqbyta3j?file=index.html)
|
|
449
|
+
|
|
540
450
|
```tsx
|
|
541
451
|
import { katexPlugin } from 'ds-markdown/plugins';
|
|
542
452
|
|
|
@@ -644,590 +554,84 @@ const customPlugin = createBuildInPlugin({
|
|
|
644
554
|
|
|
645
555
|
## 🎨 UI组件系统 🆕
|
|
646
556
|
|
|
647
|
-
ds-markdown
|
|
648
|
-
|
|
649
|
-
### Button 组件
|
|
650
|
-
|
|
651
|
-
通用按钮组件,支持图标和自定义样式。
|
|
652
|
-
|
|
653
|
-
```tsx
|
|
654
|
-
import { Button } from 'ds-markdown';
|
|
655
|
-
|
|
656
|
-
function ButtonDemo() {
|
|
657
|
-
return (
|
|
658
|
-
<Button icon={<span>📄</span>} onClick={() => console.log('clicked')} className="my-button">
|
|
659
|
-
点击按钮
|
|
660
|
-
</Button>
|
|
661
|
-
);
|
|
662
|
-
}
|
|
663
|
-
```
|
|
664
|
-
|
|
665
|
-
### IconButton 组件
|
|
557
|
+
ds-markdown 提供了丰富的UI组件,可以单独使用或与markdown组件配合。
|
|
666
558
|
|
|
667
|
-
|
|
559
|
+
### 核心组件
|
|
668
560
|
|
|
669
561
|
```tsx
|
|
670
|
-
import {
|
|
562
|
+
import {
|
|
563
|
+
Button,
|
|
564
|
+
IconButton,
|
|
565
|
+
ToolTip,
|
|
566
|
+
Segmented,
|
|
567
|
+
CopyButton,
|
|
568
|
+
DownloadButton
|
|
569
|
+
} from 'ds-markdown';
|
|
671
570
|
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
571
|
+
// 按钮组件
|
|
572
|
+
<Button icon={<span>📄</span>} onClick={() => {}}>
|
|
573
|
+
点击按钮
|
|
574
|
+
</Button>
|
|
676
575
|
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
```tsx
|
|
682
|
-
import { ToolTip } from 'ds-markdown';
|
|
683
|
-
|
|
684
|
-
function ToolTipDemo() {
|
|
685
|
-
return (
|
|
686
|
-
<ToolTip title="这是一个提示信息">
|
|
687
|
-
<button>悬停查看提示</button>
|
|
688
|
-
</ToolTip>
|
|
689
|
-
);
|
|
690
|
-
}
|
|
691
|
-
```
|
|
692
|
-
|
|
693
|
-
### Segmented 分段控制器
|
|
694
|
-
|
|
695
|
-
分段控制器组件,适用于选项切换场景。
|
|
696
|
-
|
|
697
|
-
```tsx
|
|
698
|
-
import { Segmented } from 'ds-markdown';
|
|
699
|
-
import { useState } from 'react';
|
|
700
|
-
|
|
701
|
-
function SegmentedDemo() {
|
|
702
|
-
const [value, setValue] = useState('diagram');
|
|
576
|
+
// 工具提示
|
|
577
|
+
<ToolTip title="提示信息">
|
|
578
|
+
<IconButton icon={<span>📋</span>} onClick={() => {}} />
|
|
579
|
+
</ToolTip>
|
|
703
580
|
|
|
704
|
-
|
|
581
|
+
// 分段控制器
|
|
582
|
+
<Segmented
|
|
583
|
+
Segmented={[
|
|
705
584
|
{ label: '图表', value: 'diagram' },
|
|
706
|
-
{ label: '代码', value: 'code' }
|
|
707
|
-
]
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
```
|
|
712
|
-
|
|
713
|
-
### 代码块组件
|
|
714
|
-
|
|
715
|
-
代码块相关的交互组件,提供复制、下载等功能。
|
|
716
|
-
|
|
717
|
-
```tsx
|
|
718
|
-
import { CodeBlockActions, CopyButton, DownloadButton, CodeBlockWrap, HighlightCode } from 'ds-markdown';
|
|
719
|
-
|
|
720
|
-
function MyCodeBlock() {
|
|
721
|
-
const codeContent = 'console.log("Hello World");';
|
|
585
|
+
{ label: '代码', value: 'code' }
|
|
586
|
+
]}
|
|
587
|
+
value={value}
|
|
588
|
+
onChange={setValue}
|
|
589
|
+
/>
|
|
722
590
|
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
<CodeBlockActions codeContent={codeContent} language="javascript" />
|
|
727
|
-
|
|
728
|
-
{/* 或者单独使用各个组件 */}
|
|
729
|
-
<CopyButton codeContent={codeContent} />
|
|
730
|
-
<DownloadButton codeContent={codeContent} language="javascript" />
|
|
731
|
-
|
|
732
|
-
{/* 代码块包装器 */}
|
|
733
|
-
<CodeBlockWrap language="javascript">
|
|
734
|
-
<HighlightCode code={codeContent} language="javascript" />
|
|
735
|
-
</CodeBlockWrap>
|
|
736
|
-
</div>
|
|
737
|
-
);
|
|
738
|
-
}
|
|
591
|
+
// 代码块操作
|
|
592
|
+
<CopyButton codeContent="console.log('Hello')" />
|
|
593
|
+
<DownloadButton codeContent="console.log('Hello')" language="javascript" />
|
|
739
594
|
```
|
|
740
595
|
|
|
741
|
-
### UI组件完整API
|
|
742
|
-
|
|
743
|
-
#### Button Props
|
|
744
|
-
|
|
745
|
-
| 属性 | 类型 | 说明 | 默认值 |
|
|
746
|
-
| ----------- | --------------------- | ---------- | ------ |
|
|
747
|
-
| `className` | `string` | 自定义类名 | - |
|
|
748
|
-
| `children` | `React.ReactNode` | 按钮内容 | - |
|
|
749
|
-
| `icon` | `React.ReactNode` | 按钮图标 | - |
|
|
750
|
-
| `onClick` | `() => void` | 点击回调 | - |
|
|
751
|
-
| `style` | `React.CSSProperties` | 自定义样式 | - |
|
|
752
|
-
|
|
753
|
-
#### IconButton Props
|
|
754
|
-
|
|
755
|
-
| 属性 | 类型 | 说明 | 默认值 |
|
|
756
|
-
| ----------- | --------------------- | ---------- | ------ |
|
|
757
|
-
| `className` | `string` | 自定义类名 | - |
|
|
758
|
-
| `icon` | `React.ReactNode` | 图标内容 | - |
|
|
759
|
-
| `onClick` | `() => void` | 点击回调 | - |
|
|
760
|
-
| `style` | `React.CSSProperties` | 自定义样式 | - |
|
|
761
|
-
|
|
762
|
-
#### ToolTip Props
|
|
763
|
-
|
|
764
|
-
| 属性 | 类型 | 说明 | 默认值 |
|
|
765
|
-
| ---------- | ----------------- | -------- | ------ |
|
|
766
|
-
| `title` | `string` | 提示文本 | - |
|
|
767
|
-
| `children` | `React.ReactNode` | 子元素 | - |
|
|
768
|
-
|
|
769
|
-
#### Segmented Props
|
|
770
|
-
|
|
771
|
-
| 属性 | 类型 | 说明 | 默认值 |
|
|
772
|
-
| ----------- | ------------------------- | ---------- | ------ |
|
|
773
|
-
| `Segmented` | `SegmentedItem[]` | 选项列表 | - |
|
|
774
|
-
| `value` | `string` | 当前选中值 | - |
|
|
775
|
-
| `onChange` | `(value: string) => void` | 值变化回调 | - |
|
|
776
|
-
|
|
777
|
-
#### SegmentedItem
|
|
778
|
-
|
|
779
|
-
| 属性 | 类型 | 说明 | 默认值 |
|
|
780
|
-
| ------- | -------- | -------- | ------ |
|
|
781
|
-
| `label` | `string` | 显示文本 | - |
|
|
782
|
-
| `value` | `string` | 选项值 | - |
|
|
783
|
-
|
|
784
|
-
#### CodeBlockActions Props
|
|
785
|
-
|
|
786
|
-
| 属性 | 类型 | 说明 | 默认值 |
|
|
787
|
-
| ------------- | -------- | -------- | ------ |
|
|
788
|
-
| `codeContent` | `string` | 代码内容 | - |
|
|
789
|
-
| `language` | `string` | 代码语言 | - |
|
|
790
|
-
|
|
791
|
-
#### CopyButton Props
|
|
792
|
-
|
|
793
|
-
| 属性 | 类型 | 说明 | 默认值 |
|
|
794
|
-
| ------------- | --------------------- | ---------- | ------ |
|
|
795
|
-
| `codeContent` | `string` | 代码内容 | - |
|
|
796
|
-
| `style` | `React.CSSProperties` | 自定义样式 | - |
|
|
797
|
-
|
|
798
|
-
#### DownloadButton Props
|
|
799
|
-
|
|
800
|
-
| 属性 | 类型 | 说明 | 默认值 |
|
|
801
|
-
| ------------- | --------------------- | ---------- | ------ |
|
|
802
|
-
| `codeContent` | `string` | 代码内容 | - |
|
|
803
|
-
| `language` | `string` | 代码语言 | - |
|
|
804
|
-
| `style` | `React.CSSProperties` | 自定义样式 | - |
|
|
805
|
-
|
|
806
596
|
### 样式定制
|
|
807
597
|
|
|
808
|
-
所有UI组件都支持CSS变量定制:
|
|
809
|
-
|
|
810
598
|
```css
|
|
811
599
|
:root {
|
|
812
|
-
/* 按钮样式 */
|
|
813
600
|
--ds-button-bg-color: #f5f5f5;
|
|
814
601
|
--ds-button-hover-color: #e0e0e0;
|
|
815
|
-
--ds-button-text-color: #333;
|
|
816
|
-
|
|
817
|
-
/* 工具提示样式 */
|
|
818
602
|
--ds-tooltip-bg-color: rgba(0, 0, 0, 0.8);
|
|
819
|
-
--ds-tooltip-text-color: white;
|
|
820
|
-
|
|
821
|
-
/* 分段控制器样式 */
|
|
822
|
-
--ds-segmented-bg-color: #f0f0f0;
|
|
823
|
-
--ds-segmented-active-color: #1890ff;
|
|
824
|
-
}
|
|
825
|
-
|
|
826
|
-
/* 暗色主题适配 */
|
|
827
|
-
[data-theme='dark'] {
|
|
828
|
-
--ds-button-bg-color: #333;
|
|
829
|
-
--ds-button-hover-color: #444;
|
|
830
|
-
--ds-button-text-color: #fff;
|
|
831
603
|
}
|
|
832
604
|
```
|
|
833
605
|
|
|
834
606
|
---
|
|
835
607
|
|
|
836
|
-
## 🎛️ 定时器模式详解
|
|
837
|
-
|
|
838
|
-
### `requestAnimationFrame` 模式 🌟 (推荐)
|
|
839
|
-
|
|
840
|
-
```typescript
|
|
841
|
-
// 🎯 特性
|
|
842
|
-
- 时间驱动:基于真实经过时间计算字符数量
|
|
843
|
-
- 批量处理:单帧内可处理多个字符
|
|
844
|
-
- 帧同步:与浏览器 60fps 刷新率同步
|
|
845
|
-
- 高频优化:完美支持 interval < 16ms 的高速打字
|
|
846
|
-
|
|
847
|
-
// 🎯 适用场景
|
|
848
|
-
- 现代 Web 应用的默认选择
|
|
849
|
-
- 追求流畅动画效果
|
|
850
|
-
- 高频打字 (interval > 0 即可)
|
|
851
|
-
- AI 实时对话场景
|
|
852
|
-
```
|
|
853
|
-
|
|
854
|
-
### `setTimeout` 模式 📟 (兼容)
|
|
855
|
-
|
|
856
|
-
```typescript
|
|
857
|
-
// 🎯 特性
|
|
858
|
-
- 单字符:每次精确处理一个字符
|
|
859
|
-
- 固定间隔:严格按设定时间执行
|
|
860
|
-
- 节拍感:经典打字机的节奏感
|
|
861
|
-
- 精确控制:适合特定时序要求
|
|
862
|
-
|
|
863
|
-
// 🎯 适用场景
|
|
864
|
-
- 需要精确时间控制
|
|
865
|
-
- 营造复古打字机效果
|
|
866
|
-
- 兼容性要求较高的场景
|
|
867
|
-
```
|
|
868
|
-
|
|
869
|
-
### 📊 性能对比
|
|
870
|
-
|
|
871
|
-
| 特性 | requestAnimationFrame | setTimeout |
|
|
872
|
-
| ------------ | ---------------------------- | ---------------- |
|
|
873
|
-
| **字符处理** | 每帧可处理多个字符 | 每次处理一个字符 |
|
|
874
|
-
| **高频间隔** | ✅ 优秀 (5ms → 每帧3字符) | ❌ 可能卡顿 |
|
|
875
|
-
| **低频间隔** | ✅ 正常 (100ms → 6帧后1字符) | ✅ 精确 |
|
|
876
|
-
| **视觉效果** | 🎬 流畅动画感 | ⚡ 精确节拍感 |
|
|
877
|
-
| **性能开销** | 🟢 低 (帧同步) | 🟡 中等 (定时器) |
|
|
878
|
-
|
|
879
|
-
高频推荐`requestAnimationFrame`,低频推荐 `setTimeout`
|
|
880
|
-
|
|
881
608
|
## 多语言配置
|
|
882
609
|
|
|
883
|
-
ConfigProvider 是 ds-markdown 提供的多语言配置组件,用于管理应用中的国际化文本。
|
|
884
|
-
|
|
885
|
-
### 基本用法
|
|
886
|
-
|
|
887
610
|
```tsx
|
|
888
|
-
import React from 'react';
|
|
889
611
|
import { ConfigProvider } from 'ds-markdown';
|
|
890
612
|
import zhCN from 'ds-markdown/i18n/zh';
|
|
891
|
-
|
|
892
|
-
const App: React.FC = () => {
|
|
893
|
-
return (
|
|
894
|
-
<ConfigProvider locale={zhCN}>
|
|
895
|
-
<YourApp />
|
|
896
|
-
</ConfigProvider>
|
|
897
|
-
);
|
|
898
|
-
};
|
|
899
|
-
```
|
|
900
|
-
|
|
901
|
-
### 可用的语言包
|
|
902
|
-
|
|
903
|
-
#### 中文 (zhCN)
|
|
904
|
-
|
|
905
|
-
```tsx
|
|
906
|
-
import zhCN from 'ds-markdown/i18n/zh';
|
|
907
|
-
```
|
|
908
|
-
|
|
909
|
-
包含字段:
|
|
910
|
-
|
|
911
|
-
```typescript
|
|
912
|
-
{
|
|
913
|
-
codeBlock: {
|
|
914
|
-
copy: '复制',
|
|
915
|
-
copied: '已复制',
|
|
916
|
-
download: '下载',
|
|
917
|
-
},
|
|
918
|
-
mermaid: {
|
|
919
|
-
diagram: '图表',
|
|
920
|
-
code: '代码',
|
|
921
|
-
zoomOut: '缩小',
|
|
922
|
-
zoomIn: '放大',
|
|
923
|
-
download: '下载',
|
|
924
|
-
}
|
|
925
|
-
}
|
|
926
|
-
```
|
|
927
|
-
|
|
928
|
-
#### 英文 (enUS)
|
|
929
|
-
|
|
930
|
-
```tsx
|
|
931
613
|
import enUS from 'ds-markdown/i18n/en';
|
|
932
|
-
```
|
|
933
|
-
|
|
934
|
-
包含字段:
|
|
935
|
-
|
|
936
|
-
```typescript
|
|
937
|
-
{
|
|
938
|
-
codeBlock: {
|
|
939
|
-
copy: 'Copy',
|
|
940
|
-
copied: 'Copied',
|
|
941
|
-
download: 'Download',
|
|
942
|
-
},
|
|
943
|
-
mermaid: {
|
|
944
|
-
diagram: 'Diagram',
|
|
945
|
-
code: 'Code',
|
|
946
|
-
zoomOut: 'Zoom Out',
|
|
947
|
-
zoomIn: 'Zoom In',
|
|
948
|
-
download: 'Download',
|
|
949
|
-
}
|
|
950
|
-
}
|
|
951
|
-
```
|
|
952
|
-
|
|
953
|
-
### 在组件中使用语言包
|
|
954
|
-
|
|
955
|
-
使用 `locale` 属性来切换自己想要的语言包,例如切换到英文
|
|
956
|
-
|
|
957
|
-
```tsx
|
|
958
|
-
import React from 'react';
|
|
959
|
-
import DsMarkdown from 'ds-markdown';
|
|
960
|
-
import { ConfigProvider } from 'ds-markdown';
|
|
961
|
-
import en from 'ds-markdown/i18n/en';
|
|
962
|
-
|
|
963
|
-
const MyComponent: React.FC = () => {
|
|
964
|
-
return (
|
|
965
|
-
<ConfigProvider locale={en}>
|
|
966
|
-
<DsMarkdown {...props} />
|
|
967
|
-
</ConfigProvider>
|
|
968
|
-
);
|
|
969
|
-
};
|
|
970
|
-
```
|
|
971
614
|
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
615
|
+
// 中文
|
|
616
|
+
<ConfigProvider locale={zhCN}>
|
|
617
|
+
<DsMarkdown {...props} />
|
|
618
|
+
</ConfigProvider>
|
|
975
619
|
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
copied: string;
|
|
981
|
-
download: string;
|
|
982
|
-
};
|
|
983
|
-
mermaid: {
|
|
984
|
-
diagram: string;
|
|
985
|
-
code: string;
|
|
986
|
-
zoomOut: string;
|
|
987
|
-
zoomIn: string;
|
|
988
|
-
download: string;
|
|
989
|
-
};
|
|
990
|
-
[key: string]: any;
|
|
991
|
-
}
|
|
620
|
+
// 英文
|
|
621
|
+
<ConfigProvider locale={enUS}>
|
|
622
|
+
<DsMarkdown {...props} />
|
|
623
|
+
</ConfigProvider>
|
|
992
624
|
```
|
|
993
625
|
|
|
994
|
-
### 注意事项
|
|
995
|
-
|
|
996
|
-
1. `ConfigProvider` 必须包裹在使用 `useLocale` 的组件外层
|
|
997
|
-
2. 语言包对象会被缓存,避免不必要的重新渲染
|
|
998
|
-
3. 支持扩展自定义的语言包字段
|
|
999
|
-
4. 如果没有提供 `ConfigProvider`,会使用默认的中文语言包
|
|
1000
|
-
|
|
1001
626
|
---
|
|
1002
627
|
|
|
1003
628
|
## 💡 实战示例
|
|
1004
629
|
|
|
1005
|
-
### 🎯 高级回调控制
|
|
1006
|
-
|
|
1007
|
-
```tsx
|
|
1008
|
-
import { useRef, useState } from 'react';
|
|
1009
|
-
import { MarkdownCMD, MarkdownCMDRef } from 'ds-markdown';
|
|
1010
|
-
|
|
1011
|
-
function AdvancedCallbackDemo() {
|
|
1012
|
-
const markdownRef = useRef<MarkdownCMDRef>(null);
|
|
1013
|
-
const [typingStats, setTypingStats] = useState({ progress: 0, currentChar: '', totalChars: 0 });
|
|
1014
|
-
|
|
1015
|
-
const handleBeforeTypedChar = async (data) => {
|
|
1016
|
-
// 在字符打字前进行异步操作
|
|
1017
|
-
console.log('即将打字:', data.currentChar);
|
|
1018
|
-
|
|
1019
|
-
// 可以在这里进行网络请求、数据验证等异步操作
|
|
1020
|
-
if (data.currentChar === '!') {
|
|
1021
|
-
await new Promise((resolve) => setTimeout(resolve, 500)); // 模拟延迟
|
|
1022
|
-
}
|
|
1023
|
-
};
|
|
1024
|
-
|
|
1025
|
-
const handleTypedChar = (data) => {
|
|
1026
|
-
// 更新打字统计信息
|
|
1027
|
-
setTypingStats({
|
|
1028
|
-
progress: Math.round(data.percent),
|
|
1029
|
-
currentChar: data.currentChar,
|
|
1030
|
-
totalChars: data.currentIndex + 1,
|
|
1031
|
-
});
|
|
1032
|
-
|
|
1033
|
-
// 可以在这里添加音效、动画等效果
|
|
1034
|
-
if (data.currentChar === '.') {
|
|
1035
|
-
// 播放句号音效
|
|
1036
|
-
console.log('播放句号音效');
|
|
1037
|
-
}
|
|
1038
|
-
};
|
|
1039
|
-
|
|
1040
|
-
const handleStart = (data) => {
|
|
1041
|
-
console.log('开始打字:', data.currentChar);
|
|
1042
|
-
};
|
|
1043
|
-
|
|
1044
|
-
const handleEnd = (data) => {
|
|
1045
|
-
console.log('打字完成:', data.str);
|
|
1046
|
-
};
|
|
1047
|
-
|
|
1048
|
-
const startDemo = () => {
|
|
1049
|
-
markdownRef.current?.clear();
|
|
1050
|
-
markdownRef.current?.push(
|
|
1051
|
-
'# 高级回调演示\n\n' +
|
|
1052
|
-
'这个示例展示了如何使用 `onBeforeTypedChar` 和 `onTypedChar` 回调:\n\n' +
|
|
1053
|
-
'- 🎯 **打字前回调**:可以在字符显示前进行异步操作\n' +
|
|
1054
|
-
'- 📊 **打字后回调**:可以实时更新进度和添加特效\n' +
|
|
1055
|
-
'- ⚡ **性能优化**:支持异步操作,不影响打字流畅度\n\n' +
|
|
1056
|
-
'当前进度:' +
|
|
1057
|
-
typingStats.progress +
|
|
1058
|
-
'%\n' +
|
|
1059
|
-
'已打字数:' +
|
|
1060
|
-
typingStats.totalChars +
|
|
1061
|
-
'\n\n' +
|
|
1062
|
-
'这是一个非常强大的功能!',
|
|
1063
|
-
'answer',
|
|
1064
|
-
);
|
|
1065
|
-
};
|
|
1066
|
-
|
|
1067
|
-
return (
|
|
1068
|
-
<div>
|
|
1069
|
-
<button onClick={startDemo}>🚀 开始高级演示</button>
|
|
1070
|
-
|
|
1071
|
-
<div style={{ margin: '10px 0', padding: '10px', background: '#f5f5f5', borderRadius: '4px' }}>
|
|
1072
|
-
<strong>打字统计:</strong> 进度 {typingStats.progress}% | 当前字符: "{typingStats.currentChar}" | 总字符数: {typingStats.totalChars}
|
|
1073
|
-
</div>
|
|
1074
|
-
|
|
1075
|
-
<MarkdownCMD ref={markdownRef} interval={30} onBeforeTypedChar={handleBeforeTypedChar} onTypedChar={handleTypedChar} onStart={handleStart} onEnd={handleEnd} />
|
|
1076
|
-
</div>
|
|
1077
|
-
);
|
|
1078
|
-
}
|
|
1079
|
-
```
|
|
1080
|
-
|
|
1081
|
-
### 🔄 重新开始动画演示
|
|
1082
|
-
|
|
1083
|
-
```tsx
|
|
1084
|
-
import { useRef, useState } from 'react';
|
|
1085
|
-
import { MarkdownCMD, MarkdownCMDRef } from 'ds-markdown';
|
|
1086
|
-
|
|
1087
|
-
function RestartDemo() {
|
|
1088
|
-
const markdownRef = useRef<MarkdownCMDRef>(null);
|
|
1089
|
-
const [isPlaying, setIsPlaying] = useState(false);
|
|
1090
|
-
const [hasStarted, setHasStarted] = useState(false);
|
|
1091
|
-
|
|
1092
|
-
const startContent = () => {
|
|
1093
|
-
markdownRef.current?.clear();
|
|
1094
|
-
markdownRef.current?.push(
|
|
1095
|
-
'# 重新开始动画演示\n\n' +
|
|
1096
|
-
'这个示例展示了如何使用 `restart()` 方法:\n\n' +
|
|
1097
|
-
'- 🔄 **重新开始**:从头开始播放当前内容\n' +
|
|
1098
|
-
'- ⏸️ **暂停恢复**:可以随时暂停和恢复\n' +
|
|
1099
|
-
'- 🎯 **精确控制**:完全控制动画播放状态\n\n' +
|
|
1100
|
-
'当前状态:' +
|
|
1101
|
-
(isPlaying ? '播放中' : '已暂停') +
|
|
1102
|
-
'\n\n' +
|
|
1103
|
-
'这是一个非常实用的功能!',
|
|
1104
|
-
'answer',
|
|
1105
|
-
);
|
|
1106
|
-
setIsPlaying(true);
|
|
1107
|
-
};
|
|
1108
|
-
|
|
1109
|
-
const handleStart = () => {
|
|
1110
|
-
if (hasStarted) {
|
|
1111
|
-
// 如果已经开始过,则重新开始
|
|
1112
|
-
markdownRef.current?.restart();
|
|
1113
|
-
} else {
|
|
1114
|
-
// 第一次开始
|
|
1115
|
-
markdownRef.current?.start();
|
|
1116
|
-
setHasStarted(true);
|
|
1117
|
-
}
|
|
1118
|
-
setIsPlaying(true);
|
|
1119
|
-
};
|
|
1120
|
-
|
|
1121
|
-
const handleStop = () => {
|
|
1122
|
-
markdownRef.current?.stop();
|
|
1123
|
-
setIsPlaying(false);
|
|
1124
|
-
};
|
|
1125
|
-
|
|
1126
|
-
const handleResume = () => {
|
|
1127
|
-
markdownRef.current?.resume();
|
|
1128
|
-
setIsPlaying(true);
|
|
1129
|
-
};
|
|
1130
|
-
|
|
1131
|
-
const handleRestart = () => {
|
|
1132
|
-
markdownRef.current?.restart();
|
|
1133
|
-
setIsPlaying(true);
|
|
1134
|
-
};
|
|
1135
|
-
|
|
1136
|
-
const handleEnd = () => {
|
|
1137
|
-
setIsPlaying(false);
|
|
1138
|
-
};
|
|
1139
|
-
|
|
1140
|
-
return (
|
|
1141
|
-
<div>
|
|
1142
|
-
<div style={{ marginBottom: '10px', display: 'flex', gap: '10px', flexWrap: 'wrap' }}>
|
|
1143
|
-
<button onClick={startContent}>🚀 开始内容</button>
|
|
1144
|
-
<button onClick={handleStart} disabled={isPlaying}>
|
|
1145
|
-
{hasStarted ? '🔄 重新开始' : '▶️ 开始'}
|
|
1146
|
-
</button>
|
|
1147
|
-
<button onClick={handleStop} disabled={!isPlaying}>
|
|
1148
|
-
⏸️ 暂停
|
|
1149
|
-
</button>
|
|
1150
|
-
<button onClick={handleResume} disabled={isPlaying}>
|
|
1151
|
-
▶️ 恢复
|
|
1152
|
-
</button>
|
|
1153
|
-
<button onClick={handleRestart}>🔄 重新开始</button>
|
|
1154
|
-
</div>
|
|
1155
|
-
|
|
1156
|
-
<div style={{ margin: '10px 0', padding: '10px', background: '#f5f5f5', borderRadius: '4px' }}>
|
|
1157
|
-
<strong>动画状态:</strong> {isPlaying ? '🟢 播放中' : '🔴 已暂停'}
|
|
1158
|
-
</div>
|
|
1159
|
-
|
|
1160
|
-
<MarkdownCMD ref={markdownRef} interval={25} onEnd={handleEnd} />
|
|
1161
|
-
</div>
|
|
1162
|
-
);
|
|
1163
|
-
}
|
|
1164
|
-
```
|
|
1165
|
-
|
|
1166
|
-
### ▶️ 手动开始动画演示
|
|
1167
|
-
|
|
1168
|
-
```tsx
|
|
1169
|
-
import { useRef, useState } from 'react';
|
|
1170
|
-
import { MarkdownCMD, MarkdownCMDRef } from 'ds-markdown';
|
|
1171
|
-
|
|
1172
|
-
function StartDemo() {
|
|
1173
|
-
const markdownRef = useRef<MarkdownCMDRef>(null);
|
|
1174
|
-
const [isPlaying, setIsPlaying] = useState(false);
|
|
1175
|
-
const [hasStarted, setHasStarted] = useState(false);
|
|
1176
|
-
|
|
1177
|
-
const loadContent = () => {
|
|
1178
|
-
markdownRef.current?.clear();
|
|
1179
|
-
markdownRef.current?.push(
|
|
1180
|
-
'# 手动开始动画演示\n\n' +
|
|
1181
|
-
'这个示例展示了如何使用 `start()` 方法:\n\n' +
|
|
1182
|
-
'- 🎯 **手动控制**:当 `autoStartTyping=false` 时,需要手动调用 `start()`\n' +
|
|
1183
|
-
'- ⏱️ **延迟开始**:可以在用户交互后开始动画\n' +
|
|
1184
|
-
'- 🎮 **游戏化**:适合需要用户主动触发的场景\n\n' +
|
|
1185
|
-
'点击"开始动画"按钮来手动启动打字效果!',
|
|
1186
|
-
'answer',
|
|
1187
|
-
);
|
|
1188
|
-
setIsPlaying(false);
|
|
1189
|
-
};
|
|
1190
|
-
|
|
1191
|
-
const handleStart = () => {
|
|
1192
|
-
if (hasStarted) {
|
|
1193
|
-
// 如果已经开始过,则重新开始
|
|
1194
|
-
markdownRef.current?.restart();
|
|
1195
|
-
} else {
|
|
1196
|
-
// 第一次开始
|
|
1197
|
-
markdownRef.current?.start();
|
|
1198
|
-
setHasStarted(true);
|
|
1199
|
-
}
|
|
1200
|
-
setIsPlaying(true);
|
|
1201
|
-
};
|
|
1202
|
-
|
|
1203
|
-
const handleEnd = () => {
|
|
1204
|
-
setIsPlaying(false);
|
|
1205
|
-
};
|
|
1206
|
-
|
|
1207
|
-
return (
|
|
1208
|
-
<div>
|
|
1209
|
-
<div style={{ marginBottom: '10px', display: 'flex', gap: '10px', flexWrap: 'wrap' }}>
|
|
1210
|
-
<button onClick={loadContent}>📝 加载内容</button>
|
|
1211
|
-
<button onClick={handleStart} disabled={isPlaying}>
|
|
1212
|
-
{hasStarted ? '🔄 重新开始' : '▶️ 开始动画'}
|
|
1213
|
-
</button>
|
|
1214
|
-
</div>
|
|
1215
|
-
|
|
1216
|
-
<div style={{ margin: '10px 0', padding: '10px', background: '#f5f5f5', borderRadius: '4px' }}>
|
|
1217
|
-
<strong>状态:</strong> {isPlaying ? '🟢 动画播放中' : '🔴 等待开始'}
|
|
1218
|
-
</div>
|
|
1219
|
-
|
|
1220
|
-
<MarkdownCMD ref={markdownRef} interval={30} autoStartTyping={false} onEnd={handleEnd} />
|
|
1221
|
-
</div>
|
|
1222
|
-
);
|
|
1223
|
-
}
|
|
1224
|
-
```
|
|
1225
|
-
|
|
1226
630
|
### 📝 AI 流式对话
|
|
1227
631
|
|
|
1228
632
|
[DEMO: 🔧 StackBlitz 体验](https://stackblitz.com/edit/vitejs-vite-2ri8kex3?file=src%2FApp.tsx)
|
|
1229
633
|
|
|
1230
|
-
|
|
634
|
+
```tsx
|
|
1231
635
|
import { useRef } from 'react';
|
|
1232
636
|
import { MarkdownCMD, MarkdownCMDRef } from 'ds-markdown';
|
|
1233
637
|
|
|
@@ -1251,19 +655,6 @@ function StreamingChat() {
|
|
|
1251
655
|
'- 🎯 **自动优化**:无需手动 memo 和 useMemo\n',
|
|
1252
656
|
'- ⚡ **性能提升**:编译时优化,运行时零开销\n',
|
|
1253
657
|
'- 🔧 **向后兼容**:现有代码无需修改\n\n',
|
|
1254
|
-
'## 📝 Actions 简化表单\n',
|
|
1255
|
-
'新的 Actions API 让表单处理变得更简单:\n\n',
|
|
1256
|
-
'```tsx\n',
|
|
1257
|
-
'function ContactForm({ action }) {\n',
|
|
1258
|
-
' const [state, formAction] = useActionState(action, null);\n',
|
|
1259
|
-
' return (\n',
|
|
1260
|
-
' <form action={formAction}>\n',
|
|
1261
|
-
' <input name="email" type="email" />\n',
|
|
1262
|
-
' <button>提交</button>\n',
|
|
1263
|
-
' </form>\n',
|
|
1264
|
-
' );\n',
|
|
1265
|
-
'}\n',
|
|
1266
|
-
'```\n\n',
|
|
1267
658
|
'希望这个解答对您有帮助!🎉',
|
|
1268
659
|
];
|
|
1269
660
|
|
|
@@ -1273,133 +664,17 @@ function StreamingChat() {
|
|
|
1273
664
|
}
|
|
1274
665
|
};
|
|
1275
666
|
|
|
667
|
+
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
668
|
+
|
|
1276
669
|
return (
|
|
1277
670
|
<div className="chat-container">
|
|
1278
671
|
<button onClick={simulateAIResponse}>🤖 询问 React 19 新特性</button>
|
|
1279
|
-
|
|
1280
|
-
<MarkdownCMD ref={markdownRef} interval={10} timerType="requestAnimationFrame" onEnd={(data) => console.log('段落完成:', data)} />
|
|
1281
|
-
</div>
|
|
1282
|
-
);
|
|
1283
|
-
}
|
|
1284
|
-
|
|
1285
|
-
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
1286
|
-
````
|
|
1287
|
-
|
|
1288
|
-
### 🧮 数学公式流式渲染
|
|
1289
|
-
|
|
1290
|
-
```tsx
|
|
1291
|
-
import { katexPlugin } from 'ds-markdown/plugins';
|
|
1292
|
-
|
|
1293
|
-
function MathStreamingDemo() {
|
|
1294
|
-
const markdownRef = useRef<MarkdownCMDRef>(null);
|
|
1295
|
-
|
|
1296
|
-
const simulateMathResponse = async () => {
|
|
1297
|
-
markdownRef.current?.clear();
|
|
1298
|
-
|
|
1299
|
-
const mathChunks = [
|
|
1300
|
-
'# 勾股定理详解\n\n',
|
|
1301
|
-
'在直角三角形中,斜边的平方等于两条直角边的平方和:\n\n',
|
|
1302
|
-
'$a^2 + b^2 = c^2$\n\n',
|
|
1303
|
-
'其中:\n',
|
|
1304
|
-
'- $a$ 和 $b$ 是直角边\n',
|
|
1305
|
-
'- $c$ 是斜边\n\n',
|
|
1306
|
-
'对于经典的"勾三股四弦五":\n',
|
|
1307
|
-
'$c = \\sqrt{3^2 + 4^2} = \\sqrt{25} = 5$\n\n',
|
|
1308
|
-
'这个定理在几何学中有着广泛的应用!',
|
|
1309
|
-
];
|
|
1310
|
-
|
|
1311
|
-
for (const chunk of mathChunks) {
|
|
1312
|
-
await delay(150);
|
|
1313
|
-
markdownRef.current?.push(chunk, 'answer');
|
|
1314
|
-
}
|
|
1315
|
-
};
|
|
1316
|
-
|
|
1317
|
-
return (
|
|
1318
|
-
<div>
|
|
1319
|
-
<button onClick={simulateMathResponse}>📐 讲解勾股定理</button>
|
|
1320
|
-
|
|
1321
|
-
<MarkdownCMD ref={markdownRef} interval={20} timerType="requestAnimationFrame" plugins={[katexPlugin]} math={{ splitSymbol: 'dollar' }} />
|
|
672
|
+
<MarkdownCMD ref={markdownRef} interval={10} timerType="requestAnimationFrame" />
|
|
1322
673
|
</div>
|
|
1323
674
|
);
|
|
1324
675
|
}
|
|
1325
676
|
```
|
|
1326
677
|
|
|
1327
|
-
### 📊 Mermaid图表流式渲染 🆕
|
|
1328
|
-
|
|
1329
|
-
````tsx
|
|
1330
|
-
import { useRef } from 'react';
|
|
1331
|
-
import { MarkdownCMD, MarkdownCMDRef, ConfigProvider } from 'ds-markdown';
|
|
1332
|
-
import mermaidPlugin from 'ds-markdown-mermaid-plugin';
|
|
1333
|
-
|
|
1334
|
-
function MermaidStreamingDemo() {
|
|
1335
|
-
const markdownRef = useRef<MarkdownCMDRef>(null);
|
|
1336
|
-
|
|
1337
|
-
const simulateMermaidResponse = async () => {
|
|
1338
|
-
markdownRef.current?.clear();
|
|
1339
|
-
|
|
1340
|
-
const mermaidChunks = [
|
|
1341
|
-
'# 系统架构图\n\n',
|
|
1342
|
-
'```mermaid\n',
|
|
1343
|
-
'flowchart TD\n',
|
|
1344
|
-
' A[用户请求] --> B[负载均衡器]\n',
|
|
1345
|
-
' B --> C[Web服务器]\n',
|
|
1346
|
-
' B --> D[Web服务器]\n',
|
|
1347
|
-
' C --> E[应用服务器]\n',
|
|
1348
|
-
' D --> F[应用服务器]\n',
|
|
1349
|
-
' E --> G[数据库]\n',
|
|
1350
|
-
' F --> G\n',
|
|
1351
|
-
'```\n\n',
|
|
1352
|
-
'## 用户流程图\n\n',
|
|
1353
|
-
'```mermaid\n',
|
|
1354
|
-
'sequenceDiagram\n',
|
|
1355
|
-
' participant U as 用户\n',
|
|
1356
|
-
' participant W as Web服务\n',
|
|
1357
|
-
' participant A as API服务\n',
|
|
1358
|
-
' participant D as 数据库\n',
|
|
1359
|
-
'\n',
|
|
1360
|
-
' U->>W: 访问页面\n',
|
|
1361
|
-
' W->>A: 请求数据\n',
|
|
1362
|
-
' A->>D: 查询数据\n',
|
|
1363
|
-
' D-->>A: 返回结果\n',
|
|
1364
|
-
' A-->>W: 响应数据\n',
|
|
1365
|
-
' W-->>U: 渲染页面\n',
|
|
1366
|
-
'```\n\n',
|
|
1367
|
-
'## 项目计划\n\n',
|
|
1368
|
-
'```mermaid\n',
|
|
1369
|
-
'gantt\n',
|
|
1370
|
-
' title 项目开发计划\n',
|
|
1371
|
-
' dateFormat YYYY-MM-DD\n',
|
|
1372
|
-
' section 设计阶段\n',
|
|
1373
|
-
' 需求分析 :done, des1, 2024-01-01, 2024-01-10\n',
|
|
1374
|
-
' 系统设计 :active, des2, 2024-01-11, 2024-01-25\n',
|
|
1375
|
-
' section 开发阶段\n',
|
|
1376
|
-
' 前端开发 :des3, 2024-01-26, 2024-02-15\n',
|
|
1377
|
-
' 后端开发 :des4, 2024-01-26, 2024-02-20\n',
|
|
1378
|
-
' 测试调试 :des5, 2024-02-21, 2024-02-28\n',
|
|
1379
|
-
'```\n\n',
|
|
1380
|
-
'支持多种图表类型的流式渲染,让技术文档更加生动!',
|
|
1381
|
-
];
|
|
1382
|
-
|
|
1383
|
-
for (const chunk of mermaidChunks) {
|
|
1384
|
-
await delay(100);
|
|
1385
|
-
markdownRef.current?.push(chunk, 'answer');
|
|
1386
|
-
}
|
|
1387
|
-
};
|
|
1388
|
-
|
|
1389
|
-
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
1390
|
-
|
|
1391
|
-
return (
|
|
1392
|
-
<div>
|
|
1393
|
-
<button onClick={simulateMermaidResponse}>🎨 展示 Mermaid 图表</button>
|
|
1394
|
-
|
|
1395
|
-
<ConfigProvider>
|
|
1396
|
-
<MarkdownCMD ref={markdownRef} interval={15} timerType="requestAnimationFrame" plugins={[mermaidPlugin]} />
|
|
1397
|
-
</ConfigProvider>
|
|
1398
|
-
</div>
|
|
1399
|
-
);
|
|
1400
|
-
}
|
|
1401
|
-
````
|
|
1402
|
-
|
|
1403
678
|
## 🔧 最佳实践
|
|
1404
679
|
|
|
1405
680
|
### 1. 性能优化
|
|
@@ -1410,9 +685,6 @@ function MermaidStreamingDemo() {
|
|
|
1410
685
|
timerType="requestAnimationFrame"
|
|
1411
686
|
interval={15} // 15-30ms 为最佳体验
|
|
1412
687
|
/>
|
|
1413
|
-
|
|
1414
|
-
// ❌ 避免过小间隔
|
|
1415
|
-
<DsMarkdown interval={1} /> // 可能导致性能问题
|
|
1416
688
|
```
|
|
1417
689
|
|
|
1418
690
|
### 2. 流式数据处理
|
|
@@ -1423,126 +695,31 @@ const ref = useRef<MarkdownCMDRef>(null);
|
|
|
1423
695
|
useEffect(() => {
|
|
1424
696
|
ref.current?.push(newChunk, 'answer');
|
|
1425
697
|
}, [newChunk]);
|
|
1426
|
-
|
|
1427
|
-
// ❌ 避免:频繁更新 children
|
|
1428
|
-
const [content, setContent] = useState('');
|
|
1429
|
-
// 每次更新都会重新解析整个内容
|
|
1430
698
|
```
|
|
1431
699
|
|
|
1432
700
|
### 3. 数学公式优化
|
|
1433
701
|
|
|
1434
702
|
```tsx
|
|
1435
|
-
// ✅
|
|
1436
|
-
import 'ds-markdown/
|
|
703
|
+
// ✅ 推荐:按需加载
|
|
704
|
+
import { katexPlugin } from 'ds-markdown/plugins';
|
|
1437
705
|
import 'ds-markdown/katex.css'; // 仅在需要时引入
|
|
1438
706
|
|
|
1439
|
-
// ✅ 推荐:合理使用分隔符
|
|
1440
|
-
// 对于简单公式,使用 $...$ 更简洁
|
|
1441
|
-
// 对于复杂公式,使用 $$...$$ 更清晰
|
|
1442
|
-
|
|
1443
|
-
// ✅ 推荐:插件化配置
|
|
1444
|
-
import { katexPlugin } from 'ds-markdown/plugins';
|
|
1445
707
|
<DsMarkdown plugins={[katexPlugin]}>数学公式内容</DsMarkdown>;
|
|
1446
708
|
```
|
|
1447
709
|
|
|
1448
|
-
### 4.
|
|
1449
|
-
|
|
1450
|
-
```tsx
|
|
1451
|
-
// ✅ 推荐:按需导入UI组件
|
|
1452
|
-
import { Button, ToolTip, CopyButton } from 'ds-markdown';
|
|
1453
|
-
|
|
1454
|
-
// ✅ 推荐:组合使用UI组件
|
|
1455
|
-
<ToolTip title="复制代码">
|
|
1456
|
-
<CopyButton codeContent={code} />
|
|
1457
|
-
</ToolTip>
|
|
1458
|
-
|
|
1459
|
-
// ✅ 推荐:利用CSS变量定制主题
|
|
1460
|
-
:root {
|
|
1461
|
-
--ds-button-bg-color: your-brand-color;
|
|
1462
|
-
}
|
|
1463
|
-
```
|
|
1464
|
-
|
|
1465
|
-
### 5. 代码块最佳实践 🆕
|
|
1466
|
-
|
|
1467
|
-
```tsx
|
|
1468
|
-
// ✅ 推荐:启用代码块操作
|
|
1469
|
-
<DsMarkdown
|
|
1470
|
-
codeBlock={{ headerActions: true }}
|
|
1471
|
-
// 其他配置...
|
|
1472
|
-
>
|
|
1473
|
-
{markdownContent}
|
|
1474
|
-
</DsMarkdown>;
|
|
1475
|
-
|
|
1476
|
-
// ✅ 推荐:自定义代码块组件
|
|
1477
|
-
import { CodeBlockWrap, HighlightCode } from 'ds-markdown';
|
|
1478
|
-
|
|
1479
|
-
const CustomCodeBlock = ({ code, language }) => (
|
|
1480
|
-
<CodeBlockWrap language={language}>
|
|
1481
|
-
<HighlightCode code={code} language={language} />
|
|
1482
|
-
{/* 添加自定义操作 */}
|
|
1483
|
-
</CodeBlockWrap>
|
|
1484
|
-
);
|
|
1485
|
-
```
|
|
1486
|
-
|
|
1487
|
-
### 6. 类型安全
|
|
1488
|
-
|
|
1489
|
-
```tsx
|
|
1490
|
-
import { MarkdownCMDRef, useThemeState } from 'ds-markdown';
|
|
1491
|
-
|
|
1492
|
-
const ref = useRef<MarkdownCMDRef>(null);
|
|
1493
|
-
const themeState = useThemeState(); // 🆕 获取主题状态
|
|
1494
|
-
// 完整的 TypeScript 类型提示
|
|
1495
|
-
```
|
|
1496
|
-
|
|
1497
|
-
### 7. 国际化最佳实践 🆕
|
|
710
|
+
### 4. Mermaid图表最佳实践 🆕
|
|
1498
711
|
|
|
1499
712
|
```tsx
|
|
1500
|
-
// ✅
|
|
1501
|
-
import { ConfigProvider } from 'ds-markdown';
|
|
1502
|
-
import zhCN from 'ds-markdown/i18n/zh';
|
|
1503
|
-
import enUS from 'ds-markdown/i18n/en';
|
|
1504
|
-
|
|
1505
|
-
const App = () => {
|
|
1506
|
-
const locale = userLanguage === 'zh' ? zhCN : enUS;
|
|
1507
|
-
|
|
1508
|
-
return (
|
|
1509
|
-
<ConfigProvider locale={locale}>
|
|
1510
|
-
<DsMarkdown {...props} />
|
|
1511
|
-
</ConfigProvider>
|
|
1512
|
-
);
|
|
1513
|
-
};
|
|
1514
|
-
```
|
|
1515
|
-
|
|
1516
|
-
### 8. Mermaid图表最佳实践 🆕
|
|
1517
|
-
|
|
1518
|
-
````tsx
|
|
1519
|
-
// ✅ 推荐:独立安装Mermaid插件
|
|
713
|
+
// ✅ 推荐:独立安装插件
|
|
1520
714
|
npm install ds-markdown-mermaid-plugin
|
|
1521
715
|
|
|
1522
716
|
// ✅ 推荐:配置适合的主题
|
|
1523
717
|
const mermaidConfig = {
|
|
1524
718
|
theme: 'default', // 根据应用主题选择
|
|
1525
|
-
|
|
1526
|
-
flowchart: {
|
|
1527
|
-
useMaxWidth: true, // 响应式设计
|
|
1528
|
-
},
|
|
719
|
+
flowchart: { useMaxWidth: true },
|
|
1529
720
|
};
|
|
1530
721
|
|
|
1531
|
-
|
|
1532
|
-
<ConfigProvider mermaidConfig={mermaidConfig} locale={locale}>
|
|
722
|
+
<ConfigProvider mermaidConfig={mermaidConfig}>
|
|
1533
723
|
<DsMarkdown plugins={[mermaidPlugin]} />
|
|
1534
724
|
</ConfigProvider>
|
|
1535
|
-
|
|
1536
|
-
// ✅ 推荐:复杂图表分块渲染
|
|
1537
|
-
const complexChart = [
|
|
1538
|
-
'```mermaid\n',
|
|
1539
|
-
'flowchart TD\n',
|
|
1540
|
-
' A[开始] --> B[处理]\n',
|
|
1541
|
-
' B --> C[结束]\n',
|
|
1542
|
-
'```\n',
|
|
1543
|
-
];
|
|
1544
|
-
|
|
1545
|
-
// ✅ 推荐:使用语义化的节点命名
|
|
1546
|
-
// 好的例子:A[用户登录] --> B[验证凭据]
|
|
1547
|
-
// 避免:n1 --> n2
|
|
1548
|
-
````
|
|
725
|
+
```
|