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 CHANGED
@@ -12,9 +12,13 @@
12
12
  [![React](https://img.shields.io/badge/React-18.0.0+-blue)](https://react.dev)
13
13
  [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue)](https://www.typescriptlang.org/)
14
14
 
15
- [📖 在线演示](https://onshinpei.github.io/ds-markdown/)
15
+ [使用文档](https://onshinpei.github.io/ds-markdown/)
16
16
 
17
- [DEMO:🔧 StackBlitz 体验](https://stackblitz.com/edit/vitejs-vite-ddfw8avb?file=src%2FApp.tsx)
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 提供了一套完整的UI组件系统,可以单独使用或与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 { IconButton } from 'ds-markdown';
562
+ import {
563
+ Button,
564
+ IconButton,
565
+ ToolTip,
566
+ Segmented,
567
+ CopyButton,
568
+ DownloadButton
569
+ } from 'ds-markdown';
671
570
 
672
- function IconButtonDemo() {
673
- return <IconButton icon={<span>📋</span>} onClick={() => console.log('copy')} className="my-icon-button" />;
674
- }
675
- ```
571
+ // 按钮组件
572
+ <Button icon={<span>📄</span>} onClick={() => {}}>
573
+ 点击按钮
574
+ </Button>
676
575
 
677
- ### ToolTip 组件
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
- const options = [
581
+ // 分段控制器
582
+ <Segmented
583
+ Segmented={[
705
584
  { label: '图表', value: 'diagram' },
706
- { label: '代码', value: 'code' },
707
- ];
708
-
709
- return <Segmented Segmented={options} value={value} onChange={setValue} />;
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
- return (
724
- <div className="code-block">
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
- ```typescript
977
- interface Locale {
978
- codeBlock: {
979
- copy: string;
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
- ````tsx
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/style.css';
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. UI组件使用 🆕
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
- startOnLoad: false, // 提升性能
1526
- flowchart: {
1527
- useMaxWidth: true, // 响应式设计
1528
- },
719
+ flowchart: { useMaxWidth: true },
1529
720
  };
1530
721
 
1531
- // ✅ 推荐:在ConfigProvider中统一配置
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
+ ```