@morlay/ui-conversation-message-actions 0.1.4 → 0.1.5

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.
@@ -34,6 +34,7 @@ var __copyProps = (to, from, except, desc) => {
34
34
  }
35
35
  return to;
36
36
  };
37
+ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
37
38
  var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
38
39
  value: mod,
39
40
  enumerable: true
@@ -41,4 +42,4 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
41
42
  var __toCommonJS = (mod) => __hasOwnProp.call(mod, "module.exports") ? mod["module.exports"] : __copyProps(__defProp({}, "__esModule", { value: true }), mod);
42
43
  var __require = /* #__PURE__ */ (() => createRequire(import.meta.url))();
43
44
  //#endregion
44
- export { __toCommonJS as a, __require as i, __esmMin as n, __toESM as o, __exportAll as r, __commonJSMin as t };
45
+ export { __require as a, __reExport as i, __esmMin as n, __toCommonJS as o, __exportAll as r, __toESM as s, __commonJSMin as t };
package/dist/testing.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { a as __toCommonJS, i as __require, n as __esmMin, o as __toESM, r as __exportAll, t as __commonJSMin } from "./rolldown-runtime-BMI-E3GI.mjs";
1
+ import { a as __require, n as __esmMin, o as __toCommonJS, r as __exportAll, s as __toESM, t as __commonJSMin } from "./rolldown-runtime-Dr7-SnC6.mjs";
2
2
  import { t as SESSION_EDITOR_PATHS } from "./shared-DG86bLrc.mjs";
3
3
  import { SessionEditor } from "./index.mjs";
4
4
  import { Context, Service } from "@deepseek-ai/cordis";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@morlay/ui-conversation-message-actions",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Rewind / retry / recall / fork orchestration (host) plus the browser half — replaces the conversation.chat.node user / steering rendering and overrides the conversation.composer.dock stats row.",
5
5
  "keywords": [
6
6
  "conversation-chat-node",
@@ -38,13 +38,13 @@
38
38
  "./locale/*.json": "./locale/*.json"
39
39
  },
40
40
  "dependencies": {
41
- "@morlay/session-branch": "0.1.4"
41
+ "@morlay/session-branch": "0.1.5"
42
42
  },
43
43
  "devDependencies": {
44
44
  "@deepseek-ai/dsh-client-ui-conversation": "0.2.0-rc.2",
45
45
  "@deepseek-ai/dsh-session-stats": "0.2.0-rc.2",
46
- "@morlay/dsh-client-ui-primitives": "0.0.7",
47
- "@morlay/session-rdb": "0.1.4",
46
+ "@morlay/dsh-client-ui-primitives": "0.0.8",
47
+ "@morlay/session-rdb": "0.1.5",
48
48
  "@types/react": "~18.3.1",
49
49
  "@types/react-dom": "~18.3.0",
50
50
  "react": "^18.2.0",
@@ -2,21 +2,28 @@
2
2
  // 在消息动作行上提供 edit / retry;其余 key 由官方内置渲染器处理。
3
3
 
4
4
  import {
5
+ Bubble,
6
+ Button,
7
+ IconButton,
8
+ IconEditOutlineRegular,
9
+ IconRefreshOutlineRegular,
10
+ JsonBlock,
5
11
  markdownLabels,
12
+ Modal,
6
13
  ReferenceMarkdown,
7
- styling,
14
+ Row,
15
+ Stack,
8
16
  type ReferenceActions,
9
17
  } from "@morlay/dsh-client-ui-primitives/client";
10
18
  import { memo, useMemo, useState } from "react";
11
19
  import type { ReactNode } from "react";
12
20
  import type { InjectFace } from "@deepseek-ai/dsh-client-ui-slots";
13
- import { Button, Modal } from "@deepseek-ai/dsh-client-ui-primitives";
14
21
  import type { UserMessageNode } from "@deepseek-ai/dsh-client-ui-chat/client";
15
- import { JsonBlock } from "@deepseek-ai/dsh-client-ui-primitives";
16
22
  import type { ChatNodeViewProps, ChatViewSlotProps } from "@deepseek-ai/dsh-client-ui-chat/client";
17
23
  import type { RenderMessageImages } from "@deepseek-ai/dsh-client-ui-conversation/client";
18
- import { MessageIconActions } from "./MessageIconActions.tsx";
19
- import { styles } from "./MessageItem.styles.ts";
24
+ // 动作行整条用上游那份:复制 / 分支 / 时间标签的悬停显形都归它,我们只经它的 `extraActions` 注入自己的两个入口。
25
+ // 走 vendor 源码的相对路径(与 `dsh-subagent` 接上游源码同一种写法),不经包出口。
26
+ import { MessageIconActions } from "../../../../../../vendor/deepseek-harness/packages/client/ui-chat/src/client/chat/MessageIconActions.tsx";
20
27
  import type { EditableMessageBlock } from "../../shared.ts";
21
28
  import type { SessionEditorFace } from "../controller.ts";
22
29
 
@@ -63,11 +70,11 @@ function UserStyleBubble({
63
70
  const labels = useMemo(() => markdownLabels(t), [t]);
64
71
  const showBubble = text !== "" || rest.length > 0;
65
72
  return (
66
- <div {...styling.props(styles.userRow)} data-time-hover-root>
67
- <div {...styling.props(styles.userStack)}>
73
+ <Stack align="end" gap={6} data-time-hover-root>
74
+ <Stack align="end" gap={8} narrow>
68
75
  {renderMessageImages({ images, align: "end" })}
69
76
  {showBubble && (
70
- <div {...styling.props(styles.bubble)}>
77
+ <Bubble>
71
78
  <ReferenceMarkdown text={text} labels={labels} actions={references} />
72
79
  {rest.map((block, i) => (
73
80
  <JsonBlock
@@ -77,11 +84,11 @@ function UserStyleBubble({
77
84
  truncatedLabel={truncated}
78
85
  />
79
86
  ))}
80
- </div>
87
+ </Bubble>
81
88
  )}
82
- </div>
89
+ </Stack>
83
90
  {actions?.(text)}
84
- </div>
91
+ </Stack>
85
92
  );
86
93
  }
87
94
 
@@ -147,7 +154,7 @@ export const UserMessageNodeView = memo(function UserMessageNodeView({
147
154
  closeLabel="关闭"
148
155
  description="将撤回该消息及其之后的对话内容到输入框,请修改后重新发送。"
149
156
  footer={
150
- <div {...styling.props(styles.confirmActions)}>
157
+ <Row gap={8} justify="end">
151
158
  <Button variant="outline" onClick={() => setConfirmingRecall(null)}>
152
159
  取消
153
160
  </Button>
@@ -161,7 +168,7 @@ export const UserMessageNodeView = memo(function UserMessageNodeView({
161
168
  >
162
169
  撤回并编辑
163
170
  </Button>
164
- </div>
171
+ </Row>
165
172
  }
166
173
  />
167
174
  )}
@@ -173,7 +180,7 @@ export const UserMessageNodeView = memo(function UserMessageNodeView({
173
180
  closeLabel="关闭"
174
181
  description={`将重新生成第 ${turn} 轮的回复,并抛弃该回合之后的内容。`}
175
182
  footer={
176
- <div {...styling.props(styles.confirmActions)}>
183
+ <Row gap={8} justify="end">
177
184
  <Button variant="outline" onClick={() => setConfirmingRetry(false)}>
178
185
  取消
179
186
  </Button>
@@ -186,7 +193,7 @@ export const UserMessageNodeView = memo(function UserMessageNodeView({
186
193
  >
187
194
  确认重试
188
195
  </Button>
189
- </div>
196
+ </Row>
190
197
  }
191
198
  />
192
199
  )}
@@ -201,8 +208,20 @@ export const UserMessageNodeView = memo(function UserMessageNodeView({
201
208
  time={data.time}
202
209
  clock="start"
203
210
  t={t}
204
- onEdit={onEdit}
205
- onRetry={onRetry}
211
+ extraActions={
212
+ <>
213
+ {onEdit === undefined ? null : (
214
+ <IconButton shape="circle" label="编辑" onClick={onEdit}>
215
+ <IconEditOutlineRegular />
216
+ </IconButton>
217
+ )}
218
+ {onRetry === undefined ? null : (
219
+ <IconButton shape="circle" label="重试此回合" onClick={onRetry}>
220
+ <IconRefreshOutlineRegular />
221
+ </IconButton>
222
+ )}
223
+ </>
224
+ }
206
225
  />
207
226
  )}
208
227
  />
@@ -5,16 +5,13 @@ import type {} from "@deepseek-ai/dsh-client-ui-renderer/client";
5
5
  import type { SessionId } from "@deepseek-ai/dsh-session";
6
6
  import { SessionEditorController } from "./controller.ts";
7
7
  import { registerChatNodeRenderers } from "./chat-node/register.ts";
8
- import { registerComposerStats } from "./composer-stats/register.ts";
9
- import { apply as installUiPrimitives, styling } from "@morlay/dsh-client-ui-primitives/client";
10
- import { globals as messageIconGlobals } from "./chat-node/MessageIconActions.styles.ts";
8
+ import { apply as installUiPrimitives } from "@morlay/dsh-client-ui-primitives/client";
11
9
 
12
10
  export const inject = ["slots", "conversation", "connection", "sessions", "uiWorkspace"];
13
11
 
14
12
  export function apply(ctx: Context): void {
15
13
  // 基础面随本包 inline(不再是装配行):装上它提供的字典、字段槽与按行配置页;多份副本只装一次。
16
14
  installUiPrimitives(ctx);
17
- styling.injectGlobals(messageIconGlobals);
18
15
 
19
16
  const controllers = new Map<SessionId, SessionEditorController>();
20
17
  const controllerFor = (sessionId: SessionId): SessionEditorController => {
@@ -27,6 +24,4 @@ export function apply(ctx: Context): void {
27
24
  };
28
25
 
29
26
  registerChatNodeRenderers(ctx, controllerFor);
30
-
31
- ctx.slots.inject("conversation.composer.dock", () => registerComposerStats(ctx.slots));
32
27
  }
@@ -1,76 +0,0 @@
1
- import type { CSSProps } from "@morlay/dsh-client-ui-primitives/client";
2
-
3
- export const styles = {
4
- actions: {
5
- display: "flex",
6
- alignItems: "center",
7
- gap: "10px",
8
- height: "28px",
9
- },
10
- timeStart: {
11
- paddingRight: "12px",
12
- fontSize: "14px",
13
- lineHeight: "24px",
14
- color: "var(--dsw-alias-label-tertiary)",
15
- whiteSpace: "nowrap",
16
- },
17
- timeEnd: {
18
- paddingLeft: "12px",
19
- fontSize: "14px",
20
- lineHeight: "24px",
21
- color: "var(--dsw-alias-label-tertiary)",
22
- whiteSpace: "nowrap",
23
- "&)": {
24
- "@media (hover: hover)": {
25
- opacity: "1",
26
- },
27
- },
28
- },
29
- runTimeDot: {
30
- margin: "0 10px",
31
- },
32
- action: {
33
- display: "inline-flex",
34
- alignItems: "center",
35
- justifyContent: "center",
36
- width: "28px",
37
- height: "28px",
38
- padding: "6px",
39
- border: "none",
40
- borderRadius: "28px",
41
- background: "transparent",
42
- color: "var(--dsw-alias-label-tertiary)",
43
- cursor: "pointer",
44
- "&:hover": {
45
- background: "var(--dsw-alias-interactive-bg-hover)",
46
- color: "var(--dsw-alias-label-secondary)",
47
- },
48
- "&[data-unavailable]": {
49
- cursor: "default",
50
- opacity: "0.4",
51
- },
52
- "&[data-unavailable]:hover": {
53
- background: "transparent",
54
- color: "var(--dsw-alias-label-tertiary)",
55
- },
56
- },
57
- visuallyHidden: {
58
- position: "absolute",
59
- width: "1px",
60
- height: "1px",
61
- overflow: "hidden",
62
- clip: "rect(0 0 0 0)",
63
- whiteSpace: "nowrap",
64
- },
65
- } satisfies Record<string, CSSProps>;
66
-
67
- export const globals = {
68
- "[data-time-hover-root] [data-time-label]": {
69
- opacity: "0",
70
- transition: "opacity 80ms ease",
71
- },
72
- "[data-time-hover-root]:hover :is(.timeStart, .timeEnd),\n [data-time-hover-root]:focus-within :is(.timeStart, .timeEnd)":
73
- {
74
- opacity: "1",
75
- },
76
- } satisfies Record<string, CSSProps>;
@@ -1,166 +0,0 @@
1
- // Shared IconActions chrome for user and assistant messages: copy
2
- // live, optional branch wiring, and an optional date-aware clock.
3
-
4
- import { styling } from "@morlay/dsh-client-ui-primitives/client";
5
- import { useCallback, useEffect, useId, useRef, useState, type ReactNode } from "react";
6
- import {
7
- IconBranchOutlineRegular,
8
- IconCheckOutlineRegular,
9
- IconCopyOutlineRegular,
10
- IconEditOutlineRegular,
11
- IconRefreshOutlineRegular,
12
- Tooltip,
13
- writeClipboard,
14
- } from "@deepseek-ai/dsh-client-ui-primitives";
15
- import type { ChatViewSlotProps } from "@deepseek-ai/dsh-client-ui-chat/client";
16
- import { formatMessageClock } from "./message-chrome.ts";
17
- import { useCalendarDay } from "./use-calendar-day.ts";
18
- import { styles } from "./MessageIconActions.styles.ts";
19
-
20
- export interface MessageIconActionsProps {
21
- text: string;
22
-
23
- time?: number | undefined;
24
-
25
- clock: "start" | "end";
26
-
27
- onBranch?: (() => void) | undefined;
28
-
29
- branchUnavailable?: boolean | undefined;
30
-
31
- className?: string | undefined;
32
-
33
- extraActions?: ReactNode;
34
-
35
- onEdit?: (() => void) | undefined;
36
-
37
- onRetry?: (() => void) | undefined;
38
-
39
- t: ChatViewSlotProps["t"];
40
- }
41
-
42
- export function MessageIconActions({
43
- text,
44
- time,
45
- clock,
46
- onBranch,
47
- branchUnavailable = false,
48
- className,
49
- extraActions,
50
- onEdit,
51
- onRetry,
52
- t,
53
- }: MessageIconActionsProps) {
54
- const day = useCalendarDay();
55
- const reasonId = useId();
56
- // Same success chrome as CodeBlock: a short check swap after the write,
57
- // gated so re-clicks during the window neither re-copy nor stack timers.
58
- const [copied, setCopied] = useState(false);
59
- const copyPending = useRef(false);
60
- const copyTimer = useRef<number | null>(null);
61
- const copyEpoch = useRef(0);
62
- useEffect(
63
- () => () => {
64
- copyEpoch.current += 1;
65
- copyPending.current = false;
66
- if (copyTimer.current !== null) clearTimeout(copyTimer.current);
67
- },
68
- [],
69
- );
70
- const onCopy = useCallback(() => {
71
- if (copied || copyPending.current) return;
72
- const epoch = copyEpoch.current;
73
- copyPending.current = true;
74
- void writeClipboard(text).then((ok) => {
75
- if (epoch !== copyEpoch.current) return;
76
- copyPending.current = false;
77
- if (!ok) return;
78
- setCopied(true);
79
- copyTimer.current = window.setTimeout(() => {
80
- copyTimer.current = null;
81
- setCopied(false);
82
- }, 1000);
83
- });
84
- }, [copied, text]);
85
- // 只剩时钟:耗时 / TTFT / tok-s 的读数在 0.1.7 已不属于消息 chrome(上游把它们收进
86
- // 会话统计弹窗与轮次过程节点),上游那套聊天文案表也不再提供这三个 key。
87
- const clockEl =
88
- time === undefined ? null : (
89
- <span
90
- data-time-label=""
91
- {...styling.props(clock === "start" ? styles.timeStart : styles.timeEnd)}
92
- >
93
- {formatMessageClock(time, t, day)}
94
- </span>
95
- );
96
- // 外部 className 需要拼接:给 actions 一个真实类名(而不是 data-css 属性)。
97
- const actionsClass = styling.className(styles.actions);
98
- return (
99
- <div
100
- data-time-hover-root=""
101
- className={className === undefined ? actionsClass : `${actionsClass} ${className}`}
102
- >
103
- {clock === "start" ? clockEl : null}
104
- <Tooltip label={copied ? t("copied" as never) : t("copy" as never)} side="bottom">
105
- <button
106
- type="button"
107
- {...styling.props(styles.action)}
108
- aria-label={copied ? t("copied" as never) : t("copy" as never)}
109
- onClick={onCopy}
110
- >
111
- {copied ? <IconCheckOutlineRegular /> : <IconCopyOutlineRegular />}
112
- </button>
113
- </Tooltip>
114
- {extraActions}
115
- {onEdit !== undefined && (
116
- <Tooltip label="编辑" side="bottom">
117
- <button
118
- type="button"
119
- {...styling.props(styles.action)}
120
- aria-label="编辑"
121
- onClick={onEdit}
122
- >
123
- <IconEditOutlineRegular />
124
- </button>
125
- </Tooltip>
126
- )}
127
- {onRetry !== undefined && (
128
- <Tooltip label="重试此回合" side="bottom">
129
- <button
130
- type="button"
131
- {...styling.props(styles.action)}
132
- aria-label="重试此回合"
133
- onClick={onRetry}
134
- >
135
- <IconRefreshOutlineRegular />
136
- </button>
137
- </Tooltip>
138
- )}
139
- {onBranch !== undefined && (
140
- <Tooltip
141
- label={branchUnavailable ? t("message.branchUnavailable") : t("message.branch")}
142
- side="bottom"
143
- >
144
- {/* Native disabled buttons do not deliver the hover/focus events Tooltip needs. */}
145
- <button
146
- type="button"
147
- {...styling.props(styles.action)}
148
- aria-label={t("message.branch")}
149
- aria-disabled={branchUnavailable || undefined}
150
- aria-describedby={branchUnavailable ? reasonId : undefined}
151
- data-unavailable={branchUnavailable || undefined}
152
- onClick={branchUnavailable ? undefined : onBranch}
153
- >
154
- <IconBranchOutlineRegular />
155
- </button>
156
- </Tooltip>
157
- )}
158
- {onBranch !== undefined && branchUnavailable && (
159
- <span id={reasonId} {...styling.props(styles.visuallyHidden)}>
160
- {t("message.branchUnavailable")}
161
- </span>
162
- )}
163
- {clock === "end" ? clockEl : null}
164
- </div>
165
- );
166
- }
@@ -1,248 +0,0 @@
1
- import type { CSSProps } from "@morlay/dsh-client-ui-primitives/client";
2
-
3
- export const styles = {
4
- userRow: {
5
- display: "flex",
6
- flexDirection: "column",
7
- alignItems: "flex-end",
8
- gap: "6px",
9
- },
10
- userStack: {
11
- display: "flex",
12
- flexDirection: "column",
13
- alignItems: "flex-end",
14
- gap: "8px",
15
- minWidth: "0",
16
- maxWidth: "min(525px, 82%)",
17
- },
18
- bubble: {
19
- maxWidth: "100%",
20
- background: "var(--dsw-specific-bubble)",
21
- borderRadius: "22px",
22
- padding: "10px 16px",
23
- fontSize: "16px",
24
- lineHeight: "24px",
25
- color: "var(--dsw-alias-label-primary)",
26
- },
27
- contextRow: {
28
- padding: "2px 0",
29
- },
30
- compactionRow: {
31
- padding: "2px 0",
32
- },
33
- compactionButton: {
34
- display: "flex",
35
- alignItems: "center",
36
- width: "100%",
37
- height: "24px",
38
- minWidth: "0",
39
- padding: "0",
40
- border: "none",
41
- borderRadius: "6px",
42
- background: "none",
43
- color: "inherit",
44
- font: "inherit",
45
- textAlign: "left",
46
- "&:not(:disabled)": {
47
- cursor: "pointer",
48
- },
49
- "&:not(:disabled):hover": {
50
- background: "var(--dsw-alias-interactive-bg-hover)",
51
- },
52
- "&:not(:disabled):hover .compactionContextIcon": {
53
- opacity: "0",
54
- },
55
- "&:not(:disabled):focus-visible .compactionContextIcon": {
56
- opacity: "0",
57
- },
58
- "&:not(:disabled):hover .compactionDisclosureIcon": {
59
- opacity: "1",
60
- },
61
- "&:not(:disabled):focus-visible .compactionDisclosureIcon": {
62
- opacity: "1",
63
- },
64
- },
65
- compactionLeading: {
66
- flex: "none",
67
- display: "inline-grid",
68
- placeItems: "center",
69
- width: "16px",
70
- height: "16px",
71
- marginRight: "6px",
72
- color: "var(--dsw-alias-label-secondary)",
73
- },
74
- compactionContextIcon: {
75
- display: "inline-flex",
76
- gridArea: "1 / 1",
77
- alignItems: "center",
78
- justifyContent: "center",
79
- },
80
- compactionDisclosureIcon: {
81
- display: "inline-flex",
82
- gridArea: "1 / 1",
83
- alignItems: "center",
84
- justifyContent: "center",
85
- opacity: "0",
86
- },
87
- compactionTitle: {
88
- flex: "none",
89
- fontSize: "14px",
90
- lineHeight: "24px",
91
- color: "var(--dsw-alias-label-primary-dimmed)",
92
- },
93
- compactionSep: {
94
- flex: "none",
95
- width: "2px",
96
- height: "2px",
97
- margin: "0 8px",
98
- borderRadius: "1px",
99
- background: "var(--dsw-alias-label-caption)",
100
- },
101
- compactionSummary: {
102
- flex: "1 1 auto",
103
- minWidth: "0",
104
- overflow: "hidden",
105
- color: "var(--dsw-alias-label-tertiary)",
106
- fontSize: "14px",
107
- lineHeight: "24px",
108
- textOverflow: "ellipsis",
109
- whiteSpace: "nowrap",
110
- },
111
- compactionBody: {
112
- padding: "4px 0 4px 22px",
113
- color: "var(--dsw-alias-label-tertiary)",
114
- fontSize: "14px",
115
- lineHeight: "24px",
116
- },
117
- retryRow: {
118
- color: "var(--dsw-alias-label-tertiary)",
119
- fontSize: "13px",
120
- lineHeight: "20px",
121
- "&[data-active] .retryText": {
122
- background:
123
- "linear-gradient(\n 90deg,\n var(--dsw-alias-label-tertiary) 0%,\n var(--dsw-alias-label-tertiary) 40%,\n var(--dsw-alias-label-secondary) 50%,\n var(--dsw-alias-label-tertiary) 60%,\n var(--dsw-alias-label-tertiary) 100%\n )",
124
- backgroundPosition: "100% 50%",
125
- backgroundSize: "200% 100%",
126
- backgroundClip: "text",
127
- color: "transparent",
128
- animation: "retry-shimmer 1.6s ease-in-out infinite",
129
- "@media (prefers-reduced-motion: reduce)": {
130
- background: "none",
131
- color: "inherit",
132
- animation: "none",
133
- },
134
- },
135
- "&[open] .retrySummary::after": {
136
- transform: "rotate(45deg)",
137
- },
138
- },
139
- retrySummary: {
140
- display: "inline-flex",
141
- alignItems: "center",
142
- width: "fit-content",
143
- padding: "2px 0",
144
- gap: "7px",
145
- borderRadius: "3px",
146
- color: "inherit",
147
- cursor: "pointer",
148
- listStyle: "none",
149
- userSelect: "none",
150
- "&::-webkit-details-marker": {
151
- display: "none",
152
- },
153
- "&::after": {
154
- width: "6px",
155
- height: "6px",
156
- borderRight: "1.5px solid currentcolor",
157
- borderBottom: "1.5px solid currentcolor",
158
- content: '""',
159
- opacity: "0.8",
160
- transform: "rotate(-45deg)",
161
- transition: "transform 120ms ease",
162
- },
163
- "&:hover": {
164
- color: "var(--dsw-alias-label-secondary)",
165
- },
166
- "&:focus-visible": {
167
- // 上游 ui-chat 的 MessageItem 这轮把焦点环改成读官方焦点变量(`focus.css` 口径)。
168
- outline: "1.5px solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary))",
169
- outlineOffset: "2px",
170
- },
171
- },
172
- retryText: {
173
- color: "inherit",
174
- },
175
- retryDetails: {
176
- display: "grid",
177
- gap: "2px",
178
- marginTop: "3px",
179
- paddingLeft: "14px",
180
- overflowWrap: "anywhere",
181
- fontSize: "12px",
182
- lineHeight: "18px",
183
- },
184
- retryDetailLabel: {
185
- color: "var(--dsw-alias-label-secondary)",
186
- },
187
- turnErrorRow: {
188
- display: "grid",
189
- gridTemplateColumns: "10px minmax(0, 1fr) auto",
190
- gap: "8px",
191
- alignItems: "start",
192
- padding: "2px 0",
193
- fontSize: "13px",
194
- lineHeight: "20px",
195
- },
196
- turnErrorDot: {
197
- marginTop: "5px",
198
- },
199
- turnErrorCopy: {
200
- minWidth: "0",
201
- overflowWrap: "anywhere",
202
- },
203
- turnErrorTitle: {
204
- marginRight: "6px",
205
- color: "var(--dsw-alias-state-error-primary)",
206
- fontWeight: "600",
207
- },
208
- turnErrorMessage: {
209
- color: "var(--dsw-alias-label-secondary)",
210
- },
211
- turnErrorCode: {
212
- color: "var(--dsw-alias-label-tertiary)",
213
- font: "var(--dsw-font-markdown-code-block-small)",
214
- },
215
- maxTokensTitle: {
216
- marginRight: "6px",
217
- color: "var(--dsw-alias-state-warn-primary)",
218
- fontWeight: "600",
219
- },
220
- refChip: {
221
- display: "inline-block",
222
- margin: "0 2px",
223
- padding: "0 8px",
224
- borderRadius: "6px",
225
- background: "rgba(97, 135, 216, 0.22)",
226
- color: "var(--dsw-alias-label-primary)",
227
- fontSize: "0.85em",
228
- lineHeight: "1.6",
229
- whiteSpace: "nowrap",
230
- verticalAlign: "baseline",
231
- },
232
- confirmActions: {
233
- display: "flex",
234
- justifyContent: "flex-end",
235
- gap: "8px",
236
- },
237
- } satisfies Record<string, CSSProps>;
238
-
239
- export const animations = {
240
- "retry-shimmer": {
241
- from: {
242
- backgroundPosition: "100% 50%",
243
- },
244
- to: {
245
- backgroundPosition: "0 50%",
246
- },
247
- },
248
- } satisfies Record<string, Record<string, CSSProps>>;