@ant-design/agentic-ui 2.30.5 → 2.30.6
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.js +6 -4
- package/dist/MarkdownEditor/types.d.ts +11 -1
- package/dist/MarkdownRenderer/AnimationText.d.ts +6 -3
- package/dist/MarkdownRenderer/AnimationText.js +7 -24
- package/dist/MarkdownRenderer/MarkdownRenderer.js +18 -8
- package/dist/MarkdownRenderer/StreamingAnimationContext.d.ts +6 -0
- package/dist/MarkdownRenderer/StreamingAnimationContext.js +2 -0
- package/dist/MarkdownRenderer/types.d.ts +9 -1
- package/dist/MarkdownRenderer/useMarkdownToReact.d.ts +5 -0
- package/dist/MarkdownRenderer/useMarkdownToReact.js +93 -71
- package/package.json +1 -2
|
@@ -125,20 +125,22 @@ import { MessagesContext } from "./BubbleContext";
|
|
|
125
125
|
var _content_includes, _htmlRef_current, _htmlRef_current1, _props_markdownRenderConfig, _props_originData, _props_originData1, _props_originData2, _props_markdownRenderConfig1, _props_markdownRenderConfig2, _props_markdownRenderConfig3;
|
|
126
126
|
// MarkdownRenderer 渲染路径——轻量,不创建 Slate 实例
|
|
127
127
|
if (renderMode === 'markdown') {
|
|
128
|
-
var _props_originData3, _props_markdownRenderConfig4, _props_markdownRenderConfig5, _props_markdownRenderConfig6, _props_markdownRenderConfig7;
|
|
128
|
+
var _props_originData3, _props_markdownRenderConfig4, _props_markdownRenderConfig5, _props_markdownRenderConfig6, _props_markdownRenderConfig7, _props_markdownRenderConfig8, _props_markdownRenderConfig9;
|
|
129
129
|
return /*#__PURE__*/ React.createElement(MarkdownRenderer, {
|
|
130
130
|
content: content,
|
|
131
131
|
streaming: typing,
|
|
132
132
|
isFinished: (_props_originData3 = props.originData) === null || _props_originData3 === void 0 ? void 0 : _props_originData3.isFinished,
|
|
133
133
|
plugins: (_props_markdownRenderConfig4 = props.markdownRenderConfig) === null || _props_markdownRenderConfig4 === void 0 ? void 0 : _props_markdownRenderConfig4.plugins,
|
|
134
|
+
queueOptions: (_props_markdownRenderConfig5 = props.markdownRenderConfig) === null || _props_markdownRenderConfig5 === void 0 ? void 0 : _props_markdownRenderConfig5.queueOptions,
|
|
135
|
+
streamingParagraphAnimation: (_props_markdownRenderConfig6 = props.markdownRenderConfig) === null || _props_markdownRenderConfig6 === void 0 ? void 0 : _props_markdownRenderConfig6.streamingParagraphAnimation,
|
|
134
136
|
fncProps: fncProps,
|
|
135
137
|
style: _object_spread({
|
|
136
138
|
maxWidth: standalone ? '100%' : undefined,
|
|
137
139
|
padding: isPaddingHidden ? 0 : undefined,
|
|
138
140
|
margin: isPaddingHidden ? 0 : undefined
|
|
139
|
-
}, ((
|
|
140
|
-
codeProps: (
|
|
141
|
-
apaasify: (
|
|
141
|
+
}, ((_props_markdownRenderConfig7 = props.markdownRenderConfig) === null || _props_markdownRenderConfig7 === void 0 ? void 0 : _props_markdownRenderConfig7.style) || {}),
|
|
142
|
+
codeProps: (_props_markdownRenderConfig8 = props.markdownRenderConfig) === null || _props_markdownRenderConfig8 === void 0 ? void 0 : _props_markdownRenderConfig8.codeProps,
|
|
143
|
+
apaasify: (_props_markdownRenderConfig9 = props.markdownRenderConfig) === null || _props_markdownRenderConfig9 === void 0 ? void 0 : _props_markdownRenderConfig9.apaasify
|
|
142
144
|
});
|
|
143
145
|
}
|
|
144
146
|
// Slate 渲染路径——保持向后兼容
|
|
@@ -4,7 +4,7 @@ import React from 'react';
|
|
|
4
4
|
import { BaseEditor, Editor, Selection } from 'slate';
|
|
5
5
|
import { HistoryEditor } from 'slate-history';
|
|
6
6
|
import { ReactEditor, RenderElementProps } from 'slate-react';
|
|
7
|
-
import type { RenderMode } from '../MarkdownRenderer/types';
|
|
7
|
+
import type { CharacterQueueOptions, RenderMode } from '../MarkdownRenderer/types';
|
|
8
8
|
import { TagPopupProps } from './editor/elements/TagPopup';
|
|
9
9
|
import { EditorStore } from './editor/store';
|
|
10
10
|
import { InsertAutocompleteProps } from './editor/tools/InsertAutocomplete';
|
|
@@ -473,6 +473,16 @@ export type MarkdownEditorProps = {
|
|
|
473
473
|
/** 自定义链接渲染函数 */
|
|
474
474
|
onClick?: (url?: string) => boolean | void;
|
|
475
475
|
};
|
|
476
|
+
/**
|
|
477
|
+
* MarkdownRenderer 字符队列(仅 `renderMode: 'markdown'` 只读预览时生效)
|
|
478
|
+
* @description 默认关闭逐字 RAF;需要打字机时再设 `{ animate: true, animateTailChars: 50 }` 等
|
|
479
|
+
*/
|
|
480
|
+
queueOptions?: CharacterQueueOptions;
|
|
481
|
+
/**
|
|
482
|
+
* 流式 Markdown 末段淡入(仅 `renderMode: 'markdown'` 时传给 MarkdownRenderer)
|
|
483
|
+
* @description 默认 false;设为 true 时末段使用 AnimationText 入场,可能在高频更新时产生闪动
|
|
484
|
+
*/
|
|
485
|
+
streamingParagraphAnimation?: boolean;
|
|
476
486
|
/**
|
|
477
487
|
* 依赖数组
|
|
478
488
|
* @description 用于控制 MElement 组件是否刷新的依赖数组。当 deps 数组内容发生变化时,MElement 会重新渲染
|
|
@@ -4,6 +4,11 @@ export interface AnimationConfig {
|
|
|
4
4
|
fadeDuration?: number;
|
|
5
5
|
/** 缓动函数,默认 ease-out */
|
|
6
6
|
easing?: string;
|
|
7
|
+
/**
|
|
8
|
+
* 已废弃:单段入场动画模式下不再按 chunk 瘦身 DOM,保留仅为类型兼容
|
|
9
|
+
* @deprecated
|
|
10
|
+
*/
|
|
11
|
+
collapseThreshold?: number;
|
|
7
12
|
}
|
|
8
13
|
export interface AnimationTextProps {
|
|
9
14
|
children: React.ReactNode;
|
|
@@ -12,9 +17,7 @@ export interface AnimationTextProps {
|
|
|
12
17
|
/**
|
|
13
18
|
* 流式文字淡入动画组件。
|
|
14
19
|
*
|
|
15
|
-
*
|
|
16
|
-
* 同一段流式前缀追加只触发**一次**入场动画;后续增量仅更新文案。内容被替换
|
|
17
|
-
* (非前缀增长)时重新播放入场。动画结束后仍用 span 包裹以保持布局稳定。
|
|
20
|
+
* 同一段流式前缀追加(或尾部截断修正)只触发一次入场动画;非前缀替换时重播。
|
|
18
21
|
*/
|
|
19
22
|
declare const AnimationText: React.NamedExoticComponent<AnimationTextProps>;
|
|
20
23
|
export default AnimationText;
|
|
@@ -57,34 +57,21 @@ import React, { useEffect, useMemo, useRef, useState } from "react";
|
|
|
57
57
|
}
|
|
58
58
|
return '';
|
|
59
59
|
};
|
|
60
|
-
/**
|
|
61
|
-
|
|
62
|
-
* 富文本结构(链接、脚注、图片等)在纯文本差分下会丢失结构信息,直接透传更安全。
|
|
63
|
-
*/ var hasElementNode = function hasElementNode1(children) {
|
|
64
|
-
if (children === null || children === undefined || typeof children === 'boolean') return false;
|
|
65
|
-
if (typeof children === 'string' || typeof children === 'number') return false;
|
|
66
|
-
if (Array.isArray(children)) return children.some(hasElementNode);
|
|
67
|
-
return /*#__PURE__*/ React.isValidElement(children);
|
|
60
|
+
/** 流式同一段内:前后文案仅「前缀关系」变化(增长或尾部截断修正) */ var isStreamingCompatible = function isStreamingCompatible(prev, next) {
|
|
61
|
+
return prev.startsWith(next) || next.startsWith(prev);
|
|
68
62
|
};
|
|
69
63
|
/**
|
|
70
64
|
* 流式文字淡入动画组件。
|
|
71
65
|
*
|
|
72
|
-
*
|
|
73
|
-
* 同一段流式前缀追加只触发**一次**入场动画;后续增量仅更新文案。内容被替换
|
|
74
|
-
* (非前缀增长)时重新播放入场。动画结束后仍用 span 包裹以保持布局稳定。
|
|
66
|
+
* 同一段流式前缀追加(或尾部截断修正)只触发一次入场动画;非前缀替换时重播。
|
|
75
67
|
*/ var AnimationText = /*#__PURE__*/ React.memo(function(param) {
|
|
76
68
|
var children = param.children, animationConfig = param.animationConfig;
|
|
77
|
-
var _ref = animationConfig || {}, _ref_fadeDuration = _ref.fadeDuration, fadeDuration = _ref_fadeDuration === void 0 ?
|
|
69
|
+
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;
|
|
78
70
|
var _useState = _sliced_to_array(useState(false), 2), animComplete = _useState[0], setAnimComplete = _useState[1];
|
|
79
71
|
var _useState1 = _sliced_to_array(useState(0), 2), animSession = _useState1[0], setAnimSession = _useState1[1];
|
|
80
72
|
var prevTextRef = useRef('');
|
|
81
73
|
var text = extractText(children);
|
|
82
|
-
var hasElementContent = hasElementNode(children);
|
|
83
74
|
useEffect(function() {
|
|
84
|
-
if (hasElementContent) {
|
|
85
|
-
prevTextRef.current = text;
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
75
|
if (text === prevTextRef.current) return;
|
|
89
76
|
var prev = prevTextRef.current;
|
|
90
77
|
if (!prev) {
|
|
@@ -93,7 +80,7 @@ import React, { useEffect, useMemo, useRef, useState } from "react";
|
|
|
93
80
|
setAnimComplete(false);
|
|
94
81
|
return;
|
|
95
82
|
}
|
|
96
|
-
if (
|
|
83
|
+
if (isStreamingCompatible(prev, text)) {
|
|
97
84
|
prevTextRef.current = text;
|
|
98
85
|
return;
|
|
99
86
|
}
|
|
@@ -103,8 +90,7 @@ import React, { useEffect, useMemo, useRef, useState } from "react";
|
|
|
103
90
|
});
|
|
104
91
|
prevTextRef.current = text;
|
|
105
92
|
}, [
|
|
106
|
-
text
|
|
107
|
-
hasElementContent
|
|
93
|
+
text
|
|
108
94
|
]);
|
|
109
95
|
var handleAnimationEnd = function handleAnimationEnd() {
|
|
110
96
|
return setAnimComplete(true);
|
|
@@ -120,15 +106,12 @@ import React, { useEffect, useMemo, useRef, useState } from "react";
|
|
|
120
106
|
fadeDuration,
|
|
121
107
|
easing
|
|
122
108
|
]);
|
|
123
|
-
|
|
109
|
+
var doneChunkStyle = useMemo(function() {
|
|
124
110
|
return {
|
|
125
111
|
display: 'inline-block',
|
|
126
112
|
color: 'inherit'
|
|
127
113
|
};
|
|
128
114
|
}, []);
|
|
129
|
-
if (hasElementContent) {
|
|
130
|
-
return /*#__PURE__*/ React.createElement(React.Fragment, null, children);
|
|
131
|
-
}
|
|
132
115
|
return animComplete ? /*#__PURE__*/ React.createElement("span", {
|
|
133
116
|
style: doneChunkStyle
|
|
134
117
|
}, children) : /*#__PURE__*/ React.createElement("span", {
|
|
@@ -236,7 +236,7 @@ var SCHEMA_LANGUAGES = new Set([
|
|
|
236
236
|
* - Markdown → hast → React 元素树(hast-util-to-jsx-runtime)
|
|
237
237
|
* - 特殊块(code / mermaid / chart / katex)通过组件映射拦截渲染
|
|
238
238
|
*/ var InternalMarkdownRenderer = /*#__PURE__*/ forwardRef(function(props, ref) {
|
|
239
|
-
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, apaasify = props.apaasify;
|
|
239
|
+
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;
|
|
240
240
|
var getPrefixCls = useContext(ConfigProvider.ConfigContext).getPrefixCls;
|
|
241
241
|
// 复用 MarkdownEditor 的 CSS 前缀和样式,保持渲染一致性
|
|
242
242
|
var prefixCls = getPrefixCls('agentic-md-editor', customPrefixCls);
|
|
@@ -249,6 +249,7 @@ var SCHEMA_LANGUAGES = new Set([
|
|
|
249
249
|
var containerRef = useRef(null);
|
|
250
250
|
var _useState = _sliced_to_array(useState(content || ''), 2), displayedContent = _useState[0], setDisplayedContent = _useState[1];
|
|
251
251
|
var queueRef = useRef(null);
|
|
252
|
+
/** 与 CharacterQueue 构造参数同步,避免 queueOptions 变更后仍用旧队列行为 */ var queueOptsSigRef = useRef('');
|
|
252
253
|
useImperativeHandle(ref, function() {
|
|
253
254
|
return {
|
|
254
255
|
nativeElement: containerRef.current,
|
|
@@ -263,10 +264,12 @@ var SCHEMA_LANGUAGES = new Set([
|
|
|
263
264
|
}, [
|
|
264
265
|
plugins
|
|
265
266
|
]);
|
|
266
|
-
//
|
|
267
|
+
// 字符队列:默认关闭逐字动画,避免 RAF 每帧全量重解析 Markdown 导致整页闪动。
|
|
268
|
+
// 需要打字机效果时显式传入 queueOptions={{ animate: true, animateTailChars?: number }}。
|
|
267
269
|
var resolvedQueueOptions = useMemo(function() {
|
|
268
270
|
return streaming ? _object_spread({
|
|
269
|
-
|
|
271
|
+
animate: false,
|
|
272
|
+
animateTailChars: undefined
|
|
270
273
|
}, queueOptions) : queueOptions;
|
|
271
274
|
}, [
|
|
272
275
|
streaming,
|
|
@@ -274,17 +277,23 @@ var SCHEMA_LANGUAGES = new Set([
|
|
|
274
277
|
]);
|
|
275
278
|
useEffect(function() {
|
|
276
279
|
if (!streaming) {
|
|
277
|
-
|
|
280
|
+
var _queueRef_current;
|
|
278
281
|
setDisplayedContent(content || '');
|
|
282
|
+
(_queueRef_current = queueRef.current) === null || _queueRef_current === void 0 ? void 0 : _queueRef_current.dispose();
|
|
283
|
+
queueRef.current = null;
|
|
284
|
+
queueOptsSigRef.current = '';
|
|
279
285
|
return;
|
|
280
286
|
}
|
|
281
|
-
|
|
287
|
+
var sig = JSON.stringify(resolvedQueueOptions !== null && resolvedQueueOptions !== void 0 ? resolvedQueueOptions : {});
|
|
288
|
+
if (!queueRef.current || sig !== queueOptsSigRef.current) {
|
|
289
|
+
var _queueRef_current1;
|
|
290
|
+
(_queueRef_current1 = queueRef.current) === null || _queueRef_current1 === void 0 ? void 0 : _queueRef_current1.dispose();
|
|
282
291
|
queueRef.current = new CharacterQueue(function(displayed) {
|
|
283
292
|
return setDisplayedContent(displayed);
|
|
284
293
|
}, resolvedQueueOptions);
|
|
294
|
+
queueOptsSigRef.current = sig;
|
|
285
295
|
}
|
|
286
296
|
queueRef.current.push(content || '');
|
|
287
|
-
return undefined;
|
|
288
297
|
}, [
|
|
289
298
|
content,
|
|
290
299
|
streaming,
|
|
@@ -347,7 +356,8 @@ var SCHEMA_LANGUAGES = new Set([
|
|
|
347
356
|
components: components,
|
|
348
357
|
prefixCls: prefixCls,
|
|
349
358
|
linkConfig: linkConfig,
|
|
350
|
-
streaming: streaming
|
|
359
|
+
streaming: streaming,
|
|
360
|
+
streamingParagraphAnimation: streamingParagraphAnimation
|
|
351
361
|
});
|
|
352
362
|
return wrapVarSSR(wrapSSR(wrapContentSSR(/*#__PURE__*/ React.createElement("div", {
|
|
353
363
|
ref: containerRef,
|
|
@@ -359,7 +369,7 @@ var SCHEMA_LANGUAGES = new Set([
|
|
|
359
369
|
display: 'block'
|
|
360
370
|
}
|
|
361
371
|
}, /*#__PURE__*/ React.createElement("div", {
|
|
362
|
-
className: clsx(contentCls, hashId),
|
|
372
|
+
className: clsx(contentCls, "".concat(contentCls, "-markdown-readonly"), hashId),
|
|
363
373
|
style: {
|
|
364
374
|
whiteSpace: 'normal',
|
|
365
375
|
wordWrap: 'normal'
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
/** 仅末块为 true:流式 Markdown 只对「当前生长块」播放入场,避免全页段落/表格单元格一起闪动 */
|
|
3
|
+
export interface StreamingAnimationContextValue {
|
|
4
|
+
animateBlock: boolean;
|
|
5
|
+
}
|
|
6
|
+
export declare const StreamingAnimationContext: React.Context<StreamingAnimationContextValue | null>;
|
|
@@ -4,7 +4,10 @@ import type { MarkdownEditorPlugin } from '../MarkdownEditor/plugin';
|
|
|
4
4
|
export interface CharacterQueueOptions {
|
|
5
5
|
/** 每帧输出的最大字符数,默认 3 */
|
|
6
6
|
charsPerFrame?: number;
|
|
7
|
-
/**
|
|
7
|
+
/**
|
|
8
|
+
* 是否启用 CharacterQueue 逐字输出(RAF 驱动)。
|
|
9
|
+
* MarkdownRenderer 流式默认合并为 `false`,避免每帧全量重解析导致整页闪动;需打字机时再设为 `true`。
|
|
10
|
+
*/
|
|
8
11
|
animate?: boolean;
|
|
9
12
|
/**
|
|
10
13
|
* 仅对末尾 N 个字符做动画,前面内容立即展示。
|
|
@@ -65,6 +68,11 @@ export interface MarkdownRendererProps {
|
|
|
65
68
|
/** 自定义链接点击处理,返回 false 可阻止默认跳转 */
|
|
66
69
|
onClick?: (url?: string) => boolean | void;
|
|
67
70
|
};
|
|
71
|
+
/**
|
|
72
|
+
* 流式时是否为生长中的末段启用淡入(AnimationText)。
|
|
73
|
+
* 默认 false,避免重解析时整页闪动;需要段落入场效果时再设为 true。
|
|
74
|
+
*/
|
|
75
|
+
streamingParagraphAnimation?: boolean;
|
|
68
76
|
/** Apaasify / Schema 自定义渲染 */
|
|
69
77
|
apaasify?: {
|
|
70
78
|
enable?: boolean;
|
|
@@ -14,6 +14,11 @@ interface UseMarkdownToReactOptions {
|
|
|
14
14
|
};
|
|
15
15
|
/** 是否处于流式状态,用于最后一个块的打字动画 */
|
|
16
16
|
streaming?: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* 流式时是否对「生长中的末段」启用段落淡入(AnimationText)。
|
|
19
|
+
* 默认 false:重解析时频繁触发动画易导致整页闪动;需要时再显式传入 true。
|
|
20
|
+
*/
|
|
21
|
+
streamingParagraphAnimation?: boolean;
|
|
17
22
|
}
|
|
18
23
|
export declare const useMarkdownToReact: (content: string, options?: UseMarkdownToReactOptions) => React.ReactNode;
|
|
19
24
|
/**
|
|
@@ -122,7 +122,7 @@ function _unsupported_iterable_to_array(o, minLen) {
|
|
|
122
122
|
}
|
|
123
123
|
import { Checkbox, Image } from "antd";
|
|
124
124
|
import { toJsxRuntime } from "hast-util-to-jsx-runtime";
|
|
125
|
-
import React, { useMemo, useRef } from "react";
|
|
125
|
+
import React, { useContext, useMemo, useRef } from "react";
|
|
126
126
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
127
127
|
import rehypeKatex from "rehype-katex";
|
|
128
128
|
import rehypeRaw from "rehype-raw";
|
|
@@ -141,6 +141,7 @@ import { REMARK_REHYPE_DIRECTIVE_HANDLERS } from "../MarkdownEditor/editor/utils
|
|
|
141
141
|
import { parseChineseCurrencyToNumber } from "../Plugins/chart/utils";
|
|
142
142
|
import { ToolUseBarThink } from "../ToolUseBarThink";
|
|
143
143
|
import AnimationText from "./AnimationText";
|
|
144
|
+
import { StreamingAnimationContext } from "./StreamingAnimationContext";
|
|
144
145
|
var INLINE_MATH_WITH_SINGLE_DOLLAR = {
|
|
145
146
|
singleDollarTextMath: true
|
|
146
147
|
};
|
|
@@ -432,14 +433,26 @@ var extractLanguageFromClassName = function extractLanguageFromClassName(classNa
|
|
|
432
433
|
*
|
|
433
434
|
* MarkdownEditor 的 Slate 元素使用 data-be 属性和 prefixCls 类名,
|
|
434
435
|
* 这里为原生 HTML 标签添加相同的属性,使共用的 CSS 能正确命中。
|
|
435
|
-
*/ var buildEditorAlignedComponents = function buildEditorAlignedComponents(prefixCls, userComponents, streaming, linkConfig) {
|
|
436
|
+
*/ var buildEditorAlignedComponents = function buildEditorAlignedComponents(prefixCls, userComponents, streaming, linkConfig, streamingParagraphAnimation) {
|
|
436
437
|
var listCls = "".concat(prefixCls, "-list");
|
|
437
438
|
var tableCls = "".concat(prefixCls, "-content-table");
|
|
438
439
|
var contentCls = prefixCls; // e.g. ant-agentic-md-editor-content
|
|
440
|
+
/** 仅当 streaming、末块动画上下文允许且显式开启段落动画时包 AnimationText */ var StreamAnimWrap = function StreamAnimWrap(param) {
|
|
441
|
+
var children = param.children;
|
|
442
|
+
var _ref;
|
|
443
|
+
var ctx = useContext(StreamingAnimationContext);
|
|
444
|
+
var animateBlock = (_ref = ctx === null || ctx === void 0 ? void 0 : ctx.animateBlock) !== null && _ref !== void 0 ? _ref : true;
|
|
445
|
+
var allow = !!streaming && animateBlock && !!streamingParagraphAnimation;
|
|
446
|
+
if (!allow) return children;
|
|
447
|
+
return jsx(AnimationText, {
|
|
448
|
+
children: children
|
|
449
|
+
});
|
|
450
|
+
};
|
|
451
|
+
StreamAnimWrap.displayName = 'StreamAnimWrap';
|
|
439
452
|
var wrapAnimation = function wrapAnimation(children) {
|
|
440
|
-
return
|
|
453
|
+
return jsx(StreamAnimWrap, {
|
|
441
454
|
children: children
|
|
442
|
-
})
|
|
455
|
+
});
|
|
443
456
|
};
|
|
444
457
|
return _object_spread({
|
|
445
458
|
// ================================================================
|
|
@@ -464,7 +477,7 @@ var extractLanguageFromClassName = function extractLanguageFromClassName(classNa
|
|
|
464
477
|
return jsx('h1', _object_spread_props(_object_spread({}, rest), {
|
|
465
478
|
'data-be': 'head',
|
|
466
479
|
'data-testid': 'markdown-heading-1',
|
|
467
|
-
children:
|
|
480
|
+
children: children
|
|
468
481
|
}));
|
|
469
482
|
},
|
|
470
483
|
h2: function h2(props) {
|
|
@@ -475,7 +488,7 @@ var extractLanguageFromClassName = function extractLanguageFromClassName(classNa
|
|
|
475
488
|
return jsx('h2', _object_spread_props(_object_spread({}, rest), {
|
|
476
489
|
'data-be': 'head',
|
|
477
490
|
'data-testid': 'markdown-heading-2',
|
|
478
|
-
children:
|
|
491
|
+
children: children
|
|
479
492
|
}));
|
|
480
493
|
},
|
|
481
494
|
h3: function h3(props) {
|
|
@@ -486,7 +499,7 @@ var extractLanguageFromClassName = function extractLanguageFromClassName(classNa
|
|
|
486
499
|
return jsx('h3', _object_spread_props(_object_spread({}, rest), {
|
|
487
500
|
'data-be': 'head',
|
|
488
501
|
'data-testid': 'markdown-heading-3',
|
|
489
|
-
children:
|
|
502
|
+
children: children
|
|
490
503
|
}));
|
|
491
504
|
},
|
|
492
505
|
h4: function h4(props) {
|
|
@@ -497,7 +510,7 @@ var extractLanguageFromClassName = function extractLanguageFromClassName(classNa
|
|
|
497
510
|
return jsx('h4', _object_spread_props(_object_spread({}, rest), {
|
|
498
511
|
'data-be': 'head',
|
|
499
512
|
'data-testid': 'markdown-heading-4',
|
|
500
|
-
children:
|
|
513
|
+
children: children
|
|
501
514
|
}));
|
|
502
515
|
},
|
|
503
516
|
h5: function h5(props) {
|
|
@@ -508,7 +521,7 @@ var extractLanguageFromClassName = function extractLanguageFromClassName(classNa
|
|
|
508
521
|
return jsx('h5', _object_spread_props(_object_spread({}, rest), {
|
|
509
522
|
'data-be': 'head',
|
|
510
523
|
'data-testid': 'markdown-heading-5',
|
|
511
|
-
children:
|
|
524
|
+
children: children
|
|
512
525
|
}));
|
|
513
526
|
},
|
|
514
527
|
h6: function h6(props) {
|
|
@@ -519,7 +532,7 @@ var extractLanguageFromClassName = function extractLanguageFromClassName(classNa
|
|
|
519
532
|
return jsx('h6', _object_spread_props(_object_spread({}, rest), {
|
|
520
533
|
'data-be': 'head',
|
|
521
534
|
'data-testid': 'markdown-heading-6',
|
|
522
|
-
children:
|
|
535
|
+
children: children
|
|
523
536
|
}));
|
|
524
537
|
},
|
|
525
538
|
blockquote: function blockquote(props) {
|
|
@@ -607,7 +620,7 @@ var extractLanguageFromClassName = function extractLanguageFromClassName(classNa
|
|
|
607
620
|
className: "".concat(listCls, "-item"),
|
|
608
621
|
'data-be': 'list-item',
|
|
609
622
|
'data-testid': 'markdown-list-item',
|
|
610
|
-
children:
|
|
623
|
+
children: children
|
|
611
624
|
}));
|
|
612
625
|
},
|
|
613
626
|
table: function table(props) {
|
|
@@ -686,7 +699,7 @@ var extractLanguageFromClassName = function extractLanguageFromClassName(classNa
|
|
|
686
699
|
whiteSpace: 'normal',
|
|
687
700
|
maxWidth: '20%'
|
|
688
701
|
},
|
|
689
|
-
children:
|
|
702
|
+
children: children
|
|
690
703
|
}));
|
|
691
704
|
},
|
|
692
705
|
// input[type=checkbox]:task list 的 checkbox(兜底,主逻辑在 li 中)
|
|
@@ -1061,13 +1074,31 @@ var extractLanguageFromClassName = function extractLanguageFromClassName(classNa
|
|
|
1061
1074
|
}
|
|
1062
1075
|
}, userComponents);
|
|
1063
1076
|
};
|
|
1077
|
+
/**
|
|
1078
|
+
* 在 hast 上标记「最后一个 p」,用于流式时仅该段落播放入场(单块长文时避免全页 p 一起闪)
|
|
1079
|
+
*/ var markLastParagraphStreamingTail = function markLastParagraphStreamingTail(hast) {
|
|
1080
|
+
var paragraphs = [];
|
|
1081
|
+
visit(hast, 'element', function(node) {
|
|
1082
|
+
if (node.tagName === 'p') {
|
|
1083
|
+
paragraphs.push(node);
|
|
1084
|
+
}
|
|
1085
|
+
});
|
|
1086
|
+
var last = paragraphs[paragraphs.length - 1];
|
|
1087
|
+
if (last) {
|
|
1088
|
+
last.properties = last.properties || {};
|
|
1089
|
+
last.properties.dataStreamingTail = true;
|
|
1090
|
+
}
|
|
1091
|
+
};
|
|
1064
1092
|
/**
|
|
1065
1093
|
* 将单个 markdown 片段转为 React 元素(内部函数)
|
|
1066
|
-
*/ var renderMarkdownBlock = function renderMarkdownBlock(blockContent, processor, components) {
|
|
1094
|
+
*/ var renderMarkdownBlock = function renderMarkdownBlock(blockContent, processor, components, blockOpts) {
|
|
1067
1095
|
if (!blockContent.trim()) return null;
|
|
1068
1096
|
try {
|
|
1069
1097
|
var mdast = processor.parse(blockContent);
|
|
1070
1098
|
var hast = processor.runSync(mdast);
|
|
1099
|
+
if (blockOpts === null || blockOpts === void 0 ? void 0 : blockOpts.markStreamingTailParagraph) {
|
|
1100
|
+
markLastParagraphStreamingTail(hast);
|
|
1101
|
+
}
|
|
1071
1102
|
return toJsxRuntime(hast, {
|
|
1072
1103
|
Fragment: Fragment,
|
|
1073
1104
|
jsx: jsx,
|
|
@@ -1079,62 +1110,47 @@ var extractLanguageFromClassName = function extractLanguageFromClassName(classNa
|
|
|
1079
1110
|
return null;
|
|
1080
1111
|
}
|
|
1081
1112
|
};
|
|
1082
|
-
/** 流式未闭合围栏内,空行后的下一行是否仍像围栏内代码(JSON 等)延续 */ var lineLooksLikeFenceCodeContinuation = function lineLooksLikeFenceCodeContinuation(rawLine) {
|
|
1083
|
-
var t = rawLine.trimStart();
|
|
1084
|
-
if (!t) {
|
|
1085
|
-
return true;
|
|
1086
|
-
}
|
|
1087
|
-
if (t.startsWith('```') || t.startsWith('~~~')) {
|
|
1088
|
-
return true;
|
|
1089
|
-
}
|
|
1090
|
-
var c = t[0];
|
|
1091
|
-
return c === '{' || c === '}' || c === '[' || c === ']' || c === '"' || c === "'" || c === '`' || c === '-' || c === ',' || c >= '0' && c <= '9';
|
|
1092
|
-
};
|
|
1093
1113
|
/**
|
|
1094
1114
|
* 将 markdown 按块(双换行)拆分,尊重代码围栏边界。
|
|
1095
1115
|
* 返回的每个块是一个独立的 markdown 片段,可单独解析。
|
|
1096
|
-
|
|
1097
|
-
* 流式且围栏未闭合时,inFence 会一直为 true,段间 `\n\n` 在按行拆分时只出现一个空行,
|
|
1098
|
-
* 无法用「连续两个空行」检测。此时在空行处前瞻下一行:若不像围栏内代码延续则虚拟闭合围栏,
|
|
1099
|
-
* 使末块能变为非末块且缓存键与先前一致。
|
|
1100
|
-
*/ var splitMarkdownBlocks = function splitMarkdownBlocks(content, streaming) {
|
|
1116
|
+
*/ var splitMarkdownBlocks = function splitMarkdownBlocks(content) {
|
|
1101
1117
|
var lines = content.split('\n');
|
|
1102
1118
|
var blocks = [];
|
|
1103
1119
|
var current = [];
|
|
1104
1120
|
var inFence = false;
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
var
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
if (body.length > 0) {
|
|
1122
|
-
blocks.push(body.join('\n'));
|
|
1121
|
+
var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
|
|
1122
|
+
try {
|
|
1123
|
+
for(var _iterator = lines[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
|
|
1124
|
+
var line = _step.value;
|
|
1125
|
+
var trimmed = line.trimStart();
|
|
1126
|
+
if (trimmed.startsWith('```') || trimmed.startsWith('~~~')) {
|
|
1127
|
+
inFence = !inFence;
|
|
1128
|
+
}
|
|
1129
|
+
if (!inFence && line === '' && current.length > 0) {
|
|
1130
|
+
var prev = current[current.length - 1];
|
|
1131
|
+
if (prev === '') {
|
|
1132
|
+
// 触发分割的是「第二个连续空行」,不应并入上一块末尾,否则与单块解析结果字符串不一致、缓存失效
|
|
1133
|
+
var withoutTrailingBlank = current.slice(0, -1);
|
|
1134
|
+
blocks.push(withoutTrailingBlank.join('\n'));
|
|
1135
|
+
current = [];
|
|
1136
|
+
continue;
|
|
1123
1137
|
}
|
|
1124
|
-
current = [];
|
|
1125
|
-
inFence = false;
|
|
1126
|
-
continue;
|
|
1127
1138
|
}
|
|
1139
|
+
current.push(line);
|
|
1128
1140
|
}
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1141
|
+
} catch (err) {
|
|
1142
|
+
_didIteratorError = true;
|
|
1143
|
+
_iteratorError = err;
|
|
1144
|
+
} finally{
|
|
1145
|
+
try {
|
|
1146
|
+
if (!_iteratorNormalCompletion && _iterator.return != null) {
|
|
1147
|
+
_iterator.return();
|
|
1148
|
+
}
|
|
1149
|
+
} finally{
|
|
1150
|
+
if (_didIteratorError) {
|
|
1151
|
+
throw _iteratorError;
|
|
1135
1152
|
}
|
|
1136
1153
|
}
|
|
1137
|
-
current.push(line);
|
|
1138
1154
|
}
|
|
1139
1155
|
if (current.length > 0) {
|
|
1140
1156
|
blocks.push(current.join('\n'));
|
|
@@ -1181,12 +1197,13 @@ export var useMarkdownToReact = function useMarkdownToReact(content, options) {
|
|
|
1181
1197
|
var prefixCls = (options === null || options === void 0 ? void 0 : options.prefixCls) || 'ant-agentic-md-editor';
|
|
1182
1198
|
var components = useMemo(function() {
|
|
1183
1199
|
var userComponents = (options === null || options === void 0 ? void 0 : options.components) || {};
|
|
1184
|
-
return buildEditorAlignedComponents(prefixCls, userComponents, options === null || options === void 0 ? void 0 : options.streaming, options === null || options === void 0 ? void 0 : options.linkConfig);
|
|
1200
|
+
return buildEditorAlignedComponents(prefixCls, userComponents, options === null || options === void 0 ? void 0 : options.streaming, options === null || options === void 0 ? void 0 : options.linkConfig, options === null || options === void 0 ? void 0 : options.streamingParagraphAnimation);
|
|
1185
1201
|
}, [
|
|
1186
1202
|
prefixCls,
|
|
1187
1203
|
options === null || options === void 0 ? void 0 : options.components,
|
|
1188
1204
|
options === null || options === void 0 ? void 0 : options.streaming,
|
|
1189
|
-
options === null || options === void 0 ? void 0 : options.linkConfig
|
|
1205
|
+
options === null || options === void 0 ? void 0 : options.linkConfig,
|
|
1206
|
+
options === null || options === void 0 ? void 0 : options.streamingParagraphAnimation
|
|
1190
1207
|
]);
|
|
1191
1208
|
return useMemo(function() {
|
|
1192
1209
|
if (!content) {
|
|
@@ -1201,11 +1218,20 @@ export var useMarkdownToReact = function useMarkdownToReact(content, options) {
|
|
|
1201
1218
|
prevContentRef.current = content;
|
|
1202
1219
|
try {
|
|
1203
1220
|
var preprocessed = content.replace(new RegExp(JINJA_DOLLAR_PLACEHOLDER, 'g'), '$');
|
|
1204
|
-
var blocks = splitMarkdownBlocks(preprocessed
|
|
1221
|
+
var blocks = splitMarkdownBlocks(preprocessed);
|
|
1205
1222
|
if (blocks.length === 0) return null;
|
|
1206
1223
|
var cache = blockCacheRef.current;
|
|
1207
1224
|
var newCache = new Map();
|
|
1208
1225
|
var elements = [];
|
|
1226
|
+
var wrapBlockScope = function wrapBlockScope(node, key, animateBlock) {
|
|
1227
|
+
return jsx(StreamingAnimationContext.Provider, {
|
|
1228
|
+
key: key,
|
|
1229
|
+
value: {
|
|
1230
|
+
animateBlock: animateBlock
|
|
1231
|
+
},
|
|
1232
|
+
children: node
|
|
1233
|
+
});
|
|
1234
|
+
};
|
|
1209
1235
|
var KEY_PREFIX_LEN = 64;
|
|
1210
1236
|
for(var i = 0; i < blocks.length; i++){
|
|
1211
1237
|
var block = blocks[i];
|
|
@@ -1220,9 +1246,7 @@ export var useMarkdownToReact = function useMarkdownToReact(content, options) {
|
|
|
1220
1246
|
var cached = cache.get(block);
|
|
1221
1247
|
if (cached && cached.source === block) {
|
|
1222
1248
|
newCache.set(block, cached);
|
|
1223
|
-
elements.push(
|
|
1224
|
-
children: cached.element
|
|
1225
|
-
}, stableKey));
|
|
1249
|
+
elements.push(wrapBlockScope(cached.element, stableKey, false));
|
|
1226
1250
|
continue;
|
|
1227
1251
|
}
|
|
1228
1252
|
}
|
|
@@ -1233,22 +1257,20 @@ export var useMarkdownToReact = function useMarkdownToReact(content, options) {
|
|
|
1233
1257
|
source: lastBlockRef.current.source,
|
|
1234
1258
|
element: lastBlockRef.current.element
|
|
1235
1259
|
});
|
|
1236
|
-
elements.push(
|
|
1237
|
-
children: lastBlockRef.current.element
|
|
1238
|
-
}, stableKey));
|
|
1260
|
+
elements.push(wrapBlockScope(lastBlockRef.current.element, stableKey, !!(options === null || options === void 0 ? void 0 : options.streaming)));
|
|
1239
1261
|
continue;
|
|
1240
1262
|
}
|
|
1241
1263
|
}
|
|
1242
|
-
var element = renderMarkdownBlock(block, processor, components
|
|
1264
|
+
var element = renderMarkdownBlock(block, processor, components, {
|
|
1265
|
+
markStreamingTailParagraph: isLast && !!(options === null || options === void 0 ? void 0 : options.streaming)
|
|
1266
|
+
});
|
|
1243
1267
|
var entry = {
|
|
1244
1268
|
source: block,
|
|
1245
1269
|
element: element
|
|
1246
1270
|
};
|
|
1247
1271
|
newCache.set(block, entry);
|
|
1248
1272
|
if (isLast) lastBlockRef.current = entry;
|
|
1249
|
-
elements.push(
|
|
1250
|
-
children: element
|
|
1251
|
-
}, stableKey));
|
|
1273
|
+
elements.push(wrapBlockScope(element, stableKey, isLast && !!(options === null || options === void 0 ? void 0 : options.streaming)));
|
|
1252
1274
|
}
|
|
1253
1275
|
blockCacheRef.current = newCache;
|
|
1254
1276
|
return jsxs(Fragment, {
|
|
@@ -1275,7 +1297,7 @@ export var useMarkdownToReact = function useMarkdownToReact(content, options) {
|
|
|
1275
1297
|
var mdast = processor.parse(preprocessed);
|
|
1276
1298
|
var hast = processor.runSync(mdast);
|
|
1277
1299
|
var userComps = components || {};
|
|
1278
|
-
var allComponents = buildEditorAlignedComponents('ant-agentic-md-editor', userComps, false);
|
|
1300
|
+
var allComponents = buildEditorAlignedComponents('ant-agentic-md-editor', userComps, false, undefined, false);
|
|
1279
1301
|
return toJsxRuntime(hast, {
|
|
1280
1302
|
Fragment: Fragment,
|
|
1281
1303
|
jsx: jsx,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ant-design/agentic-ui",
|
|
3
|
-
"version": "2.30.
|
|
3
|
+
"version": "2.30.6",
|
|
4
4
|
"description": "面向智能体的 UI 组件库,提供多步推理可视化、工具调用展示、任务执行协同等 Agentic UI 能力",
|
|
5
5
|
"repository": "git@github.com:ant-design/agentic-ui.git",
|
|
6
6
|
"license": "MIT",
|
|
@@ -24,7 +24,6 @@
|
|
|
24
24
|
"lint:css": "stylelint \"{src,test}/**/*.{css,less}\"",
|
|
25
25
|
"lint:es": "eslint \"{src,test}/**/*.{js,jsx,ts,tsx}\"",
|
|
26
26
|
"prepare": "husky install && dumi setup",
|
|
27
|
-
"prepublishOnly": "npm run build && npm run test",
|
|
28
27
|
"prettier": "prettier --write \"{src,docs,test}/**/*.{js,jsx,ts,tsx,css,less,json,md}\"",
|
|
29
28
|
"preview": "pnpm dumi preview",
|
|
30
29
|
"report:demo": "node scripts/generateDemoReport.js",
|