@burdenoff/fe-libs 2026.1002.2 → 2026.1003.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 (29) hide show
  1. package/dist/shared/assistant/ui/AssistantAvatar.d.ts +0 -21
  2. package/dist/shared/assistant/ui/AssistantAvatar.d.ts.map +1 -1
  3. package/dist/shared/assistant/ui/AssistantAvatar.js +13 -7
  4. package/dist/shared/assistant/ui/AssistantMessageItem.d.ts +8 -0
  5. package/dist/shared/assistant/ui/AssistantMessageItem.d.ts.map +1 -1
  6. package/dist/shared/assistant/ui/AssistantMessageItem.js +60 -58
  7. package/dist/shared/assistant/ui/composer/AssistantComposer.js +117 -117
  8. package/dist/shared/assistant/ui/composer/AssistantVoiceButton.d.ts +8 -0
  9. package/dist/shared/assistant/ui/composer/AssistantVoiceButton.d.ts.map +1 -1
  10. package/dist/shared/assistant/ui/composer/AssistantVoiceButton.js +21 -16
  11. package/dist/shared/assistant/ui/useVoiceSession.d.ts +1 -4
  12. package/dist/shared/assistant/ui/useVoiceSession.d.ts.map +1 -1
  13. package/dist/shared/assistant/ui/useVoiceSession.js +117 -114
  14. package/dist/shared/assistant/ui/voice/AssistantVoiceOrb.d.ts.map +1 -1
  15. package/dist/shared/assistant/ui/voice/AssistantVoiceOrb.js +16 -15
  16. package/dist/shared/assistant/ui/voice/VoiceCaption.d.ts.map +1 -1
  17. package/dist/shared/assistant/ui/voice/VoiceCaption.js +1 -1
  18. package/dist/shared/assistant/ui/voice/VoiceMiniController.d.ts.map +1 -1
  19. package/dist/shared/assistant/ui/voice/VoiceMiniController.js +35 -30
  20. package/dist/shared/assistant/ui/voice/VoiceStage.d.ts.map +1 -1
  21. package/dist/shared/assistant/ui/voice/VoiceStage.js +38 -37
  22. package/dist/shared/assistant/ui/voice/VoiceWaveform.d.ts +6 -0
  23. package/dist/shared/assistant/ui/voice/VoiceWaveform.d.ts.map +1 -1
  24. package/dist/shared/assistant/ui/voice/VoiceWaveform.js +40 -36
  25. package/dist/shared/assistant/voice/speechPlayback.d.ts +37 -19
  26. package/dist/shared/assistant/voice/speechPlayback.d.ts.map +1 -1
  27. package/dist/shared/assistant/voice/speechPlayback.js +11 -1
  28. package/dist/shared-assistant.js +124 -124
  29. package/package.json +1 -1
@@ -1,55 +1,56 @@
1
1
  import { useVoiceInput as e } from "../voice/useVoiceInput.js";
2
2
  import { INITIAL_SESSION as t, INTERRUPT_MAX_MS as ee, NOTHING_HEARD as n, SILENCE_SUBMIT_MS as te, advanceHeardClock as ne, isCapturing as r, isSubmittable as re, planListeningHold as ie, planReplyConsumption as ae, planVoiceAnnouncement as oe, spokenSoFar as i, voiceSessionReducer as se } from "../voice/voiceSession.js";
3
+ import { captionChunks as ce } from "../voice/speechPlayback.js";
3
4
  import { turnClockMs as a } from "../turnTimeline.js";
4
- import { useAssistantSpeech as ce } from "./AssistantSpeechProvider.js";
5
- import { useCallback as o, useEffect as s, useLayoutEffect as le, useMemo as ue, useReducer as de, useRef as c, useState as l } from "react";
5
+ import { useAssistantSpeech as le } from "./AssistantSpeechProvider.js";
6
+ import { useCallback as o, useEffect as s, useLayoutEffect as ue, useMemo as de, useReducer as fe, useRef as c, useState as l } from "react";
6
7
  //#region src/shared/assistant/ui/useVoiceSession.ts
7
- var fe = 4e3, pe = 2500, me = 5e3, he = 12e3, ge = "data:audio/wav;base64,UklGRiQAAABXQVZFZm10IBAAAAABAAEARKwAAIhYAQACABAAZGF0YQAAAAA=";
8
- function u({ onSubmit: u, latestReply: d, language: _e }) {
9
- let f = c(null), [p, m] = de(o((e, t) => se(e, t, f.current), []), t), h = ce(), { setSessionSpeaking: g, setSessionMicOpen: _, speakingMessageId: v, stop: y } = h, b = c(h.toggle), x = h.toggle;
10
- le(() => {
11
- b.current = x;
12
- }, [x]);
13
- let S = c(null), C = c({}), w = c(n), T = c(null), E = c(!1), [D, O] = l(null), [k, A] = l(!1), [j, M] = l(!1), N = c(p);
14
- N.current = p;
15
- let P = c([]), F = c(null), I = c(!1), L = o(() => {
16
- P.current = [], F.current = null, I.current = !1;
17
- }, []), R = o(() => {
8
+ var pe = 4e3, me = 2500, he = 5e3, ge = 12e3, _e = "data:audio/wav;base64,UklGRiQAAABXQVZFZm10IBAAAAABAAEARKwAAIhYAQACABAAZGF0YQAAAAA=";
9
+ function u({ onSubmit: u, latestReply: d, language: ve }) {
10
+ let f = c(null), [p, m] = fe(o((e, t) => se(e, t, f.current), []), t), h = le(), { setSessionSpeaking: g, setSessionMicOpen: _, speakingMessageId: v, stop: y } = h, ye = c(h.toggle), b = h.toggle;
11
+ ue(() => {
12
+ ye.current = b;
13
+ }, [b]);
14
+ let x = c(null), S = c({}), C = c(n), w = c(null), T = c(!1), [E, D] = l(null), [O, k] = l(!1), [A, j] = l(!1), M = c(p);
15
+ M.current = p;
16
+ let N = c([]), P = c(null), F = c(!1), I = o(() => {
17
+ N.current = [], P.current = null, F.current = !1;
18
+ }, []), L = o(() => {
18
19
  for (;;) {
19
- let e = P.current.shift();
20
+ let e = N.current.shift();
20
21
  if (!e) return !1;
21
22
  if (!(e.stillWanted && !e.stillWanted())) {
22
- F.current = e, f.current = f.current ? `${f.current} ${e.text}` : e.text;
23
+ P.current = e, f.current = f.current ? `${f.current} ${e.text}` : e.text;
23
24
  try {
24
- b.current(e.id, e.text, e.lang);
25
+ ye.current(e.id, e.text, e.lang);
25
26
  } catch {
26
- F.current = null;
27
+ P.current = null;
27
28
  continue;
28
29
  }
29
30
  return !0;
30
31
  }
31
32
  }
32
- }, []), z = c(!1), B = o((e) => {
33
+ }, []), R = c(!1), z = o((e) => {
33
34
  let t = ie({
34
35
  requested: e,
35
- held: z.current,
36
- muted: N.current.muted
36
+ held: R.current,
37
+ muted: M.current.muted
37
38
  });
38
- z.current = t.held, t.mute !== null && m({
39
+ R.current = t.held, t.mute !== null && m({
39
40
  type: "mute",
40
41
  muted: t.mute
41
42
  });
43
+ }, []), B = o((e) => {
44
+ let t = oe(M.current);
45
+ t !== "drop" && (P.current?.id === e.id || N.current.some((t) => t.id === e.id) || (N.current.push(e), t === "start" && !F.current && (F.current = !0, m({ type: "announce" }))));
42
46
  }, []), V = o((e) => {
43
- let t = oe(N.current);
44
- t !== "drop" && (F.current?.id === e.id || P.current.some((t) => t.id === e.id) || (P.current.push(e), t === "start" && !I.current && (I.current = !0, m({ type: "announce" }))));
45
- }, []), H = o((e) => {
46
- if (N.current.phase !== "thinking") {
47
- V(e);
47
+ if (M.current.phase !== "thinking") {
48
+ B(e);
48
49
  return;
49
50
  }
50
- P.current.push(e), I.current = !0, m({ type: "answered-locally" });
51
- }, [V]), U = c(d);
52
- U.current = d, s(() => {
51
+ N.current.push(e), F.current = !0, m({ type: "answered-locally" });
52
+ }, [B]), H = c(d);
53
+ H.current = d, s(() => {
53
54
  if (p.phase === "speaking") {
54
55
  f.current = d?.text ?? null;
55
56
  return;
@@ -57,99 +58,99 @@ function u({ onSubmit: u, latestReply: d, language: _e }) {
57
58
  if (f.current === null) return;
58
59
  let e = setTimeout(() => {
59
60
  f.current = null;
60
- }, pe);
61
+ }, me);
61
62
  return () => clearTimeout(e);
62
63
  }, [p.phase, d]);
63
- let W = o((e, t) => {
64
+ let U = o((e, t) => {
64
65
  m({
65
66
  type: "speech",
66
67
  transcript: e,
67
68
  final: t
68
69
  });
69
- }, []), G = c(0), K = o(() => {
70
- L(), y(), G.current = Date.now(), A(!0), m({ type: "interrupt" });
71
- }, [y, L]), q = e({
72
- onFinalize: o((e) => W(e, !0), [W]),
73
- language: _e
70
+ }, []), W = c(0), G = o(() => {
71
+ I(), y(), W.current = Date.now(), k(!0), m({ type: "interrupt" });
72
+ }, [y, I]), K = e({
73
+ onFinalize: o((e) => U(e, !0), [U]),
74
+ language: ve
74
75
  });
75
76
  s(() => {
76
- q.interim && W(q.interim, !1);
77
- }, [q.interim, W]), s(() => {
78
- if (S.current && clearTimeout(S.current), M(!1), w.current = ne(w.current, p, a()), p.phase !== "listening" || p.muted || !re(i(p))) return;
79
- let e = setTimeout(() => M(!0), 800), t = a();
80
- return S.current = setTimeout(() => {
81
- C.current = {
82
- speechEnded: w.current.at ?? t,
77
+ K.interim && U(K.interim, !1);
78
+ }, [K.interim, U]), s(() => {
79
+ if (x.current && clearTimeout(x.current), j(!1), C.current = ne(C.current, p, a()), p.phase !== "listening" || p.muted || !re(i(p))) return;
80
+ let e = setTimeout(() => j(!0), 800), t = a();
81
+ return x.current = setTimeout(() => {
82
+ S.current = {
83
+ speechEnded: C.current.at ?? t,
83
84
  graceStarted: t,
84
85
  graceEnded: a()
85
86
  }, m({ type: "silence" });
86
87
  }, te), () => {
87
- clearTimeout(e), S.current && clearTimeout(S.current);
88
+ clearTimeout(e), x.current && clearTimeout(x.current);
88
89
  };
89
90
  }, [p]), s(() => {
90
- if (!k) return;
91
- let e = Date.now() - G.current, t = q.isListening ? Math.max(0, 500 - e) : Math.max(0, ee - e), n = setTimeout(() => A(!1), t);
91
+ if (!O) return;
92
+ let e = Date.now() - W.current, t = K.isListening ? Math.max(0, 500 - e) : Math.max(0, ee - e), n = setTimeout(() => k(!1), t);
92
93
  return () => clearTimeout(n);
93
- }, [k, q.isListening]);
94
- let J = c("");
95
- p.phase === "listening" && (J.current = i(p)), s(() => {
94
+ }, [O, K.isListening]);
95
+ let q = c("");
96
+ p.phase === "listening" && (q.current = i(p)), s(() => {
96
97
  if (p.phase !== "thinking") return;
97
- _(!1), L();
98
- let e = J.current.trim();
99
- e && u(e, Y.current ?? `vs-orphan-${Date.now().toString(36)}`, C.current), C.current = {}, w.current = n;
98
+ _(!1), I();
99
+ let e = q.current.trim();
100
+ e && u(e, J.current ?? `vs-orphan-${Date.now().toString(36)}`, S.current), S.current = {}, C.current = n;
100
101
  }, [p.phase]), s(() => {
101
- let e = ae(d?.id, p.phase, T.current);
102
- e.claim && (T.current = d?.id ?? null, e.advance && d && m({
102
+ let e = ae(d?.id, p.phase, w.current);
103
+ e.claim && (w.current = d?.id ?? null, e.advance && d && m({
103
104
  type: "reply",
104
105
  text: d.text
105
106
  }));
106
107
  }, [d, p.phase]), s(() => {
107
108
  let e = v !== null;
108
- E.current && !e && (F.current = null, (N.current.phase !== "speaking" || !R()) && m({ type: "speech-ended" })), E.current = e;
109
- }, [v, R]), s(() => {
110
- p.phase !== "listening" && O((e) => e === "nothing-heard" ? null : e);
109
+ T.current && !e && (P.current = null, (M.current.phase !== "speaking" || !L()) && m({ type: "speech-ended" })), T.current = e;
110
+ }, [v, L]), s(() => {
111
+ p.phase !== "listening" && D((e) => e === "nothing-heard" ? null : e);
111
112
  }, [p.phase]), s(() => {
112
113
  if (p.phase !== "speaking" || v !== null) return;
113
114
  let e = setTimeout(() => {
114
- E.current || (L(), m({ type: "speech-ended" }));
115
- }, fe);
115
+ T.current || (I(), m({ type: "speech-ended" }));
116
+ }, pe);
116
117
  return () => clearTimeout(e);
117
118
  }, [
118
119
  p.phase,
119
120
  v,
120
- L
121
+ I
121
122
  ]), s(() => {
122
123
  let e = r(p);
123
- _(e), e ? q.isActive || q.start("auto") : q.isActive && q.stop();
124
+ _(e), e ? K.isActive || K.start("auto") : K.isActive && K.stop();
124
125
  }, [
125
126
  p,
126
- q,
127
+ K,
127
128
  _
128
129
  ]), s(() => {
129
- p.phase !== "speaking" || !I.current || (I.current = !1, R() || m({ type: "speech-ended" }));
130
- }, [p.phase, R]), s(() => {
131
- q.error === "not-allowed" || q.error === "audio-capture" ? m({
130
+ p.phase !== "speaking" || !F.current || (F.current = !1, L() || m({ type: "speech-ended" }));
131
+ }, [p.phase, L]), s(() => {
132
+ K.error === "not-allowed" || K.error === "audio-capture" ? m({
132
133
  type: "fail",
133
134
  error: "mic-denied"
134
- }) : q.error === "language-not-supported" ? m({
135
+ }) : K.error === "language-not-supported" ? m({
135
136
  type: "fail",
136
137
  error: "no-speech-support"
137
- }) : q.error === "network" ? O("network") : q.error === "unknown" && O("recognition-failed");
138
- }, [q.error]), s(() => {
139
- q.error !== null || !q.isListening || O((e) => e === "network" || e === "recognition-failed" ? null : e);
140
- }, [q.error, q.isListening]), s(() => {
141
- if (q.isListening && O((e) => e === "not-capturing" ? null : e), !r(p) || q.isListening) return;
142
- let e = setTimeout(() => O("not-capturing"), me);
138
+ }) : K.error === "network" ? D("network") : K.error === "unknown" && D("recognition-failed");
139
+ }, [K.error]), s(() => {
140
+ K.error !== null || !K.isListening || D((e) => e === "network" || e === "recognition-failed" ? null : e);
141
+ }, [K.error, K.isListening]), s(() => {
142
+ if (K.isListening && D((e) => e === "not-capturing" ? null : e), !r(p) || K.isListening) return;
143
+ let e = setTimeout(() => D("not-capturing"), he);
143
144
  return () => clearTimeout(e);
144
- }, [p, q.isListening]), s(() => {
145
- if (p.phase !== "listening" || p.muted || !q.isListening || i(p) !== "") return;
146
- let e = setTimeout(() => O("nothing-heard"), he);
145
+ }, [p, K.isListening]), s(() => {
146
+ if (p.phase !== "listening" || p.muted || !K.isListening || i(p) !== "") return;
147
+ let e = setTimeout(() => D("nothing-heard"), ge);
147
148
  return () => clearTimeout(e);
148
- }, [p, q.isListening]), s(() => {
149
- i(p) !== "" && O(null);
149
+ }, [p, K.isListening]), s(() => {
150
+ i(p) !== "" && D(null);
150
151
  }, [p]);
151
- let Y = c(null), X = o(() => {
152
- if (A(!1), M(!1), L(), z.current = !1, !q.isSupported) {
152
+ let J = c(null), Y = o(() => {
153
+ if (k(!1), j(!1), I(), R.current = !1, !K.isSupported) {
153
154
  m({
154
155
  type: "fail",
155
156
  error: "no-speech-support"
@@ -172,64 +173,66 @@ function u({ onSubmit: u, latestReply: d, language: _e }) {
172
173
  } catch {}
173
174
  try {
174
175
  if (typeof window < "u" && typeof window.Audio == "function") {
175
- let e = new window.Audio(ge);
176
+ let e = new window.Audio(_e);
176
177
  e.volume = 0, e.play().catch(() => {});
177
178
  }
178
179
  } catch {}
179
- g(!0), O(null), T.current = U.current?.id ?? null, Y.current = `vs-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`, m({ type: "start" });
180
+ g(!0), D(null), w.current = H.current?.id ?? null, J.current = `vs-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`, m({ type: "start" });
180
181
  }, [
181
- q.isSupported,
182
+ K.isSupported,
182
183
  h.isBlocked,
183
184
  g,
184
- L
185
- ]), Z = o(() => {
186
- A(!1), M(!1), L(), z.current = !1, Y.current = null, m({ type: "end" }), y(), g(!1);
185
+ I
186
+ ]), X = o(() => {
187
+ k(!1), j(!1), I(), R.current = !1, J.current = null, m({ type: "end" }), y(), g(!1);
187
188
  }, [
188
189
  y,
189
190
  g,
190
- L
191
- ]), Q = o((e) => Y.current === e, []), $ = o(() => {
191
+ I
192
+ ]), Z = o((e) => J.current === e, []), Q = o(() => {
192
193
  m({
193
194
  type: "mute",
194
- muted: !N.current.muted
195
+ muted: !M.current.muted
195
196
  });
196
197
  }, []);
197
- return s(() => () => {
198
+ s(() => () => {
198
199
  g(!1), _(!1);
199
- }, [g, _]), ue(() => ({
200
+ }, [g, _]);
201
+ let $ = ce(h.spokenChunks, p.phase, v);
202
+ return de(() => ({
200
203
  session: p,
201
- notice: D,
202
- spokenChunks: h.spokenChunks,
203
- capturing: q.isListening,
204
+ notice: E,
205
+ spokenChunks: $,
206
+ capturing: K.isListening,
204
207
  active: p.phase !== "idle" && (p.phase !== "ended" || p.error !== null),
205
- interrupting: k,
206
- awaitingEndpoint: j,
207
- available: q.isSupported && !h.isBlocked,
208
- start: X,
209
- end: Z,
210
- isCurrentSession: Q,
211
- toggleMute: $,
212
- interrupt: K,
213
- announce: V,
214
- holdListening: B,
215
- answerLocally: H
208
+ interrupting: O,
209
+ awaitingEndpoint: A,
210
+ available: K.isSupported && !h.isBlocked,
211
+ start: Y,
212
+ end: X,
213
+ isCurrentSession: Z,
214
+ toggleMute: Q,
215
+ interrupt: G,
216
+ announce: B,
217
+ holdListening: z,
218
+ answerLocally: V
216
219
  }), [
217
220
  p,
218
- D,
219
- k,
220
- j,
221
- q.isListening,
222
- q.isSupported,
221
+ E,
222
+ O,
223
+ A,
224
+ K.isListening,
225
+ K.isSupported,
223
226
  h.isBlocked,
224
- h.spokenChunks,
227
+ $,
228
+ Y,
225
229
  X,
226
230
  Z,
227
231
  Q,
228
- $,
229
- K,
230
- V,
232
+ G,
231
233
  B,
232
- H
234
+ z,
235
+ V
233
236
  ]);
234
237
  }
235
238
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"AssistantVoiceOrb.d.ts","sourceRoot":"","sources":["../../../../../src/shared/assistant/ui/voice/AssistantVoiceOrb.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAEhC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAGrE;;;;;;;;;;;;;;;;;;GAkBG;AACH,UAAU,KAAK;IACb,OAAO,EAAE,oBAAoB,CAAC;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,iEAAiE;IACjE,KAAK,EAAE,MAAM,CAAC;IACd,+EAA+E;IAC/E,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,eAAO,MAAM,iBAAiB,EAAE,EAAE,CAAC,KAAK,CAkGvC,CAAC"}
1
+ {"version":3,"file":"AssistantVoiceOrb.d.ts","sourceRoot":"","sources":["../../../../../src/shared/assistant/ui/voice/AssistantVoiceOrb.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAEhC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAIrE;;;;;;;;;;;;;;;;;;GAkBG;AACH,UAAU,KAAK;IACb,OAAO,EAAE,oBAAoB,CAAC;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,iEAAiE;IACjE,KAAK,EAAE,MAAM,CAAC;IACd,+EAA+E;IAC/E,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,eAAO,MAAM,iBAAiB,EAAE,EAAE,CAAC,KAAK,CAsGvC,CAAC"}
@@ -1,24 +1,25 @@
1
1
  import { orbMode as e } from "../../voice/voiceSession.js";
2
- import { Mic as t, MicOff as n, Square as r } from "lucide-react";
3
- import { jsx as i } from "react/jsx-runtime";
2
+ import { usePrefersReducedMotion as t } from "../usePrefersReducedMotion.js";
3
+ import { Mic as n, MicOff as r, Square as i } from "lucide-react";
4
+ import { jsx as a } from "react/jsx-runtime";
4
5
  //#region src/shared/assistant/ui/voice/AssistantVoiceOrb.tsx
5
- var a = ({ session: a, compact: o = !1, onPress: s, label: c, connecting: l = !1 }) => {
6
- let u = e(a), { muted: d, phase: f, error: p } = a, m = f === "idle" || f === "ended" || p !== null || l, h = d && f !== "speaking" ? "from-bg-elevated to-bg-elevated" : u === "listening" ? "from-action-primary-bg/80 to-action-primary-bg/20" : u === "thinking" ? "from-action-primary-bg/55 to-action-primary-bg/15" : u === "speaking" ? "from-action-primary-bg to-action-primary-bg/40" : "from-bg-elevated to-bg-elevated/40", g = d && f !== "speaking" ? "" : u === "listening" ? "motion-safe:animate-pulse" : u === "thinking" ? "motion-safe:animate-[pulse_1.6s_ease-in-out_infinite]" : u === "speaking" ? "motion-safe:animate-[pulse_0.9s_ease-in-out_infinite]" : "", _ = o ? "h-16 w-40" : "h-24 w-56", v = o ? "size-6" : "size-8", y = f === "speaking" || f === "thinking" ? r : d ? n : t;
7
- return /* @__PURE__ */ i("button", {
6
+ var o = ({ session: o, compact: s = !1, onPress: c, label: l, connecting: u = !1 }) => {
7
+ let d = e(o), f = t(), { muted: p, phase: m, error: h } = o, g = m === "idle" || m === "ended" || h !== null || u, _ = p && m !== "speaking" ? "from-bg-elevated to-bg-elevated" : d === "listening" ? "from-action-primary-bg/80 to-action-primary-bg/20" : d === "thinking" ? "from-action-primary-bg/55 to-action-primary-bg/15" : d === "speaking" ? "from-action-primary-bg to-action-primary-bg/40" : "from-bg-elevated to-bg-elevated/40", v = f || p && m !== "speaking" ? "" : d === "listening" ? "motion-safe:animate-pulse" : d === "thinking" ? "motion-safe:animate-[pulse_1.6s_ease-in-out_infinite]" : d === "speaking" ? "motion-safe:animate-[pulse_0.9s_ease-in-out_infinite]" : "", y = s ? "h-16 w-40" : "h-24 w-56", b = s ? "size-6" : "size-8", x = m === "speaking" || m === "thinking" ? i : p ? r : n;
8
+ return /* @__PURE__ */ a("button", {
8
9
  type: "button",
9
- onClick: s,
10
- disabled: m || !s,
11
- className: `flex ${_} items-center justify-center rounded-full bg-gradient-to-b ${h} ${g} text-text-primary shadow-lg transition-colors duration-300 focus:outline-none focus-visible:ring-2 focus-visible:ring-border-strong disabled:cursor-default`,
12
- "aria-label": c,
13
- "aria-pressed": f === "speaking" || f === "thinking" ? void 0 : d,
10
+ onClick: c,
11
+ disabled: g || !c,
12
+ className: `flex ${y} items-center justify-center rounded-full bg-gradient-to-b ${_} ${v} text-text-primary shadow-lg transition-colors duration-300 focus:outline-none focus-visible:ring-2 focus-visible:ring-border-strong disabled:cursor-default`,
13
+ "aria-label": l,
14
+ "aria-pressed": m === "speaking" || m === "thinking" ? void 0 : p,
14
15
  "data-testid": "assistant-voice-orb",
15
- "data-state": u,
16
- "data-muted": d || void 0,
17
- children: /* @__PURE__ */ i(y, {
18
- className: v,
16
+ "data-state": d,
17
+ "data-muted": p || void 0,
18
+ children: /* @__PURE__ */ a(x, {
19
+ className: b,
19
20
  "aria-hidden": "true"
20
21
  })
21
22
  });
22
23
  };
23
24
  //#endregion
24
- export { a as AssistantVoiceOrb };
25
+ export { o as AssistantVoiceOrb };
@@ -1 +1 @@
1
- {"version":3,"file":"VoiceCaption.d.ts","sourceRoot":"","sources":["../../../../../src/shared/assistant/ui/voice/VoiceCaption.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,EAAE,EAAE,MAAM,OAAO,CAAC;AAEnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,UAAU,KAAK;IACb,IAAI,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IAC3B,mDAAmD;IACnD,QAAQ,EAAE,OAAO,CAAC;IAClB;;;;;;;;;;;;;OAaG;IACH,YAAY,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,EAAE,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC1D,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,wBAAwB,CAAC;AAEzD,eAAO,MAAM,YAAY,EAAE,EAAE,CAAC,KAAK,CAqKlC,CAAC"}
1
+ {"version":3,"file":"VoiceCaption.d.ts","sourceRoot":"","sources":["../../../../../src/shared/assistant/ui/voice/VoiceCaption.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,EAAE,EAAE,MAAM,OAAO,CAAC;AAEnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,UAAU,KAAK;IACb,IAAI,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IAC3B,mDAAmD;IACnD,QAAQ,EAAE,OAAO,CAAC;IAClB;;;;;;;;;;;;;OAaG;IACH,YAAY,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,EAAE,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC1D,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,wBAAwB,CAAC;AAEzD,eAAO,MAAM,YAAY,EAAE,EAAE,CAAC,KAAK,CAwKlC,CAAC"}
@@ -16,7 +16,7 @@ var r = "data-caption-scroll", i = ({ text: i, role: a, expanded: o, spokenChunk
16
16
  className: [
17
17
  "w-full whitespace-pre-wrap break-words text-left",
18
18
  o ? "max-w-[45rem]" : "max-w-md",
19
- u ? "font-semibold text-text-primary" : "font-medium text-text-secondary",
19
+ u ? "font-semibold text-text-primary" : "font-semibold text-text-secondary",
20
20
  u ? o ? "text-[clamp(1.625rem,2.5vw,2.25rem)] leading-[1.5]" : "text-[clamp(1.625rem,2vw,2rem)] leading-[1.5]" : o ? "text-[clamp(1.125rem,1.8vw,1.375rem)] leading-[1.5]" : "text-base leading-relaxed"
21
21
  ].join(" "),
22
22
  role: "status",
@@ -1 +1 @@
1
- {"version":3,"file":"VoiceMiniController.d.ts","sourceRoot":"","sources":["../../../../../src/shared/assistant/ui/voice/VoiceMiniController.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAI3C,OAAO,EAIL,KAAK,eAAe,EACrB,MAAM,6BAA6B,CAAC;AAErC;;;;;;;;;;;;;;;;;GAiBG;AAEH,UAAU,KAAK;IACb,KAAK,EAAE,eAAe,CAAC;IACvB,uEAAuE;IACvE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB;;;;;;;;;OASG;IACH,YAAY,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,EAAE,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC1D,UAAU,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B;;;;;OAKG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,mEAAmE;IACnE,OAAO,EAAE,SAAS,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,eAAO,MAAM,mBAAmB,EAAE,EAAE,CAAC,KAAK,CAiHzC,CAAC"}
1
+ {"version":3,"file":"VoiceMiniController.d.ts","sourceRoot":"","sources":["../../../../../src/shared/assistant/ui/voice/VoiceMiniController.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAK3C,OAAO,EAIL,KAAK,eAAe,EACrB,MAAM,6BAA6B,CAAC;AAErC;;;;;;;;;;;;;;;;;GAiBG;AAEH,UAAU,KAAK;IACb,KAAK,EAAE,eAAe,CAAC;IACvB,uEAAuE;IACvE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB;;;;;;;;;OASG;IACH,YAAY,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,EAAE,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC1D,UAAU,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B;;;;;OAKG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,mEAAmE;IACnE,OAAO,EAAE,SAAS,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,eAAO,MAAM,mBAAmB,EAAE,EAAE,CAAC,KAAK,CA8HzC,CAAC"}
@@ -1,56 +1,61 @@
1
1
  import { showsAssistantCaption as e, waveformIsActive as t, waveformIsSettled as n } from "../../voice/voiceStageState.js";
2
2
  import { showPreviousChunk as r } from "../../voice/miniCaptionBudget.js";
3
- import { VoiceWaveform as i } from "./VoiceWaveform.js";
4
- import { VoiceStatusText as a } from "./VoiceStatusText.js";
5
- import { Fragment as o, jsx as s, jsxs as c } from "react/jsx-runtime";
3
+ import { isAwaitingFirstChunk as i } from "../../voice/speechPlayback.js";
4
+ import { VoiceWaveform as a } from "./VoiceWaveform.js";
5
+ import { VoiceStatusText as o } from "./VoiceStatusText.js";
6
+ import { Fragment as s, jsx as c, jsxs as l } from "react/jsx-runtime";
6
7
  //#region src/shared/assistant/ui/voice/VoiceMiniController.tsx
7
- var l = ({ state: l, caption: u, spokenChunks: d = null, statusText: f, statusSuffix: p, rotateStatus: m, control: h, errorText: g = null }) => {
8
- let _ = e(l), v = _ && d && d.index >= 0 ? d : null;
9
- return /* @__PURE__ */ c("div", {
8
+ var u = ({ state: u, caption: d, spokenChunks: f = null, statusText: p, statusSuffix: m, rotateStatus: h, control: g, errorText: _ = null }) => {
9
+ let v = e(u), y = v && f && f.index >= 0 ? f : null, b = v && i(f);
10
+ return /* @__PURE__ */ l("div", {
10
11
  className: "flex min-h-0 w-full flex-1 items-center gap-3 px-4",
11
12
  "data-testid": "assistant-voice-mini",
12
- "data-state": l,
13
- children: [/* @__PURE__ */ c("div", {
13
+ "data-state": u,
14
+ children: [/* @__PURE__ */ l("div", {
14
15
  className: "flex min-w-0 flex-1 flex-col gap-1.5",
15
- children: [/* @__PURE__ */ c("div", {
16
+ children: [/* @__PURE__ */ l("div", {
16
17
  className: "flex items-center gap-2",
17
- children: [/* @__PURE__ */ s(i, {
18
- active: t(l),
19
- settled: n(l),
20
- tone: l === "speaking" ? "speaking" : "listening"
21
- }), /* @__PURE__ */ s(a, {
18
+ children: [/* @__PURE__ */ c(a, {
19
+ active: t(u),
20
+ settled: n(u),
21
+ tone: u === "speaking" ? "speaking" : "listening"
22
+ }), /* @__PURE__ */ c(o, {
22
23
  className: "truncate text-xs text-text-muted",
23
- status: f,
24
- suffix: p,
25
- rotating: m
24
+ status: p,
25
+ suffix: m,
26
+ rotating: h
26
27
  })]
27
- }), l === "mic-error" ? /* @__PURE__ */ s("p", {
28
+ }), u === "mic-error" ? /* @__PURE__ */ c("p", {
28
29
  className: "line-clamp-2 text-xs text-status-warning",
29
30
  role: "alert",
30
31
  "data-testid": "assistant-voice-mini-error",
31
- children: g
32
- }) : u ? /* @__PURE__ */ s("p", {
33
- className: ["line-clamp-3 break-words text-left text-sm leading-snug", _ ? "font-semibold text-text-primary" : "font-medium text-text-secondary"].join(" "),
32
+ children: _
33
+ }) : d ? /* @__PURE__ */ c("p", {
34
+ className: [
35
+ "line-clamp-3 break-words text-left text-sm leading-snug",
36
+ b ? "min-h-9" : "",
37
+ v ? "font-semibold text-text-primary" : "font-semibold text-text-secondary"
38
+ ].join(" "),
34
39
  role: "status",
35
40
  "aria-live": "polite",
36
41
  "data-testid": "assistant-voice-caption",
37
- children: v ? /* @__PURE__ */ c(o, { children: [r(v) ? /* @__PURE__ */ c("span", {
42
+ children: y ? /* @__PURE__ */ l(s, { children: [r(y) ? /* @__PURE__ */ l("span", {
38
43
  className: "text-text-muted transition-colors duration-300",
39
- children: [v.chunks[v.index - 1], " "]
40
- }) : null, /* @__PURE__ */ s("span", {
44
+ children: [y.chunks[y.index - 1], " "]
45
+ }) : null, /* @__PURE__ */ c("span", {
41
46
  className: "text-text-primary",
42
47
  "data-testid": "assistant-voice-caption-current",
43
- children: v.chunks[v.index]
44
- })] }) : u
45
- }) : /* @__PURE__ */ s("div", {
48
+ children: y.chunks[y.index]
49
+ })] }) : b ? null : d
50
+ }) : /* @__PURE__ */ c("div", {
46
51
  className: "h-9",
47
52
  "aria-hidden": "true"
48
53
  })]
49
- }), /* @__PURE__ */ s("div", {
54
+ }), /* @__PURE__ */ c("div", {
50
55
  className: "shrink-0",
51
- children: h
56
+ children: g
52
57
  })]
53
58
  });
54
59
  };
55
60
  //#endregion
56
- export { l as VoiceMiniController };
61
+ export { u as VoiceMiniController };
@@ -1 +1 @@
1
- {"version":3,"file":"VoiceStage.d.ts","sourceRoot":"","sources":["../../../../../src/shared/assistant/ui/voice/VoiceStage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAI3C,OAAO,EAKL,KAAK,eAAe,EACrB,MAAM,6BAA6B,CAAC;AAErC;;;;;;;;;;;;;;;;;GAiBG;AAEH,UAAU,KAAK;IACb,KAAK,EAAE,eAAe,CAAC;IACvB,mDAAmD;IACnD,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,oCAAoC;IACpC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,EAAE,OAAO,CAAC;IAClB,sDAAsD;IACtD,UAAU,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B;;;;;OAKG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,0CAA0C;IAC1C,OAAO,EAAE,SAAS,CAAC;IACnB,yDAAyD;IACzD,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,+EAA+E;IAC/E,YAAY,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,EAAE,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CAC3D;AAED,eAAO,MAAM,UAAU,EAAE,EAAE,CAAC,KAAK,CAmIhC,CAAC"}
1
+ {"version":3,"file":"VoiceStage.d.ts","sourceRoot":"","sources":["../../../../../src/shared/assistant/ui/voice/VoiceStage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAK3C,OAAO,EAKL,KAAK,eAAe,EACrB,MAAM,6BAA6B,CAAC;AAErC;;;;;;;;;;;;;;;;;GAiBG;AAEH,UAAU,KAAK;IACb,KAAK,EAAE,eAAe,CAAC;IACvB,mDAAmD;IACnD,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,oCAAoC;IACpC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,EAAE,OAAO,CAAC;IAClB,sDAAsD;IACtD,UAAU,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B;;;;;OAKG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,0CAA0C;IAC1C,OAAO,EAAE,SAAS,CAAC;IACnB,yDAAyD;IACzD,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,+EAA+E;IAC/E,YAAY,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,EAAE,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CAC3D;AAED,eAAO,MAAM,UAAU,EAAE,EAAE,CAAC,KAAK,CA6IhC,CAAC"}
@@ -1,60 +1,61 @@
1
1
  import { showsAssistantCaption as e, showsUserCaption as t, waveformIsActive as n, waveformIsSettled as r } from "../../voice/voiceStageState.js";
2
- import { VoiceCaption as i } from "./VoiceCaption.js";
3
- import { VoiceWaveform as a } from "./VoiceWaveform.js";
4
- import { VoiceStatusText as o } from "./VoiceStatusText.js";
5
- import { Fragment as s, jsx as c, jsxs as l } from "react/jsx-runtime";
2
+ import { isAwaitingFirstChunk as i } from "../../voice/speechPlayback.js";
3
+ import { VoiceCaption as a } from "./VoiceCaption.js";
4
+ import { VoiceWaveform as o } from "./VoiceWaveform.js";
5
+ import { VoiceStatusText as s } from "./VoiceStatusText.js";
6
+ import { Fragment as c, jsx as l, jsxs as u } from "react/jsx-runtime";
6
7
  //#region src/shared/assistant/ui/voice/VoiceStage.tsx
7
- var u = ({ state: u, userCaption: d, assistantCaption: f, expanded: p, statusText: m, statusSuffix: h, rotateStatus: g, control: _, errorText: v = null, spokenChunks: y = null }) => {
8
- let b = e(u) ? f : t(u) ? d : null;
9
- return /* @__PURE__ */ l("div", {
8
+ var d = ({ state: d, userCaption: f, assistantCaption: p, expanded: m, statusText: h, statusSuffix: g, rotateStatus: _, control: v, errorText: y = null, spokenChunks: b = null }) => {
9
+ let x = e(d) && i(b), S = e(d) ? p : t(d) ? f : null;
10
+ return /* @__PURE__ */ u("div", {
10
11
  className: [
11
12
  "flex min-h-0 w-full flex-1 flex-col items-center",
12
- p ? "px-8" : "px-14",
13
- p ? "justify-start pt-[16vh]" : "justify-center"
13
+ m ? "px-8" : "px-14",
14
+ m ? "justify-start pt-[16vh]" : "justify-center"
14
15
  ].join(" "),
15
16
  "data-testid": "assistant-voice-stage",
16
- "data-state": u,
17
+ "data-state": d,
17
18
  children: [
18
- /* @__PURE__ */ c(o, {
19
+ /* @__PURE__ */ l(s, {
19
20
  className: [
20
21
  "text-center text-text-muted",
21
- p ? "text-base" : "text-sm",
22
- p ? "mb-3" : "mb-2"
22
+ m ? "text-base" : "text-sm",
23
+ m ? "mb-3" : "mb-2"
23
24
  ].join(" "),
24
- status: m,
25
- suffix: h,
26
- rotating: g
25
+ status: h,
26
+ suffix: g,
27
+ rotating: _
27
28
  }),
28
- u === "mic-error" ? /* @__PURE__ */ c("p", {
29
- className: `max-w-md text-center text-status-warning ${p ? "text-lg" : "text-sm"}`,
29
+ d === "mic-error" ? /* @__PURE__ */ l("p", {
30
+ className: `max-w-md text-center text-status-warning ${m ? "text-lg" : "text-sm"}`,
30
31
  role: "alert",
31
32
  "data-testid": "assistant-voice-stage-error",
32
- children: v
33
- }) : /* @__PURE__ */ l(s, { children: [/* @__PURE__ */ c("div", {
34
- className: p ? "mb-10" : "mb-5",
35
- children: /* @__PURE__ */ c(a, {
36
- active: n(u),
37
- settled: r(u),
38
- tone: u === "speaking" ? "speaking" : "listening",
39
- expanded: p
33
+ children: y
34
+ }) : /* @__PURE__ */ u(c, { children: [/* @__PURE__ */ l("div", {
35
+ className: m ? "mb-10" : "mb-5",
36
+ children: /* @__PURE__ */ l(o, {
37
+ active: n(d),
38
+ settled: r(d),
39
+ tone: d === "speaking" ? "speaking" : "listening",
40
+ expanded: m
40
41
  })
41
- }), b ? /* @__PURE__ */ c("div", {
42
- className: p ? "mb-12 max-h-[46vh] w-full overflow-y-auto" : "mb-6 max-h-[38vh] w-full overflow-y-auto",
42
+ }), S ? /* @__PURE__ */ l("div", {
43
+ className: [m ? "mb-12 max-h-[46vh] w-full overflow-y-auto" : "mb-6 max-h-[38vh] w-full overflow-y-auto", x ? m ? "min-h-[4.875rem]" : "min-h-12" : ""].join(" "),
43
44
  "data-caption-scroll": "",
44
- children: /* @__PURE__ */ c(i, {
45
- text: b,
46
- role: e(u) ? "assistant" : "user",
47
- spokenChunks: y,
48
- expanded: p,
45
+ children: /* @__PURE__ */ l(a, {
46
+ text: S,
47
+ role: e(d) ? "assistant" : "user",
48
+ spokenChunks: b,
49
+ expanded: m,
49
50
  testId: "assistant-voice-caption"
50
51
  })
51
- }) : /* @__PURE__ */ c("div", {
52
- className: p ? "mb-12 h-[4.875rem]" : "mb-6 h-12",
52
+ }) : /* @__PURE__ */ l("div", {
53
+ className: m ? "mb-12 h-[4.875rem]" : "mb-6 h-12",
53
54
  "aria-hidden": "true"
54
55
  })] }),
55
- _
56
+ v
56
57
  ]
57
58
  });
58
59
  };
59
60
  //#endregion
60
- export { u as VoiceStage };
61
+ export { d as VoiceStage };
@@ -14,6 +14,12 @@ import { FC } from 'react';
14
14
  *
15
15
  * When a real VAD stream lands (it is needed for automatic barge-in anyway),
16
16
  * this component gets amplitude as a prop and the animation becomes truthful.
17
+ *
18
+ * ★★ The bars hold still under EITHER reduced-motion signal (BOFF-8566). The
19
+ * pulse class is not emitted at all: `motion-safe:` reads only the device media
20
+ * query, so the app's own Reduce motion setting (`<html data-reduce-motion>`)
21
+ * never reached it. The bar HEIGHTS still carry the state (tall and varied when
22
+ * active, flat when not), so nothing is lost but the throb.
17
23
  */
18
24
  interface Props {
19
25
  /** Bars animate while true; a flat line while false. */