@ant-design/agentic-ui 2.30.12 → 2.30.13

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 (25) hide show
  1. package/dist/Bubble/MessagesContent/MarkdownPreview.js +3 -2
  2. package/dist/MarkdownEditor/editor/elements/AgenticUiBlocks/agenticUiEmbedUtils.d.ts +5 -1
  3. package/dist/MarkdownEditor/editor/elements/AgenticUiBlocks/agenticUiEmbedUtils.js +10 -2
  4. package/dist/MarkdownEditor/types.d.ts +6 -0
  5. package/dist/MarkdownInputField/AttachmentButton/AttachmentFileList/AttachmentFileListItem.js +2 -2
  6. package/dist/MarkdownInputField/AttachmentButton/AttachmentFileList/style.js +3 -1
  7. package/dist/MarkdownInputField/AttachmentButton/index.d.ts +12 -0
  8. package/dist/MarkdownInputField/AttachmentButton/index.js +23 -13
  9. package/dist/MarkdownInputField/FileMapView/index.d.ts +13 -1
  10. package/dist/MarkdownInputField/FileMapView/index.js +24 -8
  11. package/dist/MarkdownInputField/FileUploadManager/index.js +4 -26
  12. package/dist/MarkdownRenderer/MarkdownRenderer.js +10 -6
  13. package/dist/MarkdownRenderer/index.d.ts +1 -1
  14. package/dist/MarkdownRenderer/renderers/AgenticUiFileMapBlockRenderer.d.ts +4 -2
  15. package/dist/MarkdownRenderer/renderers/AgenticUiFileMapBlockRenderer.js +47 -5
  16. package/dist/MarkdownRenderer/renderers/ChartRenderer.js +9 -0
  17. package/dist/MarkdownRenderer/types.d.ts +45 -2
  18. package/dist/Plugins/chart/ChartRender.js +30 -9
  19. package/dist/Plugins/chart/HistogramChart/index.d.ts +5 -1
  20. package/dist/Plugins/chart/HistogramChart/index.js +79 -12
  21. package/dist/Plugins/chart/ScatterChart/index.d.ts +8 -0
  22. package/dist/Plugins/chart/ScatterChart/index.js +78 -8
  23. package/dist/Plugins/code/components/AceEditor.js +69 -8
  24. package/dist/Plugins/code/components/CodeRenderer.js +0 -1
  25. package/package.json +2 -1
@@ -125,7 +125,7 @@ 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, _props_markdownRenderConfig8, _props_markdownRenderConfig9;
128
+ var _props_originData3, _props_markdownRenderConfig4, _props_markdownRenderConfig5, _props_markdownRenderConfig6, _props_markdownRenderConfig7, _props_markdownRenderConfig8, _props_markdownRenderConfig9, _props_markdownRenderConfig10;
129
129
  return /*#__PURE__*/ React.createElement(MarkdownRenderer, {
130
130
  content: content,
131
131
  streaming: typing,
@@ -140,7 +140,8 @@ import { MessagesContext } from "./BubbleContext";
140
140
  margin: isPaddingHidden ? 0 : undefined
141
141
  }, ((_props_markdownRenderConfig7 = props.markdownRenderConfig) === null || _props_markdownRenderConfig7 === void 0 ? void 0 : _props_markdownRenderConfig7.style) || {}),
142
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
143
+ apaasify: (_props_markdownRenderConfig9 = props.markdownRenderConfig) === null || _props_markdownRenderConfig9 === void 0 ? void 0 : _props_markdownRenderConfig9.apaasify,
144
+ fileMapConfig: (_props_markdownRenderConfig10 = props.markdownRenderConfig) === null || _props_markdownRenderConfig10 === void 0 ? void 0 : _props_markdownRenderConfig10.fileMapConfig
144
145
  });
145
146
  }
146
147
  // Slate 渲染路径——保持向后兼容
@@ -26,5 +26,9 @@ export interface NormalizedFileMapEmbedProps {
26
26
  }
27
27
  /**
28
28
  * 将 ```agentic-ui-filemap JSON 规范化为 FileMapView 所需 props
29
+ *
30
+ * @param parsed - 解析后的 JSON 数据
31
+ * @param normalizeFile - 可选的自定义文件规范化函数,接收原始 JSON 条目和默认生成的
32
+ * AttachmentFile,返回最终的 AttachmentFile;返回 null 时该条目被过滤掉
29
33
  */
30
- export declare function normalizeFileMapPropsFromJson(parsed: unknown): NormalizedFileMapEmbedProps;
34
+ export declare function normalizeFileMapPropsFromJson(parsed: unknown, normalizeFile?: (raw: Record<string, unknown>, defaultFile: AttachmentFile) => AttachmentFile | null): NormalizedFileMapEmbedProps;
@@ -190,7 +190,11 @@ var fileItemFromRecord = function fileItemFromRecord(x, index) {
190
190
  };
191
191
  /**
192
192
  * 将 ```agentic-ui-filemap JSON 规范化为 FileMapView 所需 props
193
- */ export function normalizeFileMapPropsFromJson(parsed) {
193
+ *
194
+ * @param parsed - 解析后的 JSON 数据
195
+ * @param normalizeFile - 可选的自定义文件规范化函数,接收原始 JSON 条目和默认生成的
196
+ * AttachmentFile,返回最终的 AttachmentFile;返回 null 时该条目被过滤掉
197
+ */ export function normalizeFileMapPropsFromJson(parsed, normalizeFile) {
194
198
  var root = parsed && (typeof parsed === "undefined" ? "undefined" : _type_of(parsed)) === 'object' && !Array.isArray(parsed) ? parsed : null;
195
199
  var rawItems = [];
196
200
  if (root && Array.isArray(root.fileList)) {
@@ -203,7 +207,11 @@ var fileItemFromRecord = function fileItemFromRecord(x, index) {
203
207
  var fileList = rawItems.filter(function(x) {
204
208
  return !!x && (typeof x === "undefined" ? "undefined" : _type_of(x)) === 'object';
205
209
  }).map(function(x, i) {
206
- return fileItemFromRecord(x, i);
210
+ var defaultFile = fileItemFromRecord(x, i);
211
+ if (!normalizeFile) return defaultFile;
212
+ return normalizeFile(x, defaultFile);
213
+ }).filter(function(f) {
214
+ return f !== null;
207
215
  });
208
216
  var className = root && typeof root.className === 'string' ? root.className : undefined;
209
217
  return {
@@ -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
  };
@@ -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() {
@@ -200,7 +200,9 @@ var genStyle = function genStyle(token) {
200
200
  alignItems: 'center',
201
201
  gap: 4,
202
202
  '&-error': {
203
- color: 'var(--color-red-a10)'
203
+ color: 'var(--color-red-a10)',
204
+ maxWidth: '100%',
205
+ overflow: 'auto'
204
206
  },
205
207
  '&-item:not(:last-child)': {
206
208
  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
  ];
@@ -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 组件 - 文件映射视图组件
@@ -368,19 +368,32 @@ import { useStyle } from "./style";
368
368
  "data-testid": "file-view-image-list",
369
369
  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
370
  }, /*#__PURE__*/ React.createElement(Image.PreviewGroup, null, imgList.map(function(file, index) {
371
+ var key = file.uuid || file.name || index;
371
372
  if (file.status !== undefined && file.status !== null && !file.url && !file.previewUrl) {
372
- return /*#__PURE__*/ React.createElement(FileMetaPlaceholder, {
373
+ var placeholderDom = /*#__PURE__*/ React.createElement(FileMetaPlaceholder, {
373
374
  file: file,
374
- key: file.uuid || file.name || index
375
+ key: key
375
376
  });
377
+ return props.itemRender ? props.itemRender(file, placeholderDom) : placeholderDom;
376
378
  }
377
- return /*#__PURE__*/ React.createElement(Image, {
379
+ var defaultImageDom = /*#__PURE__*/ React.createElement(Image, {
378
380
  rootClassName: classNames("".concat(prefix, "-image"), hashId),
379
381
  width: 124,
380
382
  height: 124,
381
383
  src: file.previewUrl || file.url,
382
- key: file.uuid || file.name || index
384
+ key: key,
385
+ preview: props.onPreview ? {
386
+ visible: false,
387
+ onVisibleChange: function onVisibleChange() {
388
+ var _props_onPreview;
389
+ return (_props_onPreview = props.onPreview) === null || _props_onPreview === void 0 ? void 0 : _props_onPreview.call(props, file);
390
+ },
391
+ mask: /*#__PURE__*/ React.createElement("div", {
392
+ className: classNames("".concat(prefix, "-image-mask"), hashId)
393
+ })
394
+ } : undefined
383
395
  });
396
+ return props.itemRender ? props.itemRender(file, defaultImageDom) : defaultImageDom;
384
397
  }))), videoList.length > 0 && /*#__PURE__*/ React.createElement(motion.div, {
385
398
  variants: {
386
399
  visible: {
@@ -406,17 +419,19 @@ import { useStyle } from "./style";
406
419
  width: 124,
407
420
  height: 124
408
421
  };
422
+ var key = file.uuid || file.name || index;
409
423
  if (file.status !== undefined && file.status !== null && !file.url && !file.previewUrl) {
410
- return /*#__PURE__*/ React.createElement(FileMetaPlaceholder, {
424
+ var placeholderDom = /*#__PURE__*/ React.createElement(FileMetaPlaceholder, {
411
425
  file: file,
412
- key: file.uuid || file.name || index
426
+ key: key
413
427
  });
428
+ return props.itemRender ? props.itemRender(file, placeholderDom) : placeholderDom;
414
429
  }
415
- return /*#__PURE__*/ React.createElement("div", {
430
+ var defaultVideoDom = /*#__PURE__*/ React.createElement("div", {
416
431
  role: "button",
417
432
  tabIndex: 0,
418
433
  className: classNames("".concat(prefix, "-image"), "".concat(prefix, "-video-thumb"), hashId),
419
- key: file.uuid || file.name || index,
434
+ key: key,
420
435
  onClick: function onClick() {
421
436
  return handleVideoClick(file);
422
437
  },
@@ -443,6 +458,7 @@ import { useStyle } from "./style";
443
458
  className: classNames("".concat(prefix, "-video-play-overlay"), hashId),
444
459
  "aria-hidden": true
445
460
  }, /*#__PURE__*/ React.createElement(Play, null)));
461
+ return props.itemRender ? props.itemRender(file, defaultVideoDom) : defaultVideoDom;
446
462
  })), /*#__PURE__*/ React.createElement(Modal, {
447
463
  open: videoModalOpen,
448
464
  onCancel: handleVideoModalClose,
@@ -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), {
@@ -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
+ }>;
@@ -1,3 +1,39 @@
1
+ function _object_without_properties(source, excluded) {
2
+ if (source == null) return {};
3
+ var target = {}, sourceKeys, key, i;
4
+ if (typeof Reflect !== "undefined" && Reflect.ownKeys) {
5
+ sourceKeys = Reflect.ownKeys(source);
6
+ for(i = 0; i < sourceKeys.length; i++){
7
+ key = sourceKeys[i];
8
+ if (excluded.indexOf(key) >= 0) continue;
9
+ if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
10
+ target[key] = source[key];
11
+ }
12
+ return target;
13
+ }
14
+ target = _object_without_properties_loose(source, excluded);
15
+ if (Object.getOwnPropertySymbols) {
16
+ sourceKeys = Object.getOwnPropertySymbols(source);
17
+ for(i = 0; i < sourceKeys.length; i++){
18
+ key = sourceKeys[i];
19
+ if (excluded.indexOf(key) >= 0) continue;
20
+ if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
21
+ target[key] = source[key];
22
+ }
23
+ }
24
+ return target;
25
+ }
26
+ function _object_without_properties_loose(source, excluded) {
27
+ if (source == null) return {};
28
+ var target = {}, sourceKeys = Object.getOwnPropertyNames(source), key, i;
29
+ for(i = 0; i < sourceKeys.length; i++){
30
+ key = sourceKeys[i];
31
+ if (excluded.indexOf(key) >= 0) continue;
32
+ if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
33
+ target[key] = source[key];
34
+ }
35
+ return target;
36
+ }
1
37
  import json5 from "json5";
2
38
  import React, { useMemo } from "react";
3
39
  import { normalizeFileMapPropsFromJson } from "../../MarkdownEditor/editor/elements/AgenticUiBlocks/agenticUiEmbedUtils";
@@ -27,10 +63,13 @@ var parseJsonBody = function parseJsonBody(code) {
27
63
  /**
28
64
  * ```agentic-ui-filemap``` 代码块 → FileMapView
29
65
  */ export var AgenticUiFileMapBlockRenderer = function AgenticUiFileMapBlockRenderer(props) {
66
+ var fileMapConfig = props.fileMapConfig, rest = _object_without_properties(props, [
67
+ "fileMapConfig"
68
+ ]);
30
69
  var code = useMemo(function() {
31
- return extractTextContent(props.children);
70
+ return extractTextContent(rest.children);
32
71
  }, [
33
- props.children
72
+ rest.children
34
73
  ]);
35
74
  var parsed = useMemo(function() {
36
75
  return parseJsonBody(code);
@@ -38,9 +77,10 @@ var parseJsonBody = function parseJsonBody(code) {
38
77
  code
39
78
  ]);
40
79
  var _useMemo = useMemo(function() {
41
- return normalizeFileMapPropsFromJson(parsed);
80
+ return normalizeFileMapPropsFromJson(parsed, fileMapConfig === null || fileMapConfig === void 0 ? void 0 : fileMapConfig.normalizeFile);
42
81
  }, [
43
- parsed
82
+ parsed,
83
+ fileMapConfig === null || fileMapConfig === void 0 ? void 0 : fileMapConfig.normalizeFile
44
84
  ]), fileList = _useMemo.fileList, className = _useMemo.className;
45
85
  var fileMap = useMemo(function() {
46
86
  return new Map(fileList.map(function(f) {
@@ -73,7 +113,9 @@ var parseJsonBody = function parseJsonBody(code) {
73
113
  }
74
114
  }, /*#__PURE__*/ React.createElement(FileMapView, {
75
115
  fileMap: fileMap,
76
- className: className
116
+ className: className,
117
+ onPreview: fileMapConfig === null || fileMapConfig === void 0 ? void 0 : fileMapConfig.onPreview,
118
+ itemRender: fileMapConfig === null || fileMapConfig === void 0 ? void 0 : fileMapConfig.itemRender
77
119
  }));
78
120
  };
79
121
  AgenticUiFileMapBlockRenderer.displayName = 'AgenticUiFileMapBlockRenderer';
@@ -158,6 +158,7 @@ var extractTextContent = function extractTextContent1(children) {
158
158
  * 支持两种格式:
159
159
  * 1. 完整格式:{ config: [...], dataSource: [...], columns: [...] }
160
160
  * 2. 简单格式:{ chartType, x, y, data: [...] }
161
+ * 3. algTypes 格式:{ type: "histogram", value: { data: [...], dataMetaMap: {...} } }
161
162
  */ var parseChartData = function parseChartData(code) {
162
163
  try {
163
164
  var parsed = JSON.parse(code.trim());
@@ -167,6 +168,14 @@ var extractTextContent = function extractTextContent1(children) {
167
168
  config: parsed
168
169
  };
169
170
  }
171
+ // Handle { type: "histogram", value: { data: [...], dataMetaMap: {...} } } format
172
+ if (typeof parsed.type === 'string' && parsed.value && Array.isArray(parsed.value.data)) {
173
+ return {
174
+ chartType: parsed.type,
175
+ data: parsed.value.data,
176
+ dataMetaMap: parsed.value.dataMetaMap
177
+ };
178
+ }
170
179
  return parsed;
171
180
  } catch (unused) {
172
181
  return null;
@@ -1,10 +1,48 @@
1
1
  import type React from 'react';
2
2
  import type { MarkdownRemarkPlugin, MarkdownToHtmlConfig } from '../MarkdownEditor/editor/utils/markdownToHtml';
3
3
  import type { MarkdownEditorPlugin } from '../MarkdownEditor/plugin';
4
+ import type { AttachmentFile } from '../MarkdownInputField/AttachmentButton/types';
5
+ import type { FileMapViewProps } from '../MarkdownInputField/FileMapView';
4
6
  /**
5
- * markdown 渲染模式下传给 eleRender 的元素属性,
6
- * 包含 HTML 标签名、hast 节点及所有原生 HTML 属性。
7
+ * FileMapView 相关配置,透传给 agentic-ui-filemap 代码块渲染器,
8
+ * 方便在 markdownRenderConfig 中统一配置图片回显行为。
7
9
  */
10
+ export interface FileMapConfig {
11
+ /**
12
+ * 预览文件回调,透传给 FileMapView.onPreview。
13
+ * 对图片:点击缩略图时触发,传入则阻止 antd Image 内置灯箱;
14
+ * 对视频:传入则阻止内置弹窗;对普通文件:传入则阻止默认 window.open。
15
+ */
16
+ onPreview?: (file: AttachmentFile) => void;
17
+ /**
18
+ * 自定义每个媒体条目(图片/视频)的渲染,透传给 FileMapView.itemRender,
19
+ * 常用于回显场景。
20
+ */
21
+ itemRender?: FileMapViewProps['itemRender'];
22
+ /**
23
+ * 自定义文件数据规范化函数,用于将 agentic-ui-filemap 代码块中的原始 JSON 条目
24
+ * 转换为 AttachmentFile 对象。
25
+ *
26
+ * 适用于服务端返回的字段名与 AttachmentFile 不一致(如 fileUrl → url、
27
+ * fileId → uuid)或需要在数据层补充额外字段的场景。
28
+ *
29
+ * @param raw - 代码块 JSON 中的原始文件对象(未经处理)
30
+ * @param defaultFile - 由内置逻辑生成的默认 AttachmentFile,可在此基础上做局部覆盖
31
+ * @returns 转换后的 AttachmentFile;返回 null 时该条目将被过滤掉
32
+ *
33
+ * @example
34
+ * ```tsx
35
+ * fileMapConfig={{
36
+ * normalizeFile: (raw, defaultFile) => ({
37
+ * ...defaultFile,
38
+ * url: raw.fileUrl as string,
39
+ * uuid: raw.fileId as string,
40
+ * }),
41
+ * }}
42
+ * ```
43
+ */
44
+ normalizeFile?: (raw: Record<string, unknown>, defaultFile: AttachmentFile) => AttachmentFile | null;
45
+ }
8
46
  export interface MarkdownRendererEleProps {
9
47
  /** HTML tag name, e.g. 'p', 'h1', 'blockquote', 'pre' */
10
48
  tagName: string;
@@ -92,6 +130,11 @@ export interface MarkdownRendererProps {
92
130
  /** 自定义渲染函数,接收解析后的 JSON value,返回 React 节点 */
93
131
  render?: (value: any) => React.ReactNode;
94
132
  };
133
+ /**
134
+ * FileMapView 配置,透传给 agentic-ui-filemap 代码块渲染器。
135
+ * 可在 markdownRenderConfig 中统一配置图片 onPreview 和 itemRender。
136
+ */
137
+ fileMapConfig?: FileMapConfig;
95
138
  /**
96
139
  * 自定义元素渲染函数(markdown 渲染模式)
97
140
  * 与 Slate 模式的 eleItemRender 对应,允许拦截并替换任意块级/行内元素的渲染结果。
@@ -652,20 +652,41 @@ import { debounce, getDataHash, isConfigEqual, isNotEmpty, toNumber } from "./ut
652
652
  var _ref8;
653
653
  var _config_rest10;
654
654
  // 直方图数据转换:提取原始值
655
+ // 同时支持预分箱格式:groupKey.DIM_LEFT / groupKey.DIM_RIGHT + MEASURE_PROB[0].actualValue
655
656
  var histogramData = (chartData || []).map(function(row) {
657
+ var _row_groupKey, _row_groupKey1, _row_MEASURE_PROB_;
658
+ var dimLeft = row === null || row === void 0 ? void 0 : (_row_groupKey = row.groupKey) === null || _row_groupKey === void 0 ? void 0 : _row_groupKey.DIM_LEFT;
659
+ var dimRight = row === null || row === void 0 ? void 0 : (_row_groupKey1 = row.groupKey) === null || _row_groupKey1 === void 0 ? void 0 : _row_groupKey1.DIM_RIGHT;
660
+ var measureProb = Array.isArray(row === null || row === void 0 ? void 0 : row.MEASURE_PROB) ? (_row_MEASURE_PROB_ = row.MEASURE_PROB[0]) === null || _row_MEASURE_PROB_ === void 0 ? void 0 : _row_MEASURE_PROB_.actualValue : undefined;
661
+ if (typeof dimLeft === 'number' && typeof dimRight === 'number' && typeof measureProb === 'number') {
662
+ var type = getFieldValue(row, colorLegend);
663
+ var category = getFieldValue(row, groupBy);
664
+ var filterLabel = getFieldValue(row, filterBy);
665
+ return _object_spread({
666
+ value: measureProb,
667
+ left: dimLeft,
668
+ right: dimRight
669
+ }, type ? {
670
+ type: type
671
+ } : {}, category ? {
672
+ category: category
673
+ } : {}, filterLabel ? {
674
+ filterLabel: filterLabel
675
+ } : {});
676
+ }
656
677
  var value = getFieldValueSafely(row, config === null || config === void 0 ? void 0 : config.y);
657
- var type = getFieldValue(row, colorLegend);
658
- var category = getFieldValue(row, groupBy);
659
- var filterLabel = getFieldValue(row, filterBy);
678
+ var type1 = getFieldValue(row, colorLegend);
679
+ var category1 = getFieldValue(row, groupBy);
680
+ var filterLabel1 = getFieldValue(row, filterBy);
660
681
  var numValue = typeof value === 'number' ? value : toNumber(value, Number.NaN);
661
682
  return _object_spread({
662
683
  value: Number.isFinite(numValue) ? numValue : 0
663
- }, type ? {
664
- type: type
665
- } : {}, category ? {
666
- category: category
667
- } : {}, filterLabel ? {
668
- filterLabel: filterLabel
684
+ }, type1 ? {
685
+ type: type1
686
+ } : {}, category1 ? {
687
+ category: category1
688
+ } : {}, filterLabel1 ? {
689
+ filterLabel: filterLabel1
669
690
  } : {});
670
691
  });
671
692
  return /*#__PURE__*/ React.createElement(HistogramChart, {
@@ -6,8 +6,12 @@ import type { ChartClassNames, ChartStyles } from '../types/classNames';
6
6
  * 直方图数据项接口
7
7
  */
8
8
  export interface HistogramChartDataItem {
9
- /** 原始数据值 */
9
+ /** 原始数据值(自动分箱时为原始数值;预分箱时为该箱的 y 轴值) */
10
10
  value: number;
11
+ /** 预分箱左边界(设置后与 right 一起跳过自动分箱) */
12
+ left?: number;
13
+ /** 预分箱右边界 */
14
+ right?: number;
11
15
  /** 数据系列(用于分组显示) */
12
16
  type?: string;
13
17
  /** 分类(用于筛选) */
@@ -200,13 +200,18 @@ var histogramChartComponentsRegistered = false;
200
200
  };
201
201
  }
202
202
  /**
203
- * 格式化分箱标签
203
+ * 格式化分箱标签,对超出范围的数字使用普通计数格式而非科学记数法
204
204
  */ function formatBinLabel(start, end) {
205
205
  var formatNum = function formatNum(n) {
206
- if (Math.abs(n) >= 1000 || Math.abs(n) < 0.01 && n !== 0) {
207
- return n.toExponential(1);
206
+ if (Math.abs(n) < 0.01 && n !== 0) {
207
+ return n.toFixed(4);
208
208
  }
209
- return n.toFixed(2);
209
+ if (Number.isInteger(n)) {
210
+ return n.toLocaleString('en-US', {
211
+ useGrouping: false
212
+ });
213
+ }
214
+ return parseFloat(n.toFixed(2)).toString();
210
215
  };
211
216
  return "".concat(formatNum(start), " - ").concat(formatNum(end));
212
217
  }
@@ -345,6 +350,14 @@ var HistogramChart = function HistogramChart(_0) {
345
350
  }, [
346
351
  filteredData
347
352
  ]);
353
+ // 判断是否为预分箱数据(所有项都有 left 和 right 字段)
354
+ var isPreBinned = useMemo(function() {
355
+ return filteredData.length > 0 && filteredData.every(function(item) {
356
+ return typeof item.left === 'number' && typeof item.right === 'number';
357
+ });
358
+ }, [
359
+ filteredData
360
+ ]);
348
361
  // 计算分箱
349
362
  var binning = useMemo(function() {
350
363
  if (filteredData.length === 0) {
@@ -354,24 +367,57 @@ var HistogramChart = function HistogramChart(_0) {
354
367
  binCount: 0
355
368
  };
356
369
  }
370
+ if (isPreBinned) {
371
+ // 预分箱模式:按 left 排序,直接生成区间标签
372
+ var sorted = _to_consumable_array(filteredData).sort(function(a, b) {
373
+ return a.left - b.left;
374
+ });
375
+ var uniqueEdgePairs = sorted.reduce(function(acc, item) {
376
+ var l = item.left;
377
+ var r = item.right;
378
+ if (!acc.some(function(p) {
379
+ return p.left === l && p.right === r;
380
+ })) {
381
+ acc.push({
382
+ left: l,
383
+ right: r
384
+ });
385
+ }
386
+ return acc;
387
+ }, []);
388
+ var edges = _to_consumable_array(uniqueEdgePairs.map(function(p) {
389
+ return p.left;
390
+ })).concat([
391
+ uniqueEdgePairs[uniqueEdgePairs.length - 1].right
392
+ ]);
393
+ var labels = uniqueEdgePairs.map(function(p) {
394
+ return formatBinLabel(p.left, p.right);
395
+ });
396
+ return {
397
+ edges: edges,
398
+ labels: labels,
399
+ binCount: labels.length
400
+ };
401
+ }
357
402
  var allValues = filteredData.map(function(item) {
358
403
  return item.value;
359
404
  });
360
405
  var autoBinCount = customBinCount || calculateBinCount(allValues.length);
361
- var edges = calculateBinEdges(allValues, autoBinCount).edges;
406
+ var edges1 = calculateBinEdges(allValues, autoBinCount).edges;
362
407
  // 生成分箱标签
363
- var labels = [];
364
- for(var i = 0; i < edges.length - 1; i++){
365
- labels.push(formatBinLabel(edges[i], edges[i + 1]));
408
+ var labels1 = [];
409
+ for(var i = 0; i < edges1.length - 1; i++){
410
+ labels1.push(formatBinLabel(edges1[i], edges1[i + 1]));
366
411
  }
367
412
  return {
368
- edges: edges,
369
- labels: labels,
413
+ edges: edges1,
414
+ labels: labels1,
370
415
  binCount: autoBinCount
371
416
  };
372
417
  }, [
373
418
  filteredData,
374
- customBinCount
419
+ customBinCount,
420
+ isPreBinned
375
421
  ]);
376
422
  // 计算每个分箱的频率/计数
377
423
  var histogramData = useMemo(function() {
@@ -380,6 +426,26 @@ var HistogramChart = function HistogramChart(_0) {
380
426
  return {};
381
427
  }
382
428
  var result = {};
429
+ if (isPreBinned) {
430
+ // 预分箱模式:直接将 value 映射到对应区间
431
+ types.forEach(function(type) {
432
+ if (!type) return;
433
+ var typeData = filteredData.filter(function(item) {
434
+ return (item.type || '默认') === type;
435
+ });
436
+ var counts = new Array(labels.length).fill(0);
437
+ typeData.forEach(function(item) {
438
+ var l = item.left;
439
+ var r = item.right;
440
+ var idx = labels.indexOf(formatBinLabel(l, r));
441
+ if (idx !== -1) {
442
+ counts[idx] += showFrequency ? item.value : item.value;
443
+ }
444
+ });
445
+ result[type] = counts;
446
+ });
447
+ return result;
448
+ }
383
449
  types.forEach(function(type) {
384
450
  if (!type) return; // Skip undefined types
385
451
  var typeData = filteredData.filter(function(item) {
@@ -411,7 +477,8 @@ var HistogramChart = function HistogramChart(_0) {
411
477
  filteredData,
412
478
  types,
413
479
  binning,
414
- showFrequency
480
+ showFrequency,
481
+ isPreBinned
415
482
  ]);
416
483
  // 构建 Chart.js 数据结构
417
484
  var processedData = useMemo(function() {
@@ -58,6 +58,14 @@ export interface ScatterChartProps extends ChartContainerProps {
58
58
  loading?: boolean;
59
59
  /** 自定义样式对象(支持对象格式,为每层DOM设置样式) */
60
60
  styles?: ChartStyles;
61
+ /** X 轴最小值,不传则从数据自动计算 */
62
+ xMin?: number;
63
+ /** X 轴最大值,不传则从数据自动计算 */
64
+ xMax?: number;
65
+ /** Y 轴最小值,不传则从数据自动计算 */
66
+ yMin?: number;
67
+ /** Y 轴最大值,不传则从数据自动计算 */
68
+ yMax?: number;
61
69
  }
62
70
  declare const ScatterChart: React.FC<ScatterChartProps>;
63
71
  export default ScatterChart;
@@ -6,6 +6,9 @@ function _array_like_to_array(arr, len) {
6
6
  function _array_with_holes(arr) {
7
7
  if (Array.isArray(arr)) return arr;
8
8
  }
9
+ function _array_without_holes(arr) {
10
+ if (Array.isArray(arr)) return _array_like_to_array(arr);
11
+ }
9
12
  function _define_property(obj, key, value) {
10
13
  if (key in obj) {
11
14
  Object.defineProperty(obj, key, {
@@ -19,6 +22,9 @@ function _define_property(obj, key, value) {
19
22
  }
20
23
  return obj;
21
24
  }
25
+ function _iterable_to_array(iter) {
26
+ if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
27
+ }
22
28
  function _iterable_to_array_limit(arr, i) {
23
29
  var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
24
30
  if (_i == null) return;
@@ -46,6 +52,9 @@ function _iterable_to_array_limit(arr, i) {
46
52
  function _non_iterable_rest() {
47
53
  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
54
  }
55
+ function _non_iterable_spread() {
56
+ throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
57
+ }
49
58
  function _object_spread(target) {
50
59
  for(var i = 1; i < arguments.length; i++){
51
60
  var source = arguments[i] != null ? arguments[i] : {};
@@ -124,6 +133,9 @@ function _object_without_properties_loose(source, excluded) {
124
133
  function _sliced_to_array(arr, i) {
125
134
  return _array_with_holes(arr) || _iterable_to_array_limit(arr, i) || _unsupported_iterable_to_array(arr, i) || _non_iterable_rest();
126
135
  }
136
+ function _to_consumable_array(arr) {
137
+ return _array_without_holes(arr) || _iterable_to_array(arr) || _unsupported_iterable_to_array(arr) || _non_iterable_spread();
138
+ }
127
139
  function _type_of(obj) {
128
140
  "@swc/helpers - typeof";
129
141
  return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
@@ -149,7 +161,7 @@ import { hexToRgba, resolveCssVariable } from "../utils";
149
161
  import { useStyle } from "./style";
150
162
  var scatterChartComponentsRegistered = false;
151
163
  var ScatterChart = function ScatterChart(_0) {
152
- var data = _0.data, _0_width = _0.width, width = _0_width === void 0 ? 600 : _0_width, _0_height = _0.height, height = _0_height === void 0 ? 400 : _0_height, className = _0.className, classNamesProp = _0.classNames, title = _0.title, toolbarExtra = _0.toolbarExtra, _0_renderFilterInToolbar = _0.renderFilterInToolbar, renderFilterInToolbar = _0_renderFilterInToolbar === void 0 ? false : _0_renderFilterInToolbar, dataTime = _0.dataTime, _0_xUnit = _0.xUnit, xUnit = _0_xUnit === void 0 ? '月' : _0_xUnit, yUnit = _0.yUnit, xAxisLabel = _0.xAxisLabel, yAxisLabel = _0.yAxisLabel, _0_xPosition = _0.xPosition, xPosition = _0_xPosition === void 0 ? 'bottom' : _0_xPosition, _0_yPosition = _0.yPosition, yPosition = _0_yPosition === void 0 ? 'left' : _0_yPosition, _0_hiddenX = _0.hiddenX, hiddenX = _0_hiddenX === void 0 ? false : _0_hiddenX, _0_hiddenY = _0.hiddenY, hiddenY = _0_hiddenY === void 0 ? false : _0_hiddenY, _0_showGrid = _0.showGrid, showGrid = _0_showGrid === void 0 ? true : _0_showGrid, _0_theme = _0.theme, theme = _0_theme === void 0 ? 'light' : _0_theme, color = _0.color, statisticConfig = _0.statistic, _0_textMaxWidth = _0.textMaxWidth, textMaxWidth = _0_textMaxWidth === void 0 ? 80 : _0_textMaxWidth, _0_loading = _0.loading, loading = _0_loading === void 0 ? false : _0_loading, props = _object_without_properties(_0, [
164
+ var data = _0.data, _0_width = _0.width, width = _0_width === void 0 ? 600 : _0_width, _0_height = _0.height, height = _0_height === void 0 ? 400 : _0_height, className = _0.className, classNamesProp = _0.classNames, title = _0.title, toolbarExtra = _0.toolbarExtra, _0_renderFilterInToolbar = _0.renderFilterInToolbar, renderFilterInToolbar = _0_renderFilterInToolbar === void 0 ? false : _0_renderFilterInToolbar, dataTime = _0.dataTime, _0_xUnit = _0.xUnit, xUnit = _0_xUnit === void 0 ? '月' : _0_xUnit, yUnit = _0.yUnit, xAxisLabel = _0.xAxisLabel, yAxisLabel = _0.yAxisLabel, _0_xPosition = _0.xPosition, xPosition = _0_xPosition === void 0 ? 'bottom' : _0_xPosition, _0_yPosition = _0.yPosition, yPosition = _0_yPosition === void 0 ? 'left' : _0_yPosition, _0_hiddenX = _0.hiddenX, hiddenX = _0_hiddenX === void 0 ? false : _0_hiddenX, _0_hiddenY = _0.hiddenY, hiddenY = _0_hiddenY === void 0 ? false : _0_hiddenY, _0_showGrid = _0.showGrid, showGrid = _0_showGrid === void 0 ? true : _0_showGrid, _0_theme = _0.theme, theme = _0_theme === void 0 ? 'light' : _0_theme, color = _0.color, statisticConfig = _0.statistic, _0_textMaxWidth = _0.textMaxWidth, textMaxWidth = _0_textMaxWidth === void 0 ? 80 : _0_textMaxWidth, _0_loading = _0.loading, loading = _0_loading === void 0 ? false : _0_loading, xMinProp = _0.xMin, xMaxProp = _0.xMax, yMinProp = _0.yMin, yMaxProp = _0.yMax, props = _object_without_properties(_0, [
153
165
  "data",
154
166
  "width",
155
167
  "height",
@@ -172,7 +184,11 @@ var ScatterChart = function ScatterChart(_0) {
172
184
  "color",
173
185
  "statistic",
174
186
  "textMaxWidth",
175
- "loading"
187
+ "loading",
188
+ "xMin",
189
+ "xMax",
190
+ "yMin",
191
+ "yMax"
176
192
  ]);
177
193
  useMemo(function() {
178
194
  if (scatterChartComponentsRegistered) {
@@ -304,6 +320,60 @@ var ScatterChart = function ScatterChart(_0) {
304
320
  }
305
321
  }, "暂无有效数据")));
306
322
  }
323
+ // 从数据中自动计算坐标轴范围,加 10% 边距,方便查看边界点
324
+ var computeAxisBounds = function computeAxisBounds(values, overrideMin, overrideMax, fallbackMin, fallbackMax) {
325
+ var _Math, _Math1;
326
+ if (overrideMin !== undefined && overrideMax !== undefined) {
327
+ return {
328
+ min: overrideMin,
329
+ max: overrideMax
330
+ };
331
+ }
332
+ if (values.length === 0) {
333
+ return {
334
+ min: fallbackMin,
335
+ max: fallbackMax
336
+ };
337
+ }
338
+ var dataMin = (_Math = Math).min.apply(_Math, _to_consumable_array(values));
339
+ var dataMax = (_Math1 = Math).max.apply(_Math1, _to_consumable_array(values));
340
+ var range = dataMax - dataMin || 1;
341
+ var padding = range * 0.1;
342
+ return {
343
+ min: overrideMin !== undefined ? overrideMin : Math.floor(dataMin - padding),
344
+ max: overrideMax !== undefined ? overrideMax : Math.ceil(dataMax + padding)
345
+ };
346
+ };
347
+ var allXValues = filteredData.map(function(item) {
348
+ var v = typeof item.x === 'number' ? item.x : Number(item.x);
349
+ return Number.isFinite(v) ? v : null;
350
+ }).filter(function(v) {
351
+ return v !== null;
352
+ });
353
+ var allYValues = filteredData.map(function(item) {
354
+ var v = typeof item.y === 'number' ? item.y : Number(item.y);
355
+ return Number.isFinite(v) ? v : null;
356
+ }).filter(function(v) {
357
+ return v !== null;
358
+ });
359
+ var xBounds = computeAxisBounds(allXValues, xMinProp, xMaxProp, 1, 12);
360
+ var yBounds = computeAxisBounds(allYValues, yMinProp, yMaxProp, 0, 100);
361
+ var computeStepSize = function computeStepSize(min, max) {
362
+ var targetTicks = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : 10;
363
+ var range = max - min;
364
+ if (range <= 0) return 1;
365
+ var rawStep = range / targetTicks;
366
+ var magnitude = Math.pow(10, Math.floor(Math.log10(rawStep)));
367
+ var normalized = rawStep / magnitude;
368
+ var step;
369
+ if (normalized <= 1) step = magnitude;
370
+ else if (normalized <= 2) step = 2 * magnitude;
371
+ else if (normalized <= 5) step = 5 * magnitude;
372
+ else step = 10 * magnitude;
373
+ return step;
374
+ };
375
+ var xStepSize = computeStepSize(xBounds.min, xBounds.max);
376
+ var yStepSize = computeStepSize(yBounds.min, yBounds.max);
307
377
  // 构建数据集,添加更强的安全检查
308
378
  var datasets = datasetTypes.map(function(type, index) {
309
379
  var typeData = filteredData.filter(function(item) {
@@ -546,10 +616,10 @@ var ScatterChart = function ScatterChart(_0) {
546
616
  weight: 500
547
617
  }
548
618
  },
549
- min: 1,
550
- max: 12,
619
+ min: xBounds.min,
620
+ max: xBounds.max,
551
621
  ticks: {
552
- stepSize: 1,
622
+ stepSize: xStepSize,
553
623
  color: axisTextColor,
554
624
  font: {
555
625
  size: isMobile ? 8 : 10
@@ -579,10 +649,10 @@ var ScatterChart = function ScatterChart(_0) {
579
649
  },
580
650
  align: 'center'
581
651
  },
582
- min: 0,
583
- max: 100,
652
+ min: yBounds.min,
653
+ max: yBounds.max,
584
654
  ticks: {
585
- stepSize: 10,
655
+ stepSize: yStepSize,
586
656
  color: axisTextColor,
587
657
  font: {
588
658
  family: 'PingFang SC',
@@ -305,6 +305,8 @@ import { loadAceEditor, loadAceTheme } from "../loadAceEditor";
305
305
  var debounceTimer = useRef(0);
306
306
  var editorRef = useRef();
307
307
  var dom = useRef(null);
308
+ // 记录 Ace 会话当前使用的语言,用于语言变更时动态切换而不是销毁重建
309
+ var aceLanguageRef = useRef(element.language);
308
310
  // Ace Editor 异步加载状态
309
311
  var _useState = _sliced_to_array(useState(false), 2), aceLoaded = _useState[0], setAceLoaded = _useState[1];
310
312
  var aceModuleRef = useRef(null);
@@ -493,6 +495,8 @@ import { loadAceEditor, loadAceTheme } from "../loadAceEditor";
493
495
  // 初始化 Ace 编辑器(仅在库加载完成后)
494
496
  // 注意: intentionally 不将 editorProps.codeProps 列入依赖,因其对象引用在父组件内容更新时会频繁变化,
495
497
  // 导致编辑器被不必要地销毁重建。codeProps 的配置在初始化时已应用,主题等动态变更由独立 effect 处理。
498
+ // element.language 同样不列为依赖,语言切换由独立的 effect 处理,避免流式渲染中 language
499
+ // 逐字符变化时触发编辑器销毁重建。
496
500
  useEffect(function() {
497
501
  if (process.env.NODE_ENV === 'test') return;
498
502
  if (!aceLoaded || !aceModuleRef.current || !dom.current) return;
@@ -521,6 +525,7 @@ import { loadAceEditor, loadAceTheme } from "../loadAceEditor";
521
525
  showGutter: true
522
526
  }, codeProps));
523
527
  editorRef.current = codeEditor;
528
+ aceLanguageRef.current = element.language;
524
529
  // 设置主题
525
530
  var theme = codeProps.theme || props.theme || 'github';
526
531
  codeEditor.setTheme("ace/theme/".concat(theme));
@@ -551,19 +556,59 @@ import { loadAceEditor, loadAceTheme } from "../loadAceEditor";
551
556
  });
552
557
  })();
553
558
  }, 16);
554
- if (readonly) return;
555
- // 配置编辑器事件
556
- setupEditorEvents(codeEditor);
559
+ if (!readonly) {
560
+ // 配置编辑器事件
561
+ setupEditorEvents(codeEditor);
562
+ }
557
563
  return function() {
558
564
  clearTimeout(debounceTimer.current);
559
565
  codeEditor.destroy();
560
566
  };
567
+ // eslint-disable-next-line react-hooks/exhaustive-deps
561
568
  }, [
562
569
  aceLoaded,
563
- element.language,
564
570
  readonly,
565
571
  setupEditorEvents
566
572
  ]);
573
+ // 语言切换时动态更新 Ace 会话模式,无需销毁重建编辑器
574
+ useEffect(function() {
575
+ if (!editorRef.current || !aceLoaded) return;
576
+ if (aceLanguageRef.current === element.language) return;
577
+ aceLanguageRef.current = element.language;
578
+ (function() {
579
+ return _async_to_generator(function() {
580
+ var lang, aceLangs, _editorRef_current, _editorRef_current1;
581
+ return _ts_generator(this, function(_state) {
582
+ switch(_state.label){
583
+ case 0:
584
+ lang = element.language || '';
585
+ if (modeMap.has(lang)) {
586
+ lang = modeMap.get(lang);
587
+ }
588
+ return [
589
+ 4,
590
+ getAceLangs()
591
+ ];
592
+ case 1:
593
+ aceLangs = _state.sent();
594
+ if (aceLangs.has(lang)) {
595
+ ;
596
+ (_editorRef_current = editorRef.current) === null || _editorRef_current === void 0 ? void 0 : _editorRef_current.session.setMode("ace/mode/".concat(lang));
597
+ } else {
598
+ ;
599
+ (_editorRef_current1 = editorRef.current) === null || _editorRef_current1 === void 0 ? void 0 : _editorRef_current1.session.setMode("ace/mode/text");
600
+ }
601
+ return [
602
+ 2
603
+ ];
604
+ }
605
+ });
606
+ })();
607
+ })();
608
+ }, [
609
+ element.language,
610
+ aceLoaded
611
+ ]);
567
612
  // 监听外部值变化
568
613
  useEffect(function() {
569
614
  var value = element.value || '';
@@ -572,10 +617,26 @@ import { loadAceEditor, loadAceTheme } from "../loadAceEditor";
572
617
  value = JSON.stringify(partialParse(value), null, 2);
573
618
  } catch (e) {}
574
619
  }
575
- if (value !== codeRef.current || readonly) {
576
- var _editorRef_current, _editorRef_current1;
577
- if (element) (_editorRef_current = editorRef.current) === null || _editorRef_current === void 0 ? void 0 : _editorRef_current.setValue(value);
578
- (_editorRef_current1 = editorRef.current) === null || _editorRef_current1 === void 0 ? void 0 : _editorRef_current1.clearSelection();
620
+ if (value === codeRef.current) return;
621
+ var editor = editorRef.current;
622
+ var prev = codeRef.current;
623
+ codeRef.current = value;
624
+ if (!editor) return;
625
+ // 流式渲染时内容只会在末尾追加。通过检测 value.startsWith(prev) 来判断是否为纯追加,
626
+ // 若是则调用 session.insert 在末尾插入增量内容,避免 setValue 清空重写导致的闪动。
627
+ var isAppend = value.startsWith(prev);
628
+ if (isAppend) {
629
+ var delta = value.slice(prev.length);
630
+ var doc = editor.session.getDocument();
631
+ var lastRow = doc.getLength() - 1;
632
+ var lastCol = doc.getLine(lastRow).length;
633
+ editor.session.insert({
634
+ row: lastRow,
635
+ column: lastCol
636
+ }, delta);
637
+ } else {
638
+ editor.setValue(value);
639
+ editor.clearSelection();
579
640
  }
580
641
  }, [
581
642
  element.value
@@ -346,7 +346,6 @@ import { AceEditor, AceEditorContainer, CodeContainer, CodeToolbar, HtmlPreview,
346
346
  props.children,
347
347
  state.showBorder,
348
348
  state.hide,
349
- state.htmlStr,
350
349
  isSelected,
351
350
  (_editorProps_codeProps1 = editorProps.codeProps) === null || _editorProps_codeProps1 === void 0 ? void 0 : _editorProps_codeProps1.hideToolBar,
352
351
  (_editorProps_codeProps2 = editorProps.codeProps) === null || _editorProps_codeProps2 === void 0 ? void 0 : _editorProps_codeProps2.disableHtmlPreview,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ant-design/agentic-ui",
3
- "version": "2.30.12",
3
+ "version": "2.30.13",
4
4
  "description": "面向智能体的 UI 组件库,提供多步推理可视化、工具调用展示、任务执行协同等 Agentic UI 能力",
5
5
  "repository": "git@github.com:ant-design/agentic-ui.git",
6
6
  "license": "MIT",
@@ -24,6 +24,7 @@
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",
27
28
  "prettier": "prettier --write \"{src,docs,test}/**/*.{js,jsx,ts,tsx,css,less,json,md}\"",
28
29
  "preview": "pnpm dumi preview",
29
30
  "report:demo": "node scripts/generateDemoReport.js",