@burdenoff/fe-libs 2026.1029.11 → 2026.1030.2
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/connections/ConnectionDetailsTab.d.ts +4 -1
- package/dist/connections/ConnectionDetailsTab.js +18 -15
- package/dist/connections/ConnectionDialog.d.ts +8 -2
- package/dist/connections/ConnectionDialog.js +18 -17
- package/dist/connections/ConnectionDialogPanel.d.ts +3 -1
- package/dist/connections/ConnectionDialogPanel.js +141 -135
- package/dist/connections/ShareConnectionDialog.d.ts +23 -0
- package/dist/connections/ShareConnectionDialog.js +146 -0
- package/dist/connections/SharePanels.d.ts +32 -0
- package/dist/connections/SharePanels.js +158 -0
- package/dist/connections/VisibilityChoice.d.ts +12 -0
- package/dist/connections/VisibilityChoice.js +60 -0
- package/dist/connections/api.d.ts +12 -1
- package/dist/connections/api.js +1 -1
- package/dist/connections/connectionFlow.d.ts +6 -1
- package/dist/connections/connectionFlow.js +1 -1
- package/dist/connections/index.d.ts +4 -1
- package/dist/connections/sharingApi.d.ts +28 -0
- package/dist/connections/sharingApi.js +215 -0
- package/dist/connections/types.d.ts +31 -0
- package/dist/connections/useConnectionSharingDraft.d.ts +40 -0
- package/dist/connections/useConnectionSharingDraft.js +93 -0
- package/dist/connections.js +12 -9
- package/dist/shared/assistant/i18nManifest.d.ts +18 -0
- package/dist/shared/assistant/i18nManifest.js +18 -0
- package/dist/shared/assistant/index.d.ts +4 -0
- package/dist/shared/assistant/ui/AIAssistantPanel.d.ts +9 -1
- package/dist/shared/assistant/ui/AIAssistantPanel.js +194 -174
- package/dist/shared/assistant/ui/AssistantChatArea.d.ts +33 -0
- package/dist/shared/assistant/ui/AssistantChatArea.js +1463 -1397
- package/dist/shared/assistant/ui/AssistantLanguageMenu.d.ts +9 -1
- package/dist/shared/assistant/ui/AssistantLanguageMenu.js +22 -22
- package/dist/shared/assistant/ui/AssistantOverlay.d.ts +16 -2
- package/dist/shared/assistant/ui/AssistantOverlay.js +219 -200
- package/dist/shared/assistant/ui/assistantOverlayState.d.ts +16 -2
- package/dist/shared/assistant/ui/assistantOverlayState.js +57 -40
- package/dist/shared/assistant/ui/compact/AssistantConversationMenu.js +53 -52
- package/dist/shared/assistant/ui/compact/AssistantDiscardDraftDialog.js +3 -4
- package/dist/shared/assistant/ui/compact/AssistantLanguagePill.d.ts +29 -0
- package/dist/shared/assistant/ui/compact/AssistantLanguagePill.js +98 -0
- package/dist/shared/assistant/ui/compact/AssistantVoiceReady.d.ts +31 -0
- package/dist/shared/assistant/ui/compact/AssistantVoiceReady.js +41 -0
- package/dist/shared/assistant/ui/compact/AssistantWaitingChangeRow.d.ts +6 -0
- package/dist/shared/assistant/ui/compact/AssistantWaitingChangeRow.js +5 -5
- package/dist/shared/assistant/ui/compact/AssistantWindowHeader.d.ts +22 -5
- package/dist/shared/assistant/ui/compact/AssistantWindowHeader.js +45 -31
- package/dist/shared/assistant/ui/compact/windowView.d.ts +50 -0
- package/dist/shared/assistant/ui/compact/windowView.js +31 -0
- package/dist/shared/assistant/ui/composer/AssistantComposer.d.ts +6 -0
- package/dist/shared/assistant/ui/composer/AssistantComposer.js +90 -89
- package/dist/shared/assistant/ui/composer/AssistantModeMenu.d.ts +6 -0
- package/dist/shared/assistant/ui/composer/AssistantModeMenu.js +83 -83
- package/dist/shared/assistant/ui/voice/AssistantVoiceSession.d.ts +31 -0
- package/dist/shared/assistant/ui/voice/AssistantVoiceSession.js +270 -166
- package/dist/shared/assistant/ui/voice/VoiceStage.d.ts +8 -0
- package/dist/shared/assistant/ui/voice/VoiceStage.js +10 -10
- package/dist/shared/assistant/voice/voiceStartedCue.d.ts +11 -0
- package/dist/shared/assistant/voice/voiceStartedCue.js +7 -0
- package/dist/shared-assistant.js +266 -262
- package/dist/ui/modal-shell.d.ts +6 -1
- package/dist/ui/modal-shell.js +7 -6
- package/package.json +1 -1
|
@@ -267,6 +267,10 @@ export declare function assistantOverlayClassName(input: {
|
|
|
267
267
|
export type AssistantSurface = 'window' | 'panel';
|
|
268
268
|
/** Narrow a stored value to a surface. */
|
|
269
269
|
export declare function isAssistantSurface(value: unknown): value is AssistantSurface;
|
|
270
|
+
/** The Quick assistant window's two views (BOFF-10180): the conversation, or the voice stage. */
|
|
271
|
+
export type AssistantWindowView = 'chat' | 'voice';
|
|
272
|
+
/** Narrow a stored value to a window view. */
|
|
273
|
+
export declare function isAssistantWindowView(value: unknown): value is AssistantWindowView;
|
|
270
274
|
/** The storage keys only the compact presentation uses. */
|
|
271
275
|
export interface AssistantCompactOverlayKeys {
|
|
272
276
|
/** localStorage: the person's EXPLICIT Dock/Float pick (D1-A), `docked` or `floating`. */
|
|
@@ -275,10 +279,16 @@ export interface AssistantCompactOverlayKeys {
|
|
|
275
279
|
surfaceStorageKey: string;
|
|
276
280
|
/** sessionStorage: the Quick assistant window is minimized (`1`/`0`). */
|
|
277
281
|
minimizedStorageKey: string;
|
|
282
|
+
/**
|
|
283
|
+
* localStorage: the Quick assistant window's LAST USED view (CW-V), `chat` or
|
|
284
|
+
* `voice`. Profile-scoped, like the Dock/Float pick: a preference that outlives
|
|
285
|
+
* a tab, not a moment of this one.
|
|
286
|
+
*/
|
|
287
|
+
windowViewStorageKey: string;
|
|
278
288
|
}
|
|
279
289
|
/**
|
|
280
|
-
* The compact keys for a product prefix: `<prefix>:ai-panel:layout`, `:surface
|
|
281
|
-
* and `:
|
|
290
|
+
* The compact keys for a product prefix: `<prefix>:ai-panel:layout`, `:surface`,
|
|
291
|
+
* `:minimized` and `:window-view`. Separate from `assistantOverlayKeys` so the classic keys
|
|
282
292
|
* (and what a host reads of them) cannot change.
|
|
283
293
|
*/
|
|
284
294
|
export declare function assistantCompactOverlayKeys(prefix: string): AssistantCompactOverlayKeys;
|
|
@@ -286,6 +296,10 @@ export declare function assistantCompactOverlayKeys(prefix: string): AssistantCo
|
|
|
286
296
|
export type AssistantLayoutChoice = 'docked' | 'floating';
|
|
287
297
|
/** The explicit Dock/Float pick (D1-A), or null when none was made or storage fails. */
|
|
288
298
|
export declare function readAssistantLayoutChoice(storage: () => Pick<Storage, 'getItem'> | undefined, key: string): AssistantLayoutChoice | null;
|
|
299
|
+
/** The window's last-used view (CW-V), or null when none was ever chosen or storage fails. */
|
|
300
|
+
export declare function readAssistantWindowView(storage: () => Pick<Storage, 'getItem'> | undefined, key: string): AssistantWindowView | null;
|
|
301
|
+
/** Persist the window's last-used view. An unavailable store keeps it in memory only. */
|
|
302
|
+
export declare function writeAssistantWindowView(storage: () => Pick<Storage, 'setItem'> | undefined, key: string, view: AssistantWindowView): void;
|
|
289
303
|
/** Persist an explicit Dock/Float pick. An unavailable store keeps it in memory only. */
|
|
290
304
|
export declare function writeAssistantLayoutChoice(storage: () => Pick<Storage, 'setItem'> | undefined, key: string, choice: AssistantLayoutChoice): void;
|
|
291
305
|
/**
|
|
@@ -20,13 +20,13 @@ function ee(e) {
|
|
|
20
20
|
return (e.ctrlKey || e.metaKey) && e.shiftKey && typeof e.key == "string" && e.key.toLowerCase() === "a";
|
|
21
21
|
}
|
|
22
22
|
var te = "[role=\"dialog\"],[role=\"alertdialog\"],dialog[open]";
|
|
23
|
-
function
|
|
24
|
-
return
|
|
23
|
+
function ne(e, t) {
|
|
24
|
+
return a(e) ? e.closest(t) : null;
|
|
25
25
|
}
|
|
26
|
-
function
|
|
26
|
+
function a(e) {
|
|
27
27
|
return typeof e == "object" && !!e && "closest" in e && typeof e.closest == "function";
|
|
28
28
|
}
|
|
29
|
-
function
|
|
29
|
+
function o(e) {
|
|
30
30
|
return e.key !== "Escape" || !e.isOpen || e.alreadyHandled || e.dialogOpen || e.pressedInsideDialog || e.panelOwnsEscape ? "ignore" : "close";
|
|
31
31
|
}
|
|
32
32
|
var s = "max(var(--mobile-tabbar-height, 0px), var(--safe-bottom, 0px), env(safe-area-inset-bottom, 0px))";
|
|
@@ -38,36 +38,40 @@ function u(e) {
|
|
|
38
38
|
return `calc(var(${l}, 0px) + ${c(e)})`;
|
|
39
39
|
}
|
|
40
40
|
var d = "1.5rem";
|
|
41
|
-
function
|
|
41
|
+
function f(e) {
|
|
42
42
|
return e > 0 ? `calc(${d} + ${e}px)` : d;
|
|
43
43
|
}
|
|
44
|
-
var
|
|
45
|
-
function
|
|
44
|
+
var p = 440, re = "--assistant-dock-width", m = "--assistant-sheet-bottom", ie = "--assistant-overlay-top", ae = 56, oe = "(min-width: 640px)";
|
|
45
|
+
function se(e) {
|
|
46
46
|
return e.isOpen && e.docked && e.isDesktop ? 440 : 0;
|
|
47
47
|
}
|
|
48
|
-
var
|
|
49
|
-
function
|
|
48
|
+
var ce = 520, le = 24, ue = "--assistant-panel-inset";
|
|
49
|
+
function de(e) {
|
|
50
50
|
return !e.isOpen || !e.isDesktop ? 0 : e.docked ? 440 : 544;
|
|
51
51
|
}
|
|
52
|
-
var
|
|
53
|
-
function
|
|
52
|
+
var h = "fixed z-50 flex flex-col overflow-hidden border border-border-default bg-bg-surface shadow-2xl inset-x-0 bottom-[var(--assistant-sheet-bottom,0px)] top-auto rounded-t-2xl animate-in slide-in-from-bottom-4 fade-in duration-200", g = "h-[60vh] max-h-[60vh]", _ = "h-[88vh] max-h-[88vh]", v = "sm:inset-auto sm:top-auto sm:bottom-24 sm:right-6 sm:rounded-2xl sm:h-[680px] sm:max-h-[calc(100vh-6rem-var(--assistant-overlay-top,56px)-0.5rem)] sm:w-[520px] sm:max-w-[calc(100vw-2rem)]", y = "sm:left-auto sm:right-0 sm:top-[var(--assistant-overlay-top)] sm:bottom-0 sm:rounded-none sm:h-auto sm:max-h-none sm:w-[440px] sm:max-w-[calc(100vw-2rem)]";
|
|
53
|
+
function b(e) {
|
|
54
54
|
return [
|
|
55
|
-
|
|
56
|
-
e.expanded ?
|
|
57
|
-
e.docked ?
|
|
55
|
+
h,
|
|
56
|
+
e.expanded ? _ : g,
|
|
57
|
+
e.docked ? y : v
|
|
58
58
|
].join(" ");
|
|
59
59
|
}
|
|
60
|
-
function
|
|
60
|
+
function x(e) {
|
|
61
61
|
return e === "window" || e === "panel";
|
|
62
62
|
}
|
|
63
|
-
function
|
|
63
|
+
function S(e) {
|
|
64
|
+
return e === "chat" || e === "voice";
|
|
65
|
+
}
|
|
66
|
+
function C(e) {
|
|
64
67
|
return {
|
|
65
68
|
layoutStorageKey: `${e}:ai-panel:layout`,
|
|
66
69
|
surfaceStorageKey: `${e}:ai-panel:surface`,
|
|
67
|
-
minimizedStorageKey: `${e}:ai-panel:minimized
|
|
70
|
+
minimizedStorageKey: `${e}:ai-panel:minimized`,
|
|
71
|
+
windowViewStorageKey: `${e}:ai-panel:window-view`
|
|
68
72
|
};
|
|
69
73
|
}
|
|
70
|
-
function
|
|
74
|
+
function w(e, t) {
|
|
71
75
|
try {
|
|
72
76
|
let n = e()?.getItem(t);
|
|
73
77
|
return n === "docked" || n === "floating" ? n : null;
|
|
@@ -75,12 +79,25 @@ function O(e, t) {
|
|
|
75
79
|
return null;
|
|
76
80
|
}
|
|
77
81
|
}
|
|
78
|
-
function
|
|
82
|
+
function T(e, t) {
|
|
83
|
+
try {
|
|
84
|
+
let n = e()?.getItem(t);
|
|
85
|
+
return S(n) ? n : null;
|
|
86
|
+
} catch {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function E(e, t, n) {
|
|
91
|
+
try {
|
|
92
|
+
e()?.setItem(t, n);
|
|
93
|
+
} catch {}
|
|
94
|
+
}
|
|
95
|
+
function D(e, t, n) {
|
|
79
96
|
try {
|
|
80
97
|
e()?.setItem(t, n);
|
|
81
98
|
} catch {}
|
|
82
99
|
}
|
|
83
|
-
function
|
|
100
|
+
function O(e, t) {
|
|
84
101
|
try {
|
|
85
102
|
let n = e()?.getItem(t);
|
|
86
103
|
return n === "1" ? "docked" : n === "0" ? "floating" : null;
|
|
@@ -88,46 +105,46 @@ function A(e, t) {
|
|
|
88
105
|
return null;
|
|
89
106
|
}
|
|
90
107
|
}
|
|
91
|
-
var
|
|
92
|
-
function
|
|
108
|
+
var k = 1280, A = `(min-width: ${k}px)`;
|
|
109
|
+
function j(e) {
|
|
93
110
|
let t = e.explicit ?? e.legacy;
|
|
94
111
|
return t === null ? e.wideViewport : t === "docked";
|
|
95
112
|
}
|
|
96
|
-
var
|
|
97
|
-
function
|
|
113
|
+
var M = 360, N = 600, P = 760;
|
|
114
|
+
function F(e) {
|
|
98
115
|
return !e.isOpen || !e.isDesktop || e.surface !== "panel" || !e.docked ? 0 : e.expanded ? 760 : 440;
|
|
99
116
|
}
|
|
100
|
-
function
|
|
117
|
+
function I(e) {
|
|
101
118
|
if (!e.isOpen || !e.isDesktop || e.surface !== "panel") return 0;
|
|
102
119
|
let t = e.expanded ? 760 : e.docked ? 440 : 520;
|
|
103
120
|
return e.docked ? t : t + 24;
|
|
104
121
|
}
|
|
105
|
-
var
|
|
106
|
-
function
|
|
107
|
-
return `calc(${u(e)} + ${
|
|
122
|
+
var L = "--assistant-window-bottom", R = "4.5rem";
|
|
123
|
+
function z(e) {
|
|
124
|
+
return `calc(${u(e)} + ${R})`;
|
|
108
125
|
}
|
|
109
|
-
var
|
|
110
|
-
function
|
|
126
|
+
var B = "--assistant-viewport-height", V = "--assistant-keyboard-inset", H = "fixed z-50 flex flex-col overflow-hidden border border-border-default inset-x-0 bottom-[max(var(--assistant-sheet-bottom,0px),var(--assistant-keyboard-inset,0px))] top-auto rounded-t-2xl animate-in slide-in-from-bottom-4 fade-in duration-200", U = "bg-bg-surface shadow-2xl", W = "bg-bg-elevated shadow-[var(--shadow-elevation-4)]", G = "h-[62dvh] max-h-[min(62dvh,var(--assistant-viewport-height,100dvh))]", K = "h-[60dvh] max-h-[min(60dvh,var(--assistant-viewport-height,100dvh))]", q = "h-[88dvh] max-h-[min(88dvh,var(--assistant-viewport-height,100dvh))]", J = "sm:inset-auto sm:top-auto sm:bottom-[var(--assistant-window-bottom,6rem)] sm:right-6 sm:rounded-3xl sm:h-[min(600px,calc(100dvh-var(--assistant-window-bottom,6rem)-var(--assistant-overlay-top,56px)-0.5rem))] sm:max-h-none sm:w-[360px] sm:max-w-[calc(100vw-2rem)]", Y = "sm:left-auto sm:right-0 sm:top-[var(--assistant-overlay-top)] sm:bottom-0 sm:rounded-none sm:h-auto sm:max-h-none sm:w-[440px] sm:max-w-[calc(100vw-2rem)]", X = "sm:left-auto sm:right-0 sm:top-[var(--assistant-overlay-top)] sm:bottom-0 sm:rounded-none sm:h-auto sm:max-h-none sm:w-[760px] sm:max-w-[calc(100vw-2rem)]", Z = "sm:inset-auto sm:top-auto sm:bottom-24 sm:right-6 sm:rounded-2xl sm:h-[680px] sm:max-h-[calc(100dvh-6rem-var(--assistant-overlay-top,56px)-0.5rem)] sm:w-[520px] sm:max-w-[calc(100vw-2rem)]", Q = "sm:inset-auto sm:top-auto sm:bottom-6 sm:right-6 sm:rounded-2xl sm:h-[calc(100dvh-var(--assistant-overlay-top,56px)-3rem)] sm:max-h-none sm:w-[760px] sm:max-w-[calc(100vw-2rem)]";
|
|
127
|
+
function fe(e) {
|
|
111
128
|
if (e.minimized) return "hidden";
|
|
112
|
-
let t = e.surface === "window", n = e.sheetExpanded ?
|
|
129
|
+
let t = e.surface === "window", n = e.sheetExpanded ? q : t ? G : K, r = t ? J : e.docked ? e.expanded ? X : Y : e.expanded ? Q : Z;
|
|
113
130
|
return [
|
|
114
|
-
|
|
115
|
-
t ?
|
|
131
|
+
H,
|
|
132
|
+
t ? W : U,
|
|
116
133
|
n,
|
|
117
134
|
r
|
|
118
135
|
].join(" ");
|
|
119
136
|
}
|
|
120
|
-
function
|
|
137
|
+
function pe(e) {
|
|
121
138
|
return !e.isOpen || e.minimized ? "always" : e.surface === "panel" ? "hidden" : "desktop-only";
|
|
122
139
|
}
|
|
123
|
-
function
|
|
140
|
+
function me(e) {
|
|
124
141
|
let t = e.scale > 1.01, n = e.layoutHeight - e.viewportHeight - e.viewportOffsetTop, r = t ? 0 : Math.max(0, Math.round(n));
|
|
125
142
|
return {
|
|
126
143
|
heightPx: Math.max(0, Math.round(t ? e.layoutHeight : e.viewportHeight)),
|
|
127
144
|
keyboardInsetPx: r
|
|
128
145
|
};
|
|
129
146
|
}
|
|
130
|
-
function
|
|
147
|
+
function he(t) {
|
|
131
148
|
return (n, r) => {
|
|
132
149
|
if (t.isShellLessTarget?.(n)) return t.openInNewTab(n), { kind: "new-tab" };
|
|
133
150
|
let i = e(r);
|
|
@@ -138,22 +155,22 @@ function de(t) {
|
|
|
138
155
|
} : (t.navigate(n), t.isDesktop() || t.collapseSheet(), { kind: "routed" });
|
|
139
156
|
};
|
|
140
157
|
}
|
|
141
|
-
function
|
|
158
|
+
function ge(e) {
|
|
142
159
|
if (typeof CustomEvent > "u" || !(e instanceof CustomEvent)) return "generic";
|
|
143
160
|
let t = e.detail;
|
|
144
161
|
return typeof t != "object" || !t || !("kind" in t) ? "generic" : t.kind === "sandbox" || t.kind === "ai-credits" ? t.kind : "generic";
|
|
145
162
|
}
|
|
146
|
-
function
|
|
163
|
+
function $(e, t) {
|
|
147
164
|
try {
|
|
148
165
|
return e()?.getItem(t) === "1";
|
|
149
166
|
} catch {
|
|
150
167
|
return !1;
|
|
151
168
|
}
|
|
152
169
|
}
|
|
153
|
-
function
|
|
170
|
+
function _e(e, t, n) {
|
|
154
171
|
try {
|
|
155
172
|
e()?.setItem(t, n ? "1" : "0");
|
|
156
173
|
} catch {}
|
|
157
174
|
}
|
|
158
175
|
//#endregion
|
|
159
|
-
export { s as ASSISTANT_BOTTOM_CHROME_CLEARANCE,
|
|
176
|
+
export { s as ASSISTANT_BOTTOM_CHROME_CLEARANCE, A as ASSISTANT_COMPACT_DOCKED_DEFAULT_QUERY, Y as ASSISTANT_COMPACT_DOCKED_DESKTOP_CLASS, X as ASSISTANT_COMPACT_DOCKED_EXPANDED_DESKTOP_CLASS, k as ASSISTANT_COMPACT_DOCKED_MIN_VIEWPORT_PX, P as ASSISTANT_COMPACT_EXPANDED_WIDTH_PX, Z as ASSISTANT_COMPACT_FLOATING_DESKTOP_CLASS, Q as ASSISTANT_COMPACT_FLOATING_EXPANDED_DESKTOP_CLASS, U as ASSISTANT_COMPACT_PANEL_SURFACE_CLASS, H as ASSISTANT_COMPACT_SHEET_BASE_CLASS, q as ASSISTANT_COMPACT_SHEET_EXPANDED_CLASS, K as ASSISTANT_COMPACT_SHEET_PANEL_CLASS, G as ASSISTANT_COMPACT_SHEET_WINDOW_CLASS, J as ASSISTANT_COMPACT_WINDOW_DESKTOP_CLASS, N as ASSISTANT_COMPACT_WINDOW_HEIGHT_PX, W as ASSISTANT_COMPACT_WINDOW_SURFACE_CLASS, M as ASSISTANT_COMPACT_WINDOW_WIDTH_PX, te as ASSISTANT_DIALOG_SELECTOR, y as ASSISTANT_DOCKED_DESKTOP_CLASS, p as ASSISTANT_DOCK_WIDTH_PX, re as ASSISTANT_DOCK_WIDTH_VAR, v as ASSISTANT_FLOATING_DESKTOP_CLASS, le as ASSISTANT_FLOATING_RIGHT_PX, ce as ASSISTANT_FLOATING_WIDTH_PX, V as ASSISTANT_KEYBOARD_INSET_VAR, l as ASSISTANT_LAUNCHER_LIFT_VAR, d as ASSISTANT_LAUNCHER_RIGHT_INSET, ae as ASSISTANT_OVERLAY_DEFAULT_TOP_PX, oe as ASSISTANT_OVERLAY_DESKTOP_QUERY, ie as ASSISTANT_OVERLAY_TOP_VAR, ue as ASSISTANT_PANEL_INSET_VAR, h as ASSISTANT_SHEET_BASE_CLASS, m as ASSISTANT_SHEET_BOTTOM_VAR, g as ASSISTANT_SHEET_COMPACT_CLASS, _ as ASSISTANT_SHEET_EXPANDED_CLASS, i as ASSISTANT_TOGGLE_SHORTCUT_LABEL, B as ASSISTANT_VIEWPORT_HEIGHT_VAR, L as ASSISTANT_WINDOW_BOTTOM_VAR, R as ASSISTANT_WINDOW_LAUNCHER_CLEARANCE, c as aboveAssistantBottomChrome, pe as assistantCompactLauncherVisibility, fe as assistantCompactOverlayClassName, C as assistantCompactOverlayKeys, u as assistantLauncherBottom, f as assistantLauncherRight, b as assistantOverlayClassName, o as assistantOverlayEscapeAction, t as assistantOverlayKeys, ge as assistantQuotaKindOf, me as assistantVisualViewportMetrics, z as assistantWindowBottom, ne as closestAround, he as createAssistantNavigate, x as isAssistantSurface, ee as isAssistantToggleShortcut, S as isAssistantWindowView, r as nextAssistantOpenState, se as publishedAssistantDockWidth, de as publishedAssistantPanelInset, F as publishedCompactDockWidth, I as publishedCompactPanelInset, w as readAssistantLayoutChoice, O as readAssistantLegacyDockChoice, $ as readAssistantOverlayFlag, T as readAssistantWindowView, n as requestedAssistantOpenState, j as resolveCompactDocked, D as writeAssistantLayoutChoice, _e as writeAssistantOverlayFlag, E as writeAssistantWindowView };
|
|
@@ -1,87 +1,88 @@
|
|
|
1
|
-
import { DropdownMenu as e, DropdownMenuContent as t, DropdownMenuItem as n,
|
|
2
|
-
import { focusWasDropped as
|
|
3
|
-
import { getAssistantControl as
|
|
4
|
-
import { useAssistantTr as
|
|
5
|
-
import { useAssistantStore as
|
|
6
|
-
import { voiceTurnsOnly as
|
|
7
|
-
import { downloadFile as
|
|
8
|
-
import { useCallback as
|
|
9
|
-
import { FileJson as
|
|
10
|
-
import { Fragment as
|
|
1
|
+
import { DropdownMenu as e, DropdownMenuContent as t, DropdownMenuItem as n, DropdownMenuTrigger as r } from "../../../../ui/dropdown-menu.js";
|
|
2
|
+
import { focusWasDropped as i } from "../../../hooks/useReturnFocus.js";
|
|
3
|
+
import { getAssistantControl as a, hasAssistantControl as o, subscribeAssistantControls as s } from "../../appControls/registry.js";
|
|
4
|
+
import { useAssistantTr as c } from "../../i18n.js";
|
|
5
|
+
import { useAssistantStore as l } from "../../store.js";
|
|
6
|
+
import { voiceTurnsOnly as u } from "../../voice/turnVisibility.js";
|
|
7
|
+
import { downloadFile as d, exportConversation as f } from "../../exportConversation.js";
|
|
8
|
+
import { useCallback as p, useSyncExternalStore as m } from "react";
|
|
9
|
+
import { FileJson as h, FileText as g, Mic as _, MoreHorizontal as v } from "lucide-react";
|
|
10
|
+
import { Fragment as y, jsx as b, jsxs as x } from "react/jsx-runtime";
|
|
11
11
|
//#region src/shared/assistant/ui/compact/AssistantConversationMenu.tsx
|
|
12
|
-
var
|
|
13
|
-
let
|
|
14
|
-
if (!
|
|
15
|
-
let { content: t, filename: n, mimeType: r } =
|
|
16
|
-
processing: A
|
|
17
|
-
tr:
|
|
12
|
+
var S = "min-h-11 gap-2.5 px-3", C = ({ open: C, onOpenChange: w, triggerRef: T }) => {
|
|
13
|
+
let E = c(), { conversations: D, activeConversationId: O, processingByConversationId: k } = l(), A = D.find((e) => e.id === O), j = !!(A && A.messages.length > 0), M = !!(m(s, () => o("assistant.transcript"), () => !1) && A && u(A.messages).length > 0), N = (e) => {
|
|
14
|
+
if (!A) return;
|
|
15
|
+
let { content: t, filename: n, mimeType: r } = f(A, e, {
|
|
16
|
+
processing: k[A.id],
|
|
17
|
+
tr: E
|
|
18
18
|
});
|
|
19
|
-
|
|
20
|
-
},
|
|
21
|
-
|
|
22
|
-
},
|
|
23
|
-
|
|
24
|
-
}, []),
|
|
25
|
-
return /* @__PURE__ */
|
|
26
|
-
open:
|
|
27
|
-
onOpenChange:
|
|
19
|
+
d(t, n, r);
|
|
20
|
+
}, P = () => {
|
|
21
|
+
a("assistant.transcript")?.run();
|
|
22
|
+
}, F = p((e) => {
|
|
23
|
+
i(document) || e.preventDefault();
|
|
24
|
+
}, []), I = E("header.conversationOptions", "Conversation options");
|
|
25
|
+
return /* @__PURE__ */ x(e, {
|
|
26
|
+
open: C,
|
|
27
|
+
onOpenChange: w,
|
|
28
28
|
modal: !1,
|
|
29
|
-
children: [/* @__PURE__ */
|
|
29
|
+
children: [/* @__PURE__ */ b(r, {
|
|
30
30
|
asChild: !0,
|
|
31
|
-
children: /* @__PURE__ */
|
|
32
|
-
ref:
|
|
31
|
+
children: /* @__PURE__ */ b("button", {
|
|
32
|
+
ref: T,
|
|
33
33
|
type: "button",
|
|
34
|
-
"aria-label":
|
|
35
|
-
title:
|
|
34
|
+
"aria-label": I,
|
|
35
|
+
title: I,
|
|
36
36
|
className: "flex size-10 shrink-0 items-center justify-center rounded-button text-text-secondary transition-colors hover:bg-bg-sunken hover:text-text-primary focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]",
|
|
37
37
|
"data-testid": "assistant-more",
|
|
38
|
-
children: /* @__PURE__ */
|
|
38
|
+
children: /* @__PURE__ */ b(v, {
|
|
39
39
|
className: "size-5",
|
|
40
40
|
"aria-hidden": "true"
|
|
41
41
|
})
|
|
42
42
|
})
|
|
43
|
-
}), /* @__PURE__ */
|
|
43
|
+
}), /* @__PURE__ */ x(t, {
|
|
44
44
|
align: "end",
|
|
45
45
|
sideOffset: 4,
|
|
46
46
|
collisionPadding: 8,
|
|
47
|
-
onCloseAutoFocus:
|
|
47
|
+
onCloseAutoFocus: F,
|
|
48
48
|
className: "min-w-56 max-w-[calc(100vw-2rem)] max-h-[var(--radix-dropdown-menu-content-available-height)] overflow-y-auto",
|
|
49
49
|
"data-testid": "assistant-more-menu",
|
|
50
50
|
children: [
|
|
51
|
-
|
|
52
|
-
className:
|
|
53
|
-
onSelect: () =>
|
|
51
|
+
j ? /* @__PURE__ */ x(y, { children: [/* @__PURE__ */ x(n, {
|
|
52
|
+
className: S,
|
|
53
|
+
onSelect: () => N("markdown"),
|
|
54
54
|
"data-testid": "export-markdown",
|
|
55
|
-
children: [/* @__PURE__ */
|
|
55
|
+
children: [/* @__PURE__ */ b(g, {
|
|
56
56
|
className: "size-4 shrink-0 text-text-secondary",
|
|
57
57
|
"aria-hidden": "true"
|
|
58
|
-
}),
|
|
59
|
-
}), /* @__PURE__ */
|
|
60
|
-
className:
|
|
61
|
-
onSelect: () =>
|
|
58
|
+
}), E("export.markdown", "Export as Markdown")]
|
|
59
|
+
}), /* @__PURE__ */ x(n, {
|
|
60
|
+
className: S,
|
|
61
|
+
onSelect: () => N("json"),
|
|
62
62
|
"data-testid": "export-json",
|
|
63
|
-
children: [/* @__PURE__ */
|
|
63
|
+
children: [/* @__PURE__ */ b(h, {
|
|
64
64
|
className: "size-4 shrink-0 text-text-secondary",
|
|
65
65
|
"aria-hidden": "true"
|
|
66
|
-
}),
|
|
66
|
+
}), E("export.json", "Export as JSON")]
|
|
67
67
|
})] }) : null,
|
|
68
|
-
|
|
69
|
-
className:
|
|
70
|
-
onSelect:
|
|
68
|
+
M ? /* @__PURE__ */ x(n, {
|
|
69
|
+
className: S,
|
|
70
|
+
onSelect: P,
|
|
71
71
|
"data-testid": "assistant-more-voice-transcript",
|
|
72
|
-
children: [/* @__PURE__ */
|
|
72
|
+
children: [/* @__PURE__ */ b(_, {
|
|
73
73
|
className: "size-4 shrink-0 text-text-secondary",
|
|
74
74
|
"aria-hidden": "true"
|
|
75
|
-
}),
|
|
75
|
+
}), E("conversationMenu.voiceTranscript", "Voice transcript")]
|
|
76
76
|
}) : null,
|
|
77
|
-
!
|
|
78
|
-
|
|
77
|
+
!j && !M ? /* @__PURE__ */ b(n, {
|
|
78
|
+
disabled: !0,
|
|
79
|
+
className: `${S} text-text-secondary`,
|
|
79
80
|
"data-testid": "assistant-more-empty",
|
|
80
|
-
children:
|
|
81
|
+
children: E("conversationMenu.empty", "Nothing to export yet")
|
|
81
82
|
}) : null
|
|
82
83
|
]
|
|
83
84
|
})]
|
|
84
85
|
});
|
|
85
86
|
};
|
|
86
87
|
//#endregion
|
|
87
|
-
export {
|
|
88
|
+
export { C as AssistantConversationMenu };
|
|
@@ -16,6 +16,8 @@ var s = ({ open: s, onKeep: c, onDiscard: l }) => {
|
|
|
16
16
|
e.preventDefault(), d.current?.focus();
|
|
17
17
|
},
|
|
18
18
|
title: u("closeConfirm.title", "Discard your unsent message?"),
|
|
19
|
+
description: u("closeConfirm.body", "What you typed or attached has not been sent. If you close the assistant now, it is discarded."),
|
|
20
|
+
ariaModal: !0,
|
|
19
21
|
footer: /* @__PURE__ */ o(i, { children: [/* @__PURE__ */ a(e, {
|
|
20
22
|
ref: d,
|
|
21
23
|
variant: "outline",
|
|
@@ -28,10 +30,7 @@ var s = ({ open: s, onKeep: c, onDiscard: l }) => {
|
|
|
28
30
|
"data-testid": "assistant-discard-draft-confirm",
|
|
29
31
|
children: u("closeConfirm.discard", "Discard and close")
|
|
30
32
|
})] }),
|
|
31
|
-
children:
|
|
32
|
-
className: "text-sm text-text-secondary",
|
|
33
|
-
children: u("closeConfirm.body", "What you typed or attached has not been sent. If you close the assistant now, it is discarded.")
|
|
34
|
-
})
|
|
33
|
+
children: null
|
|
35
34
|
});
|
|
36
35
|
};
|
|
37
36
|
//#endregion
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { FC } from 'react';
|
|
2
|
+
export interface AssistantLanguagePillProps {
|
|
3
|
+
/**
|
|
4
|
+
* A voice conversation is live. Changing the language stops a running
|
|
5
|
+
* recogniser (`useVoiceInput`), so the pill waits for the end of the
|
|
6
|
+
* conversation and says why.
|
|
7
|
+
*/
|
|
8
|
+
voiceLive: boolean;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* The Quick assistant window's language pill (BOFF-10180, CW-L, DESIGN §7
|
|
12
|
+
* "Language semantics").
|
|
13
|
+
*
|
|
14
|
+
* ★ It sets the INPUT language (`assistantLanguage`) and nothing else. That
|
|
15
|
+
* language also drives the reply and its voice while "Assistant replies in" is
|
|
16
|
+
* "Match my language", which is the default. A reply language pinned to something
|
|
17
|
+
* else stays in the full assistant: here it is only SAID ("Replies in {{language}}
|
|
18
|
+
* — change in full assistant"), never offered. It never changes the interface
|
|
19
|
+
* language.
|
|
20
|
+
*
|
|
21
|
+
* ★ The menu is the existing `AssistantLanguageMenu`, input row only, so the
|
|
22
|
+
* choice, the list and the stored value are the ones the ⋯ menu and Settings
|
|
23
|
+
* already use. It stays a native `<select>`: a phone opens its own picker.
|
|
24
|
+
*
|
|
25
|
+
* ★ While voice is live the pill is `aria-disabled`, not `disabled`: it stays in
|
|
26
|
+
* the Tab order, so a keyboard or screen-reader user reaches it and hears why
|
|
27
|
+
* (`aria-describedby`), and it cannot open.
|
|
28
|
+
*/
|
|
29
|
+
export declare const AssistantLanguagePill: FC<AssistantLanguagePillProps>;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { useI18n as e } from "../../../providers/shell/I18nProvider.js";
|
|
2
|
+
import { EscapeLayer as t } from "../../../components/EscapeLayer.js";
|
|
3
|
+
import { useAssistantTr as n } from "../../i18n.js";
|
|
4
|
+
import { useAssistantStore as r } from "../../store.js";
|
|
5
|
+
import { replyFollowsInput as i, resolveLanguagePair as a } from "../../voice/languagePair.js";
|
|
6
|
+
import { AssistantLanguageMenu as o } from "../AssistantLanguageMenu.js";
|
|
7
|
+
import { useEffect as s, useId as c, useMemo as l, useRef as u, useState as d } from "react";
|
|
8
|
+
import { ChevronDown as f, Languages as p } from "lucide-react";
|
|
9
|
+
import { jsx as m, jsxs as h } from "react/jsx-runtime";
|
|
10
|
+
//#region src/shared/assistant/ui/compact/AssistantLanguagePill.tsx
|
|
11
|
+
var g = ({ voiceLive: g }) => {
|
|
12
|
+
let _ = n(), { locale: v } = e(), y = r((e) => e.assistantLanguage), b = r((e) => e.replyLanguage), x = l(() => a(y, b, v), [
|
|
13
|
+
y,
|
|
14
|
+
b,
|
|
15
|
+
v
|
|
16
|
+
]), [S, C] = d(!1), w = u(null), T = u(null), E = c(), D = c();
|
|
17
|
+
S && g && C(!1);
|
|
18
|
+
let O = u(S);
|
|
19
|
+
s(() => {
|
|
20
|
+
O.current = S;
|
|
21
|
+
});
|
|
22
|
+
let k = u(y);
|
|
23
|
+
s(() => {
|
|
24
|
+
k.current !== y && (k.current = y, O.current && (C(!1), T.current?.focus({ preventScroll: !0 })));
|
|
25
|
+
}, [y]), s(() => {
|
|
26
|
+
if (!S) return;
|
|
27
|
+
let e = (e) => {
|
|
28
|
+
let t = e.target;
|
|
29
|
+
t instanceof Node && w.current?.contains(t) || C(!1);
|
|
30
|
+
};
|
|
31
|
+
return document.addEventListener("pointerdown", e), () => document.removeEventListener("pointerdown", e);
|
|
32
|
+
}, [S]);
|
|
33
|
+
let A = _("window.language", "Language"), j = _("window.languageLocked", "Change the language after you end voice"), M = !i(b) && x.reply.code !== x.input.code ? x.reply.label : null, N = (e) => {
|
|
34
|
+
C(!1), e && T.current?.focus({ preventScroll: !0 });
|
|
35
|
+
};
|
|
36
|
+
return /* @__PURE__ */ h("div", {
|
|
37
|
+
ref: w,
|
|
38
|
+
className: "relative min-w-0 flex-1",
|
|
39
|
+
"data-testid": "assistant-window-language-root",
|
|
40
|
+
children: [
|
|
41
|
+
/* @__PURE__ */ h("button", {
|
|
42
|
+
ref: T,
|
|
43
|
+
type: "button",
|
|
44
|
+
onClick: () => {
|
|
45
|
+
g || C((e) => !e);
|
|
46
|
+
},
|
|
47
|
+
className: `flex h-10 min-w-0 max-w-full items-center gap-1.5 rounded-full border border-border-default px-3 text-sm transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)] ${g ? "cursor-default text-text-muted" : "text-text-primary hover:bg-bg-sunken"}`,
|
|
48
|
+
"aria-expanded": S,
|
|
49
|
+
"aria-controls": S ? E : void 0,
|
|
50
|
+
"aria-disabled": g ? "true" : void 0,
|
|
51
|
+
"aria-describedby": g ? D : void 0,
|
|
52
|
+
"aria-label": `${A}: ${x.input.label}`,
|
|
53
|
+
title: g ? j : `${A}: ${x.input.label}`,
|
|
54
|
+
"data-testid": "assistant-window-language",
|
|
55
|
+
children: [
|
|
56
|
+
/* @__PURE__ */ m(p, {
|
|
57
|
+
className: "size-4 shrink-0",
|
|
58
|
+
"aria-hidden": "true"
|
|
59
|
+
}),
|
|
60
|
+
/* @__PURE__ */ m("span", {
|
|
61
|
+
className: "min-w-0 truncate",
|
|
62
|
+
"data-testid": "assistant-window-language-name",
|
|
63
|
+
children: x.input.label
|
|
64
|
+
}),
|
|
65
|
+
/* @__PURE__ */ m(f, {
|
|
66
|
+
className: "size-4 shrink-0",
|
|
67
|
+
"aria-hidden": "true"
|
|
68
|
+
})
|
|
69
|
+
]
|
|
70
|
+
}),
|
|
71
|
+
g ? /* @__PURE__ */ m("span", {
|
|
72
|
+
id: D,
|
|
73
|
+
className: "sr-only",
|
|
74
|
+
"data-testid": "assistant-window-language-reason",
|
|
75
|
+
children: j
|
|
76
|
+
}) : null,
|
|
77
|
+
S ? /* @__PURE__ */ m(t, {
|
|
78
|
+
onDismiss: () => {
|
|
79
|
+
N(!0);
|
|
80
|
+
},
|
|
81
|
+
children: /* @__PURE__ */ h("div", {
|
|
82
|
+
id: E,
|
|
83
|
+
role: "group",
|
|
84
|
+
"aria-label": A,
|
|
85
|
+
className: "absolute start-0 top-full z-30 mt-1 w-72 max-w-[calc(100vw-2rem)] overflow-hidden rounded-card border border-border-default bg-bg-elevated py-1 shadow-[var(--shadow-overlay)]",
|
|
86
|
+
"data-testid": "assistant-window-language-menu",
|
|
87
|
+
children: [/* @__PURE__ */ m(o, { inputOnly: !0 }), M === null ? null : /* @__PURE__ */ m("p", {
|
|
88
|
+
className: "px-3 py-2 text-xs text-text-muted",
|
|
89
|
+
"data-testid": "assistant-window-language-pinned",
|
|
90
|
+
children: _("window.languagePinned", "Replies in {{language}} — change in full assistant", { language: M })
|
|
91
|
+
})]
|
|
92
|
+
})
|
|
93
|
+
}) : null
|
|
94
|
+
]
|
|
95
|
+
});
|
|
96
|
+
};
|
|
97
|
+
//#endregion
|
|
98
|
+
export { g as AssistantLanguagePill };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { FC } from 'react';
|
|
2
|
+
export interface AssistantVoiceReadyProps {
|
|
3
|
+
/**
|
|
4
|
+
* Why a voice conversation cannot start here and now (`voiceStartBlocker`),
|
|
5
|
+
* already worded. Null: it can, and Start voice is offered.
|
|
6
|
+
*/
|
|
7
|
+
blockedReason: string | null;
|
|
8
|
+
/** Start the voice conversation: the chat area's own `startVoiceWithPrewarm`. */
|
|
9
|
+
onStart: () => void;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* The Quick assistant window's Voice view, ready: not started (BOFF-10180, C2).
|
|
13
|
+
*
|
|
14
|
+
* ★ Nothing here listens. The brand orb is a still picture, with no ring, halo or
|
|
15
|
+
* motion, so it cannot read as "the microphone is open"; the status line says
|
|
16
|
+
* when it opens ("only when you press Start voice"); opening the window, or
|
|
17
|
+
* switching to this view, starts neither the microphone nor an avatar. The one
|
|
18
|
+
* thing that does is the person's press on Start voice, which is the composer's
|
|
19
|
+
* own start (`startVoiceWithPrewarm`).
|
|
20
|
+
*
|
|
21
|
+
* ★ Start voice is never auto-focused. Focus lands in the message box when the
|
|
22
|
+
* window opens, so a stray Enter cannot open the microphone.
|
|
23
|
+
*
|
|
24
|
+
* ★ Where voice cannot start (the mode takes none, the browser has no speech,
|
|
25
|
+
* the conversation is read-only, or it is busy) the reason takes the button's
|
|
26
|
+
* place, as a polite status, and there is no Start voice to press.
|
|
27
|
+
*
|
|
28
|
+
* ★ The orb is the brand's. Face stills belong to the avatar seam, which offers
|
|
29
|
+
* no accessor for the chosen face, and the window never starts an avatar.
|
|
30
|
+
*/
|
|
31
|
+
export declare const AssistantVoiceReady: FC<AssistantVoiceReadyProps>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { useAssistantTr as e } from "../../i18n.js";
|
|
2
|
+
import { Mic as t } from "lucide-react";
|
|
3
|
+
import { jsx as n, jsxs as r } from "react/jsx-runtime";
|
|
4
|
+
//#region src/shared/assistant/ui/compact/AssistantVoiceReady.tsx
|
|
5
|
+
var i = ({ blockedReason: i, onStart: a }) => {
|
|
6
|
+
let o = e();
|
|
7
|
+
return /* @__PURE__ */ r("div", {
|
|
8
|
+
className: "flex min-h-0 flex-1 flex-col items-center justify-center gap-4 overflow-y-auto px-6 py-4 text-center",
|
|
9
|
+
"data-testid": "assistant-window-voice-ready",
|
|
10
|
+
children: [
|
|
11
|
+
/* @__PURE__ */ n("span", {
|
|
12
|
+
className: "size-28 shrink-0 rounded-full bg-gradient-to-br from-action-primary-bg/80 to-action-primary-bg/20 shadow-[var(--shadow-elevation-3)]",
|
|
13
|
+
"aria-hidden": "true",
|
|
14
|
+
"data-testid": "assistant-window-orb"
|
|
15
|
+
}),
|
|
16
|
+
/* @__PURE__ */ n("h2", {
|
|
17
|
+
className: "text-lg font-semibold text-text-primary",
|
|
18
|
+
children: o("window.voiceReadyTitle", "Talk to the assistant")
|
|
19
|
+
}),
|
|
20
|
+
/* @__PURE__ */ n("p", {
|
|
21
|
+
role: "status",
|
|
22
|
+
"aria-live": "polite",
|
|
23
|
+
className: "max-w-[16rem] text-sm text-text-secondary",
|
|
24
|
+
"data-testid": "assistant-window-voice-status",
|
|
25
|
+
children: i ?? o("window.voiceReadyStatus", "The microphone starts only when you press Start voice.")
|
|
26
|
+
}),
|
|
27
|
+
i === null ? /* @__PURE__ */ r("button", {
|
|
28
|
+
type: "button",
|
|
29
|
+
onClick: a,
|
|
30
|
+
className: "flex h-12 items-center gap-2 rounded-full bg-action-primary-bg px-6 text-base font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg-hover focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--color-bg-elevated)]",
|
|
31
|
+
"data-testid": "assistant-window-start-voice",
|
|
32
|
+
children: [/* @__PURE__ */ n(t, {
|
|
33
|
+
className: "size-5",
|
|
34
|
+
"aria-hidden": "true"
|
|
35
|
+
}), o("window.startVoice", "Start voice")]
|
|
36
|
+
}) : null
|
|
37
|
+
]
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
//#endregion
|
|
41
|
+
export { i as AssistantVoiceReady };
|
|
@@ -4,6 +4,12 @@ export interface AssistantWaitingChangeRowProps {
|
|
|
4
4
|
count: number;
|
|
5
5
|
/** Scroll to the first waiting change's card and focus it. */
|
|
6
6
|
onReview: () => void;
|
|
7
|
+
/**
|
|
8
|
+
* BOFF-10180 (the Quick assistant window): the card is in the full assistant,
|
|
9
|
+
* so the row's one button says so ("Review in full assistant") and `onReview`
|
|
10
|
+
* opens the full assistant. Still a pointer, never a second way to approve.
|
|
11
|
+
*/
|
|
12
|
+
opensFull?: boolean;
|
|
7
13
|
}
|
|
8
14
|
/**
|
|
9
15
|
* The pinned "change waiting" row above the composer (N6, 2026-10-29), in the
|