@burdenoff/fe-libs 2026.1023.15 → 2026.1023.16

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.
@@ -4,39 +4,39 @@ import { useCallback as n, useEffect as r, useId as i, useRef as a, useSyncExter
4
4
  import { Video as s, VideoOff as c, Volume2 as l } from "lucide-react";
5
5
  import { jsx as u, jsxs as d } from "react/jsx-runtime";
6
6
  //#region src/shared/assistant/avatar/live/LiveAvatarStage.tsx
7
- var f = "inline-flex h-8 items-center gap-1.5 rounded-full border border-border-default bg-bg-elevated px-3 text-xs font-medium text-text-secondary transition-colors hover:bg-bg-raised hover:text-text-primary focus:outline-none focus-visible:ring-2 focus-visible:ring-border-strong aria-disabled:cursor-default aria-disabled:opacity-60", p = "inline-flex h-8 cursor-pointer items-center gap-1.5 rounded-full border px-3 text-xs font-medium transition-colors focus-within:ring-2 focus-within:ring-border-strong", m = "inline-flex h-8 items-center rounded-full bg-action-primary-bg px-3 text-xs font-medium text-action-primary-text transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-border-strong", h = ({ controller: h, expanded: g, fallback: _, avatarNames: v }) => {
8
- let y = e(), b = i(), x = i(), S = a(null), C = a(null), w = n((e) => {
7
+ var f = "inline-flex h-8 items-center gap-1.5 rounded-full border border-border-default bg-bg-elevated px-3 text-xs font-medium text-text-secondary transition-colors hover:bg-bg-raised hover:text-text-primary focus:outline-none focus-visible:ring-2 focus-visible:ring-border-strong aria-disabled:cursor-default aria-disabled:opacity-60", p = "inline-flex h-8 cursor-pointer items-center gap-1.5 rounded-full border px-3 text-xs font-medium transition-colors focus-within:ring-2 focus-within:ring-border-strong", m = "inline-flex h-8 items-center rounded-full bg-action-primary-bg px-3 text-xs font-medium text-action-primary-text transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-border-strong aria-disabled:cursor-default aria-disabled:opacity-60", h = ({ controller: h, expanded: g, fallback: _, avatarNames: v }) => {
8
+ let y = e(), b = i(), x = i(), S = i(), C = a(null), w = a(null), T = n((e) => {
9
9
  e?.focus();
10
- }, []), T = n((e) => (C.current = e, () => {
11
- C.current = null, document.activeElement === e && S.current?.focus();
12
- }), []), E = o(h.subscribe, h.getSnapshot, h.getSnapshot);
10
+ }, []), E = n((e) => (w.current = e, () => {
11
+ w.current = null, document.activeElement === e && C.current?.focus();
12
+ }), []), D = o(h.subscribe, h.getSnapshot, h.getSnapshot);
13
13
  r(() => (h.setStageMounted(!0), () => h.setStageMounted(!1)), [h]);
14
- let { phase: D } = E, O = D === "starting" || D === "connecting" || D === "ready" || D === "ending", k = D === "checking" || D === "ending", A = t(E, y), j = (e, t) => v?.[e] ?? `${y.chooserLabel} ${t + 1}`;
14
+ let { phase: O } = D, k = O === "starting" || O === "connecting" || O === "ready" || O === "ending", A = O === "checking" || O === "ending", j = Date.now(), M = D.retryAt !== null && D.retryAt > j, N = t(D, y, j), P = (e, t) => v?.[e] ?? `${y.chooserLabel} ${t + 1}`;
15
15
  return /* @__PURE__ */ d("div", {
16
- ref: S,
16
+ ref: C,
17
17
  tabIndex: -1,
18
18
  className: "flex flex-col items-center gap-2 focus:outline-none",
19
19
  "data-testid": "assistant-live-avatar",
20
20
  children: [
21
- O ? /* @__PURE__ */ d("div", {
21
+ k ? /* @__PURE__ */ d("div", {
22
22
  className: `relative overflow-hidden rounded-2xl border border-border-subtle bg-bg-sunken ${g ? "size-64" : "size-40"}`,
23
23
  "data-testid": "assistant-live-avatar-frame",
24
- "data-phase": D,
24
+ "data-phase": O,
25
25
  children: [
26
26
  /* @__PURE__ */ u("video", {
27
27
  ref: h.attachVideo,
28
- className: `size-full object-cover ${E.videoReady ? "" : "invisible"}`,
28
+ className: `size-full object-cover ${D.videoReady ? "" : "invisible"}`,
29
29
  "aria-label": y.stageLabel,
30
30
  autoPlay: !0,
31
31
  muted: !0,
32
32
  playsInline: !0,
33
33
  "data-testid": "assistant-live-avatar-video"
34
34
  }),
35
- E.videoReady ? null : /* @__PURE__ */ u("p", {
35
+ D.videoReady ? null : /* @__PURE__ */ u("p", {
36
36
  className: "absolute inset-0 flex items-center justify-center p-3 text-center text-xs text-text-muted",
37
- children: D === "ending" ? y.stateEnding : D === "connecting" ? y.stageWaiting : y.stateStarting
37
+ children: O === "ending" ? y.stateEnding : O === "connecting" ? y.stageWaiting : y.stateStarting
38
38
  }),
39
- E.audioBlocked ? /* @__PURE__ */ d("button", {
39
+ D.audioBlocked ? /* @__PURE__ */ d("button", {
40
40
  type: "button",
41
41
  onClick: () => h.resumeAudio(),
42
42
  className: "absolute inset-x-2 bottom-2 inline-flex items-center justify-center gap-1.5 rounded-xl bg-bg-elevated px-2 py-1.5 text-xs font-medium text-text-primary focus:outline-none focus-visible:ring-2 focus-visible:ring-border-strong",
@@ -48,23 +48,23 @@ var f = "inline-flex h-8 items-center gap-1.5 rounded-full border border-border-
48
48
  }) : null
49
49
  ]
50
50
  }) : _,
51
- E.offered || O ? /* @__PURE__ */ d("button", {
52
- ref: T,
51
+ D.offered || k ? /* @__PURE__ */ d("button", {
52
+ ref: E,
53
53
  type: "button",
54
54
  onClick: () => {
55
- k || (O ? h.switchOff() : D === "choosing" ? h.cancelChoice() : h.requestOn());
55
+ A || (k ? h.switchOff() : O === "choosing" ? h.cancelChoice() : h.requestOn());
56
56
  },
57
57
  className: f,
58
- "aria-pressed": O,
58
+ "aria-pressed": k,
59
59
  title: y.toggleHint,
60
- "aria-disabled": k,
60
+ "aria-disabled": A,
61
61
  "data-testid": "assistant-live-avatar-toggle",
62
- children: [u(O ? c : s, {
62
+ children: [u(k ? c : s, {
63
63
  className: "size-4",
64
64
  "aria-hidden": "true"
65
65
  }), /* @__PURE__ */ u("span", { children: y.toggle })]
66
66
  }) : null,
67
- D === "choosing" ? /* @__PURE__ */ d("fieldset", {
67
+ O === "choosing" ? /* @__PURE__ */ d("fieldset", {
68
68
  className: "flex max-w-xs flex-col gap-2 rounded-xl border border-border-default bg-bg-elevated p-3 text-start",
69
69
  "data-testid": "assistant-live-avatar-consent",
70
70
  children: [
@@ -72,20 +72,20 @@ var f = "inline-flex h-8 items-center gap-1.5 rounded-full border border-border-
72
72
  className: "sr-only",
73
73
  children: y.toggle
74
74
  }),
75
- E.avatars.length > 1 ? /* @__PURE__ */ d("fieldset", {
75
+ D.avatars.length > 1 ? /* @__PURE__ */ d("fieldset", {
76
76
  className: "flex flex-wrap gap-1.5",
77
77
  "data-testid": "assistant-live-avatar-chooser",
78
78
  children: [/* @__PURE__ */ u("legend", {
79
79
  className: "sr-only",
80
80
  children: y.chooserTitle
81
- }), E.avatars.map((e, t) => {
82
- let n = e === E.selectedAvatarId, r = j(e, t);
81
+ }), D.avatars.map((e, t) => {
82
+ let n = e === D.selectedAvatarId, r = P(e, t);
83
83
  return /* @__PURE__ */ d("label", {
84
84
  className: `${p} ${n ? "border-transparent bg-action-primary-bg text-action-primary-text" : "border-border-default bg-bg-elevated text-text-secondary hover:bg-bg-raised hover:text-text-primary"}`,
85
85
  title: n ? y.chooserSelected(r) : y.chooserOption(r),
86
86
  children: [/* @__PURE__ */ u("input", {
87
87
  type: "radio",
88
- name: x,
88
+ name: S,
89
89
  value: e,
90
90
  checked: n,
91
91
  onChange: () => h.selectAvatar(e),
@@ -96,7 +96,7 @@ var f = "inline-flex h-8 items-center gap-1.5 rounded-full border border-border-
96
96
  })]
97
97
  }) : null,
98
98
  /* @__PURE__ */ u("p", {
99
- ref: w,
99
+ ref: T,
100
100
  id: b,
101
101
  tabIndex: -1,
102
102
  className: "text-xs text-text-secondary focus:outline-none",
@@ -108,18 +108,19 @@ var f = "inline-flex h-8 items-center gap-1.5 rounded-full border border-border-
108
108
  children: [/* @__PURE__ */ u("button", {
109
109
  type: "button",
110
110
  onClick: () => {
111
- C.current?.focus(), h.cancelChoice();
111
+ w.current?.focus(), h.cancelChoice();
112
112
  },
113
113
  className: f,
114
114
  children: y.consentCancel
115
115
  }), /* @__PURE__ */ u("button", {
116
116
  type: "button",
117
117
  onClick: () => {
118
- C.current?.focus(), h.confirm();
118
+ M || (w.current?.focus(), h.confirm());
119
119
  },
120
- "aria-describedby": b,
120
+ "aria-describedby": M ? `${b} ${x}` : b,
121
+ "aria-disabled": M,
121
122
  className: m,
122
- disabled: E.selectedAvatarId === null,
123
+ disabled: D.selectedAvatarId === null,
123
124
  "data-testid": "assistant-live-avatar-confirm",
124
125
  children: y.consentConfirm
125
126
  })]
@@ -127,10 +128,11 @@ var f = "inline-flex h-8 items-center gap-1.5 rounded-full border border-border-
127
128
  ]
128
129
  }) : null,
129
130
  /* @__PURE__ */ u("p", {
130
- className: A === null ? "sr-only" : "max-w-xs text-center text-xs text-text-muted",
131
+ id: x,
132
+ className: N === null ? "sr-only" : "max-w-xs text-center text-xs text-text-muted",
131
133
  role: "status",
132
134
  "data-testid": "assistant-live-avatar-status",
133
- children: A ?? ""
135
+ children: N ?? ""
134
136
  })
135
137
  ]
136
138
  });
@@ -4,10 +4,10 @@ import { useAssistantSpeech as ee } from "../../ui/AssistantSpeechProvider.js";
4
4
  import { resolveAvatarVoiceMode as te } from "../avatarPreferences.js";
5
5
  import "./liveAvatarController.js";
6
6
  import { liveAvatarStatusText as ne } from "./liveAvatarStatus.js";
7
- import { AvatarFace as r } from "./AvatarFace.js";
8
- import { hostedAvatarVoice as i } from "./avatarVoice.js";
9
- import { useCallback as a, useEffect as o, useId as s, useLayoutEffect as re, useRef as c, useState as l, useSyncExternalStore as u } from "react";
10
- import { Volume2 as ie } from "lucide-react";
7
+ import { AvatarFace as re } from "./AvatarFace.js";
8
+ import { hostedAvatarVoice as r } from "./avatarVoice.js";
9
+ import { useCallback as i, useEffect as a, useId as o, useLayoutEffect as ie, useRef as s, useState as c, useSyncExternalStore as l } from "react";
10
+ import { Volume2 as u } from "lucide-react";
11
11
  import { jsx as d, jsxs as f } from "react/jsx-runtime";
12
12
  //#region src/shared/assistant/avatar/live/LiveAvatarTabView.tsx
13
13
  var p = "mine", m = "paired", h = "speaker:", g = /-Chirp3-HD-([A-Za-z]+)$/;
@@ -17,17 +17,17 @@ function _(e) {
17
17
  }
18
18
  function v(e, t) {
19
19
  let n = t.find((e) => e.source === "hosted")?.lang;
20
- return n === void 0 ? null : i(e, n, t);
20
+ return n === void 0 ? null : r(e, n, t);
21
21
  }
22
- var y = "text-xs font-medium text-text-secondary", b = "text-xs text-text-muted", x = "focus:outline-none focus-visible:ring-2 focus-visible:ring-border-strong", S = `inline-flex min-h-11 w-full items-center justify-center gap-2 rounded-xl border border-border-default bg-bg-elevated px-4 text-sm font-medium text-text-primary transition-colors hover:bg-bg-raised aria-disabled:cursor-default aria-disabled:opacity-60 aria-disabled:hover:bg-bg-elevated ${x}`, ae = `inline-flex min-h-11 w-full items-center justify-center rounded-xl bg-action-primary-bg px-4 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg-hover aria-disabled:cursor-default aria-disabled:opacity-60 aria-disabled:hover:bg-action-primary-bg ${x}`, oe = "relative inline-flex min-h-11 min-w-0 max-w-full cursor-pointer items-center gap-2 rounded-full border ps-1.5 pe-4 text-sm font-medium transition-colors focus-within:ring-2 focus-within:ring-border-strong", se = "absolute inset-0 m-0 size-full cursor-pointer appearance-none rounded-full opacity-0", C = ({ controller: i, shown: g, voice: C, handsFreeOff: ce, leaveHintId: le, startVoiceRef: ue, askLine: w, avatarNames: de, avatarImages: fe, avatarVoices: pe, defaultAvatarVoiceMode: me, voiceStore: T, now: E = Date.now }) => {
23
- let D = n(), O = ee(), k = s(), he = s(), A = s(), j = s(), M = s(), N = c(null), P = u(i.subscribe, i.getSnapshot, i.getSnapshot), F = u(T.subscribe, T.getState, T.getState);
24
- o(() => {
25
- if (g) return i.setStageMounted(!0), () => i.setStageMounted(!1);
26
- }, [i, g]), o(() => {
27
- let e = i.getSnapshot();
28
- e.phase === "off" && e.avatars.length === 0 && i.requestOn({ start: !1 });
29
- }, [i]);
30
- let { phase: I } = P, L = I === "starting" || I === "connecting" || I === "ready" || I === "ending", [R, z] = l(!1);
22
+ var y = "text-xs font-medium text-text-secondary", b = "text-xs text-text-muted", x = "focus:outline-none focus-visible:ring-2 focus-visible:ring-border-strong", S = `inline-flex min-h-11 w-full items-center justify-center gap-2 rounded-xl border border-border-default bg-bg-elevated px-4 text-sm font-medium text-text-primary transition-colors hover:bg-bg-raised aria-disabled:cursor-default aria-disabled:opacity-60 aria-disabled:hover:bg-bg-elevated ${x}`, ae = `inline-flex min-h-11 w-full items-center justify-center rounded-xl bg-action-primary-bg px-4 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg-hover aria-disabled:cursor-default aria-disabled:opacity-60 aria-disabled:hover:bg-action-primary-bg ${x}`, oe = "relative inline-flex min-h-11 min-w-0 max-w-full cursor-pointer items-center gap-2 rounded-full border ps-1.5 pe-4 text-sm font-medium transition-colors focus-within:ring-2 focus-within:ring-border-strong", se = "absolute inset-0 m-0 size-full cursor-pointer appearance-none rounded-full opacity-0", C = ({ controller: r, shown: g, voice: C, handsFreeOff: ce, leaveHintId: le, startVoiceRef: ue, askLine: w, avatarNames: de, avatarImages: fe, avatarVoices: pe, defaultAvatarVoiceMode: me, voiceStore: T, now: E = Date.now }) => {
23
+ let D = n(), O = ee(), k = o(), he = o(), A = o(), j = o(), M = o(), N = s(null), P = l(r.subscribe, r.getSnapshot, r.getSnapshot), F = l(T.subscribe, T.getState, T.getState);
24
+ a(() => {
25
+ if (g) return r.setStageMounted(!0), () => r.setStageMounted(!1);
26
+ }, [r, g]), a(() => {
27
+ let e = r.getSnapshot();
28
+ e.phase === "off" && e.avatars.length === 0 && r.requestOn({ start: !1 });
29
+ }, [r]);
30
+ let { phase: I } = P, L = I === "starting" || I === "connecting" || I === "ready" || I === "ending", [R, z] = c(!1);
31
31
  R && (I === "off" || I === "choosing" || I === "ready" || I === "ending") && z(!1);
32
32
  let B = E(), ge = P.retryAt !== null && P.retryAt > B, V = ne(P, D, B), H = P.selectedAvatarId, U = (e) => {
33
33
  let t = P.avatars.indexOf(e);
@@ -35,11 +35,11 @@ var y = "text-xs font-medium text-text-secondary", b = "text-xs text-text-muted"
35
35
  }, W = I === "ready" ? { kind: "turn-off" } : I === "ending" ? { kind: "ending" } : R || I === "starting" || I === "connecting" ? { kind: "starting" } : P.offered ? {
36
36
  kind: "turn-on",
37
37
  ready: !ge && H !== null && (I === "choosing" || I === "off" && P.avatars.includes(H))
38
- } : null, G = c(null), K = W?.kind === "turn-off";
39
- re(() => {
38
+ } : null, G = s(null), K = W?.kind === "turn-off";
39
+ ie(() => {
40
40
  G.current = K ? E() : null;
41
41
  }, [K, E]);
42
- let _e = a((e) => {
42
+ let _e = i((e) => {
43
43
  if (e !== null) return () => {
44
44
  e.ownerDocument.activeElement === e && N.current?.focus();
45
45
  };
@@ -47,7 +47,7 @@ var y = "text-xs font-medium text-text-secondary", b = "text-xs text-text-muted"
47
47
  if (W !== null) switch (W.kind) {
48
48
  case "turn-on":
49
49
  if (!W.ready || H === null) return;
50
- z(!0), I === "choosing" ? i.confirm() : i.requestOn({
50
+ z(!0), I === "choosing" ? r.confirm() : r.requestOn({
51
51
  start: !0,
52
52
  avatarId: H
53
53
  });
@@ -55,26 +55,26 @@ var y = "text-xs font-medium text-text-secondary", b = "text-xs text-text-muted"
55
55
  case "turn-off": {
56
56
  let e = G.current;
57
57
  if (e !== null && E() - e < 1e3) return;
58
- i.switchOff();
58
+ r.switchOff();
59
59
  return;
60
60
  }
61
61
  case "starting":
62
62
  case "ending": return;
63
63
  }
64
- }, q = te(F, me), J = H === null ? null : pe.get(H) ?? null, Y = q === "speaker" && F.avatarSpeaker !== null ? `${h}${F.avatarSpeaker}` : q === "paired" && J !== null ? m : p, ye = Y === m ? J : Y.startsWith(h) ? F.avatarSpeaker : null, X = Y === p ? O.activeVoiceName : ye === null ? null : v(ye, O.voiceChoices)?.name ?? null, be = O.speakingMessageId !== null || O.spokenChunks !== null, xe = X !== null && !C.live && !be, Se = O.activeVoiceName ? D.voiceModeMineNamed(_(O.activeVoiceName)) : D.voiceModeMine, Ce = (e) => {
64
+ }, ye = te(F, me), q = H === null ? null : pe.get(H) ?? null, J = ye === "speaker" && F.avatarSpeaker !== null ? `${h}${F.avatarSpeaker}` : ye === "paired" && q !== null ? m : p, be = J === m ? q : J.startsWith(h) ? F.avatarSpeaker : null, Y = J === p ? O.activeVoiceName : be === null ? null : v(be, O.voiceChoices)?.name ?? null, xe = O.speakingMessageId !== null || O.spokenChunks !== null, Se = Y !== null && !C.live && !xe, Ce = O.activeVoiceName ? D.voiceModeMineNamed(_(O.activeVoiceName)) : D.voiceModeMine, we = (e) => {
65
65
  if (e === p || e === m) {
66
66
  T.setVoiceMode(e);
67
67
  return;
68
68
  }
69
69
  let n = e.slice(8);
70
70
  e.startsWith(h) && t(n) && T.setAvatarSpeaker(n);
71
- }, we = I === "ending" ? D.stateEnding : I === "connecting" || I === "ready" ? D.stageWaiting : I === "starting" ? D.stateStarting : D.stateOff, [Te, Ee] = l(() => /* @__PURE__ */ new Set()), De = a((e) => {
72
- Ee((t) => t.has(e) ? t : new Set(t).add(e));
73
- }, []), Z = (e) => {
71
+ }, Te = I === "ending" ? D.stateEnding : I === "connecting" || I === "ready" ? D.stageWaiting : I === "starting" ? D.stateStarting : D.stateOff, [Ee, De] = c(() => /* @__PURE__ */ new Set()), Oe = i((e) => {
72
+ De((t) => t.has(e) ? t : new Set(t).add(e));
73
+ }, []), ke = (e) => {
74
74
  let t = fe?.get(e);
75
- return t === void 0 || Te.has(t) ? null : t;
76
- }, Q = !L && H !== null ? Z(H) : null, $ = L ? null : w === void 0 ? C.impossible ? D.askNeedsVoice : null : w === "by-typing" ? D.askByTyping : w === "needs-voice" ? D.askNeedsVoice : w === "nothing" ? D.askNothing : null, Oe = I === "off" && P.avatars.length === 0 && P.problem !== null && P.offered;
77
- return /* @__PURE__ */ f("div", {
75
+ return t === void 0 || Ee.has(t) ? null : t;
76
+ }, X = !L && H !== null ? ke(H) : null, Z = L ? null : w === void 0 ? C.impossible ? D.askNeedsVoice : null : w === "by-typing" ? D.askByTyping : w === "needs-voice" ? D.askNeedsVoice : w === "nothing" ? D.askNothing : null, Ae = I === "off" && P.avatars.length === 0 && P.offered, [Q, je] = c(!1), $ = Ae && (Q || P.problem !== null);
77
+ return $ !== Q && je($), /* @__PURE__ */ f("div", {
78
78
  ref: N,
79
79
  tabIndex: -1,
80
80
  className: "flex min-h-full shrink-0 flex-col gap-3 focus:outline-none",
@@ -88,7 +88,7 @@ var y = "text-xs font-medium text-text-secondary", b = "text-xs text-text-muted"
88
88
  "data-phase": I,
89
89
  children: [
90
90
  L ? /* @__PURE__ */ d("video", {
91
- ref: i.attachVideo,
91
+ ref: r.attachVideo,
92
92
  className: `size-full object-cover ${P.videoReady ? "" : "invisible"}`,
93
93
  "aria-label": D.stageLabel,
94
94
  autoPlay: !0,
@@ -96,23 +96,23 @@ var y = "text-xs font-medium text-text-secondary", b = "text-xs text-text-muted"
96
96
  playsInline: !0,
97
97
  "data-testid": "assistant-avatar-tab-video"
98
98
  }) : null,
99
- Q !== null && H !== null ? /* @__PURE__ */ d(r, {
99
+ X !== null && H !== null ? /* @__PURE__ */ d(re, {
100
100
  size: "frame",
101
101
  name: U(H),
102
- src: Q,
103
- onError: De
102
+ src: X,
103
+ onError: Oe
104
104
  }) : null,
105
105
  L && P.videoReady ? null : /* @__PURE__ */ d("p", {
106
- className: Q === null ? "absolute inset-0 flex items-center justify-center p-3 text-center text-sm text-text-secondary" : "absolute inset-x-0 bottom-0 bg-bg-elevated/90 px-3 py-1.5 text-center text-xs text-text-secondary",
106
+ className: X === null ? "absolute inset-0 flex items-center justify-center p-3 text-center text-sm text-text-secondary" : "absolute inset-x-0 bottom-0 bg-bg-elevated/90 px-3 py-1.5 text-center text-xs text-text-secondary",
107
107
  "data-testid": "assistant-avatar-tab-frame-text",
108
- children: we
108
+ children: Te
109
109
  }),
110
110
  P.audioBlocked ? /* @__PURE__ */ f("button", {
111
111
  type: "button",
112
- onClick: () => i.resumeAudio(),
112
+ onClick: () => r.resumeAudio(),
113
113
  className: `absolute inset-x-2 bottom-2 inline-flex min-h-11 items-center justify-center gap-1.5 rounded-xl bg-bg-elevated px-3 text-xs font-medium text-text-primary ${x}`,
114
114
  "data-testid": "assistant-avatar-tab-sound",
115
- children: [/* @__PURE__ */ d(ie, {
115
+ children: [/* @__PURE__ */ d(u, {
116
116
  className: "size-4 shrink-0",
117
117
  "aria-hidden": "true"
118
118
  }), /* @__PURE__ */ d("span", { children: D.problem("playback-blocked") })]
@@ -145,16 +145,16 @@ var y = "text-xs font-medium text-text-secondary", b = "text-xs text-text-muted"
145
145
  name: he,
146
146
  value: e,
147
147
  checked: t,
148
- onChange: () => i.selectAvatar(e),
148
+ onChange: () => r.selectAvatar(e),
149
149
  className: se,
150
150
  "data-avatar-id": e
151
151
  }),
152
- /* @__PURE__ */ d(r, {
152
+ /* @__PURE__ */ d(re, {
153
153
  size: "pill",
154
154
  name: n,
155
- src: Z(e),
155
+ src: ke(e),
156
156
  selected: t,
157
- onError: De
157
+ onError: Oe
158
158
  }),
159
159
  /* @__PURE__ */ d("span", {
160
160
  className: "truncate",
@@ -197,19 +197,19 @@ var y = "text-xs font-medium text-text-secondary", b = "text-xs text-text-muted"
197
197
  className: "flex items-center gap-2",
198
198
  children: [/* @__PURE__ */ f("select", {
199
199
  id: A,
200
- value: Y,
201
- onChange: (e) => Ce(e.target.value),
200
+ value: J,
201
+ onChange: (e) => we(e.target.value),
202
202
  "aria-describedby": j,
203
203
  className: `min-h-11 min-w-0 flex-1 rounded-xl border border-border-default bg-bg-elevated px-3 text-sm text-text-primary scheme-normal dark:scheme-dark [&_option]:bg-bg-surface [&_option]:text-text-primary ${x}`,
204
204
  "data-testid": "assistant-avatar-tab-voice",
205
205
  children: [
206
206
  /* @__PURE__ */ d("option", {
207
207
  value: p,
208
- children: Se
208
+ children: Ce
209
209
  }),
210
- J === null ? null : /* @__PURE__ */ d("option", {
210
+ q === null ? null : /* @__PURE__ */ d("option", {
211
211
  value: m,
212
- children: D.voiceModeDefaultNamed(J)
212
+ children: D.voiceModeDefaultNamed(q)
213
213
  }),
214
214
  e.map((e) => /* @__PURE__ */ d("option", {
215
215
  value: `${h}${e}`,
@@ -219,14 +219,14 @@ var y = "text-xs font-medium text-text-secondary", b = "text-xs text-text-muted"
219
219
  }), /* @__PURE__ */ d("button", {
220
220
  type: "button",
221
221
  onClick: () => {
222
- xe && X !== null && O.previewVoice(X);
222
+ Se && Y !== null && O.previewVoice(Y);
223
223
  },
224
- "aria-disabled": !xe,
224
+ "aria-disabled": !Se,
225
225
  "aria-label": D.hearVoice,
226
226
  title: D.hearVoice,
227
227
  className: `inline-flex size-11 shrink-0 items-center justify-center rounded-xl border border-border-default bg-bg-elevated text-text-secondary transition-colors hover:bg-bg-raised hover:text-text-primary aria-disabled:cursor-default aria-disabled:opacity-60 ${x}`,
228
228
  "data-testid": "assistant-avatar-tab-hear",
229
- children: /* @__PURE__ */ d(ie, {
229
+ children: /* @__PURE__ */ d(u, {
230
230
  className: "size-5",
231
231
  "aria-hidden": "true"
232
232
  })
@@ -256,9 +256,9 @@ var y = "text-xs font-medium text-text-secondary", b = "text-xs text-text-muted"
256
256
  "data-slot": W.kind,
257
257
  children: W.kind === "turn-off" ? D.stop : W.kind === "starting" ? D.turnOnStarting : W.kind === "ending" ? D.stateEnding : D.consentConfirm
258
258
  }),
259
- Oe ? /* @__PURE__ */ d("button", {
259
+ $ ? /* @__PURE__ */ d("button", {
260
260
  type: "button",
261
- onClick: () => i.requestOn({ start: !1 }),
261
+ onClick: () => r.requestOn({ start: !1 }),
262
262
  className: S,
263
263
  "data-testid": "assistant-avatar-tab-retry",
264
264
  children: D.chooserRetry
@@ -276,15 +276,15 @@ var y = "text-xs font-medium text-text-secondary", b = "text-xs text-text-muted"
276
276
  className: S,
277
277
  "data-testid": "assistant-avatar-tab-start-voice",
278
278
  children: D.startVoice
279
- }), C.blocked === null ? $ === null ? null : /* @__PURE__ */ d("p", {
279
+ }), C.blocked === null ? Z === null ? null : /* @__PURE__ */ d("p", {
280
280
  className: b,
281
281
  "data-testid": "assistant-avatar-tab-ask-note",
282
- children: $
282
+ children: Z
283
283
  }) : /* @__PURE__ */ d("p", {
284
284
  id: M,
285
285
  className: b,
286
286
  "data-testid": "assistant-avatar-tab-voice-blocked",
287
- children: $ === null ? C.blocked : `${C.blocked} ${$}`
287
+ children: Z === null ? C.blocked : `${C.blocked} ${Z}`
288
288
  })]
289
289
  }),
290
290
  ce && !P.voiceLive ? /* @__PURE__ */ d("p", {
@@ -46,7 +46,9 @@ export interface LiveAvatarSnapshot {
46
46
  readonly tabOffered: boolean;
47
47
  /**
48
48
  * After a "not now" refusal that said when (the server's Retry-After): the wall-clock ms a start may be tried again. Null otherwise.
49
- * It goes with `problem`: cleared together, and both clear by themselves when the time comes.
49
+ * It goes with `problem`: cleared together, and both clear by themselves when the time comes. A newer refusal (including a question
50
+ * that failed or was answered "not offered"), a workspace switch and a voice conversation starting outside the Avatar tab clear them
51
+ * earlier.
50
52
  */
51
53
  readonly retryAt: number | null;
52
54
  /** The avatar was turned on outside the tab during the voice conversation that is still live: closing the tab hands it back to Voice. */
@@ -132,6 +134,8 @@ export interface LiveAvatarRequestOptions {
132
134
  * and there is nothing to choose. `false`: the chooser only, never a start (the tab opening, "Try again", a workspace switch).
133
135
  * `true`: the person's Turn on, with the disclosure on screen: start with `avatarId` (else the one selected) once the answer comes,
134
136
  * only if it is still offered and the disclosure version is the one shown at the click; otherwise the chooser.
137
+ * While the snapshot carries a refusal's retry time (`retryAt`) that has not come, no mode starts: `true` asks nothing then; the other
138
+ * modes still ask (it is free) and keep the refusal with its time, and the chooser they reach waits for that time.
135
139
  */
136
140
  readonly start?: boolean;
137
141
  readonly avatarId?: string;
@@ -143,7 +147,10 @@ export interface LiveAvatarController {
143
147
  setVoiceLive(live: boolean): void;
144
148
  /** The person asked for the avatar: ask the server whether it is offered, then show the chooser and the disclosure (`options`). */
145
149
  requestOn(options?: LiveAvatarRequestOptions): void;
146
- /** The person confirmed the disclosure: start a session with the chosen avatar. */
150
+ /**
151
+ * The person confirmed the disclosure: start a session with the chosen avatar. Does nothing while the snapshot carries a refusal's retry
152
+ * time (`retryAt`) that has not come.
153
+ */
147
154
  confirm(): void;
148
155
  /**
149
156
  * The Avatar tab opened or closed (BOFF-9341). Open: the avatar may be asked for with no voice conversation, and an avatar already on
@@ -220,6 +220,7 @@ function g(s) {
220
220
  e.hide && (b = !0), C = !1, M = !1, N = null, U(), V({
221
221
  phase: "off",
222
222
  problem: e.problem,
223
+ retryAt: null,
223
224
  avatars: []
224
225
  });
225
226
  }
@@ -471,7 +472,7 @@ function g(s) {
471
472
  let o = ++T;
472
473
  V({
473
474
  phase: "checking",
474
- problem: null,
475
+ problem: B() ? v.problem : null,
475
476
  notice: null
476
477
  }), Y((e) => i.availability(e)).then((e) => {
477
478
  if (T !== o) return;
@@ -500,7 +501,7 @@ function g(s) {
500
501
  });
501
502
  },
502
503
  confirm() {
503
- if (v.phase !== "choosing" || !(v.voiceLive || j)) return;
504
+ if (v.phase !== "choosing" || !(v.voiceLive || j) || B()) return;
504
505
  let e = v.selectedAvatarId, t = v.consentVersion;
505
506
  e === null || t === null || (x = t, l.setAvatarId(e), C = !0, M = !j, j && (N ??= c.now()), U(), ce(e, t));
506
507
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/fe-libs",
3
- "version": "2026.1023.15",
3
+ "version": "2026.1023.16",
4
4
  "description": "Burdenoff frontend primitives and domain libraries",
5
5
  "type": "module",
6
6
  "bin": {