@ant-design/agentic-ui 2.29.27 → 2.29.28

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.
@@ -202,7 +202,12 @@ var getContentStyle = function getContentStyle(standalone, customStyle) {
202
202
  style: styles === null || styles === void 0 ? void 0 : styles.bubbleListItemExtraStyle,
203
203
  className: cx("".concat(prefixClass, "-bubble-before"), "".concat(prefixClass, "-bubble-before-").concat(placement), "".concat(prefixClass, "-bubble-before-user"), hashId),
204
204
  "data-testid": "message-before"
205
- }, contentBeforeDom), hasFileMap && /*#__PURE__*/ React.createElement("div", {
205
+ }, contentBeforeDom), /*#__PURE__*/ React.createElement("div", {
206
+ style: contentStyle,
207
+ className: cx("".concat(prefixClass, "-bubble-content"), "".concat(prefixClass, "-bubble-content-").concat(placement), "".concat(prefixClass, "-bubble-content-user"), _define_property({}, "".concat(prefixClass, "-bubble-content-pure"), props.pure), classNames === null || classNames === void 0 ? void 0 : classNames.bubbleListItemContentClassName, hashId),
208
+ onDoubleClick: props.onDoubleClick,
209
+ "data-testid": "message-content"
210
+ }, childrenDom), hasFileMap && /*#__PURE__*/ React.createElement("div", {
206
211
  style: fileViewStyle,
207
212
  className: cx("".concat(prefixClass, "-bubble-after"), "".concat(prefixClass, "-bubble-after-").concat(placement), "".concat(prefixClass, "-bubble-after-ai"), hashId),
208
213
  "data-testid": "message-after"
@@ -210,12 +215,7 @@ var getContentStyle = function getContentStyle(standalone, customStyle) {
210
215
  bubbleListRef: props.bubbleListRef,
211
216
  bubble: props,
212
217
  placement: placement
213
- })), /*#__PURE__*/ React.createElement("div", {
214
- style: contentStyle,
215
- className: cx("".concat(prefixClass, "-bubble-content"), "".concat(prefixClass, "-bubble-content-").concat(placement), "".concat(prefixClass, "-bubble-content-user"), _define_property({}, "".concat(prefixClass, "-bubble-content-pure"), props.pure), classNames === null || classNames === void 0 ? void 0 : classNames.bubbleListItemContentClassName, hashId),
216
- onDoubleClick: props.onDoubleClick,
217
- "data-testid": "message-content"
218
- }, childrenDom), contentAfterDom)))));
218
+ })), contentAfterDom)))));
219
219
  if ((bubbleRenderConfig === null || bubbleRenderConfig === void 0 ? void 0 : bubbleRenderConfig.render) === false) return null;
220
220
  return /*#__PURE__*/ React.createElement(MessagesContext.Provider, {
221
221
  value: {
@@ -85,6 +85,10 @@ export declare class SchemaEditorBridgeManager {
85
85
  * 检查某个 ID 是否已注册
86
86
  */
87
87
  has(id: string): boolean;
88
+ /**
89
+ * 获取指定 id 的当前内容(用于测试或调试)
90
+ */
91
+ getContentById(id: string): string | undefined;
88
92
  /**
89
93
  * 启动 Bridge(幂等,已启动时直接返回)
90
94
  */
@@ -134,6 +134,15 @@ import { MarkdownEditor } from "../../MarkdownEditor";
134
134
  return this.registry.has(id);
135
135
  }
136
136
  },
137
+ {
138
+ /**
139
+ * 获取指定 id 的当前内容(用于测试或调试)
140
+ */ key: "getContentById",
141
+ value: function getContentById(id) {
142
+ var handler = this.registry.get(id);
143
+ return handler === null || handler === void 0 ? void 0 : handler.getContent();
144
+ }
145
+ },
137
146
  {
138
147
  key: "startBridge",
139
148
  value: /**
@@ -164,6 +164,10 @@ export var getRemoteMediaType = function getRemoteMediaType(url) {
164
164
  2,
165
165
  'other'
166
166
  ];
167
+ if (typeof url !== 'string') return [
168
+ 2,
169
+ 'other'
170
+ ];
167
171
  if (url.startsWith('data:')) {
168
172
  m = url.match(/data:image\/(\w+);base64,(.*)/);
169
173
  if (m) return [
@@ -175,10 +179,6 @@ export var getRemoteMediaType = function getRemoteMediaType(url) {
175
179
  'other'
176
180
  ];
177
181
  }
178
- if (typeof url !== 'string') return [
179
- 2,
180
- 'other'
181
- ];
182
182
  _state.label = 1;
183
183
  case 1:
184
184
  _state.trys.push([
@@ -1,8 +1,168 @@
1
- import { Eye, FileFailed, FileUploadingSpin } from "@sofa-design/icons";
1
+ function _array_like_to_array(arr, len) {
2
+ if (len == null || len > arr.length) len = arr.length;
3
+ for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
4
+ return arr2;
5
+ }
6
+ function _array_with_holes(arr) {
7
+ if (Array.isArray(arr)) return arr;
8
+ }
9
+ function _define_property(obj, key, value) {
10
+ if (key in obj) {
11
+ Object.defineProperty(obj, key, {
12
+ value: value,
13
+ enumerable: true,
14
+ configurable: true,
15
+ writable: true
16
+ });
17
+ } else {
18
+ obj[key] = value;
19
+ }
20
+ return obj;
21
+ }
22
+ function _iterable_to_array_limit(arr, i) {
23
+ var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
24
+ if (_i == null) return;
25
+ var _arr = [];
26
+ var _n = true;
27
+ var _d = false;
28
+ var _s, _e;
29
+ try {
30
+ for(_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true){
31
+ _arr.push(_s.value);
32
+ if (i && _arr.length === i) break;
33
+ }
34
+ } catch (err) {
35
+ _d = true;
36
+ _e = err;
37
+ } finally{
38
+ try {
39
+ if (!_n && _i["return"] != null) _i["return"]();
40
+ } finally{
41
+ if (_d) throw _e;
42
+ }
43
+ }
44
+ return _arr;
45
+ }
46
+ function _non_iterable_rest() {
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
+ }
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
+ }
64
+ function ownKeys(object, enumerableOnly) {
65
+ var keys = Object.keys(object);
66
+ if (Object.getOwnPropertySymbols) {
67
+ var symbols = Object.getOwnPropertySymbols(object);
68
+ if (enumerableOnly) {
69
+ symbols = symbols.filter(function(sym) {
70
+ return Object.getOwnPropertyDescriptor(object, sym).enumerable;
71
+ });
72
+ }
73
+ keys.push.apply(keys, symbols);
74
+ }
75
+ return keys;
76
+ }
77
+ function _object_spread_props(target, source) {
78
+ source = source != null ? source : {};
79
+ if (Object.getOwnPropertyDescriptors) {
80
+ Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
81
+ } else {
82
+ ownKeys(Object(source)).forEach(function(key) {
83
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
84
+ });
85
+ }
86
+ return target;
87
+ }
88
+ function _sliced_to_array(arr, i) {
89
+ return _array_with_holes(arr) || _iterable_to_array_limit(arr, i) || _unsupported_iterable_to_array(arr, i) || _non_iterable_rest();
90
+ }
91
+ function _unsupported_iterable_to_array(o, minLen) {
92
+ if (!o) return;
93
+ if (typeof o === "string") return _array_like_to_array(o, minLen);
94
+ var n = Object.prototype.toString.call(o).slice(8, -1);
95
+ if (n === "Object" && o.constructor) n = o.constructor.name;
96
+ if (n === "Map" || n === "Set") return Array.from(n);
97
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
98
+ }
99
+ import { Eye, FileFailed, FileUploadingSpin, Play } from "@sofa-design/icons";
2
100
  import { Image } from "antd";
3
- import React from "react";
101
+ import React, { useEffect, useState } from "react";
4
102
  import { getFileTypeIcon } from "../../../Workspace/File/utils";
5
- import { isImageFile } from "../utils";
103
+ import { isImageFile, isVideoFile } from "../utils";
104
+ var VideoThumbnail = function VideoThumbnail(param) {
105
+ var src = param.src, className = param.className, style = param.style;
106
+ return /*#__PURE__*/ React.createElement("div", {
107
+ className: className,
108
+ style: _object_spread_props(_object_spread({}, style), {
109
+ position: 'relative',
110
+ overflow: 'hidden',
111
+ borderRadius: 'var(--radius-base)',
112
+ flexShrink: 0
113
+ })
114
+ }, /*#__PURE__*/ React.createElement("video", {
115
+ src: src,
116
+ preload: "metadata",
117
+ muted: true,
118
+ playsInline: true,
119
+ style: {
120
+ width: '100%',
121
+ height: '100%',
122
+ objectFit: 'cover',
123
+ display: 'block'
124
+ }
125
+ }), /*#__PURE__*/ React.createElement("div", {
126
+ style: {
127
+ position: 'absolute',
128
+ inset: 0,
129
+ display: 'flex',
130
+ alignItems: 'center',
131
+ justifyContent: 'center',
132
+ background: 'rgba(0, 0, 0, 0.35)',
133
+ pointerEvents: 'none'
134
+ }
135
+ }, /*#__PURE__*/ React.createElement(Play, {
136
+ style: {
137
+ width: 24,
138
+ height: 24,
139
+ color: '#fff'
140
+ }
141
+ })));
142
+ };
143
+ /**
144
+ * 从 File 创建并使用 object URL 的视频缩略图,避免每次渲染都创建新 URL
145
+ */ var VideoThumbnailFromBlob = function VideoThumbnailFromBlob(param) {
146
+ var file = param.file, className = param.className, style = param.style;
147
+ var _useState = _sliced_to_array(useState(function() {
148
+ return null;
149
+ }), 2), objectUrl = _useState[0], setObjectUrl = _useState[1];
150
+ useEffect(function() {
151
+ var url = URL.createObjectURL(file);
152
+ setObjectUrl(url);
153
+ return function() {
154
+ URL.revokeObjectURL(url);
155
+ };
156
+ }, [
157
+ file
158
+ ]);
159
+ if (!objectUrl) return null;
160
+ return /*#__PURE__*/ React.createElement(VideoThumbnail, {
161
+ src: objectUrl,
162
+ className: className,
163
+ style: style
164
+ });
165
+ };
6
166
  /**
7
167
  * AttachmentFileIcon 组件 - 附件文件图标组件
8
168
  *
@@ -65,6 +225,25 @@ export var AttachmentFileIcon = function AttachmentFileIcon(props) {
65
225
  alt: file.name
66
226
  });
67
227
  }
228
+ // 视频文件缩略图预览(与图片类似,带播放按钮)
229
+ if (isVideoFile(file)) {
230
+ var videoUrl = file.previewUrl || file.url;
231
+ if (videoUrl) {
232
+ return /*#__PURE__*/ React.createElement(VideoThumbnail, {
233
+ src: videoUrl,
234
+ className: className,
235
+ style: IMAGE_STYLE
236
+ });
237
+ }
238
+ if (file.size) {
239
+ return /*#__PURE__*/ React.createElement(VideoThumbnailFromBlob, {
240
+ key: "".concat(file.name, "-").concat(file.size, "-").concat(file.lastModified || 0),
241
+ file: file,
242
+ className: className,
243
+ style: IMAGE_STYLE
244
+ });
245
+ }
246
+ }
68
247
  // 其他类型文件图标
69
248
  var fileType = (_file_type = file.type) === null || _file_type === void 0 ? void 0 : _file_type.split('/').at(-1);
70
249
  return getFileTypeIcon(fileType, '', file.name);
@@ -25,6 +25,18 @@ export declare const kbToSize: (kb: number) => string;
25
25
  * @returns {boolean} 是否为图片文件
26
26
  */
27
27
  export declare const isImageFile: (file: File) => boolean;
28
+ /**
29
+ * 检查文件是否为视频类型
30
+ * 通过 MIME 类型和文件扩展名双重判断
31
+ *
32
+ * @param {File} file - 要检查的文件(含 AttachmentFile)
33
+ * @returns {boolean} 是否为视频文件
34
+ */
35
+ export declare const isVideoFile: (file: File) => boolean;
36
+ /**
37
+ * 检查文件是否为可展示的媒体类型(图片或视频)
38
+ */
39
+ export declare const isMediaFile: (file: File) => boolean;
28
40
  /**
29
41
  * 获取设备品牌
30
42
  *
@@ -64,6 +64,48 @@
64
64
  return fileName.endsWith(ext);
65
65
  });
66
66
  };
67
+ var VIDEO_EXTENSIONS = [
68
+ '.mp4',
69
+ '.webm',
70
+ '.ogg',
71
+ '.ogv',
72
+ '.mov',
73
+ '.avi',
74
+ '.wmv',
75
+ '.flv',
76
+ '.m4v',
77
+ '.mkv'
78
+ ];
79
+ var hasVideoExtension = function hasVideoExtension(pathOrName) {
80
+ var lower = (pathOrName === null || pathOrName === void 0 ? void 0 : pathOrName.toLowerCase()) || '';
81
+ var beforeQuery = lower.split('?')[0];
82
+ return VIDEO_EXTENSIONS.some(function(ext) {
83
+ return beforeQuery.endsWith(ext);
84
+ });
85
+ };
86
+ /**
87
+ * 检查文件是否为视频类型
88
+ * 通过 MIME 类型和文件扩展名双重判断
89
+ *
90
+ * @param {File} file - 要检查的文件(含 AttachmentFile)
91
+ * @returns {boolean} 是否为视频文件
92
+ */ export var isVideoFile = function isVideoFile(file) {
93
+ var _file_type;
94
+ if ((_file_type = file.type) === null || _file_type === void 0 ? void 0 : _file_type.startsWith('video/')) {
95
+ return true;
96
+ }
97
+ if (hasVideoExtension(file.name)) {
98
+ return true;
99
+ }
100
+ var attachmentFile = file;
101
+ var url = attachmentFile.previewUrl || attachmentFile.url;
102
+ return !!url && hasVideoExtension(url);
103
+ };
104
+ /**
105
+ * 检查文件是否为可展示的媒体类型(图片或视频)
106
+ */ export var isMediaFile = function isMediaFile(file) {
107
+ return isImageFile(file) || isVideoFile(file);
108
+ };
67
109
  /**
68
110
  * 设备品牌匹配列表
69
111
  */ var UA_MATCH_LIST = [
@@ -185,12 +185,12 @@ function _ts_generator(thisArg, body) {
185
185
  };
186
186
  }
187
187
  }
188
- import { FileSearch } from "@sofa-design/icons";
189
- import { ConfigProvider, Image } from "antd";
188
+ import { FileSearch, Play } from "@sofa-design/icons";
189
+ 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 { isImageFile } from "../AttachmentButton/utils";
193
+ import { isImageFile, isVideoFile } from "../AttachmentButton/utils";
194
194
  import { FileMapViewItem } from "./FileMapViewItem";
195
195
  import { useStyle } from "./style";
196
196
  /**
@@ -255,26 +255,48 @@ import { useStyle } from "./style";
255
255
  }, [
256
256
  fileList
257
257
  ]);
258
- // 所有非图片文件列表
259
- var allNoImageFiles = useMemo(function() {
258
+ // 视频列表,与图片一样以缩略图形式展示
259
+ var videoList = useMemo(function() {
260
260
  return fileList.filter(function(file) {
261
- return !isImageFile(file);
261
+ return isVideoFile(file);
262
262
  });
263
263
  }, [
264
264
  fileList
265
265
  ]);
266
- // 根据 maxDisplayCount 限制显示的非图片文件列表
267
- var noImageFileList = useMemo(function() {
268
- // 如果已展开所有文件,或者未设置最大显示数量,则显示所有文件
266
+ // 所有非图片、非视频文件列表
267
+ var allNoMediaFiles = useMemo(function() {
268
+ return fileList.filter(function(file) {
269
+ return !isImageFile(file) && !isVideoFile(file);
270
+ });
271
+ }, [
272
+ fileList
273
+ ]);
274
+ // 根据 maxDisplayCount 限制显示的非媒体文件列表
275
+ var noMediaFileList = useMemo(function() {
269
276
  if (showAllFiles || props.maxDisplayCount === undefined) {
270
- return allNoImageFiles;
277
+ return allNoMediaFiles;
271
278
  }
272
- return allNoImageFiles.slice(0, Math.max(0, props.maxDisplayCount));
279
+ return allNoMediaFiles.slice(0, Math.max(0, props.maxDisplayCount));
273
280
  }, [
274
- allNoImageFiles,
281
+ allNoMediaFiles,
275
282
  props.maxDisplayCount,
276
283
  showAllFiles
277
284
  ]);
285
+ var _useState1 = _sliced_to_array(useState(false), 2), videoModalOpen = _useState1[0], setVideoModalOpen = _useState1[1];
286
+ var _useState2 = _sliced_to_array(useState(null), 2), previewingVideo = _useState2[0], setPreviewingVideo = _useState2[1];
287
+ var handleVideoClick = function handleVideoClick(file) {
288
+ if (file.status === 'error') return;
289
+ if (props.onPreview) {
290
+ props.onPreview(file);
291
+ } else {
292
+ setPreviewingVideo(file);
293
+ setVideoModalOpen(true);
294
+ }
295
+ };
296
+ var handleVideoModalClose = function handleVideoModalClose() {
297
+ setVideoModalOpen(false);
298
+ setPreviewingVideo(null);
299
+ };
278
300
  var handleViewAllClick = function handleViewAllClick() {
279
301
  return _async_to_generator(function() {
280
302
  var shouldExpand;
@@ -350,7 +372,81 @@ import { useStyle } from "./style";
350
372
  src: file.previewUrl || file.url,
351
373
  key: file.uuid || file.name || index
352
374
  });
353
- }))), /*#__PURE__*/ React.createElement(motion.div, {
375
+ }))), videoList.length > 0 && /*#__PURE__*/ React.createElement(motion.div, {
376
+ variants: {
377
+ visible: {
378
+ opacity: 1
379
+ },
380
+ hidden: {
381
+ opacity: 0
382
+ }
383
+ },
384
+ whileInView: "visible",
385
+ initial: "hidden",
386
+ animate: "visible",
387
+ className: classNames("".concat(prefix, "-video-row"), "".concat(prefix, "-video-row-").concat(placement), hashId),
388
+ style: props.style
389
+ }, videoList.map(function(file, index) {
390
+ var videoUrl = file.previewUrl || file.url || '';
391
+ var isSingleVideo = videoList.length === 1;
392
+ var thumbSize = isSingleVideo ? {
393
+ width: 330,
394
+ height: 188
395
+ } : {
396
+ width: 124,
397
+ height: 124
398
+ };
399
+ return /*#__PURE__*/ React.createElement("div", {
400
+ role: "button",
401
+ tabIndex: 0,
402
+ className: classNames("".concat(prefix, "-image"), "".concat(prefix, "-video-thumb"), hashId),
403
+ key: file.uuid || file.name || index,
404
+ onClick: function onClick() {
405
+ return handleVideoClick(file);
406
+ },
407
+ onKeyDown: function onKeyDown(e) {
408
+ if (e.key === 'Enter' || e.key === ' ') {
409
+ e.preventDefault();
410
+ handleVideoClick(file);
411
+ }
412
+ },
413
+ "aria-label": "播放视频:".concat(file.name),
414
+ style: thumbSize
415
+ }, /*#__PURE__*/ React.createElement("video", {
416
+ src: videoUrl,
417
+ preload: "metadata",
418
+ muted: true,
419
+ playsInline: true,
420
+ style: {
421
+ width: '100%',
422
+ height: '100%',
423
+ objectFit: 'cover'
424
+ }
425
+ }), /*#__PURE__*/ React.createElement("div", {
426
+ className: classNames("".concat(prefix, "-video-play-overlay"), hashId),
427
+ "aria-hidden": true
428
+ }, /*#__PURE__*/ React.createElement(Play, null)));
429
+ })), /*#__PURE__*/ React.createElement(Modal, {
430
+ open: videoModalOpen,
431
+ onCancel: handleVideoModalClose,
432
+ footer: null,
433
+ width: "auto",
434
+ centered: true,
435
+ destroyOnClose: true,
436
+ styles: {
437
+ body: {
438
+ padding: 0
439
+ }
440
+ }
441
+ }, previewingVideo && /*#__PURE__*/ React.createElement("video", {
442
+ src: previewingVideo.previewUrl || previewingVideo.url,
443
+ controls: true,
444
+ autoPlay: true,
445
+ style: {
446
+ maxWidth: '80vw',
447
+ maxHeight: '80vh'
448
+ }
449
+ })), /*#__PURE__*/ React.createElement(motion.div, {
354
450
  variants: {
355
451
  visible: {
356
452
  opacity: 1,
@@ -371,7 +467,7 @@ import { useStyle } from "./style";
371
467
  animate: 'visible',
372
468
  className: classNames(prefix, hashId, props.className, "".concat(prefix, "-").concat(placement), "".concat(prefix, "-vertical")),
373
469
  style: props.style
374
- }, noImageFileList.map(function(file, index) {
470
+ }, noMediaFileList.map(function(file, index) {
375
471
  var _props_style;
376
472
  return /*#__PURE__*/ React.createElement(FileMapViewItem, {
377
473
  style: {
@@ -393,7 +489,7 @@ import { useStyle } from "./style";
393
489
  className: classNames(hashId, "".concat(prefix, "-item")),
394
490
  file: file
395
491
  });
396
- }), props.maxDisplayCount !== undefined && allNoImageFiles.length > props.maxDisplayCount && !showAllFiles ? /*#__PURE__*/ React.createElement("div", {
492
+ }), props.maxDisplayCount !== undefined && allNoMediaFiles.length > props.maxDisplayCount && !showAllFiles ? /*#__PURE__*/ React.createElement("div", {
397
493
  style: {
398
494
  width: (_props_style = props.style) === null || _props_style === void 0 ? void 0 : _props_style.width
399
495
  },
@@ -137,6 +137,51 @@ var genStyle = function genStyle(token) {
137
137
  transition: 'transform 0.3s'
138
138
  }
139
139
  }
140
+ }), _define_property(_obj, '&-video-row', {
141
+ display: 'flex',
142
+ flexWrap: 'wrap',
143
+ gap: 8,
144
+ width: 'fit-content',
145
+ '&-right': {
146
+ alignSelf: 'flex-end'
147
+ }
148
+ }), _define_property(_obj, '&-video-thumb', {
149
+ position: 'relative',
150
+ cursor: 'pointer',
151
+ opacity: 1,
152
+ background: 'var(--color-gray-bg-card-white)',
153
+ boxSizing: 'border-box',
154
+ boxShadow: 'var(--shadow-control-base)',
155
+ borderRadius: 'var(--radius-card-base)',
156
+ border: 'none',
157
+ overflow: 'hidden',
158
+ display: 'flex',
159
+ alignItems: 'center',
160
+ justifyContent: 'center',
161
+ '&:hover': {
162
+ boxShadow: 'var(--shadow-control-lg)',
163
+ '& video': {
164
+ transform: 'scale(1.05)'
165
+ }
166
+ },
167
+ '& video': {
168
+ transition: 'transform 0.3s'
169
+ }
170
+ }), _define_property(_obj, '&-video-play-overlay', {
171
+ position: 'absolute',
172
+ inset: 0,
173
+ display: 'flex',
174
+ alignItems: 'center',
175
+ justifyContent: 'center',
176
+ background: 'rgba(0, 0, 0, 0.35)',
177
+ borderRadius: 'inherit',
178
+ pointerEvents: 'none',
179
+ opacity: 0.9,
180
+ '& svg': {
181
+ width: 48,
182
+ height: 48,
183
+ color: '#fff'
184
+ }
140
185
  }), _define_property(_obj, '&-image-list-view', {
141
186
  background: 'var(--color-gray-bg-tip)',
142
187
  padding: '4px',
@@ -1,4 +1,19 @@
1
1
  import React from 'react';
2
+ import { LocalKeys } from '../I18n';
3
+ /**
4
+ * 将毫秒转换为可读的时间格式
5
+ *
6
+ * @param {number|undefined} ms - 毫秒数
7
+ * @param {LocalKeys} locale - 本地化配置
8
+ * @returns {string} 格式化后的时间字符串
9
+ *
10
+ * @example
11
+ * msToTimes(1500, locale) // "1.5s"
12
+ * msToTimes(65000, locale) // "1m 5s"
13
+ * msToTimes(3665000, locale) // "1H 1m 5s"
14
+ */
15
+ /** 导出供单测覆盖 undefined/null 分支 */
16
+ export declare const msToTimes: (ms: number | undefined | null, locale: LocalKeys) => string;
2
17
  /**
3
18
  * CostMillis 组件 - 耗时显示组件
4
19
  *
@@ -13,7 +13,7 @@ import { I18nContext } from "../I18n";
13
13
  * msToTimes(1500, locale) // "1.5s"
14
14
  * msToTimes(65000, locale) // "1m 5s"
15
15
  * msToTimes(3665000, locale) // "1H 1m 5s"
16
- */ var msToTimes = function msToTimes(ms, locale) {
16
+ */ /** 导出供单测覆盖 undefined/null 分支 */ export var msToTimes = function msToTimes(ms, locale) {
17
17
  if (ms === undefined || ms === null) {
18
18
  return '';
19
19
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ant-design/agentic-ui",
3
- "version": "2.29.27",
3
+ "version": "2.29.28",
4
4
  "description": "面向智能体的 UI 组件库,提供多步推理可视化、工具调用展示、任务执行协同等 Agentic UI 能力",
5
5
  "repository": "git@github.com:ant-design/agentic-ui.git",
6
6
  "license": "MIT",
@@ -24,7 +24,6 @@
24
24
  "lint:css": "stylelint \"{src,test}/**/*.{css,less}\"",
25
25
  "lint:es": "eslint \"{src,test}/**/*.{js,jsx,ts,tsx}\"",
26
26
  "prepare": "husky install && dumi setup",
27
- "prepublishOnly": "father doctor && pnpm run test && pnpm run build",
28
27
  "prettier": "prettier --write \"{src,docs,test}/**/*.{js,jsx,ts,tsx,css,less,json,md}\"",
29
28
  "preview": "pnpm dumi preview",
30
29
  "report:demo": "node scripts/generateDemoReport.js",