@agentscope-ai/chat 1.1.39 → 1.1.41-beta.1764749089549
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/bin/starter_webui.zip +0 -0
- package/components/AgentScopeRuntimeWebUI/core/AgentScopeRuntime/Response/Builder.tsx +8 -4
- package/components/ImageGenerator/index.tsx +1 -1
- package/components/Markdown/Markdown.tsx +105 -0
- package/components/Markdown/{Markdown/defaultComponents → core/components}/CodeBlock.tsx +1 -1
- package/components/Markdown/core/components/Null.tsx +1 -0
- package/components/Markdown/core/components/Raw.tsx +18 -0
- package/components/Markdown/{Markdown → core}/hooks/useCitationsData.tsx +3 -7
- package/components/Markdown/core/hooks/useCursorContent.tsx +15 -0
- package/components/Markdown/{Markdown/hooks/useTyping.ts → core/hooks/useTyping.tsx} +4 -1
- package/components/Markdown/core/index.tsx +18 -0
- package/components/Markdown/{plugins → core/plugins}/citations/CitationComponent.tsx +5 -3
- package/components/Markdown/{plugins → core/plugins}/citations/index.tsx +3 -4
- package/components/Markdown/{plugins → core/plugins}/cursor/Underline.tsx +1 -1
- package/components/Markdown/{plugins → core/plugins}/cursor/index.tsx +8 -8
- package/components/Markdown/demo/cursor.tsx +2 -3
- package/components/Markdown/index.en-US.md +1 -2
- package/components/Markdown/index.tsx +6 -0
- package/components/Markdown/index.zh-CN.md +1 -2
- package/components/Markdown/{Markdown/style.ts → styles.ts} +12 -21
- package/components/Markdown/types.tsx +94 -0
- package/components/index.ts +1 -3
- package/lib/AgentScopeRuntimeWebUI/core/AgentScopeRuntime/Response/Builder.js +5 -3
- package/lib/ImageGenerator/index.js +1 -1
- package/lib/Markdown/Markdown.d.ts +4 -0
- package/lib/Markdown/Markdown.js +110 -0
- package/lib/Markdown/core/components/Null.d.ts +2 -0
- package/lib/Markdown/core/components/Null.js +3 -0
- package/lib/Markdown/core/components/Raw.d.ts +8 -0
- package/lib/Markdown/core/components/Raw.js +13 -0
- package/lib/Markdown/core/hooks/useCitationsData.d.ts +6 -0
- package/lib/Markdown/{Markdown → core}/hooks/useCitationsData.js +1 -1
- package/lib/Markdown/core/hooks/useCursorContent.d.ts +4 -0
- package/lib/Markdown/core/hooks/useCursorContent.js +14 -0
- package/lib/Markdown/core/hooks/useTyping.d.ts +5 -0
- package/lib/Markdown/{Markdown → core}/hooks/useTyping.js +3 -2
- package/lib/Markdown/core/index.d.ts +2 -0
- package/lib/Markdown/{Markdown/hooks/useAnimation.js → core/index.js} +23 -23
- package/lib/Markdown/{plugins → core/plugins}/citations/CitationComponent.js +5 -5
- package/lib/Markdown/{plugins → core/plugins}/citations/index.d.ts +1 -2
- package/lib/Markdown/{plugins → core/plugins}/citations/index.js +1 -1
- package/lib/Markdown/{plugins → core/plugins}/cursor/Dot.js +1 -1
- package/lib/Markdown/{plugins → core/plugins}/cursor/Underline.js +1 -1
- package/lib/Markdown/{plugins → core/plugins}/cursor/index.js +4 -4
- package/lib/Markdown/index.d.ts +2 -1
- package/lib/Markdown/styles.js +32 -0
- package/lib/Markdown/types.d.ts +78 -0
- package/lib/index.d.ts +0 -2
- package/lib/index.js +0 -2
- package/package.json +7 -31
- package/components/AGUI/components/HelpModal/icons.tsx +0 -68
- package/components/AGUI/components/HelpModal/index.tsx +0 -1
- package/components/AGUI/components/HelpModal/modal.tsx +0 -101
- package/components/AGUI/components/chat/Button.tsx +0 -18
- package/components/AGUI/components/chat/Chat.tsx +0 -780
- package/components/AGUI/components/chat/ChatContext.tsx +0 -248
- package/components/AGUI/components/chat/CodeBlock.tsx +0 -406
- package/components/AGUI/components/chat/Header.tsx +0 -22
- package/components/AGUI/components/chat/Icons.tsx +0 -237
- package/components/AGUI/components/chat/ImageUploadQueue.tsx +0 -77
- package/components/AGUI/components/chat/Input.tsx +0 -24
- package/components/AGUI/components/chat/Markdown.tsx +0 -134
- package/components/AGUI/components/chat/Messages.tsx +0 -259
- package/components/AGUI/components/chat/Modal.tsx +0 -133
- package/components/AGUI/components/chat/Popup.tsx +0 -57
- package/components/AGUI/components/chat/PoweredByTag.tsx +0 -29
- package/components/AGUI/components/chat/Sidebar.tsx +0 -74
- package/components/AGUI/components/chat/Suggestion.tsx +0 -132
- package/components/AGUI/components/chat/Suggestions.tsx +0 -20
- package/components/AGUI/components/chat/Textarea.tsx +0 -61
- package/components/AGUI/components/chat/Window.tsx +0 -152
- package/components/AGUI/components/chat/index.tsx +0 -11
- package/components/AGUI/components/chat/messages/AssistantMessage.tsx +0 -69
- package/components/AGUI/components/chat/messages/RenderActionExecutionMessage.tsx +0 -129
- package/components/AGUI/components/chat/messages/RenderAgentStateMessage.tsx +0 -116
- package/components/AGUI/components/chat/messages/RenderImageMessage.tsx +0 -64
- package/components/AGUI/components/chat/messages/RenderResultMessage.tsx +0 -26
- package/components/AGUI/components/chat/messages/RenderTextMessage.tsx +0 -51
- package/components/AGUI/components/chat/messages/UserMessage.tsx +0 -10
- package/components/AGUI/components/chat/props.ts +0 -186
- package/components/AGUI/components/index.ts +0 -1
- package/components/AGUI/context/index.ts +0 -1
- package/components/AGUI/hooks/index.ts +0 -1
- package/components/AGUI/hooks/use-copilot-chat-suggestions.tsx +0 -122
- package/components/AGUI/hooks/use-copy-to-clipboard.tsx +0 -29
- package/components/AGUI/hooks/use-dark-mode.ts +0 -10
- package/components/AGUI/hooks/use-push-to-talk.tsx +0 -166
- package/components/AGUI/index.tsx +0 -4
- package/components/AGUI/lib/utils.test.ts +0 -7
- package/components/AGUI/lib/utils.ts +0 -27
- package/components/AGUI/styles.css +0 -0
- package/components/AGUI/types/css.ts +0 -0
- package/components/AGUI/types/index.ts +0 -1
- package/components/AGUI/types/suggestions.ts +0 -6
- package/components/Markdown/Markdown/AnimationNode.tsx +0 -89
- package/components/Markdown/Markdown/Markdown.tsx +0 -61
- package/components/Markdown/Markdown/core/Parser.ts +0 -52
- package/components/Markdown/Markdown/core/Renderer.ts +0 -121
- package/components/Markdown/Markdown/core/index.ts +0 -4
- package/components/Markdown/Markdown/hooks/index.ts +0 -4
- package/components/Markdown/Markdown/hooks/useAnimation.tsx +0 -27
- package/components/Markdown/Markdown/hooks/useStreaming.ts +0 -503
- package/components/Markdown/Markdown/index.tsx +0 -198
- package/components/Markdown/Markdown/interface.ts +0 -217
- package/components/Markdown/demo/typing.tsx +0 -82
- package/components/Markdown/index.ts +0 -1
- package/components/Markdown/plugins/latex/index.ts +0 -109
- package/components/Markdown/plugins/type.ts +0 -71
- package/lib/AGUI/components/HelpModal/icons.d.ts +0 -5
- package/lib/AGUI/components/HelpModal/icons.js +0 -84
- package/lib/AGUI/components/HelpModal/index.d.ts +0 -1
- package/lib/AGUI/components/HelpModal/index.js +0 -1
- package/lib/AGUI/components/HelpModal/modal.d.ts +0 -1
- package/lib/AGUI/components/HelpModal/modal.js +0 -104
- package/lib/AGUI/components/chat/Button.d.ts +0 -2
- package/lib/AGUI/components/chat/Button.js +0 -27
- package/lib/AGUI/components/chat/Chat.d.ts +0 -242
- package/lib/AGUI/components/chat/Chat.js +0 -634
- package/lib/AGUI/components/chat/ChatContext.d.ts +0 -142
- package/lib/AGUI/components/chat/ChatContext.js +0 -75
- package/lib/AGUI/components/chat/CodeBlock.d.ts +0 -12
- package/lib/AGUI/components/chat/CodeBlock.js +0 -398
- package/lib/AGUI/components/chat/Header.d.ts +0 -2
- package/lib/AGUI/components/chat/Header.js +0 -28
- package/lib/AGUI/components/chat/Icons.d.ts +0 -16
- package/lib/AGUI/components/chat/Icons.js +0 -247
- package/lib/AGUI/components/chat/ImageUploadQueue.d.ts +0 -11
- package/lib/AGUI/components/chat/ImageUploadQueue.js +0 -65
- package/lib/AGUI/components/chat/Input.d.ts +0 -2
- package/lib/AGUI/components/chat/Input.js +0 -30
- package/lib/AGUI/components/chat/Markdown.d.ts +0 -7
- package/lib/AGUI/components/chat/Markdown.js +0 -187
- package/lib/AGUI/components/chat/Messages.d.ts +0 -7
- package/lib/AGUI/components/chat/Messages.js +0 -242
- package/lib/AGUI/components/chat/Modal.d.ts +0 -43
- package/lib/AGUI/components/chat/Modal.js +0 -113
- package/lib/AGUI/components/chat/Popup.d.ts +0 -49
- package/lib/AGUI/components/chat/Popup.js +0 -64
- package/lib/AGUI/components/chat/PoweredByTag.d.ts +0 -3
- package/lib/AGUI/components/chat/PoweredByTag.js +0 -27
- package/lib/AGUI/components/chat/Sidebar.d.ts +0 -2
- package/lib/AGUI/components/chat/Sidebar.js +0 -85
- package/lib/AGUI/components/chat/Suggestion.d.ts +0 -16
- package/lib/AGUI/components/chat/Suggestion.js +0 -146
- package/lib/AGUI/components/chat/Suggestions.d.ts +0 -2
- package/lib/AGUI/components/chat/Suggestions.js +0 -21
- package/lib/AGUI/components/chat/Textarea.d.ts +0 -11
- package/lib/AGUI/components/chat/Textarea.js +0 -60
- package/lib/AGUI/components/chat/Window.d.ts +0 -2
- package/lib/AGUI/components/chat/Window.js +0 -115
- package/lib/AGUI/components/chat/index.d.ts +0 -11
- package/lib/AGUI/components/chat/index.js +0 -11
- package/lib/AGUI/components/chat/messages/AssistantMessage.d.ts +0 -2
- package/lib/AGUI/components/chat/messages/AssistantMessage.js +0 -56
- package/lib/AGUI/components/chat/messages/RenderActionExecutionMessage.d.ts +0 -2
- package/lib/AGUI/components/chat/messages/RenderActionExecutionMessage.js +0 -114
- package/lib/AGUI/components/chat/messages/RenderAgentStateMessage.d.ts +0 -2
- package/lib/AGUI/components/chat/messages/RenderAgentStateMessage.js +0 -97
- package/lib/AGUI/components/chat/messages/RenderImageMessage.d.ts +0 -2
- package/lib/AGUI/components/chat/messages/RenderImageMessage.js +0 -61
- package/lib/AGUI/components/chat/messages/RenderResultMessage.d.ts +0 -2
- package/lib/AGUI/components/chat/messages/RenderResultMessage.js +0 -27
- package/lib/AGUI/components/chat/messages/RenderTextMessage.d.ts +0 -2
- package/lib/AGUI/components/chat/messages/RenderTextMessage.js +0 -47
- package/lib/AGUI/components/chat/messages/UserMessage.d.ts +0 -2
- package/lib/AGUI/components/chat/messages/UserMessage.js +0 -9
- package/lib/AGUI/components/chat/props.d.ts +0 -157
- package/lib/AGUI/components/index.d.ts +0 -1
- package/lib/AGUI/components/index.js +0 -1
- package/lib/AGUI/context/index.d.ts +0 -1
- package/lib/AGUI/context/index.js +0 -1
- package/lib/AGUI/hooks/index.d.ts +0 -1
- package/lib/AGUI/hooks/index.js +0 -1
- package/lib/AGUI/hooks/use-copilot-chat-suggestions.d.ts +0 -87
- package/lib/AGUI/hooks/use-copilot-chat-suggestions.js +0 -95
- package/lib/AGUI/hooks/use-copy-to-clipboard.d.ts +0 -7
- package/lib/AGUI/hooks/use-copy-to-clipboard.js +0 -34
- package/lib/AGUI/hooks/use-dark-mode.d.ts +0 -1
- package/lib/AGUI/hooks/use-dark-mode.js +0 -4
- package/lib/AGUI/hooks/use-push-to-talk.d.ts +0 -16
- package/lib/AGUI/hooks/use-push-to-talk.js +0 -260
- package/lib/AGUI/index.d.ts +0 -4
- package/lib/AGUI/index.js +0 -4
- package/lib/AGUI/lib/utils.d.ts +0 -2
- package/lib/AGUI/lib/utils.js +0 -52
- package/lib/AGUI/styles.css +0 -0
- package/lib/AGUI/types/css.d.ts +0 -0
- package/lib/AGUI/types/css.js +0 -0
- package/lib/AGUI/types/index.d.ts +0 -1
- package/lib/AGUI/types/index.js +0 -1
- package/lib/AGUI/types/suggestions.d.ts +0 -6
- package/lib/AGUI/types/suggestions.js +0 -1
- package/lib/Markdown/Markdown/AnimationNode.d.ts +0 -20
- package/lib/Markdown/Markdown/AnimationNode.js +0 -84
- package/lib/Markdown/Markdown/Markdown.d.ts +0 -4
- package/lib/Markdown/Markdown/Markdown.js +0 -58
- package/lib/Markdown/Markdown/core/Parser.d.ts +0 -16
- package/lib/Markdown/Markdown/core/Parser.js +0 -65
- package/lib/Markdown/Markdown/core/Renderer.d.ts +0 -24
- package/lib/Markdown/Markdown/core/Renderer.js +0 -137
- package/lib/Markdown/Markdown/core/index.d.ts +0 -3
- package/lib/Markdown/Markdown/core/index.js +0 -3
- package/lib/Markdown/Markdown/hooks/index.d.ts +0 -3
- package/lib/Markdown/Markdown/hooks/index.js +0 -3
- package/lib/Markdown/Markdown/hooks/useAnimation.d.ts +0 -4
- package/lib/Markdown/Markdown/hooks/useCitationsData.d.ts +0 -7
- package/lib/Markdown/Markdown/hooks/useStreaming.d.ts +0 -3
- package/lib/Markdown/Markdown/hooks/useStreaming.js +0 -521
- package/lib/Markdown/Markdown/hooks/useTyping.d.ts +0 -4
- package/lib/Markdown/Markdown/index.d.ts +0 -84
- package/lib/Markdown/Markdown/index.js +0 -161
- package/lib/Markdown/Markdown/interface.d.ts +0 -203
- package/lib/Markdown/Markdown/interface.js +0 -1
- package/lib/Markdown/Markdown/style.js +0 -32
- package/lib/Markdown/plugins/latex/index.d.ts +0 -9
- package/lib/Markdown/plugins/latex/index.js +0 -97
- package/lib/Markdown/plugins/type.d.ts +0 -60
- package/lib/Markdown/plugins/type.js +0 -1
- /package/components/Markdown/{Markdown/defaultComponents/DisabledImage.tsx → core/components/DisableImage.tsx} +0 -0
- /package/components/Markdown/{Markdown/defaultComponents → core/components}/Media.tsx +0 -0
- /package/components/Markdown/{plugins → core/plugins}/cursor/Dot.tsx +0 -0
- /package/lib/Markdown/{Markdown/defaultComponents → core/components}/CodeBlock.d.ts +0 -0
- /package/lib/Markdown/{Markdown/defaultComponents → core/components}/CodeBlock.js +0 -0
- /package/lib/Markdown/{Markdown/defaultComponents/DisabledImage.d.ts → core/components/DisableImage.d.ts} +0 -0
- /package/lib/Markdown/{Markdown/defaultComponents/DisabledImage.js → core/components/DisableImage.js} +0 -0
- /package/lib/Markdown/{Markdown/defaultComponents → core/components}/Media.d.ts +0 -0
- /package/lib/Markdown/{Markdown/defaultComponents → core/components}/Media.js +0 -0
- /package/lib/Markdown/{plugins → core/plugins}/citations/CitationComponent.d.ts +0 -0
- /package/lib/Markdown/{plugins → core/plugins}/cursor/Dot.d.ts +0 -0
- /package/lib/Markdown/{plugins → core/plugins}/cursor/Underline.d.ts +0 -0
- /package/lib/Markdown/{plugins → core/plugins}/cursor/index.d.ts +0 -0
- /package/lib/Markdown/{Markdown/style.d.ts → styles.d.ts} +0 -0
- /package/lib/{AGUI/components/chat/props.js → Markdown/types.js} +0 -0
|
@@ -1,503 +0,0 @@
|
|
|
1
|
-
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
2
|
-
import { MarkdownProps } from '../interface';
|
|
3
|
-
|
|
4
|
-
enum TokenType {
|
|
5
|
-
Text = 0,
|
|
6
|
-
Link = 1,
|
|
7
|
-
Image = 2,
|
|
8
|
-
Heading = 3,
|
|
9
|
-
MaybeEmphasis = 4,
|
|
10
|
-
Emphasis = 5,
|
|
11
|
-
Strong = 6,
|
|
12
|
-
XML = 7,
|
|
13
|
-
MaybeCode = 8,
|
|
14
|
-
Code = 9,
|
|
15
|
-
MaybeHr = 10,
|
|
16
|
-
MaybeList = 11,
|
|
17
|
-
MaybeInlineMath = 12,
|
|
18
|
-
InlineMath = 13,
|
|
19
|
-
MaybeBlockMath = 14,
|
|
20
|
-
BlockMath = 15,
|
|
21
|
-
MaybeBackslashMath = 16,
|
|
22
|
-
Word = 17,
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const Markdown_Symbols = {
|
|
26
|
-
emphasis: ['*', '_'],
|
|
27
|
-
code: ['`'],
|
|
28
|
-
list: ['-', '+', '*'],
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
// 辅助函数:判断是否是英文字母
|
|
32
|
-
const isEnglishLetter = (char: string): boolean => {
|
|
33
|
-
const code = char.charCodeAt(0);
|
|
34
|
-
return (code >= 65 && code <= 90) || (code >= 97 && code <= 122); // A-Z or a-z
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
// 辅助函数:判断是否是单词的一部分(字母、数字、连字符、撇号)
|
|
38
|
-
const isWordChar = (char: string): boolean => {
|
|
39
|
-
const code = char.charCodeAt(0);
|
|
40
|
-
return (
|
|
41
|
-
(code >= 65 && code <= 90) || // A-Z
|
|
42
|
-
(code >= 97 && code <= 122) || // a-z
|
|
43
|
-
(code >= 48 && code <= 57) || // 0-9
|
|
44
|
-
char === '-' || // 连字符 (well-known)
|
|
45
|
-
char === "'" // 撇号 (don't)
|
|
46
|
-
);
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
// 辅助函数:判断是否是单词分隔符
|
|
50
|
-
const isWordSeparator = (char: string): boolean => {
|
|
51
|
-
return (
|
|
52
|
-
char === ' ' ||
|
|
53
|
-
char === '\n' ||
|
|
54
|
-
char === '\t' ||
|
|
55
|
-
char === ',' ||
|
|
56
|
-
char === '.' ||
|
|
57
|
-
char === '!' ||
|
|
58
|
-
char === '?' ||
|
|
59
|
-
char === ';' ||
|
|
60
|
-
char === ':' ||
|
|
61
|
-
char === ')' ||
|
|
62
|
-
char === ']' ||
|
|
63
|
-
char === '}' ||
|
|
64
|
-
char === '"' ||
|
|
65
|
-
char === "'" ||
|
|
66
|
-
char === '>' ||
|
|
67
|
-
char === '<'
|
|
68
|
-
);
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
const STREAM_BUFFER_INIT = {
|
|
72
|
-
processedLength: 0,
|
|
73
|
-
rawStream: '',
|
|
74
|
-
pending: '',
|
|
75
|
-
token: TokenType.Text,
|
|
76
|
-
tokens: [TokenType.Text],
|
|
77
|
-
headingLevel: 0,
|
|
78
|
-
emphasisCount: 0,
|
|
79
|
-
backtickCount: 0,
|
|
80
|
-
dollarCount: 0,
|
|
81
|
-
mathDelimiter: '' as '$' | '$$' | '\\(' | '\\[' | '',
|
|
82
|
-
blockMathEnding: false, // 标记是否遇到了结束的 $$
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
const useStreaming = (input: string, config?: MarkdownProps['streaming'], cursor?: MarkdownProps['cursor']) => {
|
|
86
|
-
const { hasNextChunk = false, enableWordCaching = false, enableMathCaching = true } = config || {};
|
|
87
|
-
|
|
88
|
-
const [output, setOutput] = useState('');
|
|
89
|
-
const streamBuffer = useRef({ ...STREAM_BUFFER_INIT });
|
|
90
|
-
|
|
91
|
-
const pushToken = useCallback((type: TokenType) => {
|
|
92
|
-
streamBuffer.current.tokens = [...streamBuffer.current.tokens, type];
|
|
93
|
-
streamBuffer.current.token = type;
|
|
94
|
-
}, []);
|
|
95
|
-
|
|
96
|
-
const popToken = useCallback(() => {
|
|
97
|
-
const { tokens } = streamBuffer.current;
|
|
98
|
-
if (tokens.length <= 1) return;
|
|
99
|
-
|
|
100
|
-
const newTokens = [...tokens.slice(0, -1)];
|
|
101
|
-
streamBuffer.current.tokens = newTokens;
|
|
102
|
-
streamBuffer.current.token = newTokens[newTokens.length - 1];
|
|
103
|
-
}, []);
|
|
104
|
-
|
|
105
|
-
const flushOutput = (needPopToken = true) => {
|
|
106
|
-
if (needPopToken) popToken();
|
|
107
|
-
|
|
108
|
-
streamBuffer.current.pending = '';
|
|
109
|
-
streamBuffer.current.blockMathEnding = false;
|
|
110
|
-
const renderText = streamBuffer.current.rawStream;
|
|
111
|
-
if (renderText) {
|
|
112
|
-
setOutput(renderText);
|
|
113
|
-
}
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
const handleChunk = (chunk: string) => {
|
|
117
|
-
const buffer = streamBuffer.current;
|
|
118
|
-
for (const char of chunk) {
|
|
119
|
-
buffer.rawStream += char;
|
|
120
|
-
buffer.pending += char;
|
|
121
|
-
|
|
122
|
-
const { token, pending, tokens, emphasisCount } = buffer;
|
|
123
|
-
switch (token) {
|
|
124
|
-
case TokenType.Image: {
|
|
125
|
-
/**
|
|
126
|
-
* \![
|
|
127
|
-
* ^
|
|
128
|
-
*/
|
|
129
|
-
const isInvalidStart = pending.indexOf('![') === -1;
|
|
130
|
-
/**
|
|
131
|
-
* \![image]()
|
|
132
|
-
* ^
|
|
133
|
-
*/
|
|
134
|
-
const isImageEnd = char === ')' || char === '\n';
|
|
135
|
-
if (isInvalidStart || isImageEnd) {
|
|
136
|
-
if (tokens[tokens.length - 2] === TokenType.Link) {
|
|
137
|
-
popToken();
|
|
138
|
-
} else {
|
|
139
|
-
flushOutput();
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
break;
|
|
143
|
-
}
|
|
144
|
-
case TokenType.Link: {
|
|
145
|
-
// not support link reference definitions, [foo]: /url "title" \n[foo]
|
|
146
|
-
const isReferenceLink = pending.endsWith(']:');
|
|
147
|
-
const isLinkEnd = char === ')' || char === '\n';
|
|
148
|
-
const isImageInLink = char === '!';
|
|
149
|
-
if (isImageInLink) {
|
|
150
|
-
pushToken(TokenType.Image);
|
|
151
|
-
} else if (isLinkEnd || isReferenceLink) {
|
|
152
|
-
flushOutput();
|
|
153
|
-
}
|
|
154
|
-
break;
|
|
155
|
-
}
|
|
156
|
-
case TokenType.Heading: {
|
|
157
|
-
/**
|
|
158
|
-
* # token / ## token / #####token
|
|
159
|
-
* ^ ^ ^
|
|
160
|
-
*/
|
|
161
|
-
buffer.headingLevel++;
|
|
162
|
-
|
|
163
|
-
const shouldFlushOutput = char !== '#' || buffer.headingLevel >= 6;
|
|
164
|
-
if (shouldFlushOutput) {
|
|
165
|
-
flushOutput();
|
|
166
|
-
buffer.headingLevel = 0;
|
|
167
|
-
}
|
|
168
|
-
break;
|
|
169
|
-
}
|
|
170
|
-
case TokenType.MaybeEmphasis: {
|
|
171
|
-
/**
|
|
172
|
-
* /* / *\/n
|
|
173
|
-
^ ^
|
|
174
|
-
*/
|
|
175
|
-
const shouldFlushOutput = char === ' ' || char === '\n';
|
|
176
|
-
if (shouldFlushOutput) {
|
|
177
|
-
flushOutput();
|
|
178
|
-
} else if (Markdown_Symbols.emphasis.includes(char)) {
|
|
179
|
-
buffer.emphasisCount++;
|
|
180
|
-
} else {
|
|
181
|
-
popToken();
|
|
182
|
-
if (emphasisCount === 1) {
|
|
183
|
-
/**
|
|
184
|
-
* _token_ / *token*
|
|
185
|
-
* ^ ^
|
|
186
|
-
*/
|
|
187
|
-
pushToken(TokenType.Emphasis);
|
|
188
|
-
} else if (emphasisCount === 2) {
|
|
189
|
-
/**
|
|
190
|
-
* __token__ / **token**
|
|
191
|
-
* ^ ^
|
|
192
|
-
*/
|
|
193
|
-
pushToken(TokenType.Strong);
|
|
194
|
-
} else if (emphasisCount === 3) {
|
|
195
|
-
/**
|
|
196
|
-
* ___token___ / ***token***
|
|
197
|
-
* ^ ^
|
|
198
|
-
*/
|
|
199
|
-
pushToken(TokenType.Emphasis);
|
|
200
|
-
pushToken(TokenType.Strong);
|
|
201
|
-
} else {
|
|
202
|
-
// no more than 3
|
|
203
|
-
buffer.emphasisCount = 0;
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
break;
|
|
208
|
-
}
|
|
209
|
-
case TokenType.Strong: {
|
|
210
|
-
/**
|
|
211
|
-
* __token__ / **token**
|
|
212
|
-
* ^ ^
|
|
213
|
-
*/
|
|
214
|
-
if (char === '\n') {
|
|
215
|
-
flushOutput();
|
|
216
|
-
} else if (pending.endsWith('**') || pending.endsWith('__')) {
|
|
217
|
-
if (tokens[tokens.length - 2] === TokenType.Emphasis) {
|
|
218
|
-
popToken();
|
|
219
|
-
} else {
|
|
220
|
-
flushOutput();
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
break;
|
|
225
|
-
}
|
|
226
|
-
case TokenType.Emphasis: {
|
|
227
|
-
/**
|
|
228
|
-
* _token_ / *token*
|
|
229
|
-
* ^ ^
|
|
230
|
-
*/
|
|
231
|
-
if (char === '\n') {
|
|
232
|
-
flushOutput();
|
|
233
|
-
buffer.emphasisCount = 0;
|
|
234
|
-
} else if (Markdown_Symbols.emphasis.includes(char)) {
|
|
235
|
-
flushOutput();
|
|
236
|
-
buffer.emphasisCount = 0;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
break;
|
|
240
|
-
}
|
|
241
|
-
case TokenType.XML: {
|
|
242
|
-
/**
|
|
243
|
-
* <XML /> /<XML></XML>
|
|
244
|
-
* ^ ^
|
|
245
|
-
*/
|
|
246
|
-
const shouldFlushOutput = char === '>' || pending === '< ' || char === '\n';
|
|
247
|
-
if (shouldFlushOutput) {
|
|
248
|
-
flushOutput();
|
|
249
|
-
continue;
|
|
250
|
-
}
|
|
251
|
-
break;
|
|
252
|
-
}
|
|
253
|
-
case TokenType.MaybeCode: {
|
|
254
|
-
if (char === '`') {
|
|
255
|
-
buffer.backtickCount++;
|
|
256
|
-
} else {
|
|
257
|
-
if (buffer.backtickCount > 2) {
|
|
258
|
-
/**
|
|
259
|
-
* ```
|
|
260
|
-
* ^
|
|
261
|
-
*/
|
|
262
|
-
flushOutput();
|
|
263
|
-
buffer.backtickCount = 0;
|
|
264
|
-
} else {
|
|
265
|
-
/**
|
|
266
|
-
* ``
|
|
267
|
-
* ^
|
|
268
|
-
*/
|
|
269
|
-
popToken();
|
|
270
|
-
pushToken(TokenType.Code);
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
break;
|
|
274
|
-
}
|
|
275
|
-
case TokenType.Code: {
|
|
276
|
-
if (char === '`') {
|
|
277
|
-
buffer.backtickCount--;
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
if (buffer.backtickCount === 0) {
|
|
281
|
-
flushOutput();
|
|
282
|
-
buffer.backtickCount = 0;
|
|
283
|
-
}
|
|
284
|
-
break;
|
|
285
|
-
}
|
|
286
|
-
case TokenType.MaybeHr: {
|
|
287
|
-
if (char !== '-' && char !== '=') {
|
|
288
|
-
flushOutput();
|
|
289
|
-
}
|
|
290
|
-
break;
|
|
291
|
-
}
|
|
292
|
-
case TokenType.MaybeList: {
|
|
293
|
-
if (char !== ' ') {
|
|
294
|
-
flushOutput();
|
|
295
|
-
}
|
|
296
|
-
break;
|
|
297
|
-
}
|
|
298
|
-
case TokenType.MaybeInlineMath: {
|
|
299
|
-
/**
|
|
300
|
-
* $ / $$
|
|
301
|
-
* ^ ^
|
|
302
|
-
*/
|
|
303
|
-
if (char === '$') {
|
|
304
|
-
buffer.dollarCount++;
|
|
305
|
-
if (buffer.dollarCount === 2) {
|
|
306
|
-
// $$ 块级公式
|
|
307
|
-
popToken();
|
|
308
|
-
pushToken(TokenType.MaybeBlockMath);
|
|
309
|
-
buffer.mathDelimiter = '$$';
|
|
310
|
-
}
|
|
311
|
-
} else if (char === '\n') {
|
|
312
|
-
// $ 后跟换行,不是有效的公式
|
|
313
|
-
flushOutput();
|
|
314
|
-
buffer.dollarCount = 0;
|
|
315
|
-
buffer.mathDelimiter = '';
|
|
316
|
-
} else {
|
|
317
|
-
// 确认为行内公式
|
|
318
|
-
popToken();
|
|
319
|
-
pushToken(TokenType.InlineMath);
|
|
320
|
-
buffer.mathDelimiter = '$';
|
|
321
|
-
}
|
|
322
|
-
break;
|
|
323
|
-
}
|
|
324
|
-
case TokenType.InlineMath: {
|
|
325
|
-
/**
|
|
326
|
-
* $x^2$ / \(x^2\)
|
|
327
|
-
* ^ ^
|
|
328
|
-
*/
|
|
329
|
-
if (buffer.mathDelimiter === '$') {
|
|
330
|
-
if (char === '$') {
|
|
331
|
-
flushOutput();
|
|
332
|
-
buffer.dollarCount = 0;
|
|
333
|
-
buffer.mathDelimiter = '';
|
|
334
|
-
} else if (char === '\n') {
|
|
335
|
-
// 行内公式不应跨行
|
|
336
|
-
flushOutput();
|
|
337
|
-
buffer.dollarCount = 0;
|
|
338
|
-
buffer.mathDelimiter = '';
|
|
339
|
-
}
|
|
340
|
-
} else if (buffer.mathDelimiter === '\\(') {
|
|
341
|
-
if (pending.endsWith('\\)')) {
|
|
342
|
-
flushOutput();
|
|
343
|
-
buffer.mathDelimiter = '';
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
break;
|
|
347
|
-
}
|
|
348
|
-
case TokenType.MaybeBlockMath: {
|
|
349
|
-
/**
|
|
350
|
-
* $$
|
|
351
|
-
* ^
|
|
352
|
-
*/
|
|
353
|
-
if (char !== '$') {
|
|
354
|
-
// $$ 后跟任何非 $ 字符,确认为块级公式
|
|
355
|
-
popToken();
|
|
356
|
-
pushToken(TokenType.BlockMath);
|
|
357
|
-
}
|
|
358
|
-
break;
|
|
359
|
-
}
|
|
360
|
-
case TokenType.BlockMath: {
|
|
361
|
-
/**
|
|
362
|
-
* $$E=mc^2$$
|
|
363
|
-
* ^^
|
|
364
|
-
*/
|
|
365
|
-
// 处理 $$ 块级公式
|
|
366
|
-
if (buffer.mathDelimiter === '$$') {
|
|
367
|
-
// 检测是否遇到结束的 $$
|
|
368
|
-
if (char === '$') {
|
|
369
|
-
buffer.dollarCount++;
|
|
370
|
-
if (buffer.dollarCount === 2) {
|
|
371
|
-
// 遇到了结束 $$,立即释放缓存
|
|
372
|
-
flushOutput();
|
|
373
|
-
buffer.dollarCount = 0;
|
|
374
|
-
buffer.mathDelimiter = '';
|
|
375
|
-
}
|
|
376
|
-
} else {
|
|
377
|
-
buffer.dollarCount = 0;
|
|
378
|
-
}
|
|
379
|
-
} else if (buffer.mathDelimiter === '\\[') {
|
|
380
|
-
// 处理 \[...\] 块级公式
|
|
381
|
-
if (pending.endsWith('\\]')) {
|
|
382
|
-
flushOutput();
|
|
383
|
-
buffer.mathDelimiter = '';
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
break;
|
|
387
|
-
}
|
|
388
|
-
case TokenType.MaybeBackslashMath: {
|
|
389
|
-
/**
|
|
390
|
-
* \( / \[
|
|
391
|
-
* ^ ^
|
|
392
|
-
*/
|
|
393
|
-
if (char === '(') {
|
|
394
|
-
// \( 行内公式
|
|
395
|
-
popToken();
|
|
396
|
-
pushToken(TokenType.InlineMath);
|
|
397
|
-
buffer.mathDelimiter = '\\(';
|
|
398
|
-
} else if (char === '[') {
|
|
399
|
-
// \[ 块级公式
|
|
400
|
-
popToken();
|
|
401
|
-
pushToken(TokenType.BlockMath);
|
|
402
|
-
buffer.mathDelimiter = '\\[';
|
|
403
|
-
} else {
|
|
404
|
-
// 不是数学公式,普通反斜杠
|
|
405
|
-
flushOutput();
|
|
406
|
-
buffer.mathDelimiter = '';
|
|
407
|
-
}
|
|
408
|
-
break;
|
|
409
|
-
}
|
|
410
|
-
case TokenType.Word: {
|
|
411
|
-
/**
|
|
412
|
-
* Hello world
|
|
413
|
-
* ^
|
|
414
|
-
* 缓存英文单词,直到遇到分隔符(空格、标点等)
|
|
415
|
-
*/
|
|
416
|
-
if (isWordSeparator(char)) {
|
|
417
|
-
// 遇到分隔符,释放缓存显示完整单词
|
|
418
|
-
flushOutput();
|
|
419
|
-
} else if (!isWordChar(char)) {
|
|
420
|
-
// 遇到非单词字符且非分隔符(如 Markdown 符号),也释放缓存
|
|
421
|
-
flushOutput();
|
|
422
|
-
}
|
|
423
|
-
// 否则继续缓存单词字符
|
|
424
|
-
break;
|
|
425
|
-
}
|
|
426
|
-
default: {
|
|
427
|
-
buffer.pending = char;
|
|
428
|
-
|
|
429
|
-
if (char === '!') {
|
|
430
|
-
pushToken(TokenType.Image);
|
|
431
|
-
} else if (char === '[') {
|
|
432
|
-
pushToken(TokenType.Link);
|
|
433
|
-
} else if (char === '#') {
|
|
434
|
-
pushToken(TokenType.Heading);
|
|
435
|
-
} else if (char === '_' || char === '*') {
|
|
436
|
-
pushToken(TokenType.MaybeEmphasis);
|
|
437
|
-
buffer.emphasisCount = 1;
|
|
438
|
-
} else if (char === '<') {
|
|
439
|
-
pushToken(TokenType.XML);
|
|
440
|
-
} else if (char === '`') {
|
|
441
|
-
pushToken(TokenType.MaybeCode);
|
|
442
|
-
buffer.backtickCount = 1;
|
|
443
|
-
} else if (char === '-' || char === '=') {
|
|
444
|
-
pushToken(TokenType.MaybeHr);
|
|
445
|
-
} else if (Markdown_Symbols.list.includes(char)) {
|
|
446
|
-
pushToken(TokenType.MaybeList);
|
|
447
|
-
} else if (enableMathCaching && char === '$') {
|
|
448
|
-
// 只有启用公式缓存时,才缓存 $ 符号的公式
|
|
449
|
-
pushToken(TokenType.MaybeInlineMath);
|
|
450
|
-
buffer.dollarCount = 1;
|
|
451
|
-
buffer.mathDelimiter = '';
|
|
452
|
-
} else if (enableMathCaching && char === '\\') {
|
|
453
|
-
// 只有启用公式缓存时,才缓存 \ 开头的公式
|
|
454
|
-
pushToken(TokenType.MaybeBackslashMath);
|
|
455
|
-
} else if (enableWordCaching && isEnglishLetter(char)) {
|
|
456
|
-
// 只有启用单词缓存时,才缓存英文单词
|
|
457
|
-
pushToken(TokenType.Word);
|
|
458
|
-
} else {
|
|
459
|
-
flushOutput(false);
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
};
|
|
465
|
-
|
|
466
|
-
const cursorContent = useMemo(() => {
|
|
467
|
-
if (config?.enableAnimation) return '';
|
|
468
|
-
if (cursor) {
|
|
469
|
-
if (cursor === 'dot') return ' :dot:';
|
|
470
|
-
if (cursor === 'underline') return ' :underline:';
|
|
471
|
-
return ' :dot:';
|
|
472
|
-
}
|
|
473
|
-
return '';
|
|
474
|
-
}, [cursor]);
|
|
475
|
-
|
|
476
|
-
useEffect(() => {
|
|
477
|
-
if (!input) {
|
|
478
|
-
setOutput('');
|
|
479
|
-
streamBuffer.current = { ...STREAM_BUFFER_INIT };
|
|
480
|
-
return;
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
if (typeof input !== 'string') {
|
|
484
|
-
console.error(`X-Markdown: input must be string, not ${typeof input}.`);
|
|
485
|
-
return;
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
if (!hasNextChunk) {
|
|
489
|
-
setOutput(input);
|
|
490
|
-
return;
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
const chunk = input.slice(streamBuffer.current.processedLength);
|
|
494
|
-
if (chunk.length) {
|
|
495
|
-
streamBuffer.current.processedLength += chunk.length;
|
|
496
|
-
handleChunk(chunk);
|
|
497
|
-
}
|
|
498
|
-
}, [input, hasNextChunk]);
|
|
499
|
-
|
|
500
|
-
return output + cursorContent;
|
|
501
|
-
};
|
|
502
|
-
|
|
503
|
-
export default useStreaming;
|
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
import Markdown from './Markdown';
|
|
2
|
-
import CodeBlock from './defaultComponents/CodeBlock';
|
|
3
|
-
import Media from './defaultComponents/Media';
|
|
4
|
-
import DisabledImage from './defaultComponents/DisabledImage';
|
|
5
|
-
import { useGlobalContext, useProviderContext } from '@agentscope-ai/chat';
|
|
6
|
-
import { useTyping } from './hooks/useTyping';
|
|
7
|
-
import type { MarkdownProps as InnerMarkdownProps } from './interface';
|
|
8
|
-
import { cursorExtension, CursorComponent } from '../plugins/cursor';
|
|
9
|
-
import { citationsExtension } from '../plugins/citations';
|
|
10
|
-
import latex from '../plugins/latex';
|
|
11
|
-
import useCitationsData from './hooks/useCitationsData';
|
|
12
|
-
import classnames from 'classnames';
|
|
13
|
-
import { ErrorBoundary } from "react-error-boundary";
|
|
14
|
-
import { memo, useMemo } from 'react';
|
|
15
|
-
|
|
16
|
-
export interface MarkdownProps {
|
|
17
|
-
/**
|
|
18
|
-
* @description 需要渲染的 Markdown 内容
|
|
19
|
-
* @descriptionEn Markdown content to be rendered
|
|
20
|
-
*/
|
|
21
|
-
content?: InnerMarkdownProps['content'];
|
|
22
|
-
/**
|
|
23
|
-
* @description 光标样式类型,支持点状、下划线或布尔值控制
|
|
24
|
-
* @descriptionEn Cursor style type, supports dot, underline, or boolean control
|
|
25
|
-
*/
|
|
26
|
-
cursor?: boolean | 'dot' | 'underline';
|
|
27
|
-
/**
|
|
28
|
-
* @description 基础字体大小,影响整个Markdown内容的字体大小
|
|
29
|
-
* @descriptionEn Base font size that affects the font size of the entire Markdown content
|
|
30
|
-
*/
|
|
31
|
-
baseFontSize?: InnerMarkdownProps['baseFontSize'];
|
|
32
|
-
/**
|
|
33
|
-
* @description 基础行高,影响文本的行间距
|
|
34
|
-
* @descriptionEn Base line height that affects text line spacing
|
|
35
|
-
*/
|
|
36
|
-
baseLineHeight?: InnerMarkdownProps['baseLineHeight'];
|
|
37
|
-
/**
|
|
38
|
-
* @description 引用数据数组,用于显示引用信息
|
|
39
|
-
* @descriptionEn Citation data array for displaying reference information
|
|
40
|
-
*/
|
|
41
|
-
citations?: InnerMarkdownProps['citations'];
|
|
42
|
-
/**
|
|
43
|
-
* @description 引用映射对象,用于快速查找引用信息
|
|
44
|
-
* @descriptionEn Citation mapping object for quick lookup of reference information
|
|
45
|
-
*/
|
|
46
|
-
citationsMap?: InnerMarkdownProps['citationsMap'];
|
|
47
|
-
/**
|
|
48
|
-
* @description 用于替换 HTML 元素的自定义 React 组件映射,组件会接收 domNode、streamStatus 等属性
|
|
49
|
-
* @descriptionEn Custom React components to replace HTML elements, components receive domNode, streamStatus, etc.
|
|
50
|
-
*/
|
|
51
|
-
components?: InnerMarkdownProps['components'];
|
|
52
|
-
/**
|
|
53
|
-
* @description 是否允许渲染HTML标签,影响安全性
|
|
54
|
-
* @descriptionEn Whether to allow rendering HTML tags, affects security
|
|
55
|
-
*/
|
|
56
|
-
allowHtml?: boolean;
|
|
57
|
-
/**
|
|
58
|
-
* @description 是否禁用图片渲染
|
|
59
|
-
* @descriptionEn Whether to disable image rendering
|
|
60
|
-
*/
|
|
61
|
-
disableImage?: boolean;
|
|
62
|
-
/**
|
|
63
|
-
* @description 是否启用打字机效果,逐字显示内容
|
|
64
|
-
* @descriptionEn Whether to enable typewriter effect for character-by-character display
|
|
65
|
-
*/
|
|
66
|
-
typing?: boolean | number;
|
|
67
|
-
/**
|
|
68
|
-
* @description 是否以原始文本形式显示,跳过Markdown解析
|
|
69
|
-
* @descriptionEn Whether to display as raw text, skipping Markdown parsing
|
|
70
|
-
*/
|
|
71
|
-
raw?: boolean;
|
|
72
|
-
/**
|
|
73
|
-
* @description 组件的CSS类名
|
|
74
|
-
* @descriptionEn CSS class name for the component
|
|
75
|
-
*/
|
|
76
|
-
className?: string;
|
|
77
|
-
/**
|
|
78
|
-
* @description 启用英文单词缓存,单词会在遇到空格或标点后才整体显示(仅在 typing 为 true 时生效)
|
|
79
|
-
* @descriptionEn Enable English word caching, words will be displayed as a whole after encountering spaces or punctuation (only works when typing is true)
|
|
80
|
-
* @default false
|
|
81
|
-
*/
|
|
82
|
-
enableWordCaching?: boolean;
|
|
83
|
-
/**
|
|
84
|
-
* @description 启用 LaTeX 公式缓存,公式会在完整后才整体显示(仅在 typing 为 true 时生效)
|
|
85
|
-
* @descriptionEn Enable LaTeX formula caching, formulas will be displayed as a whole when complete (only works when typing is true)
|
|
86
|
-
* @default true
|
|
87
|
-
*/
|
|
88
|
-
enableMathCaching?: boolean;
|
|
89
|
-
/**
|
|
90
|
-
* @description 启用文字出现动画效果
|
|
91
|
-
* @descriptionEn Enable text appearance animation effects
|
|
92
|
-
* @default false
|
|
93
|
-
*/
|
|
94
|
-
enableAnimation?: boolean;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const Null = () => null;
|
|
98
|
-
|
|
99
|
-
// 缓存不变的 dompurify 配置
|
|
100
|
-
const EMPTY_DOMPURIFY_CONFIG = {
|
|
101
|
-
ALLOWED_TAGS: [],
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* 检测浏览器是否支持正则表达式的 lookbehind assertions
|
|
107
|
-
* iOS Safari < 16.4 不支持此特性
|
|
108
|
-
*/
|
|
109
|
-
function supportsLookbehindAssertions(): boolean {
|
|
110
|
-
try {
|
|
111
|
-
// 尝试创建包含正向后行断言的正则表达式
|
|
112
|
-
new RegExp('(?<=a)b');
|
|
113
|
-
return true;
|
|
114
|
-
} catch (e) {
|
|
115
|
-
return false;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
const isSupportsLookbehindAssertions = supportsLookbehindAssertions();
|
|
120
|
-
|
|
121
|
-
console.log({ isSupportsLookbehindAssertions });
|
|
122
|
-
|
|
123
|
-
export default memo(function (props: MarkdownProps) {
|
|
124
|
-
const baseFontSize = props.baseFontSize || 14;
|
|
125
|
-
const baseLineHeight = props.baseLineHeight || 1.7;
|
|
126
|
-
const { getPrefixCls, } = useProviderContext();
|
|
127
|
-
const prefixCls = getPrefixCls('markdown');
|
|
128
|
-
const {
|
|
129
|
-
className,
|
|
130
|
-
allowHtml = true,
|
|
131
|
-
content: _content = '',
|
|
132
|
-
typing = false,
|
|
133
|
-
cursor = false,
|
|
134
|
-
enableWordCaching = false,
|
|
135
|
-
enableMathCaching = true,
|
|
136
|
-
enableAnimation = false,
|
|
137
|
-
...restProps
|
|
138
|
-
} = props;
|
|
139
|
-
const content = useTyping({ content: _content, typing });
|
|
140
|
-
const { citationsData, citationsDataCount, CitationComponent } = useCitationsData({ citations: props.citations, citationsMap: props.citationsMap });
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
if (props.raw || !isSupportsLookbehindAssertions) return <div className={prefixCls} style={{ fontSize: baseFontSize, lineHeight: baseLineHeight }}>{content}</div>;
|
|
144
|
-
|
|
145
|
-
// 使用 useMemo 缓存 extensions 配置
|
|
146
|
-
const extensions = useMemo(() => {
|
|
147
|
-
const exts = [
|
|
148
|
-
cursorExtension(),
|
|
149
|
-
...latex()
|
|
150
|
-
];
|
|
151
|
-
if (citationsDataCount > 0) exts.push(citationsExtension(citationsData));
|
|
152
|
-
return exts;
|
|
153
|
-
}, [citationsDataCount, citationsData]);
|
|
154
|
-
|
|
155
|
-
// 使用 useMemo 缓存 config 对象
|
|
156
|
-
const config = useMemo(() => ({
|
|
157
|
-
extensions,
|
|
158
|
-
}), [extensions]);
|
|
159
|
-
|
|
160
|
-
// 使用 useMemo 缓存 streaming 配置
|
|
161
|
-
const streaming = useMemo(() => ({
|
|
162
|
-
hasNextChunk: Boolean(typing),
|
|
163
|
-
enableWordCaching,
|
|
164
|
-
enableMathCaching,
|
|
165
|
-
enableAnimation
|
|
166
|
-
}), [typing, enableWordCaching, enableMathCaching, enableAnimation]);
|
|
167
|
-
|
|
168
|
-
// 使用 useMemo 缓存 components 对象
|
|
169
|
-
const components = useMemo(() => ({
|
|
170
|
-
// @ts-ignore
|
|
171
|
-
pre: CodeBlock,
|
|
172
|
-
style: Null,
|
|
173
|
-
script: Null,
|
|
174
|
-
img: props.disableImage ? DisabledImage : Media,
|
|
175
|
-
cursor: CursorComponent,
|
|
176
|
-
// @ts-ignore
|
|
177
|
-
citation: CitationComponent,
|
|
178
|
-
}), [props.disableImage, CitationComponent]);
|
|
179
|
-
|
|
180
|
-
// 使用 useMemo 缓存 dompurifyConfig
|
|
181
|
-
const dompurifyConfig = useMemo(() =>
|
|
182
|
-
allowHtml ? undefined : EMPTY_DOMPURIFY_CONFIG
|
|
183
|
-
, [allowHtml]);
|
|
184
|
-
|
|
185
|
-
return <ErrorBoundary fallback={<div className={prefixCls} style={{ fontSize: baseFontSize, lineHeight: baseLineHeight }}>{content}</div>}>
|
|
186
|
-
<Markdown
|
|
187
|
-
baseFontSize={baseFontSize}
|
|
188
|
-
baseLineHeight={baseLineHeight}
|
|
189
|
-
dompurifyConfig={dompurifyConfig}
|
|
190
|
-
streaming={streaming}
|
|
191
|
-
cursor={cursor}
|
|
192
|
-
className={classnames(prefixCls, className)}
|
|
193
|
-
components={components as unknown as InnerMarkdownProps['components']}
|
|
194
|
-
content={content}
|
|
195
|
-
config={config}
|
|
196
|
-
{...restProps}
|
|
197
|
-
/></ErrorBoundary>
|
|
198
|
-
});
|