@runtypelabs/persona 4.32.2 → 4.34.0
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.
- package/dist/activity-ui.d.cts +3 -15
- package/dist/activity-ui.d.ts +3 -15
- package/dist/animations/glyph-cycle.d.cts +1 -3
- package/dist/animations/glyph-cycle.d.ts +1 -3
- package/dist/animations/wipe.d.cts +1 -3
- package/dist/animations/wipe.d.ts +1 -3
- package/dist/approval-ui.cjs +2 -2
- package/dist/approval-ui.d.cts +3 -15
- package/dist/approval-ui.d.ts +3 -15
- package/dist/approval-ui.js +1 -1
- package/dist/artifacts-ui.cjs +1 -1
- package/dist/artifacts-ui.d.cts +3 -21
- package/dist/artifacts-ui.d.ts +3 -21
- package/dist/background-runtime.d.cts +2 -3
- package/dist/background-runtime.d.ts +2 -3
- package/dist/{chunk-BbXc58OA.js → chunk-6CUrH_jm.js} +1 -1
- package/dist/{chunk-B_H0l3u2.js → chunk-BRM3bHcJ.js} +1 -1
- package/dist/{chunk-DNdeIFJ6.js → chunk-Brdx4NCz.js} +1 -1
- package/dist/chunk-C-rux8Q9.js +1 -0
- package/dist/{chunk-Ds_twaZn.js → chunk-C4v-HNhS.js} +1 -1
- package/dist/{chunk-Bkma5hIU.js → chunk-CE4seJxF.js} +1 -1
- package/dist/chunk-CEPM3FOp.js +1 -0
- package/dist/{chunk-BpjtKnGI.js → chunk-CV8EPIhT.js} +1 -1
- package/dist/{chunk-DVZ8ri1z.js → chunk-CWzHNuVK.js} +1 -1
- package/dist/{chunk-B3l7TOOv.js → chunk-CYpt7PsO.js} +1 -1
- package/dist/{chunk-2FnmZ9AA.js → chunk-Csr59G5V.js} +1 -1
- package/dist/{chunk-B9Zu-wrk.js → chunk-CxNPSY-b.js} +1 -1
- package/dist/{chunk-UWMfWW2a.js → chunk-D1G8tgYc.js} +1 -1
- package/dist/{chunk-DTGvDx8o.js → chunk-Dj2a9f9w.js} +1 -1
- package/dist/chunk-Dqa_GOcj.js +1 -0
- package/dist/chunk-DsWv3EGF.js +1 -0
- package/dist/{chunk-C7-m0EmI.js → chunk-NUNdcnAZ.js} +1 -1
- package/dist/{chunk-D0tcIZJM.js → chunk-YMkMvAsa.js} +2 -2
- package/dist/{chunk-C-EHtpbB.js → chunk-h5aOI_Pa.js} +1 -1
- package/dist/chunk-i4qGOJAL.js +1 -0
- package/dist/chunk-kizhspe5.js +1 -0
- package/dist/client-dispatch.js +1 -1
- package/dist/client-history.js +1 -1
- package/dist/client-stream.js +1 -1
- package/dist/{code-generators-DqauYyfX.d.cts → code-generators-DPAqTcAz.d.cts} +0 -2
- package/dist/{code-generators-DqauYyfX.d.ts → code-generators-DPAqTcAz.d.ts} +0 -2
- package/dist/codegen.cjs +1 -1
- package/dist/codegen.d.cts +1 -1
- package/dist/codegen.d.ts +1 -1
- package/dist/codegen.js +1 -1
- package/dist/composer-actions-runtime.cjs +1 -1
- package/dist/composer-actions-runtime.d.cts +4 -20
- package/dist/composer-actions-runtime.d.ts +4 -20
- package/dist/composer-actions-runtime.js +1 -1
- package/dist/{composer-input-dwg_o9Z-.d.ts → composer-input-i_FiUp6J.d.cts} +1 -7
- package/dist/{composer-input-dwg_o9Z-.d.cts → composer-input-i_FiUp6J.d.ts} +1 -7
- package/dist/{composer-store-Dw7Zbqxr.d.ts → composer-store-DhGNgG7Z.d.cts} +1 -3
- package/dist/{composer-store-Dw7Zbqxr.d.cts → composer-store-DhGNgG7Z.d.ts} +1 -3
- package/dist/config-diagnostics.d.cts +0 -2
- package/dist/config-diagnostics.d.ts +0 -2
- package/dist/{context-mention-manager-D2p0-JH-.d.ts → context-mention-manager-DL-xwGfL.d.cts} +2 -6
- package/dist/{context-mention-manager-D2p0-JH-.d.cts → context-mention-manager-DL-xwGfL.d.ts} +2 -6
- package/dist/context-mentions-inline.cjs +1 -1
- package/dist/context-mentions-inline.d.cts +2 -4
- package/dist/context-mentions-inline.d.ts +2 -4
- package/dist/context-mentions-inline.js +1 -1
- package/dist/context-mentions.cjs +1 -1
- package/dist/context-mentions.d.cts +3 -9
- package/dist/context-mentions.d.ts +3 -9
- package/dist/{defaults-CjX0kKzb.d.ts → defaults-Bga2Xrsp.d.cts} +2 -5
- package/dist/{defaults-CjX0kKzb.d.cts → defaults-Bga2Xrsp.d.ts} +2 -5
- package/dist/dictation-runtime.cjs +1 -1
- package/dist/dictation-runtime.d.cts +4 -13
- package/dist/dictation-runtime.d.ts +4 -13
- package/dist/dictation-runtime.js +1 -1
- package/dist/{dom-context-DHTabIn7.d.ts → dom-context-Bw-_9Evh.d.cts} +0 -2
- package/dist/{dom-context-DHTabIn7.d.cts → dom-context-Bw-_9Evh.d.ts} +0 -2
- package/dist/event-stream-view.cjs +1 -1
- package/dist/event-stream-view.d.cts +3 -16
- package/dist/event-stream-view.d.ts +3 -16
- package/dist/{fallback-speech-engine-DmF7MczI.d.ts → fallback-speech-engine-kLdyPcmk.d.cts} +1 -3
- package/dist/{fallback-speech-engine-DmF7MczI.d.cts → fallback-speech-engine-kLdyPcmk.d.ts} +1 -3
- package/dist/{feature-preferences-CVFDt9Xf.d.ts → feature-preferences-CmwZGKrf.d.cts} +1 -5
- package/dist/{feature-preferences-CVFDt9Xf.d.cts → feature-preferences-CmwZGKrf.d.ts} +1 -5
- package/dist/forms-ui.d.cts +2 -4
- package/dist/forms-ui.d.ts +2 -4
- package/dist/{history-confirm-dialog-DJEXsTyE.d.cts → history-confirm-dialog-i46-lPN_.d.cts} +2 -14
- package/dist/{history-confirm-dialog-DJEXsTyE.d.ts → history-confirm-dialog-i46-lPN_.d.ts} +2 -14
- package/dist/history-shell.cjs +1 -1
- package/dist/history-shell.d.cts +8 -27
- package/dist/history-shell.d.ts +8 -27
- package/dist/history-shell.js +1 -1
- package/dist/history-view.d.cts +1 -1
- package/dist/history-view.d.ts +1 -1
- package/dist/icons-extra.cjs +1 -1
- package/dist/icons-extra.d.cts +0 -2
- package/dist/icons-extra.d.ts +0 -2
- package/dist/index.cjs +44 -44
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -11
- package/dist/index.d.ts +11 -11
- package/dist/index.global.js +1 -1
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +46 -46
- package/dist/index.js.map +1 -1
- package/dist/install.global.js +1 -1
- package/dist/install.global.js.map +1 -1
- package/dist/launcher.global.js +2 -2
- package/dist/launcher.global.js.map +1 -1
- package/dist/{loading-label-runtime-loader-CPxnoaoi.d.ts → loading-label-runtime-loader-Ccr3ETd3.d.cts} +1 -3
- package/dist/{loading-label-runtime-loader-CPxnoaoi.d.cts → loading-label-runtime-loader-Ccr3ETd3.d.ts} +1 -3
- package/dist/loading-label-runtime.cjs +1 -1
- package/dist/loading-label-runtime.d.cts +1 -1
- package/dist/loading-label-runtime.d.ts +1 -1
- package/dist/loading-label-runtime.js +1 -1
- package/dist/markdown-parsers.js +1 -1
- package/dist/{message-bubble-CkZGlCLC.d.ts → message-bubble-C6AVaH7f.d.cts} +21 -4
- package/dist/{message-bubble-CkZGlCLC.d.cts → message-bubble-C6AVaH7f.d.ts} +21 -4
- package/dist/{plugin-kit-C1mRjLgW.d.cts → plugin-kit-BVggqE3C.d.cts} +0 -2
- package/dist/{plugin-kit-C1mRjLgW.d.ts → plugin-kit-BVggqE3C.d.ts} +0 -2
- package/dist/plugin-kit.d.cts +1 -1
- package/dist/plugin-kit.d.ts +1 -1
- package/dist/preferences-runtime.cjs +1 -1
- package/dist/preferences-runtime.d.cts +1 -1
- package/dist/preferences-runtime.d.ts +1 -1
- package/dist/preferences-runtime.js +1 -1
- package/dist/{preview-DdUvoLb4.d.cts → preview-BMdRffo4.d.cts} +2 -6
- package/dist/{preview-DdUvoLb4.d.ts → preview-BMdRffo4.d.ts} +2 -6
- package/dist/{registry-Dz4iHNST.d.ts → registry-B16l8s1b.d.cts} +1 -8
- package/dist/{registry-Dz4iHNST.d.cts → registry-B16l8s1b.d.ts} +1 -8
- package/dist/{session-Baxp9iRK.d.cts → session-CtZHe7fc.d.cts} +10 -93
- package/dist/{session-Baxp9iRK.d.ts → session-CtZHe7fc.d.ts} +10 -93
- package/dist/session-reconnect.d.cts +2 -4
- package/dist/session-reconnect.d.ts +2 -4
- package/dist/smart-dom-reader.d.cts +2 -8
- package/dist/smart-dom-reader.d.ts +2 -8
- package/dist/testing.d.cts +0 -2
- package/dist/testing.d.ts +0 -2
- package/dist/theme-editor-preview.cjs +42 -42
- package/dist/theme-editor-preview.d.cts +1 -1
- package/dist/theme-editor-preview.d.ts +1 -1
- package/dist/theme-editor-preview.js +25 -25
- package/dist/theme-editor.cjs +25 -5
- package/dist/theme-editor.d.cts +2 -22
- package/dist/theme-editor.d.ts +2 -22
- package/dist/theme-editor.js +1 -1
- package/dist/theme-reference.cjs +1 -1
- package/dist/theme-reference.d.cts +4 -4
- package/dist/theme-reference.d.ts +4 -4
- package/dist/theme-reference.js +1 -1
- package/dist/{tool-loading-animation-un3kA5Ur.d.ts → tool-loading-animation-D2cyFvmM.d.cts} +1 -7
- package/dist/{tool-loading-animation-un3kA5Ur.d.cts → tool-loading-animation-D2cyFvmM.d.ts} +1 -7
- package/dist/{tooltip-BkW-8MnD.d.cts → tooltip-DbXkAuJL.d.cts} +0 -2
- package/dist/{tooltip-BkW-8MnD.d.ts → tooltip-DbXkAuJL.d.ts} +0 -2
- package/dist/{turn-activity-ui-BGNhtMcH.d.cts → turn-activity-ui-Do1Nd-Ow.d.cts} +2 -12
- package/dist/{turn-activity-ui-BGNhtMcH.d.ts → turn-activity-ui-Do1Nd-Ow.d.ts} +2 -12
- package/dist/turn-activity-ui.d.cts +1 -1
- package/dist/turn-activity-ui.d.ts +1 -1
- package/dist/{types-BOZHQIk0.d.cts → types-BC7MRxO5.d.cts} +167 -36
- package/dist/{types-BOZHQIk0.d.ts → types-BC7MRxO5.d.ts} +167 -36
- package/dist/ui-extras.js +3 -3
- package/dist/voice-client-tools.d.cts +1 -3
- package/dist/voice-client-tools.d.ts +1 -3
- package/dist/voice-runtime.cjs +1 -1
- package/dist/voice-runtime.d.cts +2 -12
- package/dist/voice-runtime.d.ts +2 -12
- package/dist/voice-runtime.js +2 -2
- package/dist/voice-worklet-player.d.cts +2 -6
- package/dist/voice-worklet-player.d.ts +2 -6
- package/dist/{webmcp-runtime-entry-DuAG1_yF.d.ts → webmcp-runtime-entry-B8g46vS0.d.cts} +1 -5
- package/dist/{webmcp-runtime-entry-DuAG1_yF.d.cts → webmcp-runtime-entry-B8g46vS0.d.ts} +1 -5
- package/dist/webmcp-runtime.d.cts +1 -1
- package/dist/webmcp-runtime.d.ts +1 -1
- package/dist/widget.css +1 -1
- package/package.json +4 -4
- package/src/client-dispatch.ts +69 -16
- package/src/client.operator-role.test.ts +217 -0
- package/src/components/event-stream-view.test.ts +5 -0
- package/src/components/message-bubble.test.ts +169 -0
- package/src/components/message-bubble.ts +123 -34
- package/src/components/scroll-to-bottom.test.ts +135 -0
- package/src/components/scroll-to-bottom.ts +50 -13
- package/src/components/user-message-collapse.ts +117 -0
- package/src/defaults-parity.test.ts +14 -0
- package/src/defaults.ts +6 -0
- package/src/index-core.ts +7 -0
- package/src/session.resubmit-from.test.ts +27 -0
- package/src/session.test.ts +10 -0
- package/src/session.ts +8 -5
- package/src/styles/widget.css +79 -1
- package/src/theme-reference.ts +5 -3
- package/src/types/theme.ts +50 -0
- package/src/types.ts +120 -11
- package/src/ui.ask-user-question-plugin.test.ts +154 -0
- package/src/ui.operator-role.test.ts +336 -0
- package/src/ui.scroll-additive.test.ts +219 -117
- package/src/ui.scroll.test.ts +176 -13
- package/src/ui.ts +267 -119
- package/src/ui.turn-activity.test.ts +7 -7
- package/src/ui.user-message-collapse.test.ts +540 -0
- package/src/utils/__snapshots__/tokens-parity.test.ts.snap +236 -0
- package/src/utils/auto-follow.test.ts +0 -38
- package/src/utils/auto-follow.ts +0 -35
- package/src/utils/brand.test.ts +14 -0
- package/src/utils/brand.ts +8 -4
- package/src/utils/history-messages.test.ts +30 -0
- package/src/utils/history-messages.ts +26 -8
- package/src/utils/message-fingerprint.ts +4 -0
- package/src/utils/resubmit-turn.test.ts +13 -0
- package/src/utils/resubmit-turn.ts +12 -1
- package/src/utils/theme.test.ts +23 -0
- package/src/utils/tokens.ts +47 -0
- package/src/welcome.test.ts +16 -0
- package/src/welcome.ts +10 -2
- package/dist/chunk-BNE40cEG.js +0 -1
- package/dist/chunk-Bz9jAgba.js +0 -1
- package/dist/chunk-CVMIncEY.js +0 -1
- package/dist/chunk-CdpVP6LZ.js +0 -1
- package/dist/chunk-CjkechxR.js +0 -1
- package/dist/chunk-DgZZqy14.js +0 -1
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import type { AgentWidgetConfig } from "../types";
|
|
2
|
+
import { createNode } from "../utils/dom";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Long user message collapse ("Show more" / "Show less").
|
|
6
|
+
*
|
|
7
|
+
* The default user bubble wraps its content (attachments, mention chips and
|
|
8
|
+
* text) in a clip region. ui.ts measures the region's real rendered height
|
|
9
|
+
* after each morph and decides whether it overflows; the bubble is then
|
|
10
|
+
* re-rendered from that state, so morphs and cached wrappers always agree
|
|
11
|
+
* with the live DOM. The full text stays in the DOM in every state (no nested
|
|
12
|
+
* scroller), so find-in-page, selection, copy and screen readers still reach it.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Default collapsed height. A bubble line is ~22–24px (0.875rem at
|
|
17
|
+
* leading-relaxed/1.75), so 240px shows about ten lines: enough to recognise
|
|
18
|
+
* the message, while leaving most of a ~640px panel for the reply that
|
|
19
|
+
* anchor-top streams in beneath it.
|
|
20
|
+
*/
|
|
21
|
+
export const DEFAULT_USER_MESSAGE_COLLAPSE_MAX_HEIGHT = 240;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Content within this many px (about two lines) of the limit stays expanded,
|
|
25
|
+
* so the toggle never hides just a line or two behind a button of its own size.
|
|
26
|
+
*/
|
|
27
|
+
export const USER_MESSAGE_COLLAPSE_SLACK = 48;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* - `fit`: not measured yet, or short enough; no toggle.
|
|
31
|
+
* - `live`: an interim voice transcript; expanded so the speaker can watch it.
|
|
32
|
+
* - `settling`: the transcript's first final render, still expanded; the
|
|
33
|
+
* post-morph measurement settles it in the same pass, holding the viewport.
|
|
34
|
+
* - `collapsed` / `expanded`: overflowing, with the toggle.
|
|
35
|
+
*/
|
|
36
|
+
export type UserMessageCollapseState = "fit" | "live" | "settling" | "collapsed" | "expanded";
|
|
37
|
+
|
|
38
|
+
export type UserMessageCollapseRender = {
|
|
39
|
+
state: UserMessageCollapseState;
|
|
40
|
+
maxHeight: number;
|
|
41
|
+
showMoreLabel: string;
|
|
42
|
+
showLessLabel: string;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export const USER_COLLAPSE_REGION_ATTR = "data-persona-user-collapse";
|
|
46
|
+
export const USER_COLLAPSE_TOGGLE_ATTR = "data-persona-user-collapse-toggle";
|
|
47
|
+
|
|
48
|
+
export const isUserMessageCollapseEnabled = (config: AgentWidgetConfig): boolean =>
|
|
49
|
+
config.features?.userMessageCollapse?.enabled === true;
|
|
50
|
+
|
|
51
|
+
export const resolveUserMessageCollapseMaxHeight = (config: AgentWidgetConfig): number => {
|
|
52
|
+
const value = config.features?.userMessageCollapse?.maxHeight;
|
|
53
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0
|
|
54
|
+
? value
|
|
55
|
+
: DEFAULT_USER_MESSAGE_COLLAPSE_MAX_HEIGHT;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export const resolveUserMessageCollapseLabels = (
|
|
59
|
+
config: AgentWidgetConfig
|
|
60
|
+
): Pick<UserMessageCollapseRender, "showMoreLabel" | "showLessLabel"> => ({
|
|
61
|
+
showMoreLabel: config.copy?.showMoreLabel?.trim() || "Show more",
|
|
62
|
+
showLessLabel: config.copy?.showLessLabel?.trim() || "Show less",
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
/** Whether a measured natural content height warrants collapsing. */
|
|
66
|
+
export const userMessageOverflows = (naturalHeight: number, maxHeight: number): boolean =>
|
|
67
|
+
naturalHeight > maxHeight + USER_MESSAGE_COLLAPSE_SLACK;
|
|
68
|
+
|
|
69
|
+
const regionId = (messageId: string) => `persona-user-collapse-${messageId}`;
|
|
70
|
+
|
|
71
|
+
export const createUserCollapseRegion = (
|
|
72
|
+
messageId: string,
|
|
73
|
+
maxHeight: number
|
|
74
|
+
): HTMLElement => {
|
|
75
|
+
const region = createNode("div", {
|
|
76
|
+
className: "persona-user-collapse-region",
|
|
77
|
+
attrs: { id: regionId(messageId), [USER_COLLAPSE_REGION_ATTR]: "fit" },
|
|
78
|
+
});
|
|
79
|
+
region.style.setProperty("--persona-user-collapse-max-height", `${maxHeight}px`);
|
|
80
|
+
return region;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Apply a state to a region and its sibling toggle. Used both while building a
|
|
85
|
+
* fresh bubble and to patch the live bubble in place on a toggle or a new
|
|
86
|
+
* measurement, so the toggle keeps its identity (and focus) across states.
|
|
87
|
+
*/
|
|
88
|
+
export const applyUserCollapseState = (
|
|
89
|
+
bubble: HTMLElement,
|
|
90
|
+
region: HTMLElement,
|
|
91
|
+
messageId: string,
|
|
92
|
+
render: UserMessageCollapseRender
|
|
93
|
+
): void => {
|
|
94
|
+
const { state } = render;
|
|
95
|
+
region.setAttribute(USER_COLLAPSE_REGION_ATTR, state);
|
|
96
|
+
region.style.setProperty("--persona-user-collapse-max-height", `${render.maxHeight}px`);
|
|
97
|
+
let toggle = bubble.querySelector<HTMLButtonElement>(`button[${USER_COLLAPSE_TOGGLE_ATTR}]`);
|
|
98
|
+
if (state !== "collapsed" && state !== "expanded") {
|
|
99
|
+
toggle?.remove();
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (!toggle) {
|
|
103
|
+
toggle = createNode("button", {
|
|
104
|
+
className: "persona-user-collapse-toggle",
|
|
105
|
+
attrs: {
|
|
106
|
+
type: "button",
|
|
107
|
+
id: `persona-user-collapse-toggle-${messageId}`,
|
|
108
|
+
[USER_COLLAPSE_TOGGLE_ATTR]: "",
|
|
109
|
+
"aria-controls": regionId(messageId),
|
|
110
|
+
},
|
|
111
|
+
}) as HTMLButtonElement;
|
|
112
|
+
region.after(toggle);
|
|
113
|
+
}
|
|
114
|
+
const expanded = state === "expanded";
|
|
115
|
+
toggle.setAttribute("aria-expanded", expanded ? "true" : "false");
|
|
116
|
+
toggle.textContent = expanded ? render.showLessLabel : render.showMoreLabel;
|
|
117
|
+
};
|
|
@@ -160,6 +160,20 @@ describe("4.22.0 defaults parity (flag off)", () => {
|
|
|
160
160
|
expect(actual.themeCssVariables[key], key).toBe(value);
|
|
161
161
|
delete resolvedActual.themeCssVariables[key];
|
|
162
162
|
}
|
|
163
|
+
// Operator bubbles only render for messages that use the operator role,
|
|
164
|
+
// so every token they emit is additive and none may exist in the baseline.
|
|
165
|
+
const additivePrefixes = [
|
|
166
|
+
"--persona-components-message-operator-",
|
|
167
|
+
"--persona-message-operator-",
|
|
168
|
+
];
|
|
169
|
+
expect(actual.themeCssVariables["--persona-components-message-operator-background"]).toBe(
|
|
170
|
+
"color-mix(in srgb, var(--persona-primary) 6%, var(--persona-container))"
|
|
171
|
+
);
|
|
172
|
+
for (const key of Object.keys(resolvedActual.themeCssVariables)) {
|
|
173
|
+
if (!additivePrefixes.some((prefix) => key.startsWith(prefix))) continue;
|
|
174
|
+
expect(baseline.themeCssVariables).not.toHaveProperty(key);
|
|
175
|
+
delete resolvedActual.themeCssVariables[key];
|
|
176
|
+
}
|
|
163
177
|
// Deliberately lengthen hover timing in both V4 and V5 without rewriting
|
|
164
178
|
// the historical fixture. Keyboard focus and the scan window are unchanged.
|
|
165
179
|
expect(baseline.mergedDefaultConfig.tooltip.delayMs).toBe(200);
|
package/src/defaults.ts
CHANGED
|
@@ -266,6 +266,9 @@ export const DEFAULTS_V5: Partial<AgentWidgetConfig> = {
|
|
|
266
266
|
features: {
|
|
267
267
|
artifacts: { enabled: true },
|
|
268
268
|
scrollToBottom: { streamingIndicator: "dots", transition: "fade", scrollBehavior: "smooth" },
|
|
269
|
+
// Long sent messages (pasted text, voice transcripts) would otherwise fill
|
|
270
|
+
// the viewport under the anchor-top pin and push the reply out of view.
|
|
271
|
+
userMessageCollapse: { enabled: true },
|
|
269
272
|
toolCallDisplay: DEFAULT_TOOL_CALL_DISPLAY_V5,
|
|
270
273
|
reasoningDisplay: DEFAULT_REASONING_DISPLAY_V5,
|
|
271
274
|
},
|
|
@@ -382,6 +385,8 @@ export function mergeWithDefaults(
|
|
|
382
385
|
const csa = config.features?.streamAnimation;
|
|
383
386
|
const dau = defaults.features?.askUserQuestion;
|
|
384
387
|
const cau = config.features?.askUserQuestion;
|
|
388
|
+
const duc = defaults.features?.userMessageCollapse;
|
|
389
|
+
const cuc = config.features?.userMessageCollapse;
|
|
385
390
|
const dh = defaults.features?.history;
|
|
386
391
|
const ch = config.features?.history;
|
|
387
392
|
const mergedArtifacts =
|
|
@@ -459,6 +464,7 @@ export function mergeWithDefaults(
|
|
|
459
464
|
...(mergedStreamAnimation !== undefined ? { streamAnimation: mergedStreamAnimation } : {}),
|
|
460
465
|
...(mergedAskUserQuestion !== undefined ? { askUserQuestion: mergedAskUserQuestion } : {}),
|
|
461
466
|
...(mergedHistory !== undefined ? { history: mergedHistory } : {}),
|
|
467
|
+
...(duc !== undefined || cuc !== undefined ? { userMessageCollapse: { ...duc, ...cuc } } : {}),
|
|
462
468
|
};
|
|
463
469
|
})(),
|
|
464
470
|
suggestionChips: config.suggestionChips ?? defaults.suggestionChips,
|
package/src/index-core.ts
CHANGED
|
@@ -5,6 +5,9 @@ import {
|
|
|
5
5
|
} from "./runtime/init";
|
|
6
6
|
|
|
7
7
|
export type {
|
|
8
|
+
AgentWidgetMessageAuthor,
|
|
9
|
+
AgentWidgetModelMessageTransform,
|
|
10
|
+
AgentWidgetModelMessageProjection,
|
|
8
11
|
AgentWidgetDictationConfig,
|
|
9
12
|
DictationProviderConfig,
|
|
10
13
|
DictationPhase,
|
|
@@ -46,6 +49,8 @@ export type {
|
|
|
46
49
|
ArtifactConfigPayload,
|
|
47
50
|
AgentWidgetInitOptions,
|
|
48
51
|
AgentWidgetMessage,
|
|
52
|
+
AgentWidgetMessageRole,
|
|
53
|
+
AgentWidgetModelMessageRole,
|
|
49
54
|
AgentWidgetTurnActivity,
|
|
50
55
|
AgentWidgetTurnActivityConfig,
|
|
51
56
|
AgentWidgetLauncherConfig,
|
|
@@ -594,6 +599,8 @@ export type {
|
|
|
594
599
|
SemanticSpacing,
|
|
595
600
|
SemanticTypography,
|
|
596
601
|
ComponentTokens,
|
|
602
|
+
MessageTokens,
|
|
603
|
+
MessageGeometryTokens,
|
|
597
604
|
ComposerOverflowMenuTokens,
|
|
598
605
|
TextStyleTokens,
|
|
599
606
|
AttachmentTokens,
|
|
@@ -327,3 +327,30 @@ describe("resubmitFrom retry payload fidelity per transport", () => {
|
|
|
327
327
|
expect(bodies[0].submitMode).toBeUndefined();
|
|
328
328
|
});
|
|
329
329
|
});
|
|
330
|
+
|
|
331
|
+
describe("human operator resubmission boundary", () => {
|
|
332
|
+
beforeEach(() => {
|
|
333
|
+
vi.restoreAllMocks();
|
|
334
|
+
global.fetch = vi.fn(async () => streamResponse()) as unknown as typeof fetch;
|
|
335
|
+
});
|
|
336
|
+
it.each(["retry", "edit"] as const)("refuses %s before a human contribution without cancelling or truncating", reason => {
|
|
337
|
+
const { session, emits } = makeSession();
|
|
338
|
+
seedTurn(session);
|
|
339
|
+
session.injectMessage({ id: "human", role: "operator", content: "Refund confirmed", author: { id: "sam", displayName: "Sam", kind: "human" } });
|
|
340
|
+
const snapshot = session.getMessages();
|
|
341
|
+
const cancel = vi.spyOn(session, "cancel");
|
|
342
|
+
emits.length = 0;
|
|
343
|
+
expect(session.resubmitFrom("u1", { reason, ...(reason === "edit" && { replacement: { text: "Changed", mentionRefs: [], options: {} } }) })).toBe(false);
|
|
344
|
+
expect(session.getMessages()).toEqual(snapshot);
|
|
345
|
+
expect(cancel).not.toHaveBeenCalled();
|
|
346
|
+
expect(emits).toHaveLength(0);
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
it("allows a fresh user turn after the human contribution", () => {
|
|
350
|
+
const { session } = makeSession();
|
|
351
|
+
session.injectMessage({ id: "human", role: "operator", content: "Refund confirmed" });
|
|
352
|
+
session.injectUserMessage({ id: "after", content: "When will it arrive?" });
|
|
353
|
+
expect(session.resubmitFrom("after", { reason: "retry" })).toBe(true);
|
|
354
|
+
expect(session.getMessages().some(message => message.id === "human")).toBe(true);
|
|
355
|
+
});
|
|
356
|
+
});
|
package/src/session.test.ts
CHANGED
|
@@ -182,6 +182,16 @@ describe('AgentWidgetSession - Message Injection', () => {
|
|
|
182
182
|
});
|
|
183
183
|
});
|
|
184
184
|
|
|
185
|
+
describe('operator role', () => {
|
|
186
|
+
it('injects an operator message with its own id prefix', () => {
|
|
187
|
+
const result = session.injectMessage({ role: 'operator', content: 'Sam from support here.' });
|
|
188
|
+
|
|
189
|
+
expect(result.role).toBe('operator');
|
|
190
|
+
expect(result.id).toMatch(/^operator-/);
|
|
191
|
+
expect(messages.map((message) => message.role)).toEqual(['operator']);
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
|
|
185
195
|
describe('message ordering', () => {
|
|
186
196
|
it('should maintain chronological order', () => {
|
|
187
197
|
session.injectMessage({
|
package/src/session.ts
CHANGED
|
@@ -68,7 +68,7 @@ import type {
|
|
|
68
68
|
ComposerResubmitOptions
|
|
69
69
|
} from "./types";
|
|
70
70
|
import { applyQuoteToContent } from "./utils/composer-quote";
|
|
71
|
-
import { findUserTurnBoundary } from "./utils/resubmit-turn";
|
|
71
|
+
import { canResubmitUserMessage, findUserTurnBoundary } from "./utils/resubmit-turn";
|
|
72
72
|
import { extractComponentDirectiveFromMessage } from "./utils/component-middleware";
|
|
73
73
|
import type { MentionSubmitBundle } from "./utils/context-mention-manager";
|
|
74
74
|
import type { VisitorStore, VisitorStoreChange } from "./utils/visitor-store";
|
|
@@ -156,6 +156,7 @@ const CONNECTION_CONFIG_KEYS = [
|
|
|
156
156
|
"parserType",
|
|
157
157
|
"contextProviders",
|
|
158
158
|
"requestMiddleware",
|
|
159
|
+
"modelMessageTransform",
|
|
159
160
|
"customFetch",
|
|
160
161
|
"backgroundConversations",
|
|
161
162
|
"parseSSEEvent",
|
|
@@ -2500,7 +2501,7 @@ export class AgentWidgetSession {
|
|
|
2500
2501
|
? generateUserMessageId()
|
|
2501
2502
|
: role === "assistant"
|
|
2502
2503
|
? generateAssistantMessageId()
|
|
2503
|
-
:
|
|
2504
|
+
: `${role === "operator" ? "operator" : "system"}-${Date.now()}-${Math.random().toString(16).slice(2)}`);
|
|
2504
2505
|
|
|
2505
2506
|
return {
|
|
2506
2507
|
id: messageId,
|
|
@@ -2515,7 +2516,8 @@ export class AgentWidgetSession {
|
|
|
2515
2516
|
...(voiceProcessing !== undefined && { voiceProcessing }),
|
|
2516
2517
|
...(voiceCaption && { voiceCaption }),
|
|
2517
2518
|
...(rawContent !== undefined && { rawContent }),
|
|
2518
|
-
...(options.dispatchError !== undefined && { dispatchError: options.dispatchError })
|
|
2519
|
+
...(options.dispatchError !== undefined && { dispatchError: options.dispatchError }),
|
|
2520
|
+
...(options.author !== undefined && { author: { ...options.author } })
|
|
2519
2521
|
};
|
|
2520
2522
|
|
|
2521
2523
|
}
|
|
@@ -3015,14 +3017,15 @@ export class AgentWidgetSession {
|
|
|
3015
3017
|
* the new attempt gets fresh message ids.
|
|
3016
3018
|
*
|
|
3017
3019
|
* Returns false when the id is unknown, is not a user message, or the rebuilt
|
|
3018
|
-
* turn would carry no content
|
|
3020
|
+
* turn would carry no content, or truncation would remove an operator reply;
|
|
3021
|
+
* nothing is truncated in those cases.
|
|
3019
3022
|
*/
|
|
3020
3023
|
public resubmitFrom(
|
|
3021
3024
|
messageId: string,
|
|
3022
3025
|
options: ComposerResubmitOptions
|
|
3023
3026
|
): boolean {
|
|
3024
3027
|
const boundary = findUserTurnBoundary(this.messages, messageId);
|
|
3025
|
-
if (!boundary) return false;
|
|
3028
|
+
if (!boundary || !canResubmitUserMessage(this.messages, messageId)) return false;
|
|
3026
3029
|
|
|
3027
3030
|
// Operate on the STORED message, never a caller-held object: appendMessage
|
|
3028
3031
|
// keeps a copy (see `ensureSequence`), so the array entry is the only ref
|
package/src/styles/widget.css
CHANGED
|
@@ -2171,6 +2171,13 @@
|
|
|
2171
2171
|
);
|
|
2172
2172
|
}
|
|
2173
2173
|
|
|
2174
|
+
.persona-message-row[data-message-role="operator"] > * {
|
|
2175
|
+
max-width: var(
|
|
2176
|
+
--persona-message-row-max-width,
|
|
2177
|
+
var(--persona-message-operator-max-width, var(--persona-message-assistant-max-width, 85%))
|
|
2178
|
+
);
|
|
2179
|
+
}
|
|
2180
|
+
|
|
2174
2181
|
.persona-message-row[data-message-width="content"] > * {
|
|
2175
2182
|
flex: 0 1 auto;
|
|
2176
2183
|
}
|
|
@@ -3086,10 +3093,68 @@
|
|
|
3086
3093
|
box-shadow: var(--persona-message-assistant-shadow, 0 1px 2px 0 rgb(0 0 0 / 0.05));
|
|
3087
3094
|
}
|
|
3088
3095
|
|
|
3096
|
+
/* Operator bubble: a human on the agent's side (role "operator"). Renders on
|
|
3097
|
+
the assistant's side; V4 tints the container with the primary, V5 outlines it. */
|
|
3098
|
+
.persona-message-operator-bubble {
|
|
3099
|
+
border-radius: var(--persona-components-message-operator-borderRadius, var(--persona-radius-lg, 0.5rem));
|
|
3100
|
+
border-color: var(--persona-components-message-operator-border, var(--persona-border, #e5e7eb));
|
|
3101
|
+
border-width: var(--persona-components-message-operator-borderWidth, 1px);
|
|
3102
|
+
}
|
|
3103
|
+
|
|
3104
|
+
[data-persona-root] .persona-message-operator-bubble.persona-shadow-sm {
|
|
3105
|
+
box-shadow: var(--persona-components-message-operator-shadow, 0 1px 2px 0 rgb(0 0 0 / 0.05));
|
|
3106
|
+
}
|
|
3107
|
+
|
|
3089
3108
|
[data-persona-root] .persona-message-user-bubble.persona-shadow-sm {
|
|
3090
3109
|
box-shadow: var(--persona-message-user-shadow);
|
|
3091
3110
|
}
|
|
3092
3111
|
|
|
3112
|
+
/* Long user message collapse (features.userMessageCollapse). The region clips
|
|
3113
|
+
without becoming a scroller (overflow: clip), so the full text stays in the
|
|
3114
|
+
DOM for find, copy and screen readers with no nested scroll area. The fade
|
|
3115
|
+
is a mask rather than a gradient overlay, so it works on any bubble fill in
|
|
3116
|
+
light and dark schemes; the toggle inherits the bubble's text color. */
|
|
3117
|
+
.persona-user-collapse-region[data-persona-user-collapse="collapsed"] {
|
|
3118
|
+
max-height: var(--persona-user-collapse-max-height, 240px);
|
|
3119
|
+
overflow: clip;
|
|
3120
|
+
-webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - var(--persona-user-collapse-fade-height, 48px)), transparent);
|
|
3121
|
+
mask-image: linear-gradient(to bottom, #000 calc(100% - var(--persona-user-collapse-fade-height, 48px)), transparent);
|
|
3122
|
+
}
|
|
3123
|
+
|
|
3124
|
+
.persona-user-collapse-toggle {
|
|
3125
|
+
display: inline-flex;
|
|
3126
|
+
align-items: center;
|
|
3127
|
+
margin-top: 0.25rem;
|
|
3128
|
+
padding: 0.125rem 0;
|
|
3129
|
+
border: 0;
|
|
3130
|
+
background: none;
|
|
3131
|
+
color: var(--persona-user-collapse-toggle-fg, inherit);
|
|
3132
|
+
font-family: inherit;
|
|
3133
|
+
font-size: var(--persona-user-collapse-toggle-font-size, 0.8125rem);
|
|
3134
|
+
font-weight: var(--persona-user-collapse-toggle-font-weight, 600);
|
|
3135
|
+
line-height: 1.25rem;
|
|
3136
|
+
cursor: pointer;
|
|
3137
|
+
text-decoration: underline;
|
|
3138
|
+
text-decoration-color: transparent;
|
|
3139
|
+
text-underline-offset: 2px;
|
|
3140
|
+
transition: text-decoration-color 150ms ease;
|
|
3141
|
+
}
|
|
3142
|
+
|
|
3143
|
+
.persona-user-collapse-toggle:hover {
|
|
3144
|
+
text-decoration-color: currentColor;
|
|
3145
|
+
}
|
|
3146
|
+
|
|
3147
|
+
.persona-user-collapse-toggle:focus-visible {
|
|
3148
|
+
outline: 2px solid currentColor;
|
|
3149
|
+
outline-offset: 2px;
|
|
3150
|
+
}
|
|
3151
|
+
|
|
3152
|
+
@media (prefers-reduced-motion: reduce) {
|
|
3153
|
+
.persona-user-collapse-toggle {
|
|
3154
|
+
transition: none;
|
|
3155
|
+
}
|
|
3156
|
+
}
|
|
3157
|
+
|
|
3093
3158
|
[data-persona-root] .persona-tool-bubble.persona-shadow-sm {
|
|
3094
3159
|
box-shadow: var(--persona-tool-bubble-shadow);
|
|
3095
3160
|
}
|
|
@@ -3244,7 +3309,8 @@
|
|
|
3244
3309
|
text-decoration: underline;
|
|
3245
3310
|
}
|
|
3246
3311
|
|
|
3247
|
-
[data-persona-root] .persona-message-assistant-bubble a
|
|
3312
|
+
[data-persona-root] .persona-message-assistant-bubble a,
|
|
3313
|
+
[data-persona-root] .persona-message-operator-bubble a {
|
|
3248
3314
|
color: var(--persona-md-link-color, var(--persona-accent, #0f0f0f));
|
|
3249
3315
|
}
|
|
3250
3316
|
|
|
@@ -3329,6 +3395,8 @@
|
|
|
3329
3395
|
|
|
3330
3396
|
.persona-message-assistant-bubble p,
|
|
3331
3397
|
.persona-message-assistant-bubble li,
|
|
3398
|
+
.persona-message-operator-bubble p,
|
|
3399
|
+
.persona-message-operator-bubble li,
|
|
3332
3400
|
.persona-error-detail p,
|
|
3333
3401
|
.persona-error-detail li {
|
|
3334
3402
|
color: inherit;
|
|
@@ -4847,6 +4915,16 @@
|
|
|
4847
4915
|
text-align: center;
|
|
4848
4916
|
}
|
|
4849
4917
|
|
|
4918
|
+
/* A pending approval below the fold: the control widens to a labelled pill.
|
|
4919
|
+
Unset approval tokens keep the pill's own colors. */
|
|
4920
|
+
[data-persona-root] .persona-scroll-to-bottom-indicator[data-persona-scroll-to-bottom-approval] {
|
|
4921
|
+
border-color: var(--persona-scroll-to-bottom-approval-border, var(--persona-scroll-to-bottom-border, var(--persona-primary, #111827)));
|
|
4922
|
+
background: var(--persona-scroll-to-bottom-approval-bg, var(--persona-scroll-to-bottom-bg, var(--persona-button-primary-bg, var(--persona-accent, #0f0f0f))));
|
|
4923
|
+
color: var(--persona-scroll-to-bottom-approval-fg, var(--persona-scroll-to-bottom-fg, var(--persona-button-primary-fg, var(--persona-text-inverse, #ffffff))));
|
|
4924
|
+
font-weight: var(--persona-scroll-to-bottom-approval-font-weight, 500);
|
|
4925
|
+
white-space: nowrap;
|
|
4926
|
+
}
|
|
4927
|
+
|
|
4850
4928
|
[data-persona-root] .persona-scroll-to-bottom-indicator:hover {
|
|
4851
4929
|
opacity: 0.92;
|
|
4852
4930
|
}
|
package/src/theme-reference.ts
CHANGED
|
@@ -144,6 +144,8 @@ export const THEME_TOKEN_DOCS = {
|
|
|
144
144
|
user: 'background, text, borderRadius, shadow.',
|
|
145
145
|
assistant:
|
|
146
146
|
'background, text, borderRadius, border (optional), shadow (optional).',
|
|
147
|
+
operator:
|
|
148
|
+
'Human operator bubble (role "operator", e.g. a support takeover), on the assistant side. background (default: container tinted 6% with the primary), text (semantic.colors.text), borderRadius, border (container tinted 20% with the primary), borderWidth (1px), shadow, plus padding, maxWidth, fontSize, fontFamily, lineHeight. V5 outlines it instead: transparent background, semantic.colors.border border.',
|
|
147
149
|
},
|
|
148
150
|
markdown: {
|
|
149
151
|
description: 'Markdown rendering in messages and artifact pane.',
|
|
@@ -169,7 +171,7 @@ export const THEME_TOKEN_DOCS = {
|
|
|
169
171
|
askUserQuestion: 'sheet (background, border, shadow), pill (background, foreground, borderRadius, selectedBackground, selectedForeground), customInput.background. Local features.askUserQuestion.styles still wins; navigation, labels and slide timing remain feature config.',
|
|
170
172
|
attachment: 'image (background, border).',
|
|
171
173
|
scrollToBottom:
|
|
172
|
-
'Floating scroll-to-bottom affordance shared by transcript and event stream: background, foreground, border, size, borderRadius, shadow, padding, gap, fontSize, iconSize.',
|
|
174
|
+
'Floating scroll-to-bottom affordance shared by transcript and event stream: background, foreground, border, size, borderRadius, shadow, padding, gap, fontSize, iconSize; approval (background, foreground, border, fontWeight) for the labelled "Approval needed" state, falling back to the control colors.',
|
|
173
175
|
toolBubble: 'shadow, background, borderColor, borderWidth, borderRadius; header (background, foreground, padding), content (background, foreground, padding), codeBlock (background, foreground, borderColor), toggleForeground, labelForeground, loading (primary, secondary, duration). Applies to card and activity-row variants without changing their distinct defaults. CSS duration uses ms/s; legacy numeric milliseconds must convert explicitly. Theme content.padding precedes activity.bodyPadding/toolBubble.bodyPadding fallbacks; explicit legacy axes override only their axis.',
|
|
174
176
|
scrollbar:
|
|
175
177
|
'Shared scrollbar appearance for every scroller: thumb (default semantic.colors.border), track (default transparent).',
|
|
@@ -248,7 +250,7 @@ export const THEME_TOKEN_DOCS = {
|
|
|
248
250
|
description:
|
|
249
251
|
'Shared transcript + event-stream jump-to-latest affordance.',
|
|
250
252
|
properties:
|
|
251
|
-
'features.scrollToBottom.enabled, features.scrollToBottom.iconName, features.scrollToBottom.label (empty string renders icon-only). Defaults: enabled=true, iconName="arrow-down", label="".',
|
|
253
|
+
'features.scrollToBottom.enabled, features.scrollToBottom.iconName, features.scrollToBottom.label (empty string renders icon-only), features.scrollToBottom.approvalLabel (shown while a pending approval is below the fold; empty string keeps the regular control). Defaults: enabled=true, iconName="arrow-down", label="", approvalLabel="Approval needed".',
|
|
252
254
|
},
|
|
253
255
|
toolCall: {
|
|
254
256
|
description:
|
|
@@ -325,7 +327,7 @@ export const THEME_TOKEN_DOCS = {
|
|
|
325
327
|
header:
|
|
326
328
|
'"default" | "minimal". Options: showIcon, showTitle, showSubtitle, showCloseButton, showClearChat.',
|
|
327
329
|
messages:
|
|
328
|
-
'"bubble" | "flat" | "minimal". Options: groupConsecutive, avatar (show, position, userAvatar, assistantAvatar), timestamp (show, position).',
|
|
330
|
+
'"bubble" | "flat" | "minimal". Options: groupConsecutive, avatar (show, position, userAvatar, assistantAvatar, operatorAvatar), timestamp (show, position, format).',
|
|
329
331
|
},
|
|
330
332
|
statusIndicator: {
|
|
331
333
|
description: 'Status text shown below the composer.',
|
package/src/types/theme.ts
CHANGED
|
@@ -530,6 +530,22 @@ export interface MessageActionsTokens {
|
|
|
530
530
|
borderRadius?: TokenReference<'radius'>;
|
|
531
531
|
}
|
|
532
532
|
|
|
533
|
+
/**
|
|
534
|
+
* Long user message collapse (`features.userMessageCollapse`). Every key is
|
|
535
|
+
* optional; unset, the fade and the toggle follow the user bubble's own text
|
|
536
|
+
* color and type, so they already work on any fill in light and dark schemes.
|
|
537
|
+
*/
|
|
538
|
+
export interface UserMessageCollapseTokens {
|
|
539
|
+
/** Height of the bottom fade on a collapsed bubble. @default "48px" */
|
|
540
|
+
fadeHeight?: string;
|
|
541
|
+
/** "Show more" / "Show less" text color. Defaults to the user bubble text color. */
|
|
542
|
+
toggleForeground?: TokenReference<'color'>;
|
|
543
|
+
/** Toggle label type size. @default "0.8125rem" */
|
|
544
|
+
toggleFontSize?: string;
|
|
545
|
+
/** Toggle label weight. @default "600" */
|
|
546
|
+
toggleFontWeight?: string;
|
|
547
|
+
}
|
|
548
|
+
|
|
533
549
|
/**
|
|
534
550
|
* Bubble geometry and type, per role. Every key is unset by default and each
|
|
535
551
|
* one falls back to the value the message layout preset already produced, so
|
|
@@ -580,6 +596,27 @@ export interface MessageTokens {
|
|
|
580
596
|
/** Assistant bubble box-shadow (token ref or raw CSS, e.g. `none`). */
|
|
581
597
|
shadow?: string;
|
|
582
598
|
};
|
|
599
|
+
/**
|
|
600
|
+
* Operator bubble: a human speaking on the agent's side (`role: "operator"`).
|
|
601
|
+
* Renders on the assistant's side. Defaults tint the container with the
|
|
602
|
+
* theme primary (`--persona-primary`), so `brand` themes follow without
|
|
603
|
+
* extra config. Geometry keys fall back to the layout preset, not to the
|
|
604
|
+
* assistant's geometry.
|
|
605
|
+
*/
|
|
606
|
+
operator?: MessageGeometryTokens & {
|
|
607
|
+
/** @default "color-mix(in srgb, var(--persona-primary) 6%, var(--persona-container))" */
|
|
608
|
+
background?: TokenReference<'color'>;
|
|
609
|
+
/** @default semantic.colors.text */
|
|
610
|
+
text?: TokenReference<'color'>;
|
|
611
|
+
/** @default palette.radius.lg */
|
|
612
|
+
borderRadius?: TokenReference<'radius'>;
|
|
613
|
+
/** @default "color-mix(in srgb, var(--persona-primary) 20%, var(--persona-container))" */
|
|
614
|
+
border?: TokenReference<'color'>;
|
|
615
|
+
/** Border width; set to 0px to drop it. @default "1px" */
|
|
616
|
+
borderWidth?: string;
|
|
617
|
+
/** Operator bubble box-shadow (token ref or raw CSS, e.g. `none`). */
|
|
618
|
+
shadow?: string;
|
|
619
|
+
};
|
|
583
620
|
/** Border color between messages in the thread. */
|
|
584
621
|
border?: TokenReference<'color'>;
|
|
585
622
|
}
|
|
@@ -1286,6 +1323,17 @@ export interface ScrollToBottomTokens extends ComponentTokenSet {
|
|
|
1286
1323
|
fontSize?: string;
|
|
1287
1324
|
fontWeight?: string;
|
|
1288
1325
|
};
|
|
1326
|
+
/**
|
|
1327
|
+
* The labelled "Approval needed" state shown while a pending approval is
|
|
1328
|
+
* below the fold. Omitted values follow the control's own colors, so it
|
|
1329
|
+
* matches the theme until you give it an accent.
|
|
1330
|
+
*/
|
|
1331
|
+
approval?: {
|
|
1332
|
+
background?: TokenReference<'color'>;
|
|
1333
|
+
foreground?: TokenReference<'color'>;
|
|
1334
|
+
border?: TokenReference<'color'>;
|
|
1335
|
+
fontWeight?: string;
|
|
1336
|
+
};
|
|
1289
1337
|
}
|
|
1290
1338
|
|
|
1291
1339
|
/** Visual tokens shared by one suggestion presentation variant. */
|
|
@@ -1336,6 +1384,8 @@ export interface ComponentTokens {
|
|
|
1336
1384
|
message: MessageTokens;
|
|
1337
1385
|
/** Hover-revealed per-message action row (copy, vote, read aloud). */
|
|
1338
1386
|
messageActions?: MessageActionsTokens;
|
|
1387
|
+
/** Fade and "Show more" toggle on collapsed long user messages. */
|
|
1388
|
+
userMessageCollapse?: UserMessageCollapseTokens;
|
|
1339
1389
|
/** Welcome / intro card shown above the message list. */
|
|
1340
1390
|
introCard?: IntroCardTokens;
|
|
1341
1391
|
/** Markdown surfaces (chat + artifact pane). */
|