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
@@ -0,0 +1,21 @@
1
+ /**
2
+ * InvocationParamPopover · 参数编辑浮层壳(业务填 children)
3
+ *
4
+ * 手写 portal + outside-click(排除 [data-odn-popup] 子树),与 ComposerMention
5
+ * SkillParamPopover 定位策略一致:贴在 anchor 上方。
6
+ */
7
+ import { type ReactNode } from 'react';
8
+ import './param-popover.scss';
9
+ export interface InvocationParamPopoverProps {
10
+ anchor: HTMLElement;
11
+ label: string;
12
+ icon?: string;
13
+ children: ReactNode;
14
+ onClose: () => void;
15
+ /**
16
+ * 浮层宽度。默认与 anchor 同宽;Composer 场景可传 composer box 实测宽度。
17
+ */
18
+ width?: number;
19
+ }
20
+ export declare function InvocationParamPopover({ anchor, label, icon, children, onClose, width, }: InvocationParamPopoverProps): import("react").ReactPortal | null;
21
+ export default InvocationParamPopover;
@@ -0,0 +1,113 @@
1
+ function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
2
+ function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
3
+ 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); }
4
+ 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; }
5
+ function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
6
+ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
7
+ /**
8
+ * InvocationParamPopover · 参数编辑浮层壳(业务填 children)
9
+ *
10
+ * 手写 portal + outside-click(排除 [data-odn-popup] 子树),与 ComposerMention
11
+ * SkillParamPopover 定位策略一致:贴在 anchor 上方。
12
+ */
13
+
14
+ import { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';
15
+ import { createPortal } from 'react-dom';
16
+ import Icon from "../icon";
17
+ import "./param-popover.scss";
18
+ export function InvocationParamPopover(_ref) {
19
+ var anchor = _ref.anchor,
20
+ label = _ref.label,
21
+ icon = _ref.icon,
22
+ children = _ref.children,
23
+ onClose = _ref.onClose,
24
+ width = _ref.width;
25
+ var ref = useRef(null);
26
+ var _useState = useState(null),
27
+ _useState2 = _slicedToArray(_useState, 2),
28
+ pos = _useState2[0],
29
+ setPos = _useState2[1];
30
+ var syncPosition = useCallback(function () {
31
+ var rect = anchor.getBoundingClientRect();
32
+ setPos({
33
+ left: rect.left + window.scrollX,
34
+ top: rect.top + window.scrollY,
35
+ width: width !== null && width !== void 0 ? width : rect.width
36
+ });
37
+ }, [anchor, width]);
38
+ useLayoutEffect(function () {
39
+ syncPosition();
40
+ }, [syncPosition]);
41
+ useEffect(function () {
42
+ var handleRelayout = function handleRelayout() {
43
+ return syncPosition();
44
+ };
45
+ window.addEventListener('resize', handleRelayout);
46
+ window.addEventListener('scroll', handleRelayout, true);
47
+ return function () {
48
+ window.removeEventListener('resize', handleRelayout);
49
+ window.removeEventListener('scroll', handleRelayout, true);
50
+ };
51
+ }, [syncPosition]);
52
+ useEffect(function () {
53
+ var handler = function handler(e) {
54
+ if (e.key === 'Escape') onClose();
55
+ };
56
+ document.addEventListener('keydown', handler);
57
+ return function () {
58
+ return document.removeEventListener('keydown', handler);
59
+ };
60
+ }, [onClose]);
61
+ useEffect(function () {
62
+ var handler = function handler(e) {
63
+ var _e$composedPath, _e$composedPath2;
64
+ if (!ref.current) return;
65
+ var target = e.target;
66
+ if (ref.current.contains(target)) return;
67
+ var path = (_e$composedPath = (_e$composedPath2 = e.composedPath) === null || _e$composedPath2 === void 0 ? void 0 : _e$composedPath2.call(e)) !== null && _e$composedPath !== void 0 ? _e$composedPath : [];
68
+ if (path.some(function (n) {
69
+ var _n$matches;
70
+ return n === null || n === void 0 || (_n$matches = n.matches) === null || _n$matches === void 0 ? void 0 : _n$matches.call(n, '[data-odn-popup]');
71
+ })) return;
72
+ if (anchor.contains(target)) return;
73
+ onClose();
74
+ };
75
+ document.addEventListener('mousedown', handler);
76
+ return function () {
77
+ return document.removeEventListener('mousedown', handler);
78
+ };
79
+ }, [anchor, onClose]);
80
+ if (!pos) return null;
81
+ return /*#__PURE__*/createPortal( /*#__PURE__*/React.createElement("div", {
82
+ ref: ref,
83
+ "data-odn-invocation-param-popover": true,
84
+ style: {
85
+ position: 'absolute',
86
+ left: pos.left,
87
+ top: pos.top,
88
+ width: pos.width,
89
+ zIndex: 1000
90
+ },
91
+ "data-odn-popup": true
92
+ }, /*#__PURE__*/React.createElement("div", {
93
+ "data-odn-invocation-param-popover-body": true
94
+ }, /*#__PURE__*/React.createElement("div", {
95
+ "data-odn-invocation-param-popover-header": true
96
+ }, icon ? /*#__PURE__*/React.createElement(Icon, {
97
+ name: icon,
98
+ size: 14
99
+ }) : null, /*#__PURE__*/React.createElement("span", {
100
+ "data-odn-invocation-param-popover-title": true
101
+ }, label), /*#__PURE__*/React.createElement("button", {
102
+ type: "button",
103
+ "data-odn-invocation-param-popover-close": true,
104
+ "aria-label": "\u5173\u95ED",
105
+ onClick: onClose
106
+ }, /*#__PURE__*/React.createElement(Icon, {
107
+ name: "x",
108
+ size: 12
109
+ }))), /*#__PURE__*/React.createElement("div", {
110
+ "data-odn-invocation-param-popover-content": true
111
+ }, children))), document.body);
112
+ }
113
+ export default InvocationParamPopover;
@@ -1,24 +1,32 @@
1
+ @charset "UTF-8";
2
+ /* 默认排版与 Composer 输入区一致(14 / 24);在 editor 内由下方 inherit 规则跟随正文 */
1
3
  [data-odn-invocation] {
2
4
  display: inline-flex;
3
5
  align-items: center;
4
6
  white-space: nowrap;
5
7
  word-break: keep-all;
6
8
  overflow-wrap: normal;
7
- margin: 0;
9
+ margin: 0 2px;
8
10
  padding: 0 4px;
9
11
  border-radius: 6px;
10
12
  background: transparent;
11
- color: var(--odn-color-cyan-6, var(--odn-color-cyan-5));
13
+ color: var(--odn-color-brand-7, var(--odn-color-brand-6));
12
14
  font-weight: 500;
13
- font-size: inherit;
14
- line-height: inherit;
15
+ font-size: 14px;
16
+ line-height: 24px;
15
17
  cursor: default;
16
18
  user-select: none;
17
19
  -webkit-user-select: none;
18
20
  transition: background-color 0.15s;
19
21
  }
22
+ [data-odn-invocation][data-state=pending] {
23
+ color: color-mix(in srgb, var(--odn-color-brand-7, var(--odn-color-brand-6)) 60%, transparent);
24
+ }
20
25
  [data-odn-invocation][data-state=active], [data-odn-invocation]:hover {
21
- background: color-mix(in srgb, var(--odn-color-cyan-5) 12%, transparent);
26
+ background: color-mix(in srgb, var(--odn-color-brand-6) 12%, transparent);
27
+ }
28
+ [data-odn-invocation][data-state=active] {
29
+ border-bottom: none;
22
30
  }
23
31
  [data-odn-invocation][data-clickable] {
24
32
  cursor: pointer;
@@ -28,6 +36,10 @@
28
36
  opacity: 0.7;
29
37
  }
30
38
 
39
+ [data-odn-invocation][data-state=pending] [data-odn-invocation-slash] {
40
+ opacity: 1;
41
+ }
42
+
31
43
  [data-odn-invocation-popover-inner] {
32
44
  display: flex;
33
45
  flex-direction: column;
@@ -39,20 +51,32 @@
39
51
  align-items: center;
40
52
  gap: 1px;
41
53
  font-weight: 500;
42
- color: var(--odn-color-cyan-6, var(--odn-color-cyan-5));
54
+ color: var(--odn-color-brand-7, var(--odn-color-brand-6));
43
55
  }
44
56
 
45
57
  [data-odn-invocation-popover-slash] {
46
58
  opacity: 0.7;
47
59
  }
48
60
 
49
- [data-odn-invocation-popover-summary] {
61
+ [data-odn-invocation-popover-summary],
62
+ [data-odn-invocation-popover-empty] {
50
63
  display: inline-block;
51
64
  align-self: flex-start;
52
65
  padding: 2px 6px;
53
66
  border-radius: 4px;
54
- background: color-mix(in srgb, var(--odn-color-cyan-5) 10%, transparent);
55
- color: var(--odn-color-cyan-6, var(--odn-color-cyan-5));
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));
56
69
  font-size: 12px;
57
70
  line-height: 1.4;
71
+ }
72
+
73
+ [data-odn-invocation-popover-empty] {
74
+ opacity: 0.85;
75
+ }
76
+
77
+ /* 文档 demo 混排容器:与 Composer 输入区同字号 */
78
+ [data-odn-inline-ref-demo] {
79
+ font-size: 14px;
80
+ line-height: 24px;
81
+ color: var(--odn-color-solid-black-12);
58
82
  }
@@ -3,14 +3,9 @@ import type { MentionData } from '../_genui-types';
3
3
  import './style';
4
4
  export interface MentionProps {
5
5
  data: MentionData;
6
- /**
7
- * true:Composer 编辑态(可点、无 hover 摘要弹层)。
8
- * false:UserBubble 等只读态(可 hover 看摘要)。
9
- */
10
6
  interactive?: boolean;
11
- /** form popover 打开时的高亮态(L4 params 启用后使用) */
7
+ /** 参数面板打开时高亮,最高优先级 */
12
8
  active?: boolean;
13
- /** 交互态单击回调 */
14
9
  onClick?: (anchor: HTMLElement) => void;
15
10
  }
16
11
  export declare function Mention({ data, interactive, active, onClick, }: MentionProps): import("react").JSX.Element;
@@ -6,9 +6,9 @@ function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" !=
6
6
  function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
7
7
  import Popover from "../popover";
8
8
  import "./style";
9
- function formatParamsSummary(params) {
10
- if (!params) return null;
11
- var entries = Object.entries(params).filter(function (_ref) {
9
+ function formatPayloadSummary(payload) {
10
+ if (!payload) return null;
11
+ var entries = Object.entries(payload).filter(function (_ref) {
12
12
  var _ref2 = _slicedToArray(_ref, 2),
13
13
  v = _ref2[1];
14
14
  return v != null && v !== '';
@@ -22,6 +22,7 @@ function formatParamsSummary(params) {
22
22
  }).join(' · ');
23
23
  }
24
24
  export function Mention(_ref5) {
25
+ var _data$state;
25
26
  var data = _ref5.data,
26
27
  _ref5$interactive = _ref5.interactive,
27
28
  interactive = _ref5$interactive === void 0 ? false : _ref5$interactive,
@@ -29,7 +30,7 @@ export function Mention(_ref5) {
29
30
  active = _ref5$active === void 0 ? false : _ref5$active,
30
31
  onClick = _ref5.onClick;
31
32
  var clickable = interactive && !!onClick;
32
- var state = active ? 'active' : 'complete';
33
+ var state = active ? 'active' : (_data$state = data.state) !== null && _data$state !== void 0 ? _data$state : 'complete';
33
34
  var handleClick = clickable ? function (e) {
34
35
  e.preventDefault();
35
36
  e.stopPropagation();
@@ -52,8 +53,8 @@ export function Mention(_ref5) {
52
53
  "data-odn-mention-label": true
53
54
  }, data.label));
54
55
  if (interactive) return core;
55
- var summary = formatParamsSummary(data.params);
56
- if (!summary) return core;
56
+ var summary = formatPayloadSummary(data.payload);
57
+ if (!summary && data.state !== 'pending') return core;
57
58
  return /*#__PURE__*/React.createElement(Popover, {
58
59
  trigger: "hover",
59
60
  placement: "top",
@@ -74,9 +75,11 @@ function MentionHoverPopup(_ref6) {
74
75
  "data-odn-mention-popover-inner": true
75
76
  }, /*#__PURE__*/React.createElement(MentionPopoverTitle, {
76
77
  label: label
77
- }), /*#__PURE__*/React.createElement("div", {
78
+ }), summary ? /*#__PURE__*/React.createElement("div", {
78
79
  "data-odn-mention-popover-summary": true
79
- }, summary));
80
+ }, summary) : /*#__PURE__*/React.createElement("div", {
81
+ "data-odn-mention-popover-empty": true
82
+ }, "\u672A\u586B\u53C2\u6570"));
80
83
  }
81
84
  function MentionPopoverTitle(_ref7) {
82
85
  var label = _ref7.label;
@@ -4,21 +4,27 @@
4
4
  white-space: nowrap;
5
5
  word-break: keep-all;
6
6
  overflow-wrap: normal;
7
- margin: 0;
7
+ margin: 0 2px;
8
8
  padding: 0 4px;
9
9
  border-radius: 6px;
10
10
  background: transparent;
11
- color: var(--odn-color-cyan-6, var(--odn-color-cyan-5));
11
+ color: var(--odn-color-brand-7, var(--odn-color-brand-6));
12
12
  font-weight: 500;
13
- font-size: inherit;
14
- line-height: inherit;
13
+ font-size: 14px;
14
+ line-height: 24px;
15
15
  cursor: default;
16
16
  user-select: none;
17
17
  -webkit-user-select: none;
18
18
  transition: background-color 0.15s;
19
19
  }
20
+ [data-odn-mention][data-state=pending] {
21
+ color: color-mix(in srgb, var(--odn-color-brand-7, var(--odn-color-brand-6)) 60%, transparent);
22
+ }
20
23
  [data-odn-mention][data-state=active], [data-odn-mention]:hover {
21
- background: color-mix(in srgb, var(--odn-color-cyan-5) 12%, transparent);
24
+ background: color-mix(in srgb, var(--odn-color-brand-6) 12%, transparent);
25
+ }
26
+ [data-odn-mention][data-state=active] {
27
+ border-bottom: none;
22
28
  }
23
29
  [data-odn-mention][data-clickable] {
24
30
  cursor: pointer;
@@ -28,6 +34,10 @@
28
34
  opacity: 0.7;
29
35
  }
30
36
 
37
+ [data-odn-mention][data-state=pending] [data-odn-mention-at] {
38
+ opacity: 1;
39
+ }
40
+
31
41
  [data-odn-mention-popover-inner] {
32
42
  display: flex;
33
43
  flex-direction: column;
@@ -39,20 +49,31 @@
39
49
  align-items: center;
40
50
  gap: 1px;
41
51
  font-weight: 500;
42
- color: var(--odn-color-cyan-6, var(--odn-color-cyan-5));
52
+ color: var(--odn-color-brand-7, var(--odn-color-brand-6));
43
53
  }
44
54
 
45
55
  [data-odn-mention-popover-at] {
46
56
  opacity: 0.7;
47
57
  }
48
58
 
49
- [data-odn-mention-popover-summary] {
59
+ [data-odn-mention-popover-summary],
60
+ [data-odn-mention-popover-empty] {
50
61
  display: inline-block;
51
62
  align-self: flex-start;
52
63
  padding: 2px 6px;
53
64
  border-radius: 4px;
54
- background: color-mix(in srgb, var(--odn-color-cyan-5) 10%, transparent);
55
- color: var(--odn-color-cyan-6, var(--odn-color-cyan-5));
65
+ background: color-mix(in srgb, var(--odn-color-brand-6) 10%, transparent);
66
+ color: var(--odn-color-brand-7, var(--odn-color-brand-6));
56
67
  font-size: 12px;
57
68
  line-height: 1.4;
69
+ }
70
+
71
+ [data-odn-mention-popover-empty] {
72
+ opacity: 0.85;
73
+ }
74
+
75
+ [data-odn-inline-ref-demo] {
76
+ font-size: 14px;
77
+ line-height: 24px;
78
+ color: var(--odn-color-solid-black-12);
58
79
  }
@@ -1,6 +1,7 @@
1
1
  import { useRef } from 'react';
2
2
  import Button from "../button";
3
3
  import Icon from "../icon";
4
+ import StreamText from "../stream-text";
4
5
  import { OdnOverlayVerticalScrollbar, useOverlayScrollbarReveal } from "../overlay-vertical-scrollbar";
5
6
  import "./style";
6
7
  export function PreviewPanel(_ref) {
@@ -28,6 +29,11 @@ export function PreviewPanel(_ref) {
28
29
  var _useOverlayScrollbarR = useOverlayScrollbarReveal(),
29
30
  previewScrollbarReveal = _useOverlayScrollbarR.reveal,
30
31
  handlePreviewScroll = _useOverlayScrollbarR.onScroll;
32
+ var isMarkdownTab = function isMarkdownTab(tab) {
33
+ var type = tab.type.toLowerCase();
34
+ var name = tab.name.toLowerCase();
35
+ return type === 'text/markdown' || type === 'text/x-markdown' || type === 'application/markdown' || type === 'application/x-markdown' || name.endsWith('.md') || name.endsWith('.markdown');
36
+ };
31
37
  var handleOpenInBrowser = function handleOpenInBrowser() {
32
38
  if (!activeTab) return;
33
39
  if (onOpenInBrowser) {
@@ -150,7 +156,11 @@ export function PreviewPanel(_ref) {
150
156
  sandbox: "allow-scripts",
151
157
  "data-odn-preview-panel-iframe": true,
152
158
  title: activeTab.name
153
- }) : /*#__PURE__*/React.createElement("pre", {
159
+ }) : isMarkdownTab(activeTab) ? /*#__PURE__*/React.createElement("div", {
160
+ "data-odn-preview-panel-markdown": true
161
+ }, /*#__PURE__*/React.createElement(StreamText, {
162
+ content: activeTab.content
163
+ })) : /*#__PURE__*/React.createElement("pre", {
154
164
  "data-odn-preview-panel-pre": true
155
165
  }, activeTab.content)), /*#__PURE__*/React.createElement(OdnOverlayVerticalScrollbar, {
156
166
  containerRef: previewScrollRef,
@@ -220,4 +220,15 @@
220
220
  background-color: var(--odn-color-solid-black-1);
221
221
  white-space: pre-wrap;
222
222
  word-break: break-word;
223
+ }
224
+
225
+ [data-odn-preview-panel-markdown] {
226
+ min-width: 0;
227
+ width: 100%;
228
+ box-sizing: border-box;
229
+ padding: 20px;
230
+ }
231
+
232
+ [data-odn-preview-panel-markdown] [data-odn-stream-text] {
233
+ max-width: none;
223
234
  }
@@ -47,18 +47,18 @@ export function SkillSlot(_ref) {
47
47
  onClick: function onClick() {
48
48
  return onSelect === null || onSelect === void 0 ? void 0 : onSelect(skill);
49
49
  }
50
+ }, /*#__PURE__*/React.createElement("span", {
51
+ "data-odn-skill-slot-card-header": true
50
52
  }, /*#__PURE__*/React.createElement("span", {
51
53
  "data-odn-skill-slot-item-icon": true
52
54
  }, /*#__PURE__*/React.createElement(Icon, {
53
55
  name: skill.icon,
54
- size: 20
56
+ size: 16
55
57
  })), /*#__PURE__*/React.createElement("span", {
56
- "data-odn-skill-slot-item-content": true
57
- }, /*#__PURE__*/React.createElement("span", {
58
58
  "data-odn-skill-slot-item-label": true
59
- }, skill.label), skill.description && /*#__PURE__*/React.createElement("span", {
59
+ }, skill.label)), skill.description && /*#__PURE__*/React.createElement("span", {
60
60
  "data-odn-skill-slot-item-desc": true
61
- }, skill.description)));
61
+ }, skill.description));
62
62
  }
63
63
  if (variant === 'menu') {
64
64
  /* HoverFill 包 button,视觉由 HoverFill 命令式控制。
@@ -69,8 +69,8 @@
69
69
  z-index: -1;
70
70
  }
71
71
  [data-odn-skill-slot][data-odn-skill-slot-variant=menu] [data-odn-skill-slot-item][data-odn-skill-slot-item-active] {
72
- color: var(--odn-color-cyan-5);
73
- background: color-mix(in srgb, var(--odn-color-cyan-5) 10%, transparent);
72
+ color: var(--odn-color-brand-6);
73
+ background: color-mix(in srgb, var(--odn-color-brand-6) 10%, transparent);
74
74
  }
75
75
 
76
76
  [data-odn-skill-slot][data-odn-skill-slot-variant=menu] [data-odn-skill-slot-item-label] {
@@ -112,63 +112,87 @@
112
112
  }
113
113
  [data-odn-skill-slot][data-odn-skill-slot-variant=bar] [data-odn-skill-slot-item]:not([data-odn-skill-slot-item-disabled]):focus-visible {
114
114
  outline: none;
115
- border-color: var(--odn-color-cyan-5);
115
+ border-color: var(--odn-color-brand-6);
116
116
  background: var(--odn-color-black-3);
117
117
  color: var(--odn-color-black-12);
118
118
  }
119
119
  [data-odn-skill-slot][data-odn-skill-slot-variant=bar] [data-odn-skill-slot-item][data-odn-skill-slot-item-active] {
120
- border-color: var(--odn-color-cyan-5);
121
- background: color-mix(in srgb, var(--odn-color-cyan-5) 8%, transparent);
122
- color: var(--odn-color-cyan-5);
120
+ border-color: var(--odn-color-brand-6);
121
+ background: color-mix(in srgb, var(--odn-color-brand-6) 8%, transparent);
122
+ color: var(--odn-color-brand-6);
123
123
  }
124
124
 
125
125
  /* ---- variant: card ---- */
126
126
  [data-odn-skill-slot][data-odn-skill-slot-variant=card] {
127
127
  display: grid;
128
128
  grid-template-columns: repeat(2, 1fr);
129
- gap: 12px;
129
+ gap: 10px;
130
130
  }
131
131
 
132
132
  [data-odn-skill-slot][data-odn-skill-slot-variant=card] [data-odn-skill-slot-item] {
133
133
  display: flex;
134
- align-items: flex-start;
135
- gap: 12px;
134
+ flex-direction: column;
135
+ align-items: stretch;
136
+ gap: 8px;
136
137
  width: 100%;
137
- padding: 14px;
138
- border-radius: 12px;
139
- border: 1px solid var(--odn-color-black-6);
140
- background: var(--odn-color-bg-elevated);
138
+ min-height: 84px;
139
+ padding: 16px 20px;
140
+ border-radius: 10px;
141
+ border: none;
142
+ background: var(--odn-color-white);
141
143
  text-align: left;
144
+ box-sizing: border-box;
145
+ transition: background-color 0.2s, box-shadow 0.2s;
142
146
  }
143
147
  [data-odn-skill-slot][data-odn-skill-slot-variant=card] [data-odn-skill-slot-item]:not([data-odn-skill-slot-item-disabled]):hover {
144
- border-color: color-mix(in srgb, var(--odn-color-cyan-5) 30%, transparent);
145
- background: color-mix(in srgb, var(--odn-color-cyan-5) 6%, transparent);
146
- box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.08), 0 2px 4px -2px rgba(0, 0, 0, 0.05);
148
+ background: var(--odn-color-white);
149
+ box-shadow: var(--odn-shadow-1);
147
150
  }
148
151
  [data-odn-skill-slot][data-odn-skill-slot-variant=card] [data-odn-skill-slot-item][data-odn-skill-slot-item-active] {
149
- border-color: var(--odn-color-cyan-5);
150
- background: color-mix(in srgb, var(--odn-color-cyan-5) 8%, transparent);
152
+ background: color-mix(in srgb, var(--odn-color-cyan-5) 8%, var(--odn-color-white));
153
+ box-shadow: 0 0 0 1px color-mix(in srgb, var(--odn-color-cyan-5) 16%, transparent);
151
154
  }
152
155
  [data-odn-skill-slot][data-odn-skill-slot-variant=card] [data-odn-skill-slot-item][data-odn-skill-slot-item-active] [data-odn-skill-slot-item-label] {
153
- color: var(--odn-color-cyan-5);
156
+ color: var(--odn-color-brand-6);
157
+ }
158
+
159
+ [data-odn-skill-slot][data-odn-skill-slot-variant=card] [data-odn-skill-slot-card-header] {
160
+ display: inline-flex;
161
+ align-items: center;
162
+ gap: 8px;
163
+ min-width: 0;
154
164
  }
155
165
 
156
166
  [data-odn-skill-slot][data-odn-skill-slot-variant=card] [data-odn-skill-slot-item-icon] {
157
167
  display: flex;
158
168
  align-items: center;
159
169
  justify-content: center;
160
- width: 36px;
161
- height: 36px;
162
- border-radius: 8px;
163
- background: color-mix(in srgb, var(--odn-color-cyan-5) 10%, transparent);
164
- color: var(--odn-color-cyan-5);
170
+ width: 16px;
171
+ height: 16px;
172
+ color: var(--odn-color-black-9);
165
173
  flex-shrink: 0;
166
174
  }
167
175
 
176
+ [data-odn-skill-slot][data-odn-skill-slot-variant=card] [data-odn-skill-slot-item-label] {
177
+ font-size: 14px;
178
+ font-weight: 600;
179
+ line-height: 22px;
180
+ }
181
+
182
+ [data-odn-skill-slot][data-odn-skill-slot-variant=card] [data-odn-skill-slot-item-desc] {
183
+ font-size: 14px;
184
+ font-weight: 400;
185
+ color: var(--odn-color-black-9);
186
+ line-height: 20px;
187
+ white-space: nowrap;
188
+ overflow: hidden;
189
+ text-overflow: ellipsis;
190
+ }
191
+
168
192
  [data-odn-skill-slot-item-content] {
169
193
  display: flex;
170
194
  flex-direction: column;
171
- gap: 2px;
195
+ gap: 4px;
172
196
  min-width: 0;
173
197
  flex: 1;
174
198
  }
@@ -177,11 +201,11 @@
177
201
  font-size: 14px;
178
202
  font-weight: 600;
179
203
  color: var(--odn-color-black-12);
180
- line-height: 1.4;
204
+ line-height: 22px;
181
205
  }
182
206
 
183
207
  [data-odn-skill-slot-item-desc] {
184
208
  font-size: 12px;
185
209
  color: var(--odn-color-black-8);
186
- line-height: 1.5;
210
+ line-height: 20px;
187
211
  }
@@ -1,4 +1,3 @@
1
- import Icon from "../icon";
2
1
  import "./style";
3
2
  export function Suggestions(_ref) {
4
3
  var suggestions = _ref.suggestions,
@@ -13,10 +12,7 @@ export function Suggestions(_ref) {
13
12
  return onSelect(text);
14
13
  },
15
14
  "data-odn-suggestions-item": true
16
- }, text, /*#__PURE__*/React.createElement(Icon, {
17
- name: "arrow-up-right",
18
- size: 12
19
- }));
15
+ }, text);
20
16
  }));
21
17
  }
22
18
  Suggestions.displayName = 'Suggestions';
@@ -8,17 +8,16 @@
8
8
  display: inline-flex;
9
9
  align-items: center;
10
10
  gap: 4px;
11
- padding: 4px 10px;
12
- border-radius: 4px;
13
- border: 1px solid var(--odn-color-black-6);
14
- background: var(--odn-color-bg-elevated);
11
+ padding: 8px 12px;
12
+ border-radius: 8px;
13
+ border: none;
14
+ background: var(--odn-color-black-2);
15
15
  font-size: 13px;
16
16
  color: var(--odn-color-black-10);
17
17
  cursor: pointer;
18
- transition: border-color 0.15s, background 0.15s, color 0.15s;
18
+ transition: background 0.15s, color 0.15s, box-shadow 0.15s;
19
19
  }
20
20
  [data-odn-suggestions-item]:hover {
21
- border-color: var(--odn-color-black-7);
22
21
  background: var(--odn-color-black-3);
23
22
  color: var(--odn-color-black-12);
24
23
  }
@@ -27,5 +26,5 @@
27
26
  }
28
27
  [data-odn-suggestions-item]:focus-visible {
29
28
  outline: none;
30
- border-color: var(--odn-color-cyan-5);
29
+ box-shadow: 0 0 0 2px var(--odn-color-cyan-5);
31
30
  }
@@ -1,12 +1,15 @@
1
1
  import { Attachments } from "../attachments";
2
2
  import MessageImage from "../message-image";
3
+ import { renderSegmentsContent, segmentsHaveVisibleContent } from "./render-segments";
3
4
  import "./style";
4
5
  export function UserBubble(_ref) {
5
- var _message$attachments;
6
+ var _message$content, _message$attachments;
6
7
  var message = _ref.message,
7
8
  onFileClick = _ref.onFileClick,
8
9
  onImagePreview = _ref.onImagePreview;
9
- var hasText = !!message.content;
10
+ var segments = message.segments;
11
+ var hasText = segments !== null && segments !== void 0 && segments.length ? segmentsHaveVisibleContent(segments) : !!((_message$content = message.content) !== null && _message$content !== void 0 && _message$content.trim());
12
+ var textBody = segments !== null && segments !== void 0 && segments.length ? renderSegmentsContent(segments) : message.content;
10
13
  var all = (_message$attachments = message.attachments) !== null && _message$attachments !== void 0 ? _message$attachments : [];
11
14
 
12
15
  /* 图片附件分流到 MessageImage,保持其数据驱动尺寸的渲染语义;
@@ -34,9 +37,11 @@ export function UserBubble(_ref) {
34
37
  onPreview: onImagePreview ? function (i) {
35
38
  return onImagePreview(i, images);
36
39
  } : undefined
37
- })), hasText && /*#__PURE__*/React.createElement("div", {
40
+ })), hasText && textBody != null && /*#__PURE__*/React.createElement("div", {
38
41
  "data-odn-user-bubble-text": true
39
- }, /*#__PURE__*/React.createElement("p", null, message.content)), files.length > 0 && /*#__PURE__*/React.createElement("div", {
42
+ }, /*#__PURE__*/React.createElement("p", {
43
+ "data-odn-user-bubble-body": true
44
+ }, textBody)), files.length > 0 && /*#__PURE__*/React.createElement("div", {
40
45
  "data-odn-user-bubble-files": true
41
46
  }, /*#__PURE__*/React.createElement(Attachments, {
42
47
  attachments: files,