@burdenoff/fe-libs 2026.1014.4 → 2026.1014.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/shared/assistant/avatar/useAvatarCopy.d.ts +2 -0
- package/dist/shared/assistant/avatar/useAvatarCopy.js +1 -0
- package/dist/shared/assistant/i18nManifest.d.ts +1 -0
- package/dist/shared/assistant/i18nManifest.js +1 -0
- package/dist/shared/assistant/ui/AIAssistantPanel.js +20 -20
- package/dist/shared/assistant/ui/assistantLiveAvatarSeam.d.ts +28 -0
- package/dist/shared/assistant/ui/assistantLiveAvatarSeam.js +66 -43
- package/dist/shared/assistant/ui/composer/AssistantHandsFreeInterruptToggle.d.ts +9 -0
- package/dist/shared/assistant/ui/composer/AssistantHandsFreeInterruptToggle.js +28 -14
- package/dist/shared/assistant/ui/useVoiceSession.js +234 -233
- package/dist/shared/assistant/ui/voice/AssistantVoiceSession.js +183 -177
- package/dist/shared/assistant/ui/voice/VoiceMiniController.js +7 -7
- package/dist/shared/assistant/ui/voice/VoiceStage.js +7 -7
- package/dist/shared/assistant/voice/handsfree/handsFreeSetting.d.ts +7 -1
- package/dist/shared/assistant/voice/handsfree/handsFreeSetting.js +2 -2
- package/dist/shared-assistant.js +185 -185
- package/package.json +1 -1
|
@@ -48,6 +48,8 @@ export interface AvatarCopy {
|
|
|
48
48
|
voiceModePaired: string;
|
|
49
49
|
voiceModeMine: string;
|
|
50
50
|
voiceModeHint: string;
|
|
51
|
+
/** Why hands-free interrupt is off while the avatar is on (the pilot rule), and that it stays off after: the session's notice, and its control's reason. */
|
|
52
|
+
handsFreeOff: string;
|
|
51
53
|
problem: (problem: AvatarProblem) => string;
|
|
52
54
|
}
|
|
53
55
|
export declare function useAvatarCopy(): AvatarCopy;
|
|
@@ -32,6 +32,7 @@ function n() {
|
|
|
32
32
|
voiceModePaired: n("avatar.voiceModePaired", "Use this avatar's recommended voice"),
|
|
33
33
|
voiceModeMine: n("avatar.voiceModeMine", "Keep my current voice"),
|
|
34
34
|
voiceModeHint: n("avatar.voiceModeHint", "The recommended voice is chosen for this avatar and the language of each reply."),
|
|
35
|
+
handsFreeOff: n("avatar.handsFreeOff", "Hands-free interrupt is off, so the avatar's voice can't interrupt itself. It stays off after you turn the avatar off; turn it back on in More options. You can still tap to interrupt."),
|
|
35
36
|
problem: (e) => {
|
|
36
37
|
switch (e) {
|
|
37
38
|
case "unavailable": return n("avatar.problemUnavailable", "The avatar isn’t available here.");
|
|
@@ -227,6 +227,7 @@ export declare const ASSISTANT_I18N_LITERAL_COPY: {
|
|
|
227
227
|
readonly "avatar.consent": "Turning on Avatar shares the assistant's reply audio with LiveKit and Protoface to animate the avatar. This feature does not send your microphone audio to Protoface.";
|
|
228
228
|
readonly "avatar.consentCancel": "Not now";
|
|
229
229
|
readonly "avatar.consentConfirm": "Turn on the avatar";
|
|
230
|
+
readonly "avatar.handsFreeOff": "Hands-free interrupt is off, so the avatar's voice can't interrupt itself. It stays off after you turn the avatar off; turn it back on in More options. You can still tap to interrupt.";
|
|
230
231
|
readonly "avatar.problemAlreadyRunning": "An avatar is already running for you.";
|
|
231
232
|
readonly "avatar.problemCapacity": "Avatars are busy right now. Try again in a moment.";
|
|
232
233
|
readonly "avatar.problemConnection": "The connection to the avatar was lost.";
|
|
@@ -121,6 +121,7 @@ var m = {
|
|
|
121
121
|
"avatar.consent": "Turning on Avatar shares the assistant's reply audio with LiveKit and Protoface to animate the avatar. This feature does not send your microphone audio to Protoface.",
|
|
122
122
|
"avatar.consentCancel": "Not now",
|
|
123
123
|
"avatar.consentConfirm": "Turn on the avatar",
|
|
124
|
+
"avatar.handsFreeOff": "Hands-free interrupt is off, so the avatar's voice can't interrupt itself. It stays off after you turn the avatar off; turn it back on in More options. You can still tap to interrupt.",
|
|
124
125
|
"avatar.problemAlreadyRunning": "An avatar is already running for you.",
|
|
125
126
|
"avatar.problemCapacity": "Avatars are busy right now. Try again in a moment.",
|
|
126
127
|
"avatar.problemConnection": "The connection to the avatar was lost.",
|
|
@@ -4,14 +4,14 @@ import { useAssistantPageLabel as n } from "../product.js";
|
|
|
4
4
|
import { useAssistantTr as r } from "../i18n.js";
|
|
5
5
|
import { useAssistantStore as i } from "../store.js";
|
|
6
6
|
import { AssistantSpeechProvider as a } from "./AssistantSpeechProvider.js";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
7
|
+
import { ASSISTANT_OVERLAY_ATTR as o, ASSISTANT_PANEL_ATTR as s, activePanelOverlay as c, escapeDismisses as l, nextPanelOverlays as u } from "./panelOverlays.js";
|
|
8
|
+
import { LiveAvatarSeamProvider as d, useLiveAvatarSpeechEngine as f } from "./assistantLiveAvatarSeam.js";
|
|
9
|
+
import { AssistantPreviewProvider as p } from "../preview/context.js";
|
|
10
|
+
import { useAssistantPreviewBridge as ee } from "../preview/useAssistantPreviewBridge.js";
|
|
11
|
+
import { AssistantConnectSourceProvider as te } from "./composer/connectSource.js";
|
|
12
|
+
import { hasAssistantPreviewSurface as ne } from "../preview/types.js";
|
|
13
|
+
import { panelOwnedPreviewBridge as re, useHostedAssistantPreviewBridge as ie } from "../preview/bridgeHostContext.js";
|
|
14
|
+
import { AssistantPreviewOverlay as ae } from "../preview/AssistantPreviewOverlay.js";
|
|
15
15
|
import { AssistantHeader as m } from "./AssistantHeader.js";
|
|
16
16
|
import { AssistantConversationList as h } from "./AssistantConversationList.js";
|
|
17
17
|
import { AssistantConversationDeleteDialogProvider as g } from "./conversationDeleteDialog.js";
|
|
@@ -26,19 +26,19 @@ import { useMemo as w, useRef as T, useState as E } from "react";
|
|
|
26
26
|
import { jsx as D, jsxs as O } from "react/jsx-runtime";
|
|
27
27
|
//#region src/shared/assistant/ui/AIAssistantPanel.tsx
|
|
28
28
|
var k = ({ onClose: k, visible: A, docked: j, onToggleDock: M, writeAccess: N, onNavigate: oe, isShellLessTarget: P, connectSourceHref: F, onConnectSource: I, preview: L, liveAvatar: R, serverHistory: z = !1 }) => {
|
|
29
|
-
let B = r(), V =
|
|
29
|
+
let B = r(), V = f(R);
|
|
30
30
|
y(z);
|
|
31
|
-
let [H, U] = E(!1), W =
|
|
31
|
+
let [H, U] = E(!1), W = ne(L);
|
|
32
32
|
H && !W && U(!1);
|
|
33
33
|
let G = H && W;
|
|
34
|
-
|
|
34
|
+
ee(re(L, ie()));
|
|
35
35
|
let K = T(null);
|
|
36
36
|
e(K);
|
|
37
|
-
let { conversations: q, activeConversationId: se, conversationListOpen: J, setConversationListOpen: Y, createConversation: ce } = i(), X = J || G, Z =
|
|
37
|
+
let { conversations: q, activeConversationId: se, conversationListOpen: J, setConversationListOpen: Y, createConversation: ce } = i(), X = J || G, Z = c({
|
|
38
38
|
historyOpen: J,
|
|
39
39
|
previewOpen: G
|
|
40
40
|
}), Q = (e) => {
|
|
41
|
-
let t =
|
|
41
|
+
let t = u({
|
|
42
42
|
historyOpen: J,
|
|
43
43
|
previewOpen: G
|
|
44
44
|
}, e);
|
|
@@ -59,7 +59,7 @@ var k = ({ onClose: k, visible: A, docked: j, onToggleDock: M, writeAccess: N, o
|
|
|
59
59
|
return S({
|
|
60
60
|
panelRef: K,
|
|
61
61
|
onClose: () => {
|
|
62
|
-
if (
|
|
62
|
+
if (l({
|
|
63
63
|
historyOpen: J,
|
|
64
64
|
previewOpen: G
|
|
65
65
|
}) === "overlay") {
|
|
@@ -71,14 +71,14 @@ var k = ({ onClose: k, visible: A, docked: j, onToggleDock: M, writeAccess: N, o
|
|
|
71
71
|
}), /* @__PURE__ */ D(a, {
|
|
72
72
|
visible: A ?? !0,
|
|
73
73
|
engine: V,
|
|
74
|
-
children: /* @__PURE__ */ D(
|
|
74
|
+
children: /* @__PURE__ */ D(d, {
|
|
75
75
|
value: R,
|
|
76
|
-
children: /* @__PURE__ */ D(
|
|
76
|
+
children: /* @__PURE__ */ D(p, {
|
|
77
77
|
value: L,
|
|
78
78
|
children: /* @__PURE__ */ D(v, {
|
|
79
79
|
navigate: oe,
|
|
80
80
|
isShellLessTarget: P,
|
|
81
|
-
children: /* @__PURE__ */ D(
|
|
81
|
+
children: /* @__PURE__ */ D(te, {
|
|
82
82
|
value: F,
|
|
83
83
|
onOpen: I,
|
|
84
84
|
children: /* @__PURE__ */ D(g, { children: /* @__PURE__ */ D(_, { children: /* @__PURE__ */ O("div", {
|
|
@@ -87,8 +87,8 @@ var k = ({ onClose: k, visible: A, docked: j, onToggleDock: M, writeAccess: N, o
|
|
|
87
87
|
role: "complementary",
|
|
88
88
|
"aria-label": B("panel.ariaLabel", "AI Assistant"),
|
|
89
89
|
"data-testid": "ai-assistant-panel",
|
|
90
|
-
[
|
|
91
|
-
...Z ? { [
|
|
90
|
+
[s]: "",
|
|
91
|
+
...Z ? { [o]: Z } : {},
|
|
92
92
|
tabIndex: -1,
|
|
93
93
|
children: [
|
|
94
94
|
/* @__PURE__ */ D("div", {
|
|
@@ -107,7 +107,7 @@ var k = ({ onClose: k, visible: A, docked: j, onToggleDock: M, writeAccess: N, o
|
|
|
107
107
|
})
|
|
108
108
|
}),
|
|
109
109
|
J && /* @__PURE__ */ D(h, {}),
|
|
110
|
-
G && /* @__PURE__ */ D(
|
|
110
|
+
G && /* @__PURE__ */ D(ae, { onClose: () => U(!1) }),
|
|
111
111
|
/* @__PURE__ */ D("div", {
|
|
112
112
|
className: "contents",
|
|
113
113
|
inert: X || void 0,
|
|
@@ -63,6 +63,34 @@ export declare function useLiveAvatarStage(): ComponentType<LiveAvatarStageProps
|
|
|
63
63
|
* is to the store `AssistantSpeechProvider` already subscribes to.
|
|
64
64
|
*/
|
|
65
65
|
export declare function useLiveAvatarSpeechEngine(seam: AssistantLiveAvatarSeam | undefined): SpeechEngine | undefined;
|
|
66
|
+
/**
|
|
67
|
+
* @internal Exported for the assistant's own hands-free wiring (`useVoiceSession`,
|
|
68
|
+
* `AssistantHandsFreeInterruptToggle`); not part of the module's public surface.
|
|
69
|
+
*
|
|
70
|
+
* Whether the live avatar is ON: never without a seam, so false in every app that passes no
|
|
71
|
+
* `liveAvatar`. Read from the ON switch with or without a stage: what it guards is the avatar's
|
|
72
|
+
* voice, not its picture.
|
|
73
|
+
*/
|
|
74
|
+
export declare function useLiveAvatarOn(): boolean;
|
|
75
|
+
/**
|
|
76
|
+
* @internal Exported for `AssistantVoiceSession` alone; not part of the module's public surface.
|
|
77
|
+
*
|
|
78
|
+
* ★★ THE PILOT RULE (BOFF-8822), while the avatar's echo reference (P5) is not in: hands-free
|
|
79
|
+
* interrupt is OFF whenever the avatar is ON. The avatar's voice plays on the speakers, where the
|
|
80
|
+
* microphone hears it, and hands-free would take it for the person speaking over the reply: a
|
|
81
|
+
* barge-in that cuts the avatar off.
|
|
82
|
+
* - Switched ON with hands-free on: hands-free is switched OFF in the setting the person sees (and
|
|
83
|
+
* stored, so it stays off), and this returns true until the avatar is OFF again, for the voice
|
|
84
|
+
* session to say why.
|
|
85
|
+
* - While it is ON: a write that turns hands-free back on is turned back at once, its menu control
|
|
86
|
+
* is `aria-disabled` (it keeps its focus) and says why (`AssistantHandsFreeInterruptToggle`), and the voice session's own
|
|
87
|
+
* reading of the setting is OFF whatever it says (`resolveHandsFreeEnabled`).
|
|
88
|
+
* - Switched OFF: hands-free stays OFF. Nothing turns it back on behind the person's back, and the
|
|
89
|
+
* copy (`avatar.handsFreeOff`) says so and where to turn it back on (More options).
|
|
90
|
+
*
|
|
91
|
+
* Without a seam nothing here subscribes to, reads or writes anything.
|
|
92
|
+
*/
|
|
93
|
+
export declare function useLiveAvatarHandsFreeGuard(): boolean;
|
|
66
94
|
/**
|
|
67
95
|
* The voice view to SHOW, given the one the user CHOSE; and the avatar kept to
|
|
68
96
|
* the live conversation (`ended`: over, but still on screen to say why it
|
|
@@ -1,53 +1,76 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
1
|
+
import { useAssistantStore as e } from "../store.js";
|
|
2
|
+
import { getSpeechEngine as t, subscribeSpeechEngine as n } from "../speech/createSpeechEngine.js";
|
|
3
|
+
import { useAvatarCopy as r } from "../avatar/useAvatarCopy.js";
|
|
4
|
+
import { ASSISTANT_VOICE_SESSION_ATTR as i } from "./panelOverlays.js";
|
|
5
|
+
import { createContext as a, useContext as o, useEffect as s, useLayoutEffect as c, useMemo as l, useRef as u, useState as d, useSyncExternalStore as f } from "react";
|
|
6
|
+
import { VideoOff as p } from "lucide-react";
|
|
7
|
+
import { jsx as m, jsxs as h } from "react/jsx-runtime";
|
|
7
8
|
//#region src/shared/assistant/ui/assistantLiveAvatarSeam.tsx
|
|
8
|
-
var
|
|
9
|
+
var g = a(null), _ = ({ value: e, children: t }) => /* @__PURE__ */ m(g.Provider, {
|
|
9
10
|
value: e ?? null,
|
|
10
11
|
children: t
|
|
11
12
|
});
|
|
12
|
-
function
|
|
13
|
-
return
|
|
13
|
+
function v() {
|
|
14
|
+
return o(g)?.Stage ?? null;
|
|
14
15
|
}
|
|
15
|
-
function
|
|
16
|
-
let r =
|
|
17
|
-
return
|
|
16
|
+
function y(e) {
|
|
17
|
+
let r = f(n, t, t), i = e?.decorateSpeechEngine;
|
|
18
|
+
return l(() => i ? i(r) : void 0, [i, r]);
|
|
18
19
|
}
|
|
19
|
-
var
|
|
20
|
+
var b = {
|
|
20
21
|
subscribe: () => () => {},
|
|
21
22
|
getSnapshot: () => !1,
|
|
22
23
|
switchOff: () => {},
|
|
23
24
|
voiceLive: () => {}
|
|
24
25
|
};
|
|
25
|
-
function
|
|
26
|
+
function x(e) {
|
|
26
27
|
return e?.Stage ? e.enabled : void 0;
|
|
27
28
|
}
|
|
28
|
-
function
|
|
29
|
-
let t = e ??
|
|
30
|
-
return
|
|
29
|
+
function S(e) {
|
|
30
|
+
let t = e ?? b;
|
|
31
|
+
return f(t.subscribe, t.getSnapshot, t.getSnapshot);
|
|
32
|
+
}
|
|
33
|
+
function C() {
|
|
34
|
+
return S(o(g)?.enabled);
|
|
31
35
|
}
|
|
32
|
-
function
|
|
33
|
-
let n =
|
|
34
|
-
|
|
35
|
-
|
|
36
|
+
function w() {
|
|
37
|
+
let t = o(g)?.enabled, [n, r] = d(null);
|
|
38
|
+
return s(() => {
|
|
39
|
+
if (!t) return;
|
|
40
|
+
let n = () => {
|
|
41
|
+
if (!t.getSnapshot()) {
|
|
42
|
+
r(null);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
let n = e.getState();
|
|
46
|
+
n.handsFreeInterrupt && (n.setHandsFreeInterrupt(!1), r(() => t));
|
|
47
|
+
};
|
|
48
|
+
n();
|
|
49
|
+
let i = t.subscribe(n), a = e.subscribe(n);
|
|
50
|
+
return () => {
|
|
51
|
+
i(), a();
|
|
52
|
+
};
|
|
53
|
+
}, [t]), n !== null && n === t;
|
|
54
|
+
}
|
|
55
|
+
function T(e, t) {
|
|
56
|
+
let n = o(g);
|
|
57
|
+
E(n?.enabled, t);
|
|
58
|
+
let r = x(n), i = S(r), [a, s] = d(() => ({
|
|
36
59
|
on: i,
|
|
37
60
|
chosen: e,
|
|
38
61
|
open: i && e === "mini"
|
|
39
62
|
}));
|
|
40
63
|
if (!r) return e;
|
|
41
|
-
let c =
|
|
42
|
-
return (
|
|
64
|
+
let c = a.open;
|
|
65
|
+
return (a.on !== i || a.chosen !== e) && (c = a.on !== i && i && e === "mini", s({
|
|
43
66
|
on: i,
|
|
44
67
|
chosen: e,
|
|
45
68
|
open: c
|
|
46
69
|
})), c && !t ? "panel" : e;
|
|
47
70
|
}
|
|
48
|
-
function
|
|
49
|
-
let n =
|
|
50
|
-
|
|
71
|
+
function E(e, t) {
|
|
72
|
+
let n = u(0);
|
|
73
|
+
s(() => {
|
|
51
74
|
if (!e) return;
|
|
52
75
|
let r = ++n.current, i = (e) => queueMicrotask(() => {
|
|
53
76
|
n.current === r && e();
|
|
@@ -63,38 +86,38 @@ function C(e, t) {
|
|
|
63
86
|
});
|
|
64
87
|
}, [e, t]);
|
|
65
88
|
}
|
|
66
|
-
function
|
|
67
|
-
return x(
|
|
89
|
+
function D() {
|
|
90
|
+
return S(x(o(g)));
|
|
68
91
|
}
|
|
69
|
-
var
|
|
70
|
-
let e =
|
|
71
|
-
return e && t ? /* @__PURE__ */
|
|
92
|
+
var O = () => {
|
|
93
|
+
let e = x(o(g)), t = S(e);
|
|
94
|
+
return e && t ? /* @__PURE__ */ m(j, {
|
|
72
95
|
onStop: e.switchOff,
|
|
73
96
|
isOn: e.getSnapshot
|
|
74
97
|
}) : null;
|
|
75
|
-
},
|
|
76
|
-
let
|
|
77
|
-
return
|
|
98
|
+
}, k = "[data-testid=\"assistant-voice-orb\"]", A = "[data-testid=\"assistant-voice-end\"]", j = ({ onStop: e, isOn: t }) => {
|
|
99
|
+
let n = r(), a = u(null), o = u(t);
|
|
100
|
+
return c(() => {
|
|
78
101
|
let e = a.current, t = o.current;
|
|
79
102
|
return () => {
|
|
80
103
|
if (!e?.contains(e.ownerDocument.activeElement)) return;
|
|
81
|
-
let n = e.closest(`[${
|
|
82
|
-
(
|
|
104
|
+
let n = e.closest(`[${i}]`), r = t() ? null : n?.querySelector(k);
|
|
105
|
+
(r && !r.hasAttribute("disabled") ? r : n?.querySelector(A))?.focus();
|
|
83
106
|
};
|
|
84
|
-
}, []), /* @__PURE__ */
|
|
107
|
+
}, []), /* @__PURE__ */ h("div", {
|
|
85
108
|
ref: a,
|
|
86
109
|
className: "absolute bottom-1.5 left-7 flex h-8 max-w-[calc(100%-13.875rem)] items-center gap-1 rounded-full border border-border-default bg-bg-elevated ps-2.5 pe-0.5 text-xs font-medium text-text-secondary rtl:left-auto rtl:right-7",
|
|
87
110
|
"data-testid": "assistant-voice-avatar",
|
|
88
|
-
children: [/* @__PURE__ */
|
|
111
|
+
children: [/* @__PURE__ */ m("span", {
|
|
89
112
|
className: "truncate",
|
|
90
|
-
children:
|
|
91
|
-
}), /* @__PURE__ */
|
|
113
|
+
children: n.stateOn
|
|
114
|
+
}), /* @__PURE__ */ m("button", {
|
|
92
115
|
type: "button",
|
|
93
116
|
onClick: () => e(),
|
|
94
117
|
className: "relative flex size-7 shrink-0 items-center justify-center rounded-full transition-colors after:absolute after:-inset-2 after:-ms-1.5 after:me-1.5 hover:bg-bg-raised hover:text-text-primary focus:outline-none focus-visible:ring-2 focus-visible:ring-border-strong",
|
|
95
|
-
"aria-label":
|
|
118
|
+
"aria-label": n.stop,
|
|
96
119
|
"data-testid": "assistant-voice-avatar-stop",
|
|
97
|
-
children: /* @__PURE__ */ p
|
|
120
|
+
children: /* @__PURE__ */ m(p, {
|
|
98
121
|
className: "size-4",
|
|
99
122
|
"aria-hidden": "true"
|
|
100
123
|
})
|
|
@@ -102,4 +125,4 @@ var T = () => {
|
|
|
102
125
|
});
|
|
103
126
|
};
|
|
104
127
|
//#endregion
|
|
105
|
-
export {
|
|
128
|
+
export { O as LiveAvatarMiniIndicator, _ as LiveAvatarSeamProvider, w as useLiveAvatarHandsFreeGuard, D as useLiveAvatarMiniIndicatorShown, C as useLiveAvatarOn, y as useLiveAvatarSpeechEngine, v as useLiveAvatarStage, T as useLiveAvatarVoiceView };
|
|
@@ -12,5 +12,14 @@ import { FC } from 'react';
|
|
|
12
12
|
* name (WCAG 2.5.3) and it is reachable by keyboard and speech control. Renders
|
|
13
13
|
* nothing where this browser can neither capture nor recognise speech: a
|
|
14
14
|
* setting that cannot do anything is not offered.
|
|
15
|
+
*
|
|
16
|
+
* ★ BOFF-8822, the avatar pilot: while a live avatar is ON this is OFF and
|
|
17
|
+
* cannot be switched on (`useLiveAvatarHandsFreeGuard`), and it stays OFF after
|
|
18
|
+
* the avatar is turned off until the person turns it back on here. The checkbox
|
|
19
|
+
* is `aria-disabled` and described by the reason, which is shown under it.
|
|
20
|
+
* Never `disabled`: the More menu has no roving focus, so a disabled checkbox
|
|
21
|
+
* drops out of the Tab order and keyboard and screen-reader users would skip
|
|
22
|
+
* the control and the reason with it (the avatar toggle keeps its focus the
|
|
23
|
+
* same way). Without an avatar it is exactly what it was.
|
|
15
24
|
*/
|
|
16
25
|
export declare const AssistantHandsFreeInterruptToggle: FC;
|
|
@@ -2,33 +2,47 @@ import { isSpeechRecognitionSupported as e } from "../../voice/useVoiceInput.js"
|
|
|
2
2
|
import { useAssistantTr as t } from "../../i18n.js";
|
|
3
3
|
import { useAssistantStore as n } from "../../store.js";
|
|
4
4
|
import { isMicCaptureSupported as r } from "../../voice/handsfree/micCapture.js";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { useAvatarCopy as i } from "../../avatar/useAvatarCopy.js";
|
|
6
|
+
import { useLiveAvatarOn as a } from "../assistantLiveAvatarSeam.js";
|
|
7
|
+
import { useId as o } from "react";
|
|
8
|
+
import { Mic as s } from "lucide-react";
|
|
9
|
+
import { Fragment as c, jsx as l, jsxs as u } from "react/jsx-runtime";
|
|
7
10
|
//#region src/shared/assistant/ui/composer/AssistantHandsFreeInterruptToggle.tsx
|
|
8
|
-
var
|
|
9
|
-
let
|
|
10
|
-
|
|
11
|
+
var d = () => {
|
|
12
|
+
let d = t(), f = i(), p = a(), m = o(), h = n((e) => e.handsFreeInterrupt), g = n((e) => e.setHandsFreeInterrupt);
|
|
13
|
+
if (!e() && !r()) return null;
|
|
14
|
+
let _ = /* @__PURE__ */ u("label", {
|
|
11
15
|
className: "flex items-center gap-2.5 px-3 py-2 text-xs text-text-primary focus-within:ring-2 focus-within:ring-inset focus-within:ring-border-strong",
|
|
12
|
-
title:
|
|
16
|
+
title: d("voice.handsFreeHint", "Let the assistant listen while it answers, so you can speak over it to correct it. Works best with headphones. You can always tap to interrupt."),
|
|
13
17
|
"data-testid": "assistant-hands-free-interrupt",
|
|
14
18
|
children: [
|
|
15
|
-
/* @__PURE__ */
|
|
19
|
+
/* @__PURE__ */ l(s, {
|
|
16
20
|
className: "size-3.5 flex-shrink-0 text-text-secondary",
|
|
17
21
|
"aria-hidden": "true"
|
|
18
22
|
}),
|
|
19
|
-
/* @__PURE__ */
|
|
23
|
+
/* @__PURE__ */ l("span", {
|
|
20
24
|
className: "flex-1",
|
|
21
|
-
children:
|
|
25
|
+
children: d("voice.handsFreeLabel", "Hands-free interrupt (beta)")
|
|
22
26
|
}),
|
|
23
|
-
/* @__PURE__ */
|
|
27
|
+
/* @__PURE__ */ l("input", {
|
|
24
28
|
type: "checkbox",
|
|
25
|
-
checked:
|
|
26
|
-
onChange: (e) =>
|
|
27
|
-
|
|
29
|
+
checked: h,
|
|
30
|
+
onChange: (e) => {
|
|
31
|
+
p || g(e.target.checked);
|
|
32
|
+
},
|
|
33
|
+
"aria-disabled": p ? "true" : void 0,
|
|
34
|
+
"aria-describedby": p ? m : void 0,
|
|
35
|
+
className: p ? "size-4 accent-current aria-disabled:cursor-default aria-disabled:opacity-60" : "size-4 accent-current",
|
|
28
36
|
"data-testid": "assistant-hands-free-interrupt-checkbox"
|
|
29
37
|
})
|
|
30
38
|
]
|
|
31
39
|
});
|
|
40
|
+
return p ? /* @__PURE__ */ u(c, { children: [_, /* @__PURE__ */ l("p", {
|
|
41
|
+
id: m,
|
|
42
|
+
className: "px-3 pb-2 text-[11px] text-text-muted",
|
|
43
|
+
"data-testid": "assistant-hands-free-interrupt-avatar",
|
|
44
|
+
children: f.handsFreeOff
|
|
45
|
+
})] }) : _;
|
|
32
46
|
};
|
|
33
47
|
//#endregion
|
|
34
|
-
export {
|
|
48
|
+
export { d as AssistantHandsFreeInterruptToggle };
|