ds-markdown 0.1.9-beta.3 → 0.1.9-beta.5

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.
@@ -4,6 +4,13 @@ declare const enUS: {
4
4
  readonly copied: "Copied";
5
5
  readonly download: "Download";
6
6
  };
7
+ readonly mermaid: {
8
+ readonly diagram: "Diagram";
9
+ readonly code: "Code";
10
+ readonly zoomOut: "Zoom Out";
11
+ readonly zoomIn: "Zoom In";
12
+ readonly download: "Download";
13
+ };
7
14
  };
8
15
  type EnUS = typeof enUS;
9
16
 
@@ -8,6 +8,13 @@ const enUS = {
8
8
  copied: 'Copied',
9
9
  download: 'Download',
10
10
  },
11
+ mermaid: {
12
+ diagram: 'Diagram',
13
+ code: 'Code',
14
+ zoomOut: 'Zoom Out',
15
+ zoomIn: 'Zoom In',
16
+ download: 'Download',
17
+ },
11
18
  };
12
19
 
13
20
  exports.default = enUS;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../../src/i18n/en/index.ts"],"sourcesContent":[null],"names":[],"mappings":";;;;AAAa,MAAA,IAAI,GAAG;AAClB,IAAA,SAAS,EAAE;AACT,QAAA,IAAI,EAAE,MAAM;AACZ,QAAA,MAAM,EAAE,QAAQ;AAChB,QAAA,QAAQ,EAAE,UAAU;AACrB,KAAA;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":["../../../../src/i18n/en/index.ts"],"sourcesContent":[null],"names":[],"mappings":";;;;AAAa,MAAA,IAAI,GAAG;AAClB,IAAA,SAAS,EAAE;AACT,QAAA,IAAI,EAAE,MAAM;AACZ,QAAA,MAAM,EAAE,QAAQ;AAChB,QAAA,QAAQ,EAAE,UAAU;AACrB,KAAA;AACD,IAAA,OAAO,EAAE;AACP,QAAA,OAAO,EAAE,SAAS;AAClB,QAAA,IAAI,EAAE,MAAM;AACZ,QAAA,OAAO,EAAE,UAAU;AACnB,QAAA,MAAM,EAAE,SAAS;AACjB,QAAA,QAAQ,EAAE,UAAU;AACrB,KAAA;;;;;;"}
@@ -4,6 +4,13 @@ declare const zhCN: {
4
4
  readonly copied: "已复制";
5
5
  readonly download: "下载";
6
6
  };
7
+ readonly mermaid: {
8
+ readonly diagram: "图表";
9
+ readonly code: "代码";
10
+ readonly zoomOut: "缩小";
11
+ readonly zoomIn: "放大";
12
+ readonly download: "下载";
13
+ };
7
14
  };
8
15
  type ZhCN = typeof zhCN;
9
16
 
@@ -8,6 +8,13 @@ const zhCN = {
8
8
  copied: '已复制',
9
9
  download: '下载',
10
10
  },
11
+ mermaid: {
12
+ diagram: '图表',
13
+ code: '代码',
14
+ zoomOut: '缩小',
15
+ zoomIn: '放大',
16
+ download: '下载',
17
+ },
11
18
  };
12
19
 
13
20
  exports.default = zhCN;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../../src/i18n/zh/index.ts"],"sourcesContent":[null],"names":[],"mappings":";;;;AAAa,MAAA,IAAI,GAAG;AAClB,IAAA,SAAS,EAAE;AACT,QAAA,IAAI,EAAE,IAAI;AACV,QAAA,MAAM,EAAE,KAAK;AACb,QAAA,QAAQ,EAAE,IAAI;AACf,KAAA;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":["../../../../src/i18n/zh/index.ts"],"sourcesContent":[null],"names":[],"mappings":";;;;AAAa,MAAA,IAAI,GAAG;AAClB,IAAA,SAAS,EAAE;AACT,QAAA,IAAI,EAAE,IAAI;AACV,QAAA,MAAM,EAAE,KAAK;AACb,QAAA,QAAQ,EAAE,IAAI;AACf,KAAA;AACD,IAAA,OAAO,EAAE;AACP,QAAA,OAAO,EAAE,IAAI;AACb,QAAA,IAAI,EAAE,IAAI;AACV,QAAA,OAAO,EAAE,IAAI;AACb,QAAA,MAAM,EAAE,IAAI;AACZ,QAAA,QAAQ,EAAE,IAAI;AACf,KAAA;;;;;;"}
@@ -123,6 +123,26 @@ interface ButtonProps {
123
123
  }
124
124
  declare const Button: React__default.FC<ButtonProps>;
125
125
 
126
+ interface IconButtonProps {
127
+ icon: React__default.ReactNode;
128
+ style?: React__default.CSSProperties;
129
+ className?: string;
130
+ onClick?: () => void;
131
+ }
132
+ declare const IconButton: React__default.FC<IconButtonProps>;
133
+
134
+ type TooltipPosition = 'top' | 'bottom' | 'left' | 'right';
135
+ interface ToolTipProps {
136
+ title: React__default.ReactNode;
137
+ children: React__default.ReactElement;
138
+ position?: TooltipPosition;
139
+ className?: string;
140
+ style?: React__default.CSSProperties;
141
+ showArrow?: boolean;
142
+ delay?: number;
143
+ }
144
+ declare const ToolTip: React__default.ForwardRefExoticComponent<ToolTipProps & React__default.RefAttributes<HTMLElement>>;
145
+
126
146
  interface CopyButtonProps {
127
147
  codeContent?: string;
128
148
  style?: React__default.CSSProperties;
@@ -150,6 +170,12 @@ interface CodeBlockWrapProps {
150
170
  }
151
171
  declare const CodeBlockWrap: React__default.FC<CodeBlockWrapProps>;
152
172
 
173
+ interface HighlightCodeProps {
174
+ code: string;
175
+ language: string;
176
+ }
177
+ declare const HighlightCode: React__default.FC<HighlightCodeProps>;
178
+
153
179
  declare namespace Mermaid {
154
180
  /**
155
181
  * The font size to use
@@ -1671,6 +1697,13 @@ interface Locale {
1671
1697
  download: string;
1672
1698
  [key: string]: string;
1673
1699
  };
1700
+ mermaid: {
1701
+ diagram: string;
1702
+ code: string;
1703
+ zoomOut: string;
1704
+ zoomIn: string;
1705
+ download: string;
1706
+ };
1674
1707
  [key: string]: unknown;
1675
1708
  }
1676
1709
  interface ConfigProviderProps {
@@ -1688,5 +1721,5 @@ declare const useLocale: () => Locale;
1688
1721
 
1689
1722
  declare const useThemeState: () => IMarkdownThemeStateProps;
1690
1723
 
1691
- export { Button, CodeBlockActions, CodeBlockWrap, ConfigProvider, CopyButton, DownloadButton, _default as Markdown, MarkdownCMD, _default as default, useConfig, useLocale, useThemeState };
1724
+ export { Button, CodeBlockActions, CodeBlockWrap, ConfigProvider, CopyButton, DownloadButton, HighlightCode, IconButton, _default as Markdown, MarkdownCMD, ToolTip, _default as default, useConfig, useLocale, useThemeState };
1692
1725
  export type { ConfigContextType, ConfigProviderProps, IMarkdownMath, ITypedChar, Locale, MarkdownCMDProps, MarkdownCMDRef, MarkdownProps, MarkdownRef };
package/dist/cjs/index.js CHANGED
@@ -3,11 +3,12 @@
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
- var reactSyntaxHighlighter = require('react-syntax-highlighter');
9
8
  var gfmPlugin = require('remark-gfm');
10
9
  var classNames = require('classnames');
10
+ var reactSyntaxHighlighter = require('react-syntax-highlighter');
11
+ var reactDom = require('react-dom');
11
12
 
12
13
  const replaceMathBracket = (value) => {
13
14
  // 1. 提取所有块级公式内容,临时替换为占位符, [...]
@@ -35,7 +36,7 @@ const replaceMathBracket = (value) => {
35
36
  const DEFAULT_THEME = 'light';
36
37
  const DEFAULT_ANSWER_TYPE = 'answer';
37
38
  const DEFAULT_PLUGINS = [];
38
- const MarkdownThemeContext = react.createContext({
39
+ const MarkdownThemeContext = React.createContext({
39
40
  state: {
40
41
  theme: DEFAULT_THEME,
41
42
  answerType: DEFAULT_ANSWER_TYPE,
@@ -43,7 +44,7 @@ const MarkdownThemeContext = react.createContext({
43
44
  methods: {},
44
45
  });
45
46
  const MarkdownThemeProvider = ({ value = {}, children }) => {
46
- const contextValue = react.useMemo(() => ({
47
+ const contextValue = React.useMemo(() => ({
47
48
  state: {
48
49
  theme: DEFAULT_THEME,
49
50
  answerType: DEFAULT_ANSWER_TYPE,
@@ -55,9 +56,9 @@ const MarkdownThemeProvider = ({ value = {}, children }) => {
55
56
  }), [value]);
56
57
  return jsxRuntime.jsx(MarkdownThemeContext.Provider, { value: contextValue, children: children });
57
58
  };
58
- const useMarkdownThemeContext = () => react.useContext(MarkdownThemeContext);
59
+ const useMarkdownThemeContext = () => React.useContext(MarkdownThemeContext);
59
60
  const useThemeState = () => {
60
- return react.useContext(MarkdownThemeContext).state;
61
+ return React.useContext(MarkdownThemeContext).state;
61
62
  };
62
63
 
63
64
  const CodeBlockWrap = ({ children, title }) => {
@@ -65,11 +66,11 @@ const CodeBlockWrap = ({ children, title }) => {
65
66
  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 })] }));
66
67
  };
67
68
 
68
- const Button = ({ className = '', children, icon, onClick, style }) => {
69
+ const Button = ({ className = '', children, icon, onClick, style, ...restProps }) => {
69
70
  return (jsxRuntime.jsxs("div", { role: "button", className: classNames({
70
71
  'ds-button': true,
71
72
  [className]: !!className,
72
- }), onClick: onClick, style: style, children: [icon && jsxRuntime.jsx("div", { className: "ds-button__icon", children: icon }), children] }));
73
+ }), onClick: onClick, style: style, ...restProps, children: [icon && jsxRuntime.jsx("div", { className: "ds-button__icon", children: icon }), children] }));
73
74
  };
74
75
 
75
76
  const CheckMarkIcon = ({ size }) => {
@@ -88,13 +89,20 @@ const zhCN = {
88
89
  copied: '已复制',
89
90
  download: '下载',
90
91
  },
92
+ mermaid: {
93
+ diagram: '图表',
94
+ code: '代码',
95
+ zoomOut: '缩小',
96
+ zoomIn: '放大',
97
+ download: '下载',
98
+ },
91
99
  };
92
100
 
93
- const ConfigContext = react.createContext({
101
+ const ConfigContext = React.createContext({
94
102
  locale: zhCN,
95
103
  });
96
104
  const ConfigProvider = ({ locale, children, mermaidConfig }) => {
97
- const contextValue = react.useMemo(() => {
105
+ const contextValue = React.useMemo(() => {
98
106
  const contextValue = {
99
107
  locale: locale || zhCN,
100
108
  };
@@ -107,7 +115,7 @@ const ConfigProvider = ({ locale, children, mermaidConfig }) => {
107
115
  };
108
116
  // Hook 用于在组件中使用配置
109
117
  const useConfig = () => {
110
- const context = react.useContext(ConfigContext);
118
+ const context = React.useContext(ConfigContext);
111
119
  return context;
112
120
  };
113
121
  // Hook 用于获取当前语言包
@@ -119,9 +127,9 @@ const useLocale = () => {
119
127
  const TIMEOUT = 3000;
120
128
  const CopyButton = ({ codeContent, style, className }) => {
121
129
  const { locale } = useConfig();
122
- const [copyText, setCopyText] = react.useState(locale.codeBlock.copy);
123
- const [showCheckmark, setShowCheckmark] = react.useState(false);
124
- const [isCopying, setIsCopying] = react.useState(false);
130
+ const [copyText, setCopyText] = React.useState(locale.codeBlock.copy);
131
+ const [showCheckmark, setShowCheckmark] = React.useState(false);
132
+ const [isCopying, setIsCopying] = React.useState(false);
125
133
  // 下载文件
126
134
  // 复制到剪贴板
127
135
  const handleCopy = async () => {
@@ -242,11 +250,14 @@ const ID_PREFIX__ = '__ds-markdown__';
242
250
  /** 数学公式插件id */
243
251
  const katexId = `${ID_PREFIX__}katex`;
244
252
 
245
- const CodeComponent = ({ className, children }) => {
253
+ const HighlightCode = ({ code, language }) => {
254
+ return (jsxRuntime.jsx(reactSyntaxHighlighter.Prism, { useInlineStyles: false, language: language, style: {}, children: code }));
255
+ };
256
+
257
+ const CodeComponent = ({ className, children = '' }) => {
246
258
  const match = /language-(\w+)/.exec(className || '');
247
259
  const codeContent = String(children).replace(/\n$/, '');
248
- const { state: themeState } = useMarkdownThemeContext();
249
- return match ? (jsxRuntime.jsx(BlockWrap, { language: match[1], codeContent: codeContent, children: jsxRuntime.jsx(reactSyntaxHighlighter.Prism, { useInlineStyles: false, language: match[1], style: {}, children: codeContent }) })) : (jsxRuntime.jsx("code", { className: className, children: children }));
260
+ return match ? (jsxRuntime.jsx(BlockWrap, { language: match[1], codeContent: codeContent, children: jsxRuntime.jsx(HighlightCode, { code: codeContent, language: match[1] }) })) : (jsxRuntime.jsx("code", { className: className, children: children }));
250
261
  };
251
262
  const HighReactMarkdown = ({ children: _children, ...props }) => {
252
263
  const { state: themeState } = useMarkdownThemeContext();
@@ -254,7 +265,7 @@ const HighReactMarkdown = ({ children: _children, ...props }) => {
254
265
  const currentMath = themeState.math;
255
266
  const currentPlugins = themeState.plugins;
256
267
  const mathSplitSymbol = currentMath?.splitSymbol ?? 'dollar';
257
- const { remarkPlugins, rehypePlugins, hasKatexPlugin, components } = react.useMemo(() => {
268
+ const { remarkPlugins, rehypePlugins, hasKatexPlugin, components } = React.useMemo(() => {
258
269
  let hasKatexPlugin = false;
259
270
  const components = {};
260
271
  const remarkPlugins = [gfmPlugin];
@@ -290,7 +301,7 @@ const HighReactMarkdown = ({ children: _children, ...props }) => {
290
301
  components,
291
302
  };
292
303
  }, [currentPlugins]);
293
- const children = react.useMemo(() => {
304
+ const children = React.useMemo(() => {
294
305
  /** 如果存在数学公式插件,并且数学公式分隔符为括号,则替换成 $ 符号 */
295
306
  if (hasKatexPlugin && mathSplitSymbol === 'bracket') {
296
307
  return replaceMathBracket(_children);
@@ -305,30 +316,30 @@ const HighReactMarkdown = ({ children: _children, ...props }) => {
305
316
  ...components,
306
317
  }, ...props, children: children }));
307
318
  };
308
- var HighReactMarkdown$1 = react.memo(HighReactMarkdown);
319
+ var HighReactMarkdown$1 = React.memo(HighReactMarkdown);
309
320
 
310
321
  const useTypingTask = (options) => {
311
322
  const { timerType = 'setTimeout', interval, charsRef, onEnd, onStart, onBeforeTypedChar, onTypedChar, processCharDisplay, wholeContentRef, disableTyping, triggerUpdate, resetWholeContent, } = options;
312
323
  /** 是否卸载 */
313
- const isUnmountRef = react.useRef(false);
324
+ const isUnmountRef = React.useRef(false);
314
325
  /** 是否正在打字 */
315
- const isTypingRef = react.useRef(false);
326
+ const isTypingRef = React.useRef(false);
316
327
  /** 动画帧ID */
317
- const animationFrameRef = react.useRef(null);
328
+ const animationFrameRef = React.useRef(null);
318
329
  /** 传统定时器(兼容模式) */
319
- const timerRef = react.useRef(null);
330
+ const timerRef = React.useRef(null);
320
331
  // 已经打过的字记录
321
- const typedCharsRef = react.useRef(undefined);
332
+ const typedCharsRef = React.useRef(undefined);
322
333
  // 是否主动调用 stop 方法
323
- const typedIsManualStopRef = react.useRef(false);
324
- const disableTypingRef = react.useRef(disableTyping);
334
+ const typedIsManualStopRef = React.useRef(false);
335
+ const disableTypingRef = React.useRef(disableTyping);
325
336
  disableTypingRef.current = disableTyping;
326
- const intervalRef = react.useRef(interval);
337
+ const intervalRef = React.useRef(interval);
327
338
  intervalRef.current = interval;
328
339
  const getChars = () => {
329
340
  return charsRef.current;
330
341
  };
331
- react.useEffect(() => {
342
+ React.useEffect(() => {
332
343
  isUnmountRef.current = false;
333
344
  return () => {
334
345
  isUnmountRef.current = true;
@@ -641,30 +652,30 @@ const useTypingTask = (options) => {
641
652
  };
642
653
  };
643
654
 
644
- const MarkdownContext = react.createContext({});
655
+ const MarkdownContext = React.createContext({});
645
656
  const MarkdownProvider = ({ value, children }) => {
646
- const contextValue = react.useMemo(() => value, [value]);
657
+ const contextValue = React.useMemo(() => value, [value]);
647
658
  return jsxRuntime.jsx(MarkdownContext.Provider, { value: contextValue, children: children });
648
659
  };
649
660
 
650
- const MarkdownCMDInner = react.forwardRef(({ interval = 30, onEnd, onStart, onTypedChar, onBeforeTypedChar, timerType = 'setTimeout', disableTyping = false, autoStartTyping = true }, ref) => {
661
+ const MarkdownCMDInner = React.forwardRef(({ interval = 30, onEnd, onStart, onTypedChar, onBeforeTypedChar, timerType = 'setTimeout', disableTyping = false, autoStartTyping = true }, ref) => {
651
662
  const { state: themeState } = useMarkdownThemeContext();
652
663
  // 从 context 中获取主题配置
653
664
  const currentTheme = themeState.theme;
654
665
  /** 是否自动开启打字动画, 后面发生变化将不会生效 */
655
- const autoStartTypingRef = react.useRef(autoStartTyping);
666
+ const autoStartTypingRef = React.useRef(autoStartTyping);
656
667
  /** 是否打过字 */
657
- const isStartedTypingRef = react.useRef(false);
668
+ const isStartedTypingRef = React.useRef(false);
658
669
  /** 当前需要打字的内容 */
659
- const charsRef = react.useRef([]);
670
+ const charsRef = React.useRef([]);
660
671
  /**
661
672
  * 打字是否已经完全结束
662
673
  * 如果打字已经完全结束,则不会再触发打字效果
663
674
  */
664
- const isWholeTypedEndRef = react.useRef(false);
665
- const charIndexRef = react.useRef(0);
675
+ const isWholeTypedEndRef = React.useRef(false);
676
+ const charIndexRef = React.useRef(0);
666
677
  /** 整个内容引用 */
667
- const wholeContentRef = react.useRef({
678
+ const wholeContentRef = React.useRef({
668
679
  thinking: {
669
680
  content: '',
670
681
  length: 0,
@@ -677,7 +688,7 @@ const MarkdownCMDInner = react.forwardRef(({ interval = 30, onEnd, onStart, onTy
677
688
  },
678
689
  allLength: 0,
679
690
  });
680
- const [, setUpdate] = react.useState(0);
691
+ const [, setUpdate] = React.useState(0);
681
692
  const triggerUpdate = () => {
682
693
  setUpdate((prev) => prev + 1);
683
694
  };
@@ -761,7 +772,7 @@ const MarkdownCMDInner = react.forwardRef(({ interval = 30, onEnd, onStart, onTy
761
772
  manual: false,
762
773
  });
763
774
  };
764
- react.useImperativeHandle(ref, () => ({
775
+ React.useImperativeHandle(ref, () => ({
765
776
  /**
766
777
  * 添加内容
767
778
  * @param content 内容 {string}
@@ -834,7 +845,7 @@ const MarkdownCMDInner = react.forwardRef(({ interval = 30, onEnd, onStart, onTy
834
845
  if (__DEV__) {
835
846
  MarkdownCMDInner.displayName = 'MarkdownCMD';
836
847
  }
837
- const MarkdownCMD = react.forwardRef((props, ref) => {
848
+ const MarkdownCMD = React.forwardRef((props, ref) => {
838
849
  const { children = '', answerType = 'answer', isInnerRender, ...reset } = props;
839
850
  if (__DEV__) {
840
851
  if (!['thinking', 'answer'].includes(answerType)) {
@@ -844,9 +855,9 @@ const MarkdownCMD = react.forwardRef((props, ref) => {
844
855
  throw new Error('Markdown组件的子元素必须是一个字符串');
845
856
  }
846
857
  }
847
- const contextValue = react.useMemo(() => ({ ...reset, answerType }), [reset, answerType]);
858
+ const contextValue = React.useMemo(() => ({ ...reset, answerType }), [reset, answerType]);
848
859
  // 分离主题相关的 props
849
- const themeProps = react.useMemo(() => ({
860
+ const themeProps = React.useMemo(() => ({
850
861
  theme: props.theme || DEFAULT_THEME,
851
862
  math: props.math,
852
863
  codeBlock: props.codeBlock,
@@ -861,9 +872,9 @@ const MarkdownCMD = react.forwardRef((props, ref) => {
861
872
  });
862
873
 
863
874
  const MarkdownInner = ({ children: _children = '', answerType, markdownRef, ...rest }) => {
864
- const cmdRef = react.useRef(null);
865
- const prefixRef = react.useRef('');
866
- const content = react.useMemo(() => {
875
+ const cmdRef = React.useRef(null);
876
+ const prefixRef = React.useRef('');
877
+ const content = React.useMemo(() => {
867
878
  if (typeof _children === 'string') {
868
879
  return _children;
869
880
  }
@@ -872,7 +883,7 @@ const MarkdownInner = ({ children: _children = '', answerType, markdownRef, ...r
872
883
  }
873
884
  return '';
874
885
  }, [_children]);
875
- react.useEffect(() => {
886
+ React.useEffect(() => {
876
887
  if (prefixRef.current !== content) {
877
888
  let newContent = '';
878
889
  if (prefixRef.current === '') {
@@ -891,7 +902,7 @@ const MarkdownInner = ({ children: _children = '', answerType, markdownRef, ...r
891
902
  prefixRef.current = content;
892
903
  }
893
904
  }, [answerType, content]);
894
- react.useImperativeHandle(markdownRef, () => ({
905
+ React.useImperativeHandle(markdownRef, () => ({
895
906
  stop: () => {
896
907
  cmdRef.current.stop();
897
908
  },
@@ -909,7 +920,7 @@ const MarkdownInner = ({ children: _children = '', answerType, markdownRef, ...r
909
920
  const { theme, math, plugins, codeBlock, ...baseProps } = rest;
910
921
  return jsxRuntime.jsx(MarkdownCMD, { ref: cmdRef, ...baseProps, isInnerRender: true });
911
922
  };
912
- const Markdown = react.forwardRef((props, ref) => {
923
+ const Markdown = React.forwardRef((props, ref) => {
913
924
  const { children = '', answerType = 'answer', ...reset } = props;
914
925
  if (__DEV__) {
915
926
  if (!['thinking', 'answer'].includes(answerType)) {
@@ -919,9 +930,9 @@ const Markdown = react.forwardRef((props, ref) => {
919
930
  throw new Error('Markdown组件的子元素必须是一个字符串');
920
931
  }
921
932
  }
922
- const contextValue = react.useMemo(() => ({ ...reset, answerType }), [reset, answerType]);
933
+ const contextValue = React.useMemo(() => ({ ...reset, answerType }), [reset, answerType]);
923
934
  // 分离主题相关的 props
924
- const themeProps = react.useMemo(() => ({
935
+ const themeProps = React.useMemo(() => ({
925
936
  theme: props.theme || DEFAULT_THEME,
926
937
  math: props.math,
927
938
  codeBlock: props.codeBlock,
@@ -930,7 +941,168 @@ const Markdown = react.forwardRef((props, ref) => {
930
941
  }), [props.theme, props.math, props.codeBlock, props.plugins, props.answerType]);
931
942
  return (jsxRuntime.jsx(MarkdownProvider, { value: contextValue, children: jsxRuntime.jsx(MarkdownThemeProvider, { value: themeProps, children: jsxRuntime.jsx(MarkdownInner, { ...props, answerType: answerType, markdownRef: ref }) }) }));
932
943
  });
933
- var Markdown$1 = react.memo(Markdown);
944
+ var Markdown$1 = React.memo(Markdown);
945
+
946
+ const IconButton = ({ icon, style, className = '', onClick, ...restProps }) => {
947
+ return jsxRuntime.jsx(Button, { icon: icon, className: `ds-icon-button ${className}`, style: style, onClick: onClick, ...restProps });
948
+ };
949
+
950
+ const ToolTip = React.forwardRef(({ title, children, position = 'top', className = '', style, showArrow = true, delay = 200 }, ref) => {
951
+ const [isVisible, setIsVisible] = React.useState(false);
952
+ const [tooltipStyle, setTooltipStyle] = React.useState({});
953
+ const triggerRef = React.useRef(null);
954
+ const tooltipRef = React.useRef(null);
955
+ const timeoutRef = React.useRef(undefined);
956
+ // 转发ref到trigger元素
957
+ React.useImperativeHandle(ref, () => triggerRef.current, []);
958
+ const showTooltip = React.useCallback(() => {
959
+ timeoutRef.current = window.setTimeout(() => {
960
+ setIsVisible(true);
961
+ }, delay);
962
+ }, [delay]);
963
+ const hideTooltip = React.useCallback(() => {
964
+ if (timeoutRef.current) {
965
+ clearTimeout(timeoutRef.current);
966
+ }
967
+ setIsVisible(false);
968
+ }, []);
969
+ const updatePosition = React.useCallback(() => {
970
+ if (!triggerRef.current || !tooltipRef.current)
971
+ return;
972
+ const triggerRect = triggerRef.current.getBoundingClientRect();
973
+ const tooltipRect = tooltipRef.current.getBoundingClientRect();
974
+ let top = 0;
975
+ let left = 0;
976
+ switch (position) {
977
+ case 'top':
978
+ top = triggerRect.top - tooltipRect.height - 8;
979
+ left = triggerRect.left + triggerRect.width / 2 - tooltipRect.width / 2;
980
+ break;
981
+ case 'bottom':
982
+ top = triggerRect.bottom + 8;
983
+ left = triggerRect.left + triggerRect.width / 2 - tooltipRect.width / 2;
984
+ break;
985
+ case 'left':
986
+ top = triggerRect.top + triggerRect.height / 2 - tooltipRect.height / 2;
987
+ left = triggerRect.left - tooltipRect.width - 8;
988
+ break;
989
+ case 'right':
990
+ top = triggerRect.top + triggerRect.height / 2 - tooltipRect.height / 2;
991
+ left = triggerRect.right + 8;
992
+ break;
993
+ }
994
+ setTooltipStyle({
995
+ position: 'fixed',
996
+ top: `${top}px`,
997
+ left: `${left}px`,
998
+ zIndex: 1000,
999
+ });
1000
+ }, [position]);
1001
+ React.useEffect(() => {
1002
+ if (isVisible) {
1003
+ updatePosition();
1004
+ }
1005
+ }, [isVisible, position, updatePosition]);
1006
+ React.useEffect(() => {
1007
+ const handleScroll = () => {
1008
+ if (isVisible) {
1009
+ updatePosition();
1010
+ }
1011
+ };
1012
+ const handleResize = () => {
1013
+ if (isVisible) {
1014
+ updatePosition();
1015
+ }
1016
+ };
1017
+ window.addEventListener('scroll', handleScroll, true);
1018
+ window.addEventListener('resize', handleResize);
1019
+ return () => {
1020
+ window.removeEventListener('scroll', handleScroll, true);
1021
+ window.removeEventListener('resize', handleResize);
1022
+ };
1023
+ }, [isVisible, updatePosition]);
1024
+ React.useEffect(() => {
1025
+ return () => {
1026
+ if (timeoutRef.current) {
1027
+ clearTimeout(timeoutRef.current);
1028
+ }
1029
+ };
1030
+ }, []);
1031
+ const renderTooltip = () => {
1032
+ if (!isVisible)
1033
+ return null;
1034
+ 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}`) })] }));
1035
+ return reactDom.createPortal(tooltipElement, document.body);
1036
+ };
1037
+ // 合并原有的事件处理器
1038
+ const handleMouseEnter = React.useCallback((e) => {
1039
+ e.stopPropagation(); // 阻止事件冒泡
1040
+ showTooltip();
1041
+ // 只在子元素有onMouseEnter时才调用
1042
+ const props = children.props;
1043
+ if (props.onMouseEnter) {
1044
+ props.onMouseEnter(e);
1045
+ }
1046
+ }, [children.props, showTooltip]);
1047
+ const handleMouseLeave = React.useCallback((e) => {
1048
+ e.stopPropagation(); // 阻止事件冒泡
1049
+ hideTooltip();
1050
+ // 只在子元素有onMouseLeave时才调用
1051
+ const props = children.props;
1052
+ if (props.onMouseLeave) {
1053
+ props.onMouseLeave(e);
1054
+ }
1055
+ }, [children.props, hideTooltip]);
1056
+ const handleFocus = React.useCallback((e) => {
1057
+ e.stopPropagation(); // 阻止事件冒泡
1058
+ showTooltip();
1059
+ // 只在子元素有onFocus时才调用
1060
+ const props = children.props;
1061
+ if (props.onFocus) {
1062
+ props.onFocus(e);
1063
+ }
1064
+ }, [children.props, showTooltip]);
1065
+ const handleBlur = React.useCallback((e) => {
1066
+ e.stopPropagation(); // 阻止事件冒泡
1067
+ hideTooltip();
1068
+ // 只在子元素有onBlur时才调用
1069
+ const props = children.props;
1070
+ if (props.onBlur) {
1071
+ props.onBlur(e);
1072
+ }
1073
+ }, [children.props, hideTooltip]);
1074
+ // 处理onClick事件
1075
+ const handleClick = React.useCallback((e) => {
1076
+ // 调用原有的onClick
1077
+ const props = children.props;
1078
+ if (props.onClick) {
1079
+ props.onClick(e);
1080
+ }
1081
+ }, [children.props]);
1082
+ // 检查组件是否支持ref
1083
+ const isForwardRef = React.isValidElement(children) &&
1084
+ typeof children.type === 'function' &&
1085
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1086
+ children.type.$$typeof === Symbol.for('react.forward_ref');
1087
+ // 如果组件不支持ref,使用包装div的方式
1088
+ if (!isForwardRef && typeof children.type === 'function') {
1089
+ 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()] }));
1090
+ }
1091
+ // 使用 cloneElement 直接给子元素添加事件监听器和ref
1092
+ const enhancedChild = React.cloneElement(children, {
1093
+ ref: triggerRef,
1094
+ className: classNames(children.props.className, className),
1095
+ style: { ...children.props.style, ...style },
1096
+ onMouseEnter: handleMouseEnter,
1097
+ onMouseLeave: handleMouseLeave,
1098
+ onFocus: handleFocus,
1099
+ onBlur: handleBlur,
1100
+ onClick: handleClick,
1101
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1102
+ });
1103
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [enhancedChild, renderTooltip()] }));
1104
+ });
1105
+ ToolTip.displayName = 'ToolTip';
934
1106
 
935
1107
  /* eslint-disable react-refresh/only-export-components */
936
1108
 
@@ -940,8 +1112,11 @@ exports.CodeBlockWrap = CodeBlockWrap;
940
1112
  exports.ConfigProvider = ConfigProvider;
941
1113
  exports.CopyButton = CopyButton;
942
1114
  exports.DownloadButton = DownloadButton;
1115
+ exports.HighlightCode = HighlightCode;
1116
+ exports.IconButton = IconButton;
943
1117
  exports.Markdown = Markdown$1;
944
1118
  exports.MarkdownCMD = MarkdownCMD;
1119
+ exports.ToolTip = ToolTip;
945
1120
  exports.default = Markdown$1;
946
1121
  exports.useConfig = useConfig;
947
1122
  exports.useLocale = useLocale;