@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.
Files changed (58) hide show
  1. package/dist/Bubble/MessagesContent/MarkdownPreview.d.ts +0 -58
  2. package/dist/Bubble/MessagesContent/MarkdownPreview.js +79 -156
  3. package/dist/Hooks/useAutoScroll.js +6 -4
  4. package/dist/MarkdownEditor/BaseMarkdownEditor.d.ts +1 -50
  5. package/dist/MarkdownEditor/BaseMarkdownEditor.js +11 -55
  6. package/dist/MarkdownEditor/editor/Editor.js +11 -9
  7. package/dist/MarkdownEditor/editor/elements/Code/index.js +1 -0
  8. package/dist/MarkdownEditor/editor/plugins/elements.d.ts +2 -0
  9. package/dist/MarkdownEditor/editor/plugins/elements.js +4 -2
  10. package/dist/MarkdownEditor/editor/plugins/handlePaste.js +46 -35
  11. package/dist/MarkdownEditor/editor/plugins/hotKeyCommands/backspace.js +133 -133
  12. package/dist/MarkdownEditor/editor/plugins/hotKeyCommands/enter.js +156 -140
  13. package/dist/MarkdownEditor/editor/plugins/hotKeyCommands/match.d.ts +2 -1
  14. package/dist/MarkdownEditor/editor/plugins/hotKeyCommands/match.js +23 -4
  15. package/dist/MarkdownEditor/editor/plugins/hotKeyCommands/tab.js +40 -36
  16. package/dist/MarkdownEditor/editor/plugins/index.d.ts +1 -0
  17. package/dist/MarkdownEditor/editor/plugins/index.js +1 -0
  18. package/dist/MarkdownEditor/editor/plugins/useKeyboard.js +46 -44
  19. package/dist/MarkdownEditor/editor/plugins/withCodeTagPlugin.js +1 -13
  20. package/dist/MarkdownEditor/editor/plugins/withMarkdown.js +2 -1
  21. package/dist/MarkdownEditor/editor/plugins/withSanitizeInvalidChildren.d.ts +7 -0
  22. package/dist/MarkdownEditor/editor/plugins/withSanitizeInvalidChildren.js +217 -0
  23. package/dist/MarkdownEditor/editor/store.d.ts +3 -1
  24. package/dist/MarkdownEditor/editor/store.js +15 -29
  25. package/dist/MarkdownEditor/editor/utils/editorCommands.js +98 -17
  26. package/dist/MarkdownEditor/editor/utils/editorUtils.d.ts +11 -0
  27. package/dist/MarkdownEditor/editor/utils/editorUtils.js +43 -6
  28. package/dist/MarkdownEditor/editor/utils/keyboard.js +14 -12
  29. package/dist/MarkdownEditor/types.d.ts +36 -414
  30. package/dist/MarkdownEditor/types.js +1 -4
  31. package/dist/MarkdownInputField/MarkdownInputField.js +2 -0
  32. package/dist/MarkdownInputField/SendActions/index.js +7 -4
  33. package/dist/MarkdownInputField/SendButton/index.d.ts +6 -0
  34. package/dist/MarkdownInputField/SendButton/index.js +6 -0
  35. package/dist/MarkdownInputField/hooks/useMarkdownInputFieldHandlers.d.ts +2 -1
  36. package/dist/MarkdownInputField/hooks/useMarkdownInputFieldHandlers.js +6 -1
  37. package/dist/MarkdownRenderer/AnimationText.d.ts +1 -5
  38. package/dist/MarkdownRenderer/AnimationText.js +2 -8
  39. package/dist/MarkdownRenderer/CharacterQueue.d.ts +0 -2
  40. package/dist/MarkdownRenderer/CharacterQueue.js +2 -2
  41. package/dist/MarkdownRenderer/MarkdownRenderer.d.ts +1 -9
  42. package/dist/MarkdownRenderer/MarkdownRenderer.js +1 -9
  43. package/dist/MarkdownRenderer/StreamingCursor.d.ts +4 -0
  44. package/dist/MarkdownRenderer/StreamingCursor.js +20 -0
  45. package/dist/MarkdownRenderer/markdownReactShared.d.ts +8 -38
  46. package/dist/MarkdownRenderer/markdownReactShared.js +9 -45
  47. package/dist/MarkdownRenderer/renderers/ChartRenderer.js +9 -1
  48. package/dist/MarkdownRenderer/streaming/MarkdownBlockPiece.d.ts +1 -3
  49. package/dist/MarkdownRenderer/streaming/MarkdownBlockPiece.js +16 -28
  50. package/dist/MarkdownRenderer/style.js +18 -0
  51. package/dist/MarkdownRenderer/types.d.ts +14 -86
  52. package/dist/MarkdownRenderer/useStreaming.d.ts +1 -10
  53. package/dist/MarkdownRenderer/useStreaming.js +5 -13
  54. package/dist/ThoughtChainList/MarkdownEditor.d.ts +1 -35
  55. package/dist/ThoughtChainList/MarkdownEditor.js +5 -44
  56. package/dist/Workspace/RealtimeFollow/index.d.ts +3 -0
  57. package/dist/Workspace/RealtimeFollow/index.js +5 -3
  58. 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];
@@ -23,9 +23,7 @@ export declare class CharacterQueue {
23
23
  complete(): void;
24
24
  /** 释放资源 */
25
25
  dispose(): void;
26
- /** 当前已展示的长度 */
27
26
  getDisplayedLength(): number;
28
- /** 完整内容 */
29
27
  getFullContent(): string;
30
28
  private ensureTicking;
31
29
  private tick;
@@ -126,13 +126,13 @@ var DEFAULT_BACKGROUND_BATCH_MULTIPLIER = 10;
126
126
  }
127
127
  },
128
128
  {
129
- /** 当前已展示的长度 */ key: "getDisplayedLength",
129
+ key: "getDisplayedLength",
130
130
  value: function getDisplayedLength() {
131
131
  return this.displayedLength;
132
132
  }
133
133
  },
134
134
  {
135
- /** 完整内容 */ key: "getFullContent",
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,4 @@
1
+ import React from 'react';
2
+ /** 流式闪烁光标,由 MarkdownBlockPiece 控制挂载/卸载 */
3
+ declare const StreamingCursor: React.FC;
4
+ export { StreamingCursor };
@@ -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
- * hast 上标记「最后一个 p」,用于流式时仅该段落播放入场(单块长文时避免全页 p 一起闪)
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, markLastParagraphStreamingTail, renderMarkdownBlock, splitMarkdownBlocks, };
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、末块动画上下文允许且显式开启段落动画时包 AnimationText */ var StreamAnimWrap = function StreamAnimWrap(param) {
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 && !!streamingParagraphAnimation;
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, markLastParagraphStreamingTail, renderMarkdownBlock, splitMarkdownBlocks };
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
- return cancelAnimationFrame(raf);
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
- * 统一的块级渲染:封版与末块使用同一组件类型;按 blockSource 缓存解析结果引用,使 tail→sealed 时与旧 Map 缓存一样复用同一棵 React 子树。
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
- * 统一的块级渲染:封版与末块使用同一组件类型;按 blockSource 缓存解析结果引用,使 tail→sealed 时与旧 Map 缓存一样复用同一棵 React 子树。
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
- /** 完整 parse 结果缓存:键为 block 源串,供 sealed 与 tail 晋升时复用同一引用 */ var parseBySourceRef = useRef(new Map());
11
+ var cacheRef = useRef(new Map());
11
12
  var node = useMemo(function() {
12
- var cached = parseBySourceRef.current.get(blockSource);
13
- if (cached && variant === 'sealed') {
14
- return cached;
15
- }
16
- if (variant === 'sealed') {
17
- var el = renderMarkdownBlock(blockSource, processor, components, {
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: el1
20
+ node: el
31
21
  };
32
- return el1;
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 el2 = renderMarkdownBlock(blockSource, processor, components, {
39
- markStreamingTailParagraph: true
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: el2
32
+ node: el1
45
33
  };
46
- return el2;
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
  };