@opensumi/ide-ai-native 3.8.3-next-1741850419.0 → 3.8.3-next-1741917543.0
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/lib/browser/chat/chat-agent.service.d.ts +1 -1
- package/lib/browser/chat/chat-agent.service.d.ts.map +1 -1
- package/lib/browser/chat/chat-agent.service.js +7 -7
- package/lib/browser/chat/chat-agent.service.js.map +1 -1
- package/lib/browser/chat/chat.view.d.ts.map +1 -1
- package/lib/browser/chat/chat.view.js +31 -69
- package/lib/browser/chat/chat.view.js.map +1 -1
- package/lib/browser/components/{chat-context/context-selector.d.ts → ChatContext/ContextSelector.d.ts} +1 -1
- package/lib/browser/components/ChatContext/ContextSelector.d.ts.map +1 -0
- package/lib/browser/components/{chat-context/context-selector.js → ChatContext/ContextSelector.js} +1 -1
- package/lib/browser/components/ChatContext/ContextSelector.js.map +1 -0
- package/lib/browser/components/ChatContext/index.d.ts.map +1 -0
- package/lib/browser/components/{chat-context → ChatContext}/index.js +2 -2
- package/lib/browser/components/ChatContext/index.js.map +1 -0
- package/lib/browser/components/ChatEditor.d.ts +2 -11
- package/lib/browser/components/ChatEditor.d.ts.map +1 -1
- package/lib/browser/components/ChatEditor.js +6 -66
- package/lib/browser/components/ChatEditor.js.map +1 -1
- package/lib/browser/components/ChatHistory.d.ts.map +1 -1
- package/lib/browser/components/ChatHistory.js +15 -15
- package/lib/browser/components/ChatHistory.js.map +1 -1
- package/lib/browser/components/ChatThinking.d.ts +1 -1
- package/lib/browser/components/ChatThinking.d.ts.map +1 -1
- package/lib/browser/components/ChatThinking.js +2 -8
- package/lib/browser/components/ChatThinking.js.map +1 -1
- package/lib/browser/components/change-list.module.less +0 -2
- package/lib/browser/components/chat-history.module.less +16 -33
- package/lib/browser/components/components.module.less +3 -39
- package/lib/browser/context/llm-context.service.d.ts +2 -10
- package/lib/browser/context/llm-context.service.d.ts.map +1 -1
- package/lib/browser/context/llm-context.service.js +2 -71
- package/lib/browser/context/llm-context.service.js.map +1 -1
- package/lib/browser/mcp/base-apply.service.d.ts +1 -1
- package/lib/browser/mcp/base-apply.service.d.ts.map +1 -1
- package/lib/browser/mcp/base-apply.service.js +9 -2
- package/lib/browser/mcp/base-apply.service.js.map +1 -1
- package/lib/common/llm-context.d.ts +1 -15
- package/lib/common/llm-context.d.ts.map +1 -1
- package/lib/common/llm-context.js.map +1 -1
- package/lib/common/prompts/context-prompt-provider.d.ts +2 -12
- package/lib/common/prompts/context-prompt-provider.d.ts.map +1 -1
- package/lib/common/prompts/context-prompt-provider.js +30 -95
- package/lib/common/prompts/context-prompt-provider.js.map +1 -1
- package/lib/common/utils.d.ts +0 -1
- package/lib/common/utils.d.ts.map +1 -1
- package/lib/common/utils.js +1 -9
- package/lib/common/utils.js.map +1 -1
- package/lib/node/mcp-server.sse.d.ts.map +1 -1
- package/lib/node/mcp-server.sse.js +2 -2
- package/lib/node/mcp-server.sse.js.map +1 -1
- package/package.json +23 -23
- package/src/browser/chat/chat-agent.service.ts +7 -7
- package/src/browser/chat/chat.view.tsx +24 -81
- package/src/browser/components/{chat-context → ChatContext}/index.tsx +1 -1
- package/src/browser/components/ChatEditor.tsx +9 -126
- package/src/browser/components/ChatHistory.tsx +30 -16
- package/src/browser/components/ChatThinking.tsx +4 -10
- package/src/browser/components/change-list.module.less +0 -2
- package/src/browser/components/chat-history.module.less +16 -33
- package/src/browser/components/components.module.less +3 -39
- package/src/browser/context/llm-context.service.ts +3 -81
- package/src/browser/mcp/base-apply.service.ts +9 -2
- package/src/common/llm-context.ts +1 -16
- package/src/common/prompts/context-prompt-provider.ts +36 -130
- package/src/common/utils.ts +0 -8
- package/src/node/mcp-server.sse.ts +2 -1
- package/lib/browser/components/ChatMentionInput.d.ts +0 -25
- package/lib/browser/components/ChatMentionInput.d.ts.map +0 -1
- package/lib/browser/components/ChatMentionInput.js +0 -229
- package/lib/browser/components/ChatMentionInput.js.map +0 -1
- package/lib/browser/components/chat-context/context-selector.d.ts.map +0 -1
- package/lib/browser/components/chat-context/context-selector.js.map +0 -1
- package/lib/browser/components/chat-context/index.d.ts.map +0 -1
- package/lib/browser/components/chat-context/index.js.map +0 -1
- package/lib/browser/components/mention-input/mention-input.d.ts +0 -5
- package/lib/browser/components/mention-input/mention-input.d.ts.map +0 -1
- package/lib/browser/components/mention-input/mention-input.js +0 -763
- package/lib/browser/components/mention-input/mention-input.js.map +0 -1
- package/lib/browser/components/mention-input/mention-input.module.less +0 -333
- package/lib/browser/components/mention-input/mention-item.d.ts +0 -10
- package/lib/browser/components/mention-input/mention-item.d.ts.map +0 -1
- package/lib/browser/components/mention-input/mention-item.js +0 -16
- package/lib/browser/components/mention-input/mention-item.js.map +0 -1
- package/lib/browser/components/mention-input/mention-panel.d.ts +0 -15
- package/lib/browser/components/mention-input/mention-panel.d.ts.map +0 -1
- package/lib/browser/components/mention-input/mention-panel.js +0 -49
- package/lib/browser/components/mention-input/mention-panel.js.map +0 -1
- package/lib/browser/components/mention-input/types.d.ts +0 -78
- package/lib/browser/components/mention-input/types.d.ts.map +0 -1
- package/lib/browser/components/mention-input/types.js +0 -16
- package/lib/browser/components/mention-input/types.js.map +0 -1
- package/src/browser/components/ChatMentionInput.tsx +0 -276
- package/src/browser/components/mention-input/mention-input.module.less +0 -333
- package/src/browser/components/mention-input/mention-input.tsx +0 -952
- package/src/browser/components/mention-input/mention-item.tsx +0 -24
- package/src/browser/components/mention-input/mention-panel.tsx +0 -89
- package/src/browser/components/mention-input/types.ts +0 -84
- /package/lib/browser/components/{chat-context → ChatContext}/index.d.ts +0 -0
- /package/lib/browser/components/{chat-context → ChatContext}/style.module.less +0 -0
- /package/src/browser/components/{chat-context/context-selector.tsx → ChatContext/ContextSelector.tsx} +0 -0
- /package/src/browser/components/{chat-context → ChatContext}/style.module.less +0 -0
|
@@ -1,763 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.MentionInput = exports.WHITE_SPACE_TEXT = void 0;
|
|
4
|
-
const tslib_1 = require("tslib");
|
|
5
|
-
const classnames_1 = tslib_1.__importDefault(require("classnames"));
|
|
6
|
-
const React = tslib_1.__importStar(require("react"));
|
|
7
|
-
const components_1 = require("@opensumi/ide-core-browser/lib/components");
|
|
8
|
-
const ai_native_1 = require("@opensumi/ide-core-browser/lib/components/ai-native");
|
|
9
|
-
const ide_utils_1 = require("@opensumi/ide-utils");
|
|
10
|
-
const mention_input_module_less_1 = tslib_1.__importDefault(require("./mention-input.module.less"));
|
|
11
|
-
const mention_panel_1 = require("./mention-panel");
|
|
12
|
-
const types_1 = require("./types");
|
|
13
|
-
exports.WHITE_SPACE_TEXT = ' ';
|
|
14
|
-
const MentionInput = ({ mentionItems = [], onSend, onStop, loading = false, mentionKeyword = types_1.MENTION_KEYWORD, onSelectionChange, labelService, workspaceService, placeholder = 'Ask anything, @ to mention', footerConfig = {
|
|
15
|
-
buttons: [],
|
|
16
|
-
showModelSelector: false,
|
|
17
|
-
}, }) => {
|
|
18
|
-
const editorRef = React.useRef(null);
|
|
19
|
-
const [mentionState, setMentionState] = React.useState({
|
|
20
|
-
active: false,
|
|
21
|
-
startPos: null,
|
|
22
|
-
filter: '',
|
|
23
|
-
position: { top: 0, left: 0 },
|
|
24
|
-
activeIndex: 0,
|
|
25
|
-
level: 0, // 0: 一级菜单, 1: 二级菜单
|
|
26
|
-
parentType: null, // 二级菜单的父类型
|
|
27
|
-
secondLevelFilter: '', // 二级菜单的筛选文本
|
|
28
|
-
inlineSearchActive: false, // 是否在输入框中进行二级搜索
|
|
29
|
-
inlineSearchStartPos: null, // 内联搜索的起始位置
|
|
30
|
-
loading: false, // 添加加载状态
|
|
31
|
-
});
|
|
32
|
-
// 添加模型选择状态
|
|
33
|
-
const [selectedModel, setSelectedModel] = React.useState(footerConfig.defaultModel || '');
|
|
34
|
-
// 添加缓存状态,用于存储二级菜单项
|
|
35
|
-
const [secondLevelCache, setSecondLevelCache] = React.useState({});
|
|
36
|
-
// 添加历史记录状态
|
|
37
|
-
const [history, setHistory] = React.useState([]);
|
|
38
|
-
const [historyIndex, setHistoryIndex] = React.useState(-1);
|
|
39
|
-
const [currentInput, setCurrentInput] = React.useState('');
|
|
40
|
-
const [isNavigatingHistory, setIsNavigatingHistory] = React.useState(false);
|
|
41
|
-
// 获取当前菜单项
|
|
42
|
-
const getCurrentItems = () => {
|
|
43
|
-
if (mentionState.level === 0) {
|
|
44
|
-
return mentionItems;
|
|
45
|
-
}
|
|
46
|
-
else if (mentionState.parentType) {
|
|
47
|
-
// 如果正在加载,返回缓存的项目
|
|
48
|
-
if (mentionState.loading) {
|
|
49
|
-
return secondLevelCache[mentionState.parentType] || [];
|
|
50
|
-
}
|
|
51
|
-
// 返回缓存的项目
|
|
52
|
-
return secondLevelCache[mentionState.parentType] || [];
|
|
53
|
-
}
|
|
54
|
-
return [];
|
|
55
|
-
};
|
|
56
|
-
// 添加防抖函数
|
|
57
|
-
const useDebounce = (value, delay) => {
|
|
58
|
-
const [debouncedValue, setDebouncedValue] = React.useState(value);
|
|
59
|
-
React.useEffect(() => {
|
|
60
|
-
const handler = setTimeout(() => {
|
|
61
|
-
setDebouncedValue(value);
|
|
62
|
-
}, delay);
|
|
63
|
-
return () => {
|
|
64
|
-
clearTimeout(handler);
|
|
65
|
-
};
|
|
66
|
-
}, [value, delay]);
|
|
67
|
-
return debouncedValue;
|
|
68
|
-
};
|
|
69
|
-
// 使用防抖处理搜索文本
|
|
70
|
-
const debouncedSecondLevelFilter = useDebounce(mentionState.secondLevelFilter, 300);
|
|
71
|
-
// 监听搜索文本变化,实时更新二级菜单
|
|
72
|
-
React.useEffect(() => {
|
|
73
|
-
if (mentionState.level === 1 && mentionState.parentType && debouncedSecondLevelFilter !== undefined) {
|
|
74
|
-
// 查找父级菜单项
|
|
75
|
-
const parentItem = mentionItems.find((item) => item.id === mentionState.parentType);
|
|
76
|
-
if (!parentItem) {
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
// 设置加载状态
|
|
80
|
-
setMentionState((prev) => ({ ...prev, loading: true }));
|
|
81
|
-
// 异步加载
|
|
82
|
-
const fetchItems = async () => {
|
|
83
|
-
try {
|
|
84
|
-
// 首先显示高优先级项目(如果有)
|
|
85
|
-
const items = [];
|
|
86
|
-
if (parentItem.getHighestLevelItems) {
|
|
87
|
-
const highestLevelItems = parentItem.getHighestLevelItems();
|
|
88
|
-
for (const item of highestLevelItems) {
|
|
89
|
-
if (!items.some((i) => i.id === item.id)) {
|
|
90
|
-
items.push(item);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
// 立即更新缓存,显示高优先级项目
|
|
94
|
-
setSecondLevelCache((prev) => ({
|
|
95
|
-
...prev,
|
|
96
|
-
[mentionState.parentType]: highestLevelItems,
|
|
97
|
-
}));
|
|
98
|
-
}
|
|
99
|
-
// 然后异步加载更多项目
|
|
100
|
-
if (parentItem.getItems) {
|
|
101
|
-
try {
|
|
102
|
-
// 获取子菜单项
|
|
103
|
-
const newItems = await parentItem.getItems(debouncedSecondLevelFilter);
|
|
104
|
-
// 去重合并
|
|
105
|
-
const combinedItems = [...items];
|
|
106
|
-
for (const item of newItems) {
|
|
107
|
-
if (!combinedItems.some((i) => i.id === item.id)) {
|
|
108
|
-
combinedItems.push(item);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
// 更新缓存
|
|
112
|
-
setSecondLevelCache((prev) => ({
|
|
113
|
-
...prev,
|
|
114
|
-
[mentionState.parentType]: combinedItems,
|
|
115
|
-
}));
|
|
116
|
-
}
|
|
117
|
-
catch (error) {
|
|
118
|
-
// 如果异步加载失败,至少保留高优先级项目
|
|
119
|
-
setMentionState((prev) => ({ ...prev, loading: false }));
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
// 最后清除加载状态
|
|
123
|
-
setMentionState((prev) => ({ ...prev, loading: false }));
|
|
124
|
-
}
|
|
125
|
-
catch (error) {
|
|
126
|
-
setMentionState((prev) => ({ ...prev, loading: false }));
|
|
127
|
-
}
|
|
128
|
-
};
|
|
129
|
-
fetchItems();
|
|
130
|
-
}
|
|
131
|
-
}, [debouncedSecondLevelFilter, mentionState.level, mentionState.parentType]);
|
|
132
|
-
// 获取光标位置
|
|
133
|
-
const getCursorPosition = (element) => {
|
|
134
|
-
const selection = window.getSelection();
|
|
135
|
-
if (!selection || !selection.rangeCount) {
|
|
136
|
-
return 0;
|
|
137
|
-
}
|
|
138
|
-
const range = selection.getRangeAt(0);
|
|
139
|
-
const preCaretRange = range.cloneRange();
|
|
140
|
-
preCaretRange.selectNodeContents(element);
|
|
141
|
-
preCaretRange.setEnd(range.endContainer, range.endOffset);
|
|
142
|
-
return preCaretRange.toString().length;
|
|
143
|
-
};
|
|
144
|
-
// 处理输入事件
|
|
145
|
-
const handleInput = () => {
|
|
146
|
-
// 如果用户开始输入,退出历史导航模式
|
|
147
|
-
if (isNavigatingHistory) {
|
|
148
|
-
setIsNavigatingHistory(false);
|
|
149
|
-
setHistoryIndex(-1);
|
|
150
|
-
}
|
|
151
|
-
const selection = window.getSelection();
|
|
152
|
-
if (!selection || !selection.rangeCount || !editorRef.current) {
|
|
153
|
-
return;
|
|
154
|
-
}
|
|
155
|
-
const text = editorRef.current.textContent || '';
|
|
156
|
-
const cursorPos = getCursorPosition(editorRef.current);
|
|
157
|
-
// 判断是否刚输入了 @
|
|
158
|
-
if (text[cursorPos - 1] === mentionKeyword && !mentionState.active && !mentionState.inlineSearchActive) {
|
|
159
|
-
setMentionState({
|
|
160
|
-
active: true,
|
|
161
|
-
startPos: cursorPos,
|
|
162
|
-
filter: mentionKeyword,
|
|
163
|
-
position: { top: 0, left: 0 }, // 固定位置,不再需要动态计算
|
|
164
|
-
activeIndex: 0,
|
|
165
|
-
level: 0,
|
|
166
|
-
parentType: null,
|
|
167
|
-
secondLevelFilter: '',
|
|
168
|
-
inlineSearchActive: false,
|
|
169
|
-
inlineSearchStartPos: null,
|
|
170
|
-
loading: false,
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
// 如果已激活提及面板且在一级菜单,更新过滤内容
|
|
174
|
-
if (mentionState.active && mentionState.level === 0 && mentionState.startPos !== null) {
|
|
175
|
-
if (cursorPos < mentionState.startPos) {
|
|
176
|
-
// 如果光标移到了 @ 之前,关闭面板
|
|
177
|
-
setMentionState((prev) => ({ ...prev, active: false }));
|
|
178
|
-
}
|
|
179
|
-
else {
|
|
180
|
-
const newFilter = text.substring(mentionState.startPos - 1, cursorPos);
|
|
181
|
-
setMentionState((prev) => ({
|
|
182
|
-
...prev,
|
|
183
|
-
filter: newFilter,
|
|
184
|
-
activeIndex: 0,
|
|
185
|
-
}));
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
// 如果在输入框中进行二级搜索
|
|
189
|
-
if (mentionState.inlineSearchActive && mentionState.inlineSearchStartPos !== null && mentionState.parentType) {
|
|
190
|
-
// 获取父级类型
|
|
191
|
-
const parentItem = mentionItems.find((i) => i.id === mentionState.parentType);
|
|
192
|
-
if (!parentItem) {
|
|
193
|
-
return;
|
|
194
|
-
}
|
|
195
|
-
// 检查光标是否在 @type: 之后
|
|
196
|
-
const typePrefix = `@${parentItem.type}:`;
|
|
197
|
-
const prefixPos = mentionState.inlineSearchStartPos - typePrefix.length;
|
|
198
|
-
if (prefixPos >= 0 && cursorPos > prefixPos + typePrefix.length) {
|
|
199
|
-
// 提取搜索文本
|
|
200
|
-
const searchText = text.substring(prefixPos + typePrefix.length, cursorPos);
|
|
201
|
-
// 只有当搜索文本变化时才更新状态
|
|
202
|
-
if (searchText !== mentionState.secondLevelFilter) {
|
|
203
|
-
setMentionState((prev) => ({
|
|
204
|
-
...prev,
|
|
205
|
-
secondLevelFilter: searchText,
|
|
206
|
-
active: true,
|
|
207
|
-
activeIndex: 0,
|
|
208
|
-
}));
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
else if (cursorPos <= prefixPos) {
|
|
212
|
-
// 如果光标移到了 @type: 之前,关闭内联搜索
|
|
213
|
-
setMentionState((prev) => ({
|
|
214
|
-
...prev,
|
|
215
|
-
inlineSearchActive: false,
|
|
216
|
-
active: false,
|
|
217
|
-
}));
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
// 检查输入框高度,如果超过最大高度则添加滚动条
|
|
221
|
-
if (editorRef.current) {
|
|
222
|
-
const editorHeight = editorRef.current.scrollHeight;
|
|
223
|
-
if (editorHeight > 120) {
|
|
224
|
-
editorRef.current.style.overflowY = 'auto';
|
|
225
|
-
}
|
|
226
|
-
else {
|
|
227
|
-
editorRef.current.style.overflowY = 'hidden';
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
// 检查编辑器内容,处理只有 <br> 标签的情况
|
|
231
|
-
if (editorRef.current) {
|
|
232
|
-
const content = editorRef.current.innerHTML;
|
|
233
|
-
// 如果内容为空或只有 <br> 标签
|
|
234
|
-
if (content === '' || content === '<br>' || content === '<br/>') {
|
|
235
|
-
// 清空编辑器内容
|
|
236
|
-
editorRef.current.innerHTML = '';
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
};
|
|
240
|
-
// 处理键盘事件
|
|
241
|
-
const handleKeyDown = (e) => {
|
|
242
|
-
// 如果按下ESC键且提及面板处于活动状态或内联搜索处于活动状态
|
|
243
|
-
if (e.key === 'Escape' && (mentionState.active || mentionState.inlineSearchActive)) {
|
|
244
|
-
// 如果在二级菜单,返回一级菜单
|
|
245
|
-
if (mentionState.level > 0) {
|
|
246
|
-
setMentionState((prev) => ({
|
|
247
|
-
...prev,
|
|
248
|
-
level: 0,
|
|
249
|
-
activeIndex: 0,
|
|
250
|
-
secondLevelFilter: '',
|
|
251
|
-
inlineSearchActive: false,
|
|
252
|
-
}));
|
|
253
|
-
}
|
|
254
|
-
else {
|
|
255
|
-
// 如果在一级菜单,完全关闭面板
|
|
256
|
-
setMentionState((prev) => ({
|
|
257
|
-
...prev,
|
|
258
|
-
active: false,
|
|
259
|
-
inlineSearchActive: false,
|
|
260
|
-
}));
|
|
261
|
-
}
|
|
262
|
-
e.preventDefault();
|
|
263
|
-
return;
|
|
264
|
-
}
|
|
265
|
-
// 添加对 @ 键的监听,支持在任意位置触发菜单
|
|
266
|
-
if (e.key === types_1.MENTION_KEYWORD && !mentionState.active && !mentionState.inlineSearchActive && editorRef.current) {
|
|
267
|
-
const cursorPos = getCursorPosition(editorRef.current);
|
|
268
|
-
// 立即设置菜单状态,不等待 handleInput
|
|
269
|
-
setMentionState({
|
|
270
|
-
active: true,
|
|
271
|
-
startPos: cursorPos + 1, // +1 因为 @ 还没有被插入
|
|
272
|
-
filter: mentionKeyword,
|
|
273
|
-
position: { top: 0, left: 0 }, // 固定位置
|
|
274
|
-
activeIndex: 0,
|
|
275
|
-
level: 0,
|
|
276
|
-
parentType: null,
|
|
277
|
-
secondLevelFilter: '',
|
|
278
|
-
inlineSearchActive: false,
|
|
279
|
-
inlineSearchStartPos: null,
|
|
280
|
-
loading: false,
|
|
281
|
-
});
|
|
282
|
-
// 不要阻止默认行为,让 @ 正常输入到编辑器中
|
|
283
|
-
}
|
|
284
|
-
// 添加对 Enter 键的处理,只有在按下 Shift+Enter 时才允许换行
|
|
285
|
-
if (e.key === 'Enter') {
|
|
286
|
-
// 检查是否是输入法的回车键
|
|
287
|
-
// isComposing 属性表示是否正在进行输入法组合输入
|
|
288
|
-
if (e.nativeEvent.isComposing) {
|
|
289
|
-
return; // 如果是输入法组合输入过程中的回车,不做任何处理
|
|
290
|
-
}
|
|
291
|
-
if (!e.shiftKey) {
|
|
292
|
-
e.preventDefault();
|
|
293
|
-
if (!mentionState.active) {
|
|
294
|
-
handleSend();
|
|
295
|
-
return;
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
// 处理上下方向键导航历史记录
|
|
300
|
-
if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {
|
|
301
|
-
// 只有在非提及面板激活状态下才处理历史导航
|
|
302
|
-
if (!mentionState.active && !mentionState.inlineSearchActive && editorRef.current) {
|
|
303
|
-
e.preventDefault();
|
|
304
|
-
// 如果是第一次按上下键,保存当前输入
|
|
305
|
-
if (!isNavigatingHistory) {
|
|
306
|
-
setCurrentInput(editorRef.current.innerHTML);
|
|
307
|
-
setIsNavigatingHistory(true);
|
|
308
|
-
}
|
|
309
|
-
// 计算新的历史索引
|
|
310
|
-
let newIndex = historyIndex;
|
|
311
|
-
if (e.key === 'ArrowUp') {
|
|
312
|
-
// 向上导航到较早的历史记录
|
|
313
|
-
newIndex = Math.min(history.length - 1, historyIndex + 1);
|
|
314
|
-
}
|
|
315
|
-
else {
|
|
316
|
-
// 向下导航到较新的历史记录
|
|
317
|
-
newIndex = Math.max(-1, historyIndex - 1);
|
|
318
|
-
}
|
|
319
|
-
setHistoryIndex(newIndex);
|
|
320
|
-
// 更新编辑器内容
|
|
321
|
-
if (newIndex === -1) {
|
|
322
|
-
// 恢复到当前输入
|
|
323
|
-
editorRef.current.innerHTML = currentInput;
|
|
324
|
-
}
|
|
325
|
-
else {
|
|
326
|
-
// 显示历史记录
|
|
327
|
-
editorRef.current.innerHTML = history[history.length - 1 - newIndex];
|
|
328
|
-
}
|
|
329
|
-
// 将光标移到末尾
|
|
330
|
-
const range = document.createRange();
|
|
331
|
-
range.selectNodeContents(editorRef.current);
|
|
332
|
-
range.collapse(false);
|
|
333
|
-
const selection = window.getSelection();
|
|
334
|
-
if (selection) {
|
|
335
|
-
selection.removeAllRanges();
|
|
336
|
-
selection.addRange(range);
|
|
337
|
-
}
|
|
338
|
-
return;
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
else if (isNavigatingHistory && e.key !== 'ArrowUp' && e.key !== 'ArrowDown') {
|
|
342
|
-
// 如果用户在浏览历史记录后开始输入,退出历史导航模式
|
|
343
|
-
setIsNavigatingHistory(false);
|
|
344
|
-
setHistoryIndex(-1);
|
|
345
|
-
}
|
|
346
|
-
// 如果提及面板未激活,不处理其他键盘事件
|
|
347
|
-
if (!mentionState.active) {
|
|
348
|
-
return;
|
|
349
|
-
}
|
|
350
|
-
// 获取当前过滤后的项目
|
|
351
|
-
let filteredItems = getCurrentItems();
|
|
352
|
-
// 一级菜单过滤
|
|
353
|
-
if (mentionState.level === 0 && mentionState.filter && mentionState.filter.length > 1) {
|
|
354
|
-
const searchText = mentionState.filter.substring(1).toLowerCase();
|
|
355
|
-
filteredItems = filteredItems.filter((item) => item.text.toLowerCase().includes(searchText));
|
|
356
|
-
}
|
|
357
|
-
// 二级菜单过滤已经在 getCurrentItems 中处理
|
|
358
|
-
if (filteredItems.length === 0) {
|
|
359
|
-
return;
|
|
360
|
-
}
|
|
361
|
-
if (e.key === 'ArrowDown') {
|
|
362
|
-
// 向下导航
|
|
363
|
-
setMentionState((prev) => ({
|
|
364
|
-
...prev,
|
|
365
|
-
activeIndex: (prev.activeIndex + 1) % filteredItems.length,
|
|
366
|
-
}));
|
|
367
|
-
e.preventDefault();
|
|
368
|
-
}
|
|
369
|
-
else if (e.key === 'ArrowUp') {
|
|
370
|
-
// 向上导航
|
|
371
|
-
setMentionState((prev) => ({
|
|
372
|
-
...prev,
|
|
373
|
-
activeIndex: (prev.activeIndex - 1 + filteredItems.length) % filteredItems.length,
|
|
374
|
-
}));
|
|
375
|
-
e.preventDefault();
|
|
376
|
-
}
|
|
377
|
-
else if (e.key === 'Enter' || e.key === 'Tab') {
|
|
378
|
-
// 确认选择
|
|
379
|
-
if (filteredItems.length > 0) {
|
|
380
|
-
handleSelectItem(filteredItems[mentionState.activeIndex]);
|
|
381
|
-
e.preventDefault();
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
// 处理 Backspace 键,检查是否需要清空编辑器
|
|
385
|
-
if (e.key === 'Backspace' && editorRef.current) {
|
|
386
|
-
const content = editorRef.current.innerHTML;
|
|
387
|
-
if (content === '<br>' || content === '<br/>') {
|
|
388
|
-
editorRef.current.innerHTML = '';
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
};
|
|
392
|
-
// 添加对输入法事件的处理
|
|
393
|
-
const handleCompositionEnd = () => {
|
|
394
|
-
// 输入法输入完成后的处理
|
|
395
|
-
// 这里可以添加额外的逻辑,如果需要的话
|
|
396
|
-
};
|
|
397
|
-
// 初始化编辑器
|
|
398
|
-
React.useEffect(() => {
|
|
399
|
-
if (editorRef.current) {
|
|
400
|
-
// 设置初始占位符
|
|
401
|
-
if (placeholder && !editorRef.current.textContent) {
|
|
402
|
-
editorRef.current.setAttribute('data-placeholder', placeholder);
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
}, [placeholder]);
|
|
406
|
-
// 处理点击事件
|
|
407
|
-
const handleDocumentClick = (e) => {
|
|
408
|
-
var _a;
|
|
409
|
-
if (mentionState.active && !((_a = document.querySelector(`.${mention_input_module_less_1.default.mention_panel}`)) === null || _a === void 0 ? void 0 : _a.contains(e.target))) {
|
|
410
|
-
setMentionState((prev) => ({
|
|
411
|
-
...prev,
|
|
412
|
-
active: false,
|
|
413
|
-
inlineSearchActive: false,
|
|
414
|
-
}));
|
|
415
|
-
}
|
|
416
|
-
};
|
|
417
|
-
// 添加和移除全局点击事件监听器
|
|
418
|
-
React.useEffect(() => {
|
|
419
|
-
document.addEventListener('click', handleDocumentClick, true);
|
|
420
|
-
return () => {
|
|
421
|
-
document.removeEventListener('click', handleDocumentClick, true);
|
|
422
|
-
};
|
|
423
|
-
}, [mentionState.active]);
|
|
424
|
-
// 选择提及项目
|
|
425
|
-
const handleSelectItem = (item, isTriggerByClick = false) => {
|
|
426
|
-
var _a;
|
|
427
|
-
if (!editorRef.current) {
|
|
428
|
-
return;
|
|
429
|
-
}
|
|
430
|
-
// 如果项目有子菜单,进入二级菜单
|
|
431
|
-
if (item.getItems) {
|
|
432
|
-
const selection = window.getSelection();
|
|
433
|
-
if (!selection || !selection.rangeCount) {
|
|
434
|
-
return;
|
|
435
|
-
}
|
|
436
|
-
// 如果是从一级菜单选择了带子菜单的项目
|
|
437
|
-
if (mentionState.level === 0 && mentionState.startPos !== null) {
|
|
438
|
-
// 更安全地处理文本替换
|
|
439
|
-
let textNode;
|
|
440
|
-
let startOffset;
|
|
441
|
-
let endOffset;
|
|
442
|
-
// 找到包含 @ 符号的文本节点
|
|
443
|
-
const walker = document.createTreeWalker(editorRef.current, NodeFilter.SHOW_TEXT);
|
|
444
|
-
let charCount = 0;
|
|
445
|
-
let node;
|
|
446
|
-
while ((node = walker.nextNode())) {
|
|
447
|
-
const nodeLength = ((_a = node.textContent) === null || _a === void 0 ? void 0 : _a.length) || 0;
|
|
448
|
-
// 检查 @ 符号是否在这个节点中
|
|
449
|
-
if (mentionState.startPos - 1 >= charCount && mentionState.startPos - 1 < charCount + nodeLength) {
|
|
450
|
-
textNode = node;
|
|
451
|
-
startOffset = mentionState.startPos - 1 - charCount;
|
|
452
|
-
// 确保不会超出节点范围
|
|
453
|
-
const cursorPos = isTriggerByClick
|
|
454
|
-
? mentionState.startPos + mentionState.filter.length - 1
|
|
455
|
-
: getCursorPosition(editorRef.current);
|
|
456
|
-
endOffset = Math.min(cursorPos - charCount, nodeLength);
|
|
457
|
-
break;
|
|
458
|
-
}
|
|
459
|
-
charCount += nodeLength;
|
|
460
|
-
}
|
|
461
|
-
if (textNode) {
|
|
462
|
-
// 创建一个新的范围来替换文本
|
|
463
|
-
const tempRange = document.createRange();
|
|
464
|
-
tempRange.setStart(textNode, startOffset);
|
|
465
|
-
tempRange.setEnd(textNode, endOffset);
|
|
466
|
-
// 替换为 @type:
|
|
467
|
-
tempRange.deleteContents();
|
|
468
|
-
const typePrefix = document.createTextNode(`${mentionKeyword}${item.type}:`);
|
|
469
|
-
tempRange.insertNode(typePrefix);
|
|
470
|
-
// 将光标移到 @type: 后面
|
|
471
|
-
const newRange = document.createRange();
|
|
472
|
-
newRange.setStartAfter(typePrefix);
|
|
473
|
-
newRange.setEndAfter(typePrefix);
|
|
474
|
-
selection.removeAllRanges();
|
|
475
|
-
selection.addRange(newRange);
|
|
476
|
-
// 激活内联搜索模式
|
|
477
|
-
setMentionState((prev) => ({
|
|
478
|
-
...prev,
|
|
479
|
-
active: true,
|
|
480
|
-
level: 1,
|
|
481
|
-
parentType: item.id,
|
|
482
|
-
inlineSearchActive: true,
|
|
483
|
-
inlineSearchStartPos: getCursorPosition(editorRef.current),
|
|
484
|
-
secondLevelFilter: '',
|
|
485
|
-
activeIndex: 0,
|
|
486
|
-
}));
|
|
487
|
-
editorRef.current.focus();
|
|
488
|
-
return;
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
return;
|
|
492
|
-
}
|
|
493
|
-
const selection = window.getSelection();
|
|
494
|
-
if (!selection || !selection.rangeCount) {
|
|
495
|
-
return;
|
|
496
|
-
}
|
|
497
|
-
// 如果是在内联搜索模式下选择项目
|
|
498
|
-
if (mentionState.inlineSearchActive && mentionState.parentType && mentionState.inlineSearchStartPos !== null) {
|
|
499
|
-
// 找到 @type: 的位置
|
|
500
|
-
const parentItem = mentionItems.find((i) => i.id === mentionState.parentType);
|
|
501
|
-
if (!parentItem) {
|
|
502
|
-
return;
|
|
503
|
-
}
|
|
504
|
-
const typePrefix = `${mentionKeyword}${parentItem.type}:`;
|
|
505
|
-
const prefixPos = mentionState.inlineSearchStartPos - typePrefix.length;
|
|
506
|
-
if (prefixPos >= 0) {
|
|
507
|
-
// 创建一个带样式的提及标签
|
|
508
|
-
const mentionTag = document.createElement('span');
|
|
509
|
-
mentionTag.className = mention_input_module_less_1.default.mention_tag;
|
|
510
|
-
mentionTag.dataset.id = item.id;
|
|
511
|
-
mentionTag.dataset.type = item.type;
|
|
512
|
-
mentionTag.dataset.contextId = item.contextId || '';
|
|
513
|
-
mentionTag.contentEditable = 'false';
|
|
514
|
-
// 为 file 和 folder 类型添加图标
|
|
515
|
-
if (item.type === 'file' || item.type === 'folder') {
|
|
516
|
-
// 创建图标容器
|
|
517
|
-
const iconSpan = document.createElement('span');
|
|
518
|
-
iconSpan.className = (0, classnames_1.default)(mention_input_module_less_1.default.mention_icon, item.type === 'file' ? labelService === null || labelService === void 0 ? void 0 : labelService.getIcon(new ide_utils_1.URI(item.text)) : (0, components_1.getIcon)('folder'));
|
|
519
|
-
mentionTag.appendChild(iconSpan);
|
|
520
|
-
}
|
|
521
|
-
const workspace = workspaceService === null || workspaceService === void 0 ? void 0 : workspaceService.workspace;
|
|
522
|
-
let relativePath = item.text;
|
|
523
|
-
if (workspace && item.contextId) {
|
|
524
|
-
relativePath = item.contextId.replace(new ide_utils_1.URI(workspace.uri).codeUri.fsPath, '').slice(1);
|
|
525
|
-
}
|
|
526
|
-
// 创建文本内容容器
|
|
527
|
-
const textSpan = document.createTextNode(relativePath);
|
|
528
|
-
mentionTag.appendChild(textSpan);
|
|
529
|
-
// 创建一个范围从 @type: 开始到当前光标
|
|
530
|
-
const tempRange = document.createRange();
|
|
531
|
-
// 定位到 @type: 的位置
|
|
532
|
-
let charIndex = 0;
|
|
533
|
-
let foundStart = false;
|
|
534
|
-
const textNodes = [];
|
|
535
|
-
function findPosition(node) {
|
|
536
|
-
if (node.nodeType === 3) {
|
|
537
|
-
// 文本节点
|
|
538
|
-
textNodes.push({
|
|
539
|
-
node,
|
|
540
|
-
start: charIndex,
|
|
541
|
-
end: charIndex + node.textContent.length,
|
|
542
|
-
});
|
|
543
|
-
charIndex += node.textContent.length;
|
|
544
|
-
}
|
|
545
|
-
else if (node.nodeType === 1) {
|
|
546
|
-
// 元素节点
|
|
547
|
-
const children = node.childNodes || [];
|
|
548
|
-
for (const child of Array.from(children)) {
|
|
549
|
-
findPosition(child);
|
|
550
|
-
}
|
|
551
|
-
}
|
|
552
|
-
}
|
|
553
|
-
findPosition(editorRef.current);
|
|
554
|
-
for (const textNode of textNodes) {
|
|
555
|
-
if (prefixPos >= textNode.start && prefixPos <= textNode.end) {
|
|
556
|
-
const startOffset = prefixPos - textNode.start;
|
|
557
|
-
tempRange.setStart(textNode.node, startOffset);
|
|
558
|
-
foundStart = true;
|
|
559
|
-
}
|
|
560
|
-
if (foundStart) {
|
|
561
|
-
// 如果是点击触发,使用过滤文本的长度来确定结束位置
|
|
562
|
-
const cursorPos = isTriggerByClick
|
|
563
|
-
? prefixPos + typePrefix.length + mentionState.secondLevelFilter.length
|
|
564
|
-
: getCursorPosition(editorRef.current);
|
|
565
|
-
if (cursorPos >= textNode.start && cursorPos <= textNode.end) {
|
|
566
|
-
const endOffset = cursorPos - textNode.start;
|
|
567
|
-
tempRange.setEnd(textNode.node, endOffset);
|
|
568
|
-
break;
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
if (foundStart) {
|
|
573
|
-
tempRange.deleteContents();
|
|
574
|
-
tempRange.insertNode(mentionTag);
|
|
575
|
-
// 将光标移到提及标签后面
|
|
576
|
-
const newRange = document.createRange();
|
|
577
|
-
newRange.setStartAfter(mentionTag);
|
|
578
|
-
newRange.setEndAfter(mentionTag);
|
|
579
|
-
selection.removeAllRanges();
|
|
580
|
-
selection.addRange(newRange);
|
|
581
|
-
// 添加一个空格,增加间隔
|
|
582
|
-
const spaceNode = document.createTextNode('\u00A0'); // 使用不间断空格
|
|
583
|
-
newRange.insertNode(spaceNode);
|
|
584
|
-
newRange.setStartAfter(spaceNode);
|
|
585
|
-
newRange.setEndAfter(spaceNode);
|
|
586
|
-
selection.removeAllRanges();
|
|
587
|
-
selection.addRange(newRange);
|
|
588
|
-
}
|
|
589
|
-
setMentionState((prev) => ({
|
|
590
|
-
...prev,
|
|
591
|
-
active: false,
|
|
592
|
-
inlineSearchActive: false,
|
|
593
|
-
}));
|
|
594
|
-
editorRef.current.focus();
|
|
595
|
-
return;
|
|
596
|
-
}
|
|
597
|
-
}
|
|
598
|
-
// 原有的处理逻辑(用于非内联搜索情况)
|
|
599
|
-
// 创建一个带样式的提及标签
|
|
600
|
-
const mentionTag = document.createElement('span');
|
|
601
|
-
mentionTag.className = mention_input_module_less_1.default.mention_tag;
|
|
602
|
-
mentionTag.dataset.id = item.id;
|
|
603
|
-
mentionTag.dataset.type = item.type;
|
|
604
|
-
mentionTag.dataset.contextId = item.contextId || '';
|
|
605
|
-
mentionTag.contentEditable = 'false';
|
|
606
|
-
// 为 file 和 folder 类型添加图标
|
|
607
|
-
if (item.type === 'file' || item.type === 'folder') {
|
|
608
|
-
// 创建图标容器
|
|
609
|
-
const iconSpan = document.createElement('span');
|
|
610
|
-
iconSpan.className = (0, classnames_1.default)(mention_input_module_less_1.default.mention_icon, item.type === 'file' ? labelService === null || labelService === void 0 ? void 0 : labelService.getIcon(new ide_utils_1.URI(item.text)) : (0, components_1.getIcon)('folder'));
|
|
611
|
-
mentionTag.appendChild(iconSpan);
|
|
612
|
-
}
|
|
613
|
-
const workspace = workspaceService === null || workspaceService === void 0 ? void 0 : workspaceService.workspace;
|
|
614
|
-
let relativePath = item.text;
|
|
615
|
-
if (workspace && item.contextId) {
|
|
616
|
-
relativePath = item.contextId.replace(new ide_utils_1.URI(workspace.uri).codeUri.fsPath, '').slice(1);
|
|
617
|
-
}
|
|
618
|
-
// 创建文本内容容器
|
|
619
|
-
const textSpan = document.createTextNode(relativePath);
|
|
620
|
-
mentionTag.appendChild(textSpan);
|
|
621
|
-
// 定位到 @ 符号的位置
|
|
622
|
-
let charIndex = 0;
|
|
623
|
-
let foundStart = false;
|
|
624
|
-
const textNodes = [];
|
|
625
|
-
function findPosition(node) {
|
|
626
|
-
if (node.nodeType === 3) {
|
|
627
|
-
// 文本节点
|
|
628
|
-
textNodes.push({
|
|
629
|
-
node,
|
|
630
|
-
start: charIndex,
|
|
631
|
-
end: charIndex + node.textContent.length,
|
|
632
|
-
});
|
|
633
|
-
charIndex += node.textContent.length;
|
|
634
|
-
}
|
|
635
|
-
else if (node.nodeType === 1) {
|
|
636
|
-
// 元素节点
|
|
637
|
-
const children = node.childNodes;
|
|
638
|
-
for (const child of Array.from(children)) {
|
|
639
|
-
findPosition(child);
|
|
640
|
-
}
|
|
641
|
-
}
|
|
642
|
-
}
|
|
643
|
-
findPosition(editorRef.current);
|
|
644
|
-
const tempRange = document.createRange();
|
|
645
|
-
if (mentionState.startPos !== null) {
|
|
646
|
-
for (const textNode of textNodes) {
|
|
647
|
-
if (mentionState.startPos - 1 >= textNode.start && mentionState.startPos - 1 <= textNode.end) {
|
|
648
|
-
const startOffset = mentionState.startPos - 1 - textNode.start;
|
|
649
|
-
tempRange.setStart(textNode.node, startOffset);
|
|
650
|
-
foundStart = true;
|
|
651
|
-
}
|
|
652
|
-
if (foundStart) {
|
|
653
|
-
// 如果是点击触发,使用过滤文本的长度来确定结束位置
|
|
654
|
-
const cursorPos = isTriggerByClick
|
|
655
|
-
? mentionState.startPos + mentionState.filter.length - 1
|
|
656
|
-
: getCursorPosition(editorRef.current);
|
|
657
|
-
if (cursorPos >= textNode.start && cursorPos <= textNode.end) {
|
|
658
|
-
const endOffset = cursorPos - textNode.start;
|
|
659
|
-
tempRange.setEnd(textNode.node, endOffset);
|
|
660
|
-
break;
|
|
661
|
-
}
|
|
662
|
-
}
|
|
663
|
-
}
|
|
664
|
-
}
|
|
665
|
-
if (foundStart) {
|
|
666
|
-
tempRange.deleteContents();
|
|
667
|
-
tempRange.insertNode(mentionTag);
|
|
668
|
-
// 将光标移到提及标签后面
|
|
669
|
-
const newRange = document.createRange();
|
|
670
|
-
newRange.setStartAfter(mentionTag);
|
|
671
|
-
newRange.setEndAfter(mentionTag);
|
|
672
|
-
selection.removeAllRanges();
|
|
673
|
-
selection.addRange(newRange);
|
|
674
|
-
// 添加一个空格,增加间隔
|
|
675
|
-
const spaceNode = document.createTextNode('\u00A0'); // 使用不间断空格
|
|
676
|
-
newRange.insertNode(spaceNode);
|
|
677
|
-
newRange.setStartAfter(spaceNode);
|
|
678
|
-
newRange.setEndAfter(spaceNode);
|
|
679
|
-
selection.removeAllRanges();
|
|
680
|
-
selection.addRange(newRange);
|
|
681
|
-
}
|
|
682
|
-
setMentionState((prev) => ({ ...prev, active: false }));
|
|
683
|
-
editorRef.current.focus();
|
|
684
|
-
};
|
|
685
|
-
// 处理模型选择变更
|
|
686
|
-
const handleModelChange = React.useCallback((value) => {
|
|
687
|
-
setSelectedModel(value);
|
|
688
|
-
onSelectionChange === null || onSelectionChange === void 0 ? void 0 : onSelectionChange(value);
|
|
689
|
-
}, [selectedModel, onSelectionChange]);
|
|
690
|
-
// 修改 handleSend 函数
|
|
691
|
-
const handleSend = () => {
|
|
692
|
-
if (!editorRef.current) {
|
|
693
|
-
return;
|
|
694
|
-
}
|
|
695
|
-
// 获取原始HTML内容
|
|
696
|
-
const rawContent = editorRef.current.innerHTML;
|
|
697
|
-
if (!rawContent) {
|
|
698
|
-
return;
|
|
699
|
-
}
|
|
700
|
-
// 创建一个临时元素来处理内容
|
|
701
|
-
const tempDiv = document.createElement('div');
|
|
702
|
-
tempDiv.innerHTML = rawContent;
|
|
703
|
-
// 查找所有提及标签并替换为对应的contextId
|
|
704
|
-
const mentionTags = tempDiv.querySelectorAll(`.${mention_input_module_less_1.default.mention_tag}`);
|
|
705
|
-
mentionTags.forEach((tag) => {
|
|
706
|
-
var _a;
|
|
707
|
-
const contextId = tag.getAttribute('data-context-id');
|
|
708
|
-
if (contextId) {
|
|
709
|
-
// 替换为contextId
|
|
710
|
-
const replacement = document.createTextNode(`{{${mentionKeyword}${tag.getAttribute('data-type')}:${contextId}}}`);
|
|
711
|
-
// 替换内容
|
|
712
|
-
(_a = tag.parentNode) === null || _a === void 0 ? void 0 : _a.replaceChild(replacement, tag);
|
|
713
|
-
}
|
|
714
|
-
});
|
|
715
|
-
// 获取处理后的内容
|
|
716
|
-
let processedContent = tempDiv.innerHTML;
|
|
717
|
-
processedContent = processedContent.trim().replaceAll(exports.WHITE_SPACE_TEXT, ' ');
|
|
718
|
-
// 添加到历史记录
|
|
719
|
-
if (rawContent) {
|
|
720
|
-
setHistory((prev) => [...prev, rawContent]);
|
|
721
|
-
// 重置历史导航状态
|
|
722
|
-
setHistoryIndex(-1);
|
|
723
|
-
setIsNavigatingHistory(false);
|
|
724
|
-
}
|
|
725
|
-
if (onSend) {
|
|
726
|
-
// 传递当前选择的模型和其他配置信息
|
|
727
|
-
onSend(processedContent, {
|
|
728
|
-
model: selectedModel,
|
|
729
|
-
...footerConfig,
|
|
730
|
-
});
|
|
731
|
-
}
|
|
732
|
-
editorRef.current.innerHTML = '';
|
|
733
|
-
// 重置编辑器高度和滚动条
|
|
734
|
-
if (editorRef.current) {
|
|
735
|
-
editorRef.current.style.overflowY = 'hidden';
|
|
736
|
-
editorRef.current.style.height = 'auto';
|
|
737
|
-
}
|
|
738
|
-
};
|
|
739
|
-
const handleStop = React.useCallback(() => {
|
|
740
|
-
if (onStop) {
|
|
741
|
-
onStop();
|
|
742
|
-
}
|
|
743
|
-
}, [onStop]);
|
|
744
|
-
// 渲染自定义按钮
|
|
745
|
-
const renderButtons = React.useCallback((position) => (footerConfig.buttons || [])
|
|
746
|
-
.filter((button) => button.position === position)
|
|
747
|
-
.map((button) => (React.createElement(components_1.Popover, { key: button.id, overlayClassName: mention_input_module_less_1.default.popover_icon, id: `ai-chat-${button.id}`, position: components_1.PopoverPosition.top, title: button.title },
|
|
748
|
-
React.createElement(ai_native_1.EnhanceIcon, { className: (0, classnames_1.default)((0, components_1.getIcon)(button.icon), mention_input_module_less_1.default[`${button.id}_logo`]), tabIndex: 0, role: 'button', ariaLabel: button.title, onClick: button.onClick })))), [footerConfig.buttons]);
|
|
749
|
-
return (React.createElement("div", { className: mention_input_module_less_1.default.input_container },
|
|
750
|
-
mentionState.active && (React.createElement("div", { className: mention_input_module_less_1.default.mention_panel_container },
|
|
751
|
-
React.createElement(mention_panel_1.MentionPanel, { items: getCurrentItems(), activeIndex: mentionState.activeIndex, onSelectItem: (item) => handleSelectItem(item, true), position: { top: 0, left: 0 }, filter: mentionState.level === 0 ? mentionState.filter : mentionState.secondLevelFilter, visible: true, level: mentionState.level, loading: mentionState.loading }))),
|
|
752
|
-
React.createElement("div", { className: mention_input_module_less_1.default.editor_area },
|
|
753
|
-
React.createElement("div", { ref: editorRef, className: mention_input_module_less_1.default.editor, contentEditable: true, onInput: handleInput, onKeyDown: handleKeyDown, onCompositionEnd: handleCompositionEnd })),
|
|
754
|
-
React.createElement("div", { className: mention_input_module_less_1.default.footer },
|
|
755
|
-
React.createElement("div", { className: mention_input_module_less_1.default.left_control },
|
|
756
|
-
footerConfig.showModelSelector && (React.createElement(components_1.Select, { options: footerConfig.modelOptions || [], value: selectedModel, onChange: handleModelChange, className: mention_input_module_less_1.default.model_selector, size: 'small' })),
|
|
757
|
-
renderButtons(types_1.FooterButtonPosition.LEFT)),
|
|
758
|
-
React.createElement("div", { className: mention_input_module_less_1.default.right_control },
|
|
759
|
-
renderButtons(types_1.FooterButtonPosition.RIGHT),
|
|
760
|
-
React.createElement(components_1.Popover, { overlayClassName: mention_input_module_less_1.default.popover_icon, id: 'ai-chat-send', position: components_1.PopoverPosition.top, content: !loading ? 'Send' : 'Stop' }, !loading ? (React.createElement(ai_native_1.EnhanceIcon, { wrapperClassName: mention_input_module_less_1.default.send_logo, className: (0, classnames_1.default)((0, components_1.getIcon)('send-outlined'), mention_input_module_less_1.default.send_logo_icon), tabIndex: 0, role: 'button', onClick: handleSend, ariaLabel: 'Send' })) : (React.createElement(ai_native_1.EnhanceIcon, { wrapperClassName: mention_input_module_less_1.default.stop_logo, className: (0, classnames_1.default)((0, components_1.getIcon)('stop'), mention_input_module_less_1.default.stop_logo_icon), tabIndex: 0, role: 'button', ariaLabel: 'Stop', onClick: handleStop })))))));
|
|
761
|
-
};
|
|
762
|
-
exports.MentionInput = MentionInput;
|
|
763
|
-
//# sourceMappingURL=mention-input.js.map
|