@burdenoff/fe-libs 2026.1029.3 → 2026.1029.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.
@@ -6,92 +6,96 @@ import { useAssistantStore as i } from "../../store.js";
6
6
  import { languageDisplayName as ee } from "../../voice/speechVoices.js";
7
7
  import { resolveAssistantLanguage as te } from "../../voice/languages.js";
8
8
  import { attachmentEditorAccessMessage as ne } from "../../attachmentAccessCopy.js";
9
- import { getSendableAttachments as a } from "../../attachments.js";
10
- import { ATTACHMENT_COMMIT_CODES as o } from "../../attachmentCommit.js";
11
- import { AssistantAttachmentButton as re } from "./AssistantAttachmentButton.js";
12
- import { AssistantAttachmentChips as ie } from "./AssistantAttachmentChips.js";
13
- import { AssistantModeSelector as ae } from "./AssistantModeSelector.js";
14
- import { AssistantVoiceButton as oe, ListeningDot as se } from "./AssistantVoiceButton.js";
15
- import { AssistantVoiceSessionButton as ce } from "../voice/AssistantVoiceSessionButton.js";
16
- import { useAssistantAttachments as le } from "../../useAssistantAttachments.js";
17
- import { useCallback as s, useEffect as c, useLayoutEffect as ue, useMemo as de, useRef as l, useState as u } from "react";
18
- import { ArrowUp as fe, Loader2 as pe } from "lucide-react";
9
+ import { getSendableAttachments as re } from "../../attachments.js";
10
+ import { ATTACHMENT_COMMIT_CODES as a } from "../../attachmentCommit.js";
11
+ import { AssistantAttachmentButton as ie } from "./AssistantAttachmentButton.js";
12
+ import { AssistantAttachmentChips as ae } from "./AssistantAttachmentChips.js";
13
+ import { AssistantModeSelector as oe } from "./AssistantModeSelector.js";
14
+ import { AssistantModeMenu as se } from "./AssistantModeMenu.js";
15
+ import { compactEnterSends as ce } from "./imeEnter.js";
16
+ import { AssistantVoiceButton as le, ListeningDot as ue } from "./AssistantVoiceButton.js";
17
+ import { AssistantVoiceSessionButton as de } from "../voice/AssistantVoiceSessionButton.js";
18
+ import { useAssistantAttachments as fe } from "../../useAssistantAttachments.js";
19
+ import { useCallback as o, useEffect as s, useLayoutEffect as pe, useMemo as me, useRef as c, useState as l } from "react";
20
+ import { ArrowUp as he, Loader2 as u, Square as ge } from "lucide-react";
19
21
  import { jsx as d, jsxs as f } from "react/jsx-runtime";
20
22
  //#region src/shared/assistant/ui/composer/AssistantComposer.tsx
21
- var me = 200, p = ({ writeAccessDenied: p = !1, onSend: m, disabled: h = !1, readOnly: he = !1, placeholder: ge, mode: _e, availableModes: ve, attachmentCharsPerFile: ye, onModeChange: be, auto: xe, onStartVoiceSession: g, onDraftStart: _, onDraftChange: v, suspendDictation: y = !1, onVoiceStateChange: b }) => {
22
- let x = r(), { locale: S } = e(), C = h || he, w = l(null), [T, E] = u(""), [Se, D] = u(!1), [O, Ce] = u(!1), k = l(!1), [A, j] = u(null), M = l(0), { attachments: N, isBusy: we, preparingCount: Te, sendBlocker: P, rejection: F, addFiles: I, remove: Ee, retry: De, clear: L, clearRejection: Oe, canAddMore: ke, commit: R, cancelCommit: z } = le({ perFileChars: ye }), B = T.trim() !== "" || N.length > 0, V = l(!1), H = l(!1);
23
- c(() => {
24
- B && !V.current ? (V.current = !0, _?.()) : B || (V.current = !1);
25
- }, [B, _]), c(() => {
26
- B || (H.current = !1), v?.({
27
- text: T,
28
- hasAttachments: N.length > 0,
29
- dictated: H.current
23
+ var _e = 200, p = ({ writeAccessDenied: p = !1, onSend: m, disabled: h = !1, readOnly: ve = !1, placeholder: ye, mode: be, availableModes: g, attachmentCharsPerFile: xe, onModeChange: Se, auto: Ce, onStartVoiceSession: _, onDraftStart: we, onDraftChange: Te, suspendDictation: Ee = !1, onVoiceStateChange: De, presentation: Oe = "classic", turnInFlight: v = !1, onStop: y, modeDisabledReason: ke = null }) => {
24
+ let b = r(), { locale: x } = e(), S = h || ve, Ae = Oe === "compact", C = c(null), [w, T] = l(""), [E, D] = l(!1), [O, je] = l(!1), k = c(!1), [Me, A] = l(null), [Ne, j] = l(null), [Pe, Fe] = l(v);
25
+ Pe !== v && (Fe(v), v && j(null));
26
+ let M = c(!1), N = c(null), P = c(!1), F = c(0), { attachments: I, isBusy: Ie, preparingCount: Le, sendBlocker: Re, rejection: ze, addFiles: L, remove: Be, retry: Ve, clear: R, clearRejection: He, canAddMore: Ue, commit: We, cancelCommit: Ge } = fe({ perFileChars: xe }), z = w.trim() !== "" || I.length > 0, B = c(!1), V = c(!1);
27
+ s(() => {
28
+ z && !B.current ? (B.current = !0, we?.()) : z || (B.current = !1);
29
+ }, [z, we]), s(() => {
30
+ z || (V.current = !1), Te?.({
31
+ text: w,
32
+ hasAttachments: I.length > 0,
33
+ dictated: V.current
30
34
  });
31
35
  }, [
32
- T,
33
- N.length,
34
- B,
35
- v
36
+ w,
37
+ I.length,
38
+ z,
39
+ Te
36
40
  ]);
37
- let U = s((e) => {
38
- H.current = !0, E((t) => t ? `${t.replace(/\s+$/, "")} ${e}` : e);
39
- }, []), W = i((e) => e.assistantLanguage), G = n({
40
- onFinalize: U,
41
- language: de(() => te(W, S), [W, S]).tag
42
- }), K = G.isActive, q = G.interim, J = G.stop;
43
- c(() => {
44
- !y || !K || (q.trim() !== "" && U(q.trim()), J());
41
+ let H = o((e) => {
42
+ V.current = !0, T((t) => t ? `${t.replace(/\s+$/, "")} ${e}` : e);
43
+ }, []), Ke = i((e) => e.assistantLanguage), U = n({
44
+ onFinalize: H,
45
+ language: me(() => te(Ke, x), [Ke, x]).tag
46
+ }), W = U.isActive, G = U.interim, qe = U.stop;
47
+ s(() => {
48
+ !Ee || !W || (G.trim() !== "" && H(G.trim()), qe());
45
49
  }, [
46
- y,
47
- K,
48
- q,
49
- J,
50
- U
51
- ]), c(() => {
52
- b?.({
50
+ Ee,
51
+ W,
52
+ G,
53
+ qe,
54
+ H
55
+ ]), s(() => {
56
+ De?.({
53
57
  committing: O,
54
- dictating: K
58
+ dictating: W
55
59
  });
56
60
  }, [
57
- b,
61
+ De,
58
62
  O,
59
- K
63
+ W
60
64
  ]);
61
- let Ae = ge ?? x("composer.placeholder", "Ask me anything…"), je = T.trim(), Y = a(N), X = N.filter((e) => e.status === "error"), Z = (je.length > 0 || Y.length > 0) && !C && !O && P === null, Me = Y.some((e) => !(e.fileId && e.downloadUrl) && !e.inlineOnly), Ne = l(C);
62
- Ne.current = C;
63
- let Q = l(!0);
64
- c(() => (Q.current = !0, () => {
65
- Q.current = !1;
66
- }), []), ue(() => {
67
- let e = w.current;
68
- e && (e.style.height = "auto", e.style.height = `${Math.min(e.scrollHeight, me)}px`);
69
- }, [T]);
70
- let $ = s(async () => {
71
- if (!Z || k.current) return;
72
- G.isActive && G.stop();
73
- let e = T.trim();
74
- if (j(null), !Me) {
75
- m(e, Y), E(""), L();
65
+ let Je = ye ?? b("composer.placeholder", "Ask me anything…"), K = w.trim(), q = re(I), J = I.filter((e) => e.status === "error"), Y = (K.length > 0 || q.length > 0) && !S && !O && Re === null, Ye = q.some((e) => !(e.fileId && e.downloadUrl) && !e.inlineOnly), X = c(S);
66
+ X.current = S;
67
+ let Z = c(!0);
68
+ s(() => (Z.current = !0, () => {
69
+ Z.current = !1;
70
+ }), []), pe(() => {
71
+ let e = C.current;
72
+ e && (e.style.height = "auto", e.style.height = `${Math.min(e.scrollHeight, _e)}px`);
73
+ }, [w]);
74
+ let Q = o(async () => {
75
+ if (!Y || k.current) return;
76
+ U.isActive && U.stop();
77
+ let e = w.trim();
78
+ if (A(null), !Ye) {
79
+ m(e, q), T(""), R();
76
80
  return;
77
81
  }
78
82
  let t = i.getState().activeConversationId;
79
- k.current = !0, Ce(!0);
83
+ k.current = !0, je(!0);
80
84
  try {
81
- let n = await R();
82
- if (!Q.current) {
85
+ let n = await We();
86
+ if (!Z.current) {
83
87
  n.ok && await n.rollback();
84
88
  return;
85
89
  }
86
90
  if (!n.ok) {
87
- n.cancelled || j({
91
+ n.cancelled || A({
88
92
  kind: "failed",
89
93
  failures: n.failures
90
94
  });
91
95
  return;
92
96
  }
93
- if (Ne.current) {
94
- await n.rollback(), Q.current && j({
97
+ if (X.current) {
98
+ await n.rollback(), Z.current && A({
95
99
  kind: "busy",
96
100
  failures: []
97
101
  });
@@ -99,141 +103,331 @@ var me = 200, p = ({ writeAccessDenied: p = !1, onSend: m, disabled: h = !1, rea
99
103
  }
100
104
  let r = i.getState();
101
105
  if (!(r.activeConversationId === t && (t === null || r.conversations.some((e) => e.id === t)))) {
102
- await n.rollback(), Q.current && j({
106
+ await n.rollback(), Z.current && A({
103
107
  kind: "moved",
104
108
  failures: []
105
109
  });
106
110
  return;
107
111
  }
108
- m(e, a(n.attachments)), n.handedOver(), E(""), L();
112
+ m(e, re(n.attachments)), n.handedOver(), T(""), R();
109
113
  } finally {
110
- k.current = !1, Q.current && Ce(!1);
114
+ k.current = !1, Z.current && je(!1);
111
115
  }
112
116
  }, [
113
- Z,
114
- Me,
115
- R,
116
- m,
117
- T,
118
117
  Y,
119
- L,
120
- G
121
- ]), Pe = s(() => {
122
- z(), w.current?.focus();
123
- }, [z]);
124
- c(() => {
125
- j(null);
126
- }, [N.length]);
127
- let Fe = (e) => {
128
- if (e.kind === "busy") return x("attachments.saveBusy", "The assistant started another reply, so nothing was sent. Your message and files are still here.");
129
- if (e.kind === "moved") return x("attachments.saveMoved", "You switched conversations while the files were being saved, so nothing was sent. Your message and files are still here.");
118
+ Ye,
119
+ We,
120
+ m,
121
+ w,
122
+ q,
123
+ R,
124
+ U
125
+ ]), Xe = o(() => {
126
+ Ge(), C.current?.focus();
127
+ }, [Ge]), $ = o(() => {
128
+ X.current ? M.current = !0 : C.current?.focus();
129
+ }, []), Ze = o(() => {
130
+ let e = y?.() ?? null;
131
+ e !== null && j(e), $();
132
+ }, [y, $]);
133
+ s(() => {
134
+ S || !M.current || (M.current = !1, C.current?.focus());
135
+ }, [S]);
136
+ let Qe = o((e) => {
137
+ if (e !== null) {
138
+ N.current = e;
139
+ return;
140
+ }
141
+ let t = N.current;
142
+ N.current = null, t !== null && t.ownerDocument.activeElement === t && (P.current = !0);
143
+ }, []), $e = Ae && v && y !== void 0;
144
+ pe(() => {
145
+ $e || !P.current || (P.current = !1, $());
146
+ }, [$e, $]);
147
+ let et = o((e) => {
148
+ T(e), j(null);
149
+ }, []);
150
+ s(() => {
151
+ A(null);
152
+ }, [I.length]);
153
+ let tt = (e) => {
154
+ if (e.kind === "busy") return b("attachments.saveBusy", "The assistant started another reply, so nothing was sent. Your message and files are still here.");
155
+ if (e.kind === "moved") return b("attachments.saveMoved", "You switched conversations while the files were being saved, so nothing was sent. Your message and files are still here.");
130
156
  let { failures: t } = e;
131
- if (t.some((e) => e.code === o.editorAccessRequired)) return ne(x, S);
132
- if (t.some((e) => e.code === o.quotaExceeded || e.code === o.quotaNotProvisioned)) return `${x("attachments.quotaFull", "File storage is full or not set up for this workspace, so the attachments couldn't be saved. Nothing was sent.")} ${x("attachments.retrySend", "Press Send to try again, or remove the file.")}`;
133
- let n = t[0], r = N.find((e) => e.id === n?.id)?.filename ?? "";
134
- return `${t.length <= 1 ? x("attachments.saveFailedOne", "{{name}} couldn't be saved, so nothing was sent.", { name: r }) : x("attachments.saveFailedMany", "{{count}} attachments couldn't be saved, so nothing was sent.", { count: t.length })} ${x("attachments.retrySend", "Press Send to try again, or remove the file.")}`;
135
- }, Ie = s((e) => {
136
- e.key === "Enter" && !e.shiftKey && (e.preventDefault(), $());
137
- }, [$]), Le = s((e) => {
157
+ if (t.some((e) => e.code === a.editorAccessRequired)) return ne(b, x);
158
+ if (t.some((e) => e.code === a.quotaExceeded || e.code === a.quotaNotProvisioned)) return `${b("attachments.quotaFull", "File storage is full or not set up for this workspace, so the attachments couldn't be saved. Nothing was sent.")} ${b("attachments.retrySend", "Press Send to try again, or remove the file.")}`;
159
+ let n = t[0], r = I.find((e) => e.id === n?.id)?.filename ?? "";
160
+ return `${t.length <= 1 ? b("attachments.saveFailedOne", "{{name}} couldn't be saved, so nothing was sent.", { name: r }) : b("attachments.saveFailedMany", "{{count}} attachments couldn't be saved, so nothing was sent.", { count: t.length })} ${b("attachments.retrySend", "Press Send to try again, or remove the file.")}`;
161
+ }, nt = o((e) => {
162
+ e.key === "Enter" && !e.shiftKey && (e.preventDefault(), Q());
163
+ }, [Q]), rt = o((e) => {
164
+ ce(e) && (e.preventDefault(), j(null), Q());
165
+ }, [Q]), it = o((e) => {
138
166
  let t = Array.from(e.clipboardData?.files ?? []);
139
- t.length !== 0 && (e.preventDefault(), I(t));
140
- }, [I]), Re = s((e) => {
141
- Array.from(e.dataTransfer?.types ?? []).includes("Files") && (M.current += 1, D(!0));
142
- }, []), ze = s(() => {
143
- M.current = Math.max(0, M.current - 1), M.current === 0 && D(!1);
144
- }, []), Be = s((e) => {
167
+ t.length !== 0 && (e.preventDefault(), L(t));
168
+ }, [L]), at = o((e) => {
169
+ Array.from(e.dataTransfer?.types ?? []).includes("Files") && (F.current += 1, D(!0));
170
+ }, []), ot = o(() => {
171
+ F.current = Math.max(0, F.current - 1), F.current === 0 && D(!1);
172
+ }, []), st = o((e) => {
145
173
  Array.from(e.dataTransfer?.types ?? []).includes("Files") && e.preventDefault();
146
- }, []), Ve = s((e) => {
147
- e.preventDefault(), M.current = 0, D(!1), I(e.dataTransfer?.files ?? null);
148
- }, [I]), He = (e) => {
174
+ }, []), ct = o((e) => {
175
+ e.preventDefault(), F.current = 0, D(!1), L(e.dataTransfer?.files ?? null);
176
+ }, [L]), lt = (e) => {
149
177
  switch (e) {
150
- case "too-many": return x("attachments.tooMany", "You can attach up to {{max}} files per message.", { max: 5 });
151
- case "too-large": return x("attachments.tooLarge", "That file is larger than 10 MB.");
152
- case "empty": return x("attachments.empty", "That file is empty.");
153
- case "unreadable": return x("attachments.unreadable", "That file could not be read.");
154
- case "unsupported-image": return x("attachments.unsupportedImage", "This device can't read that image format, so it can't be resized to send. Save it as JPEG and try again.");
155
- case "too-large-to-save": return x("attachments.tooLargeToSave", "That file is over 5 MB, so it can't be saved to Files, and no text could be read from it.");
178
+ case "too-many": return b("attachments.tooMany", "You can attach up to {{max}} files per message.", { max: 5 });
179
+ case "too-large": return b("attachments.tooLarge", "That file is larger than 10 MB.");
180
+ case "empty": return b("attachments.empty", "That file is empty.");
181
+ case "unreadable": return b("attachments.unreadable", "That file could not be read.");
182
+ case "unsupported-image": return b("attachments.unsupportedImage", "This device can't read that image format, so it can't be resized to send. Save it as JPEG and try again.");
183
+ case "too-large-to-save": return b("attachments.tooLargeToSave", "That file is over 5 MB, so it can't be saved to Files, and no text could be read from it.");
156
184
  }
157
- }, Ue = (() => {
158
- switch (G.error) {
159
- case "not-allowed": return x("voice.denied", "Microphone access is blocked. Allow it in your browser settings to dictate.");
160
- case "audio-capture": return x("voice.noMic", "No microphone was found.");
161
- case "network": return x("voice.network", "Speech recognition is offline right now.");
162
- case "language-not-supported": return x("voice.languageNotSupported", "This browser cannot recognise spoken {{language}}. Try a different browser, or type instead.", { language: ee(G.language, S) });
163
- case "unknown": return x("voice.failed", "Dictation stopped unexpectedly.");
185
+ }, ut = (() => {
186
+ switch (U.error) {
187
+ case "not-allowed": return b("voice.denied", "Microphone access is blocked. Allow it in your browser settings to dictate.");
188
+ case "audio-capture": return b("voice.noMic", "No microphone was found.");
189
+ case "network": return b("voice.network", "Speech recognition is offline right now.");
190
+ case "language-not-supported": return b("voice.languageNotSupported", "This browser cannot recognise spoken {{language}}. Try a different browser, or type instead.", { language: ee(U.language, x) });
191
+ case "unknown": return b("voice.failed", "Dictation stopped unexpectedly.");
164
192
  default: return null;
165
193
  }
166
- })();
194
+ })(), dt = (e) => O ? /* @__PURE__ */ d(t, {
195
+ onDismiss: Xe,
196
+ children: /* @__PURE__ */ f("p", {
197
+ className: "flex items-center justify-center gap-2 text-text-muted",
198
+ "data-testid": "assistant-commit-status",
199
+ children: [
200
+ /* @__PURE__ */ d(u, {
201
+ className: "size-3 motion-safe:animate-spin",
202
+ "aria-hidden": "true"
203
+ }),
204
+ /* @__PURE__ */ d("span", { children: b("attachments.saving", "Saving your attachments…") }),
205
+ /* @__PURE__ */ d("button", {
206
+ type: "button",
207
+ onClick: Xe,
208
+ className: "rounded text-text-primary underline underline-offset-2 hover:text-action-primary-bg focus:outline-none focus-visible:ring-2 focus-visible:ring-border-strong",
209
+ "data-testid": "assistant-commit-cancel",
210
+ children: b("attachments.cancelSaving", "Cancel")
211
+ })
212
+ ]
213
+ })
214
+ }) : Me ? /* @__PURE__ */ d("p", {
215
+ className: "text-status-error-text",
216
+ role: "alert",
217
+ "data-testid": "assistant-commit-failed",
218
+ children: tt(Me)
219
+ }) : U.isStarting && !U.isListening ? /* @__PURE__ */ d("p", {
220
+ className: "text-text-muted",
221
+ "data-testid": "assistant-voice-starting",
222
+ children: b("voice.starting", "Starting the microphone…")
223
+ }) : U.isListening ? /* @__PURE__ */ f("p", {
224
+ className: "text-status-error-text",
225
+ "data-testid": "assistant-voice-status",
226
+ children: [/* @__PURE__ */ d(ue, {}), U.interim || b("voice.listening", "Listening… speak now, tap the square to stop")]
227
+ }) : ut ? /* @__PURE__ */ d("p", {
228
+ className: "text-status-error-text",
229
+ "data-testid": "assistant-voice-error",
230
+ children: ut
231
+ }) : ze ? /* @__PURE__ */ d("button", {
232
+ type: "button",
233
+ onClick: He,
234
+ className: "text-status-error-text underline-offset-2 hover:underline",
235
+ "data-testid": "assistant-attachment-rejection",
236
+ children: lt(ze)
237
+ }) : Re === "failed" ? /* @__PURE__ */ d("p", {
238
+ className: "text-status-error-text",
239
+ "data-testid": "assistant-attachment-blocked",
240
+ children: J.length === 1 ? b("attachments.blockedOne", "{{name}} didn't upload. Retry or remove it before sending.", { name: J[0].filename }) : b("attachments.blockedMany", "{{count}} attachments didn't upload. Retry or remove them before sending.", { count: J.length })
241
+ }) : e ? /* @__PURE__ */ d("p", {
242
+ className: "text-text-muted",
243
+ "data-testid": "assistant-stop-status",
244
+ children: b("composer.stopped", "Reply stopped.")
245
+ }) : /* @__PURE__ */ d("p", {
246
+ className: "text-text-muted",
247
+ children: b("composer.hint", "Enter to send · Shift+Enter for newline · drag or paste files to attach")
248
+ });
249
+ if (Ae) {
250
+ let e = _ !== void 0 && K.length === 0 && I.length === 0 && !U.isActive, t = "focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--color-bg-elevated)]";
251
+ return /* @__PURE__ */ f("div", {
252
+ className: "flex-shrink-0 px-3 pb-3 pt-1.5",
253
+ children: [
254
+ /* @__PURE__ */ f("div", {
255
+ onDragEnter: at,
256
+ onDragLeave: ot,
257
+ onDragOver: st,
258
+ onDrop: ct,
259
+ className: `flex flex-col rounded-3xl border bg-bg-elevated shadow-[var(--shadow-elevation-2)] transition-colors focus-within:border-[var(--color-focus-ring)] focus-within:ring-1 focus-within:ring-[var(--color-focus-ring)] ${E ? "border-dashed border-[var(--color-focus-ring)]" : "border-[var(--color-text-muted)]"}`,
260
+ "data-testid": "assistant-composer",
261
+ "data-presentation": "compact",
262
+ children: [
263
+ /* @__PURE__ */ d("div", {
264
+ className: "px-3 pt-3 empty:hidden",
265
+ children: /* @__PURE__ */ d(ae, {
266
+ attachments: I,
267
+ onRemove: Be,
268
+ onRetry: Ve,
269
+ disabled: S || O,
270
+ preparingCount: Le
271
+ })
272
+ }),
273
+ /* @__PURE__ */ d("textarea", {
274
+ ref: C,
275
+ value: w,
276
+ onChange: (e) => et(e.target.value),
277
+ onKeyDown: rt,
278
+ onPaste: it,
279
+ disabled: S,
280
+ readOnly: O,
281
+ "aria-busy": O || void 0,
282
+ placeholder: E ? b("composer.dropHere", "Drop files to attach") : Je,
283
+ rows: 1,
284
+ className: "min-h-14 w-full resize-none bg-transparent px-5 pb-2 pt-4 text-base leading-6 text-text-primary placeholder:text-text-muted focus:outline-none disabled:opacity-50",
285
+ "aria-label": b("chatInput.ariaLabel", "Message input"),
286
+ "data-testid": "assistant-input"
287
+ }),
288
+ /* @__PURE__ */ f("div", {
289
+ className: "flex items-center gap-1 px-2 pb-2 pt-1",
290
+ children: [
291
+ /* @__PURE__ */ d(ie, {
292
+ onFiles: L,
293
+ canAddMore: Ue,
294
+ disabled: S || O,
295
+ showLabel: !0
296
+ }),
297
+ /* @__PURE__ */ d(se, {
298
+ mode: be,
299
+ availableModes: g,
300
+ onModeChange: Se,
301
+ auto: Ce,
302
+ disabled: S || O,
303
+ disabledReason: v ? "replying" : ke ?? "busy"
304
+ }),
305
+ /* @__PURE__ */ d("div", { className: "min-w-0 flex-1" }),
306
+ U.isSupported && /* @__PURE__ */ d(le, {
307
+ isListening: U.isListening,
308
+ isStarting: U.isStarting,
309
+ onToggle: U.toggle,
310
+ disabled: S || O
311
+ }),
312
+ $e ? /* @__PURE__ */ d("button", {
313
+ ref: Qe,
314
+ type: "button",
315
+ onClick: Ze,
316
+ className: `flex size-10 flex-shrink-0 items-center justify-center rounded-full bg-action-primary-bg text-action-primary-text transition-colors hover:bg-action-primary-bg-hover ${t}`,
317
+ "aria-label": b("composer.stop", "Stop the reply"),
318
+ title: b("composer.stop", "Stop the reply"),
319
+ "data-testid": "assistant-stop",
320
+ children: /* @__PURE__ */ d(ge, {
321
+ className: "size-4 fill-current",
322
+ "aria-hidden": "true"
323
+ })
324
+ }) : e ? /* @__PURE__ */ d(de, {
325
+ onStart: _,
326
+ disabled: S || O
327
+ }) : /* @__PURE__ */ d("button", {
328
+ type: "button",
329
+ onClick: () => {
330
+ j(null), Q();
331
+ },
332
+ disabled: !Y,
333
+ className: `flex size-10 flex-shrink-0 items-center justify-center rounded-full transition-colors ${t} ${Y ? "bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover" : "bg-[var(--color-bg-disabled)] text-[var(--color-text-disabled)]"}`,
334
+ "aria-label": b("chatInput.send", "Send message"),
335
+ "data-testid": "assistant-send",
336
+ children: h || Ie || O ? /* @__PURE__ */ d(u, {
337
+ className: "size-5 motion-safe:animate-spin",
338
+ "aria-hidden": "true"
339
+ }) : /* @__PURE__ */ d(he, {
340
+ className: "size-5",
341
+ "aria-hidden": "true"
342
+ })
343
+ })
344
+ ]
345
+ })
346
+ ]
347
+ }),
348
+ p ? /* @__PURE__ */ d("p", {
349
+ className: "mt-1.5 px-1 text-center text-xs text-status-warning",
350
+ "data-testid": "assistant-write-access-warning",
351
+ children: b("composer.writeAccessDenied", "Changes may not save — your role in this workspace does not currently allow edits. You can still plan and review an action.")
352
+ }) : null,
353
+ /* @__PURE__ */ d("div", {
354
+ className: "mt-1.5 px-1 text-center text-xs",
355
+ "aria-live": "polite",
356
+ children: dt(Ne !== null)
357
+ })
358
+ ]
359
+ });
360
+ }
167
361
  return /* @__PURE__ */ f("div", {
168
362
  className: "flex-shrink-0 px-3 pb-3 pt-1.5",
169
363
  children: [
170
364
  /* @__PURE__ */ f("div", {
171
- onDragEnter: Re,
172
- onDragLeave: ze,
173
- onDragOver: Be,
174
- onDrop: Ve,
175
- className: `rounded-2xl border p-2 shadow-sm transition-colors focus-within:border-action-primary-bg focus-within:ring-2 focus-within:ring-action-primary-bg/15 ${Se ? "border-action-primary-bg border-dashed bg-action-primary-bg/5" : "border-border-default bg-bg-sunken"}`,
365
+ onDragEnter: at,
366
+ onDragLeave: ot,
367
+ onDragOver: st,
368
+ onDrop: ct,
369
+ className: `rounded-2xl border p-2 shadow-sm transition-colors focus-within:border-action-primary-bg focus-within:ring-2 focus-within:ring-action-primary-bg/15 ${E ? "border-action-primary-bg border-dashed bg-action-primary-bg/5" : "border-border-default bg-bg-sunken"}`,
176
370
  "data-testid": "assistant-composer",
177
371
  children: [
178
- /* @__PURE__ */ d(ie, {
179
- attachments: N,
180
- onRemove: Ee,
181
- onRetry: De,
182
- disabled: C || O,
183
- preparingCount: Te
372
+ /* @__PURE__ */ d(ae, {
373
+ attachments: I,
374
+ onRemove: Be,
375
+ onRetry: Ve,
376
+ disabled: S || O,
377
+ preparingCount: Le
184
378
  }),
185
379
  /* @__PURE__ */ f("div", {
186
380
  className: "flex items-end gap-2",
187
381
  children: [
188
- /* @__PURE__ */ d(re, {
189
- onFiles: I,
190
- canAddMore: ke,
191
- disabled: C || O,
382
+ /* @__PURE__ */ d(ie, {
383
+ onFiles: L,
384
+ canAddMore: Ue,
385
+ disabled: S || O,
192
386
  showLabel: !0
193
387
  }),
194
388
  /* @__PURE__ */ d("textarea", {
195
- ref: w,
196
- value: T,
197
- onChange: (e) => E(e.target.value),
198
- onKeyDown: Ie,
199
- onPaste: Le,
200
- disabled: C,
389
+ ref: C,
390
+ value: w,
391
+ onChange: (e) => T(e.target.value),
392
+ onKeyDown: nt,
393
+ onPaste: it,
394
+ disabled: S,
201
395
  readOnly: O,
202
396
  "aria-busy": O || void 0,
203
- placeholder: Se ? x("composer.dropHere", "Drop files to attach") : Ae,
397
+ placeholder: E ? b("composer.dropHere", "Drop files to attach") : Je,
204
398
  rows: 1,
205
399
  className: "min-h-[36px] flex-1 resize-none self-center bg-transparent px-1 py-2 text-[15px] leading-relaxed text-text-primary placeholder:text-text-muted focus:outline-none disabled:opacity-50",
206
- "aria-label": x("chatInput.ariaLabel", "Message input"),
400
+ "aria-label": b("chatInput.ariaLabel", "Message input"),
207
401
  "data-testid": "assistant-input"
208
402
  }),
209
- G.isSupported && /* @__PURE__ */ d(oe, {
210
- isListening: G.isListening,
211
- isStarting: G.isStarting,
212
- onToggle: G.toggle,
213
- disabled: C || O
403
+ U.isSupported && /* @__PURE__ */ d(le, {
404
+ isListening: U.isListening,
405
+ isStarting: U.isStarting,
406
+ onToggle: U.toggle,
407
+ disabled: S || O
214
408
  }),
215
- g && je.length === 0 && N.length === 0 && !G.isActive ? /* @__PURE__ */ d(ce, {
216
- onStart: g,
217
- disabled: C || O
409
+ _ && K.length === 0 && I.length === 0 && !U.isActive ? /* @__PURE__ */ d(de, {
410
+ onStart: _,
411
+ disabled: S || O
218
412
  }) : /* @__PURE__ */ d("button", {
219
413
  type: "button",
220
- onClick: () => void $(),
221
- disabled: !Z,
222
- className: `flex size-9 flex-shrink-0 items-center justify-center rounded-full shadow-sm transition-all focus:outline-none focus-visible:ring-2 focus-visible:ring-border-strong ${Z ? "bg-action-primary-bg text-action-primary-text hover:scale-105 hover:bg-action-primary-bg-hover" : "bg-bg-elevated text-text-muted"}`,
223
- "aria-label": x("chatInput.send", "Send message"),
414
+ onClick: () => void Q(),
415
+ disabled: !Y,
416
+ className: `flex size-9 flex-shrink-0 items-center justify-center rounded-full shadow-sm transition-all focus:outline-none focus-visible:ring-2 focus-visible:ring-border-strong ${Y ? "bg-action-primary-bg text-action-primary-text hover:scale-105 hover:bg-action-primary-bg-hover" : "bg-bg-elevated text-text-muted"}`,
417
+ "aria-label": b("chatInput.send", "Send message"),
224
418
  "data-testid": "assistant-send",
225
- children: h || we || O ? /* @__PURE__ */ d(pe, { className: "size-4 motion-safe:animate-spin" }) : /* @__PURE__ */ d(fe, { className: "size-4" })
419
+ children: h || Ie || O ? /* @__PURE__ */ d(u, { className: "size-4 motion-safe:animate-spin" }) : /* @__PURE__ */ d(he, { className: "size-4" })
226
420
  })
227
421
  ]
228
422
  }),
229
- ve.length > 1 && /* @__PURE__ */ d("div", {
423
+ g.length > 1 && /* @__PURE__ */ d("div", {
230
424
  className: "mt-2 px-0.5",
231
- children: /* @__PURE__ */ d(ae, {
232
- mode: _e,
233
- availableModes: ve,
234
- onModeChange: be,
235
- disabled: C || O,
236
- auto: xe
425
+ children: /* @__PURE__ */ d(oe, {
426
+ mode: be,
427
+ availableModes: g,
428
+ onModeChange: Se,
429
+ disabled: S || O,
430
+ auto: Ce
237
431
  })
238
432
  })
239
433
  ]
@@ -241,62 +435,12 @@ var me = 200, p = ({ writeAccessDenied: p = !1, onSend: m, disabled: h = !1, rea
241
435
  p ? /* @__PURE__ */ d("p", {
242
436
  className: "mt-1.5 px-1 text-center text-[11px] text-status-warning",
243
437
  "data-testid": "assistant-write-access-warning",
244
- children: x("composer.writeAccessDenied", "Changes may not save — your role in this workspace does not currently allow edits. You can still plan and review an action.")
438
+ children: b("composer.writeAccessDenied", "Changes may not save — your role in this workspace does not currently allow edits. You can still plan and review an action.")
245
439
  }) : null,
246
440
  /* @__PURE__ */ d("div", {
247
441
  className: "mt-1.5 px-1 text-center text-[11px]",
248
442
  "aria-live": "polite",
249
- children: O ? /* @__PURE__ */ d(t, {
250
- onDismiss: Pe,
251
- children: /* @__PURE__ */ f("p", {
252
- className: "flex items-center justify-center gap-2 text-text-muted",
253
- "data-testid": "assistant-commit-status",
254
- children: [
255
- /* @__PURE__ */ d(pe, {
256
- className: "size-3 motion-safe:animate-spin",
257
- "aria-hidden": "true"
258
- }),
259
- /* @__PURE__ */ d("span", { children: x("attachments.saving", "Saving your attachments…") }),
260
- /* @__PURE__ */ d("button", {
261
- type: "button",
262
- onClick: Pe,
263
- className: "rounded text-text-primary underline underline-offset-2 hover:text-action-primary-bg focus:outline-none focus-visible:ring-2 focus-visible:ring-border-strong",
264
- "data-testid": "assistant-commit-cancel",
265
- children: x("attachments.cancelSaving", "Cancel")
266
- })
267
- ]
268
- })
269
- }) : A ? /* @__PURE__ */ d("p", {
270
- className: "text-status-error-text",
271
- role: "alert",
272
- "data-testid": "assistant-commit-failed",
273
- children: Fe(A)
274
- }) : G.isStarting && !G.isListening ? /* @__PURE__ */ d("p", {
275
- className: "text-text-muted",
276
- "data-testid": "assistant-voice-starting",
277
- children: x("voice.starting", "Starting the microphone…")
278
- }) : G.isListening ? /* @__PURE__ */ f("p", {
279
- className: "text-status-error-text",
280
- "data-testid": "assistant-voice-status",
281
- children: [/* @__PURE__ */ d(se, {}), G.interim || x("voice.listening", "Listening… speak now, tap the square to stop")]
282
- }) : Ue ? /* @__PURE__ */ d("p", {
283
- className: "text-status-error-text",
284
- "data-testid": "assistant-voice-error",
285
- children: Ue
286
- }) : F ? /* @__PURE__ */ d("button", {
287
- type: "button",
288
- onClick: Oe,
289
- className: "text-status-error-text underline-offset-2 hover:underline",
290
- "data-testid": "assistant-attachment-rejection",
291
- children: He(F)
292
- }) : P === "failed" ? /* @__PURE__ */ d("p", {
293
- className: "text-status-error-text",
294
- "data-testid": "assistant-attachment-blocked",
295
- children: X.length === 1 ? x("attachments.blockedOne", "{{name}} didn't upload. Retry or remove it before sending.", { name: X[0].filename }) : x("attachments.blockedMany", "{{count}} attachments didn't upload. Retry or remove them before sending.", { count: X.length })
296
- }) : /* @__PURE__ */ d("p", {
297
- className: "text-text-muted",
298
- children: x("composer.hint", "Enter to send · Shift+Enter for newline · drag or paste files to attach")
299
- })
443
+ children: dt(!1)
300
444
  })
301
445
  ]
302
446
  });