ds-markdown 0.1.10-beta.0 → 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/dist/cjs/index.js CHANGED
@@ -3,12 +3,11 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var jsxRuntime = require('react/jsx-runtime');
6
- var React = require('react');
6
+ var react = require('react');
7
7
  var Markdown$2 = require('react-markdown');
8
8
  var gfmPlugin = require('remark-gfm');
9
9
  var classNames = require('classnames');
10
10
  var reactSyntaxHighlighter = require('react-syntax-highlighter');
11
- var reactDom = require('react-dom');
12
11
 
13
12
  /**
14
13
  * 将括号格式的数学公式转换为美元符号格式
@@ -24,44 +23,32 @@ var reactDom = require('react-dom');
24
23
  * @returns 转换后的字符串
25
24
  */
26
25
  const replaceMathBracket = (value) => {
27
- // 1. 提取并保护所有 Markdown 链接(包括图片和普通链接)
28
- // 匹配 ![alt](url) 或 [text](url) 形式
29
- const mdLinkMatches = [];
30
- const protectedValue = value.replace(/!?\[[^\]]*\]\([^)]*\)/g, (m) => {
31
- mdLinkMatches.push(m);
32
- return `__MD_LINK_${mdLinkMatches.length - 1}__`;
33
- });
34
- // 2. 提取所有块级公式内容,临时替换为占位符
35
- // 处理 \[...\] 格式的块级公式
26
+ // 1. 提取所有块级公式内容,临时替换为占位符, [...]
36
27
  const blockMatches = [];
37
- let replaced = protectedValue.replace(/\\*\[([\s\S]+?)\\*\]/g, (_m, p1) => {
28
+ let replaced = value.replace(/\\+\[([\s\S]+?)\\+\]/g, (_m, p1) => {
38
29
  blockMatches.push(p1);
39
30
  return `__BLOCK_MATH_${blockMatches.length - 1}__`;
40
31
  });
41
- // 处理 $$...$$ 格式的块级公式(兼容性处理)
32
+ // 也需要兼容 $$ xxxx $$ 这种写法
42
33
  replaced = replaced.replace(/\$\$([\s\S]+?)\$\$/g, (_m, p1) => {
43
34
  blockMatches.push(p1);
44
35
  return `__BLOCK_MATH_${blockMatches.length - 1}__`;
45
36
  });
46
- // 3. 替换块级公式外部的 \(...\) 为 $...$(行内公式)
47
- replaced = replaced.replace(/\\*\(([^)]+?)\\*\)/g, (_m, p1) => {
37
+ // 2. 替换块级公式外部的 ( ... ) 为 $...$
38
+ replaced = replaced.replace(/\\+\(([^)]+?)\\+\)/g, (_m, p1) => {
48
39
  return '$' + p1 + '$';
49
40
  });
50
- // 4. 还原块级公式内容,保持其内部小括号原样
41
+ // 3. 还原块级公式内容,保持其内部小括号原样
51
42
  replaced = replaced.replace(/__BLOCK_MATH_(\d+)__/g, (_m, idx) => {
52
43
  return '$$' + blockMatches[Number(idx)] + '$$';
53
44
  });
54
- // 5. 还原被保护的 Markdown 链接
55
- replaced = replaced.replace(/__MD_LINK_(\d+)__/g, (_m, idx) => {
56
- return mdLinkMatches[Number(idx)];
57
- });
58
45
  return replaced;
59
46
  };
60
47
 
61
48
  const DEFAULT_THEME = 'light';
62
49
  const DEFAULT_ANSWER_TYPE = 'answer';
63
50
  const DEFAULT_PLUGINS = [];
64
- const MarkdownThemeContext = React.createContext({
51
+ const MarkdownThemeContext = react.createContext({
65
52
  state: {
66
53
  theme: DEFAULT_THEME,
67
54
  answerType: DEFAULT_ANSWER_TYPE,
@@ -69,7 +56,7 @@ const MarkdownThemeContext = React.createContext({
69
56
  methods: {},
70
57
  });
71
58
  const MarkdownThemeProvider = ({ value = {}, children }) => {
72
- const contextValue = React.useMemo(() => ({
59
+ const contextValue = react.useMemo(() => ({
73
60
  state: {
74
61
  theme: DEFAULT_THEME,
75
62
  answerType: DEFAULT_ANSWER_TYPE,
@@ -81,9 +68,9 @@ const MarkdownThemeProvider = ({ value = {}, children }) => {
81
68
  }), [value]);
82
69
  return jsxRuntime.jsx(MarkdownThemeContext.Provider, { value: contextValue, children: children });
83
70
  };
84
- const useMarkdownThemeContext = () => React.useContext(MarkdownThemeContext);
71
+ const useMarkdownThemeContext = () => react.useContext(MarkdownThemeContext);
85
72
  const useThemeState = () => {
86
- return React.useContext(MarkdownThemeContext).state;
73
+ return react.useContext(MarkdownThemeContext).state;
87
74
  };
88
75
 
89
76
  const CodeBlockWrap = ({ children, title }) => {
@@ -91,13 +78,6 @@ const CodeBlockWrap = ({ children, title }) => {
91
78
  return (jsxRuntime.jsxs("div", { className: `md-code-block md-code-block-${theme}`, children: [jsxRuntime.jsx("div", { className: "md-code-block-banner-wrap", children: jsxRuntime.jsx("div", { className: "md-code-block-banner md-code-block-banner-lite", children: title }) }), jsxRuntime.jsx("div", { className: "md-code-block-content", children: children })] }));
92
79
  };
93
80
 
94
- const Button = ({ className = '', children, icon, onClick, style, ...restProps }) => {
95
- return (jsxRuntime.jsxs("div", { role: "button", className: classNames({
96
- 'ds-button': true,
97
- [className]: !!className,
98
- }), onClick: onClick, style: style, ...restProps, children: [icon && jsxRuntime.jsx("div", { className: "ds-button__icon", children: icon }), children] }));
99
- };
100
-
101
81
  const CheckMarkIcon = ({ size }) => {
102
82
  return (jsxRuntime.jsx("svg", { width: size, height: size, viewBox: `0 0 ${size} ${size}`, fill: "none", xmlns: "http://www.w3.org/2000/svg", children: jsxRuntime.jsx("path", { "fill-rule": "evenodd", "clip-rule": "evenodd", d: "M9.338 21.575a1.058 1.058 0 0 1-.53-.363L2.275 13.17a1.063 1.063 0 0 1 1.65-1.341l5.63 6.928L19.33 3.86a1.064 1.064 0 0 1 1.778 1.167L10.551 21.115a1.065 1.065 0 0 1-1.213.46z", fill: "currentColor" }) }));
103
83
  };
@@ -113,6 +93,7 @@ const zhCN = {
113
93
  copy: '复制',
114
94
  copied: '已复制',
115
95
  download: '下载',
96
+ downloaded: '已下载',
116
97
  },
117
98
  mermaid: {
118
99
  diagram: '图表',
@@ -120,14 +101,20 @@ const zhCN = {
120
101
  zoomOut: '缩小',
121
102
  zoomIn: '放大',
122
103
  download: '下载',
104
+ fullScreen: '全屏',
105
+ exitFullScreen: '退出全屏',
106
+ downloadImage: '下载图片',
107
+ downloadedImage: '已下载',
108
+ copyImage: '复制图片',
109
+ copiedImage: '已复制',
123
110
  },
124
111
  };
125
112
 
126
- const ConfigContext = React.createContext({
113
+ const ConfigContext = react.createContext({
127
114
  locale: zhCN,
128
115
  });
129
116
  const ConfigProvider = ({ locale, children, mermaidConfig }) => {
130
- const contextValue = React.useMemo(() => {
117
+ const contextValue = react.useMemo(() => {
131
118
  const contextValue = {
132
119
  locale: locale || zhCN,
133
120
  };
@@ -140,7 +127,7 @@ const ConfigProvider = ({ locale, children, mermaidConfig }) => {
140
127
  };
141
128
  // Hook 用于在组件中使用配置
142
129
  const useConfig = () => {
143
- const context = React.useContext(ConfigContext);
130
+ const context = react.useContext(ConfigContext);
144
131
  return context;
145
132
  };
146
133
  // Hook 用于获取当前语言包
@@ -149,60 +136,86 @@ const useLocale = () => {
149
136
  return locale;
150
137
  };
151
138
 
152
- const TIMEOUT = 3000;
139
+ const Button = ({ className = '', children, icon, onClick, style, disabled = false, ...restProps }) => {
140
+ const handleClick = (e) => {
141
+ if (disabled) {
142
+ e.preventDefault();
143
+ return;
144
+ }
145
+ onClick?.();
146
+ };
147
+ return (jsxRuntime.jsxs("div", { role: "button", className: classNames({
148
+ 'ds-button': true,
149
+ 'ds-button__disabled': disabled,
150
+ }, className), onClick: handleClick, style: style, "aria-disabled": disabled, ...restProps, children: [icon && jsxRuntime.jsx("div", { className: "ds-button__icon", children: icon }), children] }));
151
+ };
152
+
153
+ const SuccessButton = (props) => {
154
+ const { onClick, icon, executeText, children, ...rest } = props;
155
+ const [isLoading, setIsLoading] = react.useState(false);
156
+ const [isSuccess, setIsSuccess] = react.useState(false);
157
+ const isUnmounted = react.useRef(false);
158
+ const handleClick = async () => {
159
+ if (isLoading || isSuccess) {
160
+ return;
161
+ }
162
+ try {
163
+ // 如果onClick不是异步函数,则直接调用
164
+ const returnValue = onClick();
165
+ if (returnValue instanceof Promise) {
166
+ setIsLoading(true);
167
+ const result = await returnValue;
168
+ if (result) {
169
+ setIsSuccess(true);
170
+ setTimeout(() => {
171
+ if (!isUnmounted.current) {
172
+ setIsSuccess(false);
173
+ }
174
+ }, 1000);
175
+ }
176
+ }
177
+ }
178
+ catch (error) {
179
+ setIsSuccess(false);
180
+ }
181
+ finally {
182
+ setIsLoading(false);
183
+ }
184
+ };
185
+ react.useEffect(() => {
186
+ isUnmounted.current = false;
187
+ return () => {
188
+ isUnmounted.current = true;
189
+ };
190
+ }, []);
191
+ return (jsxRuntime.jsx(Button, { ...rest, onClick: handleClick, icon: isSuccess ? jsxRuntime.jsx(CheckMarkIcon, { size: 24 }) : icon, children: isSuccess ? executeText || children : children }));
192
+ };
193
+
153
194
  const CopyButton = ({ codeContent, style, className }) => {
154
195
  const { locale } = useConfig();
155
- const [copyText, setCopyText] = React.useState(locale.codeBlock.copy);
156
- const [showCheckmark, setShowCheckmark] = React.useState(false);
157
- const [isCopying, setIsCopying] = React.useState(false);
158
- // 下载文件
159
- // 复制到剪贴板
160
196
  const handleCopy = async () => {
161
- if (isCopying || !codeContent)
162
- return;
163
- setIsCopying(true);
164
197
  try {
165
- await navigator.clipboard.writeText(codeContent);
166
- setCopyText(locale.codeBlock.copied);
167
- setShowCheckmark(true);
168
- setTimeout(() => {
169
- setCopyText(locale.codeBlock.copy);
170
- setShowCheckmark(false);
171
- setIsCopying(false);
172
- }, TIMEOUT);
198
+ await navigator.clipboard.writeText(codeContent || '');
199
+ return true;
173
200
  }
174
201
  catch (err) {
175
202
  // 降级方案:使用传统方法
176
203
  const textArea = document.createElement('textarea');
177
- textArea.value = codeContent;
178
- document.body.appendChild(textArea);
204
+ textArea.value = codeContent || '';
179
205
  textArea.select();
180
- try {
181
- document.execCommand('copy');
182
- setCopyText(locale.codeBlock.copied);
183
- setShowCheckmark(true);
184
- setTimeout(() => {
185
- setCopyText(locale.codeBlock.copy);
186
- setShowCheckmark(false);
187
- setIsCopying(false);
188
- }, TIMEOUT);
189
- }
190
- catch (fallbackErr) {
191
- console.error('Fallback copy failed:', fallbackErr);
192
- setIsCopying(false);
193
- }
194
- document.body.removeChild(textArea);
206
+ document.execCommand('copy');
207
+ return true;
195
208
  }
196
209
  };
197
- return (jsxRuntime.jsx(Button, { style: style, className: className, icon: showCheckmark ? jsxRuntime.jsx(CheckMarkIcon, { size: 24 }) : jsxRuntime.jsx(CopyIcon, { size: 24 }), onClick: handleCopy, children: jsxRuntime.jsx("span", { children: copyText }) }));
210
+ return (jsxRuntime.jsx(SuccessButton, { onClick: handleCopy, icon: jsxRuntime.jsx(CopyIcon, { size: 24 }), executeText: locale.codeBlock.copied || 'copied', style: style, className: className, children: locale.codeBlock.copy || 'copy' }));
198
211
  };
199
212
 
200
213
  const DownloadButton = ({ codeContent, language, style, className }) => {
201
214
  const { locale } = useConfig();
202
215
  // 下载文件
203
- const handleDownload = () => {
216
+ const handleDownload = async () => {
204
217
  if (!codeContent)
205
- return;
218
+ return false;
206
219
  const blob = new Blob([codeContent], { type: 'text/plain;charset=utf-8' });
207
220
  const url = URL.createObjectURL(blob);
208
221
  const link = document.createElement('a');
@@ -248,8 +261,9 @@ const DownloadButton = ({ codeContent, language, style, className }) => {
248
261
  link.click();
249
262
  document.body.removeChild(link);
250
263
  URL.revokeObjectURL(url);
264
+ return true;
251
265
  };
252
- return (jsxRuntime.jsx(Button, { style: style, className: className, icon: jsxRuntime.jsx(DownloadIcon, { size: 24 }), onClick: handleDownload, children: jsxRuntime.jsx("span", { children: locale.codeBlock.download }) }));
266
+ return (jsxRuntime.jsx(SuccessButton, { onClick: handleDownload, icon: jsxRuntime.jsx(DownloadIcon, { size: 24 }), executeText: locale.codeBlock.downloaded || 'Downloaded', style: style, className: className, children: locale.codeBlock.download || 'Download' }));
253
267
  };
254
268
 
255
269
  const CodeBlockActions = ({ codeContent, language }) => {
@@ -290,7 +304,8 @@ const HighReactMarkdown = ({ children: _children, ...props }) => {
290
304
  const currentMath = themeState.math;
291
305
  const currentPlugins = themeState.plugins;
292
306
  const mathSplitSymbol = currentMath?.splitSymbol ?? 'dollar';
293
- const { remarkPlugins, rehypePlugins, hasKatexPlugin, components } = React.useMemo(() => {
307
+ const finalReplaceMathBracket = currentMath?.replaceMathBracket ?? replaceMathBracket;
308
+ const { remarkPlugins, rehypePlugins, hasKatexPlugin, components } = react.useMemo(() => {
294
309
  let hasKatexPlugin = false;
295
310
  const components = {};
296
311
  const remarkPlugins = [gfmPlugin];
@@ -326,13 +341,13 @@ const HighReactMarkdown = ({ children: _children, ...props }) => {
326
341
  components,
327
342
  };
328
343
  }, [currentPlugins]);
329
- const children = React.useMemo(() => {
344
+ const children = react.useMemo(() => {
330
345
  /** 如果存在数学公式插件,并且数学公式分隔符为括号,则替换成 $ 符号 */
331
346
  if (hasKatexPlugin && mathSplitSymbol === 'bracket') {
332
- return replaceMathBracket(_children);
347
+ return finalReplaceMathBracket(_children);
333
348
  }
334
349
  return _children;
335
- }, [hasKatexPlugin, mathSplitSymbol, _children]);
350
+ }, [hasKatexPlugin, mathSplitSymbol, finalReplaceMathBracket, _children]);
336
351
  return (jsxRuntime.jsx(Markdown$2, { remarkPlugins: remarkPlugins, rehypePlugins: rehypePlugins, components: {
337
352
  code: CodeComponent,
338
353
  table: ({ children, ...props }) => {
@@ -341,30 +356,30 @@ const HighReactMarkdown = ({ children: _children, ...props }) => {
341
356
  ...components,
342
357
  }, ...props, children: children }));
343
358
  };
344
- var HighReactMarkdown$1 = React.memo(HighReactMarkdown);
359
+ var HighReactMarkdown$1 = react.memo(HighReactMarkdown);
345
360
 
346
361
  const useTypingTask = (options) => {
347
362
  const { timerType = 'setTimeout', interval, charsRef, onEnd, onStart, onBeforeTypedChar, onTypedChar, processCharDisplay, wholeContentRef, disableTyping, triggerUpdate, resetWholeContent, } = options;
348
363
  /** 是否卸载 */
349
- const isUnmountRef = React.useRef(false);
364
+ const isUnmountRef = react.useRef(false);
350
365
  /** 是否正在打字 */
351
- const isTypingRef = React.useRef(false);
366
+ const isTypingRef = react.useRef(false);
352
367
  /** 动画帧ID */
353
- const animationFrameRef = React.useRef(null);
368
+ const animationFrameRef = react.useRef(null);
354
369
  /** 传统定时器(兼容模式) */
355
- const timerRef = React.useRef(null);
370
+ const timerRef = react.useRef(null);
356
371
  // 已经打过的字记录
357
- const typedCharsRef = React.useRef(undefined);
372
+ const typedCharsRef = react.useRef(undefined);
358
373
  // 是否主动调用 stop 方法
359
- const typedIsManualStopRef = React.useRef(false);
360
- const disableTypingRef = React.useRef(disableTyping);
374
+ const typedIsManualStopRef = react.useRef(false);
375
+ const disableTypingRef = react.useRef(disableTyping);
361
376
  disableTypingRef.current = disableTyping;
362
- const intervalRef = React.useRef(interval);
377
+ const intervalRef = react.useRef(interval);
363
378
  intervalRef.current = interval;
364
379
  const getChars = () => {
365
380
  return charsRef.current;
366
381
  };
367
- React.useEffect(() => {
382
+ react.useEffect(() => {
368
383
  isUnmountRef.current = false;
369
384
  return () => {
370
385
  isUnmountRef.current = true;
@@ -677,30 +692,30 @@ const useTypingTask = (options) => {
677
692
  };
678
693
  };
679
694
 
680
- const MarkdownContext = React.createContext({});
695
+ const MarkdownContext = react.createContext({});
681
696
  const MarkdownProvider = ({ value, children }) => {
682
- const contextValue = React.useMemo(() => value, [value]);
697
+ const contextValue = react.useMemo(() => value, [value]);
683
698
  return jsxRuntime.jsx(MarkdownContext.Provider, { value: contextValue, children: children });
684
699
  };
685
700
 
686
- const MarkdownCMDInner = React.forwardRef(({ interval = 30, onEnd, onStart, onTypedChar, onBeforeTypedChar, timerType = 'setTimeout', disableTyping = false, autoStartTyping = true }, ref) => {
701
+ const MarkdownCMDInner = react.forwardRef(({ interval = 30, onEnd, onStart, onTypedChar, onBeforeTypedChar, timerType = 'setTimeout', disableTyping = false, autoStartTyping = true }, ref) => {
687
702
  const { state: themeState } = useMarkdownThemeContext();
688
703
  // 从 context 中获取主题配置
689
704
  const currentTheme = themeState.theme;
690
705
  /** 是否自动开启打字动画, 后面发生变化将不会生效 */
691
- const autoStartTypingRef = React.useRef(autoStartTyping);
706
+ const autoStartTypingRef = react.useRef(autoStartTyping);
692
707
  /** 是否打过字 */
693
- const isStartedTypingRef = React.useRef(false);
708
+ const isStartedTypingRef = react.useRef(false);
694
709
  /** 当前需要打字的内容 */
695
- const charsRef = React.useRef([]);
710
+ const charsRef = react.useRef([]);
696
711
  /**
697
712
  * 打字是否已经完全结束
698
713
  * 如果打字已经完全结束,则不会再触发打字效果
699
714
  */
700
- const isWholeTypedEndRef = React.useRef(false);
701
- const charIndexRef = React.useRef(0);
715
+ const isWholeTypedEndRef = react.useRef(false);
716
+ const charIndexRef = react.useRef(0);
702
717
  /** 整个内容引用 */
703
- const wholeContentRef = React.useRef({
718
+ const wholeContentRef = react.useRef({
704
719
  thinking: {
705
720
  content: '',
706
721
  length: 0,
@@ -713,7 +728,7 @@ const MarkdownCMDInner = React.forwardRef(({ interval = 30, onEnd, onStart, onTy
713
728
  },
714
729
  allLength: 0,
715
730
  });
716
- const [, setUpdate] = React.useState(0);
731
+ const [, setUpdate] = react.useState(0);
717
732
  const triggerUpdate = () => {
718
733
  setUpdate((prev) => prev + 1);
719
734
  };
@@ -797,7 +812,7 @@ const MarkdownCMDInner = React.forwardRef(({ interval = 30, onEnd, onStart, onTy
797
812
  manual: false,
798
813
  });
799
814
  };
800
- React.useImperativeHandle(ref, () => ({
815
+ react.useImperativeHandle(ref, () => ({
801
816
  /**
802
817
  * 添加内容
803
818
  * @param content 内容 {string}
@@ -870,7 +885,7 @@ const MarkdownCMDInner = React.forwardRef(({ interval = 30, onEnd, onStart, onTy
870
885
  if (__DEV__) {
871
886
  MarkdownCMDInner.displayName = 'MarkdownCMD';
872
887
  }
873
- const MarkdownCMD = React.forwardRef((props, ref) => {
888
+ const MarkdownCMD = react.forwardRef((props, ref) => {
874
889
  const { children = '', answerType = 'answer', isInnerRender, ...reset } = props;
875
890
  if (__DEV__) {
876
891
  if (!['thinking', 'answer'].includes(answerType)) {
@@ -880,9 +895,9 @@ const MarkdownCMD = React.forwardRef((props, ref) => {
880
895
  throw new Error('Markdown组件的子元素必须是一个字符串');
881
896
  }
882
897
  }
883
- const contextValue = React.useMemo(() => ({ ...reset, answerType }), [reset, answerType]);
898
+ const contextValue = react.useMemo(() => ({ ...reset, answerType }), [reset, answerType]);
884
899
  // 分离主题相关的 props
885
- const themeProps = React.useMemo(() => ({
900
+ const themeProps = react.useMemo(() => ({
886
901
  theme: props.theme || DEFAULT_THEME,
887
902
  math: props.math,
888
903
  codeBlock: props.codeBlock,
@@ -897,9 +912,9 @@ const MarkdownCMD = React.forwardRef((props, ref) => {
897
912
  });
898
913
 
899
914
  const MarkdownInner = ({ children: _children = '', answerType, markdownRef, ...rest }) => {
900
- const cmdRef = React.useRef(null);
901
- const prefixRef = React.useRef('');
902
- const content = React.useMemo(() => {
915
+ const cmdRef = react.useRef(null);
916
+ const prefixRef = react.useRef('');
917
+ const content = react.useMemo(() => {
903
918
  if (typeof _children === 'string') {
904
919
  return _children;
905
920
  }
@@ -908,7 +923,7 @@ const MarkdownInner = ({ children: _children = '', answerType, markdownRef, ...r
908
923
  }
909
924
  return '';
910
925
  }, [_children]);
911
- React.useEffect(() => {
926
+ react.useEffect(() => {
912
927
  if (prefixRef.current !== content) {
913
928
  let newContent = '';
914
929
  if (prefixRef.current === '') {
@@ -927,7 +942,7 @@ const MarkdownInner = ({ children: _children = '', answerType, markdownRef, ...r
927
942
  prefixRef.current = content;
928
943
  }
929
944
  }, [answerType, content]);
930
- React.useImperativeHandle(markdownRef, () => ({
945
+ react.useImperativeHandle(markdownRef, () => ({
931
946
  stop: () => {
932
947
  cmdRef.current.stop();
933
948
  },
@@ -945,7 +960,7 @@ const MarkdownInner = ({ children: _children = '', answerType, markdownRef, ...r
945
960
  const { theme, math, plugins, codeBlock, ...baseProps } = rest;
946
961
  return jsxRuntime.jsx(MarkdownCMD, { ref: cmdRef, ...baseProps, isInnerRender: true });
947
962
  };
948
- const Markdown = React.forwardRef((props, ref) => {
963
+ const Markdown = react.forwardRef((props, ref) => {
949
964
  const { children = '', answerType = 'answer', ...reset } = props;
950
965
  if (__DEV__) {
951
966
  if (!['thinking', 'answer'].includes(answerType)) {
@@ -955,9 +970,9 @@ const Markdown = React.forwardRef((props, ref) => {
955
970
  throw new Error('Markdown组件的子元素必须是一个字符串');
956
971
  }
957
972
  }
958
- const contextValue = React.useMemo(() => ({ ...reset, answerType }), [reset, answerType]);
973
+ const contextValue = react.useMemo(() => ({ ...reset, answerType }), [reset, answerType]);
959
974
  // 分离主题相关的 props
960
- const themeProps = React.useMemo(() => ({
975
+ const themeProps = react.useMemo(() => ({
961
976
  theme: props.theme || DEFAULT_THEME,
962
977
  math: props.math,
963
978
  codeBlock: props.codeBlock,
@@ -966,169 +981,12 @@ const Markdown = React.forwardRef((props, ref) => {
966
981
  }), [props.theme, props.math, props.codeBlock, props.plugins, props.answerType]);
967
982
  return (jsxRuntime.jsx(MarkdownProvider, { value: contextValue, children: jsxRuntime.jsx(MarkdownThemeProvider, { value: themeProps, children: jsxRuntime.jsx(MarkdownInner, { ...props, answerType: answerType, markdownRef: ref }) }) }));
968
983
  });
969
- var Markdown$1 = React.memo(Markdown);
984
+ var Markdown$1 = react.memo(Markdown);
970
985
 
971
- const IconButton = ({ icon, style, className = '', onClick, ...restProps }) => {
972
- return jsxRuntime.jsx(Button, { icon: icon, className: `ds-icon-button ${className}`, style: style, onClick: onClick, ...restProps });
986
+ const IconButton = ({ icon, className = '', ...restProps }) => {
987
+ return jsxRuntime.jsx(Button, { icon: icon, className: `ds-icon-button ${className}`, ...restProps });
973
988
  };
974
989
 
975
- const ToolTip = React.forwardRef(({ title, children, position = 'top', className = '', style, showArrow = true, delay = 200 }, ref) => {
976
- const [isVisible, setIsVisible] = React.useState(false);
977
- const [tooltipStyle, setTooltipStyle] = React.useState({});
978
- const triggerRef = React.useRef(null);
979
- const tooltipRef = React.useRef(null);
980
- const timeoutRef = React.useRef(undefined);
981
- // 转发ref到trigger元素
982
- React.useImperativeHandle(ref, () => triggerRef.current, []);
983
- const showTooltip = React.useCallback(() => {
984
- timeoutRef.current = window.setTimeout(() => {
985
- setIsVisible(true);
986
- }, delay);
987
- }, [delay]);
988
- const hideTooltip = React.useCallback(() => {
989
- if (timeoutRef.current) {
990
- clearTimeout(timeoutRef.current);
991
- }
992
- setIsVisible(false);
993
- }, []);
994
- const updatePosition = React.useCallback(() => {
995
- if (!triggerRef.current || !tooltipRef.current)
996
- return;
997
- const triggerRect = triggerRef.current.getBoundingClientRect();
998
- const tooltipRect = tooltipRef.current.getBoundingClientRect();
999
- let top = 0;
1000
- let left = 0;
1001
- switch (position) {
1002
- case 'top':
1003
- top = triggerRect.top - tooltipRect.height - 8;
1004
- left = triggerRect.left + triggerRect.width / 2 - tooltipRect.width / 2;
1005
- break;
1006
- case 'bottom':
1007
- top = triggerRect.bottom + 8;
1008
- left = triggerRect.left + triggerRect.width / 2 - tooltipRect.width / 2;
1009
- break;
1010
- case 'left':
1011
- top = triggerRect.top + triggerRect.height / 2 - tooltipRect.height / 2;
1012
- left = triggerRect.left - tooltipRect.width - 8;
1013
- break;
1014
- case 'right':
1015
- top = triggerRect.top + triggerRect.height / 2 - tooltipRect.height / 2;
1016
- left = triggerRect.right + 8;
1017
- break;
1018
- }
1019
- setTooltipStyle({
1020
- position: 'fixed',
1021
- top: `${top}px`,
1022
- left: `${left}px`,
1023
- zIndex: 1000,
1024
- });
1025
- }, [position]);
1026
- React.useEffect(() => {
1027
- if (isVisible) {
1028
- updatePosition();
1029
- }
1030
- }, [isVisible, position, updatePosition]);
1031
- React.useEffect(() => {
1032
- const handleScroll = () => {
1033
- if (isVisible) {
1034
- updatePosition();
1035
- }
1036
- };
1037
- const handleResize = () => {
1038
- if (isVisible) {
1039
- updatePosition();
1040
- }
1041
- };
1042
- window.addEventListener('scroll', handleScroll, true);
1043
- window.addEventListener('resize', handleResize);
1044
- return () => {
1045
- window.removeEventListener('scroll', handleScroll, true);
1046
- window.removeEventListener('resize', handleResize);
1047
- };
1048
- }, [isVisible, updatePosition]);
1049
- React.useEffect(() => {
1050
- return () => {
1051
- if (timeoutRef.current) {
1052
- clearTimeout(timeoutRef.current);
1053
- }
1054
- };
1055
- }, []);
1056
- const renderTooltip = () => {
1057
- if (!isVisible)
1058
- return null;
1059
- const tooltipElement = (jsxRuntime.jsxs("div", { ref: tooltipRef, className: classNames('ds-tooltip', `ds-tooltip--${position}`), style: tooltipStyle, children: [jsxRuntime.jsx("div", { className: "ds-tooltip__title", children: title }), showArrow && jsxRuntime.jsx("div", { className: classNames('ds-tooltip__arrow', `ds-tooltip__arrow--${position}`) })] }));
1060
- return reactDom.createPortal(tooltipElement, document.body);
1061
- };
1062
- // 合并原有的事件处理器
1063
- const handleMouseEnter = React.useCallback((e) => {
1064
- e.stopPropagation(); // 阻止事件冒泡
1065
- showTooltip();
1066
- // 只在子元素有onMouseEnter时才调用
1067
- const props = children.props;
1068
- if (props.onMouseEnter) {
1069
- props.onMouseEnter(e);
1070
- }
1071
- }, [children.props, showTooltip]);
1072
- const handleMouseLeave = React.useCallback((e) => {
1073
- e.stopPropagation(); // 阻止事件冒泡
1074
- hideTooltip();
1075
- // 只在子元素有onMouseLeave时才调用
1076
- const props = children.props;
1077
- if (props.onMouseLeave) {
1078
- props.onMouseLeave(e);
1079
- }
1080
- }, [children.props, hideTooltip]);
1081
- const handleFocus = React.useCallback((e) => {
1082
- e.stopPropagation(); // 阻止事件冒泡
1083
- showTooltip();
1084
- // 只在子元素有onFocus时才调用
1085
- const props = children.props;
1086
- if (props.onFocus) {
1087
- props.onFocus(e);
1088
- }
1089
- }, [children.props, showTooltip]);
1090
- const handleBlur = React.useCallback((e) => {
1091
- e.stopPropagation(); // 阻止事件冒泡
1092
- hideTooltip();
1093
- // 只在子元素有onBlur时才调用
1094
- const props = children.props;
1095
- if (props.onBlur) {
1096
- props.onBlur(e);
1097
- }
1098
- }, [children.props, hideTooltip]);
1099
- // 处理onClick事件
1100
- const handleClick = React.useCallback((e) => {
1101
- // 调用原有的onClick
1102
- const props = children.props;
1103
- if (props.onClick) {
1104
- props.onClick(e);
1105
- }
1106
- }, [children.props]);
1107
- // 检查组件是否支持ref
1108
- const isForwardRef = React.isValidElement(children) &&
1109
- typeof children.type === 'function' &&
1110
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1111
- children.type.$$typeof === Symbol.for('react.forward_ref');
1112
- // 如果组件不支持ref,使用包装div的方式
1113
- if (!isForwardRef && typeof children.type === 'function') {
1114
- return (jsxRuntime.jsxs("div", { ref: triggerRef, className: classNames('ds-tooltip-trigger', className), style: style, onMouseEnter: showTooltip, onMouseLeave: hideTooltip, onFocus: showTooltip, onBlur: hideTooltip, children: [children, renderTooltip()] }));
1115
- }
1116
- // 使用 cloneElement 直接给子元素添加事件监听器和ref
1117
- const enhancedChild = React.cloneElement(children, {
1118
- ref: triggerRef,
1119
- className: classNames(children.props.className, className),
1120
- style: { ...children.props.style, ...style },
1121
- onMouseEnter: handleMouseEnter,
1122
- onMouseLeave: handleMouseLeave,
1123
- onFocus: handleFocus,
1124
- onBlur: handleBlur,
1125
- onClick: handleClick,
1126
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1127
- });
1128
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [enhancedChild, renderTooltip()] }));
1129
- });
1130
- ToolTip.displayName = 'ToolTip';
1131
-
1132
990
  const Segmented = ({ Segmented: segments, value, onChange }) => {
1133
991
  const handleClick = (itemValue) => {
1134
992
  onChange?.(itemValue);
@@ -1139,17 +997,20 @@ const Segmented = ({ Segmented: segments, value, onChange }) => {
1139
997
  /* eslint-disable react-refresh/only-export-components */
1140
998
 
1141
999
  exports.Button = Button;
1000
+ exports.CheckMarkIcon = CheckMarkIcon;
1142
1001
  exports.CodeBlockActions = CodeBlockActions;
1143
1002
  exports.CodeBlockWrap = CodeBlockWrap;
1144
1003
  exports.ConfigProvider = ConfigProvider;
1145
1004
  exports.CopyButton = CopyButton;
1005
+ exports.CopyIcon = CopyIcon;
1146
1006
  exports.DownloadButton = DownloadButton;
1007
+ exports.DownloadIcon = DownloadIcon;
1147
1008
  exports.HighlightCode = HighlightCode;
1148
1009
  exports.IconButton = IconButton;
1149
1010
  exports.Markdown = Markdown$1;
1150
1011
  exports.MarkdownCMD = MarkdownCMD;
1151
1012
  exports.Segmented = Segmented;
1152
- exports.ToolTip = ToolTip;
1013
+ exports.SuccessButton = SuccessButton;
1153
1014
  exports.default = Markdown$1;
1154
1015
  exports.useConfig = useConfig;
1155
1016
  exports.useLocale = useLocale;