@ant-design/agentic-ui 2.30.22 → 2.30.24
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/Bubble/MessagesContent/MarkdownPreview.d.ts +0 -58
- package/dist/Bubble/MessagesContent/MarkdownPreview.js +79 -156
- package/dist/Hooks/useAutoScroll.js +6 -4
- package/dist/MarkdownEditor/BaseMarkdownEditor.d.ts +1 -50
- package/dist/MarkdownEditor/BaseMarkdownEditor.js +11 -55
- package/dist/MarkdownEditor/editor/Editor.js +11 -9
- package/dist/MarkdownEditor/editor/elements/Code/index.js +1 -0
- package/dist/MarkdownEditor/editor/plugins/elements.d.ts +2 -0
- package/dist/MarkdownEditor/editor/plugins/elements.js +4 -2
- package/dist/MarkdownEditor/editor/plugins/handlePaste.js +46 -35
- package/dist/MarkdownEditor/editor/plugins/hotKeyCommands/backspace.js +133 -133
- package/dist/MarkdownEditor/editor/plugins/hotKeyCommands/enter.js +156 -140
- package/dist/MarkdownEditor/editor/plugins/hotKeyCommands/match.d.ts +2 -1
- package/dist/MarkdownEditor/editor/plugins/hotKeyCommands/match.js +23 -4
- package/dist/MarkdownEditor/editor/plugins/hotKeyCommands/tab.js +40 -36
- package/dist/MarkdownEditor/editor/plugins/index.d.ts +1 -0
- package/dist/MarkdownEditor/editor/plugins/index.js +1 -0
- package/dist/MarkdownEditor/editor/plugins/useKeyboard.js +46 -44
- package/dist/MarkdownEditor/editor/plugins/withCodeTagPlugin.js +1 -13
- package/dist/MarkdownEditor/editor/plugins/withMarkdown.js +2 -1
- package/dist/MarkdownEditor/editor/plugins/withSanitizeInvalidChildren.d.ts +7 -0
- package/dist/MarkdownEditor/editor/plugins/withSanitizeInvalidChildren.js +217 -0
- package/dist/MarkdownEditor/editor/store.d.ts +3 -1
- package/dist/MarkdownEditor/editor/store.js +15 -29
- package/dist/MarkdownEditor/editor/utils/editorCommands.js +98 -17
- package/dist/MarkdownEditor/editor/utils/editorUtils.d.ts +11 -0
- package/dist/MarkdownEditor/editor/utils/editorUtils.js +43 -6
- package/dist/MarkdownEditor/editor/utils/keyboard.js +14 -12
- package/dist/MarkdownEditor/types.d.ts +36 -414
- package/dist/MarkdownEditor/types.js +1 -4
- package/dist/MarkdownInputField/MarkdownInputField.js +2 -0
- package/dist/MarkdownInputField/SendActions/index.js +7 -4
- package/dist/MarkdownInputField/SendButton/index.d.ts +6 -0
- package/dist/MarkdownInputField/SendButton/index.js +6 -0
- package/dist/MarkdownInputField/hooks/useMarkdownInputFieldHandlers.d.ts +2 -1
- package/dist/MarkdownInputField/hooks/useMarkdownInputFieldHandlers.js +6 -1
- package/dist/MarkdownRenderer/AnimationText.d.ts +1 -5
- package/dist/MarkdownRenderer/AnimationText.js +2 -8
- package/dist/MarkdownRenderer/CharacterQueue.d.ts +0 -2
- package/dist/MarkdownRenderer/CharacterQueue.js +2 -2
- package/dist/MarkdownRenderer/MarkdownRenderer.d.ts +1 -9
- package/dist/MarkdownRenderer/MarkdownRenderer.js +1 -9
- package/dist/MarkdownRenderer/StreamingCursor.d.ts +4 -0
- package/dist/MarkdownRenderer/StreamingCursor.js +20 -0
- package/dist/MarkdownRenderer/markdownReactShared.d.ts +8 -38
- package/dist/MarkdownRenderer/markdownReactShared.js +9 -45
- package/dist/MarkdownRenderer/renderers/ChartRenderer.js +9 -1
- package/dist/MarkdownRenderer/streaming/MarkdownBlockPiece.d.ts +1 -3
- package/dist/MarkdownRenderer/streaming/MarkdownBlockPiece.js +16 -28
- package/dist/MarkdownRenderer/style.js +18 -0
- package/dist/MarkdownRenderer/types.d.ts +14 -86
- package/dist/MarkdownRenderer/useStreaming.d.ts +1 -10
- package/dist/MarkdownRenderer/useStreaming.js +5 -13
- package/dist/ThoughtChainList/MarkdownEditor.d.ts +1 -35
- package/dist/ThoughtChainList/MarkdownEditor.js +5 -44
- package/dist/Workspace/RealtimeFollow/index.d.ts +3 -0
- package/dist/Workspace/RealtimeFollow/index.js +5 -3
- package/package.json +2 -2
|
@@ -58,7 +58,7 @@ import React, { useContext, useMemo } from "react";
|
|
|
58
58
|
import { ActionIconBox } from "../../Components/ActionIconBox";
|
|
59
59
|
import { I18nContext } from "../../I18n";
|
|
60
60
|
import { AttachmentButton } from "../AttachmentButton";
|
|
61
|
-
import { SendButton } from "../SendButton";
|
|
61
|
+
import { SendButton, resolveSendDisabled } from "../SendButton";
|
|
62
62
|
import { VoiceInputButton } from "../VoiceInput";
|
|
63
63
|
import { MARKDOWN_INPUT_FIELD_TEST_IDS } from "../testIds";
|
|
64
64
|
/**
|
|
@@ -68,6 +68,7 @@ import { MARKDOWN_INPUT_FIELD_TEST_IDS } from "../testIds";
|
|
|
68
68
|
*/ export var SendActions = function SendActions(param) {
|
|
69
69
|
var attachment = param.attachment, voiceRecognizer = param.voiceRecognizer, value = param.value, disabled = param.disabled, typing = param.typing, isLoading = param.isLoading, _param_fileUploadDone = param.fileUploadDone, fileUploadDone = _param_fileUploadDone === void 0 ? true : _param_fileUploadDone, _param_fileUploadStatus = param.fileUploadStatus, fileUploadStatus = _param_fileUploadStatus === void 0 ? fileUploadDone ? 'done' : 'uploading' : _param_fileUploadStatus, fileUploadSummary = param.fileUploadSummary, _param_recording = param.recording, recording = _param_recording === void 0 ? false : _param_recording, _param_collapseSendActions = param.collapseSendActions, collapseSendActions = _param_collapseSendActions === void 0 ? false : _param_collapseSendActions, _param_allowEmptySubmit = param.allowEmptySubmit, allowEmptySubmit = _param_allowEmptySubmit === void 0 ? false : _param_allowEmptySubmit, uploadImage = param.uploadImage, onStartRecording = param.onStartRecording, onStopRecording = param.onStopRecording, onSend = param.onSend, onStop = param.onStop, actionsRender = param.actionsRender, _param_prefixCls = param.prefixCls, prefixCls = _param_prefixCls === void 0 ? 'ant-agentic-md-input-field' : _param_prefixCls, _param_hashId = param.hashId, hashId = _param_hashId === void 0 ? '' : _param_hashId, _param_hasTools = param.hasTools, hasTools = _param_hasTools === void 0 ? false : _param_hasTools, onResize = param.onResize, sendButtonProps = param.sendButtonProps, triggerSendKey = param.triggerSendKey;
|
|
70
70
|
var fileMap = attachment === null || attachment === void 0 ? void 0 : attachment.fileMap;
|
|
71
|
+
var sendDisabled = resolveSendDisabled(sendButtonProps, fileUploadStatus);
|
|
71
72
|
var defaultActionsLen = [
|
|
72
73
|
(attachment === null || attachment === void 0 ? void 0 : attachment.enable) ? '()' : null,
|
|
73
74
|
voiceRecognizer ? '()' : null,
|
|
@@ -104,11 +105,10 @@ import { MARKDOWN_INPUT_FIELD_TEST_IDS } from "../testIds";
|
|
|
104
105
|
return Promise.resolve();
|
|
105
106
|
}
|
|
106
107
|
}) : null,
|
|
107
|
-
/*#__PURE__*/ React.createElement(SendButton, _object_spread({
|
|
108
|
+
/*#__PURE__*/ React.createElement(SendButton, _object_spread_props(_object_spread({
|
|
108
109
|
key: "send-button",
|
|
109
110
|
typing: !!typing || !!isLoading,
|
|
110
111
|
isSendable: allowEmptySubmit || !!(value === null || value === void 0 ? void 0 : value.trim()) || fileMap && fileMap.size > 0 || recording,
|
|
111
|
-
disabled: disabled,
|
|
112
112
|
onClick: function onClick() {
|
|
113
113
|
if (typing || isLoading) {
|
|
114
114
|
onStop === null || onStop === void 0 ? void 0 : onStop();
|
|
@@ -117,11 +117,14 @@ import { MARKDOWN_INPUT_FIELD_TEST_IDS } from "../testIds";
|
|
|
117
117
|
onSend === null || onSend === void 0 ? void 0 : onSend();
|
|
118
118
|
},
|
|
119
119
|
triggerSendKey: triggerSendKey
|
|
120
|
-
}, sendButtonProps)
|
|
120
|
+
}, sendButtonProps), {
|
|
121
|
+
disabled: disabled || sendDisabled
|
|
122
|
+
}))
|
|
121
123
|
].filter(Boolean);
|
|
122
124
|
}, [
|
|
123
125
|
attachment,
|
|
124
126
|
fileUploadDone,
|
|
127
|
+
sendDisabled,
|
|
125
128
|
value,
|
|
126
129
|
collapseSendActions,
|
|
127
130
|
isLoading,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import type { FileUploadManagerReturn } from '../FileUploadManager';
|
|
2
3
|
/**
|
|
3
4
|
* 按钮颜色配置
|
|
4
5
|
*/
|
|
@@ -18,7 +19,12 @@ export type SendButtonColors = {
|
|
|
18
19
|
export type SendButtonCustomizationProps = {
|
|
19
20
|
compact?: boolean;
|
|
20
21
|
colors?: SendButtonColors;
|
|
22
|
+
disabled?: boolean;
|
|
21
23
|
};
|
|
24
|
+
/**
|
|
25
|
+
* 解析发送按钮的最终禁用状态:用户显式传入优先,否则按上传状态判断
|
|
26
|
+
*/
|
|
27
|
+
export declare function resolveSendDisabled(sendButtonProps: SendButtonCustomizationProps | undefined, fileUploadStatus: FileUploadManagerReturn['fileUploadStatus'] | undefined): boolean;
|
|
22
28
|
/**
|
|
23
29
|
* Props for the SendButton component.
|
|
24
30
|
*/
|
|
@@ -70,6 +70,12 @@ import { ErrorBoundary } from "react-error-boundary";
|
|
|
70
70
|
import { StopIcon } from "../../AgentRunBar/icons";
|
|
71
71
|
import { I18nContext } from "../../I18n";
|
|
72
72
|
import { useStyle } from "./style";
|
|
73
|
+
/**
|
|
74
|
+
* 解析发送按钮的最终禁用状态:用户显式传入优先,否则按上传状态判断
|
|
75
|
+
*/ export function resolveSendDisabled(sendButtonProps, fileUploadStatus) {
|
|
76
|
+
var _ref;
|
|
77
|
+
return (_ref = sendButtonProps === null || sendButtonProps === void 0 ? void 0 : sendButtonProps.disabled) !== null && _ref !== void 0 ? _ref : fileUploadStatus === 'uploading';
|
|
78
|
+
}
|
|
73
79
|
var DEFAULT_SEND_BUTTON_COLORS = {
|
|
74
80
|
icon: '#00183D',
|
|
75
81
|
iconHover: '#fff',
|
|
@@ -4,6 +4,7 @@ import type { AttachmentFile } from '../AttachmentButton/types';
|
|
|
4
4
|
import type { MarkdownInputFieldProps } from '../types/MarkdownInputFieldProps';
|
|
5
5
|
interface UseMarkdownInputFieldHandlersParams {
|
|
6
6
|
props: Pick<MarkdownInputFieldProps, 'disabled' | 'typing' | 'onChange' | 'onSend' | 'allowEmptySubmit' | 'markdownProps' | 'attachment' | 'triggerSendKey'>;
|
|
7
|
+
sendDisabled?: boolean;
|
|
7
8
|
markdownEditorRef: React.MutableRefObject<MarkdownEditorInstance | undefined>;
|
|
8
9
|
inputRef: React.RefObject<HTMLDivElement>;
|
|
9
10
|
isSendingRef: React.MutableRefObject<boolean>;
|
|
@@ -22,7 +23,7 @@ interface UseMarkdownInputFieldHandlersParams {
|
|
|
22
23
|
* 事件处理 Hook
|
|
23
24
|
* 管理组件中的所有事件处理函数
|
|
24
25
|
*/
|
|
25
|
-
export declare const useMarkdownInputFieldHandlers: ({ props, markdownEditorRef, inputRef, isSendingRef, isLoading, setIsLoading, value, setValue, fileMap, setFileMap, recording, stopRecording, isEnlarged, setIsEnlarged, }: UseMarkdownInputFieldHandlersParams) => {
|
|
26
|
+
export declare const useMarkdownInputFieldHandlers: ({ props, sendDisabled, markdownEditorRef, inputRef, isSendingRef, isLoading, setIsLoading, value, setValue, fileMap, setFileMap, recording, stopRecording, isEnlarged, setIsEnlarged, }: UseMarkdownInputFieldHandlersParams) => {
|
|
26
27
|
handleEnlargeClick: () => void;
|
|
27
28
|
sendMessage: () => Promise<void>;
|
|
28
29
|
handlePaste: (e: React.ClipboardEvent<HTMLDivElement>) => Promise<void>;
|
|
@@ -189,7 +189,7 @@ import { getFileListFromDataTransferItems } from "../FilePaste";
|
|
|
189
189
|
* 事件处理 Hook
|
|
190
190
|
* 管理组件中的所有事件处理函数
|
|
191
191
|
*/ export var useMarkdownInputFieldHandlers = function useMarkdownInputFieldHandlers(param) {
|
|
192
|
-
var props = param.props, markdownEditorRef = param.markdownEditorRef, inputRef = param.inputRef, isSendingRef = param.isSendingRef, isLoading = param.isLoading, setIsLoading = param.setIsLoading, value = param.value, setValue = param.setValue, fileMap = param.fileMap, setFileMap = param.setFileMap, recording = param.recording, stopRecording = param.stopRecording, isEnlarged = param.isEnlarged, setIsEnlarged = param.setIsEnlarged;
|
|
192
|
+
var props = param.props, sendDisabled = param.sendDisabled, markdownEditorRef = param.markdownEditorRef, inputRef = param.inputRef, isSendingRef = param.isSendingRef, isLoading = param.isLoading, setIsLoading = param.setIsLoading, value = param.value, setValue = param.setValue, fileMap = param.fileMap, setFileMap = param.setFileMap, recording = param.recording, stopRecording = param.stopRecording, isEnlarged = param.isEnlarged, setIsEnlarged = param.setIsEnlarged;
|
|
193
193
|
/**
|
|
194
194
|
* 处理放大缩小按钮点击
|
|
195
195
|
* @description 切换编辑器的放大/缩小状态
|
|
@@ -206,6 +206,7 @@ import { getFileListFromDataTransferItems } from "../FilePaste";
|
|
|
206
206
|
return _ts_generator(this, function(_state) {
|
|
207
207
|
switch(_state.label){
|
|
208
208
|
case 0:
|
|
209
|
+
// 这个 disable 是整体 input 的禁用
|
|
209
210
|
if (props.disabled) return [
|
|
210
211
|
2
|
|
211
212
|
];
|
|
@@ -220,6 +221,10 @@ import { getFileListFromDataTransferItems } from "../FilePaste";
|
|
|
220
221
|
if (isSendingRef.current) return [
|
|
221
222
|
2
|
|
222
223
|
];
|
|
224
|
+
// 这个是发送按钮的单独禁用
|
|
225
|
+
if (sendDisabled) return [
|
|
226
|
+
2
|
|
227
|
+
];
|
|
223
228
|
if (!recording) return [
|
|
224
229
|
3,
|
|
225
230
|
2
|
|
@@ -14,10 +14,6 @@ export interface AnimationTextProps {
|
|
|
14
14
|
children: React.ReactNode;
|
|
15
15
|
animationConfig?: AnimationConfig;
|
|
16
16
|
}
|
|
17
|
-
/**
|
|
18
|
-
* 流式文字淡入动画组件。
|
|
19
|
-
*
|
|
20
|
-
* 同一段流式前缀追加(或尾部截断修正)只触发一次入场动画;非前缀替换时重播。
|
|
21
|
-
*/
|
|
17
|
+
/** 流式文字淡入,前缀追加只触发一次入场,非前缀替换时重播 */
|
|
22
18
|
declare const AnimationText: React.NamedExoticComponent<AnimationTextProps>;
|
|
23
19
|
export default AnimationText;
|
|
@@ -45,9 +45,7 @@ function _unsupported_iterable_to_array(o, minLen) {
|
|
|
45
45
|
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
|
|
46
46
|
}
|
|
47
47
|
import React, { useEffect, useMemo, useRef, useState } from "react";
|
|
48
|
-
|
|
49
|
-
* 提取 React children 的纯文本
|
|
50
|
-
*/ var extractText = function extractText1(children) {
|
|
48
|
+
var extractText = function extractText1(children) {
|
|
51
49
|
var _children_props;
|
|
52
50
|
if (typeof children === 'string') return children;
|
|
53
51
|
if (typeof children === 'number') return String(children);
|
|
@@ -60,11 +58,7 @@ import React, { useEffect, useMemo, useRef, useState } from "react";
|
|
|
60
58
|
/** 流式同一段内:前后文案仅「前缀关系」变化(增长或尾部截断修正) */ var isStreamingCompatible = function isStreamingCompatible(prev, next) {
|
|
61
59
|
return prev.startsWith(next) || next.startsWith(prev);
|
|
62
60
|
};
|
|
63
|
-
/**
|
|
64
|
-
* 流式文字淡入动画组件。
|
|
65
|
-
*
|
|
66
|
-
* 同一段流式前缀追加(或尾部截断修正)只触发一次入场动画;非前缀替换时重播。
|
|
67
|
-
*/ var AnimationText = /*#__PURE__*/ React.memo(function(param) {
|
|
61
|
+
/** 流式文字淡入,前缀追加只触发一次入场,非前缀替换时重播 */ var AnimationText = /*#__PURE__*/ React.memo(function(param) {
|
|
68
62
|
var children = param.children, animationConfig = param.animationConfig;
|
|
69
63
|
var _ref = animationConfig || {}, _ref_fadeDuration = _ref.fadeDuration, fadeDuration = _ref_fadeDuration === void 0 ? 250 : _ref_fadeDuration, _ref_easing = _ref.easing, easing = _ref_easing === void 0 ? 'ease-out' : _ref_easing;
|
|
70
64
|
var _useState = _sliced_to_array(useState(false), 2), animComplete = _useState[0], setAnimComplete = _useState[1];
|
|
@@ -126,13 +126,13 @@ var DEFAULT_BACKGROUND_BATCH_MULTIPLIER = 10;
|
|
|
126
126
|
}
|
|
127
127
|
},
|
|
128
128
|
{
|
|
129
|
-
|
|
129
|
+
key: "getDisplayedLength",
|
|
130
130
|
value: function getDisplayedLength() {
|
|
131
131
|
return this.displayedLength;
|
|
132
132
|
}
|
|
133
133
|
},
|
|
134
134
|
{
|
|
135
|
-
|
|
135
|
+
key: "getFullContent",
|
|
136
136
|
value: function getFullContent() {
|
|
137
137
|
return this.fullContent;
|
|
138
138
|
}
|
|
@@ -1,13 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { MarkdownRendererProps, MarkdownRendererRef } from './types';
|
|
3
|
-
/**
|
|
4
|
-
* MarkdownRenderer —— 流式/只读场景下的轻量 Markdown 渲染器。
|
|
5
|
-
*
|
|
6
|
-
* 核心优势:
|
|
7
|
-
* - 不创建 Slate 实例,无编辑态开销
|
|
8
|
-
* - 字符队列驱动流式逐字输出动画
|
|
9
|
-
* - Markdown → hast → React 元素树(hast-util-to-jsx-runtime)
|
|
10
|
-
* - 特殊块(code / mermaid / chart / katex)通过组件映射拦截渲染
|
|
11
|
-
*/
|
|
3
|
+
/** 轻量流式 Markdown 渲染器——无 Slate 实例,Markdown → hast → React */
|
|
12
4
|
declare const InternalMarkdownRenderer: React.ForwardRefExoticComponent<MarkdownRendererProps & React.RefAttributes<MarkdownRendererRef>>;
|
|
13
5
|
export default InternalMarkdownRenderer;
|
|
@@ -240,15 +240,7 @@ var SCHEMA_LANGUAGES = new Set([
|
|
|
240
240
|
editorCodeProps: editorCodeProps
|
|
241
241
|
}));
|
|
242
242
|
};
|
|
243
|
-
/**
|
|
244
|
-
* MarkdownRenderer —— 流式/只读场景下的轻量 Markdown 渲染器。
|
|
245
|
-
*
|
|
246
|
-
* 核心优势:
|
|
247
|
-
* - 不创建 Slate 实例,无编辑态开销
|
|
248
|
-
* - 字符队列驱动流式逐字输出动画
|
|
249
|
-
* - Markdown → hast → React 元素树(hast-util-to-jsx-runtime)
|
|
250
|
-
* - 特殊块(code / mermaid / chart / katex)通过组件映射拦截渲染
|
|
251
|
-
*/ var InternalMarkdownRenderer = /*#__PURE__*/ forwardRef(function(props, ref) {
|
|
243
|
+
/** 轻量流式 Markdown 渲染器——无 Slate 实例,Markdown → hast → React */ var InternalMarkdownRenderer = /*#__PURE__*/ forwardRef(function(props, ref) {
|
|
252
244
|
var content = props.content, _props_streaming = props.streaming, streaming = _props_streaming === void 0 ? false : _props_streaming, isFinished = props.isFinished, queueOptions = props.queueOptions, plugins = props.plugins, remarkPlugins = props.remarkPlugins, htmlConfig = props.htmlConfig, className = props.className, style = props.style, customPrefixCls = props.prefixCls, linkConfig = props.linkConfig, streamingParagraphAnimation = props.streamingParagraphAnimation, apaasify = props.apaasify, eleRender = props.eleRender, fileMapConfig = props.fileMapConfig, fncProps = props.fncProps, editorCodeProps = props.codeProps;
|
|
253
245
|
var getPrefixCls = useContext(ConfigProvider.ConfigContext).getPrefixCls;
|
|
254
246
|
// 复用 MarkdownEditor 的 CSS 前缀和样式,保持渲染一致性
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
/** 流式闪烁光标,由 MarkdownBlockPiece 控制挂载/卸载 */ var StreamingCursor = function StreamingCursor() {
|
|
3
|
+
return /*#__PURE__*/ React.createElement("span", {
|
|
4
|
+
"data-streaming-cursor": "",
|
|
5
|
+
"data-testid": "streaming-cursor",
|
|
6
|
+
"aria-hidden": "true",
|
|
7
|
+
style: {
|
|
8
|
+
display: 'inline-block',
|
|
9
|
+
width: 2,
|
|
10
|
+
height: '1.1em',
|
|
11
|
+
marginLeft: 2,
|
|
12
|
+
verticalAlign: 'text-bottom',
|
|
13
|
+
backgroundColor: 'currentColor',
|
|
14
|
+
borderRadius: 1,
|
|
15
|
+
animation: 'markdownStreamingCursorFadeIn 0.2s ease-out forwards, markdownStreamingCursorBlink 0.8s ease-in-out 0.2s infinite'
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
};
|
|
19
|
+
StreamingCursor.displayName = 'StreamingCursor';
|
|
20
|
+
export { StreamingCursor };
|
|
@@ -4,12 +4,7 @@ import { type MarkdownRemarkPlugin, type MarkdownToHtmlConfig } from '../Markdow
|
|
|
4
4
|
import type { MarkdownEditorProps } from '../MarkdownEditor/types';
|
|
5
5
|
import type { MarkdownRendererEleProps, RendererBlockProps } from './types';
|
|
6
6
|
declare const createHastProcessor: (extraRemarkPlugins?: MarkdownRemarkPlugin[], config?: MarkdownToHtmlConfig) => Processor;
|
|
7
|
-
/**
|
|
8
|
-
* 构建与 MarkdownEditor Readonly 组件对齐的 hast→React 组件映射。
|
|
9
|
-
*
|
|
10
|
-
* MarkdownEditor 的 Slate 元素使用 data-be 属性和 prefixCls 类名,
|
|
11
|
-
* 这里为原生 HTML 标签添加相同的属性,使共用的 CSS 能正确命中。
|
|
12
|
-
*/
|
|
7
|
+
/** hast → React 组件映射,与 MarkdownEditor Readonly 的 data-be / prefixCls 对齐 */
|
|
13
8
|
declare const buildEditorAlignedComponents: (prefixCls: string, userComponents: Record<string, React.ComponentType<RendererBlockProps>>, streaming?: boolean, linkConfig?: {
|
|
14
9
|
openInNewTab?: boolean | undefined;
|
|
15
10
|
onClick?: ((url?: string) => boolean | void) | undefined;
|
|
@@ -52,52 +47,27 @@ declare const buildEditorAlignedComponents: (prefixCls: string, userComponents:
|
|
|
52
47
|
think: (props: any) => React.FunctionComponentElement<import("../ToolUseBarThink").ToolUseBarThinkProps>;
|
|
53
48
|
answer: (props: any) => React.ReactElement<any, string | React.JSXElementConstructor<any>>;
|
|
54
49
|
};
|
|
55
|
-
/**
|
|
56
|
-
|
|
57
|
-
*/
|
|
58
|
-
declare const markLastParagraphStreamingTail: (hast: any) => void;
|
|
59
|
-
/**
|
|
60
|
-
* 将单个 markdown 片段转为 React 元素(内部函数)
|
|
61
|
-
*/
|
|
62
|
-
declare const renderMarkdownBlock: (blockContent: string, processor: Processor, components: Record<string, any>, blockOpts?: {
|
|
63
|
-
markStreamingTailParagraph?: boolean;
|
|
64
|
-
}) => React.ReactNode;
|
|
65
|
-
/**
|
|
66
|
-
* 将 markdown 按块(双换行)拆分,尊重代码围栏边界。
|
|
67
|
-
* 返回的每个块是一个独立的 markdown 片段,可单独解析。
|
|
68
|
-
*/
|
|
50
|
+
/** markdown 片段 → React 元素 */
|
|
51
|
+
declare const renderMarkdownBlock: (blockContent: string, processor: Processor, components: Record<string, any>) => React.ReactNode;
|
|
52
|
+
/** 按双换行拆块,尊重代码围栏边界 */
|
|
69
53
|
declare const splitMarkdownBlocks: (content: string) => string[];
|
|
70
54
|
export interface UseMarkdownToReactOptions {
|
|
71
55
|
remarkPlugins?: MarkdownRemarkPlugin[];
|
|
72
56
|
htmlConfig?: MarkdownToHtmlConfig;
|
|
73
57
|
components?: Record<string, React.ComponentType<RendererBlockProps>>;
|
|
74
|
-
/** MarkdownEditor 的 CSS 前缀,用于生成对齐的 className */
|
|
75
58
|
prefixCls?: string;
|
|
76
|
-
/** 链接配置:onClick 拦截、openInNewTab 控制 */
|
|
77
59
|
linkConfig?: {
|
|
78
60
|
openInNewTab?: boolean;
|
|
79
61
|
onClick?: (url?: string) => boolean | void;
|
|
80
62
|
};
|
|
81
|
-
/** 脚注:与只读 Slate 路径 FncLeaf / fncProps 对齐 */
|
|
82
63
|
fncProps?: MarkdownEditorProps['fncProps'];
|
|
83
|
-
/** 是否处于流式状态,用于最后一个块的打字动画 */
|
|
84
64
|
streaming?: boolean;
|
|
85
|
-
/**
|
|
86
|
-
* 流式时是否对「生长中的末段」启用段落淡入(AnimationText)。
|
|
87
|
-
* 默认 false:重解析时频繁触发动画易导致整页闪动;需要时再显式传入 true。
|
|
88
|
-
*/
|
|
65
|
+
/** 默认开启;传 false 关闭末段段落动画 */
|
|
89
66
|
streamingParagraphAnimation?: boolean;
|
|
90
|
-
/**
|
|
91
|
-
* 单调增长的原始流字符串,仅用于判断是否应保留分块缓存。
|
|
92
|
-
* 与 `content`(常为 useStreaming 输出的可解析串)分离,避免占位符与正文切换时误判为非前缀修订。
|
|
93
|
-
*/
|
|
67
|
+
/** 原始流字符串,与 useStreaming 输出分离避免缓存误判 */
|
|
94
68
|
contentRevisionSource?: string;
|
|
95
|
-
/**
|
|
96
|
-
* 自定义元素渲染拦截函数(markdown 渲染模式)。
|
|
97
|
-
* 允许在默认渲染结果基础上包装、替换任意元素。
|
|
98
|
-
* 返回 undefined 时回退到默认渲染。
|
|
99
|
-
*/
|
|
69
|
+
/** 返回 undefined 回退默认渲染 */
|
|
100
70
|
eleRender?: (props: MarkdownRendererEleProps, defaultDom: React.ReactNode) => React.ReactNode;
|
|
101
71
|
}
|
|
102
|
-
export { buildEditorAlignedComponents, createHastProcessor,
|
|
72
|
+
export { buildEditorAlignedComponents, createHastProcessor, renderMarkdownBlock, splitMarkdownBlocks, };
|
|
103
73
|
export type { MarkdownRendererEleProps };
|
|
@@ -392,9 +392,7 @@ var extractLanguageFromClassName = function extractLanguageFromClassName(classNa
|
|
|
392
392
|
}
|
|
393
393
|
return undefined;
|
|
394
394
|
};
|
|
395
|
-
|
|
396
|
-
* 提取 React children 的文本内容
|
|
397
|
-
*/ var extractChildrenText = function extractChildrenText1(children) {
|
|
395
|
+
var extractChildrenText = function extractChildrenText1(children) {
|
|
398
396
|
var _children_props;
|
|
399
397
|
if (typeof children === 'string') return children;
|
|
400
398
|
if (typeof children === 'number') return String(children);
|
|
@@ -404,13 +402,7 @@ var extractLanguageFromClassName = function extractLanguageFromClassName(classNa
|
|
|
404
402
|
}
|
|
405
403
|
return '';
|
|
406
404
|
};
|
|
407
|
-
/**
|
|
408
|
-
* <think> 标签渲染组件——使用 ToolUseBarThink 替代原生 DOM。
|
|
409
|
-
* 在 MarkdownEditor 中,<think> 被预处理为 ```think 代码块,
|
|
410
|
-
* 然后由 ThinkBlock 组件(依赖 Slate 上下文)渲染为 ToolUseBarThink。
|
|
411
|
-
* 在 MarkdownRenderer 中,<think> 通过 rehypeRaw 保留为 hast 元素,
|
|
412
|
-
* 这里直接渲染为 ToolUseBarThink,无需 Slate 上下文。
|
|
413
|
-
*/ var ThinkBlockRendererComponent = function ThinkBlockRendererComponent(props) {
|
|
405
|
+
/** <think> 标签 → ToolUseBarThink(MarkdownRenderer 无 Slate 上下文,直接渲染) */ var ThinkBlockRendererComponent = function ThinkBlockRendererComponent(props) {
|
|
414
406
|
var children = props.children;
|
|
415
407
|
var content = extractChildrenText(children);
|
|
416
408
|
var isLoading = content.endsWith('...');
|
|
@@ -428,21 +420,16 @@ var extractLanguageFromClassName = function extractLanguageFromClassName(classNa
|
|
|
428
420
|
status: isLoading ? 'loading' : 'success'
|
|
429
421
|
});
|
|
430
422
|
};
|
|
431
|
-
/**
|
|
432
|
-
* 构建与 MarkdownEditor Readonly 组件对齐的 hast→React 组件映射。
|
|
433
|
-
*
|
|
434
|
-
* MarkdownEditor 的 Slate 元素使用 data-be 属性和 prefixCls 类名,
|
|
435
|
-
* 这里为原生 HTML 标签添加相同的属性,使共用的 CSS 能正确命中。
|
|
436
|
-
*/ var buildEditorAlignedComponents = function buildEditorAlignedComponents(prefixCls, userComponents, streaming, linkConfig, fncProps, streamingParagraphAnimation, eleRender) {
|
|
423
|
+
/** hast → React 组件映射,与 MarkdownEditor Readonly 的 data-be / prefixCls 对齐 */ var buildEditorAlignedComponents = function buildEditorAlignedComponents(prefixCls, userComponents, streaming, linkConfig, fncProps, streamingParagraphAnimation, eleRender) {
|
|
437
424
|
var listCls = "".concat(prefixCls, "-list");
|
|
438
425
|
var tableCls = "".concat(prefixCls, "-content-table");
|
|
439
426
|
var contentCls = prefixCls; // e.g. ant-agentic-md-editor-content
|
|
440
|
-
/** 仅当 streaming
|
|
427
|
+
/** 仅当 streaming、末块动画上下文允许且未显式关闭段落动画时包 AnimationText */ var StreamAnimWrap = function StreamAnimWrap(param) {
|
|
441
428
|
var children = param.children;
|
|
442
429
|
var _ref;
|
|
443
430
|
var ctx = useContext(StreamingAnimationContext);
|
|
444
431
|
var animateBlock = (_ref = ctx === null || ctx === void 0 ? void 0 : ctx.animateBlock) !== null && _ref !== void 0 ? _ref : true;
|
|
445
|
-
var allow = !!streaming && animateBlock &&
|
|
432
|
+
var allow = !!streaming && animateBlock && streamingParagraphAnimation !== false;
|
|
446
433
|
if (!allow) return children;
|
|
447
434
|
return jsx(AnimationText, {
|
|
448
435
|
children: children
|
|
@@ -888,7 +875,7 @@ var extractLanguageFromClassName = function extractLanguageFromClassName(classNa
|
|
|
888
875
|
var defaultDom = jsx('mark', _object_spread_props(_object_spread({}, rest), {
|
|
889
876
|
'data-testid': 'markdown-mark',
|
|
890
877
|
style: {
|
|
891
|
-
background: '#f59e0b',
|
|
878
|
+
background: 'var(--ant-color-warning-bg, #f59e0b)',
|
|
892
879
|
padding: '0.1em 0.2em',
|
|
893
880
|
borderRadius: 2
|
|
894
881
|
},
|
|
@@ -1204,31 +1191,11 @@ var extractLanguageFromClassName = function extractLanguageFromClassName(classNa
|
|
|
1204
1191
|
}
|
|
1205
1192
|
}, userComponents);
|
|
1206
1193
|
};
|
|
1207
|
-
/**
|
|
1208
|
-
* 在 hast 上标记「最后一个 p」,用于流式时仅该段落播放入场(单块长文时避免全页 p 一起闪)
|
|
1209
|
-
*/ var markLastParagraphStreamingTail = function markLastParagraphStreamingTail(hast) {
|
|
1210
|
-
var paragraphs = [];
|
|
1211
|
-
visit(hast, 'element', function(node) {
|
|
1212
|
-
if (node.tagName === 'p') {
|
|
1213
|
-
paragraphs.push(node);
|
|
1214
|
-
}
|
|
1215
|
-
});
|
|
1216
|
-
var last = paragraphs[paragraphs.length - 1];
|
|
1217
|
-
if (last) {
|
|
1218
|
-
last.properties = last.properties || {};
|
|
1219
|
-
last.properties.dataStreamingTail = true;
|
|
1220
|
-
}
|
|
1221
|
-
};
|
|
1222
|
-
/**
|
|
1223
|
-
* 将单个 markdown 片段转为 React 元素(内部函数)
|
|
1224
|
-
*/ var renderMarkdownBlock = function renderMarkdownBlock(blockContent, processor, components, blockOpts) {
|
|
1194
|
+
/** markdown 片段 → React 元素 */ var renderMarkdownBlock = function renderMarkdownBlock(blockContent, processor, components) {
|
|
1225
1195
|
if (!blockContent.trim()) return null;
|
|
1226
1196
|
try {
|
|
1227
1197
|
var mdast = processor.parse(blockContent);
|
|
1228
1198
|
var hast = processor.runSync(mdast);
|
|
1229
|
-
if (blockOpts === null || blockOpts === void 0 ? void 0 : blockOpts.markStreamingTailParagraph) {
|
|
1230
|
-
markLastParagraphStreamingTail(hast);
|
|
1231
|
-
}
|
|
1232
1199
|
return toJsxRuntime(hast, {
|
|
1233
1200
|
Fragment: Fragment,
|
|
1234
1201
|
jsx: jsx,
|
|
@@ -1240,10 +1207,7 @@ var extractLanguageFromClassName = function extractLanguageFromClassName(classNa
|
|
|
1240
1207
|
return null;
|
|
1241
1208
|
}
|
|
1242
1209
|
};
|
|
1243
|
-
/**
|
|
1244
|
-
* 将 markdown 按块(双换行)拆分,尊重代码围栏边界。
|
|
1245
|
-
* 返回的每个块是一个独立的 markdown 片段,可单独解析。
|
|
1246
|
-
*/ var splitMarkdownBlocks = function splitMarkdownBlocks(content) {
|
|
1210
|
+
/** 按双换行拆块,尊重代码围栏边界 */ var splitMarkdownBlocks = function splitMarkdownBlocks(content) {
|
|
1247
1211
|
var lines = content.split('\n');
|
|
1248
1212
|
var blocks = [];
|
|
1249
1213
|
var current = [];
|
|
@@ -1287,4 +1251,4 @@ var extractLanguageFromClassName = function extractLanguageFromClassName(classNa
|
|
|
1287
1251
|
}
|
|
1288
1252
|
return blocks;
|
|
1289
1253
|
};
|
|
1290
|
-
export { buildEditorAlignedComponents, createHastProcessor,
|
|
1254
|
+
export { buildEditorAlignedComponents, createHastProcessor, renderMarkdownBlock, splitMarkdownBlocks };
|
|
@@ -284,15 +284,23 @@ var extractTextContent = function extractTextContent1(children) {
|
|
|
284
284
|
useEffect(function() {
|
|
285
285
|
// 延迟一帧渲染图表,确保容器已挂载到 DOM 且有正确的宽度
|
|
286
286
|
// 解决 recharts ResponsiveContainer 在零宽容器中崩溃的问题
|
|
287
|
+
var cancelled = false;
|
|
287
288
|
var raf = requestAnimationFrame(function() {
|
|
289
|
+
if (cancelled) {
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
288
292
|
setMounted(true);
|
|
289
293
|
});
|
|
290
294
|
return function() {
|
|
291
|
-
|
|
295
|
+
cancelled = true;
|
|
296
|
+
cancelAnimationFrame(raf);
|
|
292
297
|
};
|
|
293
298
|
}, []);
|
|
294
299
|
useEffect(function() {
|
|
295
300
|
if (!mounted) return;
|
|
301
|
+
if (typeof window === 'undefined') {
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
296
304
|
var updateWidth = function updateWidth() {
|
|
297
305
|
var _containerRef_current;
|
|
298
306
|
var width = ((_containerRef_current = containerRef.current) === null || _containerRef_current === void 0 ? void 0 : _containerRef_current.clientWidth) || 400;
|
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import type { Processor } from 'unified';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
export interface MarkdownBlockPieceProps {
|
|
4
|
-
/** 末块为 tail(生长中);一旦其后出现新块,同一段内容变为 sealed,保持同一 React key 可避免重组件卸载 */
|
|
5
4
|
variant: 'sealed' | 'tail';
|
|
6
5
|
blockSource: string;
|
|
7
6
|
processor: Processor;
|
|
8
7
|
components: Record<string, any>;
|
|
9
|
-
/** 仅末块且处于流式模式时为 true,用于节流与末段动画 */
|
|
10
8
|
streaming: boolean;
|
|
11
9
|
}
|
|
12
10
|
/**
|
|
13
|
-
*
|
|
11
|
+
* 块级渲染单元:sealed 块缓存不动,tail 块节流重解析 + 闪烁光标。
|
|
14
12
|
*/
|
|
15
13
|
export declare const MarkdownBlockPiece: React.NamedExoticComponent<MarkdownBlockPieceProps>;
|
|
@@ -1,49 +1,37 @@
|
|
|
1
1
|
import React, { memo, useMemo, useRef } from "react";
|
|
2
2
|
import { renderMarkdownBlock } from "../markdownReactShared";
|
|
3
3
|
import { StreamingAnimationContext } from "../StreamingAnimationContext";
|
|
4
|
+
import { StreamingCursor } from "../StreamingCursor";
|
|
4
5
|
import { shouldReparseLastBlock } from "./lastBlockThrottle";
|
|
5
6
|
/**
|
|
6
|
-
*
|
|
7
|
+
* 块级渲染单元:sealed 块缓存不动,tail 块节流重解析 + 闪烁光标。
|
|
7
8
|
*/ export var MarkdownBlockPiece = /*#__PURE__*/ memo(function MarkdownBlockPiece(param) {
|
|
8
9
|
var variant = param.variant, blockSource = param.blockSource, processor = param.processor, components = param.components, streaming = param.streaming;
|
|
9
10
|
var lastParsedRef = useRef(null);
|
|
10
|
-
|
|
11
|
+
var cacheRef = useRef(new Map());
|
|
11
12
|
var node = useMemo(function() {
|
|
12
|
-
var cached =
|
|
13
|
-
if (cached && variant === 'sealed')
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
markStreamingTailParagraph: false
|
|
19
|
-
});
|
|
20
|
-
parseBySourceRef.current.set(blockSource, el);
|
|
21
|
-
return el;
|
|
22
|
-
}
|
|
23
|
-
if (!streaming) {
|
|
24
|
-
var el1 = renderMarkdownBlock(blockSource, processor, components, {
|
|
25
|
-
markStreamingTailParagraph: false
|
|
26
|
-
});
|
|
27
|
-
parseBySourceRef.current.set(blockSource, el1);
|
|
28
|
-
lastParsedRef.current = {
|
|
13
|
+
var cached = cacheRef.current.get(blockSource);
|
|
14
|
+
if (cached && variant === 'sealed') return cached;
|
|
15
|
+
if (variant === 'sealed' || !streaming) {
|
|
16
|
+
var el = renderMarkdownBlock(blockSource, processor, components);
|
|
17
|
+
cacheRef.current.set(blockSource, el);
|
|
18
|
+
if (variant === 'tail') lastParsedRef.current = {
|
|
29
19
|
source: blockSource,
|
|
30
|
-
node:
|
|
20
|
+
node: el
|
|
31
21
|
};
|
|
32
|
-
return
|
|
22
|
+
return el;
|
|
33
23
|
}
|
|
34
24
|
var prev = lastParsedRef.current;
|
|
35
25
|
if (prev && !shouldReparseLastBlock(prev.source, blockSource, true)) {
|
|
36
26
|
return prev.node;
|
|
37
27
|
}
|
|
38
|
-
var
|
|
39
|
-
|
|
40
|
-
});
|
|
41
|
-
parseBySourceRef.current.set(blockSource, el2);
|
|
28
|
+
var el1 = renderMarkdownBlock(blockSource, processor, components);
|
|
29
|
+
cacheRef.current.set(blockSource, el1);
|
|
42
30
|
lastParsedRef.current = {
|
|
43
31
|
source: blockSource,
|
|
44
|
-
node:
|
|
32
|
+
node: el1
|
|
45
33
|
};
|
|
46
|
-
return
|
|
34
|
+
return el1;
|
|
47
35
|
}, [
|
|
48
36
|
variant,
|
|
49
37
|
blockSource,
|
|
@@ -56,6 +44,6 @@ import { shouldReparseLastBlock } from "./lastBlockThrottle";
|
|
|
56
44
|
value: {
|
|
57
45
|
animateBlock: animateBlock
|
|
58
46
|
}
|
|
59
|
-
}, node);
|
|
47
|
+
}, node, animateBlock && /*#__PURE__*/ React.createElement(StreamingCursor, null));
|
|
60
48
|
});
|
|
61
49
|
MarkdownBlockPiece.displayName = 'MarkdownBlockPiece';
|
|
@@ -42,6 +42,24 @@ export var useRendererVarStyle = function useRendererVarStyle(prefixCls) {
|
|
|
42
42
|
transform: 'translateY(0)',
|
|
43
43
|
filter: 'blur(0px)'
|
|
44
44
|
}
|
|
45
|
+
}), _define_property(_obj, '@keyframes markdownStreamingCursorBlink', {
|
|
46
|
+
'0%, 100%': {
|
|
47
|
+
opacity: 0.9,
|
|
48
|
+
boxShadow: '0 0 4px currentColor'
|
|
49
|
+
},
|
|
50
|
+
'50%': {
|
|
51
|
+
opacity: 0,
|
|
52
|
+
boxShadow: '0 0 0 currentColor'
|
|
53
|
+
}
|
|
54
|
+
}), _define_property(_obj, '@keyframes markdownStreamingCursorFadeIn', {
|
|
55
|
+
from: {
|
|
56
|
+
opacity: 0,
|
|
57
|
+
transform: 'scaleY(0.3)'
|
|
58
|
+
},
|
|
59
|
+
to: {
|
|
60
|
+
opacity: 0.9,
|
|
61
|
+
transform: 'scaleY(1)'
|
|
62
|
+
}
|
|
45
63
|
}), _obj;
|
|
46
64
|
});
|
|
47
65
|
};
|