@ai-group/chat-sdk 3.7.0 → 3.7.1-alpha2

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 (78) hide show
  1. package/dist/cjs/components/Sources/components/CarouselCard.d.ts +12 -0
  2. package/dist/cjs/components/Sources/components/CarouselCard.js +130 -0
  3. package/dist/cjs/components/Sources/components/CarouselCard.js.map +7 -0
  4. package/dist/cjs/components/Sources/index.d.ts +5 -0
  5. package/dist/cjs/components/Sources/index.js +162 -0
  6. package/dist/cjs/components/Sources/index.js.map +7 -0
  7. package/dist/cjs/components/Sources/styles.d.ts +59 -0
  8. package/dist/cjs/components/Sources/styles.js +179 -0
  9. package/dist/cjs/components/Sources/styles.js.map +7 -0
  10. package/dist/cjs/components/XAdkSender/InlineTagInput.d.ts +25 -0
  11. package/dist/cjs/components/XAdkSender/InlineTagInput.js +485 -0
  12. package/dist/cjs/components/XAdkSender/InlineTagInput.js.map +7 -0
  13. package/dist/cjs/components/XAdkSender/InputTags.d.ts +8 -0
  14. package/dist/cjs/components/XAdkSender/InputTags.js +51 -0
  15. package/dist/cjs/components/XAdkSender/InputTags.js.map +7 -0
  16. package/dist/cjs/components/XAdkSender/QuickList.d.ts +16 -0
  17. package/dist/cjs/components/XAdkSender/QuickList.js +105 -0
  18. package/dist/cjs/components/XAdkSender/QuickList.js.map +7 -0
  19. package/dist/cjs/components/XAdkSender/index.d.ts +1 -6
  20. package/dist/cjs/components/XAdkSender/index.js +350 -84
  21. package/dist/cjs/components/XAdkSender/index.js.map +3 -3
  22. package/dist/cjs/components/XAdkSender/styles.d.ts +15 -0
  23. package/dist/cjs/components/XAdkSender/styles.js +184 -5
  24. package/dist/cjs/components/XAdkSender/styles.js.map +2 -2
  25. package/dist/cjs/index.d.ts +4 -2
  26. package/dist/cjs/index.js +3 -3
  27. package/dist/cjs/index.js.map +3 -3
  28. package/dist/cjs/types/Sources.d.ts +30 -0
  29. package/dist/cjs/types/Sources.js +18 -0
  30. package/dist/cjs/types/Sources.js.map +7 -0
  31. package/dist/cjs/types/XAdkSender.d.ts +92 -4
  32. package/dist/cjs/types/XAdkSender.js.map +1 -1
  33. package/dist/cjs/types/index.d.ts +1 -0
  34. package/dist/cjs/types/index.js +3 -1
  35. package/dist/cjs/types/index.js.map +2 -2
  36. package/dist/esm/components/Sources/components/CarouselCard.d.ts +12 -0
  37. package/dist/esm/components/Sources/components/CarouselCard.js +107 -0
  38. package/dist/esm/components/Sources/components/CarouselCard.js.map +1 -0
  39. package/dist/esm/components/Sources/index.d.ts +5 -0
  40. package/dist/esm/components/Sources/index.js +127 -0
  41. package/dist/esm/components/Sources/index.js.map +1 -0
  42. package/dist/esm/components/Sources/styles.d.ts +59 -0
  43. package/dist/esm/components/Sources/styles.js +34 -0
  44. package/dist/esm/components/Sources/styles.js.map +1 -0
  45. package/dist/esm/components/XAdkSender/InlineTagInput.d.ts +25 -0
  46. package/dist/esm/components/XAdkSender/InlineTagInput.js +467 -0
  47. package/dist/esm/components/XAdkSender/InlineTagInput.js.map +1 -0
  48. package/dist/esm/components/XAdkSender/InputTags.d.ts +8 -0
  49. package/dist/esm/components/XAdkSender/InputTags.js +36 -0
  50. package/dist/esm/components/XAdkSender/InputTags.js.map +1 -0
  51. package/dist/esm/components/XAdkSender/QuickList.d.ts +16 -0
  52. package/dist/esm/components/XAdkSender/QuickList.js +96 -0
  53. package/dist/esm/components/XAdkSender/QuickList.js.map +1 -0
  54. package/dist/esm/components/XAdkSender/index.d.ts +1 -6
  55. package/dist/esm/components/XAdkSender/index.js +407 -88
  56. package/dist/esm/components/XAdkSender/index.js.map +1 -1
  57. package/dist/esm/components/XAdkSender/styles.d.ts +15 -0
  58. package/dist/esm/components/XAdkSender/styles.js +29 -11
  59. package/dist/esm/components/XAdkSender/styles.js.map +1 -1
  60. package/dist/esm/index.d.ts +4 -2
  61. package/dist/esm/index.js +4 -2
  62. package/dist/esm/index.js.map +1 -1
  63. package/dist/esm/types/Sources.d.ts +30 -0
  64. package/dist/esm/types/Sources.js +2 -0
  65. package/dist/esm/types/Sources.js.map +1 -0
  66. package/dist/esm/types/XAdkSender.d.ts +92 -4
  67. package/dist/esm/types/XAdkSender.js.map +1 -1
  68. package/dist/esm/types/index.d.ts +1 -0
  69. package/dist/esm/types/index.js +1 -0
  70. package/dist/esm/types/index.js.map +1 -1
  71. package/dist/umd/chat-sdk.min.js +1 -1
  72. package/package.json +1 -1
  73. package/dist/cjs/components/XAdkSender/Switch.d.ts +0 -16
  74. package/dist/cjs/components/XAdkSender/Switch.js +0 -95
  75. package/dist/cjs/components/XAdkSender/Switch.js.map +0 -7
  76. package/dist/esm/components/XAdkSender/Switch.d.ts +0 -16
  77. package/dist/esm/components/XAdkSender/Switch.js +0 -53
  78. package/dist/esm/components/XAdkSender/Switch.js.map +0 -1
@@ -4,12 +4,18 @@ import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator";
4
4
  import _createForOfIteratorHelper from "@babel/runtime/helpers/esm/createForOfIteratorHelper";
5
5
  import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
6
6
  import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
7
- import React, { useState, useRef, useCallback, forwardRef, useImperativeHandle } from "react";
7
+ import React, { useState, useRef, useCallback, forwardRef, useImperativeHandle, useMemo, useEffect } from "react";
8
8
  import { Popconfirm, message, Tooltip, Input, Modal } from "antd";
9
9
  import { ClearOutlined, LoadingOutlined, ArrowUpOutlined, PaperClipOutlined } from "@ant-design/icons";
10
10
  import { useStyles } from "./styles";
11
11
  import FileGallery from "../FileGallery";
12
+ import QuickList from "./QuickList";
13
+ import InputTags from "./InputTags";
14
+ import InlineTagInput from "./InlineTagInput";
12
15
  import { getExt } from "../../utils/file";
16
+ import { jsx as _jsx } from "react/jsx-runtime";
17
+ import { Fragment as _Fragment } from "react/jsx-runtime";
18
+ import { jsxs as _jsxs } from "react/jsx-runtime";
13
19
  var XAdkSender = /*#__PURE__*/forwardRef(function (_ref, ref) {
14
20
  var _ref$clearBtnShow = _ref.clearBtnShow,
15
21
  clearBtnShow = _ref$clearBtnShow === void 0 ? true : _ref$clearBtnShow,
@@ -35,6 +41,8 @@ var XAdkSender = /*#__PURE__*/forwardRef(function (_ref, ref) {
35
41
  onUploadError = _ref.onUploadError,
36
42
  _ref$maxFileSize = _ref.maxFileSize,
37
43
  maxFileSize = _ref$maxFileSize === void 0 ? 10 : _ref$maxFileSize,
44
+ _ref$placeholder = _ref.placeholder,
45
+ placeholder = _ref$placeholder === void 0 ? "" : _ref$placeholder,
38
46
  _ref$validators = _ref.validators,
39
47
  customValidators = _ref$validators === void 0 ? [] : _ref$validators,
40
48
  _ref$allowedFileTypes = _ref.allowedFileTypes,
@@ -45,7 +53,21 @@ var XAdkSender = /*#__PURE__*/forwardRef(function (_ref, ref) {
45
53
  suffix = _ref.suffix,
46
54
  header = _ref.header,
47
55
  prefix = _ref.prefix,
48
- footer = _ref.footer;
56
+ footer = _ref.footer,
57
+ footerLeft = _ref.footerLeft,
58
+ _ref$quickKeys = _ref.quickKeys,
59
+ quickKeys = _ref$quickKeys === void 0 ? [] : _ref$quickKeys,
60
+ _ref$inlineTags = _ref.inlineTags,
61
+ inlineTags = _ref$inlineTags === void 0 ? false : _ref$inlineTags,
62
+ renderTag = _ref.renderTag,
63
+ controlledTags = _ref.tags,
64
+ _ref$defaultTags = _ref.defaultTags,
65
+ defaultTags = _ref$defaultTags === void 0 ? [] : _ref$defaultTags,
66
+ onTagsChange = _ref.onTagsChange,
67
+ onQuickKeyTrigger = _ref.onQuickKeyTrigger,
68
+ _ref$submitFormat = _ref.submitFormat,
69
+ submitFormat = _ref$submitFormat === void 0 ? "text" : _ref$submitFormat,
70
+ formatTag = _ref.formatTag;
49
71
  var styles = useStyles();
50
72
  var isControlled = controlledValue !== undefined;
51
73
  var _useState = useState(defaultValue),
@@ -59,16 +81,51 @@ var XAdkSender = /*#__PURE__*/forwardRef(function (_ref, ref) {
59
81
  }
60
82
  onChange === null || onChange === void 0 || onChange(newValue);
61
83
  };
62
- var _useState3 = useState([]),
84
+
85
+ // tags 支持受控/非受控两种模式;inlineTags 打开时会和输入内容混排。
86
+ var isTagsControlled = controlledTags !== undefined;
87
+ var _useState3 = useState(defaultTags),
63
88
  _useState4 = _slicedToArray(_useState3, 2),
64
- files = _useState4[0],
65
- setFiles = _useState4[1];
66
- var _useState5 = useState(false),
89
+ internalTags = _useState4[0],
90
+ setInternalTags = _useState4[1];
91
+ var tags = isTagsControlled ? controlledTags : internalTags;
92
+ var setTags = function setTags(newTags) {
93
+ if (!isTagsControlled) {
94
+ setInternalTags(newTags);
95
+ }
96
+ onTagsChange === null || onTagsChange === void 0 || onTagsChange(newTags);
97
+ };
98
+ var _useState5 = useState([]),
67
99
  _useState6 = _slicedToArray(_useState5, 2),
68
- isDragOver = _useState6[0],
69
- setIsDragOver = _useState6[1];
100
+ files = _useState6[0],
101
+ setFiles = _useState6[1];
102
+ var _useState7 = useState(false),
103
+ _useState8 = _slicedToArray(_useState7, 2),
104
+ isDragOver = _useState8[0],
105
+ setIsDragOver = _useState8[1];
70
106
  var containerRef = useRef(null);
71
107
  var fileInputRef = useRef(null);
108
+ var textareaRef = useRef(null);
109
+ var inlineInputRef = useRef(null);
110
+
111
+ // 快捷键弹层状态:记录触发字符、关键词,以及触发字符在纯文本中的位置。
112
+ // SDK 不内置搜索框;业务方可在 onQuickKeyTrigger 中根据 keyword 自行更新 quickKeys.options。
113
+ var _useState9 = useState(null),
114
+ _useState10 = _slicedToArray(_useState9, 2),
115
+ activeQuickKey = _useState10[0],
116
+ setActiveQuickKey = _useState10[1];
117
+ var _useState11 = useState(""),
118
+ _useState12 = _slicedToArray(_useState11, 2),
119
+ quickKeyKeyword = _useState12[0],
120
+ setQuickKeyKeyword = _useState12[1];
121
+ var _useState13 = useState(-1),
122
+ _useState14 = _slicedToArray(_useState13, 2),
123
+ quickKeyTriggerIdx = _useState14[0],
124
+ setQuickKeyTriggerIdx = _useState14[1];
125
+ var _useState15 = useState(0),
126
+ _useState16 = _slicedToArray(_useState15, 2),
127
+ quickKeyActiveIndex = _useState16[0],
128
+ setQuickKeyActiveIndex = _useState16[1];
72
129
 
73
130
  // 生成唯一ID
74
131
  var generateId = function generateId() {
@@ -79,13 +136,85 @@ var XAdkSender = /*#__PURE__*/forwardRef(function (_ref, ref) {
79
136
  var data = (_response$data = response === null || response === void 0 ? void 0 : response.data) !== null && _response$data !== void 0 ? _response$data : response;
80
137
  return (_ref2 = Array.isArray(data) ? data[0] : data) !== null && _ref2 !== void 0 ? _ref2 : {};
81
138
  };
139
+ var escapeXml = function escapeXml(text) {
140
+ return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
141
+ };
142
+ var escapeMarkdownLabel = function escapeMarkdownLabel(text) {
143
+ return text.replace(/\\/g, "\\\\").replace(/\]/g, "\\]");
144
+ };
145
+ var getTagSubmitValue = function getTagSubmitValue(tag) {
146
+ var _ref3, _ref4, _ref5, _tag$value, _tag$data, _tag$data2;
147
+ return String((_ref3 = (_ref4 = (_ref5 = (_tag$value = tag.value) !== null && _tag$value !== void 0 ? _tag$value : (_tag$data = tag.data) === null || _tag$data === void 0 ? void 0 : _tag$data.value) !== null && _ref5 !== void 0 ? _ref5 : (_tag$data2 = tag.data) === null || _tag$data2 === void 0 ? void 0 : _tag$data2.name) !== null && _ref4 !== void 0 ? _ref4 : tag.label) !== null && _ref3 !== void 0 ? _ref3 : "");
148
+ };
149
+ var defaultFormatTag = function defaultFormatTag(tag, format, index) {
150
+ var value = getTagSubmitValue(tag);
151
+ if (format === "xml") {
152
+ return "<tag type=\"".concat(escapeXml(tag.type), "\" id=\"").concat(escapeXml(tag.id), "\" label=\"").concat(escapeXml(tag.label), "\" value=\"").concat(escapeXml(value), "\" />");
153
+ }
154
+ if (format === "markdown") {
155
+ return "[/".concat(escapeMarkdownLabel(tag.label), "](xadk-tag://").concat(encodeURIComponent(tag.type), "/").concat(encodeURIComponent(tag.id), ")");
156
+ }
157
+ return "/".concat(value || "tag-".concat(index + 1));
158
+ };
159
+ var serializeTag = function serializeTag(tag, format, index) {
160
+ var _formatTag;
161
+ return (_formatTag = formatTag === null || formatTag === void 0 ? void 0 : formatTag(tag, {
162
+ format: format,
163
+ index: index
164
+ })) !== null && _formatTag !== void 0 ? _formatTag : defaultFormatTag(tag, format, index);
165
+ };
166
+ var getSubmitParts = useCallback(function () {
167
+ if (inlineTags) {
168
+ var _inlineInputRef$curre;
169
+ var parts = ((_inlineInputRef$curre = inlineInputRef.current) === null || _inlineInputRef$curre === void 0 ? void 0 : _inlineInputRef$curre.getParts()) || [];
170
+ if (parts.length > 0) return parts;
171
+ }
172
+ var textParts = value ? [{
173
+ type: "text",
174
+ text: value
175
+ }] : [];
176
+ var tagParts = tags.map(function (tag) {
177
+ return {
178
+ type: "tag",
179
+ tag: tag
180
+ };
181
+ });
182
+ return [].concat(_toConsumableArray(tagParts), textParts);
183
+ }, [inlineTags, tags, value]);
184
+ var serializeParts = function serializeParts(parts, format) {
185
+ if (format === "structured") {
186
+ return parts.reduce(function (content, part) {
187
+ return content + (part.type === "text" ? part.text : "");
188
+ }, "");
189
+ }
190
+ var tagIndex = 0;
191
+ return parts.map(function (part) {
192
+ if (part.type === "text") return part.text;
193
+ var result = serializeTag(part.tag, format, tagIndex);
194
+ tagIndex += 1;
195
+ return result;
196
+ }).join("");
197
+ };
198
+ var createSubmitData = function createSubmitData(formattedFiles) {
199
+ var parts = getSubmitParts();
200
+ var rawText = parts.reduce(function (content, part) {
201
+ return content + (part.type === "text" ? part.text : "");
202
+ }, "");
203
+ return {
204
+ text: serializeParts(parts, submitFormat),
205
+ rawText: rawText,
206
+ format: submitFormat,
207
+ parts: parts,
208
+ files: formattedFiles,
209
+ tags: tags
210
+ };
211
+ };
82
212
 
83
213
  // 检查文件类型
84
214
  var checkFileType = function checkFileType(file) {
85
215
  if ((allowedFileTypes === null || allowedFileTypes === void 0 ? void 0 : allowedFileTypes.length) > 0) {
86
216
  var ext = getExt(file);
87
217
  return allowedFileTypes.some(function (type) {
88
- // 1️⃣ MIME 校验
89
218
  if (type.includes("/")) {
90
219
  if (type.endsWith("/*")) {
91
220
  return file.type.startsWith(type.split("/")[0]);
@@ -101,12 +230,6 @@ var XAdkSender = /*#__PURE__*/forwardRef(function (_ref, ref) {
101
230
  return true;
102
231
  };
103
232
 
104
- // 检查文件大小
105
- var checkFileSize = function checkFileSize(file) {
106
- var maxSize = maxFileSize * 1024 * 1024;
107
- return file.size <= maxSize;
108
- };
109
-
110
233
  // 重复文件检测
111
234
  var isDuplicateFile = function isDuplicateFile(file, files) {
112
235
  return files.some(function (f) {
@@ -115,33 +238,25 @@ var XAdkSender = /*#__PURE__*/forwardRef(function (_ref, ref) {
115
238
  };
116
239
 
117
240
  // 内置校验器集合
118
- var builtInValidators = [
119
- // 数量校验(修复批量 bug)
120
- function (_file, _ref3) {
121
- var files = _ref3.files;
241
+ var builtInValidators = [function (_file, _ref6) {
242
+ var files = _ref6.files;
122
243
  if (files.length >= maxFiles) {
123
244
  return "\u6700\u591A\u53EA\u80FD\u4E0A\u4F20 ".concat(maxFiles, " \u4E2A\u6587\u4EF6");
124
245
  }
125
246
  return null;
126
- },
127
- // 大小校验
128
- function (file) {
247
+ }, function (file) {
129
248
  var maxSize = maxFileSize * 1024 * 1024;
130
249
  if (file.size > maxSize) {
131
250
  return "\u6587\u4EF6\u5927\u5C0F\u4E0D\u80FD\u8D85\u8FC7 ".concat(maxFileSize, "MB");
132
251
  }
133
252
  return null;
134
- },
135
- // 类型校验
136
- function (file) {
253
+ }, function (file) {
137
254
  if (!checkFileType(file)) {
138
255
  return "不支持的文件类型";
139
256
  }
140
257
  return null;
141
- },
142
- // ⭐ 新增:去重校验
143
- function (file, _ref4) {
144
- var files = _ref4.files;
258
+ }, function (file, _ref7) {
259
+ var files = _ref7.files;
145
260
  if (isDuplicateFile(file, files)) {
146
261
  return "文件已存在";
147
262
  }
@@ -212,7 +327,7 @@ var XAdkSender = /*#__PURE__*/forwardRef(function (_ref, ref) {
212
327
  }
213
328
  }, [files, maxFiles, maxFileSize, allowedFileTypes]);
214
329
 
215
- // 暴露 addFiles 方法供外层(如 DefaultLayout 拖拽上传)调用
330
+ // 暴露 addFiles 方法
216
331
  useImperativeHandle(ref, function () {
217
332
  return {
218
333
  addFiles: function addFiles(rawFiles) {
@@ -221,9 +336,16 @@ var XAdkSender = /*#__PURE__*/forwardRef(function (_ref, ref) {
221
336
  };
222
337
  }, [handleFileSelect]);
223
338
 
339
+ // 触发文件选择
340
+ var triggerFileSelect = function triggerFileSelect() {
341
+ if (fileInputRef.current) {
342
+ fileInputRef.current.click();
343
+ }
344
+ };
345
+
224
346
  // 上传文件
225
347
  var uploadFiles = /*#__PURE__*/function () {
226
- var _ref5 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(fileList) {
348
+ var _ref8 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(fileList) {
227
349
  var _iterator2, _step2, _loop;
228
350
  return _regeneratorRuntime().wrap(function _callee$(_context2) {
229
351
  while (1) switch (_context2.prev = _context2.next) {
@@ -236,7 +358,6 @@ var XAdkSender = /*#__PURE__*/forwardRef(function (_ref, ref) {
236
358
  while (1) switch (_context.prev = _context.next) {
237
359
  case 0:
238
360
  localFile = _step2.value;
239
- // 开始上传
240
361
  setFiles(function (prev) {
241
362
  return prev.map(function (f) {
242
363
  return f.id === localFile.id ? _objectSpread(_objectSpread({}, f), {}, {
@@ -339,7 +460,7 @@ var XAdkSender = /*#__PURE__*/forwardRef(function (_ref, ref) {
339
460
  }, _callee, null, [[1, 10, 13, 16]]);
340
461
  }));
341
462
  return function uploadFiles(_x) {
342
- return _ref5.apply(this, arguments);
463
+ return _ref8.apply(this, arguments);
343
464
  };
344
465
  }();
345
466
 
@@ -354,13 +475,6 @@ var XAdkSender = /*#__PURE__*/forwardRef(function (_ref, ref) {
354
475
  });
355
476
  };
356
477
 
357
- // 触发文件选择
358
- var triggerFileSelect = function triggerFileSelect() {
359
- if (fileInputRef.current) {
360
- fileInputRef.current.click();
361
- }
362
- };
363
-
364
478
  // 处理拖拽事件
365
479
  var handleDragOver = useCallback(function (e) {
366
480
  e.preventDefault();
@@ -385,9 +499,170 @@ var XAdkSender = /*#__PURE__*/forwardRef(function (_ref, ref) {
385
499
  }
386
500
  }, [allowUpload, handleFileSelect]);
387
501
 
502
+ // 删除标签
503
+ var handleRemoveTag = useCallback(function (id) {
504
+ setTags(tags.filter(function (t) {
505
+ return t.id !== id;
506
+ }));
507
+ }, [tags, setTags]);
508
+
509
+ // 查找当前活跃的快捷键配置
510
+ var activeQuickKeyConfig = useMemo(function () {
511
+ if (!activeQuickKey) return null;
512
+ return quickKeys.find(function (qk) {
513
+ return qk.key === activeQuickKey;
514
+ }) || null;
515
+ }, [activeQuickKey, quickKeys]);
516
+ var activeQuickKeyOptionsLength = (activeQuickKeyConfig === null || activeQuickKeyConfig === void 0 ? void 0 : activeQuickKeyConfig.options.length) || 0;
517
+ useEffect(function () {
518
+ setQuickKeyActiveIndex(0);
519
+ }, [activeQuickKey]);
520
+ useEffect(function () {
521
+ if (activeQuickKeyOptionsLength <= 0) {
522
+ setQuickKeyActiveIndex(0);
523
+ return;
524
+ }
525
+
526
+ // 业务方可能在 onQuickKeyTrigger 中动态更新 options;
527
+ // 这里只做越界归一化,不重置有效索引,避免键盘高亮移动后又跳回第一项。
528
+ setQuickKeyActiveIndex(function (prev) {
529
+ return (prev % activeQuickKeyOptionsLength + activeQuickKeyOptionsLength) % activeQuickKeyOptionsLength;
530
+ });
531
+ }, [activeQuickKeyOptionsLength]);
532
+ var getNextQuickKeyIndex = useCallback(function (current, step) {
533
+ if (activeQuickKeyOptionsLength <= 0) return 0;
534
+ return (current + step + activeQuickKeyOptionsLength) % activeQuickKeyOptionsLength;
535
+ }, [activeQuickKeyOptionsLength]);
536
+
537
+ // 从当前光标前的连续文本片段中查找最近的快捷键,例如 abc@doc 会触发 @。
538
+ var detectQuickKey = useCallback(function (text, cursorPos) {
539
+ var quickKeyChars = quickKeys.map(function (qk) {
540
+ return qk.key;
541
+ });
542
+ if (quickKeyChars.length === 0) return;
543
+ var textBeforeCursor = text.slice(0, cursorPos);
544
+ var found = false;
545
+ for (var i = textBeforeCursor.length - 1; i >= 0; i--) {
546
+ var char = textBeforeCursor[i];
547
+ if (/\s/.test(char)) break;
548
+ if (quickKeyChars.includes(char)) {
549
+ var keyword = textBeforeCursor.slice(i + 1);
550
+ setActiveQuickKey(char);
551
+ setQuickKeyKeyword(keyword);
552
+ setQuickKeyTriggerIdx(i);
553
+ setQuickKeyActiveIndex(0);
554
+ onQuickKeyTrigger === null || onQuickKeyTrigger === void 0 || onQuickKeyTrigger(char, keyword);
555
+ found = true;
556
+ break;
557
+ }
558
+ }
559
+ if (!found && activeQuickKey) {
560
+ var triggerChar = text[quickKeyTriggerIdx];
561
+ var _keyword = text.slice(quickKeyTriggerIdx + 1, cursorPos);
562
+ if (quickKeyTriggerIdx < 0 || !triggerChar || !quickKeyChars.includes(triggerChar) || /\s/.test(_keyword)) {
563
+ setActiveQuickKey(null);
564
+ setQuickKeyKeyword("");
565
+ setQuickKeyTriggerIdx(-1);
566
+ setQuickKeyActiveIndex(0);
567
+ } else {
568
+ setQuickKeyKeyword(_keyword);
569
+ }
570
+ }
571
+ }, [activeQuickKey, onQuickKeyTrigger, quickKeyTriggerIdx, quickKeys]);
572
+
573
+ // 选择快捷项后转成结构化 tag;inline 模式会替换掉触发字符和关键词。
574
+ var handleQuickKeySelect = useCallback(function (option) {
575
+ var _ref9, _option$value, _activeQuickKeyConfig, _inlineInputRef$curre3, _textareaRef$current;
576
+ var newTag = {
577
+ id: generateId(),
578
+ label: option.label,
579
+ type: activeQuickKey || "unknown",
580
+ value: (_ref9 = (_option$value = option.value) !== null && _option$value !== void 0 ? _option$value : option.name) !== null && _ref9 !== void 0 ? _ref9 : option.label,
581
+ trigger: activeQuickKey || undefined,
582
+ icon: option.icon,
583
+ data: option
584
+ };
585
+ activeQuickKeyConfig === null || activeQuickKeyConfig === void 0 || (_activeQuickKeyConfig = activeQuickKeyConfig.onSelect) === null || _activeQuickKeyConfig === void 0 || _activeQuickKeyConfig.call(activeQuickKeyConfig, option);
586
+ if (inlineTags) {
587
+ var _inlineInputRef$curre2;
588
+ (_inlineInputRef$curre2 = inlineInputRef.current) === null || _inlineInputRef$curre2 === void 0 || _inlineInputRef$curre2.insertTag(newTag, {
589
+ start: quickKeyTriggerIdx,
590
+ end: quickKeyTriggerIdx + 1 + quickKeyKeyword.length
591
+ });
592
+ } else {
593
+ setTags([].concat(_toConsumableArray(tags), [newTag]));
594
+
595
+ // 从输入框中删除快捷键字符和关键词
596
+ if (quickKeyTriggerIdx >= 0) {
597
+ var newValue = value.slice(0, quickKeyTriggerIdx) + value.slice(quickKeyTriggerIdx + 1 + quickKeyKeyword.length);
598
+ setValue(newValue);
599
+ }
600
+ }
601
+ setActiveQuickKey(null);
602
+ setQuickKeyKeyword("");
603
+ setQuickKeyTriggerIdx(-1);
604
+ setQuickKeyActiveIndex(0);
605
+ inlineTags ? (_inlineInputRef$curre3 = inlineInputRef.current) === null || _inlineInputRef$curre3 === void 0 ? void 0 : _inlineInputRef$curre3.focus() : (_textareaRef$current = textareaRef.current) === null || _textareaRef$current === void 0 ? void 0 : _textareaRef$current.focus();
606
+ }, [activeQuickKey, activeQuickKeyConfig, inlineTags, tags, setTags, value, quickKeyTriggerIdx, quickKeyKeyword, setValue]);
607
+
608
+ // 处理输入框变化(含快捷键检测)
609
+ var handleInputChange = function handleInputChange(e) {
610
+ var newValue = e.target.value;
611
+ setValue(newValue);
612
+
613
+ // 检测快捷键触发
614
+ detectQuickKey(newValue, e.target.selectionStart || 0);
615
+ };
616
+ var handleInlineInputChange = function handleInlineInputChange(newValue) {
617
+ var _inlineInputRef$curre4;
618
+ setValue(newValue);
619
+ // contenteditable 的 selection 不一定和 React state 同步,需实时读取内部光标 offset。
620
+ detectQuickKey(newValue, ((_inlineInputRef$curre4 = inlineInputRef.current) === null || _inlineInputRef$curre4 === void 0 ? void 0 : _inlineInputRef$curre4.getCursorOffset()) || newValue.length);
621
+ };
622
+ var handleQuickKeyByText = function handleQuickKeyByText(text, cursorPos) {
623
+ var quickKeyChars = quickKeys.map(function (qk) {
624
+ return qk.key;
625
+ });
626
+ if (quickKeyChars.length === 0) return;
627
+ var textBeforeCursor = text.slice(0, cursorPos);
628
+
629
+ // 检测刚输入的字符是否是快捷键
630
+ var lastChar = textBeforeCursor[cursorPos - 1];
631
+ if (lastChar && quickKeyChars.includes(lastChar)) {
632
+ // 上下键导航后会触发 keyup,此时光标前仍是同一个快捷键字符;
633
+ // 如果重复重置 activeIndex,视觉上会“移动一下又回到第一项”。
634
+ if (activeQuickKey === lastChar && quickKeyTriggerIdx === cursorPos - 1) {
635
+ return;
636
+ }
637
+ setActiveQuickKey(lastChar);
638
+ setQuickKeyKeyword("");
639
+ setQuickKeyTriggerIdx(cursorPos - 1);
640
+ setQuickKeyActiveIndex(0);
641
+ onQuickKeyTrigger === null || onQuickKeyTrigger === void 0 || onQuickKeyTrigger(lastChar, "");
642
+ }
643
+ };
644
+
645
+ // onChange 负责更新搜索词;onKeyUp 兜底捕获刚输入的快捷键字符。
646
+ var isQuickListControlKey = function isQuickListControlKey(key) {
647
+ return key === "ArrowDown" || key === "ArrowUp" || key === "Enter" || key === "Escape";
648
+ };
649
+ var handleKeyUp = function handleKeyUp(e) {
650
+ if (activeQuickKey && isQuickListControlKey(e.key)) return;
651
+ var target = e.target;
652
+ handleQuickKeyByText(target.value || "", target.selectionStart || 0);
653
+ };
654
+ var handleInlineKeyUp = function handleInlineKeyUp(e) {
655
+ var _inlineInputRef$curre5, _inlineInputRef$curre6;
656
+ if (activeQuickKey && isQuickListControlKey(e.key)) return;
657
+ // inline 输入区不是 textarea,不能读 event.target.value,只能从 ref 取纯文本。
658
+ var text = ((_inlineInputRef$curre5 = inlineInputRef.current) === null || _inlineInputRef$curre5 === void 0 ? void 0 : _inlineInputRef$curre5.getText()) || "";
659
+ var cursorPos = ((_inlineInputRef$curre6 = inlineInputRef.current) === null || _inlineInputRef$curre6 === void 0 ? void 0 : _inlineInputRef$curre6.getCursorOffset()) || text.length;
660
+ handleQuickKeyByText(text, cursorPos);
661
+ };
662
+
388
663
  // 处理提交
389
664
  var handleSubmit = function handleSubmit() {
390
- if (!value.trim() && files.length === 0) {
665
+ if (!value.trim() && files.length === 0 && tags.length === 0) {
391
666
  message.warning("请输入消息或选择文件");
392
667
  return;
393
668
  }
@@ -406,12 +681,10 @@ var XAdkSender = /*#__PURE__*/forwardRef(function (_ref, ref) {
406
681
  onOk: function onOk() {
407
682
  var formattedFiles = formatFilesForServer(successFiles);
408
683
  if (onSubmit) {
409
- onSubmit({
410
- text: value,
411
- files: formattedFiles
412
- });
684
+ onSubmit(createSubmitData(formattedFiles));
413
685
  }
414
686
  setValue("");
687
+ setTags([]);
415
688
  setFiles(function (prev) {
416
689
  return prev.filter(function (f) {
417
690
  return f.status !== "success";
@@ -425,12 +698,10 @@ var XAdkSender = /*#__PURE__*/forwardRef(function (_ref, ref) {
425
698
  } else {
426
699
  var formattedFiles = formatFilesForServer(successFiles);
427
700
  if (onSubmit) {
428
- onSubmit({
429
- text: value,
430
- files: formattedFiles
431
- });
701
+ onSubmit(createSubmitData(formattedFiles));
432
702
  }
433
703
  setValue("");
704
+ setTags([]);
434
705
  setFiles(function (prev) {
435
706
  return prev.filter(function (f) {
436
707
  return f.status !== "success";
@@ -457,21 +728,45 @@ var XAdkSender = /*#__PURE__*/forwardRef(function (_ref, ref) {
457
728
  });
458
729
  };
459
730
 
460
- // 处理输入框变化
461
- var handleInputChange = function handleInputChange(e) {
462
- var newValue = e.target.value;
463
- setValue(newValue);
464
- };
465
-
466
731
  // 处理回车键
467
732
  var handleKeyDown = function handleKeyDown(e) {
468
- if (e.key === "Enter" && !e.shiftKey) {
733
+ var quickKeyOptions = (activeQuickKeyConfig === null || activeQuickKeyConfig === void 0 ? void 0 : activeQuickKeyConfig.options) || [];
734
+ if (activeQuickKey && quickKeyOptions.length > 0) {
735
+ if (e.key === "ArrowDown") {
736
+ e.preventDefault();
737
+ setQuickKeyActiveIndex(function (prev) {
738
+ return getNextQuickKeyIndex(prev, 1);
739
+ });
740
+ return;
741
+ }
742
+ if (e.key === "ArrowUp") {
743
+ e.preventDefault();
744
+ setQuickKeyActiveIndex(function (prev) {
745
+ return getNextQuickKeyIndex(prev, -1);
746
+ });
747
+ return;
748
+ }
749
+ if (e.key === "Enter") {
750
+ e.preventDefault();
751
+ handleQuickKeySelect(quickKeyOptions[Math.min(quickKeyActiveIndex, quickKeyOptions.length - 1)]);
752
+ return;
753
+ }
754
+ if (e.key === "Escape") {
755
+ e.preventDefault();
756
+ setActiveQuickKey(null);
757
+ setQuickKeyKeyword("");
758
+ setQuickKeyTriggerIdx(-1);
759
+ setQuickKeyActiveIndex(0);
760
+ return;
761
+ }
762
+ }
763
+ if (e.key === "Enter" && !e.shiftKey && !activeQuickKey) {
469
764
  e.preventDefault();
470
765
  handleSubmit();
471
766
  }
472
767
  };
473
768
 
474
- // 渲染文件列表 - 使用新的 FileGallery 组件
769
+ // 渲染文件列表
475
770
  var renderFileList = function renderFileList() {
476
771
  if (files.length === 0) return null;
477
772
  return /*#__PURE__*/_jsx("div", {
@@ -484,7 +779,6 @@ var XAdkSender = /*#__PURE__*/forwardRef(function (_ref, ref) {
484
779
  children: files.map(function (file) {
485
780
  return /*#__PURE__*/_jsx(FileGallery, {
486
781
  file: file,
487
- type: "file",
488
782
  removable: true,
489
783
  onRemove: handleRemoveFile
490
784
  }, file.id);
@@ -500,10 +794,10 @@ var XAdkSender = /*#__PURE__*/forwardRef(function (_ref, ref) {
500
794
  var hasFiles = files.some(function (f) {
501
795
  return f.status === "success";
502
796
  });
503
- var canSend = hasContent || hasFiles;
797
+ var hasTags = tags.length > 0;
798
+ var canSend = hasContent || hasFiles || hasTags;
504
799
 
505
- // 定义按钮组件(供外部 slot 函数通过 actionsComponents 使用)
506
- // 注意:sendButtonRender 的结果直接内联到 defaultSuffix 中,避免组件引用变化导致闪烁
800
+ // 定义按钮组件
507
801
  var SendButton = function SendButton(props) {
508
802
  if (sendButtonRender) {
509
803
  return /*#__PURE__*/_jsx(_Fragment, {
@@ -579,19 +873,10 @@ var XAdkSender = /*#__PURE__*/forwardRef(function (_ref, ref) {
579
873
  return slot;
580
874
  };
581
875
 
582
- // 默认的后缀内容(操作按钮组) - 直接内联渲染避免组件引用变化导致 unmount/remount
583
- var defaultSuffix = /*#__PURE__*/_jsxs("div", {
876
+ // 默认后缀仅保留发送/停止按钮;上传与清空统一放到底部 actionBar,方便业务扩展左侧按钮组。
877
+ var defaultSuffix = /*#__PURE__*/_jsx("div", {
584
878
  className: styles.buttonGroup,
585
- children: [allowUpload && /*#__PURE__*/_jsx(Tooltip, {
586
- title: "\u4E0A\u4F20\u6587\u4EF6",
587
- children: /*#__PURE__*/_jsx("button", {
588
- className: "".concat(styles.iconButton, " ").concat(styles.uploadButton),
589
- onClick: triggerFileSelect,
590
- disabled: isDisabled,
591
- "aria-label": "\u4E0A\u4F20\u6587\u4EF6",
592
- children: /*#__PURE__*/_jsx(PaperClipOutlined, {})
593
- })
594
- }), sendButtonRender ? sendButtonRender({
879
+ children: sendButtonRender ? sendButtonRender({
595
880
  loading: loading,
596
881
  disabled: uploading || disabled,
597
882
  canSend: canSend,
@@ -608,6 +893,16 @@ var XAdkSender = /*#__PURE__*/forwardRef(function (_ref, ref) {
608
893
  spin: true
609
894
  }) : /*#__PURE__*/_jsx(ArrowUpOutlined, {})
610
895
  })
896
+ })
897
+ });
898
+ var defaultActionBar = /*#__PURE__*/_jsxs("div", {
899
+ className: styles.actionBar,
900
+ children: [/*#__PURE__*/_jsxs("div", {
901
+ className: styles.actionBarLeft,
902
+ children: [allowUpload && /*#__PURE__*/_jsx(UploadButton, {}), renderSlot(footerLeft, false)]
903
+ }), /*#__PURE__*/_jsxs("div", {
904
+ className: styles.actionBarRight,
905
+ children: [clearBtnShow && /*#__PURE__*/_jsx(ClearButton, {}), renderSlot(suffix, defaultSuffix)]
611
906
  })]
612
907
  });
613
908
  return /*#__PURE__*/_jsxs("div", {
@@ -634,16 +929,32 @@ var XAdkSender = /*#__PURE__*/forwardRef(function (_ref, ref) {
634
929
  className: styles.mainArea,
635
930
  children: /*#__PURE__*/_jsxs("div", {
636
931
  className: styles.senderWrap,
637
- children: [/*#__PURE__*/_jsxs("div", {
932
+ children: [!inlineTags && /*#__PURE__*/_jsx(InputTags, {
933
+ tags: tags,
934
+ onRemove: handleRemoveTag
935
+ }), /*#__PURE__*/_jsxs("div", {
638
936
  className: styles.inputAndButtons,
639
- children: [clearBtnShow && /*#__PURE__*/_jsx(ClearButton, {}), renderSlot(prefix, false), /*#__PURE__*/_jsx("div", {
937
+ children: [renderSlot(prefix, false), inlineTags ? /*#__PURE__*/_jsx(InlineTagInput, {
938
+ ref: inlineInputRef,
939
+ value: value,
940
+ tags: tags,
941
+ placeholder: placeholder,
942
+ disabled: isDisabled,
943
+ onChange: handleInlineInputChange,
944
+ onTagsChange: setTags,
945
+ onKeyDown: handleKeyDown,
946
+ onKeyUp: handleInlineKeyUp,
947
+ renderTag: renderTag
948
+ }) : /*#__PURE__*/_jsx("div", {
640
949
  className: styles.textAreaWrapper,
641
950
  children: /*#__PURE__*/_jsx(Input.TextArea, {
951
+ ref: textareaRef,
642
952
  className: styles.textArea,
643
953
  value: value,
644
954
  onChange: handleInputChange,
645
955
  onKeyDown: handleKeyDown,
646
- placeholder: "\u8BF7\u8F93\u5165\u6D88\u606F...",
956
+ onKeyUp: handleKeyUp,
957
+ placeholder: placeholder,
647
958
  autoSize: {
648
959
  minRows: 1,
649
960
  maxRows: 4
@@ -655,21 +966,29 @@ var XAdkSender = /*#__PURE__*/forwardRef(function (_ref, ref) {
655
966
  padding: 0
656
967
  }
657
968
  })
658
- }), renderSlot(suffix, defaultSuffix)]
659
- }), renderSlot(footer, /*#__PURE__*/_jsx("div", {
660
- className: styles.tip,
661
- children: "\u5185\u5BB9\u7531AI\u751F\u6210,\u65E0\u6CD5\u786E\u4FDD\u771F\u5B9E\u51C6\u786E,\u4EC5\u4F9B\u53C2\u8003"
662
- }))]
969
+ })]
970
+ }), activeQuickKey && activeQuickKeyConfig && /*#__PURE__*/_jsx("div", {
971
+ className: styles.quickListWrapper,
972
+ children: /*#__PURE__*/_jsx(QuickList, {
973
+ config: activeQuickKeyConfig,
974
+ activeIndex: quickKeyActiveIndex,
975
+ onSelect: handleQuickKeySelect,
976
+ onClose: function onClose() {
977
+ setActiveQuickKey(null);
978
+ setQuickKeyKeyword("");
979
+ setQuickKeyTriggerIdx(-1);
980
+ setQuickKeyActiveIndex(0);
981
+ },
982
+ visible: true
983
+ })
984
+ }), footer === false ? defaultActionBar : renderSlot(footer, defaultActionBar)]
663
985
  })
986
+ }), !footer && /*#__PURE__*/_jsx("div", {
987
+ className: styles.tip,
988
+ children: "\u5185\u5BB9\u7531AI\u751F\u6210,\u65E0\u6CD5\u786E\u4FDD\u771F\u5B9E\u51C6\u786E,\u4EC5\u4F9B\u53C2\u8003"
664
989
  })]
665
990
  });
666
991
  });
667
992
  XAdkSender.displayName = "XAdkSender";
668
- import XAdkSenderSwitch from "./Switch";
669
- import { jsx as _jsx } from "react/jsx-runtime";
670
- import { Fragment as _Fragment } from "react/jsx-runtime";
671
- import { jsxs as _jsxs } from "react/jsx-runtime";
672
- var CompoundSender = XAdkSender;
673
- CompoundSender.Switch = XAdkSenderSwitch;
674
- export default CompoundSender;
993
+ export default XAdkSender;
675
994
  //# sourceMappingURL=index.js.map