one-design-next 0.0.77 → 0.0.80

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 (35) hide show
  1. package/dist/_genui-inline-ref.d.ts +11 -0
  2. package/dist/_genui-inline-ref.js +22 -0
  3. package/dist/artifact/actions.d.ts +7 -0
  4. package/dist/artifact/actions.js +29 -6
  5. package/dist/artifact/index.d.ts +2 -2
  6. package/dist/artifact/index.js +5 -7
  7. package/dist/artifact/style/index.css +16 -4
  8. package/dist/chat-list/index.d.ts +6 -1
  9. package/dist/chat-list/index.js +21 -18
  10. package/dist/chat-list/style/index.css +12 -6
  11. package/dist/clarify-dock/style/index.css +4 -2
  12. package/dist/composer/editor.d.ts +2 -0
  13. package/dist/composer/editor.js +43 -29
  14. package/dist/composer/hooks/useChipManager.d.ts +2 -0
  15. package/dist/composer/hooks/useChipManager.js +8 -0
  16. package/dist/composer/index.d.ts +8 -3
  17. package/dist/composer/index.js +56 -39
  18. package/dist/composer/inline-ref.d.ts +2 -0
  19. package/dist/composer/inline-ref.js +11 -0
  20. package/dist/composer/send-meta.js +1 -1
  21. package/dist/composer/style/index.css +9 -14
  22. package/dist/index.d.ts +4 -4
  23. package/dist/index.js +1 -1
  24. package/dist/invocation/index.js +42 -32
  25. package/dist/invocation/style/index.css +45 -23
  26. package/dist/mention/index.js +53 -34
  27. package/dist/mention/style/index.css +48 -12
  28. package/dist/preview-panel/index.d.ts +26 -1
  29. package/dist/preview-panel/index.js +154 -32
  30. package/dist/preview-panel/style/index.css +109 -51
  31. package/dist/user-bubble/style/index.css +1 -1
  32. package/dist/virtual-list/index.d.ts +5 -1
  33. package/dist/virtual-list/index.js +7 -8
  34. package/dist/virtual-list/style/index.css +54 -0
  35. package/package.json +1 -1
@@ -0,0 +1,11 @@
1
+ /**
2
+ * 内联引用 chip 的品类 icon。
3
+ *
4
+ * chip 视觉锚点按「类型」而非条目:skill 一律跟 Composer 技能按钮同源,
5
+ * 不使用 SkillItem.icon(那只服务技能菜单辨识)。
6
+ */
7
+ export declare const SKILL_CATEGORY_ICON = "wand-sparkles";
8
+ /** skill / 未标明的 invocation 通道 → 技能品类 icon;其它 kind 回退 data.icon */
9
+ export declare function resolveInvocationCategoryIcon(kind?: string, fallback?: string): string | undefined;
10
+ /** mention 按 kind 给品类 icon;未知 kind 回退 data.icon */
11
+ export declare function resolveMentionCategoryIcon(kind?: string, fallback?: string): string | undefined;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * 内联引用 chip 的品类 icon。
3
+ *
4
+ * chip 视觉锚点按「类型」而非条目:skill 一律跟 Composer 技能按钮同源,
5
+ * 不使用 SkillItem.icon(那只服务技能菜单辨识)。
6
+ */
7
+ export var SKILL_CATEGORY_ICON = 'wand-sparkles';
8
+
9
+ /** skill / 未标明的 invocation 通道 → 技能品类 icon;其它 kind 回退 data.icon */
10
+ export function resolveInvocationCategoryIcon(kind, fallback) {
11
+ if (!kind || kind === 'skill' || kind === 'invocation') {
12
+ return SKILL_CATEGORY_ICON;
13
+ }
14
+ return fallback;
15
+ }
16
+
17
+ /** mention 按 kind 给品类 icon;未知 kind 回退 data.icon */
18
+ export function resolveMentionCategoryIcon(kind, fallback) {
19
+ if (kind === 'file') return 'file-text';
20
+ if (kind === 'user' || kind === 'mention') return 'user';
21
+ return fallback;
22
+ }
@@ -1,4 +1,5 @@
1
1
  import type { IconName } from '../icon';
2
+ import type { ArtifactFileIconType } from './icons';
2
3
  /** 点击产物时的预期行为类型。 */
3
4
  export type ArtifactActionKind = 'preview' | 'download';
4
5
  export interface ArtifactAction {
@@ -10,3 +11,9 @@ export interface ArtifactAction {
10
11
  }
11
12
  /** 根据 actionKind 返回对应的 ArtifactAction(label + icon)。 */
12
13
  export declare function getArtifactActionFromKind(kind: ArtifactActionKind): ArtifactAction;
14
+ /**
15
+ * 按文件类型给出点击预期(业务方可据此决定 `actionKind`):
16
+ * - html / md / csv / file → 预览(arrow-right)
17
+ * - pdf / xlsx / docx / pptx → 下载(arrow-down-to-line)
18
+ */
19
+ export declare function getArtifactAction(fileType: ArtifactFileIconType): ArtifactAction;
@@ -3,17 +3,40 @@
3
3
  /** 根据 actionKind 返回对应的 ArtifactAction(label + icon)。 */
4
4
  export function getArtifactActionFromKind(kind) {
5
5
  switch (kind) {
6
- case 'preview':
7
- return {
8
- kind: 'preview',
9
- label: '预览详情',
10
- icon: 'arrow-right'
11
- };
12
6
  case 'download':
13
7
  return {
14
8
  kind: 'download',
15
9
  label: '下载导出',
16
10
  icon: 'arrow-down-to-line'
17
11
  };
12
+ case 'preview':
13
+ default:
14
+ return {
15
+ kind: 'preview',
16
+ label: '预览详情',
17
+ icon: 'arrow-right'
18
+ };
19
+ }
20
+ }
21
+
22
+ /**
23
+ * 按文件类型给出点击预期(业务方可据此决定 `actionKind`):
24
+ * - html / md / csv / file → 预览(arrow-right)
25
+ * - pdf / xlsx / docx / pptx → 下载(arrow-down-to-line)
26
+ */
27
+ export function getArtifactAction(fileType) {
28
+ switch (fileType) {
29
+ case 'html':
30
+ case 'md':
31
+ case 'csv':
32
+ case 'file':
33
+ return getArtifactActionFromKind('preview');
34
+ case 'pdf':
35
+ case 'xlsx':
36
+ case 'docx':
37
+ case 'pptx':
38
+ return getArtifactActionFromKind('download');
39
+ default:
40
+ return getArtifactActionFromKind('preview');
18
41
  }
19
42
  }
@@ -2,7 +2,7 @@ import { type CSSProperties } from 'react';
2
2
  import { type ArtifactActionKind } from './actions';
3
3
  import { type ArtifactFileIconType } from './icons';
4
4
  import './style';
5
- export { getArtifactActionFromKind, type ArtifactAction, type ArtifactActionKind, } from './actions';
5
+ export { getArtifactAction, getArtifactActionFromKind, type ArtifactAction, type ArtifactActionKind, } from './actions';
6
6
  export { ARTIFACT_FILE_GLOW_COLORS, getArtifactGlowColor } from './glow';
7
7
  export { ARTIFACT_DEDICATED_FILE_ICON_TYPES, ARTIFACT_FILE_ICON_MEDIUM_SIZE, ARTIFACT_FILE_ICON_MEDIUM_VIEWBOX, ARTIFACT_FILE_ICON_SMALL_SIZE, ARTIFACT_FILE_ICON_SMALL_VIEWBOX, ARTIFACT_FILE_ICON_TYPES, ArtifactFileIcon, artifactFileIcons, artifactFileIconsMedium, artifactFileIconsSmall, getArtifactFileIconUrl, } from './icons';
8
8
  export type { ArtifactFileIconProps, ArtifactFileIconSize, ArtifactFileIconType, } from './icons';
@@ -40,7 +40,7 @@ export interface ArtifactProps {
40
40
  /**
41
41
  * 对话流内的产物:
42
42
  * - medium / Card:左 Icon + 右标题 / 大小·日期;可点 hover 时 Icon 后退缩小、文案左移遮罩,右侧浮出操作预期
43
- * - small / Small:无底色/描边;hover 用 HoverFill 叠灰底(不展示预览/下载操作预期)
43
+ * - small / Small:无底色/描边;hover 用 HoverFill(Navi 默认色);不可预览类型额外浮出下载 Icon
44
44
  */
45
45
  export declare function Artifact({ title, actionKind, fileType, fileSize, date, size, status, onOpen, className, style, }: ArtifactProps): import("react").JSX.Element;
46
46
  export declare namespace Artifact {
@@ -10,7 +10,7 @@ import { getArtifactActionFromKind } from "./actions";
10
10
  import { getArtifactGlowColor } from "./glow";
11
11
  import { ARTIFACT_DEDICATED_FILE_ICON_TYPES, ArtifactFileIcon } from "./icons";
12
12
  import "./style";
13
- export { getArtifactActionFromKind } from "./actions";
13
+ export { getArtifactAction, getArtifactActionFromKind } from "./actions";
14
14
  export { ARTIFACT_FILE_GLOW_COLORS, getArtifactGlowColor } from "./glow";
15
15
  export { ARTIFACT_DEDICATED_FILE_ICON_TYPES, ARTIFACT_FILE_ICON_MEDIUM_SIZE, ARTIFACT_FILE_ICON_MEDIUM_VIEWBOX, ARTIFACT_FILE_ICON_SMALL_SIZE, ARTIFACT_FILE_ICON_SMALL_VIEWBOX, ARTIFACT_FILE_ICON_TYPES, ArtifactFileIcon, artifactFileIcons, artifactFileIconsMedium, artifactFileIconsSmall, getArtifactFileIconUrl } from "./icons";
16
16
 
@@ -73,7 +73,7 @@ function ArtifactActionCue(_ref) {
73
73
  /**
74
74
  * 对话流内的产物:
75
75
  * - medium / Card:左 Icon + 右标题 / 大小·日期;可点 hover 时 Icon 后退缩小、文案左移遮罩,右侧浮出操作预期
76
- * - small / Small:无底色/描边;hover 用 HoverFill 叠灰底(不展示预览/下载操作预期)
76
+ * - small / Small:无底色/描边;hover 用 HoverFill(Navi 默认色);不可预览类型额外浮出下载 Icon
77
77
  */
78
78
  export function Artifact(_ref2) {
79
79
  var title = _ref2.title,
@@ -115,8 +115,8 @@ export function Artifact(_ref2) {
115
115
  // Small 形态只展示 Icon + 标题;Card(medium)保留大小 / 日期(或 Generating 文案)
116
116
  var showMeta = size !== 'small';
117
117
  var metaParts = !showMeta ? [] : isGenerating ? ['生成中'] : [fileSize, date].filter(Boolean);
118
- // 操作预期仅 Card 可点时展示;Small 不展示
119
- var showAction = size !== 'small' && isInteractive;
118
+ // Card:预览 / 下载均可点时展示操作预期;Small:仅不可预览(下载)类型 hover 出下载 Icon
119
+ var showAction = isInteractive && (size !== 'small' || action.kind === 'download');
120
120
  var handleClick = function handleClick() {
121
121
  onOpen === null || onOpen === void 0 || onOpen();
122
122
  };
@@ -191,13 +191,11 @@ export function Artifact(_ref2) {
191
191
  onClick: handleClick
192
192
  }), content) : /*#__PURE__*/React.createElement("div", sharedProps, content);
193
193
 
194
- // Small:默认透明;可点时用 HoverFill 叠灰底(对齐 Attachments chip / ChatItem)
194
+ // Small:默认透明;可点时用 HoverFill(颜色对齐 Navi / HoverFill 默认值)
195
195
  if (size === 'small') {
196
196
  return /*#__PURE__*/React.createElement(HoverFill, {
197
197
  "data-odn-artifact-small-wrap": true,
198
198
  bgClassName: "odn-artifact-small-bg",
199
- hoverColor: "var(--odn-color-black-4)",
200
- activeColor: "var(--odn-color-black-5)",
201
199
  disabled: !isInteractive,
202
200
  className: className,
203
201
  style: style
@@ -12,7 +12,8 @@ html {
12
12
  --odn-artifact-icon-height: 36px;
13
13
  --odn-artifact-min-height: 68px;
14
14
  --odn-artifact-title-size: var(--odn-font-size-text-md);
15
- --odn-artifact-title-leading: var(--odn-font-leading-text-md);
15
+ /* 文件名行高用全局 default(非 text-md 固定 22px) */
16
+ --odn-artifact-title-leading: var(--odn-line-height);
16
17
  --odn-artifact-meta-size: var(--odn-font-size-text-mn);
17
18
  --odn-artifact-meta-leading: var(--odn-font-leading-text-mn);
18
19
  /* Card hover:对齐即梦 banner 卡(0.3s / ease-out) */
@@ -65,7 +66,8 @@ html {
65
66
  --odn-artifact-icon-height: 16px;
66
67
  --odn-artifact-min-height: 0;
67
68
  --odn-artifact-title-size: var(--odn-font-size-text-sm);
68
- --odn-artifact-title-leading: var(--odn-font-leading-text-sm);
69
+ /* 行高用全局 default(非 text-sm 固定 22px) */
70
+ --odn-artifact-title-leading: var(--odn-line-height);
69
71
  border: none;
70
72
  background: transparent;
71
73
  box-shadow: none;
@@ -117,7 +119,8 @@ button[data-odn-artifact] {
117
119
  margin: 0;
118
120
  font-size: var(--odn-artifact-title-size);
119
121
  line-height: var(--odn-artifact-title-leading);
120
- font-weight: 500;
122
+ /* Card / Small 默认 Regular;Small 选中态由使用方(如 PreviewPanel 列表)加粗 */
123
+ font-weight: 400;
121
124
  color: var(--odn-color-black-12);
122
125
  white-space: nowrap;
123
126
  }
@@ -241,7 +244,7 @@ button[data-odn-artifact] {
241
244
  transform: translateX(calc(-1 * var(--odn-artifact-hover-shift)));
242
245
  }
243
246
 
244
- /* Card:操作预期仅 Icon;右侧间距 20 */
247
+ /* 操作预期仅 Icon;Card 右侧间距 20,Small 对齐自身 padding-x 12 */
245
248
  [data-odn-artifact-action] {
246
249
  position: absolute;
247
250
  right: 20px;
@@ -260,12 +263,21 @@ button[data-odn-artifact] {
260
263
  transition: opacity var(--odn-artifact-hover-duration) var(--odn-artifact-hover-ease), transform var(--odn-artifact-hover-duration) var(--odn-artifact-hover-ease);
261
264
  }
262
265
 
266
+ [data-odn-artifact][data-odn-artifact-size=small] > [data-odn-artifact-action] {
267
+ right: 12px;
268
+ }
269
+
263
270
  [data-odn-artifact][data-odn-artifact-clickable]:hover > [data-odn-artifact-action],
264
271
  [data-odn-artifact][data-odn-artifact-clickable]:focus-visible > [data-odn-artifact-action] {
265
272
  opacity: 1;
266
273
  transform: translate(0, -50%);
267
274
  }
268
275
 
276
+ /* Small 下载态:标题给右侧 Icon 让出空间,避免叠字 */
277
+ [data-odn-artifact][data-odn-artifact-size=small][data-odn-artifact-action-kind=download] [data-odn-artifact-copy] {
278
+ padding-right: 20px;
279
+ }
280
+
269
281
  [data-odn-artifact][data-odn-artifact-status=Generating] {
270
282
  opacity: 0.85;
271
283
  }
@@ -49,12 +49,17 @@ export interface ChatListProps {
49
49
  onDelete?: ChatItemProps['onDelete'];
50
50
  /** 自定义行渲染。默认渲染 ChatItem。 */
51
51
  renderItem?: (item: ChatListItem, node: ReactNode) => ReactNode;
52
+ /**
53
+ * 将「最近」列表包进自定义滚动容器。
54
+ * 标题栏与置顶区始终留在外侧,不进入该容器。
55
+ */
56
+ renderRestScroll?: (content: ReactNode) => ReactNode;
52
57
  }
53
58
  /** 按时间筛选项判断会话是否命中。无有效 `time` 时仅在「全部」下保留。 */
54
59
  export declare function matchChatListFilterTime(time: ChatListItem['time'], filter: ChatListFilterTime, now?: number): boolean;
55
60
  /** 按类型筛选项判断会话是否命中。缺省 `type` 视为 `'ai'`。 */
56
61
  export declare function matchChatListFilterType(type: ChatListItem['type'], filter: ChatListFilterType): boolean;
57
- export declare function ChatList({ items, title, pinnedSectionTitle, recentSectionTitle, filterTime: filterTimeProp, defaultFilterTime, onFilterTimeChange, filterType: filterTypeProp, defaultFilterType, onFilterTypeChange, filterOpen: filterOpenProp, defaultFilterOpen, onFilterOpenChange, empty, actionMenuZIndex, filterMenuZIndex, className, onItemClick, onRename, onPin, onDelete, renderItem, }: ChatListProps): import("react").JSX.Element;
62
+ export declare function ChatList({ items, title, pinnedSectionTitle, recentSectionTitle, filterTime: filterTimeProp, defaultFilterTime, onFilterTimeChange, filterType: filterTypeProp, defaultFilterType, onFilterTypeChange, filterOpen: filterOpenProp, defaultFilterOpen, onFilterOpenChange, empty, actionMenuZIndex, filterMenuZIndex, className, onItemClick, onRename, onPin, onDelete, renderItem, renderRestScroll, }: ChatListProps): import("react").JSX.Element;
58
63
  export declare namespace ChatList {
59
64
  var displayName: string;
60
65
  }
@@ -1,6 +1,6 @@
1
1
  import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
2
- import { useMemo, useState } from 'react';
3
2
  import clsx from 'clsx';
3
+ import { useMemo, useState } from 'react';
4
4
  import ChatItem from "../chat-item";
5
5
  import Dropdown from "../dropdown";
6
6
  import Icon from "../icon";
@@ -34,7 +34,7 @@ var TYPE_OPTIONS = [{
34
34
  label: '人工客服'
35
35
  }];
36
36
  function parseItemTime(time) {
37
- if (time == null) return null;
37
+ if (time === null || time === undefined) return null;
38
38
  var t = typeof time === 'number' ? time : time instanceof Date ? time.getTime() : Date.parse(time);
39
39
  return Number.isFinite(t) ? t : null;
40
40
  }
@@ -49,7 +49,7 @@ export function matchChatListFilterTime(time, filter) {
49
49
  var now = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : Date.now();
50
50
  if (filter === 'all') return true;
51
51
  var t = parseItemTime(time);
52
- if (t == null) return false;
52
+ if (t === null || t === undefined) return false;
53
53
  if (t > now) return false;
54
54
  if (filter === 'today') return t >= startOfLocalDay(now);
55
55
  if (filter === '7d') return t >= now - 7 * 86400000;
@@ -144,7 +144,8 @@ export function ChatList(_ref) {
144
144
  onPin = _ref.onPin,
145
145
  onDelete = _ref.onDelete,
146
146
  _ref$renderItem = _ref.renderItem,
147
- renderItem = _ref$renderItem === void 0 ? defaultRenderItem : _ref$renderItem;
147
+ renderItem = _ref$renderItem === void 0 ? defaultRenderItem : _ref$renderItem,
148
+ renderRestScroll = _ref.renderRestScroll;
148
149
  var _useControllable = useControllable(filterTimeProp, defaultFilterTime, onFilterTimeChange),
149
150
  _useControllable2 = _slicedToArray(_useControllable, 2),
150
151
  filterTime = _useControllable2[0],
@@ -196,6 +197,20 @@ export function ChatList(_ref) {
196
197
  }, renderItem(item, node));
197
198
  };
198
199
  var hasContent = pinnedItems.length > 0 || restItems.length > 0;
200
+ var pinnedSection = pinnedItems.length > 0 ? /*#__PURE__*/React.createElement("div", {
201
+ "data-odn-chat-list-pinned": true
202
+ }, pinnedSectionTitle !== null && pinnedSectionTitle !== undefined ? /*#__PURE__*/React.createElement("div", {
203
+ "data-odn-chat-list-pinned-title": true
204
+ }, pinnedSectionTitle) : null, /*#__PURE__*/React.createElement("div", {
205
+ "data-odn-chat-list-pinned-body": true
206
+ }, pinnedItems.map(renderChatItem))) : null;
207
+ var restSection = restItems.length > 0 ? /*#__PURE__*/React.createElement("div", {
208
+ "data-odn-chat-list-rest": true
209
+ }, pinnedItems.length > 0 && recentSectionTitle !== null && recentSectionTitle !== undefined ? /*#__PURE__*/React.createElement("div", {
210
+ "data-odn-chat-list-recent-title": true
211
+ }, recentSectionTitle) : null, /*#__PURE__*/React.createElement("div", {
212
+ "data-odn-chat-list-rest-body": true
213
+ }, restItems.map(renderChatItem))) : null;
199
214
  return /*#__PURE__*/React.createElement("div", {
200
215
  "data-odn-chat-list": true,
201
216
  className: clsx(className)
@@ -236,21 +251,9 @@ export function ChatList(_ref) {
236
251
  size: 16
237
252
  }))))), !hasContent ? /*#__PURE__*/React.createElement("div", {
238
253
  "data-odn-chat-list-empty": true
239
- }, empty !== null && empty !== void 0 ? empty : null) : /*#__PURE__*/React.createElement("div", {
254
+ }, empty !== null && empty !== void 0 ? empty : null) : renderRestScroll ? /*#__PURE__*/React.createElement(React.Fragment, null, pinnedSection, restSection ? renderRestScroll(restSection) : null) : /*#__PURE__*/React.createElement("div", {
240
255
  "data-odn-chat-list-body": true
241
- }, pinnedItems.length > 0 ? /*#__PURE__*/React.createElement("div", {
242
- "data-odn-chat-list-pinned": true
243
- }, pinnedSectionTitle != null ? /*#__PURE__*/React.createElement("div", {
244
- "data-odn-chat-list-pinned-title": true
245
- }, pinnedSectionTitle) : null, /*#__PURE__*/React.createElement("div", {
246
- "data-odn-chat-list-pinned-body": true
247
- }, pinnedItems.map(renderChatItem))) : null, restItems.length > 0 ? /*#__PURE__*/React.createElement("div", {
248
- "data-odn-chat-list-rest": true
249
- }, pinnedItems.length > 0 && recentSectionTitle != null ? /*#__PURE__*/React.createElement("div", {
250
- "data-odn-chat-list-recent-title": true
251
- }, recentSectionTitle) : null, /*#__PURE__*/React.createElement("div", {
252
- "data-odn-chat-list-rest-body": true
253
- }, restItems.map(renderChatItem))) : null));
256
+ }, pinnedSection, restSection));
254
257
  }
255
258
  ChatList.displayName = 'ChatList';
256
259
  export default ChatList;
@@ -9,19 +9,21 @@
9
9
 
10
10
  [data-odn-chat-list-toolbar] {
11
11
  display: flex;
12
+ flex-shrink: 0;
12
13
  align-items: center;
13
14
  justify-content: space-between;
14
15
  gap: 8px;
15
16
  min-height: 32px;
16
17
  min-width: 0;
17
- padding: 0 4px;
18
+ /* ChatItem / 分区标题左缘统一 12px */
19
+ padding: 0 12px;
18
20
  background: transparent;
19
21
  }
20
22
 
21
23
  [data-odn-chat-list-title] {
22
24
  flex: 1 1 auto;
23
25
  min-width: 0;
24
- padding: 0 4px;
26
+ padding: 0;
25
27
  color: var(--odn-color-black-9);
26
28
  font-size: 14px;
27
29
  font-weight: 400;
@@ -110,14 +112,18 @@
110
112
  [data-odn-chat-list-rest] {
111
113
  display: flex;
112
114
  flex-direction: column;
113
- gap: 2px;
115
+ gap: 4px;
114
116
  min-width: 0;
115
117
  }
116
118
 
117
- /* 置顶 / 最近分区头:视觉同组标题,无折叠 / 菜单等交互 */
119
+ [data-odn-chat-list-pinned] {
120
+ flex-shrink: 0;
121
+ }
122
+
123
+ /* 置顶 / 最近分区头:视觉同组标题,无折叠 / 菜单等交互;左缘同标题栏 / ChatItem */
118
124
  [data-odn-chat-list-pinned-title],
119
125
  [data-odn-chat-list-recent-title] {
120
- padding: 4px 8px 2px;
126
+ padding: 4px 12px 2px;
121
127
  color: var(--odn-color-black-9);
122
128
  font-size: 12px;
123
129
  font-weight: 400;
@@ -130,6 +136,6 @@
130
136
  [data-odn-chat-list-rest-body] {
131
137
  display: flex;
132
138
  flex-direction: column;
133
- gap: 2px;
139
+ gap: 4px;
134
140
  min-width: 0;
135
141
  }
@@ -545,13 +545,15 @@ div[data-odn-clarify-dock] [data-odn-clarify-dock-body] {
545
545
  div[data-odn-clarify-dock] [data-odn-date-picker-container]:not([data-odn-date-picker-container-range]) {
546
546
  display: inline-block;
547
547
  box-sizing: border-box;
548
- width: calc(12ch + 10px + 32px + 2px);
548
+ font-size: var(--odn-font-size-text-sm);
549
+ width: calc(10ch + 10px + 32px + 2px);
549
550
  }
550
551
 
551
552
  div[data-odn-clarify-dock] [data-odn-date-picker-container-range] {
552
553
  display: inline-block;
553
554
  box-sizing: border-box;
554
- width: calc(25ch + 10px + 32px + 2px);
555
+ font-size: var(--odn-font-size-text-sm);
556
+ width: calc(21ch + 10px + 32px + 2px);
555
557
  }
556
558
 
557
559
  div[data-odn-clarify-dock] [data-odn-date-picker-input] {
@@ -41,6 +41,8 @@ export interface ComposerEditorProps {
41
41
  defaultValue?: string;
42
42
  /** 值变化回调;参数是 raw string,含 marker。 */
43
43
  onChange?: (value: string) => void;
44
+ /** 与 defaultValue / 首次受控 value 配套,把 marker 还原成 chip。 */
45
+ defaultChips?: ChipData[];
44
46
  placeholder?: string;
45
47
  autoSize?: ComposerEditorAutoSize;
46
48
  /**
@@ -22,13 +22,13 @@ import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
22
22
 
23
23
  import { forwardRef, useCallback, useEffect, useImperativeHandle, useLayoutEffect, useRef, useState } from 'react';
24
24
  import { createPortal } from 'react-dom';
25
+ import ScrollArea from "../scroll-area";
26
+ import { findChipHostBeforeCaret, mergeLineIntoPreviousAtCaretStart, normalizeCollapsedCaretAtChipBoundary, resolveCaretMove, splitLineAt } from "./caret";
25
27
  import { buildClipboardPayload, COMPOSER_CLIPBOARD_MIME, parseClipboardPayload, plainTextFromClipboardPayload, remapClipboardPayload } from "./clipboard";
26
28
  import { useChipManager } from "./hooks/useChipManager";
27
29
  import { useChipSelectionMarker } from "./hooks/useChipSelectionMarker";
30
+ import { chipHasEditableParams, ComposerInlineRef } from "./inline-ref";
28
31
  import { createLineRoot, createLineRootWithText, ensureLineRoots, getPlainText, isEditorEmpty, LINE_ATTR_NAME, normalizeEditorDom, probeTrigger } from "./utils";
29
- import { findChipHostBeforeCaret, mergeLineIntoPreviousAtCaretStart, normalizeCollapsedCaretAtChipBoundary, resolveCaretMove, splitLineAt } from "./caret";
30
- import { ComposerInlineRef } from "./inline-ref";
31
- import ScrollArea from "../scroll-area";
32
32
 
33
33
  /** Composer editor 触发态对外信号——告诉父组件该弹浮层选 skill 了。 */
34
34
 
@@ -83,6 +83,7 @@ export var ComposerEditor = /*#__PURE__*/forwardRef(function ComposerEditor(_ref
83
83
  var valueProp = _ref.value,
84
84
  _ref$defaultValue = _ref.defaultValue,
85
85
  defaultValue = _ref$defaultValue === void 0 ? '' : _ref$defaultValue,
86
+ defaultChips = _ref.defaultChips,
86
87
  onChange = _ref.onChange,
87
88
  placeholder = _ref.placeholder,
88
89
  autoSize = _ref.autoSize,
@@ -113,7 +114,7 @@ export var ComposerEditor = /*#__PURE__*/forwardRef(function ComposerEditor(_ref
113
114
  var minRows = (_autoSize$minRows = autoSize === null || autoSize === void 0 ? void 0 : autoSize.minRows) !== null && _autoSize$minRows !== void 0 ? _autoSize$minRows : 1;
114
115
  var maxRows = autoSize === null || autoSize === void 0 ? void 0 : autoSize.maxRows;
115
116
  var minHeightPx = minRows * LINE_HEIGHT + PADDING_Y * 2;
116
- var maxHeightPx = maxRows != null ? maxRows * LINE_HEIGHT + PADDING_Y * 2 : undefined;
117
+ var maxHeightPx = maxRows !== undefined ? maxRows * LINE_HEIGHT + PADDING_Y * 2 : undefined;
117
118
 
118
119
  /** 当前活动 trigger probe;null 表示无触发态。 */
119
120
  var triggerRef = useRef(null);
@@ -182,8 +183,8 @@ export var ComposerEditor = /*#__PURE__*/forwardRef(function ComposerEditor(_ref
182
183
  var el = editorRef.current;
183
184
  if (!el) return;
184
185
  var natural = Math.ceil(el.scrollHeight);
185
- var clamped = Math.max(minHeightPx, maxHeightPx != null ? Math.min(natural, maxHeightPx) : natural);
186
- var overflow = maxHeightPx != null && natural > maxHeightPx + 1;
186
+ var clamped = Math.max(minHeightPx, maxHeightPx !== undefined ? Math.min(natural, maxHeightPx) : natural);
187
+ var overflow = maxHeightPx !== undefined && natural > maxHeightPx + 1;
187
188
  setScrollHeight(function (prev) {
188
189
  return prev === clamped ? prev : clamped;
189
190
  });
@@ -203,7 +204,7 @@ export var ComposerEditor = /*#__PURE__*/forwardRef(function ComposerEditor(_ref
203
204
  }, []);
204
205
  var scheduleControlledSync = useCallback(function () {
205
206
  if (!isControlled) return;
206
- if (controlledSyncRafRef.current != null) {
207
+ if (controlledSyncRafRef.current !== null) {
207
208
  cancelAnimationFrame(controlledSyncRafRef.current);
208
209
  }
209
210
  controlledSyncRafRef.current = requestAnimationFrame(function () {
@@ -215,7 +216,7 @@ export var ComposerEditor = /*#__PURE__*/forwardRef(function ComposerEditor(_ref
215
216
  }, [isControlled]);
216
217
  useEffect(function () {
217
218
  return function () {
218
- if (controlledSyncRafRef.current != null) {
219
+ if (controlledSyncRafRef.current !== null) {
219
220
  cancelAnimationFrame(controlledSyncRafRef.current);
220
221
  }
221
222
  };
@@ -241,9 +242,10 @@ export var ComposerEditor = /*#__PURE__*/forwardRef(function ComposerEditor(_ref
241
242
  /* ─────────────────────────────────────
242
243
  * chip 管理
243
244
  * ───────────────────────────────────── */
245
+ var recomputeTriggerRef = useRef(function () {});
244
246
  var _useChipManager = useChipManager(function () {
245
247
  fireChange();
246
- recomputeTrigger();
248
+ recomputeTriggerRef.current();
247
249
  }),
248
250
  chips = _useChipManager.chips,
249
251
  _insertChip = _useChipManager.insertChip,
@@ -252,8 +254,11 @@ export var ComposerEditor = /*#__PURE__*/forwardRef(function ComposerEditor(_ref
252
254
  removeChip = _useChipManager.removeChip,
253
255
  updateChipData = _useChipManager.updateChipData,
254
256
  getChipHost = _useChipManager.getChipHost,
257
+ getChips = _useChipManager.getChips,
255
258
  resetChips = _useChipManager.resetChips;
256
259
  useChipSelectionMarker(editorRef, chips);
260
+ var insertSerializedAtRangeRef = useRef(insertSerializedAtRange);
261
+ insertSerializedAtRangeRef.current = insertSerializedAtRange;
257
262
 
258
263
  /* ─────────────────────────────────────
259
264
  * Trigger 探测
@@ -282,6 +287,7 @@ export var ComposerEditor = /*#__PURE__*/forwardRef(function ComposerEditor(_ref
282
287
  triggerRef.current = next;
283
288
  onTriggerChange === null || onTriggerChange === void 0 || onTriggerChange(next ? probeToInfo(next) : null);
284
289
  }, [triggers, onTriggerChange, probeToInfo]);
290
+ recomputeTriggerRef.current = recomputeTrigger;
285
291
 
286
292
  /* ─────────────────────────────────────
287
293
  * ref 命令式 API
@@ -363,18 +369,14 @@ export var ComposerEditor = /*#__PURE__*/forwardRef(function ComposerEditor(_ref
363
369
  },
364
370
  /* chips 快照:按 DOM 实际出现顺序输出(chips state 维护时已经有序)。
365
371
  * 不直接返回 chips 引用,避免外部 mutate 弄花内部 state。 */
366
- getChips: function getChips() {
367
- return chips.map(function (c) {
368
- return c.data;
369
- });
370
- },
372
+ getChips: getChips,
371
373
  updateChipData: updateChipData,
372
374
  getChipHost: getChipHost,
373
375
  get nativeElement() {
374
376
  return editorRef.current;
375
377
  }
376
378
  };
377
- }, [onChange, _insertChip, removeChip, resetChips, onTriggerChange, chips, updateChipData, getChipHost]);
379
+ }, [onChange, _insertChip, removeChip, resetChips, onTriggerChange, getChips, updateChipData, getChipHost]);
378
380
 
379
381
  /* ─────────────────────────────────────
380
382
  * 监听 selection 变化:方向键 / 鼠标点击移位都要重算 trigger
@@ -431,22 +433,34 @@ export var ComposerEditor = /*#__PURE__*/forwardRef(function ComposerEditor(_ref
431
433
  var el = editorRef.current;
432
434
  if (!el) return;
433
435
  var initial = isControlled ? valueProp !== null && valueProp !== void 0 ? valueProp : '' : defaultValue;
436
+ var initialChips = defaultChips !== null && defaultChips !== void 0 ? defaultChips : [];
434
437
  if (el.childNodes.length === 0) {
435
- var lines = (initial !== null && initial !== void 0 ? initial : '').split('\n');
436
- var frag = document.createDocumentFragment();
437
- var _iterator = _createForOfIteratorHelper(lines),
438
- _step;
439
- try {
440
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
441
- var line = _step.value;
442
- frag.appendChild(createLineRootWithText(line));
438
+ if (initialChips.length > 0) {
439
+ el.appendChild(createLineRoot());
440
+ var firstLine = el.firstChild;
441
+ if (firstLine) {
442
+ var range = document.createRange();
443
+ range.selectNodeContents(firstLine);
444
+ range.collapse(true);
445
+ insertSerializedAtRangeRef.current(initial, initialChips, range, el);
443
446
  }
444
- } catch (err) {
445
- _iterator.e(err);
446
- } finally {
447
- _iterator.f();
447
+ } else {
448
+ var lines = (initial !== null && initial !== void 0 ? initial : '').split('\n');
449
+ var frag = document.createDocumentFragment();
450
+ var _iterator = _createForOfIteratorHelper(lines),
451
+ _step;
452
+ try {
453
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
454
+ var line = _step.value;
455
+ frag.appendChild(createLineRootWithText(line));
456
+ }
457
+ } catch (err) {
458
+ _iterator.e(err);
459
+ } finally {
460
+ _iterator.f();
461
+ }
462
+ el.appendChild(frag);
448
463
  }
449
- el.appendChild(frag);
450
464
  if (initial && initial.length > 0) setEmpty(false);
451
465
  }
452
466
  // 仅初始化一次;后续受控同步走下方 effect
@@ -793,7 +807,7 @@ export var ComposerEditor = /*#__PURE__*/forwardRef(function ComposerEditor(_ref
793
807
  return /*#__PURE__*/createPortal( /*#__PURE__*/React.createElement(ComposerInlineRef, {
794
808
  data: chip.data,
795
809
  active: paramEditChipId === chip.data.id,
796
- onClick: onInlineRefClick ? function (anchor) {
810
+ onClick: onInlineRefClick && chipHasEditableParams(chip.data) ? function (anchor) {
797
811
  return onInlineRefClick(chip.data.id, anchor);
798
812
  } : undefined
799
813
  }), chip.host, chip.data.id);
@@ -39,6 +39,8 @@ export interface UseChipManagerReturn {
39
39
  updateChipData: (id: string, patch: Partial<ChipData>) => void;
40
40
  /** 按 id 取 chip host(参数面板 anchor)。 */
41
41
  getChipHost: (id: string) => HTMLSpanElement | null;
42
+ /** 当前 chip 快照(读 ref,插入后同步 onChange 时可用)。 */
43
+ getChips: () => ChipData[];
42
44
  /** 清空所有 chip 的 React 状态(DOM 由调用方 editor.innerHTML='' 一并处理)。 */
43
45
  resetChips: () => void;
44
46
  }
@@ -388,6 +388,13 @@ onAfterMutate) {
388
388
  return c.data.id === id;
389
389
  })) === null || _chipsRef$current$fin2 === void 0 ? void 0 : _chipsRef$current$fin2.host) !== null && _chipsRef$current$fin !== void 0 ? _chipsRef$current$fin : null;
390
390
  }, []);
391
+
392
+ /** 读 ref,插入后同步 onChange 时 state 可能还没 flush。 */
393
+ var getChips = useCallback(function () {
394
+ return chipsRef.current.map(function (c) {
395
+ return c.data;
396
+ });
397
+ }, []);
391
398
  var resetChips = useCallback(function () {
392
399
  setChips([]);
393
400
  chipsRef.current = [];
@@ -401,6 +408,7 @@ onAfterMutate) {
401
408
  removeChip: removeChip,
402
409
  updateChipData: updateChipData,
403
410
  getChipHost: getChipHost,
411
+ getChips: getChips,
404
412
  resetChips: resetChips
405
413
  };
406
414
  }
@@ -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;