@ant-design/agentic-ui 2.29.26 → 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.
- package/dist/Bubble/AIBubble.js +1 -2
- package/dist/Bubble/BubbleConfigProvide.d.ts +0 -3
- package/dist/Bubble/BubbleConfigProvide.js +1 -2
- package/dist/Bubble/MessagesContent/BubbleExtra.js +2 -2
- package/dist/Bubble/MessagesContent/CopyButton/index.js +3 -5
- package/dist/Bubble/MessagesContent/MarkdownPreview.js +2 -2
- package/dist/Bubble/PureBubble.js +1 -2
- package/dist/Bubble/UserBubble.js +8 -9
- package/dist/Bubble/schema-editor/SchemaEditorBridgeManager.d.ts +4 -0
- package/dist/Bubble/schema-editor/SchemaEditorBridgeManager.js +9 -0
- package/dist/MarkdownEditor/editor/utils/media.js +4 -4
- package/dist/MarkdownInputField/AttachmentButton/AttachmentFileList/AttachmentFileIcon.js +182 -3
- package/dist/MarkdownInputField/AttachmentButton/utils.d.ts +12 -0
- package/dist/MarkdownInputField/AttachmentButton/utils.js +42 -0
- package/dist/MarkdownInputField/FileMapView/index.js +111 -15
- package/dist/MarkdownInputField/FileMapView/style.js +45 -0
- package/dist/ThoughtChainList/CostMillis.d.ts +15 -0
- package/dist/ThoughtChainList/CostMillis.js +1 -1
- package/package.json +1 -1
package/dist/Bubble/AIBubble.js
CHANGED
|
@@ -275,7 +275,7 @@ var shouldRenderBeforeContent = function shouldRenderBeforeContent(placement, ro
|
|
|
275
275
|
var _React_useState = _sliced_to_array(React.useState(false), 2), hidePadding = _React_useState[0], setHidePadding = _React_useState[1];
|
|
276
276
|
var getPrefixCls = useContext(ConfigProvider.ConfigContext).getPrefixCls;
|
|
277
277
|
var context = useContext(BubbleConfigContext);
|
|
278
|
-
var _ref = context || {}, compact = _ref.compact, standalone = _ref.standalone
|
|
278
|
+
var _ref = context || {}, compact = _ref.compact, standalone = _ref.standalone;
|
|
279
279
|
var prefixClass = getPrefixCls('agentic');
|
|
280
280
|
var _useStyle = useStyle(prefixClass), wrapSSR = _useStyle.wrapSSR, hashId = _useStyle.hashId;
|
|
281
281
|
var preMessageSameRole = isSameRoleAsPrevious(preMessage, originData);
|
|
@@ -356,7 +356,6 @@ var shouldRenderBeforeContent = function shouldRenderBeforeContent(placement, ro
|
|
|
356
356
|
value: {
|
|
357
357
|
compact: compact,
|
|
358
358
|
standalone: !!standalone,
|
|
359
|
-
locale: locale,
|
|
360
359
|
bubble: props
|
|
361
360
|
}
|
|
362
361
|
}, /*#__PURE__*/ React.createElement(Flex, {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import type { LocalKeys } from '../I18n';
|
|
3
2
|
import { ThoughtChainListProps } from '../ThoughtChainList/types';
|
|
4
3
|
import { BubbleProps } from './type';
|
|
5
4
|
export type ChatConfigType = {
|
|
@@ -18,8 +17,6 @@ export type ChatConfigType = {
|
|
|
18
17
|
*/
|
|
19
18
|
enable: boolean;
|
|
20
19
|
};
|
|
21
|
-
/** 可选覆盖,与 I18nContext 合并时优先生效,国际化主数据源为 I18nContext */
|
|
22
|
-
locale?: Partial<LocalKeys>;
|
|
23
20
|
bubble?: BubbleProps<{
|
|
24
21
|
/**
|
|
25
22
|
* 聊天内容
|
|
@@ -269,7 +269,7 @@ import { motion } from "framer-motion";
|
|
|
269
269
|
import React, { useContext, useEffect, useMemo, useState } from "react";
|
|
270
270
|
import { ActionIconBox } from "../../Components/ActionIconBox";
|
|
271
271
|
import { Loading } from "../../Components/Loading";
|
|
272
|
-
import {
|
|
272
|
+
import { useLocale } from "../../I18n";
|
|
273
273
|
import { BubbleConfigContext } from "../BubbleConfigProvide";
|
|
274
274
|
import { CopyButton } from "./CopyButton";
|
|
275
275
|
import { VoiceButton } from "./VoiceButton";
|
|
@@ -307,7 +307,7 @@ import { VoiceButton } from "./VoiceButton";
|
|
|
307
307
|
var _originalData_extra, _originalData_extra1, _originalData_extra2, _originalData_extra3, _bubble_originData, _bubble_originData1, _props_rightRender;
|
|
308
308
|
var getPrefixCls = useContext(ConfigProvider.ConfigContext).getPrefixCls;
|
|
309
309
|
var context = useContext(BubbleConfigContext);
|
|
310
|
-
var locale =
|
|
310
|
+
var locale = useLocale();
|
|
311
311
|
var _useState = _sliced_to_array(useState(false), 2), feedbackLoading = _useState[0], setFeedbackLoading = _useState[1];
|
|
312
312
|
// 获取聊天项的原始数据
|
|
313
313
|
var originalData = bubble === null || bubble === void 0 ? void 0 : bubble.originData;
|
|
@@ -214,14 +214,13 @@ function _ts_generator(thisArg, body) {
|
|
|
214
214
|
};
|
|
215
215
|
}
|
|
216
216
|
}
|
|
217
|
-
import { memo
|
|
217
|
+
import { memo } from "react";
|
|
218
218
|
import { CheckCircleFilled } from "@ant-design/icons";
|
|
219
219
|
import { isFunction } from "lodash-es";
|
|
220
220
|
import React from "react";
|
|
221
221
|
import { ActionIconBox } from "../../../Components/ActionIconBox";
|
|
222
222
|
import { useCopied } from "../../../Hooks/useCopied";
|
|
223
|
-
import {
|
|
224
|
-
import { BubbleConfigContext } from "../../BubbleConfigProvide";
|
|
223
|
+
import { useLocale } from "../../../I18n";
|
|
225
224
|
/**
|
|
226
225
|
* CopyIcon 组件 - 复制图标组件
|
|
227
226
|
*
|
|
@@ -310,9 +309,8 @@ import { BubbleConfigContext } from "../../BubbleConfigProvide";
|
|
|
310
309
|
"onClick",
|
|
311
310
|
'data-testid'
|
|
312
311
|
]);
|
|
313
|
-
var _useContext;
|
|
314
312
|
var _useCopied = useCopied(), copied = _useCopied.copied, setCopied = _useCopied.setCopied;
|
|
315
|
-
var locale =
|
|
313
|
+
var locale = useLocale();
|
|
316
314
|
var copySuccessText = (locale === null || locale === void 0 ? void 0 : locale['chat.message.copy.success']) || '复制成功';
|
|
317
315
|
return /*#__PURE__*/ React.createElement(ActionIconBox, _object_spread_props(_object_spread({
|
|
318
316
|
onClick: function onClick1(e) {
|
|
@@ -54,7 +54,7 @@ import { Popover, theme } from "antd";
|
|
|
54
54
|
import React, { useContext, useEffect, useMemo } from "react";
|
|
55
55
|
import { ErrorBoundary } from "react-error-boundary";
|
|
56
56
|
import { MarkdownEditor, parserMdToSchema } from "../..";
|
|
57
|
-
import {
|
|
57
|
+
import { useLocale } from "../../I18n";
|
|
58
58
|
import { BubbleConfigContext } from "../BubbleConfigProvide";
|
|
59
59
|
import { MessagesContext } from "./BubbleContext";
|
|
60
60
|
/**
|
|
@@ -98,7 +98,7 @@ import { MessagesContext } from "./BubbleContext";
|
|
|
98
98
|
var MarkdownEditorRef = React.useRef(undefined);
|
|
99
99
|
var hidePadding = (useContext(MessagesContext) || {}).hidePadding;
|
|
100
100
|
var config = useContext(BubbleConfigContext);
|
|
101
|
-
var locale =
|
|
101
|
+
var locale = useLocale();
|
|
102
102
|
var standalone = config === null || config === void 0 ? void 0 : config.standalone;
|
|
103
103
|
var token = theme.useToken().token;
|
|
104
104
|
var isPaddingHidden = useMemo(function() {
|
|
@@ -279,7 +279,7 @@ export var PureBubble = /*#__PURE__*/ memo(function(props) {
|
|
|
279
279
|
var _React_useState = _sliced_to_array(React.useState(false), 2), hidePadding = _React_useState[0], setHidePadding = _React_useState[1];
|
|
280
280
|
var getPrefixCls = useContext(ConfigProvider.ConfigContext).getPrefixCls;
|
|
281
281
|
var context = useContext(BubbleConfigContext);
|
|
282
|
-
var _ref1 = context || {}, compact = _ref1.compact, standalone = _ref1.standalone
|
|
282
|
+
var _ref1 = context || {}, compact = _ref1.compact, standalone = _ref1.standalone;
|
|
283
283
|
var prefixClass = getPrefixCls('agentic');
|
|
284
284
|
var _useStyle = useStyle(prefixClass), wrapSSR = _useStyle.wrapSSR, hashId = _useStyle.hashId;
|
|
285
285
|
var placement = (_props_placement = props.placement) !== null && _props_placement !== void 0 ? _props_placement : 'left';
|
|
@@ -452,7 +452,6 @@ export var PureBubble = /*#__PURE__*/ memo(function(props) {
|
|
|
452
452
|
value: {
|
|
453
453
|
compact: compact,
|
|
454
454
|
standalone: !!standalone,
|
|
455
|
-
locale: locale,
|
|
456
455
|
bubble: props
|
|
457
456
|
}
|
|
458
457
|
}, /*#__PURE__*/ React.createElement(Flex, {
|
|
@@ -128,7 +128,7 @@ var getContentStyle = function getContentStyle(standalone, customStyle) {
|
|
|
128
128
|
var _React_useState = _sliced_to_array(React.useState(false), 2), hidePadding = _React_useState[0], setHidePadding = _React_useState[1];
|
|
129
129
|
var getPrefixCls = useContext(ConfigProvider.ConfigContext).getPrefixCls;
|
|
130
130
|
var context = useContext(BubbleConfigContext);
|
|
131
|
-
var _ref = context || {}, compact = _ref.compact, standalone = _ref.standalone
|
|
131
|
+
var _ref = context || {}, compact = _ref.compact, standalone = _ref.standalone;
|
|
132
132
|
var prefixClass = getPrefixCls('agentic');
|
|
133
133
|
var _useStyle = useStyle(prefixClass, classNames), wrapSSR = _useStyle.wrapSSR, hashId = _useStyle.hashId;
|
|
134
134
|
var time = (originData === null || originData === void 0 ? void 0 : originData.createAt) || props.time;
|
|
@@ -180,7 +180,6 @@ var getContentStyle = function getContentStyle(standalone, customStyle) {
|
|
|
180
180
|
value: {
|
|
181
181
|
compact: compact,
|
|
182
182
|
standalone: !!standalone,
|
|
183
|
-
locale: locale,
|
|
184
183
|
bubble: props
|
|
185
184
|
}
|
|
186
185
|
}, /*#__PURE__*/ React.createElement(Flex, {
|
|
@@ -203,7 +202,12 @@ var getContentStyle = function getContentStyle(standalone, customStyle) {
|
|
|
203
202
|
style: styles === null || styles === void 0 ? void 0 : styles.bubbleListItemExtraStyle,
|
|
204
203
|
className: cx("".concat(prefixClass, "-bubble-before"), "".concat(prefixClass, "-bubble-before-").concat(placement), "".concat(prefixClass, "-bubble-before-user"), hashId),
|
|
205
204
|
"data-testid": "message-before"
|
|
206
|
-
}, contentBeforeDom),
|
|
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", {
|
|
207
211
|
style: fileViewStyle,
|
|
208
212
|
className: cx("".concat(prefixClass, "-bubble-after"), "".concat(prefixClass, "-bubble-after-").concat(placement), "".concat(prefixClass, "-bubble-after-ai"), hashId),
|
|
209
213
|
"data-testid": "message-after"
|
|
@@ -211,12 +215,7 @@ var getContentStyle = function getContentStyle(standalone, customStyle) {
|
|
|
211
215
|
bubbleListRef: props.bubbleListRef,
|
|
212
216
|
bubble: props,
|
|
213
217
|
placement: placement
|
|
214
|
-
})),
|
|
215
|
-
style: contentStyle,
|
|
216
|
-
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),
|
|
217
|
-
onDoubleClick: props.onDoubleClick,
|
|
218
|
-
"data-testid": "message-content"
|
|
219
|
-
}, childrenDom), contentAfterDom)))));
|
|
218
|
+
})), contentAfterDom)))));
|
|
220
219
|
if ((bubbleRenderConfig === null || bubbleRenderConfig === void 0 ? void 0 : bubbleRenderConfig.render) === false) return null;
|
|
221
220
|
return /*#__PURE__*/ React.createElement(MessagesContext.Provider, {
|
|
222
221
|
value: {
|
|
@@ -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
|
-
|
|
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
|
|
258
|
+
// 视频列表,与图片一样以缩略图形式展示
|
|
259
|
+
var videoList = useMemo(function() {
|
|
260
260
|
return fileList.filter(function(file) {
|
|
261
|
-
return
|
|
261
|
+
return isVideoFile(file);
|
|
262
262
|
});
|
|
263
263
|
}, [
|
|
264
264
|
fileList
|
|
265
265
|
]);
|
|
266
|
-
//
|
|
267
|
-
var
|
|
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
|
|
277
|
+
return allNoMediaFiles;
|
|
271
278
|
}
|
|
272
|
-
return
|
|
279
|
+
return allNoMediaFiles.slice(0, Math.max(0, props.maxDisplayCount));
|
|
273
280
|
}, [
|
|
274
|
-
|
|
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
|
-
},
|
|
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 &&
|
|
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
|
}
|