@ant-design/agentic-ui 2.30.12 → 2.30.14

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 (51) hide show
  1. package/dist/Bubble/AIBubble.js +32 -18
  2. package/dist/Bubble/ContentFilemapView.d.ts +14 -0
  3. package/dist/Bubble/ContentFilemapView.js +95 -0
  4. package/dist/Bubble/MessagesContent/MarkdownPreview.js +3 -2
  5. package/dist/Bubble/UserBubble.js +48 -6
  6. package/dist/Bubble/extractFilemapBlocks.d.ts +17 -0
  7. package/dist/Bubble/extractFilemapBlocks.js +23 -0
  8. package/dist/Bubble/type.d.ts +3 -0
  9. package/dist/Hooks/useLanguage.d.ts +2 -0
  10. package/dist/I18n/locales.d.ts +2 -0
  11. package/dist/I18n/locales.js +5 -1
  12. package/dist/MarkdownEditor/editor/elements/AgenticUiBlocks/agenticUiEmbedUtils.d.ts +5 -1
  13. package/dist/MarkdownEditor/editor/elements/AgenticUiBlocks/agenticUiEmbedUtils.js +10 -2
  14. package/dist/MarkdownEditor/editor/elements/Code/index.js +22 -14
  15. package/dist/MarkdownEditor/editor/parser/constants.d.ts +10 -0
  16. package/dist/MarkdownEditor/editor/parser/constants.js +46 -0
  17. package/dist/MarkdownEditor/editor/parser/parserMarkdownToSlateNode.js +3 -1
  18. package/dist/MarkdownEditor/editor/parser/parserSlateNodeToMarkdown.js +11 -0
  19. package/dist/MarkdownEditor/editor/utils/markdownToHtml.js +6 -4
  20. package/dist/MarkdownEditor/types.d.ts +6 -0
  21. package/dist/MarkdownInputField/AttachmentButton/AttachmentFileList/AttachmentFileIcon.js +3 -1
  22. package/dist/MarkdownInputField/AttachmentButton/AttachmentFileList/AttachmentFileListItem.js +2 -2
  23. package/dist/MarkdownInputField/AttachmentButton/AttachmentFileList/index.js +6 -1
  24. package/dist/MarkdownInputField/AttachmentButton/AttachmentFileList/style.js +11 -1
  25. package/dist/MarkdownInputField/AttachmentButton/index.d.ts +12 -0
  26. package/dist/MarkdownInputField/AttachmentButton/index.js +23 -13
  27. package/dist/MarkdownInputField/FileMapView/FileMapViewItem.js +20 -1
  28. package/dist/MarkdownInputField/FileMapView/index.d.ts +13 -1
  29. package/dist/MarkdownInputField/FileMapView/index.js +57 -18
  30. package/dist/MarkdownInputField/FileMapView/style.js +6 -0
  31. package/dist/MarkdownInputField/FileUploadManager/index.js +4 -26
  32. package/dist/MarkdownInputField/style.js +7 -0
  33. package/dist/MarkdownRenderer/MarkdownRenderer.js +10 -6
  34. package/dist/MarkdownRenderer/index.d.ts +1 -1
  35. package/dist/MarkdownRenderer/renderers/AgenticUiFileMapBlockRenderer.d.ts +4 -2
  36. package/dist/MarkdownRenderer/renderers/AgenticUiFileMapBlockRenderer.js +47 -5
  37. package/dist/MarkdownRenderer/renderers/ChartRenderer.js +9 -0
  38. package/dist/MarkdownRenderer/streaming/useStreamingMarkdownReact.js +2 -2
  39. package/dist/MarkdownRenderer/types.d.ts +45 -2
  40. package/dist/MarkdownRenderer/useMarkdownToReact.js +2 -2
  41. package/dist/Plugins/chart/ChartRender.js +30 -9
  42. package/dist/Plugins/chart/DonutChart/index.js +21 -7
  43. package/dist/Plugins/chart/HistogramChart/index.d.ts +5 -1
  44. package/dist/Plugins/chart/HistogramChart/index.js +79 -12
  45. package/dist/Plugins/chart/ScatterChart/index.d.ts +8 -0
  46. package/dist/Plugins/chart/ScatterChart/index.js +78 -8
  47. package/dist/Plugins/chart/components/ChartContainer/ChartErrorBoundary.d.ts +4 -0
  48. package/dist/Plugins/code/components/AceEditor.js +69 -8
  49. package/dist/Plugins/code/components/CodeRenderer.js +0 -1
  50. package/dist/Workspace/Browser/index.js +3 -1
  51. package/package.json +1 -1
@@ -1152,6 +1152,17 @@ export var isMix = function isMix(t) {
1152
1152
  } catch (e) {
1153
1153
  console.warn('Invalid code object', e);
1154
1154
  }
1155
+ } else if ((node === null || node === void 0 ? void 0 : node.type) === 'code') {
1156
+ var _node_children;
1157
+ // 对于普通代码块(type === 'code'),优先从 Slate children 中读取文本
1158
+ // 因为用户编辑后 Slate 只更新 children,而 value 保留的是初始解析值
1159
+ var childrenText = node === null || node === void 0 ? void 0 : (_node_children = node.children) === null || _node_children === void 0 ? void 0 : _node_children.map(function(child) {
1160
+ var _ref;
1161
+ return (_ref = child === null || child === void 0 ? void 0 : child.text) !== null && _ref !== void 0 ? _ref : '';
1162
+ }).join('');
1163
+ if (childrenText !== undefined && childrenText !== null) {
1164
+ code = childrenText;
1165
+ }
1155
1166
  }
1156
1167
  // 如果语言是 think,转换为 <think> 标签
1157
1168
  if (node.language === 'think') {
@@ -174,7 +174,7 @@ import remarkParse from "remark-parse";
174
174
  import remarkRehype from "remark-rehype";
175
175
  import { unified } from "unified";
176
176
  import { visit } from "unist-util-visit";
177
- import { JINJA_DOLLAR_PLACEHOLDER } from "../parser/constants";
177
+ import { JINJA_DOLLAR_PLACEHOLDER, preprocessNormalizeLeafToContainerDirective } from "../parser/constants";
178
178
  import { remarkDirectiveContainer } from "../parser/remarkDirectiveContainer";
179
179
  import remarkDirectiveContainersOnly from "../parser/remarkDirectiveContainersOnly";
180
180
  import { convertParagraphToImage, fixStrongWithSpecialChars, protectJinjaDollarInText } from "../parser/remarkParse";
@@ -462,7 +462,7 @@ var createMarkdownProcessor = function createMarkdownProcessor(plugins, config)
462
462
  * @throws {Error} 当转换过程中发生错误时返回空字符串
463
463
  */ export var markdownToHtml = function markdownToHtml(markdown, plugins, config) {
464
464
  return _async_to_generator(function() {
465
- var _file_value, file, htmlContent, error;
465
+ var _file_value, normalizedMarkdown, file, htmlContent, error;
466
466
  return _ts_generator(this, function(_state) {
467
467
  switch(_state.label){
468
468
  case 0:
@@ -472,9 +472,10 @@ var createMarkdownProcessor = function createMarkdownProcessor(plugins, config)
472
472
  ,
473
473
  3
474
474
  ]);
475
+ normalizedMarkdown = preprocessNormalizeLeafToContainerDirective(markdown);
475
476
  return [
476
477
  4,
477
- createMarkdownProcessor(plugins, config).process(markdown)
478
+ createMarkdownProcessor(plugins, config).process(normalizedMarkdown)
478
479
  ];
479
480
  case 1:
480
481
  file = _state.sent();
@@ -530,7 +531,8 @@ var createMarkdownProcessor = function createMarkdownProcessor(plugins, config)
530
531
  */ export var markdownToHtmlSync = function markdownToHtmlSync(markdown, plugins, config) {
531
532
  try {
532
533
  var _file_value;
533
- var file = createMarkdownProcessor(plugins, config).processSync(markdown);
534
+ var normalizedMarkdown = preprocessNormalizeLeafToContainerDirective(markdown);
535
+ var file = createMarkdownProcessor(plugins, config).processSync(normalizedMarkdown);
534
536
  var htmlContent = file && (typeof file === "undefined" ? "undefined" : _type_of(file)) === 'object' && 'value' in file ? String((_file_value = file.value) !== null && _file_value !== void 0 ? _file_value : '') : String(file);
535
537
  return htmlContent.split(JINJA_DOLLAR_PLACEHOLDER).join('$');
536
538
  } catch (error) {
@@ -647,4 +647,10 @@ export type MarkdownEditorProps = {
647
647
  * @returns 自定义渲染节点,或 undefined 时回退到 defaultDom
648
648
  */
649
649
  eleRender?: (props: import('../MarkdownRenderer/types').MarkdownRendererEleProps, defaultDom: React.ReactNode) => React.ReactNode;
650
+ /**
651
+ * FileMapView 配置(仅 `renderMode: 'markdown'` 时生效)
652
+ * @description 透传给 agentic-ui-filemap 代码块渲染器,
653
+ * 统一配置图片/视频条目的 onPreview 拦截和 itemRender 自定义回显。
654
+ */
655
+ fileMapConfig?: import('../MarkdownRenderer/types').FileMapConfig;
650
656
  };
@@ -213,6 +213,7 @@ var VideoThumbnail = function VideoThumbnail(param) {
213
213
  return /*#__PURE__*/ React.createElement(Tooltip, {
214
214
  title: file.name
215
215
  }, /*#__PURE__*/ React.createElement("div", {
216
+ "data-testid": "file-meta-placeholder",
216
217
  className: className,
217
218
  style: _object_spread({
218
219
  height: 48,
@@ -225,7 +226,8 @@ var VideoThumbnail = function VideoThumbnail(param) {
225
226
  color: 'var(--color-text-tertiary, rgba(0,0,0,0.45))',
226
227
  lineHeight: 1.2,
227
228
  overflow: 'hidden',
228
- flex: 1,
229
+ // 占位块不应在 flex 容器中自动拉伸为整行宽度
230
+ flex: '0 0 auto',
229
231
  minWidth: 80,
230
232
  padding: 'var(--padding-1x) var(--padding-2x)',
231
233
  flexDirection: 'column'
@@ -105,8 +105,8 @@ export var AttachmentFileListItem = function AttachmentFileListItem(param) {
105
105
  var file = param.file, prefixCls = param.prefixCls, hashId = param.hashId, onPreview = param.onPreview, onRetry = param.onRetry, onDelete = param.onDelete, className = param.className;
106
106
  var locale = useContext(I18nContext).locale;
107
107
  var isErrorStatus = file.status === 'error';
108
- var isSizeExceededError = isErrorStatus && file.errorCode === 'FILE_SIZE_EXCEEDED';
109
- var canRetry = isErrorStatus && !isSizeExceededError;
108
+ var isNonRetryableError = isErrorStatus && (file.errorCode === 'FILE_SIZE_EXCEEDED' || file.errorCode === 'FILE_COUNT_EXCEEDED');
109
+ var canRetry = isErrorStatus && !isNonRetryableError;
110
110
  var isDoneStatus = file.status === 'done';
111
111
  var canDelete = !isAttachmentFileLoading(file.status);
112
112
  var handleFileClick = function handleFileClick() {
@@ -63,6 +63,7 @@ import classNames from "clsx";
63
63
  import { AnimatePresence, motion } from "framer-motion";
64
64
  import React, { useContext } from "react";
65
65
  import { ActionIconBox } from "../../../Components/ActionIconBox";
66
+ import { I18nContext } from "../../../I18n";
66
67
  import { isImageFile } from "../utils";
67
68
  import { AttachmentFileListItem } from "./AttachmentFileListItem";
68
69
  import { useStyle } from "./style";
@@ -112,6 +113,7 @@ var ClearButton = function ClearButton(param) {
112
113
  export var AttachmentFileList = function AttachmentFileList(param) {
113
114
  var fileMap = param.fileMap, onDelete = param.onDelete, onPreview = param.onPreview, onDownload = param.onDownload, onRetry = param.onRetry, onClearFileMap = param.onClearFileMap, dataTestId = param.dataTestId;
114
115
  var context = useContext(ConfigProvider.ConfigContext);
116
+ var locale = useContext(I18nContext).locale;
115
117
  var prefix = context === null || context === void 0 ? void 0 : context.getPrefixCls('agentic-md-editor-attachment-list');
116
118
  var _useStyle = useStyle(prefix), wrapSSR = _useStyle.wrapSSR, hashId = _useStyle.hashId;
117
119
  var _React_useState = _sliced_to_array(React.useState(undefined), 2), imgSrc = _React_useState[0], setImgSrc = _React_useState[1];
@@ -148,7 +150,10 @@ export var AttachmentFileList = function AttachmentFileList(param) {
148
150
  animate: "visible",
149
151
  style: containerStyle,
150
152
  className: classNames(prefix, hashId)
151
- }, /*#__PURE__*/ React.createElement(AnimatePresence, {
153
+ }, hasFiles ? /*#__PURE__*/ React.createElement("div", {
154
+ className: classNames("".concat(prefix, "-title"), hashId),
155
+ "data-testid": "attachment-list-title"
156
+ }, (locale === null || locale === void 0 ? void 0 : locale['input.attachmentListTitle']) || '上传附件') : null, /*#__PURE__*/ React.createElement(AnimatePresence, {
152
157
  initial: false
153
158
  }, fileList.map(function(file, index) {
154
159
  return /*#__PURE__*/ React.createElement(AttachmentFileListItem, {
@@ -106,6 +106,14 @@ var genStyle = function genStyle(token) {
106
106
  transform: 'scale(1.05)'
107
107
  }
108
108
  },
109
+ '&-title': {
110
+ width: '100%',
111
+ flexBasis: '100%',
112
+ color: 'var(--color-gray-text-light)',
113
+ font: 'var(--font-text-body-sm)',
114
+ lineHeight: '20px',
115
+ marginBottom: 'var(--margin-0-5x)'
116
+ },
109
117
  '&-item': {
110
118
  width: '168px',
111
119
  height: '48px',
@@ -200,7 +208,9 @@ var genStyle = function genStyle(token) {
200
208
  alignItems: 'center',
201
209
  gap: 4,
202
210
  '&-error': {
203
- color: 'var(--color-red-a10)'
211
+ color: 'var(--color-red-a10)',
212
+ maxWidth: '100%',
213
+ overflow: 'auto'
204
214
  },
205
215
  '&-item:not(:last-child)': {
206
216
  lineHeight: '9px',
@@ -42,6 +42,12 @@ export type AttachmentButtonProps = {
42
42
  minFileCount?: number;
43
43
  /** 是否允许一次选择多个文件(默认:true) */
44
44
  allowMultiple?: boolean;
45
+ /** 文件数量超出 maxFileCount 限制时的回调 */
46
+ onExceedMaxCount?: (info: {
47
+ maxCount: number;
48
+ currentCount: number;
49
+ selectedCount: number;
50
+ }) => void;
45
51
  };
46
52
  /**
47
53
  * 文件上传配置
@@ -63,6 +69,12 @@ type UploadProps = {
63
69
  minFileCount?: number;
64
70
  /** 国际化文案 */
65
71
  locale?: any;
72
+ /** 文件数量超出 maxFileCount 限制时的回调 */
73
+ onExceedMaxCount?: (info: {
74
+ maxCount: number;
75
+ currentCount: number;
76
+ selectedCount: number;
77
+ }) => void;
66
78
  };
67
79
  /**
68
80
  * 上传文件到服务器
@@ -187,16 +187,6 @@ var prepareFile = function prepareFile(file) {
187
187
  var getLocaleMessage = function getLocaleMessage(locale, key, defaultMsg) {
188
188
  return (locale === null || locale === void 0 ? void 0 : locale[key]) || defaultMsg;
189
189
  };
190
- var validateFileCount = function validateFileCount(newFileCount, existingFileCount, props) {
191
- var totalFileCount = newFileCount + existingFileCount;
192
- if (props.maxFileCount && totalFileCount > props.maxFileCount) {
193
- return false;
194
- }
195
- if (props.minFileCount && totalFileCount < props.minFileCount) {
196
- return false;
197
- }
198
- return true;
199
- };
200
190
  var validateFileSize = function validateFileSize(file, props) {
201
191
  if (!props.maxFileSize || file.size <= props.maxFileSize) return true;
202
192
  return false;
@@ -351,7 +341,7 @@ var processFile = function processFile(file, index, map, props) {
351
341
  * @param props.locale - 国际化文案
352
342
  */ export var upLoadFileToServer = function upLoadFileToServer(files, props) {
353
343
  return _async_to_generator(function() {
354
- var map, existingFileCount, hideLoading, fileList, i, error;
344
+ var map, existingFileCount, hideLoading, fileList, totalCount, isMaxExceeded, isMinNotMet, _props_onFileMapChange, _props_onExceedMaxCount, maxCount, rawMessage, errorMessage, i, error;
355
345
  return _ts_generator(this, function(_state) {
356
346
  switch(_state.label){
357
347
  case 0:
@@ -360,9 +350,29 @@ var processFile = function processFile(file, index, map, props) {
360
350
  hideLoading = function hideLoading() {};
361
351
  fileList = Array.from(files);
362
352
  fileList.forEach(prepareFile);
363
- // 在添加到 fileMap 之前先验证文件数量
364
- if (!validateFileCount(fileList.length, existingFileCount, props)) {
353
+ totalCount = fileList.length + existingFileCount;
354
+ isMaxExceeded = typeof props.maxFileCount === 'number' && totalCount > props.maxFileCount;
355
+ isMinNotMet = typeof props.minFileCount === 'number' && totalCount < props.minFileCount;
356
+ if (isMaxExceeded || isMinNotMet) {
365
357
  hideLoading();
358
+ if (isMaxExceeded) {
359
+ ;
360
+ maxCount = props.maxFileCount;
361
+ rawMessage = getLocaleMessage(props.locale, 'markdownInput.maxFileCountExceeded', DEFAULT_MESSAGES.maxFileCountExceeded(maxCount));
362
+ errorMessage = rawMessage.replace(/\$\{maxFileCount\}/g, String(maxCount));
363
+ fileList.forEach(function(file) {
364
+ file.status = 'error';
365
+ file.errorCode = 'FILE_COUNT_EXCEEDED';
366
+ file.errorMessage = errorMessage;
367
+ if (file.uuid) map.set(file.uuid, file);
368
+ });
369
+ (_props_onFileMapChange = props.onFileMapChange) === null || _props_onFileMapChange === void 0 ? void 0 : _props_onFileMapChange.call(props, map);
370
+ (_props_onExceedMaxCount = props.onExceedMaxCount) === null || _props_onExceedMaxCount === void 0 ? void 0 : _props_onExceedMaxCount.call(props, {
371
+ maxCount: maxCount,
372
+ currentCount: existingFileCount,
373
+ selectedCount: fileList.length
374
+ });
375
+ }
366
376
  return [
367
377
  2
368
378
  ];
@@ -46,6 +46,21 @@ function _iterable_to_array_limit(arr, i) {
46
46
  function _non_iterable_rest() {
47
47
  throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
48
48
  }
49
+ function _object_spread(target) {
50
+ for(var i = 1; i < arguments.length; i++){
51
+ var source = arguments[i] != null ? arguments[i] : {};
52
+ var ownKeys = Object.keys(source);
53
+ if (typeof Object.getOwnPropertySymbols === "function") {
54
+ ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
55
+ return Object.getOwnPropertyDescriptor(source, sym).enumerable;
56
+ }));
57
+ }
58
+ ownKeys.forEach(function(key) {
59
+ _define_property(target, key, source[key]);
60
+ });
61
+ }
62
+ return target;
63
+ }
49
64
  function _sliced_to_array(arr, i) {
50
65
  return _array_with_holes(arr) || _iterable_to_array_limit(arr, i) || _unsupported_iterable_to_array(arr, i) || _non_iterable_rest();
51
66
  }
@@ -169,7 +184,11 @@ import { isFileMetaPlaceholderState, kbToSize } from "../AttachmentButton/utils"
169
184
  // 有 status 但无 url/previewUrl:文件内容未拿到,展示大小与格式占位块(loading 状态除外)
170
185
  if (isFileMetaPlaceholderState(file)) {
171
186
  return /*#__PURE__*/ React.createElement(FileMetaPlaceholder, {
172
- file: file
187
+ file: file,
188
+ className: classNames(props.className, props.prefixCls ? "".concat(props.prefixCls, "-meta-placeholder") : undefined),
189
+ style: _object_spread({
190
+ height: 56
191
+ }, props.style)
173
192
  });
174
193
  }
175
194
  return /*#__PURE__*/ React.createElement(Tooltip, {
@@ -5,7 +5,12 @@ export type FileMapViewProps = {
5
5
  showMoreButton?: boolean;
6
6
  /** 文件映射表 */
7
7
  fileMap?: Map<string, AttachmentFile>;
8
- /** 预览文件回调 */
8
+ /**
9
+ * 预览文件回调。
10
+ * - 对于非图片/视频文件:点击预览按钮时触发,传入时阻止默认的 window.open 行为。
11
+ * - 对于图片文件:点击缩略图时触发,传入时阻止 antd Image 内置灯箱预览。
12
+ * - 对于视频文件:点击缩略图时触发,传入时阻止内置弹窗播放。
13
+ */
9
14
  onPreview?: (file: AttachmentFile) => void;
10
15
  /** 下载文件回调 */
11
16
  onDownload?: (file: AttachmentFile) => void;
@@ -22,6 +27,13 @@ export type FileMapViewProps = {
22
27
  /** 最多展示的非图片文件数量,传入则开启溢出控制并在超出时显示"查看所有文件"按钮,不传则展示所有文件且不显示按钮 */
23
28
  maxDisplayCount?: number;
24
29
  placement?: 'left' | 'right';
30
+ /**
31
+ * 自定义每个媒体(图片/视频)条目的渲染。
32
+ * 接收文件对象和默认渲染节点,返回自定义节点即可替换默认展示,常用于回显场景。
33
+ * @param file - 当前文件
34
+ * @param defaultDom - 默认渲染的 React 节点
35
+ */
36
+ itemRender?: (file: AttachmentFile, defaultDom: React.ReactNode) => React.ReactNode;
25
37
  };
26
38
  /**
27
39
  * FileMapView 组件 - 文件映射视图组件
@@ -190,10 +190,23 @@ import { ConfigProvider, Image, Modal } from "antd";
190
190
  import classNames from "clsx";
191
191
  import { motion } from "framer-motion";
192
192
  import React, { useContext, useMemo, useState } from "react";
193
+ import { I18nContext } from "../../I18n";
193
194
  import { FileMetaPlaceholder } from "../AttachmentButton/AttachmentFileList/AttachmentFileIcon";
194
- import { isImageFile, isVideoFile } from "../AttachmentButton/utils";
195
+ import { isFileMetaPlaceholderState, isImageFile, isVideoFile } from "../AttachmentButton/utils";
195
196
  import { FileMapViewItem } from "./FileMapViewItem";
196
197
  import { useStyle } from "./style";
198
+ var IMAGE_THUMBNAIL_SIZE = 124;
199
+ var SINGLE_VIDEO_THUMBNAIL_SIZE = {
200
+ width: 330,
201
+ height: 188
202
+ };
203
+ var getMediaPlaceholderStyle = function getMediaPlaceholderStyle(size) {
204
+ return {
205
+ width: size.width,
206
+ height: size.height,
207
+ minWidth: size.width
208
+ };
209
+ };
197
210
  /**
198
211
  * FileMapView 组件 - 文件映射视图组件
199
212
  *
@@ -236,6 +249,7 @@ import { useStyle } from "./style";
236
249
  var _props_style;
237
250
  var _props_placement = props.placement, placement = _props_placement === void 0 ? 'left' : _props_placement;
238
251
  var context = useContext(ConfigProvider.ConfigContext);
252
+ var locale = useContext(I18nContext).locale;
239
253
  var prefix = context === null || context === void 0 ? void 0 : context.getPrefixCls('agentic-md-editor-file-view-list');
240
254
  var _useStyle = useStyle(prefix), wrapSSR = _useStyle.wrapSSR, hashId = _useStyle.hashId;
241
255
  var _useState = _sliced_to_array(useState(false), 2), showAllFiles = _useState[0], setShowAllFiles = _useState[1];
@@ -333,6 +347,11 @@ import { useStyle } from "./style";
333
347
  });
334
348
  })();
335
349
  };
350
+ var imagePlaceholderStyle = getMediaPlaceholderStyle({
351
+ width: IMAGE_THUMBNAIL_SIZE,
352
+ height: IMAGE_THUMBNAIL_SIZE
353
+ });
354
+ var hasAnyFiles = fileList.length > 0;
336
355
  var _obj;
337
356
  return wrapSSR(/*#__PURE__*/ React.createElement("div", {
338
357
  "data-testid": "file-view-list",
@@ -345,7 +364,10 @@ import { useStyle } from "./style";
345
364
  alignItems: placement === 'left' ? 'flex-start' : 'flex-end',
346
365
  width: 'max-content'
347
366
  }
348
- }, imgList.length > 0 && /*#__PURE__*/ React.createElement(motion.div, {
367
+ }, hasAnyFiles ? /*#__PURE__*/ React.createElement("div", {
368
+ className: classNames("".concat(prefix, "-title"), hashId),
369
+ "data-testid": "file-view-title"
370
+ }, (locale === null || locale === void 0 ? void 0 : locale['chat.fileMapTitle']) || '结果文件') : null, imgList.length > 0 && /*#__PURE__*/ React.createElement(motion.div, {
349
371
  variants: {
350
372
  visible: {
351
373
  opacity: 1,
@@ -368,19 +390,34 @@ import { useStyle } from "./style";
368
390
  "data-testid": "file-view-image-list",
369
391
  className: classNames(prefix, hashId, props.className, "".concat(prefix, "-").concat(placement), (_obj = {}, _define_property(_obj, "".concat(prefix, "-image-list-view"), imgList.length > 1), _define_property(_obj, "".concat(prefix, "-image-list-view-").concat(placement), imgList.length > 1), _obj))
370
392
  }, /*#__PURE__*/ React.createElement(Image.PreviewGroup, null, imgList.map(function(file, index) {
371
- if (file.status !== undefined && file.status !== null && !file.url && !file.previewUrl) {
372
- return /*#__PURE__*/ React.createElement(FileMetaPlaceholder, {
393
+ var key = file.uuid || file.name || index;
394
+ if (isFileMetaPlaceholderState(file)) {
395
+ var placeholderDom = /*#__PURE__*/ React.createElement(FileMetaPlaceholder, {
373
396
  file: file,
374
- key: file.uuid || file.name || index
397
+ key: key,
398
+ className: classNames("".concat(prefix, "-image"), hashId),
399
+ style: imagePlaceholderStyle
375
400
  });
401
+ return props.itemRender ? props.itemRender(file, placeholderDom) : placeholderDom;
376
402
  }
377
- return /*#__PURE__*/ React.createElement(Image, {
403
+ var defaultImageDom = /*#__PURE__*/ React.createElement(Image, {
378
404
  rootClassName: classNames("".concat(prefix, "-image"), hashId),
379
405
  width: 124,
380
406
  height: 124,
381
407
  src: file.previewUrl || file.url,
382
- key: file.uuid || file.name || index
408
+ key: key,
409
+ preview: props.onPreview ? {
410
+ visible: false,
411
+ onVisibleChange: function onVisibleChange() {
412
+ var _props_onPreview;
413
+ return (_props_onPreview = props.onPreview) === null || _props_onPreview === void 0 ? void 0 : _props_onPreview.call(props, file);
414
+ },
415
+ mask: /*#__PURE__*/ React.createElement("div", {
416
+ className: classNames("".concat(prefix, "-image-mask"), hashId)
417
+ })
418
+ } : undefined
383
419
  });
420
+ return props.itemRender ? props.itemRender(file, defaultImageDom) : defaultImageDom;
384
421
  }))), videoList.length > 0 && /*#__PURE__*/ React.createElement(motion.div, {
385
422
  variants: {
386
423
  visible: {
@@ -399,24 +436,25 @@ import { useStyle } from "./style";
399
436
  }, videoList.map(function(file, index) {
400
437
  var videoUrl = file.previewUrl || file.url || '';
401
438
  var isSingleVideo = videoList.length === 1;
402
- var thumbSize = isSingleVideo ? {
403
- width: 330,
404
- height: 188
405
- } : {
406
- width: 124,
407
- height: 124
439
+ var thumbSize = isSingleVideo ? SINGLE_VIDEO_THUMBNAIL_SIZE : {
440
+ width: IMAGE_THUMBNAIL_SIZE,
441
+ height: IMAGE_THUMBNAIL_SIZE
408
442
  };
409
- if (file.status !== undefined && file.status !== null && !file.url && !file.previewUrl) {
410
- return /*#__PURE__*/ React.createElement(FileMetaPlaceholder, {
443
+ var key = file.uuid || file.name || index;
444
+ if (isFileMetaPlaceholderState(file)) {
445
+ var placeholderDom = /*#__PURE__*/ React.createElement(FileMetaPlaceholder, {
411
446
  file: file,
412
- key: file.uuid || file.name || index
447
+ key: key,
448
+ className: classNames("".concat(prefix, "-image"), "".concat(prefix, "-video-thumb"), hashId),
449
+ style: getMediaPlaceholderStyle(thumbSize)
413
450
  });
451
+ return props.itemRender ? props.itemRender(file, placeholderDom) : placeholderDom;
414
452
  }
415
- return /*#__PURE__*/ React.createElement("div", {
453
+ var defaultVideoDom = /*#__PURE__*/ React.createElement("div", {
416
454
  role: "button",
417
455
  tabIndex: 0,
418
456
  className: classNames("".concat(prefix, "-image"), "".concat(prefix, "-video-thumb"), hashId),
419
- key: file.uuid || file.name || index,
457
+ key: key,
420
458
  onClick: function onClick() {
421
459
  return handleVideoClick(file);
422
460
  },
@@ -443,6 +481,7 @@ import { useStyle } from "./style";
443
481
  className: classNames("".concat(prefix, "-video-play-overlay"), hashId),
444
482
  "aria-hidden": true
445
483
  }, /*#__PURE__*/ React.createElement(Play, null)));
484
+ return props.itemRender ? props.itemRender(file, defaultVideoDom) : defaultVideoDom;
446
485
  })), /*#__PURE__*/ React.createElement(Modal, {
447
486
  open: videoModalOpen,
448
487
  onCancel: handleVideoModalClose,
@@ -212,6 +212,12 @@ var genStyle = function genStyle(token) {
212
212
  }), _define_property(_obj1, '&-more-file-name', {
213
213
  font: 'var(--font-size-h6)',
214
214
  color: 'var(--color-gray-text-secondary)'
215
+ }), _define_property(_obj1, '&-title', {
216
+ width: '100%',
217
+ color: 'var(--color-gray-text-light)',
218
+ font: 'var(--font-text-body-sm)',
219
+ lineHeight: '20px',
220
+ marginBottom: 2
215
221
  }), _define_property(_obj1, '&-item', {
216
222
  width: '285px',
217
223
  height: '56px',
@@ -252,7 +252,7 @@ import { isMobileDevice, isVivoOrOppoDevice, isWeChat } from "../AttachmentButto
252
252
  * 上传图片
253
253
  */ var uploadImage = useRefFunction(function(forGallery) {
254
254
  return _async_to_generator(function() {
255
- var _ref, isUploading, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, file, currentFileCount, accept, input;
255
+ var _ref, isUploading, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, file, accept, input;
256
256
  return _ts_generator(this, function(_state) {
257
257
  // 检查是否有文件正在上传中
258
258
  isUploading = false;
@@ -284,13 +284,6 @@ import { isMobileDevice, isVivoOrOppoDevice, isWeChat } from "../AttachmentButto
284
284
  2
285
285
  ];
286
286
  }
287
- // 检查是否已达到最大文件数量限制
288
- currentFileCount = (fileMap === null || fileMap === void 0 ? void 0 : fileMap.size) || 0;
289
- if ((attachment === null || attachment === void 0 ? void 0 : attachment.maxFileCount) && currentFileCount >= attachment.maxFileCount) {
290
- return [
291
- 2
292
- ];
293
- }
294
287
  accept = getAcceptValue(forGallery || false);
295
288
  input = document.createElement('input');
296
289
  input.id = 'uploadImage' + '_' + Math.random();
@@ -300,7 +293,7 @@ import { isMobileDevice, isVivoOrOppoDevice, isWeChat } from "../AttachmentButto
300
293
  input.style.display = 'none';
301
294
  input.onchange = function(e) {
302
295
  return _async_to_generator(function() {
303
- var selectedFiles, currentFileCount, totalFileCount, error;
296
+ var selectedFiles, error;
304
297
  return _ts_generator(this, function(_state) {
305
298
  switch(_state.label){
306
299
  case 0:
@@ -324,23 +317,8 @@ import { isMobileDevice, isVivoOrOppoDevice, isWeChat } from "../AttachmentButto
324
317
  2
325
318
  ];
326
319
  }
327
- // 检查选择的文件数量是否超过限制
328
- currentFileCount = (fileMap === null || fileMap === void 0 ? void 0 : fileMap.size) || 0;
329
- if (attachment === null || attachment === void 0 ? void 0 : attachment.maxFileCount) {
330
- // 如果一次选择的文件数量超过最大限制,完全拒绝
331
- if (selectedFiles.length > attachment.maxFileCount) {
332
- return [
333
- 2
334
- ];
335
- }
336
- // 如果选择的文件数量加上已有文件数量超过限制,完全拒绝
337
- totalFileCount = selectedFiles.length + currentFileCount;
338
- if (totalFileCount > attachment.maxFileCount) {
339
- return [
340
- 2
341
- ];
342
- }
343
- }
320
+ // 检查选择的文件数量是否超过限制——超限时交由 upLoadFileToServer 统一处理
321
+ // (upLoadFileToServer validateFileCount 失败时会把文件以 error 状态入 map 并触发 onExceedMaxCount)
344
322
  return [
345
323
  4,
346
324
  upLoadFileToServer(selectedFiles, _object_spread_props(_object_spread({}, attachment), {
@@ -94,6 +94,8 @@ var INPUT_FIELD_PADDING = {
94
94
  NONE: '0px',
95
95
  SMALL: "".concat(GLOW_BORDER_OFFSET, "px")
96
96
  };
97
+ // MarkdownInputField 中 code block 的默认高度,避免初始占位过高
98
+ var DEFAULT_INPUT_CODE_BLOCK_HEIGHT = 120;
97
99
  // 定义旋转动画
98
100
  var stopIconRotate = new Keyframes('stopIconRotate', {
99
101
  '0%': {
@@ -183,6 +185,11 @@ var genStyle = function genStyle(token) {
183
185
  padding: '0 !important'
184
186
  }
185
187
  },
188
+ // 仅覆盖 MarkdownInputField 内的代码块默认高度
189
+ '& [data-language][data-is-unclosed]': {
190
+ height: "".concat(DEFAULT_INPUT_CODE_BLOCK_HEIGHT, "px !important"),
191
+ minHeight: "".concat(DEFAULT_INPUT_CODE_BLOCK_HEIGHT, "px !important")
192
+ },
186
193
  '&-editor-content': _define_property({
187
194
  display: 'flex',
188
195
  flexDirection: 'column',
@@ -187,10 +187,11 @@ var SCHEMA_LANGUAGES = new Set([
187
187
  /**
188
188
  * 默认的代码块路由——根据语言分发到对应渲染器
189
189
  */ var DefaultCodeRouter = function DefaultCodeRouter(props) {
190
- var language = props.language, pluginComponents = props.pluginComponents, apaasifyRender = props.apaasifyRender, rest = _object_without_properties(props, [
190
+ var language = props.language, pluginComponents = props.pluginComponents, apaasifyRender = props.apaasifyRender, fileMapConfig = props.fileMapConfig, rest = _object_without_properties(props, [
191
191
  "language",
192
192
  "pluginComponents",
193
- "apaasifyRender"
193
+ "apaasifyRender",
194
+ "fileMapConfig"
194
195
  ]);
195
196
  if (language === 'mermaid') {
196
197
  var MermaidComp = pluginComponents.mermaid || MermaidBlockRenderer;
@@ -219,7 +220,8 @@ var SCHEMA_LANGUAGES = new Set([
219
220
  if (language === 'agentic-ui-filemap') {
220
221
  var FileMapComp = pluginComponents['agentic-ui-filemap'] || AgenticUiFileMapBlockRenderer;
221
222
  return /*#__PURE__*/ React.createElement(FileMapComp, _object_spread_props(_object_spread({}, rest), {
222
- language: language
223
+ language: language,
224
+ fileMapConfig: fileMapConfig
223
225
  }));
224
226
  }
225
227
  if (SCHEMA_LANGUAGES.has(language)) {
@@ -243,7 +245,7 @@ var SCHEMA_LANGUAGES = new Set([
243
245
  * - Markdown → hast → React 元素树(hast-util-to-jsx-runtime)
244
246
  * - 特殊块(code / mermaid / chart / katex)通过组件映射拦截渲染
245
247
  */ var InternalMarkdownRenderer = /*#__PURE__*/ forwardRef(function(props, ref) {
246
- 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;
248
+ 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;
247
249
  var getPrefixCls = useContext(ConfigProvider.ConfigContext).getPrefixCls;
248
250
  // 复用 MarkdownEditor 的 CSS 前缀和样式,保持渲染一致性
249
251
  var prefixCls = getPrefixCls('agentic-md-editor', customPrefixCls);
@@ -344,7 +346,8 @@ var SCHEMA_LANGUAGES = new Set([
344
346
  var codeRouter = function codeRouter(codeProps) {
345
347
  return /*#__PURE__*/ React.createElement(DefaultCodeRouter, _object_spread_props(_object_spread({}, codeProps), {
346
348
  pluginComponents: pluginComponents,
347
- apaasifyRender: apaasifyRender
349
+ apaasifyRender: apaasifyRender,
350
+ fileMapConfig: fileMapConfig
348
351
  }));
349
352
  };
350
353
  codeRouter.displayName = 'CodeRouter';
@@ -353,7 +356,8 @@ var SCHEMA_LANGUAGES = new Set([
353
356
  }, pluginComponents);
354
357
  }, [
355
358
  pluginComponents,
356
- apaasifyRender
359
+ apaasifyRender,
360
+ fileMapConfig
357
361
  ]);
358
362
  // 流式缓存:将不完整的 Markdown token 暂缓,避免 parser 错误解析
359
363
  var safeContent = useStreaming(displayedContent, streaming);
@@ -9,7 +9,7 @@ export { ChartBlockRenderer } from './renderers/ChartRenderer';
9
9
  export { CodeBlockRenderer } from './renderers/CodeRenderer';
10
10
  export { MermaidBlockRenderer } from './renderers/MermaidRenderer';
11
11
  export { SchemaBlockRenderer } from './renderers/SchemaRenderer';
12
- export type { CharacterQueueOptions, MarkdownRendererEleProps, MarkdownRendererProps, MarkdownRendererRef, RenderMode, RendererBlockProps, } from './types';
12
+ export type { CharacterQueueOptions, FileMapConfig, MarkdownRendererEleProps, MarkdownRendererProps, MarkdownRendererRef, RenderMode, RendererBlockProps, } from './types';
13
13
  export type { UseMarkdownToReactOptions } from './markdownReactShared';
14
14
  export { markdownToReactSync, useMarkdownToReact } from './useMarkdownToReact';
15
15
  export { useStreamingMarkdownReact } from './streaming/useStreamingMarkdownReact';
@@ -1,6 +1,8 @@
1
1
  import React from 'react';
2
- import type { RendererBlockProps } from '../types';
2
+ import type { FileMapConfig, RendererBlockProps } from '../types';
3
3
  /**
4
4
  * ```agentic-ui-filemap``` 代码块 → FileMapView
5
5
  */
6
- export declare const AgenticUiFileMapBlockRenderer: React.FC<RendererBlockProps>;
6
+ export declare const AgenticUiFileMapBlockRenderer: React.FC<RendererBlockProps & {
7
+ fileMapConfig?: FileMapConfig;
8
+ }>;