@burdenoff/fe-libs 2026.913.2 → 2026.914.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/dist/shared/assistant/conversation.d.ts +29 -0
  2. package/dist/shared/assistant/conversation.d.ts.map +1 -1
  3. package/dist/shared/assistant/displayContent.d.ts +57 -0
  4. package/dist/shared/assistant/displayContent.d.ts.map +1 -0
  5. package/dist/shared/assistant/displayContent.js +26 -0
  6. package/dist/shared/assistant/exportConversation.d.ts +12 -2
  7. package/dist/shared/assistant/exportConversation.d.ts.map +1 -1
  8. package/dist/shared/assistant/exportConversation.js +24 -22
  9. package/dist/shared/assistant/index.d.ts +7 -0
  10. package/dist/shared/assistant/index.d.ts.map +1 -1
  11. package/dist/shared/assistant/legacyFiller.d.ts +60 -0
  12. package/dist/shared/assistant/legacyFiller.d.ts.map +1 -0
  13. package/dist/shared/assistant/legacyFiller.js +35 -0
  14. package/dist/shared/assistant/preview/previewTransitions.d.ts +15 -1
  15. package/dist/shared/assistant/preview/previewTransitions.d.ts.map +1 -1
  16. package/dist/shared/assistant/preview/previewTransitions.js +5 -2
  17. package/dist/shared/assistant/preview/useAssistantPreviewBridge.d.ts.map +1 -1
  18. package/dist/shared/assistant/preview/useAssistantPreviewBridge.js +51 -52
  19. package/dist/shared/assistant/spokenTurns.d.ts +25 -0
  20. package/dist/shared/assistant/spokenTurns.d.ts.map +1 -0
  21. package/dist/shared/assistant/spokenTurns.js +12 -0
  22. package/dist/shared/assistant/stageCopy.d.ts +23 -34
  23. package/dist/shared/assistant/stageCopy.d.ts.map +1 -1
  24. package/dist/shared/assistant/stageCopy.js +7 -16
  25. package/dist/shared/assistant/store.d.ts +10 -2
  26. package/dist/shared/assistant/store.d.ts.map +1 -1
  27. package/dist/shared/assistant/store.js +16 -9
  28. package/dist/shared/assistant/turnActivity.d.ts +70 -0
  29. package/dist/shared/assistant/turnActivity.d.ts.map +1 -0
  30. package/dist/shared/assistant/turnActivity.js +41 -0
  31. package/dist/shared/assistant/turnProgress.d.ts +51 -0
  32. package/dist/shared/assistant/turnProgress.d.ts.map +1 -0
  33. package/dist/shared/assistant/turnProgress.js +27 -0
  34. package/dist/shared/assistant/ui/AssistantChatArea.d.ts.map +1 -1
  35. package/dist/shared/assistant/ui/AssistantChatArea.js +285 -302
  36. package/dist/shared/assistant/ui/AssistantConversationList.d.ts.map +1 -1
  37. package/dist/shared/assistant/ui/AssistantConversationList.js +81 -80
  38. package/dist/shared/assistant/ui/AssistantMessageItem.d.ts +12 -1
  39. package/dist/shared/assistant/ui/AssistantMessageItem.d.ts.map +1 -1
  40. package/dist/shared/assistant/ui/AssistantMessageItem.js +103 -83
  41. package/dist/shared/assistant/ui/AssistantMessageList.d.ts +7 -1
  42. package/dist/shared/assistant/ui/AssistantMessageList.d.ts.map +1 -1
  43. package/dist/shared/assistant/ui/AssistantMessageList.js +28 -26
  44. package/dist/shared/assistant/ui/AssistantMoreMenu.d.ts.map +1 -1
  45. package/dist/shared/assistant/ui/AssistantMoreMenu.js +23 -20
  46. package/dist/shared/assistant/ui/AssistantTurnActivity.d.ts +40 -0
  47. package/dist/shared/assistant/ui/AssistantTurnActivity.d.ts.map +1 -0
  48. package/dist/shared/assistant/ui/AssistantTurnActivity.js +33 -0
  49. package/dist/shared/assistant/ui/usePrefersReducedMotion.d.ts +55 -0
  50. package/dist/shared/assistant/ui/usePrefersReducedMotion.d.ts.map +1 -0
  51. package/dist/shared/assistant/ui/usePrefersReducedMotion.js +28 -0
  52. package/dist/shared/assistant/ui/voice/VoiceMiniController.d.ts +4 -2
  53. package/dist/shared/assistant/ui/voice/VoiceMiniController.d.ts.map +1 -1
  54. package/dist/shared/assistant/ui/voice/VoiceStage.d.ts +4 -2
  55. package/dist/shared/assistant/ui/voice/VoiceStage.d.ts.map +1 -1
  56. package/dist/shared/assistant/ui/voice/VoiceStatusText.d.ts +12 -1
  57. package/dist/shared/assistant/ui/voice/VoiceStatusText.d.ts.map +1 -1
  58. package/dist/shared/assistant/ui/voice/VoiceStatusText.js +19 -18
  59. package/dist/shared/assistant/voice/voiceStatus.d.ts +8 -2
  60. package/dist/shared/assistant/voice/voiceStatus.d.ts.map +1 -1
  61. package/dist/shared-assistant.js +74 -67
  62. package/package.json +1 -1
@@ -1,39 +1,41 @@
1
1
  import { useAssistantTr as e } from "../i18n.js";
2
- import { AssistantMessageItem as t } from "./AssistantMessageItem.js";
3
- import { useEffect as n, useRef as r } from "react";
4
- import { jsx as i, jsxs as a } from "react/jsx-runtime";
2
+ import { readReducedMotion as t } from "./usePrefersReducedMotion.js";
3
+ import { AssistantMessageItem as n } from "./AssistantMessageItem.js";
4
+ import { useEffect as r, useRef as i } from "react";
5
+ import { jsx as a, jsxs as o } from "react/jsx-runtime";
5
6
  //#region src/shared/assistant/ui/AssistantMessageList.tsx
6
- var o = ({ onApprovePendingWrite: o, approvingWriteRef: s = null, messages: c, streamingMessageId: l, failedMessageId: u, onRetry: d }) => {
7
- let f = e(), p = (() => {
8
- for (let e = c.length - 1; e >= 0; --e) if (c[e].role === "assistant") return c[e].id;
7
+ var s = ({ onApprovePendingWrite: s, approvingWriteRef: c = null, messages: l, processing: u, streamingMessageId: d, failedMessageId: f, onRetry: p }) => {
8
+ let m = e(), h = (() => {
9
+ for (let e = l.length - 1; e >= 0; --e) if (l[e].role === "assistant") return l[e].id;
9
10
  return null;
10
- })(), m = r(null), h = r(null);
11
- return n(() => {
12
- let e = h.current;
11
+ })(), g = i(null), _ = i(null);
12
+ return r(() => {
13
+ let e = _.current;
13
14
  if (e && e.scrollHeight - e.scrollTop - e.clientHeight < 100) {
14
- let e = typeof window < "u" && window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
15
- m.current?.scrollIntoView({ behavior: e ? "auto" : "smooth" });
15
+ let e = t();
16
+ g.current?.scrollIntoView({ behavior: e ? "auto" : "smooth" });
16
17
  }
17
- }, [c, l]), n(() => {
18
- m.current?.scrollIntoView({ behavior: "instant" });
19
- }, []), /* @__PURE__ */ a("div", {
20
- ref: h,
18
+ }, [l, d]), r(() => {
19
+ g.current?.scrollIntoView({ behavior: "instant" });
20
+ }, []), /* @__PURE__ */ o("div", {
21
+ ref: _,
21
22
  className: "flex-1 space-y-4 overflow-y-auto p-3",
22
23
  role: "log",
23
24
  "aria-live": "polite",
24
25
  "aria-relevant": "additions",
25
- "aria-busy": l !== null,
26
- "aria-label": f("messageList.ariaLabel", "Conversation messages"),
27
- children: [c.map((e) => /* @__PURE__ */ i(t, {
28
- onApprovePendingWrite: o,
29
- approvingWriteRef: s,
26
+ "aria-busy": d !== null,
27
+ "aria-label": m("messageList.ariaLabel", "Conversation messages"),
28
+ children: [l.map((e) => /* @__PURE__ */ a(n, {
29
+ onApprovePendingWrite: s,
30
+ approvingWriteRef: c,
30
31
  message: e,
31
- isStreaming: e.id === l,
32
- isFailed: e.id === u,
33
- isLastAssistant: e.id === p,
34
- onRetry: d
35
- }, e.id)), /* @__PURE__ */ i("div", { ref: m })]
32
+ processing: u,
33
+ isStreaming: e.id === d,
34
+ isFailed: e.id === f,
35
+ isLastAssistant: e.id === h,
36
+ onRetry: p
37
+ }, e.id)), /* @__PURE__ */ a("div", { ref: g })]
36
38
  });
37
39
  };
38
40
  //#endregion
39
- export { o as AssistantMessageList };
41
+ export { s as AssistantMessageList };
@@ -1 +1 @@
1
- {"version":3,"file":"AssistantMoreMenu.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/ui/AssistantMoreMenu.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA+B,KAAK,EAAE,EAAE,MAAM,OAAO,CAAC;AAiB7D;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,eAAO,MAAM,iBAAiB,EAAE,EAgM/B,CAAC"}
1
+ {"version":3,"file":"AssistantMoreMenu.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/ui/AssistantMoreMenu.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA+B,KAAK,EAAE,EAAE,MAAM,OAAO,CAAC;AAiB7D;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,eAAO,MAAM,iBAAiB,EAAE,EAqM/B,CAAC"}
@@ -10,7 +10,7 @@ import { Check as d, FileJson as f, FileText as p, MoreHorizontal as m, Play as
10
10
  import { Fragment as _, jsx as v, jsxs as y } from "react/jsx-runtime";
11
11
  //#region src/shared/assistant/ui/AssistantMoreMenu.tsx
12
12
  var b = () => {
13
- let b = e(), [x, S] = u(!1), C = l(null), w = l(null), { conversations: T, activeConversationId: E } = t(), D = T.find((e) => e.id === E), O = !!(D && D.messages.length > 0), { isSupported: k, isBlocked: A, disabledReason: j, autoSpeakEnabled: M, setAutoSpeak: N, stop: P, previewVoice: F, activeVoiceName: I } = n(), L = A && !M;
13
+ let b = e(), [x, S] = u(!1), C = l(null), w = l(null), { conversations: T, activeConversationId: E, processingByConversationId: D } = t(), O = T.find((e) => e.id === E), k = !!(O && O.messages.length > 0), { isSupported: A, isBlocked: j, disabledReason: M, autoSpeakEnabled: N, setAutoSpeak: P, stop: F, previewVoice: I, activeVoiceName: L } = n(), R = j && !N;
14
14
  i(x, C, w, () => S(!1)), c(() => {
15
15
  if (!x) return;
16
16
  let e = (e) => {
@@ -21,13 +21,16 @@ var b = () => {
21
21
  document.removeEventListener("mousedown", e);
22
22
  };
23
23
  }, [x]);
24
- let R = (e) => {
25
- if (!D) return;
26
- let { content: t, filename: n, mimeType: r } = s(D, e);
24
+ let z = (e) => {
25
+ if (!O) return;
26
+ let { content: t, filename: n, mimeType: r } = s(O, e, {
27
+ processing: D[O.id],
28
+ tr: b
29
+ });
27
30
  o(t, n, r), S(!1);
28
- }, z = () => {
29
- M && P(), N(!M);
30
- }, B = b("header.more", "More options");
31
+ }, B = () => {
32
+ N && F(), P(!N);
33
+ }, V = b("header.more", "More options");
31
34
  return /* @__PURE__ */ y("div", {
32
35
  className: "relative",
33
36
  children: [/* @__PURE__ */ v("button", {
@@ -35,7 +38,7 @@ var b = () => {
35
38
  type: "button",
36
39
  onClick: () => S((e) => !e),
37
40
  className: "rounded p-1 transition-colors hover:bg-bg-elevated",
38
- "aria-label": B,
41
+ "aria-label": V,
39
42
  "aria-haspopup": "menu",
40
43
  "aria-expanded": x,
41
44
  "data-testid": "assistant-more",
@@ -43,17 +46,17 @@ var b = () => {
43
46
  }), x ? /* @__PURE__ */ y("div", {
44
47
  ref: C,
45
48
  role: "menu",
46
- "aria-label": B,
49
+ "aria-label": V,
47
50
  className: "absolute right-0 top-full z-50 mt-1 min-w-56 overflow-hidden rounded-xl border border-border-default bg-bg-surface py-1 shadow-lg",
48
51
  "data-testid": "assistant-more-menu",
49
52
  children: [
50
- k ? /* @__PURE__ */ y("button", {
53
+ A ? /* @__PURE__ */ y("button", {
51
54
  type: "button",
52
55
  role: "menuitemcheckbox",
53
- "aria-checked": M,
54
- onClick: z,
55
- disabled: L,
56
- title: L ? j ?? void 0 : void 0,
56
+ "aria-checked": N,
57
+ onClick: B,
58
+ disabled: R,
59
+ title: R ? M ?? void 0 : void 0,
57
60
  className: "flex w-full items-center gap-2.5 px-3 py-2 text-left text-xs text-text-primary transition-colors hover:bg-bg-elevated disabled:cursor-not-allowed disabled:text-text-muted disabled:hover:bg-transparent",
58
61
  "data-testid": "assistant-auto-speak",
59
62
  children: [
@@ -65,16 +68,16 @@ var b = () => {
65
68
  className: "flex-1",
66
69
  children: b("header.autoRead", "Auto-read replies")
67
70
  }),
68
- M ? /* @__PURE__ */ v(d, { className: "size-3.5 flex-shrink-0 text-action-primary-bg" }) : null
71
+ N ? /* @__PURE__ */ v(d, { className: "size-3.5 flex-shrink-0 text-action-primary-bg" }) : null
69
72
  ]
70
73
  }) : null,
71
74
  /* @__PURE__ */ v(r, {}),
72
75
  /* @__PURE__ */ y("div", {
73
76
  className: "flex items-center gap-1 px-3 py-1.5",
74
77
  "data-testid": "assistant-more-voice",
75
- children: [/* @__PURE__ */ v(a, {}), I ? /* @__PURE__ */ y("button", {
78
+ children: [/* @__PURE__ */ v(a, {}), L ? /* @__PURE__ */ y("button", {
76
79
  type: "button",
77
- onClick: () => F(I),
80
+ onClick: () => I(L),
78
81
  className: "flex items-center gap-1 rounded-md px-1.5 py-1 text-[11px] text-text-muted transition-colors hover:bg-bg-elevated hover:text-text-secondary focus:outline-none focus-visible:ring-2 focus-visible:ring-border-strong",
79
82
  "aria-label": b("voice.preview", "Hear this voice"),
80
83
  "data-testid": "assistant-voice-preview",
@@ -84,7 +87,7 @@ var b = () => {
84
87
  }), b("voice.previewShort", "Preview")]
85
88
  }) : null]
86
89
  }),
87
- O ? /* @__PURE__ */ y(_, { children: [
90
+ k ? /* @__PURE__ */ y(_, { children: [
88
91
  /* @__PURE__ */ v("div", {
89
92
  className: "my-1 border-t border-border-subtle",
90
93
  role: "separator"
@@ -92,7 +95,7 @@ var b = () => {
92
95
  /* @__PURE__ */ y("button", {
93
96
  type: "button",
94
97
  role: "menuitem",
95
- onClick: () => R("json"),
98
+ onClick: () => z("json"),
96
99
  className: "flex w-full items-center gap-2.5 px-3 py-2 text-left text-xs text-text-primary transition-colors hover:bg-bg-elevated",
97
100
  "data-testid": "export-json",
98
101
  children: [/* @__PURE__ */ v(f, {
@@ -103,7 +106,7 @@ var b = () => {
103
106
  /* @__PURE__ */ y("button", {
104
107
  type: "button",
105
108
  role: "menuitem",
106
- onClick: () => R("markdown"),
109
+ onClick: () => z("markdown"),
107
110
  className: "flex w-full items-center gap-2.5 px-3 py-2 text-left text-xs text-text-primary transition-colors hover:bg-bg-elevated",
108
111
  "data-testid": "export-markdown",
109
112
  children: [/* @__PURE__ */ v(p, {
@@ -0,0 +1,40 @@
1
+ import { FC } from 'react';
2
+ import { AssistantConversationProcessing } from '../conversation';
3
+ /**
4
+ * The waiting line for one turn, as markup.
5
+ *
6
+ * ★ Two spans, like the voice status line: the moving phrase is hidden from
7
+ * assistive tech and the step's label is read instead, so a screen reader
8
+ * browsing the transcript hears "Thinking..." rather than whichever decoration
9
+ * the rotation happened to be on. Neither is a live region — the transcript is
10
+ * `role="log"` and `aria-busy` while a turn runs, which already says so.
11
+ *
12
+ * ★ `relative` contains the `sr-only` span. Without a positioned ancestor its
13
+ * absolute box escapes to the nearest scroll container.
14
+ *
15
+ * Exported separately so the markup can be rendered with different shown and
16
+ * label text; static rendering runs no clock, so the stateful component alone
17
+ * would only ever show the two equal.
18
+ */
19
+ export declare const TurnActivityLine: FC<{
20
+ shown: string;
21
+ label: string;
22
+ }>;
23
+ /**
24
+ * What a live turn is doing, drawn from its processing state (BOFF-7277).
25
+ *
26
+ * ★★ The clock lives HERE. A tick re-renders only this line, the orchestrator
27
+ * stays free of timers, and nothing is written anywhere — the message's content
28
+ * is untouched while the phrase moves.
29
+ *
30
+ * ★ Under reduced motion the line holds the step's label instead of rotating:
31
+ * text that changes every few seconds on its own is what a person asking for
32
+ * less motion wants stopped, as the avatar and caret already are. BOTH routes
33
+ * count — the OS setting and the app's own "Reduce motion" (BOFF-7284); this
34
+ * used to honour only the first. (For auto-updating text the WCAG criterion is
35
+ * 2.2.2 Pause, Stop, Hide.)
36
+ */
37
+ export declare const AssistantTurnActivity: FC<{
38
+ processing: AssistantConversationProcessing | null | undefined;
39
+ }>;
40
+ //# sourceMappingURL=AssistantTurnActivity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AssistantTurnActivity.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/ui/AssistantTurnActivity.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,EAAE,EAAE,MAAM,OAAO,CAAC;AAErD,OAAO,KAAK,EAAE,+BAA+B,EAAE,MAAM,iBAAiB,CAAC;AAUvE;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,gBAAgB,EAAE,EAAE,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAkBjE,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,qBAAqB,EAAE,EAAE,CAAC;IACrC,UAAU,EAAE,+BAA+B,GAAG,IAAI,GAAG,SAAS,CAAC;CAChE,CAaA,CAAC"}
@@ -0,0 +1,33 @@
1
+ import { useAssistantTr as e } from "../i18n.js";
2
+ import { elapsedSince as t, startPhraseTicker as n, turnActivityCopy as r, turnActivityStage as i } from "../turnActivity.js";
3
+ import { usePrefersReducedMotion as a } from "./usePrefersReducedMotion.js";
4
+ import { useEffect as o, useState as s } from "react";
5
+ import { jsx as c, jsxs as l } from "react/jsx-runtime";
6
+ //#region src/shared/assistant/ui/AssistantTurnActivity.tsx
7
+ var u = ({ shown: e, label: t }) => /* @__PURE__ */ l("p", {
8
+ className: "relative text-[15px] leading-relaxed text-text-secondary",
9
+ "data-testid": "assistant-turn-activity",
10
+ children: [/* @__PURE__ */ c("span", {
11
+ "aria-hidden": "true",
12
+ "data-testid": "assistant-turn-activity-shown",
13
+ children: e
14
+ }), /* @__PURE__ */ c("span", {
15
+ className: "sr-only left-0 top-0",
16
+ "data-testid": "assistant-turn-activity-label",
17
+ children: t
18
+ })]
19
+ }), d = ({ processing: t }) => {
20
+ let n = e(), o = a(), s = r(n, t, f(i(t) === "thinking" && !o && typeof t?.stageStartedAt == "number" ? t.stageStartedAt : null));
21
+ return s ? /* @__PURE__ */ c(u, {
22
+ shown: s.shown,
23
+ label: s.label
24
+ }) : null;
25
+ };
26
+ function f(e) {
27
+ let [r, i] = s(() => Date.now());
28
+ return o(() => {
29
+ if (e !== null) return n(e, i);
30
+ }, [e]), t(e, r);
31
+ }
32
+ //#endregion
33
+ export { d as AssistantTurnActivity, u as TurnActivityLine };
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Whether the person has asked for less motion — by EITHER route.
3
+ *
4
+ * ★★ TWO SIGNALS, and the assistant's own animated text must obey both:
5
+ *
6
+ * - the operating system's `prefers-reduced-motion: reduce`;
7
+ * - the app's own "Reduce motion" setting (ThemePreferences). `ThemeProvider`
8
+ * writes its EFFECTIVE value — a custom theme's override included — to
9
+ * `<html data-reduce-motion>`, and `tokens.css` clamps every CSS animation
10
+ * under that attribute.
11
+ *
12
+ * CSS covers the avatar, the caret and every `motion-safe:` class. It cannot
13
+ * stop a phrase that JavaScript swaps every few seconds, which is why the chat
14
+ * waiting line honoured only the OS setting and the voice status line honoured
15
+ * neither (BOFF-7284). Reading the attribute rather than theme context keeps the
16
+ * JS in lockstep with the CSS by construction, needs no change to
17
+ * `ThemeProvider` (whose context is not exported, and whose `useTheme` throws
18
+ * without a provider), and in a host with no `ThemeProvider` simply falls back
19
+ * to the OS signal.
20
+ */
21
+ export declare const REDUCED_MOTION_QUERY = "(prefers-reduced-motion: reduce)";
22
+ export declare const REDUCED_MOTION_ATTRIBUTE = "data-reduce-motion";
23
+ /**
24
+ * The current answer, read fresh from the environment every time.
25
+ *
26
+ * ★ Guarded piece by piece — `window`, `matchMedia` and `document` are each
27
+ * absent in some test or render environment here — and never cached: a test
28
+ * may swap `window` between two renders, and a cached `MediaQueryList` would
29
+ * keep answering for the old one.
30
+ */
31
+ export declare function readReducedMotion(): boolean;
32
+ /**
33
+ * Call `onChange` whenever either signal may have changed. Returns the cleanup.
34
+ *
35
+ * ★ The attribute is written by a passive effect in `ThemeProvider`, one commit
36
+ * after its state changes — the observer is what carries that change here
37
+ * without a reload.
38
+ */
39
+ export declare function subscribeReducedMotion(onChange: () => void): () => void;
40
+ /**
41
+ * React binding: re-renders the caller when either signal changes.
42
+ *
43
+ * ★★ The server snapshot is the SAME guarded reader, deliberately — not a
44
+ * constant `false`. On a real server there is no `window`, so it answers false
45
+ * anyway; under a test that stubs the environment it answers from the stub, which
46
+ * is what lets a static render prove the reduced-motion path at all. Both host
47
+ * apps mount with `createRoot`, so there is no hydration for this to mismatch.
48
+ *
49
+ * ★ Not for `hydrateRoot`: on hydration React calls the server snapshot on the
50
+ * client, where this reader can answer true while the server's HTML was rendered
51
+ * with false — a recoverable hydration mismatch. A future SSR consumer must pass
52
+ * a constant server snapshot instead.
53
+ */
54
+ export declare function usePrefersReducedMotion(): boolean;
55
+ //# sourceMappingURL=usePrefersReducedMotion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePrefersReducedMotion.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/ui/usePrefersReducedMotion.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,oBAAoB,qCAAqC,CAAC;AACvE,eAAO,MAAM,wBAAwB,uBAAuB,CAAC;AAE7D;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAW3C;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CA+BvE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,uBAAuB,IAAI,OAAO,CAMjD"}
@@ -0,0 +1,28 @@
1
+ import { useSyncExternalStore as e } from "react";
2
+ //#region src/shared/assistant/ui/usePrefersReducedMotion.ts
3
+ var t = "(prefers-reduced-motion: reduce)", n = "data-reduce-motion";
4
+ function r() {
5
+ return typeof document < "u" && typeof document.documentElement?.hasAttribute == "function" && document.documentElement.hasAttribute("data-reduce-motion") ? !0 : typeof window > "u" || typeof window.matchMedia != "function" ? !1 : window.matchMedia(t)?.matches === !0;
6
+ }
7
+ function i(e) {
8
+ let r = [];
9
+ if (typeof window < "u" && typeof window.matchMedia == "function") {
10
+ let n = window.matchMedia(t);
11
+ typeof n?.addEventListener == "function" ? (n.addEventListener("change", e), r.push(() => n.removeEventListener("change", e))) : typeof n?.addListener == "function" && (n.addListener(e), r.push(() => n.removeListener(e)));
12
+ }
13
+ if (typeof document < "u" && document.documentElement && typeof MutationObserver < "u") {
14
+ let t = new MutationObserver(e);
15
+ t.observe(document.documentElement, {
16
+ attributes: !0,
17
+ attributeFilter: [n]
18
+ }), r.push(() => t.disconnect());
19
+ }
20
+ return () => {
21
+ for (let e of r) e();
22
+ };
23
+ }
24
+ function a() {
25
+ return e(i, r, r);
26
+ }
27
+ //#endregion
28
+ export { n as REDUCED_MOTION_ATTRIBUTE, t as REDUCED_MOTION_QUERY, r as readReducedMotion, i as subscribeReducedMotion, a as usePrefersReducedMotion };
@@ -43,8 +43,10 @@ interface Props {
43
43
  */
44
44
  statusSuffix?: string | null;
45
45
  /**
46
- * Rotate the SHOWN status through the thinking phrases while the assistant
47
- * thinks. What is ANNOUNCED is always `statusText` — see `VoiceStatusText`.
46
+ * Ask for the SHOWN status to rotate through the thinking phrases while the
47
+ * assistant thinks — suppressed under reduced motion (OS or app setting, see
48
+ * `usePrefersReducedMotion`). What is ANNOUNCED is always `statusText` — see
49
+ * `VoiceStatusText`.
48
50
  */
49
51
  rotateStatus?: boolean;
50
52
  /** Mic / interrupt control — the same orb, in its compact size. */
@@ -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;;;OAGG;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;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"}
@@ -33,8 +33,10 @@ interface Props {
33
33
  */
34
34
  statusSuffix?: string | null;
35
35
  /**
36
- * Rotate the SHOWN status through the thinking phrases while the assistant
37
- * thinks. What is ANNOUNCED is always `statusText` — see `VoiceStatusText`.
36
+ * Ask for the SHOWN status to rotate through the thinking phrases while the
37
+ * assistant thinks — suppressed under reduced motion (OS or app setting, see
38
+ * `usePrefersReducedMotion`). What is ANNOUNCED is always `statusText` — see
39
+ * `VoiceStatusText`.
38
40
  */
39
41
  rotateStatus?: boolean;
40
42
  /** The microphone / interrupt control. */
@@ -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;;;OAGG;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;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"}
@@ -38,13 +38,24 @@ export declare const VoiceStatusLine: FC<{
38
38
  *
39
39
  * ★ The clock lives HERE, not in `AssistantVoiceSession`: a tick re-renders only
40
40
  * this line, and the orchestrators stay free of timers.
41
+ *
42
+ * ★★ Under reduced motion — the OS setting OR the app's own (BOFF-7284) — the
43
+ * line does not rotate: no clock runs, and it shows the status itself, e.g.
44
+ * "Thinking…" (with "· Microphone off" when muted). A phrase swapped every
45
+ * 2.5 seconds is exactly the self-starting movement that preference asks to stop.
46
+ * The announced text was never affected, so nothing changes for a screen reader.
47
+ * (The WCAG criterion for auto-updating text is 2.2.2 Pause, Stop, Hide; the
48
+ * reduced-motion preferences are how a person asks for it here.)
41
49
  */
42
50
  export declare const VoiceStatusText: FC<{
43
51
  /** The meaningful status. This is what is announced. */
44
52
  status: string;
45
53
  /** Kept visible while the shown phrase rotates, e.g. "Microphone off". */
46
54
  suffix?: string | null;
47
- /** Rotate the SHOWN text through the thinking phrases. */
55
+ /**
56
+ * The stage ASKS to rotate the shown text through the thinking phrases. The
57
+ * line honours it only when motion is allowed — see `usePrefersReducedMotion`.
58
+ */
48
59
  rotating?: boolean;
49
60
  className: string;
50
61
  }>;
@@ -1 +1 @@
1
- {"version":3,"file":"VoiceStatusText.d.ts","sourceRoot":"","sources":["../../../../../src/shared/assistant/ui/voice/VoiceStatusText.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,EAAE,EAAE,MAAM,OAAO,CAAC;AAYrD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,eAAe,EAAE,EAAE,CAAC;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB,CAiBA,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,EAAE,EAAE,CAAC;IAC/B,wDAAwD;IACxD,MAAM,EAAE,MAAM,CAAC;IACf,0EAA0E;IAC1E,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB,CAiBA,CAAC"}
1
+ {"version":3,"file":"VoiceStatusText.d.ts","sourceRoot":"","sources":["../../../../../src/shared/assistant/ui/voice/VoiceStatusText.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,EAAE,EAAE,MAAM,OAAO,CAAC;AAarD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,eAAe,EAAE,EAAE,CAAC;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB,CAiBA,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,eAAe,EAAE,EAAE,CAAC;IAC/B,wDAAwD;IACxD,MAAM,EAAE,MAAM,CAAC;IACf,0EAA0E;IAC1E,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB,CAqBA,CAAC"}
@@ -1,42 +1,43 @@
1
1
  import { useAssistantTr as e } from "../../i18n.js";
2
2
  import { voiceStatusParts as t } from "../../voice/voiceStatus.js";
3
3
  import { IDLE_ROTATION_CLOCK as n, advanceRotationClock as r, rotationElapsedMs as i, startRotationTicker as a, syncRotationClock as o } from "../../voice/rotationClock.js";
4
- import { useEffect as s, useState as c } from "react";
5
- import { jsx as l, jsxs as u } from "react/jsx-runtime";
4
+ import { usePrefersReducedMotion as s } from "../usePrefersReducedMotion.js";
5
+ import { useEffect as c, useState as l } from "react";
6
+ import { jsx as u, jsxs as d } from "react/jsx-runtime";
6
7
  //#region src/shared/assistant/ui/voice/VoiceStatusText.tsx
7
- var d = ({ announced: e, shown: t, className: n }) => /* @__PURE__ */ u("p", {
8
+ var f = ({ announced: e, shown: t, className: n }) => /* @__PURE__ */ d("p", {
8
9
  className: `relative ${n}`,
9
10
  "data-testid": "assistant-voice-status-line",
10
- children: [/* @__PURE__ */ l("span", {
11
+ children: [/* @__PURE__ */ u("span", {
11
12
  "aria-hidden": "true",
12
13
  "data-testid": "assistant-voice-status-shown",
13
14
  children: t
14
- }), /* @__PURE__ */ l("span", {
15
+ }), /* @__PURE__ */ u("span", {
15
16
  className: "sr-only left-0 top-0",
16
17
  "aria-live": "polite",
17
18
  "aria-atomic": "true",
18
19
  "data-testid": "assistant-voice-status",
19
20
  children: e
20
21
  })]
21
- }), f = ({ status: n, suffix: r = null, rotating: i = !1, className: a }) => {
22
- let { announced: o, shown: s } = t({
23
- tr: e(),
22
+ }), p = ({ status: n, suffix: r = null, rotating: i = !1, className: a }) => {
23
+ let o = e(), c = s(), l = i && !c, { announced: d, shown: p } = t({
24
+ tr: o,
24
25
  status: n,
25
26
  suffix: r,
26
- rotating: i,
27
- elapsedMs: p(i)
27
+ rotating: l,
28
+ elapsedMs: m(l)
28
29
  });
29
- return /* @__PURE__ */ l(d, {
30
+ return /* @__PURE__ */ u(f, {
30
31
  className: a,
31
- announced: o,
32
- shown: s
32
+ announced: d,
33
+ shown: p
33
34
  });
34
35
  };
35
- function p(e) {
36
- let [t, l] = c(() => o(n, e)), u = o(t, e);
37
- return u !== t && l(u), s(() => {
38
- if (e) return a(() => l((e) => r(e)));
36
+ function m(e) {
37
+ let [t, s] = l(() => o(n, e)), u = o(t, e);
38
+ return u !== t && s(u), c(() => {
39
+ if (e) return a(() => s((e) => r(e)));
39
40
  }, [e]), i(u);
40
41
  }
41
42
  //#endregion
42
- export { d as VoiceStatusLine, f as VoiceStatusText };
43
+ export { f as VoiceStatusLine, p as VoiceStatusText };
@@ -64,7 +64,10 @@ export declare function composeVoiceStatus(label: string, suffix: string | null)
64
64
  export interface VoiceStatusParts {
65
65
  /** For the live region. Changes only when the status does. */
66
66
  readonly announced: string;
67
- /** For the eye. Rotates while thinking; otherwise identical to `announced`. */
67
+ /**
68
+ * For the eye. Rotates while `rotating` (thinking, with motion allowed);
69
+ * otherwise identical to `announced`.
70
+ */
68
71
  readonly shown: string;
69
72
  }
70
73
  export declare function voiceStatusParts(args: {
@@ -73,7 +76,10 @@ export declare function voiceStatusParts(args: {
73
76
  status: string;
74
77
  /** Kept on the shown text while it rotates, e.g. "Microphone off". */
75
78
  suffix: string | null;
76
- /** True only while the assistant is thinking. */
79
+ /**
80
+ * Whether the shown text may rotate: the assistant is thinking AND motion is
81
+ * allowed. `VoiceStatusText` passes false under reduced motion (BOFF-7284).
82
+ */
77
83
  rotating: boolean;
78
84
  /** Time since rotation began. */
79
85
  elapsedMs: number;
@@ -1 +1 @@
1
- {"version":3,"file":"voiceStatus.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/voice/voiceStatus.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,EAIL,KAAK,cAAc,EACpB,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD,yGAAyG;AACzG,eAAO,MAAM,oBAAoB,EAAE,cAGlC,CAAC;AAEF,8DAA8D;AAC9D,eAAO,MAAM,iBAAiB,EAAE,cAG/B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE;IACtC,EAAE,EAAE,WAAW,CAAC;IAChB,KAAK,EAAE,eAAe,CAAC;IACvB,KAAK,EAAE,OAAO,CAAC;IACf,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;CACf,GAAG,MAAM,GAAG,IAAI,CAKhB;AAED,2EAA2E;AAC3E,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GAAG,IAAI,GACpB,MAAM,CAER;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,WAAW,gBAAgB;IAC/B,8DAA8D;IAC9D,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,+EAA+E;IAC/E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAKD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IACrC,EAAE,EAAE,WAAW,CAAC;IAChB,gEAAgE;IAChE,MAAM,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,iDAAiD;IACjD,QAAQ,EAAE,OAAO,CAAC;IAClB,iCAAiC;IACjC,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,gBAAgB,CAmBnB"}
1
+ {"version":3,"file":"voiceStatus.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/voice/voiceStatus.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,EAIL,KAAK,cAAc,EACpB,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD,yGAAyG;AACzG,eAAO,MAAM,oBAAoB,EAAE,cAGlC,CAAC;AAEF,8DAA8D;AAC9D,eAAO,MAAM,iBAAiB,EAAE,cAG/B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE;IACtC,EAAE,EAAE,WAAW,CAAC;IAChB,KAAK,EAAE,eAAe,CAAC;IACvB,KAAK,EAAE,OAAO,CAAC;IACf,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;CACf,GAAG,MAAM,GAAG,IAAI,CAKhB;AAED,2EAA2E;AAC3E,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GAAG,IAAI,GACpB,MAAM,CAER;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,WAAW,gBAAgB;IAC/B,8DAA8D;IAC9D,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAKD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IACrC,EAAE,EAAE,WAAW,CAAC;IAChB,gEAAgE;IAChE,MAAM,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB;;;OAGG;IACH,QAAQ,EAAE,OAAO,CAAC;IAClB,iCAAiC;IACjC,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,gBAAgB,CAmBnB"}