one-design-next 0.0.123 → 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.
@@ -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;未知 kind 回退 data.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;未知 kind 回退 data.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' || kind === 'mention') return 'user';
20
+ if (kind === 'user') return 'user';
21
+ if (kind === 'mention') return undefined;
21
22
  return fallback;
22
23
  }
@@ -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
- webSearch?: boolean;
274
+ /**
275
+ * 推理模式。只有工具栏放了 `mode` 时才会带上。
276
+ * `fast` 是快速,`featured` 是精选。
277
+ */
278
+ mode?: 'fast' | 'featured';
262
279
  }
263
280
  export type AgentEvent = {
264
281
  kind: 'thinking';
@@ -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 在发送瞬间追加的模板
@@ -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 * 2;
288
+ var inlineContentWidth = containerWidth - inlineInset - endInset;
287
289
  if (inlineContentWidth <= 0) return true;
288
290
 
289
291
  // 逐个文本节点取 rect:Range 覆盖整棵子树时拿到的是行容器(block)的宽度,
@@ -637,6 +639,10 @@ export var ComposerEditor = /*#__PURE__*/forwardRef(function ComposerEditor(_ref
637
639
  var pullCaretBeforeHint = useCallback(function () {
638
640
  var el = editorRef.current;
639
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
+ }
640
646
  if (!el || !sel || sel.rangeCount !== 1 || !sel.isCollapsed) return;
641
647
  if (!el.contains(sel.anchorNode)) return;
642
648
  if (!normalizeCollapsedCaretBeforeHint(sel.getRangeAt(0), el)) return;
@@ -1492,6 +1498,14 @@ export var ComposerEditor = /*#__PURE__*/forwardRef(function ComposerEditor(_ref
1492
1498
  return /*#__PURE__*/createPortal( /*#__PURE__*/React.createElement(ComposerInlineRef, {
1493
1499
  data: chip.data,
1494
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,
1495
1509
  onClick: onInlineRefClick && chipHasEditableParams(chip.data) ? function (anchor) {
1496
1510
  return onInlineRefClick(chip.data.id, anchor);
1497
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) {
@@ -3,13 +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';
7
8
  import { type ComposerSkillHint } from './segments';
8
9
  import './style';
9
10
  export type { ComposerInsertOptions, ComposerInsertPart, ComposerInsertResult, } from './insert';
11
+ export type { ComposerMentionItem } from './mention';
10
12
  export type { ComposerParamPanelContext } from './param-panel';
11
13
  export type { ComposerHintTarget, ComposerSkillHint } from './segments';
12
- export type ComposerTool = 'attachment' | 'webSearch' | 'skill';
14
+ export type ComposerTool = 'attachment' | 'skill';
15
+ /** 快速 / 精选。不是工具按钮,`showMode` 为 true 才出现在发送键左侧。 */
16
+ export type ComposerMode = 'fast' | 'featured';
13
17
  export type ComposerVariant = 'full' | 'lite';
14
18
  export type SubmitType = 'enter' | 'shiftEnter';
15
19
  /**
@@ -20,7 +24,7 @@ export type SubmitType = 'enter' | 'shiftEnter';
20
24
  * - 整个配置对象不传(key 不存在于 `toolConfigs`)时使用内置默认值。
21
25
  * - 仅传 `tooltip`(不传 icon / label)时:保留默认图标与文案,只覆盖说明。
22
26
  * - 传了配置对象且 icon / label 均未设置、也未传 tooltip 时(`{}`),兜底显示工具英文名
23
- * (如 "attachment" / "webSearch" / "skill")作为 label,无图标,
27
+ * (如 "attachment" / "skill")作为 label,无图标,
24
28
  * 方便开发者一眼看出配置遗漏。
25
29
  */
26
30
  export interface ComposerToolConfig {
@@ -67,6 +71,7 @@ export interface ComposerRef {
67
71
  * - `skill` 走与菜单插入相同的 chip 结构(含 `hint` / `initialState`);
68
72
  * `initialState: 'pending'` 且提供 `renderParamPanel` 时自动打开参数面板
69
73
  * (`focus: false` 的后台预填不打开)。
74
+ * - `slot` 是提示词槽位:`name` 显示在空槽上,`value` 是已填的字。
70
75
  * - `chip` 是逃生舱:mention / 自定义 kind / 已存草稿都可以直接传。
71
76
  * - chip id 与编辑器已有 chip 冲突时自动换新 id,以返回的 `chipIds` 为准。
72
77
  * - 受控 `value` 场景请在 onChange 内回写,与手动输入一致(否则一帧后会被
@@ -127,7 +132,7 @@ export interface ComposerProps {
127
132
  * 发送回调。
128
133
  *
129
134
  * `segments`:有序内容 IR,业务按数组顺序自定义拼后端。
130
- * `meta`:附件 / 联网搜索等非正文数据;为空时不传。
135
+ * `meta`:附件等非正文数据;为空时不传。
131
136
  *
132
137
  * **派生 `hint` 段**:当最后一个 chip 是带 `SkillItem.hint` 的 skill、其后
133
138
  * 一个字符都没有(空格 / 换行都算内容)、且这颗 chip 的 hint 还没关闭时,
@@ -177,7 +182,7 @@ export interface ComposerProps {
177
182
  variant?: ComposerVariant;
178
183
  /**
179
184
  * 左下工具按钮集合(按数组顺序展示)。传入空数组即不渲染任何左下按钮。
180
- * @default ['attachment', 'webSearch', 'skill']
185
+ * @default ['attachment', 'skill']
181
186
  */
182
187
  tools?: ComposerTool[];
183
188
  /**
@@ -191,7 +196,6 @@ export interface ComposerProps {
191
196
  /**
192
197
  * 各工具按钮的自定义配置(icon / label / tooltip)。按 `ComposerTool` 类型做 key:
193
198
  * - `attachment`:附件按钮
194
- * - `webSearch`:联网按钮
195
199
  * - `skill`:技能按钮
196
200
  *
197
201
  * **语义约定**:
@@ -206,7 +210,6 @@ export interface ComposerProps {
206
210
  * ```tsx
207
211
  * toolConfigs={{
208
212
  * attachment: { tooltip: '上传材料,补充上下文' }, // 只改说明
209
- * webSearch: { label: '搜索' }, // 仅文字
210
213
  * skill: { icon: 'command' }, // 仅图标
211
214
  * }}
212
215
  * ```
@@ -218,6 +221,38 @@ export interface ComposerProps {
218
221
  * 菜单宽高由 Composer 按输入框与视口计算,不经本袋覆盖。
219
222
  */
220
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;
221
256
  /**
222
257
  * 提交模式:
223
258
  * - `'enter'`(默认):Enter 发送,Shift+Enter 换行
@@ -307,7 +342,7 @@ export interface ComposerProps {
307
342
  /**
308
343
  * 工具栏按钮被点击时触发。
309
344
  *
310
- * - `tool`:被点击的工具类型(`'attachment'` / `'webSearch'` / `'skill'`)。
345
+ * - `tool`:被点击的工具类型(`'attachment'` / `'skill'`)。
311
346
  * - 对于 `'skill'`:在 skill 弹窗打开时触发(而非选中某个 skill 时)。
312
347
  * - 此回调为纯通知性质,不影响组件内部行为(若需阻止,请使用 `disabled` 等控制)。
313
348
  */