one-design-next 0.0.76 → 0.0.78

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.
@@ -66,8 +66,10 @@ export interface ComposerProps {
66
66
  value?: string;
67
67
  /** 输入框非受控默认值 */
68
68
  defaultValue?: string;
69
- /** 输入框值变化回调 */
70
- onChange?: (value: string) => void;
69
+ /** defaultValue 配套,首次挂载时把 marker 还原成 chip。 */
70
+ defaultChips?: ChipData[];
71
+ /** 输入框值变化回调。第二参是当前 chip 快照,旧调用方忽略即可。 */
72
+ onChange?: (value: string, chips?: ChipData[]) => void;
71
73
  /**
72
74
  * 发送回调。
73
75
  *
@@ -176,6 +178,8 @@ export interface ComposerProps {
176
178
  * - 不传则非受控,组件内部自管,沿用 `URL.createObjectURL(f)` 生成 blob url 的旧行为(向后兼容)。
177
179
  */
178
180
  attachments?: Attachment[];
181
+ /** 非受控附件初始值,随组件挂载(如 `key` 切换会话)生效。 */
182
+ defaultAttachments?: Attachment[];
179
183
  /**
180
184
  * 附件数组变化时触发(新增、删除、外部回写都会调)。
181
185
  * 受控模式下与 `attachments` 配合形成 React 标准受控形态。
@@ -235,7 +239,8 @@ export interface ComposerProps {
235
239
  */
236
240
  fileRejectMessage?: (ext: string) => string;
237
241
  /**
238
- * 参数面板内容渲染。提供后 invocation chip 可点击打开面板;
242
+ * 参数面板内容渲染。提供后,**待补充 / 已填参数** 的 invocation chip
243
+ * 可点击打开面板;无参数 skill 无 hover、不可点。
239
244
  * `SkillItem.initialState='pending'` 插入后会自动打开。
240
245
  */
241
246
  renderParamPanel?: (ctx: ComposerParamPanelContext) => React.ReactNode;
@@ -6,6 +6,7 @@ import _regeneratorRuntime from "@babel/runtime/helpers/esm/regeneratorRuntime";
6
6
  import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator";
7
7
  import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
8
8
  import { forwardRef, useCallback, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState } from 'react';
9
+ import { SKILL_CATEGORY_ICON } from "../_genui-inline-ref";
9
10
  import useControlledState from "../_util/useControlledState";
10
11
  import Attachments from "../attachments";
11
12
  import HoverFill from "../hover-fill";
@@ -16,7 +17,7 @@ import Popover from "../popover";
16
17
  import SkillSlot from "../skill-slot";
17
18
  import Tooltip from "../tooltip";
18
19
  import { ComposerEditor } from "./editor";
19
- import { isMentionChip } from "./inline-ref";
20
+ import { chipHasEditableParams, isMentionChip } from "./inline-ref";
20
21
  import { rawValueToSegments, segmentsHasContent } from "./segments";
21
22
  import "./style";
22
23
  function createInvocationChipData(skill) {
@@ -82,7 +83,7 @@ var DEFAULT_TOOL_CONFIGS = {
82
83
  tooltip: '联网搜索'
83
84
  },
84
85
  skill: {
85
- icon: 'wand-sparkles',
86
+ icon: SKILL_CATEGORY_ICON,
86
87
  label: '技能',
87
88
  tooltip: '选择技能'
88
89
  }
@@ -99,6 +100,7 @@ export var Composer = /*#__PURE__*/forwardRef(function Composer(_ref, ref) {
99
100
  var valueProp = _ref.value,
100
101
  _ref$defaultValue = _ref.defaultValue,
101
102
  defaultValue = _ref$defaultValue === void 0 ? '' : _ref$defaultValue,
103
+ defaultChips = _ref.defaultChips,
102
104
  onChangeProp = _ref.onChange,
103
105
  onSend = _ref.onSend,
104
106
  onStop = _ref.onStop,
@@ -124,6 +126,7 @@ export var Composer = /*#__PURE__*/forwardRef(function Composer(_ref, ref) {
124
126
  submitType = _ref$submitType === void 0 ? 'enter' : _ref$submitType,
125
127
  onEnter = _ref.onEnter,
126
128
  attachmentsProp = _ref.attachments,
129
+ defaultAttachments = _ref.defaultAttachments,
127
130
  onAttachmentsChange = _ref.onAttachmentsChange,
128
131
  onAttachFiles = _ref.onAttachFiles,
129
132
  onAttachmentRemove = _ref.onAttachmentRemove,
@@ -153,7 +156,7 @@ export var Composer = /*#__PURE__*/forwardRef(function Composer(_ref, ref) {
153
156
  _useControlledState2 = _slicedToArray(_useControlledState, 2),
154
157
  text = _useControlledState2[0],
155
158
  setText = _useControlledState2[1];
156
- var _useControlledState3 = useControlledState([], attachmentsProp),
159
+ var _useControlledState3 = useControlledState(defaultAttachments !== null && defaultAttachments !== void 0 ? defaultAttachments : [], attachmentsProp),
157
160
  _useControlledState4 = _slicedToArray(_useControlledState3, 2),
158
161
  attachments = _useControlledState4[0],
159
162
  setAttachments = _useControlledState4[1];
@@ -248,14 +251,24 @@ export var Composer = /*#__PURE__*/forwardRef(function Composer(_ref, ref) {
248
251
  var chip = chips.find(function (c) {
249
252
  return c.id === chipId;
250
253
  });
251
- if (!chip || isMentionChip(chip)) return;
254
+ if (!chip || !chipHasEditableParams(chip)) return;
255
+ var body = renderParamPanel({
256
+ chip: chip,
257
+ anchor: anchor,
258
+ onApply: function onApply(patch) {
259
+ var _editorRef$current4;
260
+ (_editorRef$current4 = editorRef.current) === null || _editorRef$current4 === void 0 || _editorRef$current4.updateChipData(chip.id, patch);
261
+ },
262
+ onClose: closeParamPanel
263
+ });
264
+ if (body === null || body === undefined) return;
252
265
  setParamEdit(function (prev) {
253
266
  return (prev === null || prev === void 0 ? void 0 : prev.chipId) === chipId ? null : {
254
267
  chipId: chipId,
255
268
  anchor: anchor
256
269
  };
257
270
  });
258
- }, [renderParamPanel]);
271
+ }, [closeParamPanel, renderParamPanel]);
259
272
 
260
273
  /* ---- ref 实例方法 ----
261
274
  * editor.clear() 内部已经会调 onChange(''),会经由 ComposerEditor 的
@@ -264,38 +277,39 @@ export var Composer = /*#__PURE__*/forwardRef(function Composer(_ref, ref) {
264
277
  useImperativeHandle(ref, function () {
265
278
  return {
266
279
  focus: function focus(options) {
267
- var _editorRef$current4;
268
- return (_editorRef$current4 = editorRef.current) === null || _editorRef$current4 === void 0 ? void 0 : _editorRef$current4.focus(options);
280
+ var _editorRef$current5;
281
+ return (_editorRef$current5 = editorRef.current) === null || _editorRef$current5 === void 0 ? void 0 : _editorRef$current5.focus(options);
269
282
  },
270
283
  blur: function blur() {
271
- var _editorRef$current5;
272
- return (_editorRef$current5 = editorRef.current) === null || _editorRef$current5 === void 0 ? void 0 : _editorRef$current5.blur();
284
+ var _editorRef$current6;
285
+ return (_editorRef$current6 = editorRef.current) === null || _editorRef$current6 === void 0 ? void 0 : _editorRef$current6.blur();
273
286
  },
274
287
  clear: function clear() {
275
- var _editorRef$current6;
276
- return (_editorRef$current6 = editorRef.current) === null || _editorRef$current6 === void 0 ? void 0 : _editorRef$current6.clear();
288
+ var _editorRef$current7;
289
+ return (_editorRef$current7 = editorRef.current) === null || _editorRef$current7 === void 0 ? void 0 : _editorRef$current7.clear();
277
290
  },
278
291
  insertSkill: function insertSkill(skill) {
279
- var _editorRef$current7, _editorRef$current8;
292
+ var _editorRef$current8, _editorRef$current9;
280
293
  var data = createInvocationChipData(skill);
281
- (_editorRef$current7 = editorRef.current) === null || _editorRef$current7 === void 0 || _editorRef$current7.insertChip(data);
282
- (_editorRef$current8 = editorRef.current) === null || _editorRef$current8 === void 0 || _editorRef$current8.focus();
294
+ (_editorRef$current8 = editorRef.current) === null || _editorRef$current8 === void 0 || _editorRef$current8.insertChip(data);
295
+ (_editorRef$current9 = editorRef.current) === null || _editorRef$current9 === void 0 || _editorRef$current9.focus();
283
296
  if (skill.initialState === 'pending') openParamPanel(data.id);
284
297
  return data.id;
285
298
  },
286
299
  updateChipData: function updateChipData(id, patch) {
287
- var _editorRef$current9;
288
- return (_editorRef$current9 = editorRef.current) === null || _editorRef$current9 === void 0 ? void 0 : _editorRef$current9.updateChipData(id, patch);
300
+ var _editorRef$current10;
301
+ return (_editorRef$current10 = editorRef.current) === null || _editorRef$current10 === void 0 ? void 0 : _editorRef$current10.updateChipData(id, patch);
289
302
  },
290
303
  get nativeElement() {
291
- var _editorRef$current$na, _editorRef$current10;
292
- return (_editorRef$current$na = (_editorRef$current10 = editorRef.current) === null || _editorRef$current10 === void 0 ? void 0 : _editorRef$current10.nativeElement) !== null && _editorRef$current$na !== void 0 ? _editorRef$current$na : null;
304
+ var _editorRef$current$na, _editorRef$current11;
305
+ return (_editorRef$current$na = (_editorRef$current11 = editorRef.current) === null || _editorRef$current11 === void 0 ? void 0 : _editorRef$current11.nativeElement) !== null && _editorRef$current$na !== void 0 ? _editorRef$current$na : null;
293
306
  }
294
307
  };
295
308
  });
296
309
  var updateText = useCallback(function (v) {
310
+ var _editorRef$current$ge2, _editorRef$current12;
297
311
  setText(v);
298
- onChangeProp === null || onChangeProp === void 0 || onChangeProp(v);
312
+ onChangeProp === null || onChangeProp === void 0 || onChangeProp(v, (_editorRef$current$ge2 = (_editorRef$current12 = editorRef.current) === null || _editorRef$current12 === void 0 ? void 0 : _editorRef$current12.getChips()) !== null && _editorRef$current$ge2 !== void 0 ? _editorRef$current$ge2 : []);
299
313
  }, [setText, onChangeProp]);
300
314
 
301
315
  /* ---- Attachments controlled writer ----
@@ -385,8 +399,8 @@ export var Composer = /*#__PURE__*/forwardRef(function Composer(_ref, ref) {
385
399
  * `onAttachmentsChange={setAttachments}` 直接回写。
386
400
  * - webSearch 无受控接口,直接清。 */
387
401
  var handleSend = useCallback( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee() {
388
- var _editorRef$current$ge2, _editorRef$current11;
389
- var chips, segments, hasAttachments, meta, hasMeta, result, _editorRef$current12;
402
+ var _editorRef$current$ge3, _editorRef$current13;
403
+ var chips, segments, hasAttachments, meta, hasMeta, result, _editorRef$current14;
390
404
  return _regeneratorRuntime().wrap(function _callee$(_context) {
391
405
  while (1) switch (_context.prev = _context.next) {
392
406
  case 0:
@@ -405,7 +419,7 @@ export var Composer = /*#__PURE__*/forwardRef(function Composer(_ref, ref) {
405
419
  }
406
420
  return _context.abrupt("return");
407
421
  case 4:
408
- chips = (_editorRef$current$ge2 = (_editorRef$current11 = editorRef.current) === null || _editorRef$current11 === void 0 ? void 0 : _editorRef$current11.getChips()) !== null && _editorRef$current$ge2 !== void 0 ? _editorRef$current$ge2 : [];
422
+ chips = (_editorRef$current$ge3 = (_editorRef$current13 = editorRef.current) === null || _editorRef$current13 === void 0 ? void 0 : _editorRef$current13.getChips()) !== null && _editorRef$current$ge3 !== void 0 ? _editorRef$current$ge3 : [];
409
423
  segments = rawValueToSegments(text, chips);
410
424
  hasAttachments = attachments.length > 0;
411
425
  if (!(!segmentsHasContent(segments) && !hasAttachments)) {
@@ -430,7 +444,7 @@ export var Composer = /*#__PURE__*/forwardRef(function Composer(_ref, ref) {
430
444
  case 18:
431
445
  closeParamPanel();
432
446
  if (valueProp === undefined) {
433
- (_editorRef$current12 = editorRef.current) === null || _editorRef$current12 === void 0 || _editorRef$current12.clear();
447
+ (_editorRef$current14 = editorRef.current) === null || _editorRef$current14 === void 0 || _editorRef$current14.clear();
434
448
  }
435
449
  if (attachmentsProp === undefined) {
436
450
  setAttachments([]);
@@ -540,7 +554,7 @@ export var Composer = /*#__PURE__*/forwardRef(function Composer(_ref, ref) {
540
554
  updateAttachments([].concat(_toConsumableArray(attachments), _toConsumableArray(accepted)));
541
555
  }, [accept, attachments, attachmentsDisabled, disabled, maxFileCount, maxFileSize, maxTotalSize, onAttachFiles, updateAttachments]);
542
556
  var handleFileChange = function handleFileChange(e) {
543
- var _editorRef$current13;
557
+ var _editorRef$current15;
544
558
  var files = e.target.files;
545
559
  if (!files) return;
546
560
  addFilesFromList(Array.from(files));
@@ -548,7 +562,7 @@ export var Composer = /*#__PURE__*/forwardRef(function Composer(_ref, ref) {
548
562
  /* 文件框关闭后焦点回到 editor:
549
563
  * 键盘(Tab + Enter)唤起文件框的路径下按钮持有焦点,
550
564
  * 不夺回焦点时 Enter 会再次激活按钮而不是发送 */
551
- (_editorRef$current13 = editorRef.current) === null || _editorRef$current13 === void 0 || _editorRef$current13.focus();
565
+ (_editorRef$current15 = editorRef.current) === null || _editorRef$current15 === void 0 || _editorRef$current15.focus();
552
566
  };
553
567
  var _useState19 = useState(false),
554
568
  _useState20 = _slicedToArray(_useState19, 2),
@@ -590,14 +604,14 @@ export var Composer = /*#__PURE__*/forwardRef(function Composer(_ref, ref) {
590
604
  var handleSelectSkill = useCallback(function (skill, source) {
591
605
  var data = createInvocationChipData(skill);
592
606
  if (source === 'trigger') {
593
- var _editorRef$current14;
594
- (_editorRef$current14 = editorRef.current) === null || _editorRef$current14 === void 0 || _editorRef$current14.replaceTriggerWithChip(data);
607
+ var _editorRef$current16;
608
+ (_editorRef$current16 = editorRef.current) === null || _editorRef$current16 === void 0 || _editorRef$current16.replaceTriggerWithChip(data);
595
609
  setTriggerInfo(null);
596
610
  } else {
597
- var _editorRef$current15, _editorRef$current16;
598
- (_editorRef$current15 = editorRef.current) === null || _editorRef$current15 === void 0 || _editorRef$current15.insertChip(data);
611
+ var _editorRef$current17, _editorRef$current18;
612
+ (_editorRef$current17 = editorRef.current) === null || _editorRef$current17 === void 0 || _editorRef$current17.insertChip(data);
599
613
  setToolMenuOpen(false);
600
- (_editorRef$current16 = editorRef.current) === null || _editorRef$current16 === void 0 || _editorRef$current16.focus();
614
+ (_editorRef$current18 = editorRef.current) === null || _editorRef$current18 === void 0 || _editorRef$current18.focus();
601
615
  }
602
616
  if (skill.initialState === 'pending') openParamPanel(data.id);
603
617
  }, [openParamPanel]);
@@ -681,9 +695,9 @@ export var Composer = /*#__PURE__*/forwardRef(function Composer(_ref, ref) {
681
695
  return true;
682
696
  }
683
697
  if (e.key === 'Escape') {
684
- var _editorRef$current17;
698
+ var _editorRef$current19;
685
699
  e.preventDefault();
686
- (_editorRef$current17 = editorRef.current) === null || _editorRef$current17 === void 0 || _editorRef$current17.cancelTrigger();
700
+ (_editorRef$current19 = editorRef.current) === null || _editorRef$current19 === void 0 || _editorRef$current19.cancelTrigger();
687
701
  setTriggerInfo(null);
688
702
  return true;
689
703
  }
@@ -1009,9 +1023,9 @@ export var Composer = /*#__PURE__*/forwardRef(function Composer(_ref, ref) {
1009
1023
  "data-odn-composer-file-input": true,
1010
1024
  onChange: handleFileChange
1011
1025
  });
1012
- var paramPanelNode = function (_editorRef$current$ge3, _editorRef$current18, _boxRef$current) {
1026
+ var paramPanelNode = function (_editorRef$current$ge4, _editorRef$current20, _boxRef$current) {
1013
1027
  if (!paramEdit || !renderParamPanel) return null;
1014
- var chips = (_editorRef$current$ge3 = (_editorRef$current18 = editorRef.current) === null || _editorRef$current18 === void 0 ? void 0 : _editorRef$current18.getChips()) !== null && _editorRef$current$ge3 !== void 0 ? _editorRef$current$ge3 : [];
1028
+ var chips = (_editorRef$current$ge4 = (_editorRef$current20 = editorRef.current) === null || _editorRef$current20 === void 0 ? void 0 : _editorRef$current20.getChips()) !== null && _editorRef$current$ge4 !== void 0 ? _editorRef$current$ge4 : [];
1015
1029
  var chip = chips.find(function (c) {
1016
1030
  return c.id === paramEdit.chipId;
1017
1031
  });
@@ -1021,18 +1035,20 @@ export var Composer = /*#__PURE__*/forwardRef(function Composer(_ref, ref) {
1021
1035
  chip: chip,
1022
1036
  anchor: paramEdit.anchor,
1023
1037
  onApply: function onApply(patch) {
1024
- var _editorRef$current19;
1025
- (_editorRef$current19 = editorRef.current) === null || _editorRef$current19 === void 0 || _editorRef$current19.updateChipData(chip.id, patch);
1038
+ var _editorRef$current21;
1039
+ (_editorRef$current21 = editorRef.current) === null || _editorRef$current21 === void 0 || _editorRef$current21.updateChipData(chip.id, patch);
1026
1040
  },
1027
1041
  onClose: closeParamPanel
1028
1042
  };
1043
+ var body = renderParamPanel(ctx);
1044
+ if (body === null || body === undefined) return null;
1029
1045
  return /*#__PURE__*/React.createElement(InvocationParamPopover, {
1030
1046
  anchor: paramEdit.anchor,
1031
1047
  label: chip.label,
1032
1048
  icon: chip.icon,
1033
1049
  width: boxWidth,
1034
1050
  onClose: closeParamPanel
1035
- }, renderParamPanel(ctx));
1051
+ }, body);
1036
1052
  }();
1037
1053
  var editorNode = /*#__PURE__*/React.createElement(ComposerEditor, {
1038
1054
  ref: editorRef,
@@ -1042,6 +1058,7 @@ export var Composer = /*#__PURE__*/forwardRef(function Composer(_ref, ref) {
1042
1058
  },
1043
1059
  placeholder: placeholder,
1044
1060
  value: text,
1061
+ defaultChips: defaultChips,
1045
1062
  onChange: updateText,
1046
1063
  disabled: disabled,
1047
1064
  paramEditChipId: (_paramEdit$chipId = paramEdit === null || paramEdit === void 0 ? void 0 : paramEdit.chipId) !== null && _paramEdit$chipId !== void 0 ? _paramEdit$chipId : null,
@@ -1086,8 +1103,8 @@ export var Composer = /*#__PURE__*/forwardRef(function Composer(_ref, ref) {
1086
1103
  visible: triggerMenuVisible,
1087
1104
  onVisibleChange: function onVisibleChange(v) {
1088
1105
  if (!v) {
1089
- var _editorRef$current20;
1090
- (_editorRef$current20 = editorRef.current) === null || _editorRef$current20 === void 0 || _editorRef$current20.cancelTrigger();
1106
+ var _editorRef$current22;
1107
+ (_editorRef$current22 = editorRef.current) === null || _editorRef$current22 === void 0 || _editorRef$current22.cancelTrigger();
1091
1108
  setTriggerInfo(null);
1092
1109
  }
1093
1110
  },
@@ -1,6 +1,8 @@
1
1
  /// <reference types="react" />
2
2
  import type { ChipData } from '../_genui-types';
3
3
  export declare function isMentionChip(chip: ChipData): boolean;
4
+ /** 仅待补充 / 已填参数的 invocation 可点开面板;无参数 skill 无 hover、不可点。 */
5
+ export declare function chipHasEditableParams(chip: ChipData): boolean;
4
6
  export interface ComposerInlineRefProps {
5
7
  data: ChipData;
6
8
  /** 参数面板打开时高亮 */
@@ -4,6 +4,17 @@ import { chipToInvocationData, chipToMentionData } from "./send-meta";
4
4
  export function isMentionChip(chip) {
5
5
  return chip.kind === 'mention';
6
6
  }
7
+
8
+ /** 仅待补充 / 已填参数的 invocation 可点开面板;无参数 skill 无 hover、不可点。 */
9
+ export function chipHasEditableParams(chip) {
10
+ if (isMentionChip(chip)) return false;
11
+ if (chip.state === 'pending') return true;
12
+ var payload = chip.payload;
13
+ if (!payload) return false;
14
+ return Object.values(payload).some(function (v) {
15
+ return v !== null && v !== undefined && v !== '';
16
+ });
17
+ }
7
18
  /** Composer 内联引用视觉:按 kind 派发 Invocation(/)或 Mention(@)。 */
8
19
  export function ComposerInlineRef(_ref) {
9
20
  var data = _ref.data,
@@ -8,7 +8,7 @@ export function chipToInvocationData(chip) {
8
8
  return {
9
9
  id: chip.id,
10
10
  refId: chip.refId,
11
- kind: chip.kind === 'mention' || !chip.kind ? 'skill' : chip.kind,
11
+ kind: chip.kind === 'mention' || !chip.kind || chip.kind === 'invocation' ? 'skill' : chip.kind,
12
12
  label: chip.label,
13
13
  icon: chip.icon,
14
14
  state: chip.state,
@@ -272,7 +272,8 @@
272
272
  white-space: nowrap;
273
273
  }
274
274
 
275
- /* 内联引用 host:Portal 注入 Invocation / Mention,视觉由组件自带样式承担 */
275
+ /* 内联引用 host:Portal 注入 Invocation / Mention
276
+ * 必须 inline(不能 inline-block),让内部文字参与同一行基线。 */
276
277
  [data-odn-composer] [data-odn-composer-chip-host] {
277
278
  display: inline;
278
279
  vertical-align: baseline;
@@ -301,31 +302,25 @@
301
302
  display: inline;
302
303
  }
303
304
 
304
- /* editor 内跟随正文 inherit,避免与外层 14/24 双写冲突。
305
- * chip 与正文按同一文本节奏排版:
306
- * - 移除额外 margin / padding,不再制造视觉“假空白”
307
- * - 间距由真实输入空格控制(插入 chip 后会自动补一个可删除空格) */
305
+ /* editor 内跟随正文字号 / 行高,蓝字与「请用」同一套行盒。
306
+ * 与正文间距仍由真实输入空格控制。 */
308
307
  [data-odn-composer] [data-odn-composer-editor] [data-odn-invocation],
309
308
  [data-odn-composer] [data-odn-composer-editor] [data-odn-mention] {
310
- margin-inline: 0;
311
- padding-left: 0;
312
- padding-right: 0;
313
- border-radius: 0;
314
309
  font-size: inherit;
315
310
  line-height: inherit;
316
311
  }
317
312
 
318
- /* 键盘输入模态:鼠标会被隐藏,此时不应沿用旧鼠标位置触发 hover 态。 */
319
- [data-odn-composer] [data-odn-composer-editor][data-odn-input-modality=keyboard] [data-odn-invocation]:hover:not([data-state=active]),
320
- [data-odn-composer] [data-odn-composer-editor][data-odn-input-modality=keyboard] [data-odn-mention]:hover:not([data-state=active]) {
321
- background: transparent;
313
+ /* 键盘输入模态:鼠标会被隐藏,此时不应沿用旧鼠标位置触发 hover 加深。
314
+ * 回到常驻浅底,而不是透明(否则视觉锚点会丢)。 */
315
+ [data-odn-composer] [data-odn-composer-editor][data-odn-input-modality=keyboard] [data-odn-invocation][data-hoverable]:hover:not([data-state=active]),
316
+ [data-odn-composer] [data-odn-composer-editor][data-odn-input-modality=keyboard] [data-odn-mention][data-hoverable]:hover:not([data-state=active]) {
317
+ background: var(--odn-inline-ref-bg);
322
318
  }
323
319
 
324
320
  /* chip 在 contentEditable=false 下无原生 selection 高亮,自绘选中态 */
325
321
  [data-odn-composer] [data-odn-composer-chip-host][data-selected] [data-odn-invocation],
326
322
  [data-odn-composer] [data-odn-composer-chip-host][data-selected] [data-odn-mention] {
327
323
  background: color-mix(in srgb, var(--odn-color-solid-black-12) 12%, transparent);
328
- border-radius: 0;
329
324
  transition: none;
330
325
  }
331
326
 
package/dist/index.d.ts CHANGED
@@ -55,7 +55,7 @@ export { default as ActionBar, type ActionBarProps } from './action-bar';
55
55
  export { default as AgentStep, type AgentStepGroupProps, type AgentStepProps, } from './agent-step';
56
56
  export { default as AgentThink, type AgentThinkProps } from './agent-think';
57
57
  export { APPROVAL_DEFAULT_ACTIONS_HINT, default as Approval, type ApprovalDecision, type ApprovalProps, type ApprovalResolvePayload, type ApprovalSpec, type ApprovalSummaryItem, } from './approval';
58
- export { ARTIFACT_DEDICATED_FILE_ICON_TYPES, ARTIFACT_FILE_GLOW_COLORS, ARTIFACT_FILE_ICON_TYPES, default as Artifact, ArtifactFileIcon, getArtifactActionFromKind, getArtifactGlowColor, type ArtifactAction, type ArtifactActionKind, type ArtifactFileIconProps, type ArtifactFileIconSize, type ArtifactFileIconType, type ArtifactProps, type ArtifactSize, } from './artifact';
58
+ export { ARTIFACT_DEDICATED_FILE_ICON_TYPES, ARTIFACT_FILE_GLOW_COLORS, ARTIFACT_FILE_ICON_TYPES, default as Artifact, ArtifactFileIcon, getArtifactAction, getArtifactActionFromKind, getArtifactGlowColor, type ArtifactAction, type ArtifactActionKind, type ArtifactFileIconProps, type ArtifactFileIconSize, type ArtifactFileIconType, type ArtifactProps, type ArtifactSize, } from './artifact';
59
59
  export { default as Attachments, type AttachmentsProps } from './attachments';
60
60
  export { default as ChatItem, formatRelativeTime, type ChatItemProps, } from './chat-item';
61
61
  export { default as ChatList, matchChatListFilterTime, matchChatListFilterType, type ChatListFilterTime, type ChatListFilterType, type ChatListItem, type ChatListProps, } from './chat-list';
@@ -68,7 +68,7 @@ export { default as Fab, type FabProps } from './fab';
68
68
  export { default as Invocation, InvocationParamPopover, type InvocationParamPopoverProps, type InvocationProps, } from './invocation';
69
69
  export { default as Mention, type MentionProps } from './mention';
70
70
  export { default as MessageImage, type MessageImageItem, type MessageImageProps, } from './message-image';
71
- export { default as PreviewPanel, type PreviewPanelActionTooltips, type PreviewPanelProps, } from './preview-panel';
71
+ export { default as PreviewPanel, type PreviewPanelActionTooltips, type PreviewPanelArtifact, type PreviewPanelProps, } from './preview-panel';
72
72
  export { default as Provenance, type ProvenanceProps, type ProvenanceType, } from './provenance';
73
73
  export { default as SkillSlot, type SkillSlotHandle, type SkillSlotProps, } from './skill-slot';
74
74
  export { default as Sources, type SourcesProps } from './sources';
@@ -78,6 +78,6 @@ export { default as Suggestions, type SuggestionsProps } from './suggestions';
78
78
  export { default as UserBubble, type UserBubbleProps } from './user-bubble';
79
79
  export { default as Welcome, type WelcomeProps } from './welcome';
80
80
  export { ComposerSegmentType } from './_genui-types';
81
- export type { AgentEvent, Attachment, ChatMessage, ComposerInvocationSegment, ComposerMentionSegment, ComposerSegment, ComposerTextSegment, Conversation, InlineRefState, InvocationData, MentionData, MessageSnapshot, PreviewTab, PreviewTarget, SendMeta, SkillGroup, SkillItem, Source, TextData, ToolCall, ToolStatus, } from './_genui-types';
81
+ export type { AgentEvent, Attachment, ChatMessage, ChipData, ComposerInvocationSegment, ComposerMentionSegment, ComposerSegment, ComposerTextSegment, Conversation, InlineRefState, InvocationData, MentionData, MessageSnapshot, PreviewTab, PreviewTarget, SendMeta, SkillGroup, SkillItem, Source, TextData, ToolCall, ToolStatus, } from './_genui-types';
82
82
  export type { InterruptBase, InterruptIntent, InterruptStatus, } from './_interrupt-types';
83
83
  export { isInvocationSegment, isMentionSegment, isTextSegment, rawValueToSegments, segmentsHasContent, segmentsToReadableText, type SegmentsToReadableTextOptions, } from './composer/segments';
package/dist/index.js CHANGED
@@ -61,7 +61,7 @@ export { default as ActionBar } from "./action-bar";
61
61
  export { default as AgentStep } from "./agent-step";
62
62
  export { default as AgentThink } from "./agent-think";
63
63
  export { APPROVAL_DEFAULT_ACTIONS_HINT, default as Approval } from "./approval";
64
- export { ARTIFACT_DEDICATED_FILE_ICON_TYPES, ARTIFACT_FILE_GLOW_COLORS, ARTIFACT_FILE_ICON_TYPES, default as Artifact, ArtifactFileIcon, getArtifactActionFromKind, getArtifactGlowColor } from "./artifact";
64
+ export { ARTIFACT_DEDICATED_FILE_ICON_TYPES, ARTIFACT_FILE_GLOW_COLORS, ARTIFACT_FILE_ICON_TYPES, default as Artifact, ArtifactFileIcon, getArtifactAction, getArtifactActionFromKind, getArtifactGlowColor } from "./artifact";
65
65
  export { default as Attachments } from "./attachments";
66
66
  export { default as ChatItem, formatRelativeTime } from "./chat-item";
67
67
  export { default as ChatList, matchChatListFilterTime, matchChatListFilterType } from "./chat-list";
@@ -1,4 +1,6 @@
1
1
  import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
2
+ import { resolveInvocationCategoryIcon } from "../_genui-inline-ref";
3
+ import Icon from "../icon";
2
4
  import Popover from "../popover";
3
5
  import "./style";
4
6
  function formatPayloadSummary(payload) {
@@ -6,7 +8,7 @@ function formatPayloadSummary(payload) {
6
8
  var entries = Object.entries(payload).filter(function (_ref) {
7
9
  var _ref2 = _slicedToArray(_ref, 2),
8
10
  v = _ref2[1];
9
- return v != null && v !== '';
11
+ return v !== null && v !== undefined && v !== '';
10
12
  });
11
13
  if (entries.length === 0) return null;
12
14
  return entries.map(function (_ref3) {
@@ -16,17 +18,40 @@ function formatPayloadSummary(payload) {
16
18
  return "".concat(k, ": ").concat(String(v));
17
19
  }).join(' · ');
18
20
  }
19
- export function Invocation(_ref5) {
21
+ function InvocationHoverPopup(_ref5) {
22
+ var label = _ref5.label,
23
+ icon = _ref5.icon,
24
+ summary = _ref5.summary;
25
+ return /*#__PURE__*/React.createElement("div", {
26
+ "data-odn-invocation-popover-inner": true
27
+ }, /*#__PURE__*/React.createElement("div", {
28
+ "data-odn-invocation-popover-title": true
29
+ }, icon ? /*#__PURE__*/React.createElement("span", {
30
+ "data-odn-invocation-icon": true
31
+ }, /*#__PURE__*/React.createElement(Icon, {
32
+ name: icon,
33
+ size: 12
34
+ })) : null, label), summary ? /*#__PURE__*/React.createElement("div", {
35
+ "data-odn-invocation-popover-summary": true
36
+ }, summary) : /*#__PURE__*/React.createElement("div", {
37
+ "data-odn-invocation-popover-empty": true
38
+ }, "\u672A\u586B\u53C2\u6570"));
39
+ }
40
+ export function Invocation(_ref6) {
20
41
  var _data$state;
21
- var data = _ref5.data,
22
- _ref5$interactive = _ref5.interactive,
23
- interactive = _ref5$interactive === void 0 ? false : _ref5$interactive,
24
- _ref5$active = _ref5.active,
25
- active = _ref5$active === void 0 ? false : _ref5$active,
26
- onClick = _ref5.onClick;
42
+ var data = _ref6.data,
43
+ _ref6$interactive = _ref6.interactive,
44
+ interactive = _ref6$interactive === void 0 ? false : _ref6$interactive,
45
+ _ref6$active = _ref6.active,
46
+ active = _ref6$active === void 0 ? false : _ref6$active,
47
+ onClick = _ref6.onClick;
27
48
  var clickable = interactive && !!onClick;
28
49
  /** 状态优先级:active > data.state > 'complete' */
29
50
  var state = active ? 'active' : (_data$state = data.state) !== null && _data$state !== void 0 ? _data$state : 'complete';
51
+ var categoryIcon = resolveInvocationCategoryIcon(data.kind, data.icon);
52
+ var summary = formatPayloadSummary(data.payload);
53
+ var hasHoverPopup = !interactive && (!!summary || data.state === 'pending');
54
+ var hoverable = clickable || hasHoverPopup;
30
55
  var handleClick = clickable ? function (e) {
31
56
  e.preventDefault();
32
57
  e.stopPropagation();
@@ -40,18 +65,18 @@ export function Invocation(_ref5) {
40
65
  "data-odn-invocation": true,
41
66
  "data-state": state,
42
67
  "data-clickable": clickable || undefined,
68
+ "data-hoverable": hoverable || undefined,
43
69
  onClick: handleClick,
44
70
  onMouseDown: handleMouseDown
45
- }, /*#__PURE__*/React.createElement("span", {
46
- "data-odn-invocation-slash": true,
47
- "aria-hidden": true
48
- }, "/"), /*#__PURE__*/React.createElement("span", {
71
+ }, categoryIcon ? /*#__PURE__*/React.createElement("span", {
72
+ "data-odn-invocation-icon": true
73
+ }, /*#__PURE__*/React.createElement(Icon, {
74
+ name: categoryIcon,
75
+ size: 14
76
+ })) : null, /*#__PURE__*/React.createElement("span", {
49
77
  "data-odn-invocation-label": true
50
78
  }, data.label));
51
- if (interactive) return core;
52
- var summary = formatPayloadSummary(data.payload);
53
- /** 只读态:有 payload 摘要 → hover;pending 但无 payload → 「未填参数」;否则不弹 */
54
- if (!summary && data.state !== 'pending') return core;
79
+ if (!hasHoverPopup) return core;
55
80
  return /*#__PURE__*/React.createElement(Popover, {
56
81
  trigger: "hover",
57
82
  placement: "top",
@@ -61,25 +86,10 @@ export function Invocation(_ref5) {
61
86
  mouseLeaveDelay: 0.1,
62
87
  popup: /*#__PURE__*/React.createElement(InvocationHoverPopup, {
63
88
  label: data.label,
89
+ icon: categoryIcon,
64
90
  summary: summary
65
91
  })
66
92
  }, core);
67
93
  }
68
- function InvocationHoverPopup(_ref6) {
69
- var label = _ref6.label,
70
- summary = _ref6.summary;
71
- return /*#__PURE__*/React.createElement("div", {
72
- "data-odn-invocation-popover-inner": true
73
- }, /*#__PURE__*/React.createElement("div", {
74
- "data-odn-invocation-popover-title": true
75
- }, /*#__PURE__*/React.createElement("span", {
76
- "data-odn-invocation-popover-slash": true,
77
- "aria-hidden": true
78
- }, "/"), label), summary ? /*#__PURE__*/React.createElement("div", {
79
- "data-odn-invocation-popover-summary": true
80
- }, summary) : /*#__PURE__*/React.createElement("div", {
81
- "data-odn-invocation-popover-empty": true
82
- }, "\u672A\u586B\u53C2\u6570"));
83
- }
84
94
  export { InvocationParamPopover } from "./param-popover";
85
95
  export default Invocation;
@@ -1,17 +1,34 @@
1
1
  @charset "UTF-8";
2
- /* 默认排版与 Composer 输入区一致(14 / 24);在 editor 内由下方 inherit 规则跟随正文 */
2
+ /* Invocation / Mention 完成后 chip 共用皮:默认无底 + 品牌色字 + 品类 icon
3
+ *
4
+ * 必须是 inline,不能是 inline-flex / inline-block。
5
+ * 蓝字要和旁边正文走同一条基线、同一套行高;做成独立盒子后,
6
+ * 内部文字基线永远对不齐(1em 盒子贴基线时,字在盒子里还会再上浮一截)。
7
+ */
8
+ /* 默认排版与 Composer 输入区一致(14 / 24);在 editor / 气泡内跟随正文 inherit */
3
9
  [data-odn-invocation] {
4
- display: inline-flex;
5
- align-items: center;
10
+ display: inline;
11
+ vertical-align: baseline;
6
12
  white-space: nowrap;
7
13
  word-break: keep-all;
8
14
  overflow-wrap: normal;
9
15
  margin: 0;
10
- padding: 0;
11
- border-radius: 0;
12
- background: transparent;
16
+ padding: 0 4px;
17
+ border-radius: 4px;
18
+ --odn-inline-ref-bg: transparent;
19
+ --odn-inline-ref-bg-hover: color-mix(
20
+ in srgb,
21
+ var(--odn-color-brand-6) 12%,
22
+ transparent
23
+ );
24
+ --odn-inline-ref-bg-active: color-mix(
25
+ in srgb,
26
+ var(--odn-color-brand-6) 16%,
27
+ transparent
28
+ );
29
+ background: var(--odn-inline-ref-bg);
13
30
  color: var(--odn-color-brand-7, var(--odn-color-brand-6));
14
- font-weight: 500;
31
+ font-weight: 400;
15
32
  font-size: 14px;
16
33
  line-height: 24px;
17
34
  cursor: default;
@@ -22,22 +39,31 @@
22
39
  [data-odn-invocation][data-state=pending] {
23
40
  color: color-mix(in srgb, var(--odn-color-brand-7, var(--odn-color-brand-6)) 60%, transparent);
24
41
  }
25
- [data-odn-invocation][data-state=active], [data-odn-invocation]:hover {
26
- background: color-mix(in srgb, var(--odn-color-brand-6) 12%, transparent);
42
+ [data-odn-invocation][data-hoverable]:hover {
43
+ background: var(--odn-inline-ref-bg-hover);
27
44
  }
28
45
  [data-odn-invocation][data-state=active] {
46
+ background: var(--odn-inline-ref-bg-active);
29
47
  border-bottom: none;
30
48
  }
31
49
  [data-odn-invocation][data-clickable] {
32
50
  cursor: pointer;
33
51
  }
34
52
 
35
- [data-odn-invocation-slash] {
36
- opacity: 0.7;
37
- }
38
-
39
- [data-odn-invocation][data-state=pending] [data-odn-invocation-slash] {
40
- opacity: 1;
53
+ [data-odn-invocation-icon] {
54
+ display: inline-block;
55
+ width: 1em;
56
+ height: 1em;
57
+ margin-inline-end: 2px;
58
+ /* 1em SVG 贴基线会整块落在字的上方,下移与汉字视觉中心对齐 */
59
+ vertical-align: -0.15em;
60
+ line-height: 0;
61
+ color: inherit;
62
+ }
63
+ [data-odn-invocation-icon] :where(svg) {
64
+ display: block;
65
+ width: 100%;
66
+ height: 100%;
41
67
  }
42
68
 
43
69
  [data-odn-invocation-popover-inner] {
@@ -49,23 +75,19 @@
49
75
  [data-odn-invocation-popover-title] {
50
76
  display: inline-flex;
51
77
  align-items: center;
52
- gap: 1px;
53
- font-weight: 500;
78
+ gap: 2px;
79
+ font-weight: 400;
54
80
  color: var(--odn-color-brand-7, var(--odn-color-brand-6));
55
81
  }
56
82
 
57
- [data-odn-invocation-popover-slash] {
58
- opacity: 0.7;
59
- }
60
-
61
83
  [data-odn-invocation-popover-summary],
62
84
  [data-odn-invocation-popover-empty] {
63
85
  display: inline-block;
64
86
  align-self: flex-start;
65
87
  padding: 2px 6px;
66
88
  border-radius: 4px;
67
- background: color-mix(in srgb, var(--odn-color-brand-6) 10%, transparent);
68
- color: var(--odn-color-brand-7, var(--odn-color-brand-6));
89
+ background: var(--odn-color-black-4);
90
+ color: var(--odn-color-solid-black-10);
69
91
  font-size: 12px;
70
92
  line-height: 1.4;
71
93
  }