@burdenoff/fe-libs 2026.1029.10 → 2026.1030.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/dist/shared/assistant/i18nManifest.d.ts +22 -0
  2. package/dist/shared/assistant/i18nManifest.js +22 -0
  3. package/dist/shared/assistant/index.d.ts +6 -0
  4. package/dist/shared/assistant/ui/AIAssistantPanel.d.ts +26 -0
  5. package/dist/shared/assistant/ui/AIAssistantPanel.js +197 -160
  6. package/dist/shared/assistant/ui/AssistantChatArea.d.ts +33 -0
  7. package/dist/shared/assistant/ui/AssistantChatArea.js +1463 -1397
  8. package/dist/shared/assistant/ui/AssistantLanguageMenu.d.ts +9 -1
  9. package/dist/shared/assistant/ui/AssistantLanguageMenu.js +22 -22
  10. package/dist/shared/assistant/ui/AssistantOverlay.d.ts +91 -3
  11. package/dist/shared/assistant/ui/AssistantOverlay.js +347 -127
  12. package/dist/shared/assistant/ui/assistantOverlayState.d.ts +224 -0
  13. package/dist/shared/assistant/ui/assistantOverlayState.js +116 -29
  14. package/dist/shared/assistant/ui/compact/AssistantConversationMenu.js +53 -52
  15. package/dist/shared/assistant/ui/compact/AssistantDiscardDraftDialog.js +3 -4
  16. package/dist/shared/assistant/ui/compact/AssistantLanguagePill.d.ts +29 -0
  17. package/dist/shared/assistant/ui/compact/AssistantLanguagePill.js +98 -0
  18. package/dist/shared/assistant/ui/compact/AssistantVoiceReady.d.ts +31 -0
  19. package/dist/shared/assistant/ui/compact/AssistantVoiceReady.js +41 -0
  20. package/dist/shared/assistant/ui/compact/AssistantWaitingChangeRow.d.ts +6 -0
  21. package/dist/shared/assistant/ui/compact/AssistantWaitingChangeRow.js +5 -5
  22. package/dist/shared/assistant/ui/compact/AssistantWindowHeader.d.ts +36 -0
  23. package/dist/shared/assistant/ui/compact/AssistantWindowHeader.js +68 -0
  24. package/dist/shared/assistant/ui/compact/windowView.d.ts +50 -0
  25. package/dist/shared/assistant/ui/compact/windowView.js +31 -0
  26. package/dist/shared/assistant/ui/composer/AssistantAttachmentButton.d.ts +8 -0
  27. package/dist/shared/assistant/ui/composer/AssistantAttachmentButton.js +34 -34
  28. package/dist/shared/assistant/ui/composer/AssistantComposer.d.ts +6 -0
  29. package/dist/shared/assistant/ui/composer/AssistantComposer.js +92 -90
  30. package/dist/shared/assistant/ui/composer/AssistantModeMenu.d.ts +6 -0
  31. package/dist/shared/assistant/ui/composer/AssistantModeMenu.js +83 -83
  32. package/dist/shared/assistant/ui/useAssistantVisualViewport.d.ts +3 -0
  33. package/dist/shared/assistant/ui/useAssistantVisualViewport.js +24 -0
  34. package/dist/shared/assistant/ui/voice/AssistantVoiceSession.d.ts +31 -0
  35. package/dist/shared/assistant/ui/voice/AssistantVoiceSession.js +270 -166
  36. package/dist/shared/assistant/ui/voice/VoiceStage.d.ts +8 -0
  37. package/dist/shared/assistant/ui/voice/VoiceStage.js +10 -10
  38. package/dist/shared/assistant/voice/voiceStartedCue.d.ts +11 -0
  39. package/dist/shared/assistant/voice/voiceStartedCue.js +7 -0
  40. package/dist/shared-assistant.js +266 -260
  41. package/dist/ui/modal-shell.d.ts +6 -1
  42. package/dist/ui/modal-shell.js +7 -6
  43. package/package.json +1 -1
@@ -254,6 +254,230 @@ export declare function assistantOverlayClassName(input: {
254
254
  expanded: boolean;
255
255
  docked: boolean;
256
256
  }): string;
257
+ /**
258
+ * What the one assistant container is showing (DESIGN §8.2):
259
+ * - `window`: the Quick assistant, a small non-modal window above the launcher
260
+ * (a bottom sheet on a phone);
261
+ * - `panel`: the full assistant, docked, floating or a sheet.
262
+ *
263
+ * ★ A surface is a CLASS and a geometry on one persistent element, never a
264
+ * place in the tree: the in-flight turn, the draft, its attachments, the
265
+ * microphone and the voice session all live below it.
266
+ */
267
+ export type AssistantSurface = 'window' | 'panel';
268
+ /** Narrow a stored value to a surface. */
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;
274
+ /** The storage keys only the compact presentation uses. */
275
+ export interface AssistantCompactOverlayKeys {
276
+ /** localStorage: the person's EXPLICIT Dock/Float pick (D1-A), `docked` or `floating`. */
277
+ layoutStorageKey: string;
278
+ /** sessionStorage: which surface is showing, `window` or `panel`. */
279
+ surfaceStorageKey: string;
280
+ /** sessionStorage: the Quick assistant window is minimized (`1`/`0`). */
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;
288
+ }
289
+ /**
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
292
+ * (and what a host reads of them) cannot change.
293
+ */
294
+ export declare function assistantCompactOverlayKeys(prefix: string): AssistantCompactOverlayKeys;
295
+ /** Dock or Float, as a person picked it. */
296
+ export type AssistantLayoutChoice = 'docked' | 'floating';
297
+ /** The explicit Dock/Float pick (D1-A), or null when none was made or storage fails. */
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;
303
+ /** Persist an explicit Dock/Float pick. An unavailable store keeps it in memory only. */
304
+ export declare function writeAssistantLayoutChoice(storage: () => Pick<Storage, 'setItem'> | undefined, key: string, choice: AssistantLayoutChoice): void;
305
+ /**
306
+ * The LEGACY dock key (`<prefix>:ai-panel:docked`) as a choice: `"1"` is docked,
307
+ * `"0"` is floating, anything else (absent, unreadable) is no choice.
308
+ *
309
+ * ★ The classic overlay writes `"0"` on mount, so a browser that has run any
310
+ * overlay holds a `"0"` that does not mean "I chose Float". The compact
311
+ * presentation therefore reads it only AFTER its own explicit key, and never
312
+ * writes it (D1-A).
313
+ */
314
+ export declare function readAssistantLegacyDockChoice(storage: () => Pick<Storage, 'getItem'> | undefined, key: string): AssistantLayoutChoice | null;
315
+ /**
316
+ * Docked is the default from this viewport width up (N2, DESIGN-DELTA A2): at
317
+ * 1024 the default sidebar leaves the page 328 px beside a 440 px dock, at 1280
318
+ * it leaves 584. Between 640 and 1279 the default is a floating window.
319
+ */
320
+ export declare const ASSISTANT_COMPACT_DOCKED_MIN_VIEWPORT_PX = 1280;
321
+ /** The media query for `ASSISTANT_COMPACT_DOCKED_MIN_VIEWPORT_PX`. */
322
+ export declare const ASSISTANT_COMPACT_DOCKED_DEFAULT_QUERY = "(min-width: 1280px)";
323
+ /**
324
+ * Is the full assistant docked? D1-A: the person's explicit pick, then the
325
+ * legacy stored `"1"`/`"0"`, then the viewport default (docked from 1280 px).
326
+ * On a phone the answer is irrelevant: every layout class is `sm:`.
327
+ */
328
+ export declare function resolveCompactDocked(input: {
329
+ explicit: AssistantLayoutChoice | null;
330
+ legacy: AssistantLayoutChoice | null;
331
+ wideViewport: boolean;
332
+ }): boolean;
333
+ /** Width of the Quick assistant window on a desktop. Must match `sm:w-[360px]` below. */
334
+ export declare const ASSISTANT_COMPACT_WINDOW_WIDTH_PX = 360;
335
+ /** The window's height ceiling on a desktop. Must match the `600px` in its class below. */
336
+ export declare const ASSISTANT_COMPACT_WINDOW_HEIGHT_PX = 600;
337
+ /**
338
+ * The expanded width, docked or floating (N2): a FIXED 760 px, so the published
339
+ * inset stays a pure constant. Must match `sm:w-[760px]` below.
340
+ */
341
+ export declare const ASSISTANT_COMPACT_EXPANDED_WIDTH_PX = 760;
342
+ /** What a panel's geometry depends on besides the open flag and the viewport. */
343
+ export interface AssistantCompactGeometryInput {
344
+ isOpen: boolean;
345
+ docked: boolean;
346
+ isDesktop: boolean;
347
+ surface: AssistantSurface;
348
+ /** Expand was pressed (the panel only reports it from 1536 px up). */
349
+ expanded: boolean;
350
+ }
351
+ /**
352
+ * The width the docked full panel takes from the page, in px: 440, or 760 when
353
+ * expanded. Nothing for the window, the floating panel, a phone sheet or a
354
+ * closed assistant. A pure constant of its inputs.
355
+ */
356
+ export declare function publishedCompactDockWidth(input: AssistantCompactGeometryInput): number;
357
+ /**
358
+ * How far the open full panel reaches in from the page's right edge, in px:
359
+ * the dock width while docked (440, 760 expanded), the floating width plus its
360
+ * right gap while floating (544, 784 expanded). Nothing is published for the
361
+ * Quick assistant window (it is a small non-modal overlay and the page stays
362
+ * whole), for a phone sheet, or while closed.
363
+ */
364
+ export declare function publishedCompactPanelInset(input: AssistantCompactGeometryInput): number;
365
+ /**
366
+ * Where the window's bottom edge sits: above the launcher. A variable the
367
+ * overlay sets on the container, from the launcher's own bottom offset, so a
368
+ * host that lifts the launcher lifts the window with it. Falls back to 6rem,
369
+ * the classic floating window's anchor.
370
+ */
371
+ export declare const ASSISTANT_WINDOW_BOTTOM_VAR = "--assistant-window-bottom";
372
+ /** The launcher is `size-14` (3.5rem); the window rests 1rem above it. */
373
+ export declare const ASSISTANT_WINDOW_LAUNCHER_CLEARANCE = "4.5rem";
374
+ /** The window's bottom offset for a launcher inset: the launcher's own, plus its size and a gap. */
375
+ export declare function assistantWindowBottom(launcherBottomInset: string): string;
376
+ /**
377
+ * CSS custom properties the overlay sets on the PHONE sheet from the visual
378
+ * viewport (DELTA A5): the height the sheet may use, and how far the on-screen
379
+ * keyboard covers the layout viewport's bottom edge. Set on the container, not
380
+ * on `<html>`: they are the sheet's own, and a keyboard animation writes them
381
+ * on every frame.
382
+ */
383
+ export declare const ASSISTANT_VIEWPORT_HEIGHT_VAR = "--assistant-viewport-height";
384
+ export declare const ASSISTANT_KEYBOARD_INSET_VAR = "--assistant-keyboard-inset";
385
+ /**
386
+ * Shared by every compact surface, on a phone: a full-width bottom sheet with a
387
+ * rounded top edge. ★ No height here (see the heights below), and no surface
388
+ * colour: the window and the panel each name their own, so one class never
389
+ * fights another for the same property.
390
+ *
391
+ * ★ The bottom edge is the LARGER of the tab bar and the keyboard. With the
392
+ * keyboard up the tab bar is behind it, so the sheet rests on the keyboard;
393
+ * without one the inset is 0 and the tab bar wins, as in classic.
394
+ */
395
+ export declare const ASSISTANT_COMPACT_SHEET_BASE_CLASS: string;
396
+ /** The full panel's colours on every viewport: classic's surface and shadow. */
397
+ export declare const ASSISTANT_COMPACT_PANEL_SURFACE_CLASS = "bg-bg-surface shadow-2xl";
398
+ /**
399
+ * The window's colours on every viewport: an elevated surface and the elevation-4
400
+ * shadow.
401
+ *
402
+ * ★ The shadow is read from the TOKEN: `--shadow-elevation-4` is a `:root` custom
403
+ * property with no `@theme` entry, so `shadow-elevation-4` is not a utility and
404
+ * would paint nothing. The arbitrary-value form is how the other call sites read
405
+ * `--shadow-focus`.
406
+ */
407
+ export declare const ASSISTANT_COMPACT_WINDOW_SURFACE_CLASS = "bg-bg-elevated shadow-[var(--shadow-elevation-4)]";
408
+ /**
409
+ * Phone sheet heights, in `dvh` and capped by the visual viewport (DELTA A5 a):
410
+ * the sheet never grows taller than what the keyboard leaves, so the composer
411
+ * and Stop stay on screen and only the message list gives way. The window
412
+ * opens at about 62 %, the full panel at 60 %; either expands to 88 %.
413
+ */
414
+ export declare const ASSISTANT_COMPACT_SHEET_WINDOW_CLASS = "h-[62dvh] max-h-[min(62dvh,var(--assistant-viewport-height,100dvh))]";
415
+ export declare const ASSISTANT_COMPACT_SHEET_PANEL_CLASS = "h-[60dvh] max-h-[min(60dvh,var(--assistant-viewport-height,100dvh))]";
416
+ export declare const ASSISTANT_COMPACT_SHEET_EXPANDED_CLASS = "h-[88dvh] max-h-[min(88dvh,var(--assistant-viewport-height,100dvh))]";
417
+ /**
418
+ * Desktop: the Quick assistant window. 360 wide, `min(600px, 100dvh − header −
419
+ * launcher area)` tall, resting above the launcher; non-modal (no scrim).
420
+ */
421
+ export declare const ASSISTANT_COMPACT_WINDOW_DESKTOP_CLASS: string;
422
+ /** Desktop: the docked full panel, 440 wide. */
423
+ export declare const ASSISTANT_COMPACT_DOCKED_DESKTOP_CLASS: string;
424
+ /** Desktop: the docked full panel, expanded to a fixed 760. */
425
+ export declare const ASSISTANT_COMPACT_DOCKED_EXPANDED_DESKTOP_CLASS: string;
426
+ /** Desktop: the floating full panel, 520 × 680 clamped to the viewport, as classic. */
427
+ export declare const ASSISTANT_COMPACT_FLOATING_DESKTOP_CLASS: string;
428
+ /**
429
+ * Desktop: the floating full panel, expanded: a fixed 760 wide and `viewport −
430
+ * header − 48px` tall, so it keeps 24 px under the header and 24 px above the
431
+ * bottom edge. The launcher is hidden while the full panel is open (L1), so
432
+ * nothing needs the room it would have kept.
433
+ */
434
+ export declare const ASSISTANT_COMPACT_FLOATING_EXPANDED_DESKTOP_CLASS: string;
435
+ /**
436
+ * The container's class for the compact presentation.
437
+ *
438
+ * ★★ Like the classic one, every axis selects a CLASS on ONE persistent
439
+ * element, never a mount: surface, minimized, dock, float, sheet and expanded.
440
+ * A minimized window keeps its element (and the panel inside it) and only stops
441
+ * being displayed.
442
+ *
443
+ * @param sheetExpanded the phone sheet is raised from its grab handle (88 %)
444
+ * @param expanded the panel is Expanded to a fixed 760 px (desktop)
445
+ */
446
+ export declare function assistantCompactOverlayClassName(input: {
447
+ surface: AssistantSurface;
448
+ minimized: boolean;
449
+ docked: boolean;
450
+ expanded: boolean;
451
+ sheetExpanded: boolean;
452
+ }): string;
453
+ /**
454
+ * Does the launcher show? Classic hides it on a phone while the assistant is
455
+ * open. The compact presentation hides it at ALL widths while the full panel is
456
+ * open (L1, the header button is the way back), and on a phone while the window
457
+ * is open (the sheet would be painted over by it). A minimized window shows it:
458
+ * it is the way back in.
459
+ */
460
+ export declare function assistantCompactLauncherVisibility(input: {
461
+ isOpen: boolean;
462
+ surface: AssistantSurface;
463
+ minimized: boolean;
464
+ }): 'always' | 'desktop-only' | 'hidden';
465
+ /**
466
+ * The visual viewport, reduced to what the sheet needs. The keyboard inset is how
467
+ * far the on-screen keyboard covers the bottom of the LAYOUT viewport; the
468
+ * height is what is left for the sheet. `scale` guards pinch-zoom: a zoomed
469
+ * visual viewport is smaller than the layout one without any keyboard, and the
470
+ * sheet must not shrink for it.
471
+ */
472
+ export declare function assistantVisualViewportMetrics(input: {
473
+ layoutHeight: number;
474
+ viewportHeight: number;
475
+ viewportOffsetTop: number;
476
+ scale: number;
477
+ }): {
478
+ heightPx: number;
479
+ keyboardInsetPx: number;
480
+ };
257
481
  export interface AssistantNavigateOptions {
258
482
  /** The product router's navigate, e.g. React Router's `useNavigate()`. */
259
483
  navigate: (path: string) => void;
@@ -16,48 +16,135 @@ function r(e, t) {
16
16
  return t ?? !e;
17
17
  }
18
18
  var i = "Ctrl+Shift+A";
19
- function a(e) {
19
+ function ee(e) {
20
20
  return (e.ctrlKey || e.metaKey) && e.shiftKey && typeof e.key == "string" && e.key.toLowerCase() === "a";
21
21
  }
22
- var o = "[role=\"dialog\"],[role=\"alertdialog\"],dialog[open]";
23
- function s(e, t) {
24
- return c(e) ? e.closest(t) : null;
22
+ var te = "[role=\"dialog\"],[role=\"alertdialog\"],dialog[open]";
23
+ function ne(e, t) {
24
+ return a(e) ? e.closest(t) : null;
25
25
  }
26
- function c(e) {
26
+ function a(e) {
27
27
  return typeof e == "object" && !!e && "closest" in e && typeof e.closest == "function";
28
28
  }
29
- function l(e) {
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
- var u = "max(var(--mobile-tabbar-height, 0px), var(--safe-bottom, 0px), env(safe-area-inset-bottom, 0px))";
33
- function d(e) {
34
- return `calc(${e} + ${u})`;
32
+ var s = "max(var(--mobile-tabbar-height, 0px), var(--safe-bottom, 0px), env(safe-area-inset-bottom, 0px))";
33
+ function c(e) {
34
+ return `calc(${e} + ${s})`;
35
35
  }
36
- var f = "--assistant-launcher-lift";
37
- function p(e) {
38
- return `calc(var(${f}, 0px) + ${d(e)})`;
36
+ var l = "--assistant-launcher-lift";
37
+ function u(e) {
38
+ return `calc(var(${l}, 0px) + ${c(e)})`;
39
39
  }
40
- var m = "1.5rem";
41
- function h(e) {
42
- return e > 0 ? `calc(${m} + ${e}px)` : m;
40
+ var d = "1.5rem";
41
+ function f(e) {
42
+ return e > 0 ? `calc(${d} + ${e}px)` : d;
43
43
  }
44
- var g = 440, _ = "--assistant-dock-width", v = "--assistant-sheet-bottom", y = "--assistant-overlay-top", b = 56, x = "(min-width: 640px)";
45
- function S(e) {
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 C = 520, w = 24, T = "--assistant-panel-inset";
49
- function E(e) {
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 D = "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", O = "h-[60vh] max-h-[60vh]", k = "h-[88vh] max-h-[88vh]", A = "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)]", j = "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 M(e) {
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
+ return [
55
+ h,
56
+ e.expanded ? _ : g,
57
+ e.docked ? y : v
58
+ ].join(" ");
59
+ }
60
+ function x(e) {
61
+ return e === "window" || e === "panel";
62
+ }
63
+ function S(e) {
64
+ return e === "chat" || e === "voice";
65
+ }
66
+ function C(e) {
67
+ return {
68
+ layoutStorageKey: `${e}:ai-panel:layout`,
69
+ surfaceStorageKey: `${e}:ai-panel:surface`,
70
+ minimizedStorageKey: `${e}:ai-panel:minimized`,
71
+ windowViewStorageKey: `${e}:ai-panel:window-view`
72
+ };
73
+ }
74
+ function w(e, t) {
75
+ try {
76
+ let n = e()?.getItem(t);
77
+ return n === "docked" || n === "floating" ? n : null;
78
+ } catch {
79
+ return null;
80
+ }
81
+ }
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) {
96
+ try {
97
+ e()?.setItem(t, n);
98
+ } catch {}
99
+ }
100
+ function O(e, t) {
101
+ try {
102
+ let n = e()?.getItem(t);
103
+ return n === "1" ? "docked" : n === "0" ? "floating" : null;
104
+ } catch {
105
+ return null;
106
+ }
107
+ }
108
+ var k = 1280, A = `(min-width: ${k}px)`;
109
+ function j(e) {
110
+ let t = e.explicit ?? e.legacy;
111
+ return t === null ? e.wideViewport : t === "docked";
112
+ }
113
+ var M = 360, N = 600, P = 760;
114
+ function F(e) {
115
+ return !e.isOpen || !e.isDesktop || e.surface !== "panel" || !e.docked ? 0 : e.expanded ? 760 : 440;
116
+ }
117
+ function I(e) {
118
+ if (!e.isOpen || !e.isDesktop || e.surface !== "panel") return 0;
119
+ let t = e.expanded ? 760 : e.docked ? 440 : 520;
120
+ return e.docked ? t : t + 24;
121
+ }
122
+ var L = "--assistant-window-bottom", R = "4.5rem";
123
+ function z(e) {
124
+ return `calc(${u(e)} + ${R})`;
125
+ }
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) {
128
+ if (e.minimized) return "hidden";
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;
54
130
  return [
55
- D,
56
- e.expanded ? k : O,
57
- e.docked ? j : A
131
+ H,
132
+ t ? W : U,
133
+ n,
134
+ r
58
135
  ].join(" ");
59
136
  }
60
- function N(t) {
137
+ function pe(e) {
138
+ return !e.isOpen || e.minimized ? "always" : e.surface === "panel" ? "hidden" : "desktop-only";
139
+ }
140
+ function me(e) {
141
+ let t = e.scale > 1.01, n = e.layoutHeight - e.viewportHeight - e.viewportOffsetTop, r = t ? 0 : Math.max(0, Math.round(n));
142
+ return {
143
+ heightPx: Math.max(0, Math.round(t ? e.layoutHeight : e.viewportHeight)),
144
+ keyboardInsetPx: r
145
+ };
146
+ }
147
+ function he(t) {
61
148
  return (n, r) => {
62
149
  if (t.isShellLessTarget?.(n)) return t.openInNewTab(n), { kind: "new-tab" };
63
150
  let i = e(r);
@@ -68,22 +155,22 @@ function N(t) {
68
155
  } : (t.navigate(n), t.isDesktop() || t.collapseSheet(), { kind: "routed" });
69
156
  };
70
157
  }
71
- function P(e) {
158
+ function ge(e) {
72
159
  if (typeof CustomEvent > "u" || !(e instanceof CustomEvent)) return "generic";
73
160
  let t = e.detail;
74
161
  return typeof t != "object" || !t || !("kind" in t) ? "generic" : t.kind === "sandbox" || t.kind === "ai-credits" ? t.kind : "generic";
75
162
  }
76
- function F(e, t) {
163
+ function $(e, t) {
77
164
  try {
78
165
  return e()?.getItem(t) === "1";
79
166
  } catch {
80
167
  return !1;
81
168
  }
82
169
  }
83
- function I(e, t, n) {
170
+ function _e(e, t, n) {
84
171
  try {
85
172
  e()?.setItem(t, n ? "1" : "0");
86
173
  } catch {}
87
174
  }
88
175
  //#endregion
89
- export { u as ASSISTANT_BOTTOM_CHROME_CLEARANCE, o as ASSISTANT_DIALOG_SELECTOR, j as ASSISTANT_DOCKED_DESKTOP_CLASS, g as ASSISTANT_DOCK_WIDTH_PX, _ as ASSISTANT_DOCK_WIDTH_VAR, A as ASSISTANT_FLOATING_DESKTOP_CLASS, w as ASSISTANT_FLOATING_RIGHT_PX, C as ASSISTANT_FLOATING_WIDTH_PX, f as ASSISTANT_LAUNCHER_LIFT_VAR, m as ASSISTANT_LAUNCHER_RIGHT_INSET, b as ASSISTANT_OVERLAY_DEFAULT_TOP_PX, x as ASSISTANT_OVERLAY_DESKTOP_QUERY, y as ASSISTANT_OVERLAY_TOP_VAR, T as ASSISTANT_PANEL_INSET_VAR, D as ASSISTANT_SHEET_BASE_CLASS, v as ASSISTANT_SHEET_BOTTOM_VAR, O as ASSISTANT_SHEET_COMPACT_CLASS, k as ASSISTANT_SHEET_EXPANDED_CLASS, i as ASSISTANT_TOGGLE_SHORTCUT_LABEL, d as aboveAssistantBottomChrome, p as assistantLauncherBottom, h as assistantLauncherRight, M as assistantOverlayClassName, l as assistantOverlayEscapeAction, t as assistantOverlayKeys, P as assistantQuotaKindOf, s as closestAround, N as createAssistantNavigate, a as isAssistantToggleShortcut, r as nextAssistantOpenState, S as publishedAssistantDockWidth, E as publishedAssistantPanelInset, F as readAssistantOverlayFlag, n as requestedAssistantOpenState, I as writeAssistantOverlayFlag };
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, DropdownMenuLabel as r, DropdownMenuTrigger as i } from "../../../../ui/dropdown-menu.js";
2
- import { focusWasDropped as a } from "../../../hooks/useReturnFocus.js";
3
- import { getAssistantControl as o, hasAssistantControl as s, subscribeAssistantControls as c } from "../../appControls/registry.js";
4
- import { useAssistantTr as l } from "../../i18n.js";
5
- import { useAssistantStore as u } from "../../store.js";
6
- import { voiceTurnsOnly as d } from "../../voice/turnVisibility.js";
7
- import { downloadFile as f, exportConversation as p } from "../../exportConversation.js";
8
- import { useCallback as m, useSyncExternalStore as h } from "react";
9
- import { FileJson as g, FileText as _, Mic as v, MoreHorizontal as y } from "lucide-react";
10
- import { Fragment as b, jsx as x, jsxs as S } from "react/jsx-runtime";
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 C = "min-h-11 gap-2.5 px-3", w = ({ open: w, onOpenChange: T, triggerRef: E }) => {
13
- let D = l(), { conversations: O, activeConversationId: k, processingByConversationId: A } = u(), j = O.find((e) => e.id === k), M = !!(j && j.messages.length > 0), N = !!(h(c, () => s("assistant.transcript"), () => !1) && j && d(j.messages).length > 0), P = (e) => {
14
- if (!j) return;
15
- let { content: t, filename: n, mimeType: r } = p(j, e, {
16
- processing: A[j.id],
17
- tr: D
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
- f(t, n, r);
20
- }, F = () => {
21
- o("assistant.transcript")?.run();
22
- }, I = m((e) => {
23
- a(document) || e.preventDefault();
24
- }, []), L = D("header.conversationOptions", "Conversation options");
25
- return /* @__PURE__ */ S(e, {
26
- open: w,
27
- onOpenChange: T,
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__ */ x(i, {
29
+ children: [/* @__PURE__ */ b(r, {
30
30
  asChild: !0,
31
- children: /* @__PURE__ */ x("button", {
32
- ref: E,
31
+ children: /* @__PURE__ */ b("button", {
32
+ ref: T,
33
33
  type: "button",
34
- "aria-label": L,
35
- title: L,
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__ */ x(y, {
38
+ children: /* @__PURE__ */ b(v, {
39
39
  className: "size-5",
40
40
  "aria-hidden": "true"
41
41
  })
42
42
  })
43
- }), /* @__PURE__ */ S(t, {
43
+ }), /* @__PURE__ */ x(t, {
44
44
  align: "end",
45
45
  sideOffset: 4,
46
46
  collisionPadding: 8,
47
- onCloseAutoFocus: I,
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
- M ? /* @__PURE__ */ S(b, { children: [/* @__PURE__ */ S(n, {
52
- className: C,
53
- onSelect: () => P("markdown"),
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__ */ x(_, {
55
+ children: [/* @__PURE__ */ b(g, {
56
56
  className: "size-4 shrink-0 text-text-secondary",
57
57
  "aria-hidden": "true"
58
- }), D("export.markdown", "Export as Markdown")]
59
- }), /* @__PURE__ */ S(n, {
60
- className: C,
61
- onSelect: () => P("json"),
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__ */ x(g, {
63
+ children: [/* @__PURE__ */ b(h, {
64
64
  className: "size-4 shrink-0 text-text-secondary",
65
65
  "aria-hidden": "true"
66
- }), D("export.json", "Export as JSON")]
66
+ }), E("export.json", "Export as JSON")]
67
67
  })] }) : null,
68
- N ? /* @__PURE__ */ S(n, {
69
- className: C,
70
- onSelect: F,
68
+ M ? /* @__PURE__ */ x(n, {
69
+ className: S,
70
+ onSelect: P,
71
71
  "data-testid": "assistant-more-voice-transcript",
72
- children: [/* @__PURE__ */ x(v, {
72
+ children: [/* @__PURE__ */ b(_, {
73
73
  className: "size-4 shrink-0 text-text-secondary",
74
74
  "aria-hidden": "true"
75
- }), D("conversationMenu.voiceTranscript", "Voice transcript")]
75
+ }), E("conversationMenu.voiceTranscript", "Voice transcript")]
76
76
  }) : null,
77
- !M && !N ? /* @__PURE__ */ x(r, {
78
- className: "px-3 py-2 text-sm font-normal text-text-secondary",
77
+ !j && !M ? /* @__PURE__ */ b(n, {
78
+ disabled: !0,
79
+ className: `${S} text-text-secondary`,
79
80
  "data-testid": "assistant-more-empty",
80
- children: D("conversationMenu.empty", "Nothing to export yet")
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 { w as AssistantConversationMenu };
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: /* @__PURE__ */ a("p", {
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>;