one-design-next 0.0.13 → 0.0.15
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/_genui-types.d.ts +72 -27
- package/dist/action-bar/style/index.css +2 -2
- package/dist/agent-step/style/index.css +1 -1
- package/dist/attachments/style/index.css +5 -5
- package/dist/chat-item/style/index.css +2 -2
- package/dist/composer/clipboard.d.ts +1 -1
- package/dist/composer/editor.d.ts +10 -2
- package/dist/composer/editor.js +199 -35
- package/dist/composer/hooks/useChipManager.d.ts +8 -3
- package/dist/composer/hooks/useChipManager.js +105 -10
- package/dist/composer/index.d.ts +17 -2
- package/dist/composer/index.js +136 -65
- package/dist/composer/inline-ref.d.ts +6 -2
- package/dist/composer/inline-ref.js +10 -3
- package/dist/composer/param-panel.d.ts +14 -0
- package/dist/composer/param-panel.js +1 -0
- package/dist/composer/segments.d.ts +29 -0
- package/dist/composer/segments.js +83 -0
- package/dist/composer/send-meta.d.ts +7 -4
- package/dist/composer/send-meta.js +12 -52
- package/dist/composer/style/index.css +27 -8
- package/dist/composer/utils.d.ts +35 -1
- package/dist/composer/utils.js +281 -36
- package/dist/fab/style/index.css +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +4 -2
- package/dist/invocation/index.d.ts +7 -2
- package/dist/invocation/index.js +14 -8
- package/dist/invocation/param-popover.d.ts +21 -0
- package/dist/invocation/param-popover.js +113 -0
- package/dist/invocation/style/index.css +33 -9
- package/dist/mention/index.d.ts +1 -6
- package/dist/mention/index.js +11 -8
- package/dist/mention/style/index.css +30 -9
- package/dist/preview-panel/index.js +11 -1
- package/dist/preview-panel/style/index.css +11 -0
- package/dist/skill-slot/index.js +5 -5
- package/dist/skill-slot/style/index.css +51 -27
- package/dist/suggestions/index.js +1 -5
- package/dist/suggestions/style/index.css +6 -7
- package/dist/user-bubble/index.js +9 -4
- package/dist/user-bubble/render-segments.d.ts +9 -0
- package/dist/user-bubble/render-segments.js +42 -0
- package/dist/user-bubble/style/index.css +9 -0
- package/dist/welcome/style/index.css +1 -1
- package/package.json +4 -4
- package/dist/composer/chip.d.ts +0 -36
- package/dist/composer/chip.js +0 -49
|
@@ -27,11 +27,11 @@
|
|
|
27
27
|
transition: border-color 0.15s;
|
|
28
28
|
}
|
|
29
29
|
[data-odn-composer-box]:focus-within {
|
|
30
|
-
border-color: color-mix(in srgb, var(--odn-color-
|
|
30
|
+
border-color: color-mix(in srgb, var(--odn-color-brand-6) 50%, transparent);
|
|
31
31
|
}
|
|
32
32
|
[data-odn-composer-box][data-odn-composer-file-drag] {
|
|
33
|
-
border-color: color-mix(in srgb, var(--odn-color-
|
|
34
|
-
background: color-mix(in srgb, var(--odn-color-
|
|
33
|
+
border-color: color-mix(in srgb, var(--odn-color-brand-6) 60%, transparent);
|
|
34
|
+
background: color-mix(in srgb, var(--odn-color-brand-6) 6%, var(--odn-color-bg-elevated));
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
/* ------------------------------------------------------------------
|
|
@@ -225,6 +225,25 @@
|
|
|
225
225
|
vertical-align: baseline;
|
|
226
226
|
}
|
|
227
227
|
|
|
228
|
+
/* editor 内跟随正文 inherit,避免与外层 14/24 双写冲突。
|
|
229
|
+
* 同时收紧 chip 视觉间距:
|
|
230
|
+
* - 取消组件默认 margin(否则 text↔chip / chip↔chip 都会被双边叠加拉宽)
|
|
231
|
+
* - 下调横向 padding,保留可点击热区但减少“透明留白”观感 */
|
|
232
|
+
[data-odn-composer] [data-odn-composer-editor] [data-odn-invocation],
|
|
233
|
+
[data-odn-composer] [data-odn-composer-editor] [data-odn-mention] {
|
|
234
|
+
margin-inline: 1px;
|
|
235
|
+
padding-left: 2px;
|
|
236
|
+
padding-right: 2px;
|
|
237
|
+
font-size: inherit;
|
|
238
|
+
line-height: inherit;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/* 键盘输入模态:鼠标会被隐藏,此时不应沿用旧鼠标位置触发 hover 态。 */
|
|
242
|
+
[data-odn-composer] [data-odn-composer-editor][data-odn-input-modality=keyboard] [data-odn-invocation]:hover:not([data-state=active]),
|
|
243
|
+
[data-odn-composer] [data-odn-composer-editor][data-odn-input-modality=keyboard] [data-odn-mention]:hover:not([data-state=active]) {
|
|
244
|
+
background: transparent;
|
|
245
|
+
}
|
|
246
|
+
|
|
228
247
|
/* chip 在 contentEditable=false 下无原生 selection 高亮,自绘选中态 */
|
|
229
248
|
[data-odn-composer] [data-odn-composer-chip-host][data-selected] [data-odn-invocation],
|
|
230
249
|
[data-odn-composer] [data-odn-composer-chip-host][data-selected] [data-odn-mention] {
|
|
@@ -303,9 +322,9 @@
|
|
|
303
322
|
transition: opacity 0.15s;
|
|
304
323
|
}
|
|
305
324
|
[data-odn-composer-tool-btn][data-odn-composer-tool-active] {
|
|
306
|
-
color: var(--odn-color-
|
|
325
|
+
color: var(--odn-color-brand-6);
|
|
307
326
|
font-weight: 600;
|
|
308
|
-
background: color-mix(in srgb, var(--odn-color-
|
|
327
|
+
background: color-mix(in srgb, var(--odn-color-brand-6) 10%, transparent);
|
|
309
328
|
}
|
|
310
329
|
[data-odn-composer-tool-btn][data-odn-composer-tool-active]::before {
|
|
311
330
|
opacity: 1;
|
|
@@ -321,11 +340,11 @@
|
|
|
321
340
|
height: 16px;
|
|
322
341
|
margin-left: 2px;
|
|
323
342
|
border-radius: 4px;
|
|
324
|
-
color: color-mix(in srgb, var(--odn-color-
|
|
343
|
+
color: color-mix(in srgb, var(--odn-color-brand-6) 70%, transparent);
|
|
325
344
|
transition: color 0.15s;
|
|
326
345
|
}
|
|
327
346
|
[data-odn-composer-skill-clear]:hover {
|
|
328
|
-
color: var(--odn-color-
|
|
347
|
+
color: var(--odn-color-brand-6);
|
|
329
348
|
}
|
|
330
349
|
[data-odn-composer-skill-clear] [data-odn-hover-fill-content] {
|
|
331
350
|
display: inline-flex;
|
|
@@ -350,7 +369,7 @@
|
|
|
350
369
|
padding: 0;
|
|
351
370
|
border-radius: 6px;
|
|
352
371
|
border: none;
|
|
353
|
-
background-color: var(--odn-color-
|
|
372
|
+
background-color: var(--odn-color-brand-6);
|
|
354
373
|
color: #fff;
|
|
355
374
|
cursor: pointer;
|
|
356
375
|
transition: opacity 0.15s;
|
package/dist/composer/utils.d.ts
CHANGED
|
@@ -9,8 +9,10 @@
|
|
|
9
9
|
*
|
|
10
10
|
* @ / / 触发判定(getTriggerContext)放在 step 4 一起加。
|
|
11
11
|
*/
|
|
12
|
-
/** Zero Width Space (U+200B)
|
|
12
|
+
/** Zero Width Space (U+200B):仅用于 marker 包裹。 */
|
|
13
13
|
export declare const ZWSP = "\u200B";
|
|
14
|
+
/** Zero Width No-Break Space (U+FEFF):仅用于 caret 锚点(chip 后 spacer)。 */
|
|
15
|
+
export declare const CARET_SPACER = "\uFEFF";
|
|
14
16
|
/** Invisible Separator (U+2063):包裹 marker 的 id,业务文本不会出现。 */
|
|
15
17
|
export declare const SEP = "\u2063";
|
|
16
18
|
export declare function stripInvisibleChars(s: string): string;
|
|
@@ -63,6 +65,25 @@ export declare function getPlainText(editor: HTMLElement, chipIdAttr?: string):
|
|
|
63
65
|
* 空格 / 全角空格也算"已输入",只要文本非空就该收起 placeholder。
|
|
64
66
|
*/
|
|
65
67
|
export declare function isEditorEmpty(editor: HTMLElement, chipIdAttr?: string): boolean;
|
|
68
|
+
export declare const isZwspText: (n: Node | null | undefined) => n is Text;
|
|
69
|
+
/** chip 后插入(或复用)独立 spacer text node,供 caret 落点与方向键 helper 识别。 */
|
|
70
|
+
export declare function attachCaretSpacerAfter(host: HTMLElement): Text;
|
|
71
|
+
/** 删除 chip 时一并移除紧随的 ZWSP 锚点(仅整 node 为 ZWSP 时删,避免误伤合并 text)。 */
|
|
72
|
+
export declare function detachCaretSpacerAfter(host: HTMLElement): void;
|
|
73
|
+
/**
|
|
74
|
+
* 把 element-boundary caret 位置规范为 text-node caret:
|
|
75
|
+
* - 若 offset 左侧已经是 text node,落到该 text 末尾
|
|
76
|
+
* - 否则在 offset 位置插入一个 caret spacer text,并落到 offset=1
|
|
77
|
+
*/
|
|
78
|
+
export declare function ensureTextAnchorAt(parent: Node, offset: number): {
|
|
79
|
+
node: Text;
|
|
80
|
+
offset: number;
|
|
81
|
+
} | null;
|
|
82
|
+
/**
|
|
83
|
+
* 清理行首浏览器占位:leading `<br>` / 空 text / 孤立 ZWSP(紧邻 chip 前)。
|
|
84
|
+
* 返回是否改过 DOM;若 caret 落在被删节点上,恢复到 editor 起点或首个 chip 前。
|
|
85
|
+
*/
|
|
86
|
+
export declare function normalizeComposerEditorDom(editor: HTMLElement, chipIdAttr?: string): boolean;
|
|
66
87
|
/**
|
|
67
88
|
* caret 视觉是否紧邻某个 chip 后方?返回该 chip,否则 null。
|
|
68
89
|
* 用于 Backspace 整块删 + ArrowLeft 跨过 chip。
|
|
@@ -86,6 +107,19 @@ export declare function resolveCaretJumpAroundChip(range: Range, direction: 'lef
|
|
|
86
107
|
node: Node;
|
|
87
108
|
offset: number;
|
|
88
109
|
} | null;
|
|
110
|
+
export declare function childIndex(node: Node): number;
|
|
111
|
+
/** chip 之前的可见纯文本(不含 marker / 不可见字符)。 */
|
|
112
|
+
export declare function getVisibleTextBeforeHost(editor: HTMLElement, host: HTMLElement, chipIdAttr?: string): string;
|
|
113
|
+
/**
|
|
114
|
+
* 清理 contenteditable 删字后的幽灵节点:空 text、仅 chip 时的占位 <br>。
|
|
115
|
+
* 避免「文字 + invocation」删光文字后出现多余换行,以及 caret 卡在 chip 后误删 invocation。
|
|
116
|
+
*/
|
|
117
|
+
export declare function normalizeEditorDom(editor: HTMLElement, _chipIdAttr?: string): void;
|
|
118
|
+
/** caret 落在 chip 后空 text 时,挪到 chip 前(不删 chip)。 */
|
|
119
|
+
export declare function moveCaretBeforeChip(host: HTMLElement, opts?: {
|
|
120
|
+
removeTrailingEmptyText?: boolean;
|
|
121
|
+
trailingText?: Text | null;
|
|
122
|
+
}): void;
|
|
89
123
|
export interface TriggerProbe {
|
|
90
124
|
/** 触发字符 */
|
|
91
125
|
trigger: string;
|
package/dist/composer/utils.js
CHANGED
|
@@ -17,8 +17,10 @@ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len
|
|
|
17
17
|
* Marker · 用零宽字符把 mention id 写入纯文本
|
|
18
18
|
* ──────────────────────────────────────────────────────────────────── */
|
|
19
19
|
|
|
20
|
-
/** Zero Width Space (U+200B)
|
|
20
|
+
/** Zero Width Space (U+200B):仅用于 marker 包裹。 */
|
|
21
21
|
export var ZWSP = "\u200B";
|
|
22
|
+
/** Zero Width No-Break Space (U+FEFF):仅用于 caret 锚点(chip 后 spacer)。 */
|
|
23
|
+
export var CARET_SPACER = "\uFEFF";
|
|
22
24
|
|
|
23
25
|
/** Invisible Separator (U+2063):包裹 marker 的 id,业务文本不会出现。 */
|
|
24
26
|
export var SEP = "\u2063";
|
|
@@ -29,11 +31,14 @@ var escapeRe = function escapeRe(s) {
|
|
|
29
31
|
};
|
|
30
32
|
var MARKER_RE = new RegExp("".concat(escapeRe(MARKER_OPEN), "([^").concat(SEP, "]+)").concat(escapeRe(MARKER_CLOSE)), 'g');
|
|
31
33
|
|
|
32
|
-
/** 从用户可见文本中剔除
|
|
33
|
-
var INVISIBLE_RE = new RegExp("[".concat(ZWSP).concat(SEP, "]"), 'g');
|
|
34
|
+
/** 从用户可见文本中剔除 marker/锚点不可见字符。 */
|
|
35
|
+
var INVISIBLE_RE = new RegExp("[".concat(ZWSP).concat(CARET_SPACER).concat(SEP, "]"), 'g');
|
|
34
36
|
export function stripInvisibleChars(s) {
|
|
35
37
|
return s.replace(INVISIBLE_RE, '');
|
|
36
38
|
}
|
|
39
|
+
var isCaretSpacerChar = function isCaretSpacerChar(ch) {
|
|
40
|
+
return ch === CARET_SPACER || ch === ZWSP;
|
|
41
|
+
};
|
|
37
42
|
|
|
38
43
|
/** 把 mention id 包成 marker token,插入 value 的 string 里。 */
|
|
39
44
|
export function createMarker(id) {
|
|
@@ -184,6 +189,143 @@ var kebab = function kebab(s) {
|
|
|
184
189
|
return "-".concat(m.toLowerCase());
|
|
185
190
|
});
|
|
186
191
|
};
|
|
192
|
+
var makeIsHost = function makeIsHost(chipIdAttr) {
|
|
193
|
+
return function (el) {
|
|
194
|
+
return el instanceof HTMLElement && el.dataset[chipIdAttr] !== undefined;
|
|
195
|
+
};
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
/* ────────────────────────────────────────────────────────────────────
|
|
199
|
+
* DOM 不变量 · chip 后 ZWSP 锚点 + 行首占位清理
|
|
200
|
+
*
|
|
201
|
+
* contentEditable=false 的 chip 顶在行首时,浏览器常会塞占位 <br>,删光前文后
|
|
202
|
+
* invocation 会「掉到第二行」。chip 后固定插 ZWSP(caret 锚点),input 时剥掉
|
|
203
|
+
* chip 前的 leading <br> / 空 text node。
|
|
204
|
+
* ──────────────────────────────────────────────────────────────────── */
|
|
205
|
+
|
|
206
|
+
export var isZwspText = function isZwspText(n) {
|
|
207
|
+
var _n$textContent;
|
|
208
|
+
return !!n && n.nodeType === Node.TEXT_NODE && isCaretSpacerChar((_n$textContent = n.textContent) !== null && _n$textContent !== void 0 ? _n$textContent : '');
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
/** chip 后插入(或复用)独立 spacer text node,供 caret 落点与方向键 helper 识别。 */
|
|
212
|
+
export function attachCaretSpacerAfter(host) {
|
|
213
|
+
var _host$parentNode;
|
|
214
|
+
var next = host.nextSibling;
|
|
215
|
+
if (isZwspText(next)) return next;
|
|
216
|
+
var spacer = document.createTextNode(CARET_SPACER);
|
|
217
|
+
(_host$parentNode = host.parentNode) === null || _host$parentNode === void 0 || _host$parentNode.insertBefore(spacer, host.nextSibling);
|
|
218
|
+
return spacer;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/** 删除 chip 时一并移除紧随的 ZWSP 锚点(仅整 node 为 ZWSP 时删,避免误伤合并 text)。 */
|
|
222
|
+
export function detachCaretSpacerAfter(host) {
|
|
223
|
+
var next = host.nextSibling;
|
|
224
|
+
if (isZwspText(next)) next.remove();
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* 把 element-boundary caret 位置规范为 text-node caret:
|
|
229
|
+
* - 若 offset 左侧已经是 text node,落到该 text 末尾
|
|
230
|
+
* - 否则在 offset 位置插入一个 caret spacer text,并落到 offset=1
|
|
231
|
+
*/
|
|
232
|
+
export function ensureTextAnchorAt(parent, offset) {
|
|
233
|
+
var _parent$childNodes$sa;
|
|
234
|
+
var len = parent.childNodes.length;
|
|
235
|
+
var safeOffset = Math.max(0, Math.min(offset, len));
|
|
236
|
+
var left = parent.childNodes[safeOffset - 1];
|
|
237
|
+
if ((left === null || left === void 0 ? void 0 : left.nodeType) === Node.TEXT_NODE) {
|
|
238
|
+
var _t$textContent;
|
|
239
|
+
var t = left;
|
|
240
|
+
return {
|
|
241
|
+
node: t,
|
|
242
|
+
offset: ((_t$textContent = t.textContent) !== null && _t$textContent !== void 0 ? _t$textContent : '').length
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
var ref = (_parent$childNodes$sa = parent.childNodes[safeOffset]) !== null && _parent$childNodes$sa !== void 0 ? _parent$childNodes$sa : null;
|
|
246
|
+
var spacer = document.createTextNode(CARET_SPACER);
|
|
247
|
+
parent.insertBefore(spacer, ref);
|
|
248
|
+
return {
|
|
249
|
+
node: spacer,
|
|
250
|
+
offset: 1
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* 清理行首浏览器占位:leading `<br>` / 空 text / 孤立 ZWSP(紧邻 chip 前)。
|
|
256
|
+
* 返回是否改过 DOM;若 caret 落在被删节点上,恢复到 editor 起点或首个 chip 前。
|
|
257
|
+
*/
|
|
258
|
+
export function normalizeComposerEditorDom(editor) {
|
|
259
|
+
var chipIdAttr = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'mentionId';
|
|
260
|
+
var isHost = makeIsHost(chipIdAttr);
|
|
261
|
+
var nodeStartsWithChip = function nodeStartsWithChip(n) {
|
|
262
|
+
if (!n) return false;
|
|
263
|
+
if (isHost(n)) return true;
|
|
264
|
+
if (isZwspText(n) && isHost(n.nextSibling)) return true;
|
|
265
|
+
return false;
|
|
266
|
+
};
|
|
267
|
+
var isRemovableLeading = function isRemovableLeading(n) {
|
|
268
|
+
if (n.nodeType === Node.ELEMENT_NODE && n.tagName === 'BR') return true;
|
|
269
|
+
if (n.nodeType === Node.TEXT_NODE) {
|
|
270
|
+
var _n$textContent2;
|
|
271
|
+
return stripInvisibleChars((_n$textContent2 = n.textContent) !== null && _n$textContent2 !== void 0 ? _n$textContent2 : '') === '';
|
|
272
|
+
}
|
|
273
|
+
return false;
|
|
274
|
+
};
|
|
275
|
+
var sel = window.getSelection();
|
|
276
|
+
var saved = sel && sel.rangeCount > 0 && sel.isCollapsed && editor.contains(sel.anchorNode) ? {
|
|
277
|
+
node: sel.anchorNode,
|
|
278
|
+
offset: sel.anchorOffset
|
|
279
|
+
} : null;
|
|
280
|
+
var mutated = false;
|
|
281
|
+
while (editor.firstChild) {
|
|
282
|
+
var first = editor.firstChild;
|
|
283
|
+
if (isRemovableLeading(first) && nodeStartsWithChip(first.nextSibling)) {
|
|
284
|
+
first.remove();
|
|
285
|
+
mutated = true;
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
break;
|
|
289
|
+
}
|
|
290
|
+
var chipHosts = Array.from(editor.querySelectorAll("[data-".concat(kebab(chipIdAttr), "]")));
|
|
291
|
+
for (var _i3 = 0, _chipHosts = chipHosts; _i3 < _chipHosts.length; _i3++) {
|
|
292
|
+
var el = _chipHosts[_i3];
|
|
293
|
+
if (!isZwspText(el.nextSibling)) {
|
|
294
|
+
attachCaretSpacerAfter(el);
|
|
295
|
+
mutated = true;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
if (mutated && saved && (!saved.node.isConnected || !editor.contains(saved.node))) {
|
|
299
|
+
restoreCaretAtEditorStart(editor, chipIdAttr);
|
|
300
|
+
}
|
|
301
|
+
return mutated;
|
|
302
|
+
}
|
|
303
|
+
function restoreCaretAtEditorStart(editor, chipIdAttr) {
|
|
304
|
+
var sel = window.getSelection();
|
|
305
|
+
if (!sel) return;
|
|
306
|
+
var isHost = makeIsHost(chipIdAttr);
|
|
307
|
+
var r = document.createRange();
|
|
308
|
+
var first = editor.firstChild;
|
|
309
|
+
if (!first) {
|
|
310
|
+
r.setStart(editor, 0);
|
|
311
|
+
} else if (first.nodeType === Node.TEXT_NODE) {
|
|
312
|
+
var _first$textContent;
|
|
313
|
+
var text = (_first$textContent = first.textContent) !== null && _first$textContent !== void 0 ? _first$textContent : '';
|
|
314
|
+
r.setStart(first, text.length > 0 && isCaretSpacerChar(text[0]) ? 1 : 0);
|
|
315
|
+
} else {
|
|
316
|
+
var anchor = ensureTextAnchorAt(editor, 0);
|
|
317
|
+
if (anchor) {
|
|
318
|
+
r.setStart(anchor.node, anchor.offset);
|
|
319
|
+
} else if (isHost(first)) {
|
|
320
|
+
r.setStart(editor, 0);
|
|
321
|
+
} else {
|
|
322
|
+
r.setStart(editor, 0);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
r.collapse(true);
|
|
326
|
+
sel.removeAllRanges();
|
|
327
|
+
sel.addRange(r);
|
|
328
|
+
}
|
|
187
329
|
|
|
188
330
|
/* ────────────────────────────────────────────────────────────────────
|
|
189
331
|
* Cursor helpers · chip 边界判定
|
|
@@ -201,16 +343,6 @@ var kebab = function kebab(s) {
|
|
|
201
343
|
* 多按一次」「两 chip 之间又卡一下」的体验问题。
|
|
202
344
|
* ──────────────────────────────────────────────────────────────────── */
|
|
203
345
|
|
|
204
|
-
var isZwspText = function isZwspText(n) {
|
|
205
|
-
var _n$textContent;
|
|
206
|
-
return !!n && n.nodeType === Node.TEXT_NODE && ((_n$textContent = n.textContent) !== null && _n$textContent !== void 0 ? _n$textContent : '') === ZWSP;
|
|
207
|
-
};
|
|
208
|
-
var makeIsHost = function makeIsHost(chipIdAttr) {
|
|
209
|
-
return function (el) {
|
|
210
|
-
return el instanceof HTMLElement && el.dataset[chipIdAttr] !== undefined;
|
|
211
|
-
};
|
|
212
|
-
};
|
|
213
|
-
|
|
214
346
|
/**
|
|
215
347
|
* caret 视觉是否紧邻某个 chip 后方?返回该 chip,否则 null。
|
|
216
348
|
* 用于 Backspace 整块删 + ArrowLeft 跨过 chip。
|
|
@@ -233,7 +365,7 @@ export function findChipHostBeforeCaret(range) {
|
|
|
233
365
|
}
|
|
234
366
|
// (a) caret 紧贴 text 开头的 ZWSP(含 ZWSP 与后续输入合并的场景,如 '\u200babc')
|
|
235
367
|
// 视觉位置 = chip 之后,应让 Backspace / ← 一次跨过 chip
|
|
236
|
-
if (text[0]
|
|
368
|
+
if (isCaretSpacerChar(text[0]) && (offset === 0 || offset === 1) && isHost(node.previousSibling)) {
|
|
237
369
|
return node.previousSibling;
|
|
238
370
|
}
|
|
239
371
|
return null;
|
|
@@ -272,9 +404,12 @@ export function findChipHostAfterCaret(range) {
|
|
|
272
404
|
return node.nextSibling.nextSibling;
|
|
273
405
|
}
|
|
274
406
|
}
|
|
275
|
-
//
|
|
276
|
-
|
|
277
|
-
|
|
407
|
+
// 独立 ZWSP 节点:仅 offset=1(紧贴下一 chip 前缘)才算「caret 在 chip 前」
|
|
408
|
+
if (text.length === 1 && isCaretSpacerChar(text[0]) && offset === 1 && isHost(node.nextSibling)) {
|
|
409
|
+
return node.nextSibling;
|
|
410
|
+
}
|
|
411
|
+
// 合并 text(spacer + 正文):offset=1 且下一 sibling 是 chip
|
|
412
|
+
if (text.length > 1 && isCaretSpacerChar(text[0]) && offset === 1 && isHost(node.nextSibling)) {
|
|
278
413
|
return node.nextSibling;
|
|
279
414
|
}
|
|
280
415
|
return null;
|
|
@@ -283,10 +418,6 @@ export function findChipHostAfterCaret(range) {
|
|
|
283
418
|
var el = node;
|
|
284
419
|
var next = el.childNodes[offset];
|
|
285
420
|
if (isHost(next)) return next;
|
|
286
|
-
// chip + ZWSP 链:next 是 ZWSP,再后一个是 chip
|
|
287
|
-
if (isZwspText(next) && isHost(next.nextSibling)) {
|
|
288
|
-
return next.nextSibling;
|
|
289
|
-
}
|
|
290
421
|
}
|
|
291
422
|
return null;
|
|
292
423
|
}
|
|
@@ -301,16 +432,56 @@ export function findChipHostAfterCaret(range) {
|
|
|
301
432
|
* 返回 null 表示无需介入;调用方按浏览器默认处理即可。
|
|
302
433
|
*/
|
|
303
434
|
export function resolveCaretJumpAroundChip(range, direction) {
|
|
435
|
+
var _node$textContent4;
|
|
304
436
|
var chipIdAttr = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'mentionId';
|
|
437
|
+
var isHost = makeIsHost(chipIdAttr);
|
|
438
|
+
var node = range.startContainer,
|
|
439
|
+
offset = range.startOffset;
|
|
440
|
+
|
|
441
|
+
/* spacer 内微步:仅保留 ArrowRight 的 0→1。
|
|
442
|
+
* ArrowLeft 在 chip 右侧一律直接跨到 chip 左侧,避免任何“卡一下”。 */
|
|
443
|
+
if (node.nodeType === Node.TEXT_NODE && isCaretSpacerChar((_node$textContent4 = node.textContent) !== null && _node$textContent4 !== void 0 ? _node$textContent4 : '')) {
|
|
444
|
+
if (direction === 'right' && offset === 0) {
|
|
445
|
+
return {
|
|
446
|
+
node: node,
|
|
447
|
+
offset: 1
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
if (direction === 'left' && offset === 1) {
|
|
451
|
+
var _chip = findChipHostBeforeCaret(range, chipIdAttr);
|
|
452
|
+
if (!_chip) return null;
|
|
453
|
+
var _parent = _chip.parentNode;
|
|
454
|
+
if (!_parent) return null;
|
|
455
|
+
return ensureTextAnchorAt(_parent, childIndex(_chip));
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
459
|
+
var el = node;
|
|
460
|
+
if (direction === 'right') {
|
|
461
|
+
var next = el.childNodes[offset];
|
|
462
|
+
if (isZwspText(next)) {
|
|
463
|
+
return {
|
|
464
|
+
node: next,
|
|
465
|
+
offset: 0
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
} else {
|
|
469
|
+
var prev = el.childNodes[offset - 1];
|
|
470
|
+
var _next = el.childNodes[offset];
|
|
471
|
+
if (isZwspText(prev) && isHost(_next)) {
|
|
472
|
+
return {
|
|
473
|
+
node: prev,
|
|
474
|
+
offset: 1
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
}
|
|
305
479
|
if (direction === 'left') {
|
|
306
|
-
var
|
|
307
|
-
if (!
|
|
308
|
-
var
|
|
309
|
-
if (!
|
|
310
|
-
return
|
|
311
|
-
node: _parent,
|
|
312
|
-
offset: childIndex(_chip)
|
|
313
|
-
};
|
|
480
|
+
var _chip2 = findChipHostBeforeCaret(range, chipIdAttr);
|
|
481
|
+
if (!_chip2) return null;
|
|
482
|
+
var _parent2 = _chip2.parentNode;
|
|
483
|
+
if (!_parent2) return null;
|
|
484
|
+
return ensureTextAnchorAt(_parent2, childIndex(_chip2));
|
|
314
485
|
}
|
|
315
486
|
var chip = findChipHostAfterCaret(range, chipIdAttr);
|
|
316
487
|
if (!chip) return null;
|
|
@@ -323,12 +494,9 @@ export function resolveCaretJumpAroundChip(range, direction) {
|
|
|
323
494
|
}
|
|
324
495
|
var parent = chip.parentNode;
|
|
325
496
|
if (!parent) return null;
|
|
326
|
-
return
|
|
327
|
-
node: parent,
|
|
328
|
-
offset: childIndex(chip) + 1
|
|
329
|
-
};
|
|
497
|
+
return ensureTextAnchorAt(parent, childIndex(chip) + 1);
|
|
330
498
|
}
|
|
331
|
-
function childIndex(node) {
|
|
499
|
+
export function childIndex(node) {
|
|
332
500
|
var i = 0;
|
|
333
501
|
var cur = node.previousSibling;
|
|
334
502
|
while (cur) {
|
|
@@ -338,6 +506,83 @@ function childIndex(node) {
|
|
|
338
506
|
return i;
|
|
339
507
|
}
|
|
340
508
|
|
|
509
|
+
/** chip 之前的可见纯文本(不含 marker / 不可见字符)。 */
|
|
510
|
+
export function getVisibleTextBeforeHost(editor, host) {
|
|
511
|
+
var chipIdAttr = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'mentionId';
|
|
512
|
+
var r = document.createRange();
|
|
513
|
+
r.selectNodeContents(editor);
|
|
514
|
+
r.setEndBefore(host);
|
|
515
|
+
var tmp = document.createElement('div');
|
|
516
|
+
tmp.appendChild(r.cloneContents());
|
|
517
|
+
return stripInvisibleChars(stripMarkers(getPlainText(tmp))).replace(/\n/g, '');
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* 清理 contenteditable 删字后的幽灵节点:空 text、仅 chip 时的占位 <br>。
|
|
522
|
+
* 避免「文字 + invocation」删光文字后出现多余换行,以及 caret 卡在 chip 后误删 invocation。
|
|
523
|
+
*/
|
|
524
|
+
export function normalizeEditorDom(editor) {
|
|
525
|
+
var _chipIdAttr = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'mentionId';
|
|
526
|
+
var emptyTexts = [];
|
|
527
|
+
var walker = document.createTreeWalker(editor, NodeFilter.SHOW_TEXT);
|
|
528
|
+
var n;
|
|
529
|
+
while (n = walker.nextNode()) {
|
|
530
|
+
var _t$textContent2;
|
|
531
|
+
var t = n;
|
|
532
|
+
// 仅清理真正的空文本节点;保留 caret spacer,避免首次换行落点被抹掉
|
|
533
|
+
if (((_t$textContent2 = t.textContent) !== null && _t$textContent2 !== void 0 ? _t$textContent2 : '') === '') {
|
|
534
|
+
emptyTexts.push(t);
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
emptyTexts.forEach(function (t) {
|
|
538
|
+
return t.remove();
|
|
539
|
+
});
|
|
540
|
+
editor.querySelectorAll('[data-odn-composer-chip-host]').forEach(function (hostEl) {
|
|
541
|
+
var host = hostEl;
|
|
542
|
+
var prev = host.previousSibling;
|
|
543
|
+
while (prev) {
|
|
544
|
+
if (prev.nodeType === Node.TEXT_NODE) {
|
|
545
|
+
var _prev$textContent;
|
|
546
|
+
var _t = stripInvisibleChars((_prev$textContent = prev.textContent) !== null && _prev$textContent !== void 0 ? _prev$textContent : '');
|
|
547
|
+
if (_t !== '') break;
|
|
548
|
+
var rm = prev;
|
|
549
|
+
prev = prev.previousSibling;
|
|
550
|
+
rm.remove();
|
|
551
|
+
continue;
|
|
552
|
+
}
|
|
553
|
+
if (prev.nodeType === Node.ELEMENT_NODE && prev.tagName === 'BR') {
|
|
554
|
+
// 用户主动换行(data-odn-composer-user-break)必须保留,否则会出现
|
|
555
|
+
// 「第二行/第三行换行被吞、chip 插入回到首行」。仅清理浏览器塞的占位 <br>。
|
|
556
|
+
var brEl = prev;
|
|
557
|
+
if (brEl.hasAttribute('data-odn-composer-user-break')) break;
|
|
558
|
+
var _rm = prev;
|
|
559
|
+
prev = prev.previousSibling;
|
|
560
|
+
_rm.remove();
|
|
561
|
+
continue;
|
|
562
|
+
}
|
|
563
|
+
break;
|
|
564
|
+
}
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
/** caret 落在 chip 后空 text 时,挪到 chip 前(不删 chip)。 */
|
|
569
|
+
export function moveCaretBeforeChip(host, opts) {
|
|
570
|
+
var parent = host.parentNode;
|
|
571
|
+
if (!parent) return;
|
|
572
|
+
var sel = window.getSelection();
|
|
573
|
+
if (!sel) return;
|
|
574
|
+
var anchor = ensureTextAnchorAt(parent, childIndex(host));
|
|
575
|
+
if (!anchor) return;
|
|
576
|
+
var r = document.createRange();
|
|
577
|
+
r.setStart(anchor.node, anchor.offset);
|
|
578
|
+
r.collapse(true);
|
|
579
|
+
sel.removeAllRanges();
|
|
580
|
+
sel.addRange(r);
|
|
581
|
+
if (opts !== null && opts !== void 0 && opts.removeTrailingEmptyText && opts.trailingText) {
|
|
582
|
+
opts.trailingText.remove();
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
341
586
|
/* ────────────────────────────────────────────────────────────────────
|
|
342
587
|
* Trigger probe · @ / / 触发态判定
|
|
343
588
|
*
|
|
@@ -376,7 +621,7 @@ var isTriggerBoundary = function isTriggerBoundary(node) {
|
|
|
376
621
|
return false;
|
|
377
622
|
};
|
|
378
623
|
export function probeTrigger(range, triggers) {
|
|
379
|
-
var _node$
|
|
624
|
+
var _node$textContent5;
|
|
380
625
|
var maxQueryLen = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 50;
|
|
381
626
|
if (!range.collapsed) return null;
|
|
382
627
|
|
|
@@ -401,7 +646,7 @@ export function probeTrigger(range, triggers) {
|
|
|
401
646
|
}
|
|
402
647
|
}
|
|
403
648
|
if (node.nodeType !== Node.TEXT_NODE) return null;
|
|
404
|
-
var text = (_node$
|
|
649
|
+
var text = (_node$textContent5 = node.textContent) !== null && _node$textContent5 !== void 0 ? _node$textContent5 : '';
|
|
405
650
|
var triggerOffset = -1;
|
|
406
651
|
var trigger = '';
|
|
407
652
|
for (var i = caret - 1; i >= 0 && caret - i <= maxQueryLen + 1; i--) {
|
package/dist/fab/style/index.css
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
backdrop-filter: blur(12px);
|
|
15
15
|
-webkit-backdrop-filter: blur(12px);
|
|
16
16
|
-webkit-tap-highlight-color: transparent;
|
|
17
|
-
|
|
17
|
+
transition: all 200ms cubic-bezier(0.32, 0.72, 0, 1);
|
|
18
18
|
}
|
|
19
19
|
[data-odn-fab]:active {
|
|
20
20
|
transform: scale(0.95);
|
package/dist/index.d.ts
CHANGED
|
@@ -59,7 +59,8 @@ export { default as AgentThink, type AgentThinkProps } from './agent-think';
|
|
|
59
59
|
export { default as Attachments, type AttachmentsProps } from './attachments';
|
|
60
60
|
export { default as CodeBlock, type CodeBlockProps } from './code-block';
|
|
61
61
|
export { default as Composer, type ComposerProps, type ComposerRef } from './composer';
|
|
62
|
-
export { default as Invocation, type InvocationProps } from './invocation';
|
|
62
|
+
export { default as Invocation, InvocationParamPopover, type InvocationProps, type InvocationParamPopoverProps, } from './invocation';
|
|
63
|
+
export { type ComposerParamPanelContext } from './composer/param-panel';
|
|
63
64
|
export { default as Mention, type MentionProps } from './mention';
|
|
64
65
|
export { default as ChatItem, type ChatItemProps } from './chat-item';
|
|
65
66
|
export { default as SkillSlot, type SkillSlotProps } from './skill-slot';
|
|
@@ -72,4 +73,5 @@ export { default as StreamText, type StreamTextProps, type TypographyOverrides }
|
|
|
72
73
|
export { default as Suggestions, type SuggestionsProps } from './suggestions';
|
|
73
74
|
export { default as UserBubble, type UserBubbleProps } from './user-bubble';
|
|
74
75
|
export { default as Welcome, type WelcomeProps } from './welcome';
|
|
75
|
-
export type { ToolCall, ToolStatus, Source, Attachment, PreviewTarget, PreviewTab, SendMeta,
|
|
76
|
+
export type { ToolCall, ToolStatus, Source, Attachment, PreviewTarget, PreviewTab, SendMeta, ComposerSegment, InvocationData, MentionData, InlineRefState, SkillItem, AgentEvent, Conversation, MessageSnapshot, ChatMessage } from './_genui-types';
|
|
77
|
+
export { rawValueToSegments, segmentsToReadableText, segmentsHasContent, type SegmentsToReadableTextOptions, } from './composer/segments';
|
package/dist/index.js
CHANGED
|
@@ -65,7 +65,7 @@ export { default as AgentThink } from "./agent-think";
|
|
|
65
65
|
export { default as Attachments } from "./attachments";
|
|
66
66
|
export { default as CodeBlock } from "./code-block";
|
|
67
67
|
export { default as Composer } from "./composer";
|
|
68
|
-
export { default as Invocation } from "./invocation";
|
|
68
|
+
export { default as Invocation, InvocationParamPopover } from "./invocation";
|
|
69
69
|
export { default as Mention } from "./mention";
|
|
70
70
|
export { default as ChatItem } from "./chat-item";
|
|
71
71
|
export { default as SkillSlot } from "./skill-slot";
|
|
@@ -79,4 +79,6 @@ export { default as Suggestions } from "./suggestions";
|
|
|
79
79
|
export { default as UserBubble } from "./user-bubble";
|
|
80
80
|
export { default as Welcome } from "./welcome";
|
|
81
81
|
|
|
82
|
-
// GenUI shared modules
|
|
82
|
+
// GenUI shared modules
|
|
83
|
+
|
|
84
|
+
export { rawValueToSegments, segmentsToReadableText, segmentsHasContent } from "./composer/segments";
|
|
@@ -8,10 +8,15 @@ export interface InvocationProps {
|
|
|
8
8
|
* false:UserBubble 等只读态(可 hover 看摘要)。
|
|
9
9
|
*/
|
|
10
10
|
interactive?: boolean;
|
|
11
|
-
/**
|
|
11
|
+
/**
|
|
12
|
+
* 参数面板打开时高亮(最高优先级,叠浅底色)。
|
|
13
|
+
* 不进 `data.state`,因为它是临时 UI 状态,不属于 invocation 自身语义。
|
|
14
|
+
*/
|
|
12
15
|
active?: boolean;
|
|
13
|
-
/**
|
|
16
|
+
/** 交互态单击;业务接管打开参数面板等行为 */
|
|
14
17
|
onClick?: (anchor: HTMLElement) => void;
|
|
15
18
|
}
|
|
16
19
|
export declare function Invocation({ data, interactive, active, onClick, }: InvocationProps): import("react").JSX.Element;
|
|
20
|
+
export { InvocationParamPopover } from './param-popover';
|
|
21
|
+
export type { InvocationParamPopoverProps } from './param-popover';
|
|
17
22
|
export default Invocation;
|
package/dist/invocation/index.js
CHANGED
|
@@ -6,9 +6,9 @@ function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" !=
|
|
|
6
6
|
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
|
7
7
|
import Popover from "../popover";
|
|
8
8
|
import "./style";
|
|
9
|
-
function
|
|
10
|
-
if (!
|
|
11
|
-
var entries = Object.entries(
|
|
9
|
+
function formatPayloadSummary(payload) {
|
|
10
|
+
if (!payload) return null;
|
|
11
|
+
var entries = Object.entries(payload).filter(function (_ref) {
|
|
12
12
|
var _ref2 = _slicedToArray(_ref, 2),
|
|
13
13
|
v = _ref2[1];
|
|
14
14
|
return v != null && v !== '';
|
|
@@ -22,6 +22,7 @@ function formatParamsSummary(params) {
|
|
|
22
22
|
}).join(' · ');
|
|
23
23
|
}
|
|
24
24
|
export function Invocation(_ref5) {
|
|
25
|
+
var _data$state;
|
|
25
26
|
var data = _ref5.data,
|
|
26
27
|
_ref5$interactive = _ref5.interactive,
|
|
27
28
|
interactive = _ref5$interactive === void 0 ? false : _ref5$interactive,
|
|
@@ -29,7 +30,8 @@ export function Invocation(_ref5) {
|
|
|
29
30
|
active = _ref5$active === void 0 ? false : _ref5$active,
|
|
30
31
|
onClick = _ref5.onClick;
|
|
31
32
|
var clickable = interactive && !!onClick;
|
|
32
|
-
|
|
33
|
+
/** 状态优先级:active > data.state > 'complete' */
|
|
34
|
+
var state = active ? 'active' : (_data$state = data.state) !== null && _data$state !== void 0 ? _data$state : 'complete';
|
|
33
35
|
var handleClick = clickable ? function (e) {
|
|
34
36
|
e.preventDefault();
|
|
35
37
|
e.stopPropagation();
|
|
@@ -52,8 +54,9 @@ export function Invocation(_ref5) {
|
|
|
52
54
|
"data-odn-invocation-label": true
|
|
53
55
|
}, data.label));
|
|
54
56
|
if (interactive) return core;
|
|
55
|
-
var summary =
|
|
56
|
-
|
|
57
|
+
var summary = formatPayloadSummary(data.payload);
|
|
58
|
+
/** 只读态:有 payload 摘要 → hover;pending 但无 payload → 「未填参数」;否则不弹 */
|
|
59
|
+
if (!summary && data.state !== 'pending') return core;
|
|
57
60
|
return /*#__PURE__*/React.createElement(Popover, {
|
|
58
61
|
trigger: "hover",
|
|
59
62
|
placement: "top",
|
|
@@ -77,8 +80,11 @@ function InvocationHoverPopup(_ref6) {
|
|
|
77
80
|
}, /*#__PURE__*/React.createElement("span", {
|
|
78
81
|
"data-odn-invocation-popover-slash": true,
|
|
79
82
|
"aria-hidden": true
|
|
80
|
-
}, "/"), label), /*#__PURE__*/React.createElement("div", {
|
|
83
|
+
}, "/"), label), summary ? /*#__PURE__*/React.createElement("div", {
|
|
81
84
|
"data-odn-invocation-popover-summary": true
|
|
82
|
-
}, summary)
|
|
85
|
+
}, summary) : /*#__PURE__*/React.createElement("div", {
|
|
86
|
+
"data-odn-invocation-popover-empty": true
|
|
87
|
+
}, "\u672A\u586B\u53C2\u6570"));
|
|
83
88
|
}
|
|
89
|
+
export { InvocationParamPopover } from "./param-popover";
|
|
84
90
|
export default Invocation;
|