one-design-next 0.0.122 → 0.0.124
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-inline-ref.d.ts +1 -1
- package/dist/_genui-inline-ref.js +3 -2
- package/dist/_genui-types.d.ts +21 -4
- package/dist/_genui-types.js +4 -0
- package/dist/composer/editor.d.ts +11 -0
- package/dist/composer/editor.js +77 -5
- package/dist/composer/hooks/useChipManager.js +1 -0
- package/dist/composer/index.d.ts +60 -7
- package/dist/composer/index.js +314 -160
- package/dist/composer/inline-ref.d.ts +6 -1
- package/dist/composer/inline-ref.js +22 -2
- package/dist/composer/insert.d.ts +12 -0
- package/dist/composer/insert.js +23 -0
- package/dist/composer/mention-menu.d.ts +11 -0
- package/dist/composer/mention-menu.js +50 -0
- package/dist/composer/mention.d.ts +10 -0
- package/dist/composer/mention.js +18 -0
- package/dist/composer/segments.d.ts +19 -2
- package/dist/composer/segments.js +41 -2
- package/dist/composer/slot.d.ts +11 -0
- package/dist/composer/slot.js +121 -0
- package/dist/composer/style/index.css +257 -7
- package/dist/composer/utils.d.ts +7 -0
- package/dist/composer/utils.js +15 -0
- package/dist/dropdown/index.d.ts +4 -0
- package/dist/dropdown/index.js +14 -6
- package/dist/icon/svg-data.d.ts +4 -0
- package/dist/icon/svg-data.js +1 -1
- package/dist/icon/types.d.ts +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +1 -1
- package/dist/mention/index.js +8 -2
- package/dist/user-bubble/render-segments.js +8 -1
- package/package.json +1 -1
|
@@ -7,5 +7,5 @@
|
|
|
7
7
|
export declare const SKILL_CATEGORY_ICON = "astroid";
|
|
8
8
|
/** skill / 未标明的 invocation 通道 → 技能品类 icon;其它 kind 回退 data.icon */
|
|
9
9
|
export declare function resolveInvocationCategoryIcon(kind?: string, fallback?: string): string | undefined;
|
|
10
|
-
/** mention 按 kind 给品类 icon
|
|
10
|
+
/** mention 按 kind 给品类 icon。`mention` 是 @ 文件引用,不画 icon,格式看文件名后缀。 */
|
|
11
11
|
export declare function resolveMentionCategoryIcon(kind?: string, fallback?: string): string | undefined;
|
|
@@ -14,9 +14,10 @@ export function resolveInvocationCategoryIcon(kind, fallback) {
|
|
|
14
14
|
return fallback;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
/** mention 按 kind 给品类 icon
|
|
17
|
+
/** mention 按 kind 给品类 icon。`mention` 是 @ 文件引用,不画 icon,格式看文件名后缀。 */
|
|
18
18
|
export function resolveMentionCategoryIcon(kind, fallback) {
|
|
19
19
|
if (kind === 'file') return 'file-text';
|
|
20
|
-
if (kind === 'user'
|
|
20
|
+
if (kind === 'user') return 'user';
|
|
21
|
+
if (kind === 'mention') return undefined;
|
|
21
22
|
return fallback;
|
|
22
23
|
}
|
package/dist/_genui-types.d.ts
CHANGED
|
@@ -131,10 +131,10 @@ export interface ChipData {
|
|
|
131
131
|
label: string;
|
|
132
132
|
icon?: string;
|
|
133
133
|
/**
|
|
134
|
-
* 'invocation' = `/` 或 Skill 按钮;'mention' =
|
|
134
|
+
* 'invocation' = `/` 或 Skill 按钮;'mention' = `@`;'slot' = 提示词槽位。
|
|
135
135
|
* 其他值归 invocation。
|
|
136
136
|
*/
|
|
137
|
-
kind?: 'invocation' | 'mention' | (string & NonNullable<unknown>);
|
|
137
|
+
kind?: 'invocation' | 'mention' | 'slot' | (string & NonNullable<unknown>);
|
|
138
138
|
state?: InlineRefState;
|
|
139
139
|
payload?: Record<string, unknown>;
|
|
140
140
|
/**
|
|
@@ -222,6 +222,8 @@ export declare const ComposerSegmentType: {
|
|
|
222
222
|
readonly Text: "text";
|
|
223
223
|
readonly Invocation: "invocation";
|
|
224
224
|
readonly Mention: "mention";
|
|
225
|
+
/** 提示词模板槽位。空槽保留名称,填过的带 value */
|
|
226
|
+
readonly Slot: "slot";
|
|
225
227
|
/** 派生的 skill 提示文本;发送时按结构谓词追加,见 `ComposerHintSegment` */
|
|
226
228
|
readonly Hint: "hint";
|
|
227
229
|
};
|
|
@@ -238,6 +240,17 @@ export interface ComposerMentionSegment {
|
|
|
238
240
|
type: typeof ComposerSegmentType.Mention;
|
|
239
241
|
data: MentionData;
|
|
240
242
|
}
|
|
243
|
+
/** 提示词槽位。`name` 是空槽上的名称,`value` 是填入的字,空字符串表示还没填。 */
|
|
244
|
+
export interface SlotData {
|
|
245
|
+
id: string;
|
|
246
|
+
name: string;
|
|
247
|
+
value: string;
|
|
248
|
+
templateId?: string;
|
|
249
|
+
}
|
|
250
|
+
export interface ComposerSlotSegment {
|
|
251
|
+
type: typeof ComposerSegmentType.Slot;
|
|
252
|
+
data: SlotData;
|
|
253
|
+
}
|
|
241
254
|
/**
|
|
242
255
|
* 派生的 skill 提示段:**不是用户输入的内容**,而是「最后一个 skill chip + 其后
|
|
243
256
|
* 无内容 + hint 未关闭」这一结构谓词成立时,由 Composer 在发送瞬间追加的模板
|
|
@@ -254,11 +267,15 @@ export interface ComposerHintSegment {
|
|
|
254
267
|
export interface HintData {
|
|
255
268
|
text: string;
|
|
256
269
|
}
|
|
257
|
-
export type ComposerSegment = ComposerTextSegment | ComposerInvocationSegment | ComposerMentionSegment | ComposerHintSegment;
|
|
270
|
+
export type ComposerSegment = ComposerTextSegment | ComposerInvocationSegment | ComposerMentionSegment | ComposerSlotSegment | ComposerHintSegment;
|
|
258
271
|
/** `onSend(segments, meta?)` 第二参数:非正文的附加数据。 */
|
|
259
272
|
export interface SendMeta {
|
|
260
273
|
attachments?: Attachment[];
|
|
261
|
-
|
|
274
|
+
/**
|
|
275
|
+
* 推理模式。只有工具栏放了 `mode` 时才会带上。
|
|
276
|
+
* `fast` 是快速,`featured` 是精选。
|
|
277
|
+
*/
|
|
278
|
+
mode?: 'fast' | 'featured';
|
|
262
279
|
}
|
|
263
280
|
export type AgentEvent = {
|
|
264
281
|
kind: 'thinking';
|
package/dist/_genui-types.js
CHANGED
|
@@ -48,12 +48,16 @@ export var ComposerSegmentType = {
|
|
|
48
48
|
Text: 'text',
|
|
49
49
|
Invocation: 'invocation',
|
|
50
50
|
Mention: 'mention',
|
|
51
|
+
/** 提示词模板槽位。空槽保留名称,填过的带 value */
|
|
52
|
+
Slot: 'slot',
|
|
51
53
|
/** 派生的 skill 提示文本;发送时按结构谓词追加,见 `ComposerHintSegment` */
|
|
52
54
|
Hint: 'hint'
|
|
53
55
|
};
|
|
54
56
|
// 同名 type 供 `seg.type === ComposerSegmentType.Invocation` 收窄,与 const 对象并存。
|
|
55
57
|
// eslint-disable-next-line @typescript-eslint/no-redeclare -- 有意的 const + type 同名
|
|
56
58
|
|
|
59
|
+
/** 提示词槽位。`name` 是空槽上的名称,`value` 是填入的字,空字符串表示还没填。 */
|
|
60
|
+
|
|
57
61
|
/**
|
|
58
62
|
* 派生的 skill 提示段:**不是用户输入的内容**,而是「最后一个 skill chip + 其后
|
|
59
63
|
* 无内容 + hint 未关闭」这一结构谓词成立时,由 Composer 在发送瞬间追加的模板
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
*/
|
|
19
19
|
import React from 'react';
|
|
20
20
|
import type { ChipData } from '../_genui-types';
|
|
21
|
+
import { type ComposerSkillHint } from './segments';
|
|
21
22
|
/** Composer editor 触发态对外信号——告诉父组件该弹浮层选 skill 了。 */
|
|
22
23
|
export interface ComposerEditorTriggerInfo {
|
|
23
24
|
/** 触发字符(@ 或 /) */
|
|
@@ -72,6 +73,16 @@ export interface ComposerEditorProps {
|
|
|
72
73
|
defaultValue?: string;
|
|
73
74
|
/** 值变化回调;参数是 raw string,含 marker。 */
|
|
74
75
|
onChange?: (value: string) => void;
|
|
76
|
+
/**
|
|
77
|
+
* 灰字(skill hint)命中状态变化回调:
|
|
78
|
+
* - 灰字出现(最后一个 chip 命中结构谓词)→ 传入命中的 chip / 文案
|
|
79
|
+
* - 灰字消失(后面有内容 / chip 被删 / hint 已关闭)→ 传入 null
|
|
80
|
+
*
|
|
81
|
+
* 只在状态**真的变化**时抛一次;与灰字渲染共用同一份判定(先落 DOM 再抛,
|
|
82
|
+
* 不会各自算一套)。判定成立但灰字被临时摘掉(IME 合成期)时不跟着抖。
|
|
83
|
+
* 挂载时会先同步一次当前状态(空内容即 null),业务侧不必自己猜初始值。
|
|
84
|
+
*/
|
|
85
|
+
onSkillHintChange?: (hint: ComposerSkillHint | null) => void;
|
|
75
86
|
/** 与 defaultValue / 首次受控 value 配套,把 marker 还原成 chip。 */
|
|
76
87
|
defaultChips?: ChipData[];
|
|
77
88
|
placeholder?: string;
|
package/dist/composer/editor.js
CHANGED
|
@@ -279,11 +279,13 @@ export var COMPOSER_EDITOR_HEIGHT_CAP_EXIT_PX = contentHeightForRows(9);
|
|
|
279
279
|
var measureFitsInlineWidth = function measureFitsInlineWidth(el) {
|
|
280
280
|
var computed = window.getComputedStyle(el);
|
|
281
281
|
var inlineInset = Number.parseFloat(computed.getPropertyValue('--odn-composer-editor-inline-inset'));
|
|
282
|
+
var inlineInsetEnd = Number.parseFloat(computed.getPropertyValue('--odn-composer-editor-inline-inset-end'));
|
|
282
283
|
// 非 lite 变体没有这个变量:这里不做中间区判定,一律视为放得下。
|
|
283
284
|
if (!Number.isFinite(inlineInset) || inlineInset <= 0) return true;
|
|
285
|
+
var endInset = Number.isFinite(inlineInsetEnd) && inlineInsetEnd > 0 ? inlineInsetEnd : inlineInset;
|
|
284
286
|
var viewport = el.closest('[data-odn-scroll-area-viewport]');
|
|
285
287
|
var containerWidth = viewport instanceof HTMLElement ? viewport.clientWidth : el.clientWidth;
|
|
286
|
-
var inlineContentWidth = containerWidth - inlineInset
|
|
288
|
+
var inlineContentWidth = containerWidth - inlineInset - endInset;
|
|
287
289
|
if (inlineContentWidth <= 0) return true;
|
|
288
290
|
|
|
289
291
|
// 逐个文本节点取 rect:Range 覆盖整棵子树时拿到的是行容器(block)的宽度,
|
|
@@ -326,6 +328,7 @@ export var ComposerEditor = /*#__PURE__*/forwardRef(function ComposerEditor(_ref
|
|
|
326
328
|
defaultValue = _ref$defaultValue === void 0 ? '' : _ref$defaultValue,
|
|
327
329
|
defaultChips = _ref.defaultChips,
|
|
328
330
|
onChange = _ref.onChange,
|
|
331
|
+
onSkillHintChange = _ref.onSkillHintChange,
|
|
329
332
|
placeholder = _ref.placeholder,
|
|
330
333
|
autoSize = _ref.autoSize,
|
|
331
334
|
onPressEnter = _ref.onPressEnter,
|
|
@@ -353,6 +356,9 @@ export var ComposerEditor = /*#__PURE__*/forwardRef(function ComposerEditor(_ref
|
|
|
353
356
|
var isComposingRef = useRef(false);
|
|
354
357
|
var onTriggerChangeRef = useRef(onTriggerChange);
|
|
355
358
|
onTriggerChangeRef.current = onTriggerChange;
|
|
359
|
+
/** 灰字状态回调走 ref:调用方常传内联函数,不能让 fireChange / 挂载同步因此反复重建 */
|
|
360
|
+
var onSkillHintChangeRef = useRef(onSkillHintChange);
|
|
361
|
+
onSkillHintChangeRef.current = onSkillHintChange;
|
|
356
362
|
var isControlled = valueProp !== undefined;
|
|
357
363
|
var minRows = (_autoSize$minRows = autoSize === null || autoSize === void 0 ? void 0 : autoSize.minRows) !== null && _autoSize$minRows !== void 0 ? _autoSize$minRows : 1;
|
|
358
364
|
var maxRows = autoSize === null || autoSize === void 0 ? void 0 : autoSize.maxRows;
|
|
@@ -587,6 +593,33 @@ export var ComposerEditor = /*#__PURE__*/forwardRef(function ComposerEditor(_ref
|
|
|
587
593
|
}
|
|
588
594
|
}, [removeHintNode]);
|
|
589
595
|
|
|
596
|
+
/* 灰字状态的**上一帧快照**:回调只在真的变化时抛一次。
|
|
597
|
+
* fireChange 每次输入都会跑,不去重的话业务侧会被同一条状态反复冲刷。
|
|
598
|
+
* `undefined` = 还没抛过(与「抛过 null」区分),保证挂载时一定会同步一次。 */
|
|
599
|
+
var lastSkillHintRef = useRef(undefined);
|
|
600
|
+
|
|
601
|
+
/**
|
|
602
|
+
* 把「灰字当前状态」通知给业务方(与 syncHintNode 同一份 target,保证同源)。
|
|
603
|
+
*
|
|
604
|
+
* 只在 chipId / refId / 文案任一变化时抛:同一条状态在连续输入里会算很多次。
|
|
605
|
+
*/
|
|
606
|
+
var notifySkillHint = useCallback(function (target, chips) {
|
|
607
|
+
var _chips$find, _onSkillHintChangeRef;
|
|
608
|
+
var next = target ? {
|
|
609
|
+
chipId: target.chipId,
|
|
610
|
+
text: target.text,
|
|
611
|
+
refId: (_chips$find = chips.find(function (chip) {
|
|
612
|
+
return chip.id === target.chipId;
|
|
613
|
+
})) === null || _chips$find === void 0 ? void 0 : _chips$find.refId
|
|
614
|
+
} : null;
|
|
615
|
+
var prev = lastSkillHintRef.current;
|
|
616
|
+
if (prev !== undefined && (prev === null || prev === void 0 ? void 0 : prev.chipId) === (next === null || next === void 0 ? void 0 : next.chipId) && (prev === null || prev === void 0 ? void 0 : prev.text) === (next === null || next === void 0 ? void 0 : next.text) && (prev === null || prev === void 0 ? void 0 : prev.refId) === (next === null || next === void 0 ? void 0 : next.refId)) {
|
|
617
|
+
return;
|
|
618
|
+
}
|
|
619
|
+
lastSkillHintRef.current = next;
|
|
620
|
+
(_onSkillHintChangeRef = onSkillHintChangeRef.current) === null || _onSkillHintChangeRef === void 0 || _onSkillHintChangeRef.call(onSkillHintChangeRef, next);
|
|
621
|
+
}, []);
|
|
622
|
+
|
|
590
623
|
/** 把 caret 直接落到 hint 之前(= chip 右侧);没有 hint 时不动。 */
|
|
591
624
|
var placeCaretBeforeHint = useCallback(function () {
|
|
592
625
|
var el = editorRef.current;
|
|
@@ -606,6 +639,10 @@ export var ComposerEditor = /*#__PURE__*/forwardRef(function ComposerEditor(_ref
|
|
|
606
639
|
var pullCaretBeforeHint = useCallback(function () {
|
|
607
640
|
var el = editorRef.current;
|
|
608
641
|
var sel = window.getSelection();
|
|
642
|
+
var active = document.activeElement;
|
|
643
|
+
if (active instanceof HTMLElement && active.hasAttribute('data-odn-composer-slot-input')) {
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
609
646
|
if (!el || !sel || sel.rangeCount !== 1 || !sel.isCollapsed) return;
|
|
610
647
|
if (!el.contains(sel.anchorNode)) return;
|
|
611
648
|
if (!normalizeCollapsedCaretBeforeHint(sel.getRangeAt(0), el)) return;
|
|
@@ -627,7 +664,12 @@ export var ComposerEditor = /*#__PURE__*/forwardRef(function ComposerEditor(_ref
|
|
|
627
664
|
* 否则「chip 被删」时残留的 hint 文本会让 placeholder 判定与 lite 升格
|
|
628
665
|
* 判定晚一拍。 */
|
|
629
666
|
closeChipHintsRef.current(resolveHintClosedChipIds(raw, chips));
|
|
630
|
-
|
|
667
|
+
/* 关闭会改写 chips 快照,谓词必须用关闭后的快照重新取;
|
|
668
|
+
* 渲染(syncHintNode)与对外回调(notifySkillHint)共用这一份 target,
|
|
669
|
+
* 业务拿到的是「这一刻灰字该不该在」的同一份判定,不会各算一套。 */
|
|
670
|
+
var hintChips = getChipsRef.current();
|
|
671
|
+
var hintTarget = resolveHintTarget(raw, hintChips);
|
|
672
|
+
syncHintNode(hintTarget);
|
|
631
673
|
var showPlaceholder = shouldShowPlaceholder(el);
|
|
632
674
|
if (forceNonEmptyOnceRef.current && showPlaceholder) {
|
|
633
675
|
setEmpty(false);
|
|
@@ -640,7 +682,23 @@ export var ComposerEditor = /*#__PURE__*/forwardRef(function ComposerEditor(_ref
|
|
|
640
682
|
scheduleControlledSync();
|
|
641
683
|
// editor.height 锁定时 RO 不触发,主动同步一次,确保升格判定能拿到 scrollHeight
|
|
642
684
|
syncHeight();
|
|
643
|
-
|
|
685
|
+
/* 对外回调放在所有内部状态更新之后:业务在里面同步 setState 甚至
|
|
686
|
+
* updateChipData 都不会插进「DOM 已落、caret / 高度还没收尾」的中间态。 */
|
|
687
|
+
notifySkillHint(hintTarget, hintChips);
|
|
688
|
+
}, [notifySkillHint, onChange, pullCaretBeforeHint, scheduleControlledSync, shouldShowPlaceholder, syncHeight, syncHintNode]);
|
|
689
|
+
|
|
690
|
+
/* 挂载时同步一次灰字状态。
|
|
691
|
+
*
|
|
692
|
+
* 带 chips 的草稿恢复已经在挂载的 layout effect 里走 fireChange 抛过一次,
|
|
693
|
+
* 这里兜的是「空内容 / 只有纯文本挂载」——否则业务侧上一轮留下的状态没人复位。
|
|
694
|
+
* 放在 passive effect:晚于 chips 还原,且 notifySkillHint 自带去重,
|
|
695
|
+
* 与 fireChange 那一次重复时不会再抛。 */
|
|
696
|
+
useEffect(function () {
|
|
697
|
+
var el = editorRef.current;
|
|
698
|
+
if (!el) return;
|
|
699
|
+
var hintChips = getChipsRef.current();
|
|
700
|
+
notifySkillHint(resolveHintTarget(getPlainText(el), hintChips), hintChips);
|
|
701
|
+
}, [notifySkillHint]);
|
|
644
702
|
|
|
645
703
|
/* ─────────────────────────────────────
|
|
646
704
|
* chip 管理
|
|
@@ -785,6 +843,10 @@ export var ComposerEditor = /*#__PURE__*/forwardRef(function ComposerEditor(_ref
|
|
|
785
843
|
onTriggerChange === null || onTriggerChange === void 0 || onTriggerChange(null);
|
|
786
844
|
}
|
|
787
845
|
onChange === null || onChange === void 0 || onChange('');
|
|
846
|
+
/* 这条路不走 fireChange(清空不是「内容变化」链路的一环),
|
|
847
|
+
* 灰字状态要在这里手动同步,否则业务侧会一直以为灰字还显示着。
|
|
848
|
+
* 位置放在 onChange 之后,与 fireChange 的「先 onChange 再灰字」一致。 */
|
|
849
|
+
notifySkillHint(null, []);
|
|
788
850
|
},
|
|
789
851
|
insertChip: function insertChip(data) {
|
|
790
852
|
var el = editorRef.current;
|
|
@@ -881,7 +943,7 @@ export var ComposerEditor = /*#__PURE__*/forwardRef(function ComposerEditor(_ref
|
|
|
881
943
|
return editorRef.current;
|
|
882
944
|
}
|
|
883
945
|
};
|
|
884
|
-
}, [onChange, _insertChip, insertSerializedAtRange, requestScrollCaretIntoView, removeChip, resetChips, onTriggerChange, getChips, updateChipData, getChipHost]);
|
|
946
|
+
}, [onChange, _insertChip, insertSerializedAtRange, notifySkillHint, requestScrollCaretIntoView, removeChip, resetChips, onTriggerChange, getChips, updateChipData, getChipHost]);
|
|
885
947
|
|
|
886
948
|
/* ─────────────────────────────────────
|
|
887
949
|
* 监听 selection 变化:方向键 / 鼠标点击移位都要重算 trigger
|
|
@@ -1037,6 +1099,8 @@ export var ComposerEditor = /*#__PURE__*/forwardRef(function ComposerEditor(_ref
|
|
|
1037
1099
|
}
|
|
1038
1100
|
removeHintNode();
|
|
1039
1101
|
resetChips();
|
|
1102
|
+
/* 同 clear():外部改写 value 不走 fireChange,灰字状态在这里手动同步 */
|
|
1103
|
+
notifySkillHint(null, []);
|
|
1040
1104
|
setEmpty(shouldShowPlaceholder(el));
|
|
1041
1105
|
if (triggerRef.current) {
|
|
1042
1106
|
var _onTriggerChangeRef$c;
|
|
@@ -1045,7 +1109,7 @@ export var ComposerEditor = /*#__PURE__*/forwardRef(function ComposerEditor(_ref
|
|
|
1045
1109
|
}
|
|
1046
1110
|
syncHeight();
|
|
1047
1111
|
}
|
|
1048
|
-
}, [controlledSyncTick, valueProp, isControlled, resetChips, shouldShowPlaceholder, syncHeight]);
|
|
1112
|
+
}, [controlledSyncTick, valueProp, isControlled, notifySkillHint, resetChips, shouldShowPlaceholder, syncHeight]);
|
|
1049
1113
|
|
|
1050
1114
|
/* ─────────────────────────────────────
|
|
1051
1115
|
* 输入事件
|
|
@@ -1434,6 +1498,14 @@ export var ComposerEditor = /*#__PURE__*/forwardRef(function ComposerEditor(_ref
|
|
|
1434
1498
|
return /*#__PURE__*/createPortal( /*#__PURE__*/React.createElement(ComposerInlineRef, {
|
|
1435
1499
|
data: chip.data,
|
|
1436
1500
|
active: paramEditChipId === chip.data.id,
|
|
1501
|
+
disabled: disabled,
|
|
1502
|
+
onSlotChange: chip.data.kind === 'slot' ? function (value) {
|
|
1503
|
+
return updateChipData(chip.data.id, {
|
|
1504
|
+
payload: _objectSpread(_objectSpread({}, chip.data.payload), {}, {
|
|
1505
|
+
value: value
|
|
1506
|
+
})
|
|
1507
|
+
});
|
|
1508
|
+
} : undefined,
|
|
1437
1509
|
onClick: onInlineRefClick && chipHasEditableParams(chip.data) ? function (anchor) {
|
|
1438
1510
|
return onInlineRefClick(chip.data.id, anchor);
|
|
1439
1511
|
} : undefined
|
|
@@ -25,6 +25,7 @@ function createChipHost(data) {
|
|
|
25
25
|
host.dataset.mentionId = data.id;
|
|
26
26
|
host.contentEditable = 'false';
|
|
27
27
|
host.setAttribute('data-odn-composer-chip-host', '');
|
|
28
|
+
if (data.kind) host.dataset.chipKind = data.kind;
|
|
28
29
|
return host;
|
|
29
30
|
}
|
|
30
31
|
function createCaretAnchorAtBoundary(parent, offset) {
|
package/dist/composer/index.d.ts
CHANGED
|
@@ -3,11 +3,17 @@ import type { Attachment, ChipData, ComposerSegment, SendMeta, SkillItem } from
|
|
|
3
3
|
import type { IconName } from '../icon';
|
|
4
4
|
import { type SkillSlotProps } from '../skill-slot';
|
|
5
5
|
import { type ComposerInsertOptions, type ComposerInsertPart, type ComposerInsertResult } from './insert';
|
|
6
|
+
import { type ComposerMentionItem } from './mention';
|
|
6
7
|
import type { ComposerParamPanelContext } from './param-panel';
|
|
8
|
+
import { type ComposerSkillHint } from './segments';
|
|
7
9
|
import './style';
|
|
8
10
|
export type { ComposerInsertOptions, ComposerInsertPart, ComposerInsertResult, } from './insert';
|
|
11
|
+
export type { ComposerMentionItem } from './mention';
|
|
9
12
|
export type { ComposerParamPanelContext } from './param-panel';
|
|
10
|
-
export type
|
|
13
|
+
export type { ComposerHintTarget, ComposerSkillHint } from './segments';
|
|
14
|
+
export type ComposerTool = 'attachment' | 'skill';
|
|
15
|
+
/** 快速 / 精选。不是工具按钮,`showMode` 为 true 才出现在发送键左侧。 */
|
|
16
|
+
export type ComposerMode = 'fast' | 'featured';
|
|
11
17
|
export type ComposerVariant = 'full' | 'lite';
|
|
12
18
|
export type SubmitType = 'enter' | 'shiftEnter';
|
|
13
19
|
/**
|
|
@@ -18,7 +24,7 @@ export type SubmitType = 'enter' | 'shiftEnter';
|
|
|
18
24
|
* - 整个配置对象不传(key 不存在于 `toolConfigs`)时使用内置默认值。
|
|
19
25
|
* - 仅传 `tooltip`(不传 icon / label)时:保留默认图标与文案,只覆盖说明。
|
|
20
26
|
* - 传了配置对象且 icon / label 均未设置、也未传 tooltip 时(`{}`),兜底显示工具英文名
|
|
21
|
-
* (如 "attachment" / "
|
|
27
|
+
* (如 "attachment" / "skill")作为 label,无图标,
|
|
22
28
|
* 方便开发者一眼看出配置遗漏。
|
|
23
29
|
*/
|
|
24
30
|
export interface ComposerToolConfig {
|
|
@@ -65,6 +71,7 @@ export interface ComposerRef {
|
|
|
65
71
|
* - `skill` 走与菜单插入相同的 chip 结构(含 `hint` / `initialState`);
|
|
66
72
|
* `initialState: 'pending'` 且提供 `renderParamPanel` 时自动打开参数面板
|
|
67
73
|
* (`focus: false` 的后台预填不打开)。
|
|
74
|
+
* - `slot` 是提示词槽位:`name` 显示在空槽上,`value` 是已填的字。
|
|
68
75
|
* - `chip` 是逃生舱:mention / 自定义 kind / 已存草稿都可以直接传。
|
|
69
76
|
* - chip id 与编辑器已有 chip 冲突时自动换新 id,以返回的 `chipIds` 为准。
|
|
70
77
|
* - 受控 `value` 场景请在 onChange 内回写,与手动输入一致(否则一帧后会被
|
|
@@ -105,11 +112,27 @@ export interface ComposerProps {
|
|
|
105
112
|
defaultChips?: ChipData[];
|
|
106
113
|
/** 输入框值变化回调。第二参是当前 chip 快照,旧调用方忽略即可。 */
|
|
107
114
|
onChange?: (value: string, chips?: ChipData[]) => void;
|
|
115
|
+
/**
|
|
116
|
+
* 技能灰字(`SkillItem.hint`)的出现 / 消失回调。
|
|
117
|
+
*
|
|
118
|
+
* 入参与输入框里那行灰字共用**同一份判定**(`resolveHintTarget`):命中时给
|
|
119
|
+
* `{ chipId, text, refId }`,消失时给 `null`。因此业务不需要自己解析
|
|
120
|
+
* value / chips,也不会出现「库里觉得有、业务觉得没有」的分歧。
|
|
121
|
+
*
|
|
122
|
+
* 语义要点:
|
|
123
|
+
* - 只在状态真的变化时抛一次,同一条状态不会因为连续输入重复抛;
|
|
124
|
+
* - 判定成立但灰字被临时摘掉(IME 合成期避开候选串)时不跟着抖;
|
|
125
|
+
* - 挂载时先同步一次当前状态(首屏没有灰字即 `null`),便于业务复位上一轮状态;
|
|
126
|
+
* - 灰字一次性:收起后即使把内容删回空串也不会再抛命中;
|
|
127
|
+
* - 卸载不会再补一次 `null`:需要清理时由业务在自己的卸载路径处理;
|
|
128
|
+
* - 与 `hint`(底部快捷键提示开关)无关。
|
|
129
|
+
*/
|
|
130
|
+
onSkillHintChange?: (hint: ComposerSkillHint | null) => void;
|
|
108
131
|
/**
|
|
109
132
|
* 发送回调。
|
|
110
133
|
*
|
|
111
134
|
* `segments`:有序内容 IR,业务按数组顺序自定义拼后端。
|
|
112
|
-
* `meta
|
|
135
|
+
* `meta`:附件等非正文数据;为空时不传。
|
|
113
136
|
*
|
|
114
137
|
* **派生 `hint` 段**:当最后一个 chip 是带 `SkillItem.hint` 的 skill、其后
|
|
115
138
|
* 一个字符都没有(空格 / 换行都算内容)、且这颗 chip 的 hint 还没关闭时,
|
|
@@ -159,7 +182,7 @@ export interface ComposerProps {
|
|
|
159
182
|
variant?: ComposerVariant;
|
|
160
183
|
/**
|
|
161
184
|
* 左下工具按钮集合(按数组顺序展示)。传入空数组即不渲染任何左下按钮。
|
|
162
|
-
* @default ['attachment', '
|
|
185
|
+
* @default ['attachment', 'skill']
|
|
163
186
|
*/
|
|
164
187
|
tools?: ComposerTool[];
|
|
165
188
|
/**
|
|
@@ -173,7 +196,6 @@ export interface ComposerProps {
|
|
|
173
196
|
/**
|
|
174
197
|
* 各工具按钮的自定义配置(icon / label / tooltip)。按 `ComposerTool` 类型做 key:
|
|
175
198
|
* - `attachment`:附件按钮
|
|
176
|
-
* - `webSearch`:联网按钮
|
|
177
199
|
* - `skill`:技能按钮
|
|
178
200
|
*
|
|
179
201
|
* **语义约定**:
|
|
@@ -188,7 +210,6 @@ export interface ComposerProps {
|
|
|
188
210
|
* ```tsx
|
|
189
211
|
* toolConfigs={{
|
|
190
212
|
* attachment: { tooltip: '上传材料,补充上下文' }, // 只改说明
|
|
191
|
-
* webSearch: { label: '搜索' }, // 仅文字
|
|
192
213
|
* skill: { icon: 'command' }, // 仅图标
|
|
193
214
|
* }}
|
|
194
215
|
* ```
|
|
@@ -200,6 +221,38 @@ export interface ComposerProps {
|
|
|
200
221
|
* 菜单宽高由 Composer 按输入框与视口计算,不经本袋覆盖。
|
|
201
222
|
*/
|
|
202
223
|
skillSlotProps?: ComposerSkillSlotProps;
|
|
224
|
+
/**
|
|
225
|
+
* 为 false 时正文里的 `/` 不打开技能菜单。技能按钮不受影响。
|
|
226
|
+
* @default true
|
|
227
|
+
*/
|
|
228
|
+
slash?: boolean;
|
|
229
|
+
/**
|
|
230
|
+
* `@` 引用名单。不传则不响应 `@`。
|
|
231
|
+
* 选中时 `onSelect` 返回 `false` 不插入。块被删掉时调用 `onRemove`。
|
|
232
|
+
*/
|
|
233
|
+
mentionProps?: {
|
|
234
|
+
items: ComposerMentionItem[];
|
|
235
|
+
onSelect?: (item: ComposerMentionItem) => boolean | void;
|
|
236
|
+
onRemove?: (mention: {
|
|
237
|
+
id: string;
|
|
238
|
+
refId?: string;
|
|
239
|
+
label: string;
|
|
240
|
+
}) => void;
|
|
241
|
+
};
|
|
242
|
+
/**
|
|
243
|
+
* 是否显示快速 / 精选。它贴在发送键左侧,不属于 `tools`。
|
|
244
|
+
* @default false
|
|
245
|
+
*/
|
|
246
|
+
showMode?: boolean;
|
|
247
|
+
/**
|
|
248
|
+
* 当前推理模式。只在 `showMode` 时显示,并随发送放进 `SendMeta.mode`。
|
|
249
|
+
* 不传时组件自己记,默认精选。
|
|
250
|
+
*/
|
|
251
|
+
mode?: ComposerMode;
|
|
252
|
+
/** 非受控时的初始模式。@default 'featured' */
|
|
253
|
+
defaultMode?: ComposerMode;
|
|
254
|
+
/** 用户改选快速 / 精选时调用 */
|
|
255
|
+
onModeChange?: (mode: ComposerMode) => void;
|
|
203
256
|
/**
|
|
204
257
|
* 提交模式:
|
|
205
258
|
* - `'enter'`(默认):Enter 发送,Shift+Enter 换行
|
|
@@ -289,7 +342,7 @@ export interface ComposerProps {
|
|
|
289
342
|
/**
|
|
290
343
|
* 工具栏按钮被点击时触发。
|
|
291
344
|
*
|
|
292
|
-
* - `tool`:被点击的工具类型(`'attachment'` / `'
|
|
345
|
+
* - `tool`:被点击的工具类型(`'attachment'` / `'skill'`)。
|
|
293
346
|
* - 对于 `'skill'`:在 skill 弹窗打开时触发(而非选中某个 skill 时)。
|
|
294
347
|
* - 此回调为纯通知性质,不影响组件内部行为(若需阻止,请使用 `disabled` 等控制)。
|
|
295
348
|
*/
|