@ant-design/agentic-ui 2.9.0 → 2.10.1

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.
@@ -166,7 +166,10 @@ var genStyle = function(token) {
166
166
  flex: 1,
167
167
  overflowY: 'auto',
168
168
  overflowX: 'hidden',
169
- padding: 'var(--padding-2x)',
169
+ paddingTop: 'var(--padding-2x)',
170
+ paddingLeft: 'var(--padding-2x)',
171
+ paddingRight: 'var(--padding-2x)',
172
+ paddingBottom: '144px',
170
173
  '&::-webkit-scrollbar': {
171
174
  width: '6px'
172
175
  },
@@ -347,6 +347,9 @@ export declare function useLanguage(): {
347
347
  'input.voiceInput': string;
348
348
  'input.voiceInputting': string;
349
349
  'input.placeholder': string;
350
+ 'input.selectFile': string;
351
+ 'input.openGallery': string;
352
+ 'input.openFile': string;
350
353
  'common.name': string;
351
354
  'common.updateTime': string;
352
355
  'common.type': string;
@@ -311,6 +311,9 @@ export declare const cnLabels: {
311
311
  'input.voiceInput': string;
312
312
  'input.voiceInputting': string;
313
313
  'input.placeholder': string;
314
+ 'input.selectFile': string;
315
+ 'input.openGallery': string;
316
+ 'input.openFile': string;
314
317
  'common.name': string;
315
318
  'common.updateTime': string;
316
319
  'common.type': string;
@@ -330,6 +330,9 @@
330
330
  'input.voiceInput': '语音输入',
331
331
  'input.voiceInputting': '语音输入中,点击可停止。',
332
332
  'input.placeholder': '请输入',
333
+ 'input.selectFile': '选择文件',
334
+ 'input.openGallery': '打开相册',
335
+ 'input.openFile': '打开文件',
333
336
  // Other translations
334
337
  'common.name': '名称',
335
338
  'common.updateTime': '更新时间',
@@ -689,6 +692,9 @@
689
692
  'input.voiceInput': 'Voice input',
690
693
  'input.voiceInputting': 'Voice input in progress, click to stop.',
691
694
  'input.placeholder': 'Please input',
695
+ 'input.selectFile': 'Select File',
696
+ 'input.openGallery': 'Open Gallery',
697
+ 'input.openFile': 'Open File',
692
698
  // Other translations
693
699
  'common.name': 'Name',
694
700
  'common.updateTime': 'Update Time',
@@ -9,6 +9,10 @@ export type SupportedFormat = {
9
9
  export type AttachmentButtonPopoverProps = {
10
10
  children?: React.ReactNode;
11
11
  supportedFormat?: SupportedFormat;
12
+ /** 文件选择后的回调函数,参数为选中的文件 */
13
+ onFileSelect?: (files: FileList, accept: string) => void;
14
+ /** 是否允许一次选择多个文件 */
15
+ allowMultiple?: boolean;
12
16
  };
13
17
  export declare const SupportedFileFormats: {
14
18
  image: {
@@ -1,7 +1,57 @@
1
- import { AudioOutlined, FileImageOutlined, FileTextFilled, VideoCameraOutlined } from "@ant-design/icons";
2
- import { Tooltip } from "antd";
3
- import React from "react";
4
- import { kbToSize } from "./utils";
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 _iterable_to_array_limit(arr, i) {
10
+ var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
11
+ if (_i == null) return;
12
+ var _arr = [];
13
+ var _n = true;
14
+ var _d = false;
15
+ var _s, _e;
16
+ try {
17
+ for(_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true){
18
+ _arr.push(_s.value);
19
+ if (i && _arr.length === i) break;
20
+ }
21
+ } catch (err) {
22
+ _d = true;
23
+ _e = err;
24
+ } finally{
25
+ try {
26
+ if (!_n && _i["return"] != null) _i["return"]();
27
+ } finally{
28
+ if (_d) throw _e;
29
+ }
30
+ }
31
+ return _arr;
32
+ }
33
+ function _non_iterable_rest() {
34
+ throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
35
+ }
36
+ function _sliced_to_array(arr, i) {
37
+ return _array_with_holes(arr) || _iterable_to_array_limit(arr, i) || _unsupported_iterable_to_array(arr, i) || _non_iterable_rest();
38
+ }
39
+ function _unsupported_iterable_to_array(o, minLen) {
40
+ if (!o) return;
41
+ if (typeof o === "string") return _array_like_to_array(o, minLen);
42
+ var n = Object.prototype.toString.call(o).slice(8, -1);
43
+ if (n === "Object" && o.constructor) n = o.constructor.name;
44
+ if (n === "Map" || n === "Set") return Array.from(n);
45
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
46
+ }
47
+ import { AudioOutlined, FileImageOutlined, FileTextFilled, FolderOpenOutlined, PictureOutlined, VideoCameraOutlined } from "@ant-design/icons";
48
+ import { Button, Modal, Tooltip } from "antd";
49
+ import React, { useCallback, useContext, useMemo, useState } from "react";
50
+ import { I18nContext } from "../../I18n";
51
+ import { isMobileDevice, isVivoOrOppoDevice, kbToSize } from "./utils";
52
+ /**
53
+ * 移动设备默认的文件类型 accept 值
54
+ */ var MOBILE_DEFAULT_ACCEPT = 'application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-powerpoint,application/vnd.openxmlformats-officedocument.presentationml.presentation,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/pdf,.csv,image/*,text/plain,application/x-zip-compressed';
5
55
  var FILE_SIZE_UNITS = {
6
56
  KB: 1024,
7
57
  MB: 1024 * 1024
@@ -82,17 +132,155 @@ export var AttachmentSupportedFormatsContent = function(param) {
82
132
  });
83
133
  };
84
134
  export var AttachmentButtonPopover = function(param) {
85
- var children = param.children, supportedFormat = param.supportedFormat;
135
+ var children = param.children, supportedFormat = param.supportedFormat, onFileSelect = param.onFileSelect, _param_allowMultiple = param.allowMultiple, allowMultiple = _param_allowMultiple === void 0 ? true : _param_allowMultiple;
136
+ var _useState = _sliced_to_array(useState(false), 2), modalOpen = _useState[0], setModalOpen = _useState[1];
137
+ var locale = useContext(I18nContext).locale;
138
+ var isVivoOrOppo = useMemo(function() {
139
+ return isVivoOrOppoDevice();
140
+ }, []);
141
+ var isMobile = useMemo(function() {
142
+ return isMobileDevice();
143
+ }, []);
144
+ var trigger = useMemo(function() {
145
+ return isVivoOrOppo ? [
146
+ 'click'
147
+ ] : [
148
+ 'hover',
149
+ 'click'
150
+ ];
151
+ }, [
152
+ isVivoOrOppo
153
+ ]);
154
+ var format = supportedFormat || SupportedFileFormats.image;
155
+ var extensions = format.extensions || [];
156
+ /**
157
+ * 根据支持的格式获取 accept 属性值
158
+ */ var getAcceptValue = useCallback(function(forGallery) {
159
+ // 如果是移动设备,返回默认的 accept 值
160
+ if (isMobile || forGallery) {
161
+ return MOBILE_DEFAULT_ACCEPT;
162
+ }
163
+ // 打开文件,使用具体扩展名列表
164
+ return extensions.length > 0 ? extensions.map(function(ext) {
165
+ return ".".concat(ext);
166
+ }).join(',') : MOBILE_DEFAULT_ACCEPT;
167
+ }, [
168
+ extensions,
169
+ isMobile
170
+ ]);
171
+ /**
172
+ * 创建文件输入并触发选择
173
+ */ var triggerFileInput = useCallback(function(forGallery) {
174
+ var accept = getAcceptValue(forGallery);
175
+ var input = document.createElement('input');
176
+ input.type = 'file';
177
+ input.accept = accept;
178
+ input.multiple = allowMultiple;
179
+ input.style.display = 'none';
180
+ input.onchange = function(e) {
181
+ var target = e.target;
182
+ if (target.files && target.files.length > 0 && onFileSelect) {
183
+ onFileSelect(target.files, accept);
184
+ }
185
+ // 清理
186
+ input.remove();
187
+ };
188
+ document.body.appendChild(input);
189
+ input.click();
190
+ setModalOpen(false);
191
+ }, [
192
+ getAcceptValue,
193
+ onFileSelect,
194
+ allowMultiple
195
+ ]);
196
+ var handleClick = useCallback(function(e) {
197
+ if (isVivoOrOppo) {
198
+ e.stopPropagation();
199
+ e.preventDefault();
200
+ setModalOpen(true);
201
+ }
202
+ }, [
203
+ isVivoOrOppo
204
+ ]);
205
+ var handleOpenGallery = useCallback(function() {
206
+ triggerFileInput(true);
207
+ }, [
208
+ triggerFileInput
209
+ ]);
210
+ var handleOpenFile = useCallback(function() {
211
+ triggerFileInput(false);
212
+ }, [
213
+ triggerFileInput
214
+ ]);
215
+ if (isVivoOrOppo) {
216
+ return /*#__PURE__*/ React.createElement("div", {
217
+ onClick: function(e) {
218
+ if (isVivoOrOppo) {
219
+ e.stopPropagation();
220
+ e.preventDefault();
221
+ }
222
+ }
223
+ }, /*#__PURE__*/ React.createElement("span", {
224
+ onClick: handleClick
225
+ }, children), /*#__PURE__*/ React.createElement(Modal, {
226
+ open: modalOpen,
227
+ onCancel: function() {
228
+ return setModalOpen(false);
229
+ },
230
+ footer: null,
231
+ closable: false,
232
+ maskClosable: true,
233
+ centered: true,
234
+ styles: {
235
+ content: {
236
+ padding: 0
237
+ },
238
+ body: {
239
+ padding: 0
240
+ }
241
+ },
242
+ width: 120
243
+ }, /*#__PURE__*/ React.createElement("div", {
244
+ style: {
245
+ display: 'flex',
246
+ flexDirection: 'column',
247
+ gap: 2,
248
+ padding: '12px 0'
249
+ },
250
+ onClick: function(e) {
251
+ e.stopPropagation();
252
+ e.preventDefault();
253
+ }
254
+ }, /*#__PURE__*/ React.createElement(Button, {
255
+ color: "default",
256
+ variant: "text",
257
+ icon: /*#__PURE__*/ React.createElement(PictureOutlined, null),
258
+ onClick: handleOpenGallery
259
+ }, (locale === null || locale === void 0 ? void 0 : locale['input.openGallery']) || '打开相册'), /*#__PURE__*/ React.createElement(Button, {
260
+ color: "default",
261
+ variant: "text",
262
+ icon: /*#__PURE__*/ React.createElement(FolderOpenOutlined, null),
263
+ onClick: handleOpenFile
264
+ }, (locale === null || locale === void 0 ? void 0 : locale['input.openFile']) || '打开文件'))));
265
+ }
266
+ // 如果是移动设备,不显示 Tooltip
267
+ if (isMobile) {
268
+ return /*#__PURE__*/ React.createElement("span", null, children);
269
+ }
86
270
  return /*#__PURE__*/ React.createElement(Tooltip, {
87
271
  arrow: false,
88
272
  mouseEnterDelay: 1,
89
- trigger: [
90
- 'hover',
91
- 'click'
92
- ],
273
+ trigger: trigger,
93
274
  title: /*#__PURE__*/ React.createElement(AttachmentSupportedFormatsContent, {
94
275
  supportedFormat: supportedFormat
95
276
  })
96
- }, /*#__PURE__*/ React.createElement("span", null, children));
277
+ }, /*#__PURE__*/ React.createElement("span", {
278
+ onClick: function(e) {
279
+ if (isVivoOrOppo) {
280
+ e.stopPropagation();
281
+ e.preventDefault();
282
+ }
283
+ }
284
+ }, children));
97
285
  };
98
286
  export default AttachmentButtonPopover;
@@ -470,7 +470,7 @@ var ButtonContent = function(param) {
470
470
  * />
471
471
  * ```
472
472
  */ export var AttachmentButton = function(param) {
473
- var disabled = param.disabled, uploadImage = param.uploadImage, title = param.title, supportedFormat = param.supportedFormat, render = param.render;
473
+ var disabled = param.disabled, uploadImage = param.uploadImage, title = param.title, supportedFormat = param.supportedFormat, render = param.render, upload = param.upload, uploadWithResponse = param.uploadWithResponse, fileMap = param.fileMap, onFileMapChange = param.onFileMapChange, maxFileSize = param.maxFileSize, maxFileCount = param.maxFileCount, minFileCount = param.minFileCount, allowMultiple = param.allowMultiple;
474
474
  var context = useContext(ConfigProvider.ConfigContext);
475
475
  var prefix = context === null || context === void 0 ? void 0 : context.getPrefixCls('agentic-md-editor-attachment-button');
476
476
  var _useStyle = useStyle(prefix), wrapSSR = _useStyle.wrapSSR, hashId = _useStyle.hashId;
@@ -484,11 +484,26 @@ var ButtonContent = function(param) {
484
484
  }, /*#__PURE__*/ React.createElement(ButtonContent, {
485
485
  title: title
486
486
  }));
487
+ var handleFileSelect = function(files) {
488
+ // 触发文件上传
489
+ upLoadFileToServer(files, {
490
+ upload: upload,
491
+ uploadWithResponse: uploadWithResponse,
492
+ fileMap: fileMap,
493
+ onFileMapChange: onFileMapChange,
494
+ maxFileSize: maxFileSize,
495
+ maxFileCount: maxFileCount,
496
+ minFileCount: minFileCount,
497
+ locale: {}
498
+ });
499
+ };
487
500
  var wrapper = render ? render({
488
501
  children: buttonWithStyle,
489
502
  supportedFormat: format
490
503
  }) : /*#__PURE__*/ React.createElement(AttachmentButtonPopover, {
491
- supportedFormat: format
504
+ supportedFormat: format,
505
+ onFileSelect: handleFileSelect,
506
+ allowMultiple: allowMultiple
492
507
  }, buttonWithStyle);
493
508
  return wrapSSR(/*#__PURE__*/ React.createElement("div", {
494
509
  className: classNames("".concat(prefix), hashId, _define_property({}, "".concat(prefix, "-disabled"), disabled)),
@@ -25,3 +25,63 @@ 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
+ *
31
+ * @param {string} [ua] - User Agent 字符串,如果不提供则使用 navigator.userAgent
32
+ * @returns {string | false} 设备品牌名称,如果无法匹配则返回 false
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * getDeviceBrand() // 'vivo' | '华为' | 'iphone' | false
37
+ * getDeviceBrand('Mozilla/5.0...vivo...') // 'vivo'
38
+ * ```
39
+ */
40
+ export declare const getDeviceBrand: (ua?: string) => string | false;
41
+ /**
42
+ * 检测是否为 vivo 手机
43
+ *
44
+ * @param {string} [ua] - User Agent 字符串,如果不提供则使用 navigator.userAgent
45
+ * @returns {boolean} 是否为 vivo 设备
46
+ *
47
+ * @example
48
+ * ```ts
49
+ * isVivoDevice() // true | false
50
+ * ```
51
+ */
52
+ export declare const isVivoDevice: (ua?: string) => boolean;
53
+ /**
54
+ * 检测是否为 oppo 手机
55
+ *
56
+ * @param {string} [ua] - User Agent 字符串,如果不提供则使用 navigator.userAgent
57
+ * @returns {boolean} 是否为 oppo 设备
58
+ *
59
+ * @example
60
+ * ```ts
61
+ * isOppoDevice() // true | false
62
+ * ```
63
+ */
64
+ export declare const isOppoDevice: (ua?: string) => boolean;
65
+ /**
66
+ * 检测是否为 vivo 或 oppo 手机
67
+ *
68
+ * @param {string} [ua] - User Agent 字符串,如果不提供则使用 navigator.userAgent
69
+ * @returns {boolean} 是否为 vivo 或 oppo 设备
70
+ *
71
+ * @example
72
+ * ```ts
73
+ * isVivoOrOppoDevice() // true | false
74
+ * ```
75
+ */
76
+ export declare const isVivoOrOppoDevice: (ua?: string) => boolean;
77
+ /**
78
+ * 检测是否为移动设备
79
+ *
80
+ * @returns {boolean} 是否为移动设备
81
+ *
82
+ * @example
83
+ * ```ts
84
+ * isMobileDevice() // true | false
85
+ * ```
86
+ */
87
+ export declare const isMobileDevice: () => boolean;
@@ -64,3 +64,305 @@
64
64
  return fileName.endsWith(ext);
65
65
  });
66
66
  };
67
+ /**
68
+ * 设备品牌匹配列表
69
+ */ var UA_MATCH_LIST = [
70
+ {
71
+ name: 'iphone',
72
+ matchList: [
73
+ /iPhone/i
74
+ ]
75
+ },
76
+ {
77
+ name: '华为',
78
+ matchList: [
79
+ /HUAWEI/i,
80
+ /SPN-AL00/i,
81
+ /GLK-AL00/i,
82
+ /Huawei/i,
83
+ /HMSCore/i,
84
+ /HW/
85
+ ]
86
+ },
87
+ {
88
+ name: '荣耀',
89
+ matchList: [
90
+ /HONOR/i
91
+ ]
92
+ },
93
+ {
94
+ name: 'oppo',
95
+ matchList: [
96
+ /PCAM10/i,
97
+ /OPPO/i,
98
+ /PCH/,
99
+ /PBAM00/,
100
+ /PBEM00/,
101
+ /HeyTapBrowser/,
102
+ /PADT00/,
103
+ /PCDM10/
104
+ ]
105
+ },
106
+ {
107
+ name: 'vivo',
108
+ matchList: [
109
+ /V1981A/i,
110
+ /vivo/i,
111
+ /V1818A/,
112
+ /V1838A/,
113
+ /V19/,
114
+ /VivoBrowser/
115
+ ]
116
+ },
117
+ {
118
+ name: '小米',
119
+ matchList: [
120
+ /Redmi/i,
121
+ /HM/,
122
+ /MIX/i,
123
+ /MI/,
124
+ /XiaoMi/
125
+ ]
126
+ },
127
+ {
128
+ name: '金利',
129
+ matchList: [
130
+ /GN708T/i
131
+ ]
132
+ },
133
+ {
134
+ name: 'oneplus',
135
+ matchList: [
136
+ /GM1910/i,
137
+ /ONEPLUS/i
138
+ ]
139
+ },
140
+ {
141
+ name: 'sony',
142
+ matchList: [
143
+ /SOV/i,
144
+ /LT29i/,
145
+ /Xperia/
146
+ ]
147
+ },
148
+ {
149
+ name: '三星',
150
+ matchList: [
151
+ /SAMSUNG/i,
152
+ /SM-/,
153
+ /GT/,
154
+ /SCH-I939I/
155
+ ]
156
+ },
157
+ {
158
+ name: '魅族',
159
+ matchList: [
160
+ /MZ-/,
161
+ /MX4/i,
162
+ /M355/,
163
+ /M353/,
164
+ /M351/,
165
+ /M811/,
166
+ /PRO 7-H/
167
+ ]
168
+ },
169
+ {
170
+ name: '华硕',
171
+ matchList: [
172
+ /ASUS/
173
+ ]
174
+ },
175
+ {
176
+ name: '美图',
177
+ matchList: [
178
+ /MP/
179
+ ]
180
+ },
181
+ {
182
+ name: '天语',
183
+ matchList: [
184
+ /K-Touch/
185
+ ]
186
+ },
187
+ {
188
+ name: '联想',
189
+ matchList: [
190
+ /Lenovo/i
191
+ ]
192
+ },
193
+ {
194
+ name: '宇飞来',
195
+ matchList: [
196
+ /YU FLY/i
197
+ ]
198
+ },
199
+ {
200
+ name: '糖果',
201
+ matchList: [
202
+ /SUGAR/i
203
+ ]
204
+ },
205
+ {
206
+ name: '酷派',
207
+ matchList: [
208
+ /Coolpad/i
209
+ ]
210
+ },
211
+ {
212
+ name: 'ecell',
213
+ matchList: [
214
+ /ecell/i
215
+ ]
216
+ },
217
+ {
218
+ name: '詹姆士',
219
+ matchList: [
220
+ /A99A/i
221
+ ]
222
+ },
223
+ {
224
+ name: 'tcl',
225
+ matchList: [
226
+ /TCL/i
227
+ ]
228
+ },
229
+ {
230
+ name: '捷语',
231
+ matchList: [
232
+ /6000/i,
233
+ /V1813A/
234
+ ]
235
+ },
236
+ {
237
+ name: '8848',
238
+ matchList: [
239
+ /8848/i
240
+ ]
241
+ },
242
+ {
243
+ name: 'H6',
244
+ matchList: [
245
+ /H6/
246
+ ]
247
+ },
248
+ {
249
+ name: '中兴',
250
+ matchList: [
251
+ /ZTE/i
252
+ ]
253
+ },
254
+ {
255
+ name: '努比亚',
256
+ matchList: [
257
+ /NX/
258
+ ]
259
+ },
260
+ {
261
+ name: '海信',
262
+ matchList: [
263
+ /HS/
264
+ ]
265
+ },
266
+ {
267
+ name: 'HTC',
268
+ matchList: [
269
+ /HTC/
270
+ ]
271
+ }
272
+ ];
273
+ /**
274
+ * 获取设备品牌
275
+ *
276
+ * @param {string} [ua] - User Agent 字符串,如果不提供则使用 navigator.userAgent
277
+ * @returns {string | false} 设备品牌名称,如果无法匹配则返回 false
278
+ *
279
+ * @example
280
+ * ```ts
281
+ * getDeviceBrand() // 'vivo' | '华为' | 'iphone' | false
282
+ * getDeviceBrand('Mozilla/5.0...vivo...') // 'vivo'
283
+ * ```
284
+ */ export var getDeviceBrand = function(ua) {
285
+ if (typeof navigator === 'undefined' && !ua) {
286
+ return false;
287
+ }
288
+ var userAgent = ua || navigator.userAgent;
289
+ // 遍历匹配列表
290
+ for(var i = 0; i < UA_MATCH_LIST.length; i++){
291
+ var uaDetail = UA_MATCH_LIST[i];
292
+ for(var j = 0; j < uaDetail.matchList.length; j++){
293
+ var re = uaDetail.matchList[j];
294
+ if (re.test(userAgent)) {
295
+ return uaDetail.name;
296
+ }
297
+ }
298
+ }
299
+ // 如果匹配列表中没有找到,尝试从 Build 信息中提取
300
+ var brandMatch = /; ([^;]+) Build/.exec(userAgent);
301
+ if (brandMatch) {
302
+ return brandMatch[1];
303
+ }
304
+ return false;
305
+ };
306
+ /**
307
+ * 检测是否为 vivo 手机
308
+ *
309
+ * @param {string} [ua] - User Agent 字符串,如果不提供则使用 navigator.userAgent
310
+ * @returns {boolean} 是否为 vivo 设备
311
+ *
312
+ * @example
313
+ * ```ts
314
+ * isVivoDevice() // true | false
315
+ * ```
316
+ */ export var isVivoDevice = function(ua) {
317
+ var brand = getDeviceBrand(ua);
318
+ return brand === 'vivo';
319
+ };
320
+ /**
321
+ * 检测是否为 oppo 手机
322
+ *
323
+ * @param {string} [ua] - User Agent 字符串,如果不提供则使用 navigator.userAgent
324
+ * @returns {boolean} 是否为 oppo 设备
325
+ *
326
+ * @example
327
+ * ```ts
328
+ * isOppoDevice() // true | false
329
+ * ```
330
+ */ export var isOppoDevice = function(ua) {
331
+ var brand = getDeviceBrand(ua);
332
+ return brand === 'oppo';
333
+ };
334
+ /**
335
+ * 检测是否为 vivo 或 oppo 手机
336
+ *
337
+ * @param {string} [ua] - User Agent 字符串,如果不提供则使用 navigator.userAgent
338
+ * @returns {boolean} 是否为 vivo 或 oppo 设备
339
+ *
340
+ * @example
341
+ * ```ts
342
+ * isVivoOrOppoDevice() // true | false
343
+ * ```
344
+ */ export var isVivoOrOppoDevice = function(ua) {
345
+ return isVivoDevice(ua) || isOppoDevice(ua);
346
+ };
347
+ /**
348
+ * 检测是否为移动设备
349
+ *
350
+ * @returns {boolean} 是否为移动设备
351
+ *
352
+ * @example
353
+ * ```ts
354
+ * isMobileDevice() // true | false
355
+ * ```
356
+ */ export var isMobileDevice = function() {
357
+ if (typeof navigator === 'undefined') {
358
+ return false;
359
+ }
360
+ var userAgent = navigator.userAgent.toLowerCase();
361
+ // 检测常见的移动设备标识
362
+ var mobileRegex = /android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini|mobile|mobile safari|micromessenger/i;
363
+ // 检测触摸设备
364
+ var hasTouchScreen = 'ontouchstart' in window || navigator.maxTouchPoints > 0;
365
+ // 检测屏幕宽度(移动设备通常小于 768px)
366
+ var isSmallScreen = typeof window !== 'undefined' && window.innerWidth <= 768;
367
+ return mobileRegex.test(userAgent) || hasTouchScreen && isSmallScreen;
368
+ };
@@ -180,6 +180,10 @@ import { useRefFunction } from "../../Hooks/useRefFunction";
180
180
  import { I18nContext } from "../../I18n";
181
181
  import { upLoadFileToServer } from "../AttachmentButton";
182
182
  import { SupportedFileFormats } from "../AttachmentButton/AttachmentButtonPopover";
183
+ import { isMobileDevice, isVivoOrOppoDevice } from "../AttachmentButton/utils";
184
+ /**
185
+ * 移动设备默认的文件类型 accept 值
186
+ */ var MOBILE_DEFAULT_ACCEPT = 'application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-powerpoint,application/vnd.openxmlformats-officedocument.presentationml.presentation,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/pdf,.csv,image/*,text/plain,application/x-zip-compressed';
183
187
  /**
184
188
  * 文件上传管理器
185
189
  *
@@ -199,9 +203,49 @@ import { SupportedFileFormats } from "../AttachmentButton/AttachmentButtonPopove
199
203
  onFileMapChange === null || onFileMapChange === void 0 ? void 0 : onFileMapChange(new Map(newFileMap));
200
204
  });
201
205
  /**
206
+ * 根据支持的格式获取 accept 属性值
207
+ * 在移动设备上,使用默认的 accept 值
208
+ * 在 vivo 或 oppo 手机上,如果只支持图片格式,使用 image/* 打开相册;否则使用具体扩展名打开文件选择器
209
+ */ var getAcceptValue = function() {
210
+ var isMobile = isMobileDevice();
211
+ var isVivoOrOppo = isVivoOrOppoDevice();
212
+ var extensions = (supportedFormat === null || supportedFormat === void 0 ? void 0 : supportedFormat.extensions) || [];
213
+ // 如果是移动设备,返回默认的 accept 值
214
+ if (isMobile) {
215
+ return MOBILE_DEFAULT_ACCEPT;
216
+ }
217
+ if (!isVivoOrOppo) {
218
+ // 非 vivo/oppo 设备,直接使用扩展名列表
219
+ return extensions.length > 0 ? extensions.map(function(ext) {
220
+ return ".".concat(ext);
221
+ }).join(',') : 'image/*';
222
+ }
223
+ // vivo/oppo 设备:判断是否只包含图片格式
224
+ var imageExtensions = [
225
+ 'jpg',
226
+ 'jpeg',
227
+ 'png',
228
+ 'gif',
229
+ 'bmp',
230
+ 'webp',
231
+ 'svg'
232
+ ];
233
+ var isImageOnly = extensions.length > 0 && extensions.every(function(ext) {
234
+ return imageExtensions.includes(ext.toLowerCase());
235
+ });
236
+ if (isImageOnly) {
237
+ // 只支持图片格式,使用 image/* 打开相册
238
+ return 'image/*';
239
+ }
240
+ // 支持其他格式,使用具体扩展名列表打开文件选择器
241
+ return extensions.length > 0 ? extensions.map(function(ext) {
242
+ return ".".concat(ext);
243
+ }).join(',') : 'image/*';
244
+ };
245
+ /**
202
246
  * 上传图片
203
247
  */ var uploadImage = useRefFunction(/*#__PURE__*/ _async_to_generator(function() {
204
- var _supportedFormat_extensions, isUploading, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, file, currentFileCount, errorMsg, input, _attachment_allowMultiple;
248
+ var isUploading, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, file, currentFileCount, errorMsg, input, _attachment_allowMultiple;
205
249
  return _ts_generator(this, function(_state) {
206
250
  // 检查是否有文件正在上传中
207
251
  isUploading = false;
@@ -245,7 +289,7 @@ import { SupportedFileFormats } from "../AttachmentButton/AttachmentButtonPopove
245
289
  input = document.createElement('input');
246
290
  input.id = 'uploadImage' + '_' + Math.random();
247
291
  input.type = 'file';
248
- input.accept = (supportedFormat === null || supportedFormat === void 0 ? void 0 : (_supportedFormat_extensions = supportedFormat.extensions) === null || _supportedFormat_extensions === void 0 ? void 0 : _supportedFormat_extensions.join(',')) || 'image/*';
292
+ input.accept = getAcceptValue();
249
293
  input.multiple = (_attachment_allowMultiple = attachment === null || attachment === void 0 ? void 0 : attachment.allowMultiple) !== null && _attachment_allowMultiple !== void 0 ? _attachment_allowMultiple : true;
250
294
  input.style.display = 'none';
251
295
  input.onchange = /*#__PURE__*/ function() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ant-design/agentic-ui",
3
- "version": "2.9.0",
3
+ "version": "2.10.1",
4
4
  "description": "面向智能体的 UI 组件库,提供多步推理可视化、工具调用展示、任务执行协同等 Agentic UI 能力",
5
5
  "repository": "git@github.com:ant-design/agentic-ui.git",
6
6
  "license": "MIT",