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.
Files changed (48) hide show
  1. package/dist/_genui-types.d.ts +72 -27
  2. package/dist/action-bar/style/index.css +2 -2
  3. package/dist/agent-step/style/index.css +1 -1
  4. package/dist/attachments/style/index.css +5 -5
  5. package/dist/chat-item/style/index.css +2 -2
  6. package/dist/composer/clipboard.d.ts +1 -1
  7. package/dist/composer/editor.d.ts +10 -2
  8. package/dist/composer/editor.js +199 -35
  9. package/dist/composer/hooks/useChipManager.d.ts +8 -3
  10. package/dist/composer/hooks/useChipManager.js +105 -10
  11. package/dist/composer/index.d.ts +17 -2
  12. package/dist/composer/index.js +136 -65
  13. package/dist/composer/inline-ref.d.ts +6 -2
  14. package/dist/composer/inline-ref.js +10 -3
  15. package/dist/composer/param-panel.d.ts +14 -0
  16. package/dist/composer/param-panel.js +1 -0
  17. package/dist/composer/segments.d.ts +29 -0
  18. package/dist/composer/segments.js +83 -0
  19. package/dist/composer/send-meta.d.ts +7 -4
  20. package/dist/composer/send-meta.js +12 -52
  21. package/dist/composer/style/index.css +27 -8
  22. package/dist/composer/utils.d.ts +35 -1
  23. package/dist/composer/utils.js +281 -36
  24. package/dist/fab/style/index.css +1 -1
  25. package/dist/index.d.ts +4 -2
  26. package/dist/index.js +4 -2
  27. package/dist/invocation/index.d.ts +7 -2
  28. package/dist/invocation/index.js +14 -8
  29. package/dist/invocation/param-popover.d.ts +21 -0
  30. package/dist/invocation/param-popover.js +113 -0
  31. package/dist/invocation/style/index.css +33 -9
  32. package/dist/mention/index.d.ts +1 -6
  33. package/dist/mention/index.js +11 -8
  34. package/dist/mention/style/index.css +30 -9
  35. package/dist/preview-panel/index.js +11 -1
  36. package/dist/preview-panel/style/index.css +11 -0
  37. package/dist/skill-slot/index.js +5 -5
  38. package/dist/skill-slot/style/index.css +51 -27
  39. package/dist/suggestions/index.js +1 -5
  40. package/dist/suggestions/style/index.css +6 -7
  41. package/dist/user-bubble/index.js +9 -4
  42. package/dist/user-bubble/render-segments.d.ts +9 -0
  43. package/dist/user-bubble/render-segments.js +42 -0
  44. package/dist/user-bubble/style/index.css +9 -0
  45. package/dist/welcome/style/index.css +1 -1
  46. package/package.json +4 -4
  47. package/dist/composer/chip.d.ts +0 -36
  48. package/dist/composer/chip.js +0 -49
@@ -1,6 +1,8 @@
1
1
  /// <reference types="react" />
2
- import type { Attachment, SkillItem, SendMeta } from '../_genui-types';
2
+ import type { Attachment, ComposerSegment, SkillItem, SendMeta } from '../_genui-types';
3
+ import type { ComposerParamPanelContext } from './param-panel';
3
4
  import './style';
5
+ export type { ComposerParamPanelContext } from './param-panel';
4
6
  export type ComposerTool = 'attachment' | 'webSearch' | 'skill';
5
7
  export type ComposerVariant = 'full' | 'lite';
6
8
  export type SubmitType = 'enter' | 'shiftEnter';
@@ -33,7 +35,15 @@ export interface ComposerProps {
33
35
  defaultValue?: string;
34
36
  /** 输入框值变化回调 */
35
37
  onChange?: (value: string) => void;
36
- onSend: (text: string, meta?: SendMeta) => void;
38
+ /**
39
+ * 发送回调。
40
+ *
41
+ * `segments`:有序内容 IR,业务按数组顺序自定义拼后端。
42
+ * `meta`:附件 / 联网搜索等非正文数据;为空时不传。
43
+ *
44
+ * 兼容旧链路(需要单串文本):业务可调 `segmentsToReadableText(segments)`。
45
+ */
46
+ onSend: (segments: ComposerSegment[], meta?: SendMeta) => void;
37
47
  onStop?: () => void;
38
48
  isGenerating?: boolean;
39
49
  /**
@@ -133,6 +143,11 @@ export interface ComposerProps {
133
143
  * @default 20 * 1024 * 1024(20MB)
134
144
  */
135
145
  maxFileSize?: number;
146
+ /**
147
+ * 参数面板内容渲染。提供后 invocation chip 可点击打开面板;
148
+ * `SkillItem.initialState='pending'` 插入后会自动打开。
149
+ */
150
+ renderParamPanel?: (ctx: ComposerParamPanelContext) => React.ReactNode;
136
151
  className?: string;
137
152
  style?: React.CSSProperties;
138
153
  }
@@ -18,14 +18,28 @@ import Popover from "../popover";
18
18
  import Attachments from "../attachments";
19
19
  import { Message } from "../message";
20
20
  import SkillSlot from "../skill-slot";
21
+ import { InvocationParamPopover } from "../invocation/param-popover";
21
22
  import useControlledState from "../_util/useControlledState";
22
23
  import { ComposerEditor } from "./editor";
23
- import { buildSendMetaFromChips } from "./send-meta";
24
- import { stripMarkers } from "./utils";
24
+ import { isMentionChip } from "./inline-ref";
25
+ import { rawValueToSegments, segmentsHasContent } from "./segments";
25
26
  import "./style";
26
- var TOOL_BTN_ACTIVE = 'color-mix(in srgb, var(--odn-color-cyan-5) 10%, transparent)';
27
+ function createInvocationChipData(skill) {
28
+ return {
29
+ id: "skill-".concat(skill.id, "-").concat(Date.now().toString(36), "-").concat(Math.random().toString(36).slice(2, 6)),
30
+ label: skill.label,
31
+ icon: skill.icon,
32
+ kind: 'invocation',
33
+ state: skill.initialState,
34
+ payload: {
35
+ refId: skill.id
36
+ }
37
+ };
38
+ }
39
+ var TOOL_BTN_ACTIVE = 'color-mix(in srgb, var(--odn-color-brand-6) 10%, transparent)';
27
40
  var DEFAULT_TOOLS = ['attachment', 'webSearch', 'skill'];
28
41
  export var Composer = /*#__PURE__*/forwardRef(function Composer(_ref, ref) {
42
+ var _paramEdit$chipId;
29
43
  var valueProp = _ref.value,
30
44
  _ref$defaultValue = _ref.defaultValue,
31
45
  defaultValue = _ref$defaultValue === void 0 ? '' : _ref$defaultValue,
@@ -62,6 +76,7 @@ export var Composer = /*#__PURE__*/forwardRef(function Composer(_ref, ref) {
62
76
  maxFileCount = _ref$maxFileCount === void 0 ? 5 : _ref$maxFileCount,
63
77
  _ref$maxFileSize = _ref.maxFileSize,
64
78
  maxFileSize = _ref$maxFileSize === void 0 ? 20 * 1024 * 1024 : _ref$maxFileSize,
79
+ renderParamPanel = _ref.renderParamPanel,
65
80
  className = _ref.className,
66
81
  style = _ref.style;
67
82
  var _useControlledState = useControlledState(defaultValue, valueProp),
@@ -115,6 +130,40 @@ export var Composer = /*#__PURE__*/forwardRef(function Composer(_ref, ref) {
115
130
  setAtMax = _useState14[1];
116
131
  var fileInputRef = useRef(null);
117
132
  var editorRef = useRef(null);
133
+ var boxRef = useRef(null);
134
+ var _useState15 = useState(null),
135
+ _useState16 = _slicedToArray(_useState15, 2),
136
+ paramEdit = _useState16[0],
137
+ setParamEdit = _useState16[1];
138
+ var openParamPanel = useCallback(function (chipId) {
139
+ if (!renderParamPanel) return;
140
+ requestAnimationFrame(function () {
141
+ var _editorRef$current;
142
+ var host = (_editorRef$current = editorRef.current) === null || _editorRef$current === void 0 ? void 0 : _editorRef$current.getChipHost(chipId);
143
+ if (host) setParamEdit({
144
+ chipId: chipId,
145
+ anchor: host
146
+ });
147
+ });
148
+ }, [renderParamPanel]);
149
+ var closeParamPanel = useCallback(function () {
150
+ setParamEdit(null);
151
+ }, []);
152
+ var handleInlineRefClick = useCallback(function (chipId, anchor) {
153
+ var _editorRef$current$ge, _editorRef$current2;
154
+ if (!renderParamPanel) return;
155
+ var chips = (_editorRef$current$ge = (_editorRef$current2 = editorRef.current) === null || _editorRef$current2 === void 0 ? void 0 : _editorRef$current2.getChips()) !== null && _editorRef$current$ge !== void 0 ? _editorRef$current$ge : [];
156
+ var chip = chips.find(function (c) {
157
+ return c.id === chipId;
158
+ });
159
+ if (!chip || isMentionChip(chip)) return;
160
+ setParamEdit(function (prev) {
161
+ return (prev === null || prev === void 0 ? void 0 : prev.chipId) === chipId ? null : {
162
+ chipId: chipId,
163
+ anchor: anchor
164
+ };
165
+ });
166
+ }, [renderParamPanel]);
118
167
 
119
168
  /* ---- ref 实例方法 ----
120
169
  * editor.clear() 内部已经会调 onChange(''),会经由 ComposerEditor 的
@@ -123,32 +172,27 @@ export var Composer = /*#__PURE__*/forwardRef(function Composer(_ref, ref) {
123
172
  useImperativeHandle(ref, function () {
124
173
  return {
125
174
  focus: function focus(options) {
126
- var _editorRef$current;
127
- return (_editorRef$current = editorRef.current) === null || _editorRef$current === void 0 ? void 0 : _editorRef$current.focus(options);
175
+ var _editorRef$current3;
176
+ return (_editorRef$current3 = editorRef.current) === null || _editorRef$current3 === void 0 ? void 0 : _editorRef$current3.focus(options);
128
177
  },
129
178
  blur: function blur() {
130
- var _editorRef$current2;
131
- return (_editorRef$current2 = editorRef.current) === null || _editorRef$current2 === void 0 ? void 0 : _editorRef$current2.blur();
179
+ var _editorRef$current4;
180
+ return (_editorRef$current4 = editorRef.current) === null || _editorRef$current4 === void 0 ? void 0 : _editorRef$current4.blur();
132
181
  },
133
182
  clear: function clear() {
134
- var _editorRef$current3;
135
- return (_editorRef$current3 = editorRef.current) === null || _editorRef$current3 === void 0 ? void 0 : _editorRef$current3.clear();
183
+ var _editorRef$current5;
184
+ return (_editorRef$current5 = editorRef.current) === null || _editorRef$current5 === void 0 ? void 0 : _editorRef$current5.clear();
136
185
  },
137
186
  insertSkill: function insertSkill(skill) {
138
- var _editorRef$current4, _editorRef$current5;
139
- var data = {
140
- id: "c_".concat(Date.now(), "_").concat(Math.random().toString(36).slice(2, 6)),
141
- skillId: skill.id,
142
- label: skill.label,
143
- icon: skill.icon,
144
- kind: 'invocation'
145
- };
146
- (_editorRef$current4 = editorRef.current) === null || _editorRef$current4 === void 0 || _editorRef$current4.insertChip(data);
147
- (_editorRef$current5 = editorRef.current) === null || _editorRef$current5 === void 0 || _editorRef$current5.focus();
187
+ var _editorRef$current6, _editorRef$current7;
188
+ var data = createInvocationChipData(skill);
189
+ (_editorRef$current6 = editorRef.current) === null || _editorRef$current6 === void 0 || _editorRef$current6.insertChip(data);
190
+ (_editorRef$current7 = editorRef.current) === null || _editorRef$current7 === void 0 || _editorRef$current7.focus();
191
+ if (skill.initialState === 'pending') openParamPanel(data.id);
148
192
  },
149
193
  get nativeElement() {
150
- var _editorRef$current$na, _editorRef$current6;
151
- return (_editorRef$current$na = (_editorRef$current6 = editorRef.current) === null || _editorRef$current6 === void 0 ? void 0 : _editorRef$current6.nativeElement) !== null && _editorRef$current$na !== void 0 ? _editorRef$current$na : null;
194
+ var _editorRef$current$na, _editorRef$current8;
195
+ return (_editorRef$current$na = (_editorRef$current8 = editorRef.current) === null || _editorRef$current8 === void 0 ? void 0 : _editorRef$current8.nativeElement) !== null && _editorRef$current$na !== void 0 ? _editorRef$current$na : null;
152
196
  }
153
197
  };
154
198
  });
@@ -210,29 +254,30 @@ export var Composer = /*#__PURE__*/forwardRef(function Composer(_ref, ref) {
210
254
  }, [text, attachments.length, expanded]);
211
255
 
212
256
  /* ---- Send ----
213
- * 内部 text 是 raw value(chip 序列化为不可见 marker 字符)。对外 onSend:
214
- * - text 给 stripMarkers 之后的纯文本(旧业务收到的字符串保持纯净)
215
- * - invocations / mentions editor.getChips() 经 buildSendMetaFromChips 拆分;
216
- * chips 仍双写(deprecated)
257
+ * 内部 text 是 raw value(chip 序列化为零宽 marker)。
258
+ * 对外只有一份契约:`onSend(segments, meta?)`
259
+ * - segments:有序 IR(text / invocation / mention 交替)
260
+ * - meta:attachments / webSearch 等非正文数据;都为空时不传
217
261
  *
218
- * 发送后内部状态全部清空:text、attachments、webSearch——与 ChatGPT / Claude /
219
- * iMessage 等业界对话产品一致。attachments revoke blob URL:业务方在 onSend
220
- * 回调里可能仍持有 url(消息记录、本地预览等),由消费方负责回收。 */
262
+ * 需要单串文本的业务方在 onSend 内自行调 segmentsToReadableText。
263
+ * 发送后内部状态全部清空。attachments blob URL 由消费方负责回收。 */
221
264
  var handleSend = useCallback(function () {
222
- var _editorRef$current$ge, _editorRef$current7, _editorRef$current8;
265
+ var _editorRef$current$ge2, _editorRef$current9, _editorRef$current10;
223
266
  if (disabled) return;
224
- var plain = stripMarkers(text).trim();
225
- if (!plain && attachments.length === 0) return;
226
- var chips = (_editorRef$current$ge = (_editorRef$current7 = editorRef.current) === null || _editorRef$current7 === void 0 ? void 0 : _editorRef$current7.getChips()) !== null && _editorRef$current$ge !== void 0 ? _editorRef$current$ge : [];
227
- var meta = buildSendMetaFromChips(chips, {
228
- attachments: attachments.length > 0 ? attachments : undefined,
229
- webSearch: webSearch || undefined
230
- });
231
- onSend(plain, meta);
232
- (_editorRef$current8 = editorRef.current) === null || _editorRef$current8 === void 0 || _editorRef$current8.clear();
267
+ var chips = (_editorRef$current$ge2 = (_editorRef$current9 = editorRef.current) === null || _editorRef$current9 === void 0 ? void 0 : _editorRef$current9.getChips()) !== null && _editorRef$current$ge2 !== void 0 ? _editorRef$current$ge2 : [];
268
+ var segments = rawValueToSegments(text, chips);
269
+ var hasAttachments = attachments.length > 0;
270
+ if (!segmentsHasContent(segments) && !hasAttachments) return;
271
+ var meta = {};
272
+ if (hasAttachments) meta.attachments = attachments;
273
+ if (webSearch) meta.webSearch = true;
274
+ var hasMeta = hasAttachments || webSearch;
275
+ onSend(segments, hasMeta ? meta : undefined);
276
+ closeParamPanel();
277
+ (_editorRef$current10 = editorRef.current) === null || _editorRef$current10 === void 0 || _editorRef$current10.clear();
233
278
  setAttachments([]);
234
279
  setWebSearch(false);
235
- }, [text, attachments, webSearch, onSend]);
280
+ }, [text, attachments, webSearch, onSend, disabled, closeParamPanel]);
236
281
 
237
282
  /* ---- File upload ----
238
283
  * 三入口(按钮 / 拖入 / 粘贴)共用此函数。先做内置校验(数量、单文件体积、重名),
@@ -314,10 +359,10 @@ export var Composer = /*#__PURE__*/forwardRef(function Composer(_ref, ref) {
314
359
  addFilesFromList(Array.from(files));
315
360
  e.target.value = '';
316
361
  };
317
- var _useState15 = useState(false),
318
- _useState16 = _slicedToArray(_useState15, 2),
319
- fileDragOver = _useState16[0],
320
- setFileDragOver = _useState16[1];
362
+ var _useState17 = useState(false),
363
+ _useState18 = _slicedToArray(_useState17, 2),
364
+ fileDragOver = _useState18[0],
365
+ setFileDragOver = _useState18[1];
321
366
  var composerBoxFileDragAttrs = fileDragOver ? {
322
367
  'data-odn-composer-file-drag': ''
323
368
  } : {};
@@ -352,24 +397,19 @@ export var Composer = /*#__PURE__*/forwardRef(function Composer(_ref, ref) {
352
397
  * source = 'trigger' → editor.replaceTriggerWithChip 替换 `/` + query 整段
353
398
  * 任一入口选完后都关闭对应 menu。chip data 用 skill.id + 一次性实例 id。 */
354
399
  var handleSelectSkill = useCallback(function (skill, source) {
355
- var data = {
356
- id: "skill-".concat(skill.id, "-").concat(Date.now().toString(36), "-").concat(Math.random().toString(36).slice(2, 6)),
357
- skillId: skill.id,
358
- label: skill.label,
359
- icon: skill.icon,
360
- kind: 'invocation'
361
- };
400
+ var data = createInvocationChipData(skill);
362
401
  if (source === 'trigger') {
363
- var _editorRef$current9;
364
- (_editorRef$current9 = editorRef.current) === null || _editorRef$current9 === void 0 || _editorRef$current9.replaceTriggerWithChip(data);
402
+ var _editorRef$current11;
403
+ (_editorRef$current11 = editorRef.current) === null || _editorRef$current11 === void 0 || _editorRef$current11.replaceTriggerWithChip(data);
365
404
  setTriggerInfo(null);
366
405
  } else {
367
- var _editorRef$current10, _editorRef$current11;
368
- (_editorRef$current10 = editorRef.current) === null || _editorRef$current10 === void 0 || _editorRef$current10.insertChip(data);
406
+ var _editorRef$current12, _editorRef$current13;
407
+ (_editorRef$current12 = editorRef.current) === null || _editorRef$current12 === void 0 || _editorRef$current12.insertChip(data);
369
408
  setToolMenuOpen(false);
370
- (_editorRef$current11 = editorRef.current) === null || _editorRef$current11 === void 0 || _editorRef$current11.focus();
409
+ (_editorRef$current13 = editorRef.current) === null || _editorRef$current13 === void 0 || _editorRef$current13.focus();
371
410
  }
372
- }, []);
411
+ if (skill.initialState === 'pending') openParamPanel(data.id);
412
+ }, [openParamPanel]);
373
413
 
374
414
  /* trigger query 实时筛选 skills(substring match,case-insensitive)。
375
415
  * 没有 query / 没有 trigger → 返回原列表。 */
@@ -410,16 +450,16 @@ export var Composer = /*#__PURE__*/forwardRef(function Composer(_ref, ref) {
410
450
  });
411
451
  return true;
412
452
  }
413
- if (e.key === 'Enter' || e.key === 'Tab') {
453
+ if (e.key === 'Enter' && !e.shiftKey || e.key === 'Tab') {
414
454
  e.preventDefault();
415
455
  var _skill = list === null || list === void 0 ? void 0 : list[triggerActiveIndex];
416
456
  if (_skill) handleSelectSkill(_skill, 'trigger');
417
457
  return true;
418
458
  }
419
459
  if (e.key === 'Escape') {
420
- var _editorRef$current12;
460
+ var _editorRef$current14;
421
461
  e.preventDefault();
422
- (_editorRef$current12 = editorRef.current) === null || _editorRef$current12 === void 0 || _editorRef$current12.cancelTrigger();
462
+ (_editorRef$current14 = editorRef.current) === null || _editorRef$current14 === void 0 || _editorRef$current14.cancelTrigger();
423
463
  setTriggerInfo(null);
424
464
  return true;
425
465
  }
@@ -538,6 +578,9 @@ export var Composer = /*#__PURE__*/forwardRef(function Composer(_ref, ref) {
538
578
  }, /*#__PURE__*/React.createElement("button", {
539
579
  type: "button",
540
580
  disabled: disabled,
581
+ onMouseDown: function onMouseDown(e) {
582
+ return e.preventDefault();
583
+ },
541
584
  "data-odn-composer-tool-btn": true,
542
585
  "data-odn-composer-tool-iconic": !effectiveLabeled || undefined,
543
586
  "data-odn-composer-tool-active": toolMenuOpen || undefined,
@@ -655,6 +698,31 @@ export var Composer = /*#__PURE__*/forwardRef(function Composer(_ref, ref) {
655
698
  /* trigger 浮层渲染条件:editor 处于 `/` 触发态 + 业务方传了 skills。
656
699
  * `@` 触发本轮不接(mention 数据源待业务接入),onTriggerChange 拿到也不弹。 */
657
700
  var triggerMenuVisible = !!(triggerInfo && triggerInfo.trigger === '/' && skills && skills.length > 0);
701
+ var paramPanelNode = function (_editorRef$current$ge3, _editorRef$current15, _boxRef$current) {
702
+ if (!paramEdit || !renderParamPanel) return null;
703
+ var chips = (_editorRef$current$ge3 = (_editorRef$current15 = editorRef.current) === null || _editorRef$current15 === void 0 ? void 0 : _editorRef$current15.getChips()) !== null && _editorRef$current$ge3 !== void 0 ? _editorRef$current$ge3 : [];
704
+ var chip = chips.find(function (c) {
705
+ return c.id === paramEdit.chipId;
706
+ });
707
+ if (!chip || isMentionChip(chip)) return null;
708
+ var boxWidth = (_boxRef$current = boxRef.current) === null || _boxRef$current === void 0 ? void 0 : _boxRef$current.getBoundingClientRect().width;
709
+ var ctx = {
710
+ chip: chip,
711
+ anchor: paramEdit.anchor,
712
+ onApply: function onApply(patch) {
713
+ var _editorRef$current16;
714
+ (_editorRef$current16 = editorRef.current) === null || _editorRef$current16 === void 0 || _editorRef$current16.updateChipData(chip.id, patch);
715
+ },
716
+ onClose: closeParamPanel
717
+ };
718
+ return /*#__PURE__*/React.createElement(InvocationParamPopover, {
719
+ anchor: paramEdit.anchor,
720
+ label: chip.label,
721
+ icon: chip.icon,
722
+ width: boxWidth,
723
+ onClose: closeParamPanel
724
+ }, renderParamPanel(ctx));
725
+ }();
658
726
  var editorNode = /*#__PURE__*/React.createElement(ComposerEditor, {
659
727
  ref: editorRef,
660
728
  autoSize: {
@@ -664,7 +732,9 @@ export var Composer = /*#__PURE__*/forwardRef(function Composer(_ref, ref) {
664
732
  placeholder: placeholder,
665
733
  value: text,
666
734
  onChange: updateText,
667
- disabled: disabled
735
+ disabled: disabled,
736
+ paramEditChipId: (_paramEdit$chipId = paramEdit === null || paramEdit === void 0 ? void 0 : paramEdit.chipId) !== null && _paramEdit$chipId !== void 0 ? _paramEdit$chipId : null,
737
+ onInlineRefClick: renderParamPanel ? handleInlineRefClick : undefined
668
738
  /* 本轮只接 `/`,`@` 留给业务接 mention 搜索时再加 */,
669
739
  triggers: ['/'],
670
740
  onTriggerChange: setTriggerInfo,
@@ -678,8 +748,8 @@ export var Composer = /*#__PURE__*/forwardRef(function Composer(_ref, ref) {
678
748
  },
679
749
  onPressEnter: function onPressEnter(e) {
680
750
  if (e.nativeEvent.isComposing || e.keyCode === 229) return;
681
- // trigger 浮层激活时 Enter 留给浮层做选择,本组件不发送也不换行
682
- if (triggerMenuVisible) {
751
+ // trigger 浮层激活时,普通 Enter 留给浮层做选择;Shift+Enter 继续换行
752
+ if (triggerMenuVisible && !e.shiftKey) {
683
753
  e.preventDefault();
684
754
  return false;
685
755
  }
@@ -705,8 +775,8 @@ export var Composer = /*#__PURE__*/forwardRef(function Composer(_ref, ref) {
705
775
  visible: triggerMenuVisible,
706
776
  onVisibleChange: function onVisibleChange(v) {
707
777
  if (!v) {
708
- var _editorRef$current13;
709
- (_editorRef$current13 = editorRef.current) === null || _editorRef$current13 === void 0 || _editorRef$current13.cancelTrigger();
778
+ var _editorRef$current17;
779
+ (_editorRef$current17 = editorRef.current) === null || _editorRef$current17 === void 0 || _editorRef$current17.cancelTrigger();
710
780
  setTriggerInfo(null);
711
781
  }
712
782
  },
@@ -746,7 +816,8 @@ export var Composer = /*#__PURE__*/forwardRef(function Composer(_ref, ref) {
746
816
  style: style
747
817
  }, /*#__PURE__*/React.createElement("div", {
748
818
  "data-odn-composer-inner": true
749
- }, hiddenFileInput, triggerMenu, /*#__PURE__*/React.createElement("div", _extends({
819
+ }, hiddenFileInput, triggerMenu, paramPanelNode, /*#__PURE__*/React.createElement("div", _extends({
820
+ ref: boxRef,
750
821
  "data-odn-composer-box": true
751
822
  }, composerBoxFileDragAttrs, {
752
823
  onDragEnter: handleComposerDragEnter,
@@ -1,9 +1,13 @@
1
1
  /// <reference types="react" />
2
- import type { ChipData } from './chip';
2
+ import type { ChipData } from '../_genui-types';
3
3
  export declare function isMentionChip(chip: ChipData): boolean;
4
4
  export interface ComposerInlineRefProps {
5
5
  data: ChipData;
6
+ /** 参数面板打开时高亮 */
7
+ active?: boolean;
8
+ /** 有参数面板时由 Composer 注入;点击打开面板 */
9
+ onClick?: (anchor: HTMLElement) => void;
6
10
  }
7
11
  /** Composer 内联引用视觉:按 kind 派发 Invocation(/)或 Mention(@)。 */
8
- export declare function ComposerInlineRef({ data }: ComposerInlineRefProps): import("react").JSX.Element;
12
+ export declare function ComposerInlineRef({ data, active, onClick, }: ComposerInlineRefProps): import("react").JSX.Element;
9
13
  export default ComposerInlineRef;
@@ -6,16 +6,23 @@ export function isMentionChip(chip) {
6
6
  }
7
7
  /** Composer 内联引用视觉:按 kind 派发 Invocation(/)或 Mention(@)。 */
8
8
  export function ComposerInlineRef(_ref) {
9
- var data = _ref.data;
9
+ var data = _ref.data,
10
+ _ref$active = _ref.active,
11
+ active = _ref$active === void 0 ? false : _ref$active,
12
+ onClick = _ref.onClick;
10
13
  if (isMentionChip(data)) {
11
14
  return /*#__PURE__*/React.createElement(Mention, {
12
15
  data: chipToMentionData(data),
13
- interactive: true
16
+ interactive: true,
17
+ active: active,
18
+ onClick: onClick
14
19
  });
15
20
  }
16
21
  return /*#__PURE__*/React.createElement(Invocation, {
17
22
  data: chipToInvocationData(data),
18
- interactive: true
23
+ interactive: true,
24
+ active: active,
25
+ onClick: onClick
19
26
  });
20
27
  }
21
28
  export default ComposerInlineRef;
@@ -0,0 +1,14 @@
1
+ import type { ChipData, InlineRefState } from '../_genui-types';
2
+ /** Composer `renderParamPanel` 回调上下文。 */
3
+ export interface ComposerParamPanelContext {
4
+ chip: ChipData;
5
+ anchor: HTMLElement;
6
+ /**
7
+ * 关闭即保存:业务在表单 onChange 时调用,合并进 chip.payload / state。
8
+ */
9
+ onApply: (patch: {
10
+ payload?: Record<string, unknown>;
11
+ state?: InlineRefState;
12
+ }) => void;
13
+ onClose: () => void;
14
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Composer Segments · 发送时的有序 IR
3
+ *
4
+ * `onSend(segments, meta?)` 的主出口;业务按数组顺序自定义拼后端。
5
+ *
6
+ * - `rawValueToSegments`:库内部用,把含零宽 marker 的 raw value + chip 列表
7
+ * 还原为 `ComposerSegment[]`。
8
+ * - `segmentsToReadableText`:业务可选工具,按指定占位符格式把 segments 拼成
9
+ * 一句话(默认 `[Skill: label]` / `[@label]`,与 ComposerMention 兼容)。
10
+ * - `segmentsHasContent`:是否含可见内容;库内 send 校验用,业务可复用。
11
+ */
12
+ import type { ComposerSegment } from '../_genui-types';
13
+ import type { ChipData } from '../_genui-types';
14
+ export type { ComposerSegment };
15
+ /** 从含零宽 marker 的 raw value + chip 列表构建有序 segments。 */
16
+ export declare function rawValueToSegments(raw: string, chips: ChipData[]): ComposerSegment[];
17
+ export interface SegmentsToReadableTextOptions {
18
+ /** invocation 占位格式,默认 `[Skill: {label}]` */
19
+ formatInvocation?: (label: string) => string;
20
+ /** mention 占位格式,默认 `[@{label}]` */
21
+ formatMention?: (label: string) => string;
22
+ }
23
+ /**
24
+ * 把 segments 拼成一条字符串,供需要单串 string 的 LLM / 旧后端使用。
25
+ * 库**不内置调用**此函数;由业务在 onSend 内自行选择。
26
+ */
27
+ export declare function segmentsToReadableText(segments: ComposerSegment[], options?: SegmentsToReadableTextOptions): string;
28
+ /** segments 是否含可见内容(文本非空或含内联引用)。 */
29
+ export declare function segmentsHasContent(segments: ComposerSegment[]): boolean;
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Composer Segments · 发送时的有序 IR
3
+ *
4
+ * `onSend(segments, meta?)` 的主出口;业务按数组顺序自定义拼后端。
5
+ *
6
+ * - `rawValueToSegments`:库内部用,把含零宽 marker 的 raw value + chip 列表
7
+ * 还原为 `ComposerSegment[]`。
8
+ * - `segmentsToReadableText`:业务可选工具,按指定占位符格式把 segments 拼成
9
+ * 一句话(默认 `[Skill: label]` / `[@label]`,与 ComposerMention 兼容)。
10
+ * - `segmentsHasContent`:是否含可见内容;库内 send 校验用,业务可复用。
11
+ */
12
+
13
+ import { chipToInvocationData, chipToMentionData } from "./send-meta";
14
+ import { forEachMarkerSegment } from "./utils";
15
+ /** 从含零宽 marker 的 raw value + chip 列表构建有序 segments。 */
16
+ export function rawValueToSegments(raw, chips) {
17
+ var chipById = new Map(chips.map(function (c) {
18
+ return [c.id, c];
19
+ }));
20
+ var segments = [];
21
+ forEachMarkerSegment(raw, function (seg) {
22
+ if (seg.type === 'text') {
23
+ if (seg.text.length > 0) {
24
+ segments.push({
25
+ type: 'text',
26
+ data: {
27
+ text: seg.text
28
+ }
29
+ });
30
+ }
31
+ return;
32
+ }
33
+ var chip = chipById.get(seg.id);
34
+ if (!chip) return;
35
+ if (chip.kind === 'mention') {
36
+ segments.push({
37
+ type: 'mention',
38
+ data: chipToMentionData(chip)
39
+ });
40
+ } else {
41
+ segments.push({
42
+ type: 'invocation',
43
+ data: chipToInvocationData(chip)
44
+ });
45
+ }
46
+ });
47
+ return segments;
48
+ }
49
+ var defaultFormatInvocation = function defaultFormatInvocation(label) {
50
+ return "[Skill: ".concat(label, "]");
51
+ };
52
+ var defaultFormatMention = function defaultFormatMention(label) {
53
+ return "[@".concat(label, "]");
54
+ };
55
+
56
+ /**
57
+ * 把 segments 拼成一条字符串,供需要单串 string 的 LLM / 旧后端使用。
58
+ * 库**不内置调用**此函数;由业务在 onSend 内自行选择。
59
+ */
60
+ export function segmentsToReadableText(segments, options) {
61
+ var _options$formatInvoca, _options$formatMentio;
62
+ var fmtInv = (_options$formatInvoca = options === null || options === void 0 ? void 0 : options.formatInvocation) !== null && _options$formatInvoca !== void 0 ? _options$formatInvoca : defaultFormatInvocation;
63
+ var fmtMen = (_options$formatMentio = options === null || options === void 0 ? void 0 : options.formatMention) !== null && _options$formatMentio !== void 0 ? _options$formatMentio : defaultFormatMention;
64
+ return segments.map(function (seg) {
65
+ switch (seg.type) {
66
+ case 'text':
67
+ return seg.data.text;
68
+ case 'invocation':
69
+ return fmtInv(seg.data.label);
70
+ case 'mention':
71
+ return fmtMen(seg.data.label);
72
+ default:
73
+ return '';
74
+ }
75
+ }).join('');
76
+ }
77
+
78
+ /** segments 是否含可见内容(文本非空或含内联引用)。 */
79
+ export function segmentsHasContent(segments) {
80
+ return segments.some(function (s) {
81
+ return s.type === 'invocation' || s.type === 'mention' || s.type === 'text' && s.data.text.trim().length > 0;
82
+ });
83
+ }
@@ -1,6 +1,9 @@
1
- import type { InvocationData, MentionData, SendMeta } from '../_genui-types';
2
- import type { ChipData } from './chip';
1
+ import type { ChipData, InvocationData, MentionData } from '../_genui-types';
2
+ /**
3
+ * Chip → Invocation/Mention 派发。
4
+ *
5
+ * 库只搬运 UI 字段(id/kind/label/icon/state)与业务字段(payload),
6
+ * 不对 payload 内容做任何假设。
7
+ */
3
8
  export declare function chipToInvocationData(chip: ChipData): InvocationData;
4
9
  export declare function chipToMentionData(chip: ChipData): MentionData;
5
- /** 从 editor chip 列表构建 SendMeta(含 invocations / mentions + chips 兼容字段)。 */
6
- export declare function buildSendMetaFromChips(chips: ChipData[], base?: Omit<SendMeta, 'chips' | 'invocations' | 'mentions'>): SendMeta;
@@ -1,20 +1,17 @@
1
- function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
2
- function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3
- function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
4
- function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
5
- function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
6
- function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
7
- function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
8
- function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
9
- function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
1
+ /**
2
+ * Chip Invocation/Mention 派发。
3
+ *
4
+ * 库只搬运 UI 字段(id/kind/label/icon/state)与业务字段(payload),
5
+ * 不对 payload 内容做任何假设。
6
+ */
10
7
  export function chipToInvocationData(chip) {
11
- var kind = chip.kind === 'skill' || chip.kind === 'invocation' || !chip.kind ? 'skill' : chip.kind;
12
8
  return {
13
9
  id: chip.id,
14
- kind: kind,
15
- refId: chip.skillId,
10
+ kind: chip.kind === 'mention' || !chip.kind ? 'skill' : chip.kind,
16
11
  label: chip.label,
17
- icon: chip.icon
12
+ icon: chip.icon,
13
+ state: chip.state,
14
+ payload: chip.payload
18
15
  };
19
16
  }
20
17
  export function chipToMentionData(chip) {
@@ -22,46 +19,9 @@ export function chipToMentionData(chip) {
22
19
  return {
23
20
  id: chip.id,
24
21
  kind: (_chip$kind = chip.kind) !== null && _chip$kind !== void 0 ? _chip$kind : 'mention',
25
- refId: chip.skillId,
26
- label: chip.label,
27
- icon: chip.icon
28
- };
29
- }
30
- function chipToLegacyMeta(chip) {
31
- var kind = chip.kind === 'mention' ? 'mention' : chip.kind === 'invocation' || chip.kind === 'skill' || !chip.kind ? 'skill' : chip.kind;
32
- return {
33
- id: chip.id,
34
- skillId: chip.skillId,
35
22
  label: chip.label,
36
23
  icon: chip.icon,
37
- kind: kind
24
+ state: chip.state,
25
+ payload: chip.payload
38
26
  };
39
- }
40
-
41
- /** 从 editor chip 列表构建 SendMeta(含 invocations / mentions + chips 兼容字段)。 */
42
- export function buildSendMetaFromChips(chips) {
43
- var base = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
44
- var invocations = [];
45
- var mentions = [];
46
- var _iterator = _createForOfIteratorHelper(chips),
47
- _step;
48
- try {
49
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
50
- var chip = _step.value;
51
- if (chip.kind === 'mention') {
52
- mentions.push(chipToMentionData(chip));
53
- } else {
54
- invocations.push(chipToInvocationData(chip));
55
- }
56
- }
57
- } catch (err) {
58
- _iterator.e(err);
59
- } finally {
60
- _iterator.f();
61
- }
62
- return _objectSpread(_objectSpread({}, base), {}, {
63
- invocations: invocations.length > 0 ? invocations : undefined,
64
- mentions: mentions.length > 0 ? mentions : undefined,
65
- chips: chips.length > 0 ? chips.map(chipToLegacyMeta) : undefined
66
- });
67
27
  }