@ai-group/chat-sdk 3.7.1-alpha1 → 3.7.1-alpha10
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/README.md +22 -0
- 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/Sources/components/CarouselCard.d.ts +12 -0
- package/dist/cjs/components/Sources/components/CarouselCard.js +130 -0
- package/dist/cjs/components/Sources/components/CarouselCard.js.map +7 -0
- package/dist/cjs/components/Sources/index.d.ts +5 -0
- package/dist/cjs/components/Sources/index.js +162 -0
- package/dist/cjs/components/Sources/index.js.map +7 -0
- package/dist/cjs/components/Sources/styles.d.ts +59 -0
- package/dist/cjs/components/Sources/styles.js +179 -0
- package/dist/cjs/components/Sources/styles.js.map +7 -0
- package/dist/cjs/components/XAdkChatbot/components/MarkdownRender/index.d.ts +19 -1
- package/dist/cjs/components/XAdkChatbot/components/MarkdownRender/index.js +232 -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 +83 -0
- package/dist/cjs/components/XAdkChatbot/components/MarkdownRender/styles.js.map +2 -2
- package/dist/cjs/components/XAdkChatbot/index.d.ts +2 -2
- package/dist/cjs/components/XAdkChatbot/index.js +75 -8
- 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/XAdkProvider/compound/DefaultLayout.d.ts +7 -2
- package/dist/cjs/components/XAdkProvider/compound/DefaultLayout.js +30 -12
- package/dist/cjs/components/XAdkProvider/compound/DefaultLayout.js.map +2 -2
- package/dist/cjs/components/XAdkProvider/compound/Sender.d.ts +3 -1
- package/dist/cjs/components/XAdkProvider/compound/Sender.js +81 -4
- package/dist/cjs/components/XAdkProvider/compound/Sender.js.map +3 -3
- package/dist/cjs/components/XAdkProvider/compound/styles.d.ts +1 -0
- package/dist/cjs/components/XAdkProvider/compound/styles.js +16 -0
- package/dist/cjs/components/XAdkProvider/compound/styles.js.map +2 -2
- package/dist/cjs/components/XAdkProvider/context/ChatSenderStateContext.d.ts +4 -0
- package/dist/cjs/components/XAdkProvider/context/ChatSenderStateContext.js.map +2 -2
- package/dist/cjs/components/XAdkProvider/context/DefaultLayoutContext.d.ts +9 -0
- package/dist/cjs/components/XAdkProvider/context/DefaultLayoutContext.js +34 -0
- package/dist/cjs/components/XAdkProvider/context/DefaultLayoutContext.js.map +7 -0
- package/dist/cjs/components/XAdkProvider/context/index.d.ts +5 -4
- package/dist/cjs/components/XAdkProvider/context/index.js +3 -1
- package/dist/cjs/components/XAdkProvider/context/index.js.map +2 -2
- package/dist/cjs/components/XAdkProvider/index.js +11 -10
- package/dist/cjs/components/XAdkProvider/index.js.map +2 -2
- package/dist/cjs/components/XAdkSender/InlineTagInput.d.ts +12 -5
- package/dist/cjs/components/XAdkSender/InlineTagInput.js +419 -121
- 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 +173 -112
- package/dist/cjs/components/XAdkSender/index.js.map +3 -3
- package/dist/cjs/components/XAdkSender/styles.d.ts +4 -0
- package/dist/cjs/components/XAdkSender/styles.js +47 -6
- package/dist/cjs/components/XAdkSender/styles.js.map +2 -2
- package/dist/cjs/components/XAiConversations/styles.js +11 -1
- package/dist/cjs/components/XAiConversations/styles.js.map +2 -2
- package/dist/cjs/hooks/useADKChat.js +5 -1
- package/dist/cjs/hooks/useADKChat.js.map +2 -2
- package/dist/cjs/index.d.ts +8 -2
- package/dist/cjs/index.js +44 -7
- package/dist/cjs/index.js.map +3 -3
- package/dist/cjs/presets/base.d.ts +6 -0
- package/dist/cjs/presets/base.js +50 -0
- package/dist/cjs/presets/base.js.map +7 -0
- package/dist/cjs/presets/define.d.ts +11 -0
- package/dist/cjs/presets/define.js +58 -0
- package/dist/cjs/presets/define.js.map +7 -0
- package/dist/cjs/presets/index.d.ts +3 -0
- package/dist/cjs/presets/index.js +28 -0
- package/dist/cjs/presets/index.js.map +7 -0
- package/dist/cjs/presets/runtime.d.ts +22 -0
- package/dist/cjs/presets/runtime.js +75 -0
- package/dist/cjs/presets/runtime.js.map +7 -0
- package/dist/cjs/presets/xgroup/index.d.ts +5 -0
- package/dist/cjs/presets/xgroup/index.js +10 -0
- package/dist/cjs/presets/xgroup/index.js.map +2 -2
- package/dist/cjs/presets/xgroup/knowledgeReference.d.ts +17 -0
- package/dist/cjs/presets/xgroup/knowledgeReference.js +162 -0
- package/dist/cjs/presets/xgroup/knowledgeReference.js.map +7 -0
- package/dist/cjs/presets/xgroup/preset.d.ts +1 -13
- package/dist/cjs/presets/xgroup/preset.js +16 -37
- package/dist/cjs/presets/xgroup/preset.js.map +2 -2
- package/dist/cjs/presets/xgroup/strategies.d.ts +5 -4
- package/dist/cjs/presets/xgroup/strategies.js +11 -15
- package/dist/cjs/presets/xgroup/strategies.js.map +3 -3
- package/dist/cjs/presets/xgroup/webReference.d.ts +10 -0
- package/dist/cjs/presets/xgroup/webReference.js +85 -0
- package/dist/cjs/presets/xgroup/webReference.js.map +7 -0
- package/dist/cjs/types/ChatStrategies.d.ts +11 -2
- package/dist/cjs/types/ChatStrategies.js.map +1 -1
- package/dist/cjs/types/FileGallery.d.ts +3 -0
- package/dist/cjs/types/FileGallery.js.map +1 -1
- package/dist/cjs/types/Sources.d.ts +30 -0
- package/dist/cjs/types/Sources.js +18 -0
- package/dist/cjs/types/Sources.js.map +7 -0
- package/dist/cjs/types/XAdkChatbot.d.ts +33 -0
- package/dist/cjs/types/XAdkChatbot.js.map +1 -1
- package/dist/cjs/types/XAdkSender.d.ts +112 -21
- package/dist/cjs/types/XAdkSender.js.map +1 -1
- package/dist/cjs/types/index.d.ts +1 -0
- package/dist/cjs/types/index.js +3 -1
- package/dist/cjs/types/index.js.map +2 -2
- 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 +14 -0
- package/dist/cjs/utils/markdownResource.js +131 -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/Sources/components/CarouselCard.d.ts +12 -0
- package/dist/esm/components/Sources/components/CarouselCard.js +107 -0
- package/dist/esm/components/Sources/components/CarouselCard.js.map +1 -0
- package/dist/esm/components/Sources/index.d.ts +5 -0
- package/dist/esm/components/Sources/index.js +127 -0
- package/dist/esm/components/Sources/index.js.map +1 -0
- package/dist/esm/components/Sources/styles.d.ts +59 -0
- package/dist/esm/components/Sources/styles.js +34 -0
- package/dist/esm/components/Sources/styles.js.map +1 -0
- package/dist/esm/components/XAdkChatbot/components/MarkdownRender/index.d.ts +19 -1
- package/dist/esm/components/XAdkChatbot/components/MarkdownRender/index.js +190 -11
- 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.d.ts +2 -2
- package/dist/esm/components/XAdkChatbot/index.js +55 -10
- 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/XAdkProvider/compound/DefaultLayout.d.ts +7 -2
- package/dist/esm/components/XAdkProvider/compound/DefaultLayout.js +40 -17
- package/dist/esm/components/XAdkProvider/compound/DefaultLayout.js.map +1 -1
- package/dist/esm/components/XAdkProvider/compound/Sender.d.ts +3 -1
- package/dist/esm/components/XAdkProvider/compound/Sender.js +70 -6
- package/dist/esm/components/XAdkProvider/compound/Sender.js.map +1 -1
- package/dist/esm/components/XAdkProvider/compound/styles.d.ts +1 -0
- package/dist/esm/components/XAdkProvider/compound/styles.js +3 -2
- package/dist/esm/components/XAdkProvider/compound/styles.js.map +1 -1
- package/dist/esm/components/XAdkProvider/context/ChatSenderStateContext.d.ts +4 -0
- package/dist/esm/components/XAdkProvider/context/ChatSenderStateContext.js.map +1 -1
- package/dist/esm/components/XAdkProvider/context/DefaultLayoutContext.d.ts +9 -0
- package/dist/esm/components/XAdkProvider/context/DefaultLayoutContext.js +9 -0
- package/dist/esm/components/XAdkProvider/context/DefaultLayoutContext.js.map +1 -0
- package/dist/esm/components/XAdkProvider/context/index.d.ts +5 -4
- package/dist/esm/components/XAdkProvider/context/index.js +1 -0
- package/dist/esm/components/XAdkProvider/context/index.js.map +1 -1
- package/dist/esm/components/XAdkProvider/index.js +7 -3
- package/dist/esm/components/XAdkProvider/index.js.map +1 -1
- package/dist/esm/components/XAdkSender/InlineTagInput.d.ts +12 -5
- package/dist/esm/components/XAdkSender/InlineTagInput.js +408 -111
- 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 +10 -9
- package/dist/esm/components/XAdkSender/InputTags.js.map +1 -1
- package/dist/esm/components/XAdkSender/index.js +206 -122
- 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/components/XAiConversations/styles.js +3 -3
- package/dist/esm/components/XAiConversations/styles.js.map +1 -1
- package/dist/esm/hooks/useADKChat.js +8 -2
- package/dist/esm/hooks/useADKChat.js.map +1 -1
- package/dist/esm/index.d.ts +8 -2
- package/dist/esm/index.js +7 -3
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/presets/base.d.ts +6 -0
- package/dist/esm/presets/base.js +28 -0
- package/dist/esm/presets/base.js.map +1 -0
- package/dist/esm/presets/define.d.ts +11 -0
- package/dist/esm/presets/define.js +33 -0
- package/dist/esm/presets/define.js.map +1 -0
- package/dist/esm/presets/index.d.ts +3 -0
- package/dist/esm/presets/index.js +4 -0
- package/dist/esm/presets/index.js.map +1 -0
- package/dist/esm/presets/runtime.d.ts +22 -0
- package/dist/esm/presets/runtime.js +45 -0
- package/dist/esm/presets/runtime.js.map +1 -0
- package/dist/esm/presets/xgroup/index.d.ts +5 -0
- package/dist/esm/presets/xgroup/index.js +6 -0
- package/dist/esm/presets/xgroup/index.js.map +1 -1
- package/dist/esm/presets/xgroup/knowledgeReference.d.ts +17 -0
- package/dist/esm/presets/xgroup/knowledgeReference.js +95 -0
- package/dist/esm/presets/xgroup/knowledgeReference.js.map +1 -0
- package/dist/esm/presets/xgroup/preset.d.ts +1 -13
- package/dist/esm/presets/xgroup/preset.js +9 -29
- package/dist/esm/presets/xgroup/preset.js.map +1 -1
- package/dist/esm/presets/xgroup/strategies.d.ts +5 -4
- package/dist/esm/presets/xgroup/strategies.js +8 -20
- package/dist/esm/presets/xgroup/strategies.js.map +1 -1
- package/dist/esm/presets/xgroup/webReference.d.ts +10 -0
- package/dist/esm/presets/xgroup/webReference.js +46 -0
- package/dist/esm/presets/xgroup/webReference.js.map +1 -0
- package/dist/esm/types/ChatStrategies.d.ts +11 -2
- package/dist/esm/types/ChatStrategies.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/Sources.d.ts +30 -0
- package/dist/esm/types/Sources.js +2 -0
- package/dist/esm/types/Sources.js.map +1 -0
- package/dist/esm/types/XAdkChatbot.d.ts +33 -0
- package/dist/esm/types/XAdkChatbot.js.map +1 -1
- package/dist/esm/types/XAdkSender.d.ts +112 -21
- package/dist/esm/types/XAdkSender.js.map +1 -1
- package/dist/esm/types/index.d.ts +1 -0
- package/dist/esm/types/index.js +1 -0
- package/dist/esm/types/index.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 +14 -0
- package/dist/esm/utils/markdownResource.js +101 -0
- package/dist/esm/utils/markdownResource.js.map +1 -0
- package/dist/umd/chat-sdk.min.js +1 -1
- package/package.json +6 -1
|
@@ -1,15 +1,20 @@
|
|
|
1
|
+
import _createForOfIteratorHelper from "@babel/runtime/helpers/esm/createForOfIteratorHelper";
|
|
1
2
|
import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
|
|
2
|
-
import
|
|
3
|
+
import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
|
|
4
|
+
import React, { forwardRef, useCallback, useEffect, useLayoutEffect, useImperativeHandle, useRef, useState } from "react";
|
|
3
5
|
import { createRoot } from "react-dom/client";
|
|
4
6
|
import { useStyles } from "./styles";
|
|
7
|
+
import { parseMarkdownResourceLinksAsParts } from "../../utils/markdownResource";
|
|
5
8
|
import { Fragment as _Fragment } from "react/jsx-runtime";
|
|
6
9
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
7
|
-
|
|
8
|
-
|
|
10
|
+
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
11
|
+
var MENTION_ATTR = "data-xadk-inline-mention-id";
|
|
12
|
+
// contenteditable 无法把光标放进 contenteditable=false 的 Mention 里,需用零宽字符承接“Mention 后方”的光标。
|
|
9
13
|
var CARET_TEXT = "\u200B";
|
|
10
14
|
var createTextNode = function createTextNode(text) {
|
|
11
15
|
return document.createTextNode(text);
|
|
12
16
|
};
|
|
17
|
+
var useIsomorphicLayoutEffect = typeof window === "undefined" ? useEffect : useLayoutEffect;
|
|
13
18
|
var normalizeText = function normalizeText(text) {
|
|
14
19
|
return text.replace(/\u200B/g, "").replace(/\u00a0/g, " ");
|
|
15
20
|
};
|
|
@@ -25,33 +30,52 @@ var toRawOffset = function toRawOffset(text, plainOffset) {
|
|
|
25
30
|
}
|
|
26
31
|
return text.length;
|
|
27
32
|
};
|
|
33
|
+
|
|
34
|
+
// 内联标签展示逻辑
|
|
28
35
|
var InlineTagInput = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
29
36
|
var value = _ref.value,
|
|
30
|
-
|
|
37
|
+
mentions = _ref.mentions,
|
|
38
|
+
defaultInputParts = _ref.defaultInputParts,
|
|
31
39
|
placeholder = _ref.placeholder,
|
|
32
40
|
disabled = _ref.disabled,
|
|
33
41
|
onChange = _ref.onChange,
|
|
34
|
-
|
|
42
|
+
onMentionsChange = _ref.onMentionsChange,
|
|
35
43
|
onKeyDown = _ref.onKeyDown,
|
|
36
|
-
|
|
37
|
-
|
|
44
|
+
_onKeyUp = _ref.onKeyUp,
|
|
45
|
+
renderMention = _ref.renderMention;
|
|
38
46
|
var styles = useStyles();
|
|
39
47
|
var editorRef = useRef(null);
|
|
40
|
-
var
|
|
48
|
+
var latestMentionsRef = useRef(mentions);
|
|
41
49
|
var tagRootMapRef = useRef(new WeakMap());
|
|
42
50
|
var composingRef = useRef(false);
|
|
43
51
|
var lastInsertedCaretRef = useRef(null);
|
|
52
|
+
var savedRangeRef = useRef(null);
|
|
53
|
+
var defaultInputPartsAppliedRef = useRef(false);
|
|
54
|
+
var skipEmptyCleanupOnceRef = useRef(false);
|
|
55
|
+
var structuralCleanupFrameRef = useRef(null);
|
|
56
|
+
var _useState = useState(function () {
|
|
57
|
+
return Boolean(value || mentions.length);
|
|
58
|
+
}),
|
|
59
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
60
|
+
hasContent = _useState2[0],
|
|
61
|
+
setHasContent = _useState2[1];
|
|
62
|
+
var lastEmittedStateRef = useRef({
|
|
63
|
+
value: value,
|
|
64
|
+
mentionIds: mentions.map(function (mention) {
|
|
65
|
+
return mention.id;
|
|
66
|
+
}).join("|")
|
|
67
|
+
});
|
|
44
68
|
useEffect(function () {
|
|
45
|
-
|
|
46
|
-
}, [
|
|
47
|
-
var
|
|
69
|
+
latestMentionsRef.current = mentions;
|
|
70
|
+
}, [mentions]);
|
|
71
|
+
var getOrderedMentions = useCallback(function () {
|
|
48
72
|
var editor = editorRef.current;
|
|
49
73
|
if (!editor) return [];
|
|
50
|
-
var
|
|
51
|
-
return [
|
|
74
|
+
var mentionMap = new Map(latestMentionsRef.current.map(function (mention) {
|
|
75
|
+
return [mention.id, mention];
|
|
52
76
|
}));
|
|
53
|
-
return Array.from(editor.querySelectorAll("[".concat(
|
|
54
|
-
return
|
|
77
|
+
return Array.from(editor.querySelectorAll("[".concat(MENTION_ATTR, "]"))).map(function (node) {
|
|
78
|
+
return mentionMap.get(node.dataset.xadkInlineMentionId || "");
|
|
55
79
|
}).filter(Boolean);
|
|
56
80
|
}, []);
|
|
57
81
|
|
|
@@ -67,23 +91,61 @@ var InlineTagInput = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
67
91
|
});
|
|
68
92
|
return normalizeText(text);
|
|
69
93
|
}, []);
|
|
94
|
+
|
|
95
|
+
// 提交时需要保留文本与 Mention 的真实顺序;仅靠 value + mentions 无法区分 Mention 在句首、句中还是句尾。
|
|
96
|
+
var getParts = useCallback(function () {
|
|
97
|
+
var editor = editorRef.current;
|
|
98
|
+
if (!editor) return [];
|
|
99
|
+
var mentionMap = new Map(latestMentionsRef.current.map(function (mention) {
|
|
100
|
+
return [mention.id, mention];
|
|
101
|
+
}));
|
|
102
|
+
var parts = [];
|
|
103
|
+
editor.childNodes.forEach(function (node) {
|
|
104
|
+
if (node.nodeType === Node.TEXT_NODE) {
|
|
105
|
+
var text = normalizeText(node.textContent || "");
|
|
106
|
+
if (text) parts.push({
|
|
107
|
+
type: "text",
|
|
108
|
+
text: text
|
|
109
|
+
});
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
if (node instanceof HTMLElement && node.hasAttribute(MENTION_ATTR)) {
|
|
113
|
+
var mentionId = node.dataset.xadkInlineMentionId || "";
|
|
114
|
+
var _mention = mentionMap.get(mentionId);
|
|
115
|
+
if (_mention) parts.push({
|
|
116
|
+
type: "mention",
|
|
117
|
+
mention: _mention
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
return parts;
|
|
122
|
+
}, []);
|
|
70
123
|
var emitChange = useCallback(function () {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
124
|
+
var nextValue = getPlainText();
|
|
125
|
+
var nextMentions = getOrderedMentions();
|
|
126
|
+
setHasContent(Boolean(nextValue || nextMentions.length));
|
|
127
|
+
lastEmittedStateRef.current = {
|
|
128
|
+
value: nextValue,
|
|
129
|
+
mentionIds: nextMentions.map(function (mention) {
|
|
130
|
+
return mention.id;
|
|
131
|
+
}).join("|")
|
|
132
|
+
};
|
|
133
|
+
onChange(nextValue);
|
|
134
|
+
onMentionsChange(nextMentions);
|
|
135
|
+
}, [getOrderedMentions, getPlainText, onChange, onMentionsChange]);
|
|
74
136
|
var removeTextRange = useCallback(function (node, start, end) {
|
|
75
137
|
var text = node.textContent || "";
|
|
76
138
|
node.textContent = "".concat(text.slice(0, start)).concat(text.slice(end));
|
|
77
139
|
if (!node.textContent) node.remove();
|
|
78
140
|
}, []);
|
|
79
|
-
var
|
|
141
|
+
var removeMentionNode = useCallback(function (node) {
|
|
80
142
|
var _tagRootMapRef$curren;
|
|
81
143
|
var previous = node.previousSibling;
|
|
82
144
|
var next = node.nextSibling;
|
|
83
145
|
(_tagRootMapRef$curren = tagRootMapRef.current.get(node)) === null || _tagRootMapRef$curren === void 0 || _tagRootMapRef$curren.unmount();
|
|
84
146
|
node.remove();
|
|
85
147
|
|
|
86
|
-
//
|
|
148
|
+
// Mention 后会补一个不可见光标锚点;删除 Mention 时同步清理,避免留下冗余节点。
|
|
87
149
|
if ((next === null || next === void 0 ? void 0 : next.nodeType) === Node.TEXT_NODE) {
|
|
88
150
|
var _text$match;
|
|
89
151
|
var text = next.textContent || "";
|
|
@@ -102,51 +164,69 @@ var InlineTagInput = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
102
164
|
}
|
|
103
165
|
}
|
|
104
166
|
}, [removeTextRange]);
|
|
105
|
-
var
|
|
167
|
+
var removeMentionById = useCallback(function (id) {
|
|
106
168
|
var editor = editorRef.current;
|
|
107
|
-
var node = Array.from((editor === null || editor === void 0 ? void 0 : editor.querySelectorAll("[".concat(
|
|
108
|
-
return item.dataset.
|
|
169
|
+
var node = Array.from((editor === null || editor === void 0 ? void 0 : editor.querySelectorAll("[".concat(MENTION_ATTR, "]"))) || []).find(function (item) {
|
|
170
|
+
return item.dataset.xadkInlineMentionId === id;
|
|
109
171
|
});
|
|
110
172
|
if (node) {
|
|
111
|
-
|
|
173
|
+
removeMentionNode(node);
|
|
112
174
|
}
|
|
113
175
|
emitChange();
|
|
114
176
|
editor === null || editor === void 0 || editor.focus();
|
|
115
|
-
}, [emitChange,
|
|
177
|
+
}, [emitChange, removeMentionNode]);
|
|
116
178
|
|
|
117
|
-
//
|
|
118
|
-
var
|
|
179
|
+
// Mention 节点本身不可编辑;删除入口通过 onRemove 回到组件内部统一维护 DOM 与 mentions。
|
|
180
|
+
var buildMentionNode = useCallback(function (mention) {
|
|
119
181
|
var span = document.createElement("span");
|
|
120
182
|
span.setAttribute("contenteditable", "false");
|
|
121
|
-
span.setAttribute(
|
|
122
|
-
span.dataset.
|
|
183
|
+
span.setAttribute(MENTION_ATTR, mention.id);
|
|
184
|
+
span.dataset.xadkInlineMentionId = mention.id;
|
|
185
|
+
span.dataset.xadkInlineMentionType = mention.type;
|
|
123
186
|
span.className = styles.inlineTag;
|
|
124
|
-
if (
|
|
187
|
+
if (renderMention) {
|
|
125
188
|
var root = createRoot(span);
|
|
126
189
|
tagRootMapRef.current.set(span, root);
|
|
127
190
|
root.render( /*#__PURE__*/_jsx(_Fragment, {
|
|
128
|
-
children:
|
|
191
|
+
children: renderMention(mention, {
|
|
129
192
|
onRemove: function onRemove() {
|
|
130
|
-
return
|
|
193
|
+
return removeMentionById(mention.id);
|
|
131
194
|
}
|
|
132
195
|
})
|
|
133
196
|
}));
|
|
134
197
|
} else {
|
|
135
198
|
var label = document.createElement("span");
|
|
136
199
|
label.className = "xadk-inline-tag-label";
|
|
137
|
-
label.textContent =
|
|
200
|
+
label.textContent = mention.displayName || mention.label;
|
|
138
201
|
var close = document.createElement("span");
|
|
139
202
|
close.className = "xadk-inline-tag-close";
|
|
140
203
|
close.innerHTML = "×";
|
|
141
204
|
close.onclick = function (event) {
|
|
142
205
|
event.preventDefault();
|
|
143
206
|
event.stopPropagation();
|
|
144
|
-
|
|
207
|
+
removeMentionById(mention.id);
|
|
145
208
|
};
|
|
146
209
|
span.append(label, close);
|
|
147
210
|
}
|
|
148
211
|
return span;
|
|
149
|
-
}, [
|
|
212
|
+
}, [removeMentionById, renderMention, styles.inlineTag]);
|
|
213
|
+
var renderPartsToEditor = useCallback(function (parts) {
|
|
214
|
+
var editor = editorRef.current;
|
|
215
|
+
if (!editor) return;
|
|
216
|
+
editor.querySelectorAll("[".concat(MENTION_ATTR, "]")).forEach(function (node) {
|
|
217
|
+
var _tagRootMapRef$curren2;
|
|
218
|
+
(_tagRootMapRef$curren2 = tagRootMapRef.current.get(node)) === null || _tagRootMapRef$curren2 === void 0 || _tagRootMapRef$curren2.unmount();
|
|
219
|
+
});
|
|
220
|
+
editor.innerHTML = "";
|
|
221
|
+
parts.forEach(function (part) {
|
|
222
|
+
if (part.type === "text") {
|
|
223
|
+
if (part.text) editor.appendChild(createTextNode(part.text));
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
var mention = part.type === "mention" ? part.mention : part.tag;
|
|
227
|
+
editor.append(buildMentionNode(mention), createTextNode(CARET_TEXT));
|
|
228
|
+
});
|
|
229
|
+
}, [buildMentionNode]);
|
|
150
230
|
var setCursorAtTextEnd = useCallback(function (node) {
|
|
151
231
|
var _node$textContent;
|
|
152
232
|
var range = document.createRange();
|
|
@@ -155,6 +235,17 @@ var InlineTagInput = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
155
235
|
range.collapse(true);
|
|
156
236
|
selection === null || selection === void 0 || selection.removeAllRanges();
|
|
157
237
|
selection === null || selection === void 0 || selection.addRange(range);
|
|
238
|
+
savedRangeRef.current = range.cloneRange();
|
|
239
|
+
}, []);
|
|
240
|
+
var saveSelectionRange = useCallback(function () {
|
|
241
|
+
var editor = editorRef.current;
|
|
242
|
+
var selection = window.getSelection();
|
|
243
|
+
if (!editor || !selection || selection.rangeCount === 0) return;
|
|
244
|
+
var range = selection.getRangeAt(0);
|
|
245
|
+
if (!editor.contains(range.startContainer) || !editor.contains(range.endContainer)) {
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
savedRangeRef.current = range.cloneRange();
|
|
158
249
|
}, []);
|
|
159
250
|
var restoreCursorAfterInsert = useCallback(function (node) {
|
|
160
251
|
var editor = editorRef.current;
|
|
@@ -162,52 +253,80 @@ var InlineTagInput = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
162
253
|
editor.focus();
|
|
163
254
|
setCursorAtTextEnd(node);
|
|
164
255
|
}, [setCursorAtTextEnd]);
|
|
165
|
-
var
|
|
166
|
-
return node instanceof HTMLElement && node.hasAttribute(
|
|
256
|
+
var isMentionNode = function isMentionNode(node) {
|
|
257
|
+
return node instanceof HTMLElement && node.hasAttribute(MENTION_ATTR);
|
|
167
258
|
};
|
|
168
259
|
var isOnlyCaretText = function isOnlyCaretText(text) {
|
|
169
260
|
return normalizeText(text) === "";
|
|
170
261
|
};
|
|
171
262
|
|
|
172
|
-
// Backspace/Delete
|
|
173
|
-
var
|
|
263
|
+
// Backspace/Delete 需要跨过零宽锚点识别相邻 Mention,不能只看光标所在文本节点。
|
|
264
|
+
var getMentionBeforeRange = function getMentionBeforeRange(range) {
|
|
174
265
|
var container = range.startContainer;
|
|
175
266
|
if (container.nodeType === Node.TEXT_NODE) {
|
|
176
267
|
var text = container.textContent || "";
|
|
177
268
|
var beforeCursor = text.slice(0, range.startOffset);
|
|
178
|
-
if (isOnlyCaretText(beforeCursor) &&
|
|
269
|
+
if (isOnlyCaretText(beforeCursor) && isMentionNode(container.previousSibling)) {
|
|
179
270
|
return container.previousSibling;
|
|
180
271
|
}
|
|
181
272
|
}
|
|
182
273
|
if (container instanceof HTMLElement) {
|
|
183
274
|
var previous = container.childNodes[range.startOffset - 1];
|
|
184
|
-
if (
|
|
185
|
-
if ((previous === null || previous === void 0 ? void 0 : previous.nodeType) === Node.TEXT_NODE && isOnlyCaretText(previous.textContent || "") &&
|
|
275
|
+
if (isMentionNode(previous)) return previous;
|
|
276
|
+
if ((previous === null || previous === void 0 ? void 0 : previous.nodeType) === Node.TEXT_NODE && isOnlyCaretText(previous.textContent || "") && isMentionNode(previous.previousSibling)) {
|
|
186
277
|
return previous.previousSibling;
|
|
187
278
|
}
|
|
188
279
|
}
|
|
189
280
|
return null;
|
|
190
281
|
};
|
|
191
|
-
var
|
|
282
|
+
var getMentionAfterRange = function getMentionAfterRange(range) {
|
|
192
283
|
var container = range.startContainer;
|
|
193
284
|
if (container.nodeType === Node.TEXT_NODE) {
|
|
194
285
|
var text = container.textContent || "";
|
|
195
286
|
var afterCursor = text.slice(range.startOffset);
|
|
196
|
-
if (isOnlyCaretText(afterCursor) &&
|
|
287
|
+
if (isOnlyCaretText(afterCursor) && isMentionNode(container.nextSibling)) {
|
|
197
288
|
return container.nextSibling;
|
|
198
289
|
}
|
|
199
290
|
}
|
|
200
291
|
if (container instanceof HTMLElement) {
|
|
201
292
|
var next = container.childNodes[range.startOffset];
|
|
202
|
-
if (
|
|
203
|
-
if ((next === null || next === void 0 ? void 0 : next.nodeType) === Node.TEXT_NODE && isOnlyCaretText(next.textContent || "") &&
|
|
293
|
+
if (isMentionNode(next)) return next;
|
|
294
|
+
if ((next === null || next === void 0 ? void 0 : next.nodeType) === Node.TEXT_NODE && isOnlyCaretText(next.textContent || "") && isMentionNode(next.nextSibling)) {
|
|
204
295
|
return next.nextSibling;
|
|
205
296
|
}
|
|
206
297
|
}
|
|
207
298
|
return null;
|
|
208
299
|
};
|
|
300
|
+
var moveCursorAroundMention = useCallback(function (mention, direction) {
|
|
301
|
+
var editor = editorRef.current;
|
|
302
|
+
var selection = window.getSelection();
|
|
303
|
+
if (!editor || !selection || !editor.contains(mention)) return;
|
|
304
|
+
var range = document.createRange();
|
|
305
|
+
if (direction === "before") {
|
|
306
|
+
var previous = mention.previousSibling;
|
|
307
|
+
if ((previous === null || previous === void 0 ? void 0 : previous.nodeType) === Node.TEXT_NODE) {
|
|
308
|
+
var _previous$textContent;
|
|
309
|
+
range.setStart(previous, ((_previous$textContent = previous.textContent) === null || _previous$textContent === void 0 ? void 0 : _previous$textContent.length) || 0);
|
|
310
|
+
} else {
|
|
311
|
+
range.setStartBefore(mention);
|
|
312
|
+
}
|
|
313
|
+
} else {
|
|
314
|
+
var next = mention.nextSibling;
|
|
315
|
+
if ((next === null || next === void 0 ? void 0 : next.nodeType) === Node.TEXT_NODE) {
|
|
316
|
+
var _match;
|
|
317
|
+
var leadingCaretLength = ((_match = (next.textContent || "").match(/^\u200B+/)) === null || _match === void 0 ? void 0 : _match[0].length) || 0;
|
|
318
|
+
range.setStart(next, leadingCaretLength);
|
|
319
|
+
} else {
|
|
320
|
+
range.setStartAfter(mention);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
range.collapse(true);
|
|
324
|
+
selection.removeAllRanges();
|
|
325
|
+
selection.addRange(range);
|
|
326
|
+
savedRangeRef.current = range.cloneRange();
|
|
327
|
+
}, []);
|
|
209
328
|
|
|
210
|
-
// 读取光标在纯文本中的位置,供快捷键搜索词和
|
|
329
|
+
// 读取光标在纯文本中的位置,供快捷键搜索词和 Mention 插入位置复用。
|
|
211
330
|
var getOffsetInEditor = useCallback(function () {
|
|
212
331
|
var editor = editorRef.current;
|
|
213
332
|
var selection = window.getSelection();
|
|
@@ -224,7 +343,7 @@ var InlineTagInput = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
224
343
|
found = true;
|
|
225
344
|
return;
|
|
226
345
|
}
|
|
227
|
-
if (node instanceof HTMLElement && node.hasAttribute(
|
|
346
|
+
if (node instanceof HTMLElement && node.hasAttribute(MENTION_ATTR)) return;
|
|
228
347
|
if (node.nodeType === Node.TEXT_NODE) {
|
|
229
348
|
offset += getPlainLength(node.textContent || "");
|
|
230
349
|
return;
|
|
@@ -244,8 +363,8 @@ var InlineTagInput = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
244
363
|
return index;
|
|
245
364
|
};
|
|
246
365
|
|
|
247
|
-
// 删除快捷键触发片段,例如把 “@文档” 替换成一个结构化
|
|
248
|
-
// 注意:纯文本 offset 不包含
|
|
366
|
+
// 删除快捷键触发片段,例如把 “@文档” 替换成一个结构化 Mention,并返回删除位置对应的真实 DOM Range。
|
|
367
|
+
// 注意:纯文本 offset 不包含 Mention,Mention 前后可能都是 offset 0;插入 Mention 必须依赖真实 Range,不能再反推 offset。
|
|
249
368
|
var replaceTextRange = useCallback(function (start, end) {
|
|
250
369
|
var editor = editorRef.current;
|
|
251
370
|
if (!editor) return null;
|
|
@@ -281,7 +400,7 @@ var InlineTagInput = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
281
400
|
return insertRange;
|
|
282
401
|
}, []);
|
|
283
402
|
|
|
284
|
-
// 浏览器拆分 Range 后可能留下空文本节点;清理后才能保证后续
|
|
403
|
+
// 浏览器拆分 Range 后可能留下空文本节点;清理后才能保证后续 Mention 继续 append 在队尾。
|
|
285
404
|
var cleanupCaretTextNodes = useCallback(function () {
|
|
286
405
|
var editor = editorRef.current;
|
|
287
406
|
if (!editor) return;
|
|
@@ -297,43 +416,122 @@ var InlineTagInput = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
297
416
|
}
|
|
298
417
|
});
|
|
299
418
|
}, []);
|
|
300
|
-
|
|
419
|
+
|
|
420
|
+
// Chrome 会把标签前临时输入的文字包进块级节点;文字被删空后,可能留下
|
|
421
|
+
// <div><br></div>。它没有消息语义,却会在 contenteditable 中占据一整行。
|
|
422
|
+
var cleanupEmptyStructuralNodes = useCallback(function () {
|
|
423
|
+
var editor = editorRef.current;
|
|
424
|
+
var selection = window.getSelection();
|
|
425
|
+
if (!editor) return;
|
|
426
|
+
Array.from(editor.children).forEach(function (node) {
|
|
427
|
+
if (node.hasAttribute(MENTION_ATTR)) return;
|
|
428
|
+
if (node.querySelector("[".concat(MENTION_ATTR, "]"))) return;
|
|
429
|
+
if (normalizeText(node.textContent || "")) return;
|
|
430
|
+
var range = selection !== null && selection !== void 0 && selection.rangeCount ? selection.getRangeAt(0) : null;
|
|
431
|
+
var nodeIndex = getNodeIndex(node);
|
|
432
|
+
var containsCursor = Boolean(range && range.collapsed && (range.startContainer === node || node.contains(range.startContainer) || range.startContainer === editor && (range.startOffset === nodeIndex || range.startOffset === nodeIndex + 1)));
|
|
433
|
+
if (containsCursor && selection) {
|
|
434
|
+
// 光标紧邻 contenteditable=false 的 Mention 时,单纯删除 <br> 会让 Chrome
|
|
435
|
+
// 再次生成它。替换成零宽文本锚点,既能承接光标,也不会增加行高。
|
|
436
|
+
var caretNode = createTextNode(CARET_TEXT);
|
|
437
|
+
node.replaceWith(caretNode);
|
|
438
|
+
var nextRange = document.createRange();
|
|
439
|
+
nextRange.setStart(caretNode, CARET_TEXT.length);
|
|
440
|
+
nextRange.collapse(true);
|
|
441
|
+
selection.removeAllRanges();
|
|
442
|
+
selection.addRange(nextRange);
|
|
443
|
+
savedRangeRef.current = nextRange.cloneRange();
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
node.remove();
|
|
447
|
+
});
|
|
448
|
+
}, []);
|
|
449
|
+
useEffect(function () {
|
|
301
450
|
var editor = editorRef.current;
|
|
302
451
|
if (!editor) return;
|
|
452
|
+
|
|
453
|
+
// 某些业务容器会截断 React 委托事件;直接监听编辑器的原生 input,确保删除事务结束后
|
|
454
|
+
// 仍能清理 Chrome 在不可编辑 Mention 前生成的占行 <br>。仅处理 delete*,不影响 Enter 换行。
|
|
455
|
+
var handleNativeDelete = function handleNativeDelete(event) {
|
|
456
|
+
if (!(event instanceof InputEvent)) return;
|
|
457
|
+
if (!event.inputType.startsWith("delete")) return;
|
|
458
|
+
if (structuralCleanupFrameRef.current !== null) {
|
|
459
|
+
window.cancelAnimationFrame(structuralCleanupFrameRef.current);
|
|
460
|
+
}
|
|
461
|
+
structuralCleanupFrameRef.current = window.requestAnimationFrame(function () {
|
|
462
|
+
structuralCleanupFrameRef.current = null;
|
|
463
|
+
cleanupEmptyStructuralNodes();
|
|
464
|
+
cleanupCaretTextNodes();
|
|
465
|
+
});
|
|
466
|
+
};
|
|
467
|
+
editor.addEventListener("input", handleNativeDelete);
|
|
468
|
+
return function () {
|
|
469
|
+
return editor.removeEventListener("input", handleNativeDelete);
|
|
470
|
+
};
|
|
471
|
+
}, [cleanupCaretTextNodes, cleanupEmptyStructuralNodes]);
|
|
472
|
+
var insertMention = useCallback(function (mention, replace) {
|
|
473
|
+
var editor = editorRef.current;
|
|
474
|
+
if (!editor) return;
|
|
475
|
+
// 工具栏/弹窗会先抢走焦点;必须在 focus 之前保存当前 Selection,
|
|
476
|
+
// 否则浏览器新建在输入框开头的 Range 会覆盖最后一次真实光标位置。
|
|
477
|
+
var selectionBeforeFocus = window.getSelection();
|
|
478
|
+
var activeRangeBeforeFocus = selectionBeforeFocus !== null && selectionBeforeFocus !== void 0 && selectionBeforeFocus.rangeCount && editor.contains(selectionBeforeFocus.getRangeAt(0).startContainer) ? selectionBeforeFocus.getRangeAt(0).cloneRange() : null;
|
|
479
|
+
var savedRangeBeforeFocus = savedRangeRef.current && editor.contains(savedRangeRef.current.startContainer) ? savedRangeRef.current.cloneRange() : null;
|
|
480
|
+
var rangeBeforeFocus = activeRangeBeforeFocus || savedRangeBeforeFocus;
|
|
303
481
|
editor.focus();
|
|
304
|
-
|
|
305
|
-
return item.id !==
|
|
306
|
-
})), [
|
|
482
|
+
latestMentionsRef.current = [].concat(_toConsumableArray(latestMentionsRef.current.filter(function (item) {
|
|
483
|
+
return item.id !== mention.id;
|
|
484
|
+
})), [mention]);
|
|
307
485
|
var insertRange = null;
|
|
308
486
|
if (replace) {
|
|
309
487
|
insertRange = replaceTextRange(replace.start, replace.end);
|
|
310
488
|
cleanupCaretTextNodes();
|
|
311
489
|
}
|
|
312
|
-
|
|
490
|
+
// 浏览器会在空 contenteditable 中生成 <div><br> 等占位块。
|
|
491
|
+
// 空编辑器插入首个 Mention 前先清掉这些无语义节点,避免标签被放进第二个视觉行。
|
|
492
|
+
var isSemanticallyEmpty = !getPlainText() && !editor.querySelector("[".concat(MENTION_ATTR, "]"));
|
|
493
|
+
if (isSemanticallyEmpty) {
|
|
494
|
+
editor.innerHTML = "";
|
|
495
|
+
savedRangeRef.current = null;
|
|
496
|
+
insertRange = null;
|
|
497
|
+
}
|
|
498
|
+
var mentionNode = buildMentionNode(mention);
|
|
313
499
|
var caretNode = createTextNode(CARET_TEXT);
|
|
314
|
-
var
|
|
315
|
-
var range = insertRange || (selection !== null && selection !== void 0 && selection.rangeCount ? selection.getRangeAt(0) : null);
|
|
500
|
+
var range = insertRange || rangeBeforeFocus;
|
|
316
501
|
if (range && editor.contains(range.startContainer)) {
|
|
317
|
-
// 用 DocumentFragment 一次性插入,避免连续 insertNode 导致
|
|
502
|
+
// 用 DocumentFragment 一次性插入,避免连续 insertNode 导致 mention/caret 顺序被浏览器 Range 状态打乱。
|
|
318
503
|
var fragment = document.createDocumentFragment();
|
|
319
|
-
fragment.append(
|
|
504
|
+
fragment.append(mentionNode, caretNode);
|
|
320
505
|
range.insertNode(fragment);
|
|
321
506
|
} else {
|
|
322
|
-
editor.append(
|
|
507
|
+
editor.append(mentionNode, caretNode);
|
|
323
508
|
}
|
|
324
509
|
cleanupCaretTextNodes();
|
|
325
510
|
lastInsertedCaretRef.current = caretNode;
|
|
326
511
|
setCursorAtTextEnd(caretNode);
|
|
327
512
|
emitChange();
|
|
328
513
|
|
|
329
|
-
// 关闭快捷列表和父组件同步
|
|
330
|
-
// 下一帧再恢复到刚插入
|
|
514
|
+
// 关闭快捷列表和父组件同步 mentions/value 会触发一次 React 更新;
|
|
515
|
+
// 下一帧再恢复到刚插入 Mention 后的零宽锚点,避免光标被 focus 或重渲染带回旧位置。
|
|
331
516
|
window.requestAnimationFrame(function () {
|
|
332
517
|
if (lastInsertedCaretRef.current === caretNode) {
|
|
333
518
|
restoreCursorAfterInsert(caretNode);
|
|
334
519
|
}
|
|
335
520
|
});
|
|
336
|
-
}, [
|
|
521
|
+
}, [buildMentionNode, cleanupCaretTextNodes, emitChange, getPlainText, replaceTextRange, restoreCursorAfterInsert, setCursorAtTextEnd]);
|
|
522
|
+
useEffect(function () {
|
|
523
|
+
document.addEventListener("selectionchange", saveSelectionRange);
|
|
524
|
+
return function () {
|
|
525
|
+
document.removeEventListener("selectionchange", saveSelectionRange);
|
|
526
|
+
};
|
|
527
|
+
}, [saveSelectionRange]);
|
|
528
|
+
useEffect(function () {
|
|
529
|
+
return function () {
|
|
530
|
+
if (structuralCleanupFrameRef.current !== null) {
|
|
531
|
+
window.cancelAnimationFrame(structuralCleanupFrameRef.current);
|
|
532
|
+
}
|
|
533
|
+
};
|
|
534
|
+
}, []);
|
|
337
535
|
useImperativeHandle(ref, function () {
|
|
338
536
|
return {
|
|
339
537
|
focus: function focus() {
|
|
@@ -341,65 +539,150 @@ var InlineTagInput = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
341
539
|
return (_editorRef$current = editorRef.current) === null || _editorRef$current === void 0 ? void 0 : _editorRef$current.focus();
|
|
342
540
|
},
|
|
343
541
|
getText: getPlainText,
|
|
542
|
+
getParts: getParts,
|
|
344
543
|
getCursorOffset: getOffsetInEditor,
|
|
345
|
-
|
|
544
|
+
insertMention: insertMention,
|
|
545
|
+
insertTag: insertMention
|
|
346
546
|
};
|
|
347
|
-
}, [getOffsetInEditor, getPlainText,
|
|
348
|
-
|
|
349
|
-
var editor = editorRef.current;
|
|
350
|
-
if (!editor || editor.childNodes.length > 0) return;
|
|
351
|
-
if (value) editor.appendChild(createTextNode(value));
|
|
352
|
-
tags.forEach(function (tag) {
|
|
353
|
-
return editor.append(buildTagNode(tag), createTextNode(CARET_TEXT));
|
|
354
|
-
});
|
|
355
|
-
}, []);
|
|
356
|
-
|
|
357
|
-
// 外部受控 tags 变化时,同步补齐或删除 DOM 中的 tag 节点。
|
|
358
|
-
useEffect(function () {
|
|
547
|
+
}, [getOffsetInEditor, getParts, getPlainText, insertMention]);
|
|
548
|
+
useIsomorphicLayoutEffect(function () {
|
|
359
549
|
var editor = editorRef.current;
|
|
360
550
|
if (!editor) return;
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
551
|
+
|
|
552
|
+
// 默认片段只在空输入首次挂载时灌入,避免外部重新渲染覆盖用户正在编辑的内容。
|
|
553
|
+
if (!defaultInputPartsAppliedRef.current && defaultInputParts !== null && defaultInputParts !== void 0 && defaultInputParts.length && !value && mentions.length === 0) {
|
|
554
|
+
defaultInputPartsAppliedRef.current = true;
|
|
555
|
+
// emitChange 的受控回写要到下一次 render 才生效;跳过本轮紧随其后的空值清理,
|
|
556
|
+
// 避免刚渲染的默认 Mention 被旧的空 value/mentions 立即移除。
|
|
557
|
+
skipEmptyCleanupOnceRef.current = true;
|
|
558
|
+
renderPartsToEditor(defaultInputParts);
|
|
559
|
+
emitChange();
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
562
|
+
var incomingMentionIds = mentions.map(function (mention) {
|
|
563
|
+
return mention.id;
|
|
564
|
+
}).join("|");
|
|
565
|
+
var lastEmittedState = lastEmittedStateRef.current;
|
|
566
|
+
var isInternalControlledEcho = value === lastEmittedState.value && incomingMentionIds === lastEmittedState.mentionIds;
|
|
567
|
+
if (isInternalControlledEcho && editor.childNodes.length > 0) return;
|
|
568
|
+
renderPartsToEditor([].concat(_toConsumableArray(value ? [{
|
|
569
|
+
type: "text",
|
|
570
|
+
text: value
|
|
571
|
+
}] : []), _toConsumableArray(mentions.map(function (mention) {
|
|
572
|
+
return {
|
|
573
|
+
type: "mention",
|
|
574
|
+
mention: mention
|
|
575
|
+
};
|
|
576
|
+
}))));
|
|
577
|
+
setHasContent(Boolean(value || mentions.length));
|
|
578
|
+
|
|
579
|
+
// 外部主动写入 value/mentions 后,需要在首帧绘制前同步 DOM;若输入区已有焦点,则把光标放在内容末尾。
|
|
580
|
+
var lastTextNode = Array.from(editor.childNodes).reverse().find(function (node) {
|
|
581
|
+
return node.nodeType === Node.TEXT_NODE;
|
|
377
582
|
});
|
|
378
|
-
|
|
379
|
-
|
|
583
|
+
if (document.activeElement === editor && lastTextNode) {
|
|
584
|
+
setCursorAtTextEnd(lastTextNode);
|
|
585
|
+
}
|
|
586
|
+
}, [defaultInputParts, emitChange, renderPartsToEditor, setCursorAtTextEnd, mentions, value]);
|
|
587
|
+
useIsomorphicLayoutEffect(function () {
|
|
380
588
|
var editor = editorRef.current;
|
|
381
589
|
if (!editor) return;
|
|
382
|
-
if (
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
590
|
+
if (skipEmptyCleanupOnceRef.current) {
|
|
591
|
+
skipEmptyCleanupOnceRef.current = false;
|
|
592
|
+
return;
|
|
593
|
+
}
|
|
594
|
+
if (!value && mentions.length === 0 && editor.childNodes.length > 0) {
|
|
595
|
+
editor.querySelectorAll("[".concat(MENTION_ATTR, "]")).forEach(function (node) {
|
|
596
|
+
var _tagRootMapRef$curren3;
|
|
597
|
+
(_tagRootMapRef$curren3 = tagRootMapRef.current.get(node)) === null || _tagRootMapRef$curren3 === void 0 || _tagRootMapRef$curren3.unmount();
|
|
386
598
|
});
|
|
387
599
|
editor.innerHTML = "";
|
|
388
600
|
}
|
|
389
|
-
}, [
|
|
601
|
+
}, [mentions.length, value]);
|
|
390
602
|
var handleInput = function handleInput() {
|
|
391
|
-
if (!composingRef.current)
|
|
603
|
+
if (!composingRef.current) {
|
|
604
|
+
cleanupEmptyStructuralNodes();
|
|
605
|
+
cleanupCaretTextNodes();
|
|
606
|
+
emitChange();
|
|
607
|
+
|
|
608
|
+
// Chrome 可能在 input 回调返回后才补上用于承接光标的 <br>;下一帧再归一化一次。
|
|
609
|
+
if (structuralCleanupFrameRef.current !== null) {
|
|
610
|
+
window.cancelAnimationFrame(structuralCleanupFrameRef.current);
|
|
611
|
+
}
|
|
612
|
+
structuralCleanupFrameRef.current = window.requestAnimationFrame(function () {
|
|
613
|
+
structuralCleanupFrameRef.current = null;
|
|
614
|
+
cleanupEmptyStructuralNodes();
|
|
615
|
+
cleanupCaretTextNodes();
|
|
616
|
+
});
|
|
617
|
+
}
|
|
618
|
+
};
|
|
619
|
+
var handlePaste = function handlePaste(event) {
|
|
620
|
+
event.preventDefault();
|
|
621
|
+
var editor = editorRef.current;
|
|
622
|
+
if (!editor) return;
|
|
623
|
+
|
|
624
|
+
// 始终按 text/plain 粘贴,避免消息气泡的背景色等 HTML 样式进入 contenteditable。
|
|
625
|
+
var text = event.clipboardData.getData("text/plain");
|
|
626
|
+
if (!text) return;
|
|
627
|
+
var parts = parseMarkdownResourceLinksAsParts(text);
|
|
628
|
+
var selection = window.getSelection();
|
|
629
|
+
var range = selection !== null && selection !== void 0 && selection.rangeCount && editor.contains(selection.getRangeAt(0).startContainer) ? selection.getRangeAt(0) : null;
|
|
630
|
+
var fragment = document.createDocumentFragment();
|
|
631
|
+
var lastTextNode = null;
|
|
632
|
+
var _iterator = _createForOfIteratorHelper(parts),
|
|
633
|
+
_step;
|
|
634
|
+
try {
|
|
635
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
636
|
+
var part = _step.value;
|
|
637
|
+
if (part.type === "text") {
|
|
638
|
+
lastTextNode = createTextNode(part.text);
|
|
639
|
+
fragment.append(lastTextNode);
|
|
640
|
+
continue;
|
|
641
|
+
}
|
|
642
|
+
latestMentionsRef.current = [].concat(_toConsumableArray(latestMentionsRef.current), [part.mention]);
|
|
643
|
+
fragment.append(buildMentionNode(part.mention));
|
|
644
|
+
lastTextNode = createTextNode(CARET_TEXT);
|
|
645
|
+
fragment.append(lastTextNode);
|
|
646
|
+
}
|
|
647
|
+
} catch (err) {
|
|
648
|
+
_iterator.e(err);
|
|
649
|
+
} finally {
|
|
650
|
+
_iterator.f();
|
|
651
|
+
}
|
|
652
|
+
if (range) {
|
|
653
|
+
range.deleteContents();
|
|
654
|
+
range.insertNode(fragment);
|
|
655
|
+
} else {
|
|
656
|
+
editor.append(fragment);
|
|
657
|
+
}
|
|
658
|
+
cleanupCaretTextNodes();
|
|
659
|
+
if (lastTextNode) setCursorAtTextEnd(lastTextNode);
|
|
660
|
+
emitChange();
|
|
392
661
|
};
|
|
393
662
|
var handleKeyDown = function handleKeyDown(event) {
|
|
394
|
-
if (event.key === "
|
|
663
|
+
if (event.key === "ArrowLeft" || event.key === "ArrowRight") {
|
|
395
664
|
var selection = window.getSelection();
|
|
396
665
|
if (selection !== null && selection !== void 0 && selection.rangeCount) {
|
|
397
666
|
var range = selection.getRangeAt(0);
|
|
398
667
|
if (range.collapsed) {
|
|
399
|
-
var
|
|
400
|
-
if (
|
|
668
|
+
var targetMention = event.key === "ArrowLeft" ? getMentionBeforeRange(range) : getMentionAfterRange(range);
|
|
669
|
+
if (targetMention) {
|
|
401
670
|
event.preventDefault();
|
|
402
|
-
|
|
671
|
+
moveCursorAroundMention(targetMention, event.key === "ArrowLeft" ? "before" : "after");
|
|
672
|
+
return;
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
if (event.key === "Backspace" || event.key === "Delete") {
|
|
678
|
+
var _selection = window.getSelection();
|
|
679
|
+
if (_selection !== null && _selection !== void 0 && _selection.rangeCount) {
|
|
680
|
+
var _range = _selection.getRangeAt(0);
|
|
681
|
+
if (_range.collapsed) {
|
|
682
|
+
var _targetMention = event.key === "Backspace" ? getMentionBeforeRange(_range) : getMentionAfterRange(_range);
|
|
683
|
+
if (_targetMention) {
|
|
684
|
+
event.preventDefault();
|
|
685
|
+
removeMentionById(_targetMention.dataset.xadkInlineMentionId || "");
|
|
403
686
|
return;
|
|
404
687
|
}
|
|
405
688
|
}
|
|
@@ -407,10 +690,15 @@ var InlineTagInput = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
407
690
|
}
|
|
408
691
|
onKeyDown === null || onKeyDown === void 0 || onKeyDown(event);
|
|
409
692
|
};
|
|
410
|
-
|
|
693
|
+
|
|
694
|
+
// placeholder 只由受控 value/mentions 派生,避免从 contenteditable DOM 读取导致外部插入 Mention 后状态滞后一帧。
|
|
695
|
+
var showPlaceholder = !hasContent;
|
|
696
|
+
return /*#__PURE__*/_jsxs("div", {
|
|
411
697
|
className: styles.inlineInputWrapper,
|
|
412
|
-
|
|
413
|
-
|
|
698
|
+
children: [showPlaceholder && placeholder && /*#__PURE__*/_jsx("div", {
|
|
699
|
+
className: styles.inlinePlaceholder,
|
|
700
|
+
children: placeholder
|
|
701
|
+
}), /*#__PURE__*/_jsx("div", {
|
|
414
702
|
ref: editorRef,
|
|
415
703
|
className: styles.inlineInput,
|
|
416
704
|
contentEditable: !disabled,
|
|
@@ -418,18 +706,27 @@ var InlineTagInput = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
418
706
|
role: "textbox",
|
|
419
707
|
"aria-multiline": "true",
|
|
420
708
|
onInput: handleInput,
|
|
709
|
+
onPaste: handlePaste,
|
|
421
710
|
onKeyDown: handleKeyDown,
|
|
422
|
-
onKeyUp: onKeyUp
|
|
711
|
+
onKeyUp: function onKeyUp(event) {
|
|
712
|
+
cleanupEmptyStructuralNodes();
|
|
713
|
+
cleanupCaretTextNodes();
|
|
714
|
+
saveSelectionRange();
|
|
715
|
+
_onKeyUp === null || _onKeyUp === void 0 || _onKeyUp(event);
|
|
716
|
+
},
|
|
717
|
+
onMouseUp: saveSelectionRange,
|
|
718
|
+
onFocus: saveSelectionRange,
|
|
423
719
|
onCompositionStart: function onCompositionStart() {
|
|
424
720
|
composingRef.current = true;
|
|
721
|
+
// 中文 IME 在 compositionend 前不会触发受控 value 更新;候选输入一出现就应隐藏 placeholder。
|
|
722
|
+
setHasContent(true);
|
|
425
723
|
},
|
|
426
724
|
onCompositionEnd: function onCompositionEnd() {
|
|
427
725
|
composingRef.current = false;
|
|
428
726
|
emitChange();
|
|
429
727
|
},
|
|
430
|
-
"data-empty": !getPlainText() && getOrderedTags().length === 0,
|
|
431
728
|
"data-cursor-offset": getOffsetInEditor()
|
|
432
|
-
})
|
|
729
|
+
})]
|
|
433
730
|
});
|
|
434
731
|
});
|
|
435
732
|
InlineTagInput.displayName = "InlineTagInput";
|