ds-markdown 0.1.9 → 0.1.10-beta.0

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
@@ -67,18 +67,9 @@
67
67
  - [代码块功能](#代码块功能) 🆕
68
68
  - [Mermaid图表支持](#mermaid图表支持) 🆕
69
69
  - [📚 完整 API 文档](#-完整-api-文档)
70
- - [🧮 数学公式使用指南](#-数学公式使用指南)
71
70
  - [🔌 插件系统](#-插件系统)
72
71
  - [🎨 UI组件系统](#-ui组件系统) 🆕
73
- - [🎛️ 定时器模式详解](#️-定时器模式详解)
74
72
  - [💡 实战示例](#-实战示例)
75
- - [🎯 高级回调控制](#-高级回调控制)
76
- - [🔄 重新开始动画演示](#-重新开始动画演示)
77
- - [▶️ 手动开始动画演示](#️-手动开始动画演示)
78
- - [📝 AI 流式对话](#-ai-流式对话)
79
- - [🧮 数学公式流式渲染](#-数学公式流式渲染)
80
- - [📊 Mermaid图表流式渲染](#-mermaid图表流式渲染) 🆕
81
- - [多语言配置](#多语言配置)
82
73
  - [🔧 最佳实践](#-最佳实践)
83
74
 
84
75
  ---
@@ -444,93 +435,6 @@ markdownRef.current?.restart(); // 重新开始动画
444
435
 
445
436
  ---
446
437
 
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
438
  ## 🔌 插件系统
535
439
 
536
440
  ### 内置插件
@@ -644,590 +548,84 @@ const customPlugin = createBuildInPlugin({
644
548
 
645
549
  ## 🎨 UI组件系统 🆕
646
550
 
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 组件
551
+ ds-markdown 提供了丰富的UI组件,可以单独使用或与markdown组件配合。
666
552
 
667
- 图标按钮组件,适用于工具栏和操作区域。
553
+ ### 核心组件
668
554
 
669
555
  ```tsx
670
- import { IconButton } from 'ds-markdown';
671
-
672
- function IconButtonDemo() {
673
- return <IconButton icon={<span>📋</span>} onClick={() => console.log('copy')} className="my-icon-button" />;
674
- }
675
- ```
556
+ import {
557
+ Button,
558
+ IconButton,
559
+ ToolTip,
560
+ Segmented,
561
+ CopyButton,
562
+ DownloadButton
563
+ } from 'ds-markdown';
676
564
 
677
- ### ToolTip 组件
565
+ // 按钮组件
566
+ <Button icon={<span>📄</span>} onClick={() => {}}>
567
+ 点击按钮
568
+ </Button>
678
569
 
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');
570
+ // 工具提示
571
+ <ToolTip title="提示信息">
572
+ <IconButton icon={<span>📋</span>} onClick={() => {}} />
573
+ </ToolTip>
703
574
 
704
- const options = [
575
+ // 分段控制器
576
+ <Segmented
577
+ Segmented={[
705
578
  { 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");';
579
+ { label: '代码', value: 'code' }
580
+ ]}
581
+ value={value}
582
+ onChange={setValue}
583
+ />
722
584
 
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
- }
585
+ // 代码块操作
586
+ <CopyButton codeContent="console.log('Hello')" />
587
+ <DownloadButton codeContent="console.log('Hello')" language="javascript" />
739
588
  ```
740
589
 
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
590
  ### 样式定制
807
591
 
808
- 所有UI组件都支持CSS变量定制:
809
-
810
592
  ```css
811
593
  :root {
812
- /* 按钮样式 */
813
594
  --ds-button-bg-color: #f5f5f5;
814
595
  --ds-button-hover-color: #e0e0e0;
815
- --ds-button-text-color: #333;
816
-
817
- /* 工具提示样式 */
818
596
  --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
597
  }
832
598
  ```
833
599
 
834
600
  ---
835
601
 
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
602
  ## 多语言配置
882
603
 
883
- ConfigProvider 是 ds-markdown 提供的多语言配置组件,用于管理应用中的国际化文本。
884
-
885
- ### 基本用法
886
-
887
604
  ```tsx
888
- import React from 'react';
889
605
  import { ConfigProvider } from 'ds-markdown';
890
606
  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
607
  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
-
972
- ### 语言包结构
973
608
 
974
- 当前支持的语言包包含以下字段:
609
+ // 中文
610
+ <ConfigProvider locale={zhCN}>
611
+ <DsMarkdown {...props} />
612
+ </ConfigProvider>
975
613
 
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
- }
614
+ // 英文
615
+ <ConfigProvider locale={enUS}>
616
+ <DsMarkdown {...props} />
617
+ </ConfigProvider>
992
618
  ```
993
619
 
994
- ### 注意事项
995
-
996
- 1. `ConfigProvider` 必须包裹在使用 `useLocale` 的组件外层
997
- 2. 语言包对象会被缓存,避免不必要的重新渲染
998
- 3. 支持扩展自定义的语言包字段
999
- 4. 如果没有提供 `ConfigProvider`,会使用默认的中文语言包
1000
-
1001
620
  ---
1002
621
 
1003
622
  ## 💡 实战示例
1004
623
 
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
624
  ### 📝 AI 流式对话
1227
625
 
1228
626
  [DEMO: 🔧 StackBlitz 体验](https://stackblitz.com/edit/vitejs-vite-2ri8kex3?file=src%2FApp.tsx)
1229
627
 
1230
- ````tsx
628
+ ```tsx
1231
629
  import { useRef } from 'react';
1232
630
  import { MarkdownCMD, MarkdownCMDRef } from 'ds-markdown';
1233
631
 
@@ -1251,19 +649,6 @@ function StreamingChat() {
1251
649
  '- 🎯 **自动优化**:无需手动 memo 和 useMemo\n',
1252
650
  '- ⚡ **性能提升**:编译时优化,运行时零开销\n',
1253
651
  '- 🔧 **向后兼容**:现有代码无需修改\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
652
  '希望这个解答对您有帮助!🎉',
1268
653
  ];
1269
654
 
@@ -1273,133 +658,17 @@ function StreamingChat() {
1273
658
  }
1274
659
  };
1275
660
 
661
+ const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
662
+
1276
663
  return (
1277
664
  <div className="chat-container">
1278
665
  <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' }} />
666
+ <MarkdownCMD ref={markdownRef} interval={10} timerType="requestAnimationFrame" />
1322
667
  </div>
1323
668
  );
1324
669
  }
1325
670
  ```
1326
671
 
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
672
  ## 🔧 最佳实践
1404
673
 
1405
674
  ### 1. 性能优化
@@ -1410,9 +679,6 @@ function MermaidStreamingDemo() {
1410
679
  timerType="requestAnimationFrame"
1411
680
  interval={15} // 15-30ms 为最佳体验
1412
681
  />
1413
-
1414
- // ❌ 避免过小间隔
1415
- <DsMarkdown interval={1} /> // 可能导致性能问题
1416
682
  ```
1417
683
 
1418
684
  ### 2. 流式数据处理
@@ -1423,126 +689,31 @@ const ref = useRef<MarkdownCMDRef>(null);
1423
689
  useEffect(() => {
1424
690
  ref.current?.push(newChunk, 'answer');
1425
691
  }, [newChunk]);
1426
-
1427
- // ❌ 避免:频繁更新 children
1428
- const [content, setContent] = useState('');
1429
- // 每次更新都会重新解析整个内容
1430
692
  ```
1431
693
 
1432
694
  ### 3. 数学公式优化
1433
695
 
1434
696
  ```tsx
1435
- // ✅ 推荐:按需加载数学公式样式
1436
- import 'ds-markdown/style.css';
697
+ // ✅ 推荐:按需加载
698
+ import { katexPlugin } from 'ds-markdown/plugins';
1437
699
  import 'ds-markdown/katex.css'; // 仅在需要时引入
1438
700
 
1439
- // ✅ 推荐:合理使用分隔符
1440
- // 对于简单公式,使用 $...$ 更简洁
1441
- // 对于复杂公式,使用 $$...$$ 更清晰
1442
-
1443
- // ✅ 推荐:插件化配置
1444
- import { katexPlugin } from 'ds-markdown/plugins';
1445
701
  <DsMarkdown plugins={[katexPlugin]}>数学公式内容</DsMarkdown>;
1446
702
  ```
1447
703
 
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. 国际化最佳实践 🆕
704
+ ### 4. Mermaid图表最佳实践 🆕
1498
705
 
1499
706
  ```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插件
707
+ // ✅ 推荐:独立安装插件
1520
708
  npm install ds-markdown-mermaid-plugin
1521
709
 
1522
710
  // ✅ 推荐:配置适合的主题
1523
711
  const mermaidConfig = {
1524
712
  theme: 'default', // 根据应用主题选择
1525
- startOnLoad: false, // 提升性能
1526
- flowchart: {
1527
- useMaxWidth: true, // 响应式设计
1528
- },
713
+ flowchart: { useMaxWidth: true },
1529
714
  };
1530
715
 
1531
- // ✅ 推荐:在ConfigProvider中统一配置
1532
- <ConfigProvider mermaidConfig={mermaidConfig} locale={locale}>
716
+ <ConfigProvider mermaidConfig={mermaidConfig}>
1533
717
  <DsMarkdown plugins={[mermaidPlugin]} />
1534
718
  </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
- ````
719
+ ```