@ai-group/chat-sdk 3.7.1-alpha2 → 3.7.1-alpha4
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/cjs/components/FileGallery/index.js +59 -40
- package/dist/cjs/components/FileGallery/index.js.map +2 -2
- package/dist/cjs/components/FileGallery/styles.d.ts +7 -0
- package/dist/cjs/components/FileGallery/styles.js +78 -0
- package/dist/cjs/components/FileGallery/styles.js.map +2 -2
- package/dist/cjs/components/XAdkChatbot/components/MarkdownRender/index.d.ts +7 -1
- package/dist/cjs/components/XAdkChatbot/components/MarkdownRender/index.js +82 -22
- package/dist/cjs/components/XAdkChatbot/components/MarkdownRender/index.js.map +2 -2
- package/dist/cjs/components/XAdkChatbot/components/MarkdownRender/styles.d.ts +3 -0
- package/dist/cjs/components/XAdkChatbot/components/MarkdownRender/styles.js +39 -0
- package/dist/cjs/components/XAdkChatbot/components/MarkdownRender/styles.js.map +2 -2
- package/dist/cjs/components/XAdkChatbot/index.js +35 -5
- package/dist/cjs/components/XAdkChatbot/index.js.map +2 -2
- package/dist/cjs/components/XAdkChatbot/styles.js +1 -1
- package/dist/cjs/components/XAdkChatbot/styles.js.map +1 -1
- package/dist/cjs/components/XAdkSender/InlineTagInput.d.ts +11 -5
- package/dist/cjs/components/XAdkSender/InlineTagInput.js +188 -113
- package/dist/cjs/components/XAdkSender/InlineTagInput.js.map +2 -2
- package/dist/cjs/components/XAdkSender/InputTags.d.ts +2 -2
- package/dist/cjs/components/XAdkSender/InputTags.js +8 -8
- package/dist/cjs/components/XAdkSender/InputTags.js.map +2 -2
- package/dist/cjs/components/XAdkSender/index.js +104 -64
- package/dist/cjs/components/XAdkSender/index.js.map +2 -2
- package/dist/cjs/components/XAdkSender/styles.d.ts +4 -0
- package/dist/cjs/components/XAdkSender/styles.js +34 -6
- package/dist/cjs/components/XAdkSender/styles.js.map +2 -2
- package/dist/cjs/index.d.ts +2 -1
- package/dist/cjs/index.js +7 -0
- package/dist/cjs/index.js.map +2 -2
- package/dist/cjs/types/FileGallery.d.ts +3 -0
- package/dist/cjs/types/FileGallery.js.map +1 -1
- package/dist/cjs/types/XAdkChatbot.d.ts +15 -0
- package/dist/cjs/types/XAdkChatbot.js.map +1 -1
- package/dist/cjs/types/XAdkSender.d.ts +74 -23
- package/dist/cjs/types/XAdkSender.js.map +1 -1
- package/dist/cjs/utils/index.d.ts +1 -0
- package/dist/cjs/utils/index.js +3 -1
- package/dist/cjs/utils/index.js.map +2 -2
- package/dist/cjs/utils/markdownResource.d.ts +7 -0
- package/dist/cjs/utils/markdownResource.js +73 -0
- package/dist/cjs/utils/markdownResource.js.map +7 -0
- package/dist/esm/components/FileGallery/index.js +22 -16
- package/dist/esm/components/FileGallery/index.js.map +1 -1
- package/dist/esm/components/FileGallery/styles.d.ts +7 -0
- package/dist/esm/components/FileGallery/styles.js +24 -17
- package/dist/esm/components/FileGallery/styles.js.map +1 -1
- package/dist/esm/components/XAdkChatbot/components/MarkdownRender/index.d.ts +7 -1
- package/dist/esm/components/XAdkChatbot/components/MarkdownRender/index.js +57 -7
- package/dist/esm/components/XAdkChatbot/components/MarkdownRender/index.js.map +1 -1
- package/dist/esm/components/XAdkChatbot/components/MarkdownRender/styles.d.ts +3 -0
- package/dist/esm/components/XAdkChatbot/components/MarkdownRender/styles.js +5 -2
- package/dist/esm/components/XAdkChatbot/components/MarkdownRender/styles.js.map +1 -1
- package/dist/esm/components/XAdkChatbot/index.js +20 -6
- package/dist/esm/components/XAdkChatbot/index.js.map +1 -1
- package/dist/esm/components/XAdkChatbot/styles.js +1 -1
- package/dist/esm/components/XAdkChatbot/styles.js.map +1 -1
- package/dist/esm/components/XAdkSender/InlineTagInput.d.ts +11 -5
- package/dist/esm/components/XAdkSender/InlineTagInput.js +185 -117
- package/dist/esm/components/XAdkSender/InlineTagInput.js.map +1 -1
- package/dist/esm/components/XAdkSender/InputTags.d.ts +2 -2
- package/dist/esm/components/XAdkSender/InputTags.js +9 -9
- package/dist/esm/components/XAdkSender/InputTags.js.map +1 -1
- package/dist/esm/components/XAdkSender/index.js +124 -77
- package/dist/esm/components/XAdkSender/index.js.map +1 -1
- package/dist/esm/components/XAdkSender/styles.d.ts +4 -0
- package/dist/esm/components/XAdkSender/styles.js +29 -25
- package/dist/esm/components/XAdkSender/styles.js.map +1 -1
- package/dist/esm/index.d.ts +2 -1
- package/dist/esm/index.js +2 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/types/FileGallery.d.ts +3 -0
- package/dist/esm/types/FileGallery.js.map +1 -1
- package/dist/esm/types/XAdkChatbot.d.ts +15 -0
- package/dist/esm/types/XAdkChatbot.js.map +1 -1
- package/dist/esm/types/XAdkSender.d.ts +74 -23
- package/dist/esm/types/XAdkSender.js.map +1 -1
- package/dist/esm/utils/index.d.ts +1 -0
- package/dist/esm/utils/index.js +1 -0
- package/dist/esm/utils/index.js.map +1 -1
- package/dist/esm/utils/markdownResource.d.ts +7 -0
- package/dist/esm/utils/markdownResource.js +33 -0
- package/dist/esm/utils/markdownResource.js.map +1 -0
- package/dist/umd/chat-sdk.min.js +1 -1
- package/package.json +1 -1
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
|
|
2
|
-
import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useRef } from "react";
|
|
2
|
+
import React, { forwardRef, useCallback, useEffect, useLayoutEffect, useImperativeHandle, useRef } from "react";
|
|
3
3
|
import { createRoot } from "react-dom/client";
|
|
4
4
|
import { useStyles } from "./styles";
|
|
5
5
|
import { Fragment as _Fragment } from "react/jsx-runtime";
|
|
6
6
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
8
|
+
var MENTION_ATTR = "data-xadk-inline-mention-id";
|
|
9
|
+
// contenteditable 无法把光标放进 contenteditable=false 的 Mention 里,需用零宽字符承接“Mention 后方”的光标。
|
|
9
10
|
var CARET_TEXT = "\u200B";
|
|
10
11
|
var createTextNode = function createTextNode(text) {
|
|
11
12
|
return document.createTextNode(text);
|
|
12
13
|
};
|
|
14
|
+
var useIsomorphicLayoutEffect = typeof window === "undefined" ? useEffect : useLayoutEffect;
|
|
13
15
|
var normalizeText = function normalizeText(text) {
|
|
14
16
|
return text.replace(/\u200B/g, "").replace(/\u00a0/g, " ");
|
|
15
17
|
};
|
|
@@ -27,31 +29,40 @@ var toRawOffset = function toRawOffset(text, plainOffset) {
|
|
|
27
29
|
};
|
|
28
30
|
var InlineTagInput = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
29
31
|
var value = _ref.value,
|
|
30
|
-
|
|
32
|
+
mentions = _ref.mentions,
|
|
33
|
+
defaultInputParts = _ref.defaultInputParts,
|
|
31
34
|
placeholder = _ref.placeholder,
|
|
32
35
|
disabled = _ref.disabled,
|
|
33
36
|
onChange = _ref.onChange,
|
|
34
|
-
|
|
37
|
+
onMentionsChange = _ref.onMentionsChange,
|
|
35
38
|
onKeyDown = _ref.onKeyDown,
|
|
36
|
-
|
|
37
|
-
|
|
39
|
+
_onKeyUp = _ref.onKeyUp,
|
|
40
|
+
renderMention = _ref.renderMention;
|
|
38
41
|
var styles = useStyles();
|
|
39
42
|
var editorRef = useRef(null);
|
|
40
|
-
var
|
|
43
|
+
var latestMentionsRef = useRef(mentions);
|
|
41
44
|
var tagRootMapRef = useRef(new WeakMap());
|
|
42
45
|
var composingRef = useRef(false);
|
|
43
46
|
var lastInsertedCaretRef = useRef(null);
|
|
47
|
+
var savedRangeRef = useRef(null);
|
|
48
|
+
var defaultInputPartsAppliedRef = useRef(false);
|
|
49
|
+
var lastEmittedStateRef = useRef({
|
|
50
|
+
value: value,
|
|
51
|
+
mentionIds: mentions.map(function (mention) {
|
|
52
|
+
return mention.id;
|
|
53
|
+
}).join("|")
|
|
54
|
+
});
|
|
44
55
|
useEffect(function () {
|
|
45
|
-
|
|
46
|
-
}, [
|
|
47
|
-
var
|
|
56
|
+
latestMentionsRef.current = mentions;
|
|
57
|
+
}, [mentions]);
|
|
58
|
+
var getOrderedMentions = useCallback(function () {
|
|
48
59
|
var editor = editorRef.current;
|
|
49
60
|
if (!editor) return [];
|
|
50
|
-
var
|
|
51
|
-
return [
|
|
61
|
+
var mentionMap = new Map(latestMentionsRef.current.map(function (mention) {
|
|
62
|
+
return [mention.id, mention];
|
|
52
63
|
}));
|
|
53
|
-
return Array.from(editor.querySelectorAll("[".concat(
|
|
54
|
-
return
|
|
64
|
+
return Array.from(editor.querySelectorAll("[".concat(MENTION_ATTR, "]"))).map(function (node) {
|
|
65
|
+
return mentionMap.get(node.dataset.xadkInlineMentionId || "");
|
|
55
66
|
}).filter(Boolean);
|
|
56
67
|
}, []);
|
|
57
68
|
|
|
@@ -68,12 +79,12 @@ var InlineTagInput = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
68
79
|
return normalizeText(text);
|
|
69
80
|
}, []);
|
|
70
81
|
|
|
71
|
-
// 提交时需要保留文本与
|
|
82
|
+
// 提交时需要保留文本与 Mention 的真实顺序;仅靠 value + mentions 无法区分 Mention 在句首、句中还是句尾。
|
|
72
83
|
var getParts = useCallback(function () {
|
|
73
84
|
var editor = editorRef.current;
|
|
74
85
|
if (!editor) return [];
|
|
75
|
-
var
|
|
76
|
-
return [
|
|
86
|
+
var mentionMap = new Map(latestMentionsRef.current.map(function (mention) {
|
|
87
|
+
return [mention.id, mention];
|
|
77
88
|
}));
|
|
78
89
|
var parts = [];
|
|
79
90
|
editor.childNodes.forEach(function (node) {
|
|
@@ -85,34 +96,42 @@ var InlineTagInput = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
85
96
|
});
|
|
86
97
|
return;
|
|
87
98
|
}
|
|
88
|
-
if (node instanceof HTMLElement && node.hasAttribute(
|
|
89
|
-
var
|
|
90
|
-
var
|
|
91
|
-
if (
|
|
92
|
-
type: "
|
|
93
|
-
|
|
99
|
+
if (node instanceof HTMLElement && node.hasAttribute(MENTION_ATTR)) {
|
|
100
|
+
var mentionId = node.dataset.xadkInlineMentionId || "";
|
|
101
|
+
var _mention = mentionMap.get(mentionId);
|
|
102
|
+
if (_mention) parts.push({
|
|
103
|
+
type: "mention",
|
|
104
|
+
mention: _mention
|
|
94
105
|
});
|
|
95
106
|
}
|
|
96
107
|
});
|
|
97
108
|
return parts;
|
|
98
109
|
}, []);
|
|
99
110
|
var emitChange = useCallback(function () {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
111
|
+
var nextValue = getPlainText();
|
|
112
|
+
var nextMentions = getOrderedMentions();
|
|
113
|
+
lastEmittedStateRef.current = {
|
|
114
|
+
value: nextValue,
|
|
115
|
+
mentionIds: nextMentions.map(function (mention) {
|
|
116
|
+
return mention.id;
|
|
117
|
+
}).join("|")
|
|
118
|
+
};
|
|
119
|
+
onChange(nextValue);
|
|
120
|
+
onMentionsChange(nextMentions);
|
|
121
|
+
}, [getOrderedMentions, getPlainText, onChange, onMentionsChange]);
|
|
103
122
|
var removeTextRange = useCallback(function (node, start, end) {
|
|
104
123
|
var text = node.textContent || "";
|
|
105
124
|
node.textContent = "".concat(text.slice(0, start)).concat(text.slice(end));
|
|
106
125
|
if (!node.textContent) node.remove();
|
|
107
126
|
}, []);
|
|
108
|
-
var
|
|
127
|
+
var removeMentionNode = useCallback(function (node) {
|
|
109
128
|
var _tagRootMapRef$curren;
|
|
110
129
|
var previous = node.previousSibling;
|
|
111
130
|
var next = node.nextSibling;
|
|
112
131
|
(_tagRootMapRef$curren = tagRootMapRef.current.get(node)) === null || _tagRootMapRef$curren === void 0 || _tagRootMapRef$curren.unmount();
|
|
113
132
|
node.remove();
|
|
114
133
|
|
|
115
|
-
//
|
|
134
|
+
// Mention 后会补一个不可见光标锚点;删除 Mention 时同步清理,避免留下冗余节点。
|
|
116
135
|
if ((next === null || next === void 0 ? void 0 : next.nodeType) === Node.TEXT_NODE) {
|
|
117
136
|
var _text$match;
|
|
118
137
|
var text = next.textContent || "";
|
|
@@ -131,51 +150,68 @@ var InlineTagInput = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
131
150
|
}
|
|
132
151
|
}
|
|
133
152
|
}, [removeTextRange]);
|
|
134
|
-
var
|
|
153
|
+
var removeMentionById = useCallback(function (id) {
|
|
135
154
|
var editor = editorRef.current;
|
|
136
|
-
var node = Array.from((editor === null || editor === void 0 ? void 0 : editor.querySelectorAll("[".concat(
|
|
137
|
-
return item.dataset.
|
|
155
|
+
var node = Array.from((editor === null || editor === void 0 ? void 0 : editor.querySelectorAll("[".concat(MENTION_ATTR, "]"))) || []).find(function (item) {
|
|
156
|
+
return item.dataset.xadkInlineMentionId === id;
|
|
138
157
|
});
|
|
139
158
|
if (node) {
|
|
140
|
-
|
|
159
|
+
removeMentionNode(node);
|
|
141
160
|
}
|
|
142
161
|
emitChange();
|
|
143
162
|
editor === null || editor === void 0 || editor.focus();
|
|
144
|
-
}, [emitChange,
|
|
163
|
+
}, [emitChange, removeMentionNode]);
|
|
145
164
|
|
|
146
|
-
//
|
|
147
|
-
var
|
|
165
|
+
// Mention 节点本身不可编辑;删除入口通过 onRemove 回到组件内部统一维护 DOM 与 mentions。
|
|
166
|
+
var buildMentionNode = useCallback(function (mention) {
|
|
148
167
|
var span = document.createElement("span");
|
|
149
168
|
span.setAttribute("contenteditable", "false");
|
|
150
|
-
span.setAttribute(
|
|
151
|
-
span.dataset.
|
|
169
|
+
span.setAttribute(MENTION_ATTR, mention.id);
|
|
170
|
+
span.dataset.xadkInlineMentionId = mention.id;
|
|
152
171
|
span.className = styles.inlineTag;
|
|
153
|
-
if (
|
|
172
|
+
if (renderMention) {
|
|
154
173
|
var root = createRoot(span);
|
|
155
174
|
tagRootMapRef.current.set(span, root);
|
|
156
175
|
root.render( /*#__PURE__*/_jsx(_Fragment, {
|
|
157
|
-
children:
|
|
176
|
+
children: renderMention(mention, {
|
|
158
177
|
onRemove: function onRemove() {
|
|
159
|
-
return
|
|
178
|
+
return removeMentionById(mention.id);
|
|
160
179
|
}
|
|
161
180
|
})
|
|
162
181
|
}));
|
|
163
182
|
} else {
|
|
164
183
|
var label = document.createElement("span");
|
|
165
184
|
label.className = "xadk-inline-tag-label";
|
|
166
|
-
label.textContent =
|
|
185
|
+
label.textContent = mention.displayName || mention.label;
|
|
167
186
|
var close = document.createElement("span");
|
|
168
187
|
close.className = "xadk-inline-tag-close";
|
|
169
188
|
close.innerHTML = "×";
|
|
170
189
|
close.onclick = function (event) {
|
|
171
190
|
event.preventDefault();
|
|
172
191
|
event.stopPropagation();
|
|
173
|
-
|
|
192
|
+
removeMentionById(mention.id);
|
|
174
193
|
};
|
|
175
194
|
span.append(label, close);
|
|
176
195
|
}
|
|
177
196
|
return span;
|
|
178
|
-
}, [
|
|
197
|
+
}, [removeMentionById, renderMention, styles.inlineTag]);
|
|
198
|
+
var renderPartsToEditor = useCallback(function (parts) {
|
|
199
|
+
var editor = editorRef.current;
|
|
200
|
+
if (!editor) return;
|
|
201
|
+
editor.querySelectorAll("[".concat(MENTION_ATTR, "]")).forEach(function (node) {
|
|
202
|
+
var _tagRootMapRef$curren2;
|
|
203
|
+
(_tagRootMapRef$curren2 = tagRootMapRef.current.get(node)) === null || _tagRootMapRef$curren2 === void 0 || _tagRootMapRef$curren2.unmount();
|
|
204
|
+
});
|
|
205
|
+
editor.innerHTML = "";
|
|
206
|
+
parts.forEach(function (part) {
|
|
207
|
+
if (part.type === "text") {
|
|
208
|
+
if (part.text) editor.appendChild(createTextNode(part.text));
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
var mention = part.type === "mention" ? part.mention : part.tag;
|
|
212
|
+
editor.append(buildMentionNode(mention), createTextNode(CARET_TEXT));
|
|
213
|
+
});
|
|
214
|
+
}, [buildMentionNode]);
|
|
179
215
|
var setCursorAtTextEnd = useCallback(function (node) {
|
|
180
216
|
var _node$textContent;
|
|
181
217
|
var range = document.createRange();
|
|
@@ -184,6 +220,17 @@ var InlineTagInput = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
184
220
|
range.collapse(true);
|
|
185
221
|
selection === null || selection === void 0 || selection.removeAllRanges();
|
|
186
222
|
selection === null || selection === void 0 || selection.addRange(range);
|
|
223
|
+
savedRangeRef.current = range.cloneRange();
|
|
224
|
+
}, []);
|
|
225
|
+
var saveSelectionRange = useCallback(function () {
|
|
226
|
+
var editor = editorRef.current;
|
|
227
|
+
var selection = window.getSelection();
|
|
228
|
+
if (!editor || !selection || selection.rangeCount === 0) return;
|
|
229
|
+
var range = selection.getRangeAt(0);
|
|
230
|
+
if (!editor.contains(range.startContainer) || !editor.contains(range.endContainer)) {
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
savedRangeRef.current = range.cloneRange();
|
|
187
234
|
}, []);
|
|
188
235
|
var restoreCursorAfterInsert = useCallback(function (node) {
|
|
189
236
|
var editor = editorRef.current;
|
|
@@ -191,52 +238,52 @@ var InlineTagInput = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
191
238
|
editor.focus();
|
|
192
239
|
setCursorAtTextEnd(node);
|
|
193
240
|
}, [setCursorAtTextEnd]);
|
|
194
|
-
var
|
|
195
|
-
return node instanceof HTMLElement && node.hasAttribute(
|
|
241
|
+
var isMentionNode = function isMentionNode(node) {
|
|
242
|
+
return node instanceof HTMLElement && node.hasAttribute(MENTION_ATTR);
|
|
196
243
|
};
|
|
197
244
|
var isOnlyCaretText = function isOnlyCaretText(text) {
|
|
198
245
|
return normalizeText(text) === "";
|
|
199
246
|
};
|
|
200
247
|
|
|
201
|
-
// Backspace/Delete
|
|
202
|
-
var
|
|
248
|
+
// Backspace/Delete 需要跨过零宽锚点识别相邻 Mention,不能只看光标所在文本节点。
|
|
249
|
+
var getMentionBeforeRange = function getMentionBeforeRange(range) {
|
|
203
250
|
var container = range.startContainer;
|
|
204
251
|
if (container.nodeType === Node.TEXT_NODE) {
|
|
205
252
|
var text = container.textContent || "";
|
|
206
253
|
var beforeCursor = text.slice(0, range.startOffset);
|
|
207
|
-
if (isOnlyCaretText(beforeCursor) &&
|
|
254
|
+
if (isOnlyCaretText(beforeCursor) && isMentionNode(container.previousSibling)) {
|
|
208
255
|
return container.previousSibling;
|
|
209
256
|
}
|
|
210
257
|
}
|
|
211
258
|
if (container instanceof HTMLElement) {
|
|
212
259
|
var previous = container.childNodes[range.startOffset - 1];
|
|
213
|
-
if (
|
|
214
|
-
if ((previous === null || previous === void 0 ? void 0 : previous.nodeType) === Node.TEXT_NODE && isOnlyCaretText(previous.textContent || "") &&
|
|
260
|
+
if (isMentionNode(previous)) return previous;
|
|
261
|
+
if ((previous === null || previous === void 0 ? void 0 : previous.nodeType) === Node.TEXT_NODE && isOnlyCaretText(previous.textContent || "") && isMentionNode(previous.previousSibling)) {
|
|
215
262
|
return previous.previousSibling;
|
|
216
263
|
}
|
|
217
264
|
}
|
|
218
265
|
return null;
|
|
219
266
|
};
|
|
220
|
-
var
|
|
267
|
+
var getMentionAfterRange = function getMentionAfterRange(range) {
|
|
221
268
|
var container = range.startContainer;
|
|
222
269
|
if (container.nodeType === Node.TEXT_NODE) {
|
|
223
270
|
var text = container.textContent || "";
|
|
224
271
|
var afterCursor = text.slice(range.startOffset);
|
|
225
|
-
if (isOnlyCaretText(afterCursor) &&
|
|
272
|
+
if (isOnlyCaretText(afterCursor) && isMentionNode(container.nextSibling)) {
|
|
226
273
|
return container.nextSibling;
|
|
227
274
|
}
|
|
228
275
|
}
|
|
229
276
|
if (container instanceof HTMLElement) {
|
|
230
277
|
var next = container.childNodes[range.startOffset];
|
|
231
|
-
if (
|
|
232
|
-
if ((next === null || next === void 0 ? void 0 : next.nodeType) === Node.TEXT_NODE && isOnlyCaretText(next.textContent || "") &&
|
|
278
|
+
if (isMentionNode(next)) return next;
|
|
279
|
+
if ((next === null || next === void 0 ? void 0 : next.nodeType) === Node.TEXT_NODE && isOnlyCaretText(next.textContent || "") && isMentionNode(next.nextSibling)) {
|
|
233
280
|
return next.nextSibling;
|
|
234
281
|
}
|
|
235
282
|
}
|
|
236
283
|
return null;
|
|
237
284
|
};
|
|
238
285
|
|
|
239
|
-
// 读取光标在纯文本中的位置,供快捷键搜索词和
|
|
286
|
+
// 读取光标在纯文本中的位置,供快捷键搜索词和 Mention 插入位置复用。
|
|
240
287
|
var getOffsetInEditor = useCallback(function () {
|
|
241
288
|
var editor = editorRef.current;
|
|
242
289
|
var selection = window.getSelection();
|
|
@@ -253,7 +300,7 @@ var InlineTagInput = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
253
300
|
found = true;
|
|
254
301
|
return;
|
|
255
302
|
}
|
|
256
|
-
if (node instanceof HTMLElement && node.hasAttribute(
|
|
303
|
+
if (node instanceof HTMLElement && node.hasAttribute(MENTION_ATTR)) return;
|
|
257
304
|
if (node.nodeType === Node.TEXT_NODE) {
|
|
258
305
|
offset += getPlainLength(node.textContent || "");
|
|
259
306
|
return;
|
|
@@ -273,8 +320,8 @@ var InlineTagInput = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
273
320
|
return index;
|
|
274
321
|
};
|
|
275
322
|
|
|
276
|
-
// 删除快捷键触发片段,例如把 “@文档” 替换成一个结构化
|
|
277
|
-
// 注意:纯文本 offset 不包含
|
|
323
|
+
// 删除快捷键触发片段,例如把 “@文档” 替换成一个结构化 Mention,并返回删除位置对应的真实 DOM Range。
|
|
324
|
+
// 注意:纯文本 offset 不包含 Mention,Mention 前后可能都是 offset 0;插入 Mention 必须依赖真实 Range,不能再反推 offset。
|
|
278
325
|
var replaceTextRange = useCallback(function (start, end) {
|
|
279
326
|
var editor = editorRef.current;
|
|
280
327
|
if (!editor) return null;
|
|
@@ -310,7 +357,7 @@ var InlineTagInput = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
310
357
|
return insertRange;
|
|
311
358
|
}, []);
|
|
312
359
|
|
|
313
|
-
// 浏览器拆分 Range 后可能留下空文本节点;清理后才能保证后续
|
|
360
|
+
// 浏览器拆分 Range 后可能留下空文本节点;清理后才能保证后续 Mention 继续 append 在队尾。
|
|
314
361
|
var cleanupCaretTextNodes = useCallback(function () {
|
|
315
362
|
var editor = editorRef.current;
|
|
316
363
|
if (!editor) return;
|
|
@@ -326,43 +373,50 @@ var InlineTagInput = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
326
373
|
}
|
|
327
374
|
});
|
|
328
375
|
}, []);
|
|
329
|
-
var
|
|
376
|
+
var insertMention = useCallback(function (mention, replace) {
|
|
330
377
|
var editor = editorRef.current;
|
|
331
378
|
if (!editor) return;
|
|
332
379
|
editor.focus();
|
|
333
|
-
|
|
334
|
-
return item.id !==
|
|
335
|
-
})), [
|
|
380
|
+
latestMentionsRef.current = [].concat(_toConsumableArray(latestMentionsRef.current.filter(function (item) {
|
|
381
|
+
return item.id !== mention.id;
|
|
382
|
+
})), [mention]);
|
|
336
383
|
var insertRange = null;
|
|
337
384
|
if (replace) {
|
|
338
385
|
insertRange = replaceTextRange(replace.start, replace.end);
|
|
339
386
|
cleanupCaretTextNodes();
|
|
340
387
|
}
|
|
341
|
-
var
|
|
388
|
+
var mentionNode = buildMentionNode(mention);
|
|
342
389
|
var caretNode = createTextNode(CARET_TEXT);
|
|
343
390
|
var selection = window.getSelection();
|
|
344
|
-
var
|
|
391
|
+
var savedRange = savedRangeRef.current;
|
|
392
|
+
var range = insertRange || (selection !== null && selection !== void 0 && selection.rangeCount && editor.contains(selection.getRangeAt(0).startContainer) ? selection.getRangeAt(0) : savedRange && editor.contains(savedRange.startContainer) ? savedRange : null);
|
|
345
393
|
if (range && editor.contains(range.startContainer)) {
|
|
346
|
-
// 用 DocumentFragment 一次性插入,避免连续 insertNode 导致
|
|
394
|
+
// 用 DocumentFragment 一次性插入,避免连续 insertNode 导致 mention/caret 顺序被浏览器 Range 状态打乱。
|
|
347
395
|
var fragment = document.createDocumentFragment();
|
|
348
|
-
fragment.append(
|
|
396
|
+
fragment.append(mentionNode, caretNode);
|
|
349
397
|
range.insertNode(fragment);
|
|
350
398
|
} else {
|
|
351
|
-
editor.append(
|
|
399
|
+
editor.append(mentionNode, caretNode);
|
|
352
400
|
}
|
|
353
401
|
cleanupCaretTextNodes();
|
|
354
402
|
lastInsertedCaretRef.current = caretNode;
|
|
355
403
|
setCursorAtTextEnd(caretNode);
|
|
356
404
|
emitChange();
|
|
357
405
|
|
|
358
|
-
// 关闭快捷列表和父组件同步
|
|
359
|
-
// 下一帧再恢复到刚插入
|
|
406
|
+
// 关闭快捷列表和父组件同步 mentions/value 会触发一次 React 更新;
|
|
407
|
+
// 下一帧再恢复到刚插入 Mention 后的零宽锚点,避免光标被 focus 或重渲染带回旧位置。
|
|
360
408
|
window.requestAnimationFrame(function () {
|
|
361
409
|
if (lastInsertedCaretRef.current === caretNode) {
|
|
362
410
|
restoreCursorAfterInsert(caretNode);
|
|
363
411
|
}
|
|
364
412
|
});
|
|
365
|
-
}, [
|
|
413
|
+
}, [buildMentionNode, cleanupCaretTextNodes, emitChange, replaceTextRange, restoreCursorAfterInsert, setCursorAtTextEnd]);
|
|
414
|
+
useEffect(function () {
|
|
415
|
+
document.addEventListener("selectionchange", saveSelectionRange);
|
|
416
|
+
return function () {
|
|
417
|
+
document.removeEventListener("selectionchange", saveSelectionRange);
|
|
418
|
+
};
|
|
419
|
+
}, [saveSelectionRange]);
|
|
366
420
|
useImperativeHandle(ref, function () {
|
|
367
421
|
return {
|
|
368
422
|
focus: function focus() {
|
|
@@ -372,51 +426,56 @@ var InlineTagInput = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
372
426
|
getText: getPlainText,
|
|
373
427
|
getParts: getParts,
|
|
374
428
|
getCursorOffset: getOffsetInEditor,
|
|
375
|
-
|
|
429
|
+
insertMention: insertMention,
|
|
430
|
+
insertTag: insertMention
|
|
376
431
|
};
|
|
377
|
-
}, [getOffsetInEditor, getParts, getPlainText,
|
|
378
|
-
|
|
379
|
-
var editor = editorRef.current;
|
|
380
|
-
if (!editor || editor.childNodes.length > 0) return;
|
|
381
|
-
if (value) editor.appendChild(createTextNode(value));
|
|
382
|
-
tags.forEach(function (tag) {
|
|
383
|
-
return editor.append(buildTagNode(tag), createTextNode(CARET_TEXT));
|
|
384
|
-
});
|
|
385
|
-
}, []);
|
|
386
|
-
|
|
387
|
-
// 外部受控 tags 变化时,同步补齐或删除 DOM 中的 tag 节点。
|
|
388
|
-
useEffect(function () {
|
|
432
|
+
}, [getOffsetInEditor, getParts, getPlainText, insertMention]);
|
|
433
|
+
useIsomorphicLayoutEffect(function () {
|
|
389
434
|
var editor = editorRef.current;
|
|
390
435
|
if (!editor) return;
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
436
|
+
|
|
437
|
+
// 默认片段只在空输入首次挂载时灌入,避免外部重新渲染覆盖用户正在编辑的内容。
|
|
438
|
+
if (!defaultInputPartsAppliedRef.current && defaultInputParts !== null && defaultInputParts !== void 0 && defaultInputParts.length && !value && mentions.length === 0) {
|
|
439
|
+
defaultInputPartsAppliedRef.current = true;
|
|
440
|
+
renderPartsToEditor(defaultInputParts);
|
|
441
|
+
emitChange();
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
var incomingMentionIds = mentions.map(function (mention) {
|
|
445
|
+
return mention.id;
|
|
446
|
+
}).join("|");
|
|
447
|
+
var lastEmittedState = lastEmittedStateRef.current;
|
|
448
|
+
var isInternalControlledEcho = value === lastEmittedState.value && incomingMentionIds === lastEmittedState.mentionIds;
|
|
449
|
+
if (isInternalControlledEcho && editor.childNodes.length > 0) return;
|
|
450
|
+
renderPartsToEditor([].concat(_toConsumableArray(value ? [{
|
|
451
|
+
type: "text",
|
|
452
|
+
text: value
|
|
453
|
+
}] : []), _toConsumableArray(mentions.map(function (mention) {
|
|
454
|
+
return {
|
|
455
|
+
type: "mention",
|
|
456
|
+
mention: mention
|
|
457
|
+
};
|
|
458
|
+
}))));
|
|
459
|
+
|
|
460
|
+
// 外部主动写入 value/mentions 后,需要在首帧绘制前同步 DOM;若输入区已有焦点,则把光标放在内容末尾。
|
|
461
|
+
var lastTextNode = Array.from(editor.childNodes).reverse().find(function (node) {
|
|
462
|
+
return node.nodeType === Node.TEXT_NODE;
|
|
407
463
|
});
|
|
408
|
-
|
|
409
|
-
|
|
464
|
+
if (document.activeElement === editor && lastTextNode) {
|
|
465
|
+
setCursorAtTextEnd(lastTextNode);
|
|
466
|
+
}
|
|
467
|
+
}, [defaultInputParts, emitChange, renderPartsToEditor, setCursorAtTextEnd, mentions, value]);
|
|
468
|
+
useIsomorphicLayoutEffect(function () {
|
|
410
469
|
var editor = editorRef.current;
|
|
411
470
|
if (!editor) return;
|
|
412
|
-
if (!value &&
|
|
413
|
-
editor.querySelectorAll("[".concat(
|
|
414
|
-
var _tagRootMapRef$
|
|
415
|
-
(_tagRootMapRef$
|
|
471
|
+
if (!value && mentions.length === 0 && editor.childNodes.length > 0) {
|
|
472
|
+
editor.querySelectorAll("[".concat(MENTION_ATTR, "]")).forEach(function (node) {
|
|
473
|
+
var _tagRootMapRef$curren3;
|
|
474
|
+
(_tagRootMapRef$curren3 = tagRootMapRef.current.get(node)) === null || _tagRootMapRef$curren3 === void 0 || _tagRootMapRef$curren3.unmount();
|
|
416
475
|
});
|
|
417
476
|
editor.innerHTML = "";
|
|
418
477
|
}
|
|
419
|
-
}, [
|
|
478
|
+
}, [mentions.length, value]);
|
|
420
479
|
var handleInput = function handleInput() {
|
|
421
480
|
if (!composingRef.current) emitChange();
|
|
422
481
|
};
|
|
@@ -426,10 +485,10 @@ var InlineTagInput = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
426
485
|
if (selection !== null && selection !== void 0 && selection.rangeCount) {
|
|
427
486
|
var range = selection.getRangeAt(0);
|
|
428
487
|
if (range.collapsed) {
|
|
429
|
-
var
|
|
430
|
-
if (
|
|
488
|
+
var targetMention = event.key === "Backspace" ? getMentionBeforeRange(range) : getMentionAfterRange(range);
|
|
489
|
+
if (targetMention) {
|
|
431
490
|
event.preventDefault();
|
|
432
|
-
|
|
491
|
+
removeMentionById(targetMention.dataset.xadkInlineMentionId || "");
|
|
433
492
|
return;
|
|
434
493
|
}
|
|
435
494
|
}
|
|
@@ -437,19 +496,29 @@ var InlineTagInput = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
437
496
|
}
|
|
438
497
|
onKeyDown === null || onKeyDown === void 0 || onKeyDown(event);
|
|
439
498
|
};
|
|
440
|
-
|
|
499
|
+
|
|
500
|
+
// placeholder 只由受控 value/mentions 派生,避免从 contenteditable DOM 读取导致外部插入 Mention 后状态滞后一帧。
|
|
501
|
+
var showPlaceholder = !value && mentions.length === 0;
|
|
502
|
+
return /*#__PURE__*/_jsxs("div", {
|
|
441
503
|
className: styles.inlineInputWrapper,
|
|
442
|
-
children: /*#__PURE__*/_jsx("div", {
|
|
504
|
+
children: [showPlaceholder && placeholder && /*#__PURE__*/_jsx("div", {
|
|
505
|
+
className: styles.inlinePlaceholder,
|
|
506
|
+
children: placeholder
|
|
507
|
+
}), /*#__PURE__*/_jsx("div", {
|
|
443
508
|
ref: editorRef,
|
|
444
509
|
className: styles.inlineInput,
|
|
445
|
-
"data-placeholder": placeholder,
|
|
446
510
|
contentEditable: !disabled,
|
|
447
511
|
suppressContentEditableWarning: true,
|
|
448
512
|
role: "textbox",
|
|
449
513
|
"aria-multiline": "true",
|
|
450
514
|
onInput: handleInput,
|
|
451
515
|
onKeyDown: handleKeyDown,
|
|
452
|
-
onKeyUp: onKeyUp
|
|
516
|
+
onKeyUp: function onKeyUp(event) {
|
|
517
|
+
saveSelectionRange();
|
|
518
|
+
_onKeyUp === null || _onKeyUp === void 0 || _onKeyUp(event);
|
|
519
|
+
},
|
|
520
|
+
onMouseUp: saveSelectionRange,
|
|
521
|
+
onFocus: saveSelectionRange,
|
|
453
522
|
onCompositionStart: function onCompositionStart() {
|
|
454
523
|
composingRef.current = true;
|
|
455
524
|
},
|
|
@@ -457,9 +526,8 @@ var InlineTagInput = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
457
526
|
composingRef.current = false;
|
|
458
527
|
emitChange();
|
|
459
528
|
},
|
|
460
|
-
"data-empty": !getPlainText() && getOrderedTags().length === 0,
|
|
461
529
|
"data-cursor-offset": getOffsetInEditor()
|
|
462
|
-
})
|
|
530
|
+
})]
|
|
463
531
|
});
|
|
464
532
|
});
|
|
465
533
|
InlineTagInput.displayName = "InlineTagInput";
|