@green-on-grey/ui-kit 0.0.0-stage → 0.1.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.
package/dist/chat.js ADDED
@@ -0,0 +1,575 @@
1
+ import { c as e, d as t, i as n, l as r } from "./ui-CGgZtEVm.js";
2
+ import { n as i, t as a } from "./i18n-BJ8rsBp6.js";
3
+ import { Fragment as o, jsx as s, jsxs as c } from "react/jsx-runtime";
4
+ import { useCallback as l, useEffect as u, useLayoutEffect as d, useRef as f, useState as p } from "react";
5
+ import { useTranslation as m } from "react-i18next";
6
+ //#region src/chat/MessageView.tsx
7
+ var h = (e) => e === "zh" ? "zh-CN" : e;
8
+ function g(e, t) {
9
+ return new Intl.DateTimeFormat(h(t), {
10
+ hour: "2-digit",
11
+ minute: "2-digit"
12
+ }).format(new Date(e));
13
+ }
14
+ function _(e, t) {
15
+ return t || e.length <= 3 ? e : e.slice(-2);
16
+ }
17
+ var v = {
18
+ done: {
19
+ icon: "check",
20
+ cls: "ok"
21
+ },
22
+ error: {
23
+ icon: "alert",
24
+ cls: "er"
25
+ },
26
+ running: {
27
+ icon: "clock",
28
+ cls: "run"
29
+ }
30
+ };
31
+ function y({ m: e, busy: n, onRetry: i }) {
32
+ let { t: l, i18n: u } = m(a), [d, f] = p(!1);
33
+ if (e.role === "note") return /* @__PURE__ */ s("div", {
34
+ className: "sysnote",
35
+ children: e.text
36
+ });
37
+ let h = e.mark && /* @__PURE__ */ c("div", {
38
+ className: "chan",
39
+ children: [
40
+ /* @__PURE__ */ s(t, {
41
+ name: e.mark.icon,
42
+ size: 12
43
+ }),
44
+ " ",
45
+ e.mark.text,
46
+ " · ",
47
+ g(e.createdAt, u.language)
48
+ ]
49
+ }), y = e.attachments && e.attachments.length > 0 && /* @__PURE__ */ s("div", {
50
+ className: "atts",
51
+ children: e.attachments.map((e) => /* @__PURE__ */ c("a", {
52
+ href: e.href,
53
+ children: [
54
+ /* @__PURE__ */ s(t, {
55
+ name: "clip",
56
+ size: 12
57
+ }),
58
+ " ",
59
+ e.fileName
60
+ ]
61
+ }, e.id))
62
+ });
63
+ if (e.role === "user") return /* @__PURE__ */ c("div", {
64
+ className: "m u",
65
+ children: [
66
+ h,
67
+ e.content,
68
+ e.text && /* @__PURE__ */ s("div", {
69
+ className: "bub",
70
+ children: e.text
71
+ }),
72
+ y,
73
+ e.wait && /* @__PURE__ */ s("div", {
74
+ className: `turnstate${e.wait.state === "queued" ? " q" : ""}`,
75
+ role: "status",
76
+ children: e.wait.state === "queued" ? /* @__PURE__ */ c(o, { children: [/* @__PURE__ */ s(t, {
77
+ name: "clock",
78
+ size: 12
79
+ }), l("chat.wait.queued", { count: e.wait.position })] }) : /* @__PURE__ */ c(o, { children: [/* @__PURE__ */ s("span", {
80
+ className: "spin",
81
+ "aria-hidden": "true"
82
+ }), l("chat.wait.starting")] })
83
+ })
84
+ ]
85
+ });
86
+ let b = e.steps ?? [], x = (e.status === "streaming" || e.status === "pending") && !e.text && !e.content;
87
+ return /* @__PURE__ */ c("div", {
88
+ className: "m a",
89
+ children: [
90
+ h,
91
+ b.length > 3 && /* @__PURE__ */ s("button", {
92
+ className: "tools-fold",
93
+ onClick: () => f((e) => !e),
94
+ "aria-expanded": d,
95
+ children: d ? l("chat.hideSteps") : l("chat.moreSteps", { count: b.length - 2 })
96
+ }),
97
+ _(b, d).map((e) => /* @__PURE__ */ c("div", {
98
+ className: "tool",
99
+ title: e.title,
100
+ children: [/* @__PURE__ */ s(t, {
101
+ name: v[e.status].icon,
102
+ size: 14,
103
+ className: v[e.status].cls
104
+ }), /* @__PURE__ */ s("span", {
105
+ className: "tx",
106
+ children: e.text
107
+ })]
108
+ }, e.id)),
109
+ x && /* @__PURE__ */ s("div", {
110
+ className: "bub",
111
+ children: /* @__PURE__ */ c("span", {
112
+ className: "typing",
113
+ "aria-label": l("chat.typing"),
114
+ children: [
115
+ /* @__PURE__ */ s("i", {}),
116
+ /* @__PURE__ */ s("i", {}),
117
+ /* @__PURE__ */ s("i", {})
118
+ ]
119
+ })
120
+ }),
121
+ e.content ?? (e.text && /* @__PURE__ */ s("div", {
122
+ className: "bub",
123
+ children: /* @__PURE__ */ s(r, { text: e.text })
124
+ })),
125
+ y,
126
+ e.error && /* @__PURE__ */ c("div", {
127
+ className: `llmerr${e.error.transient ? " amber" : ""}`,
128
+ role: "alert",
129
+ style: { marginTop: 6 },
130
+ children: [/* @__PURE__ */ s("span", { children: e.error.text }), i && /* @__PURE__ */ s("div", {
131
+ className: "row",
132
+ children: /* @__PURE__ */ c("button", {
133
+ className: "btn sm",
134
+ disabled: n,
135
+ onClick: i,
136
+ children: [/* @__PURE__ */ s(t, {
137
+ name: "refresh",
138
+ size: 14
139
+ }), l("chat.retry")]
140
+ })
141
+ })]
142
+ })
143
+ ]
144
+ });
145
+ }
146
+ //#endregion
147
+ //#region src/chat/useRecorder.ts
148
+ function b() {
149
+ let e = typeof window < "u" && "MediaRecorder" in window && !!navigator.mediaDevices?.getUserMedia, [t, n] = p(!1), [r, i] = p(0), [a, o] = p(!1), s = f(null), c = f([]), d = f(void 0), m = f(null), h = l(() => {
150
+ window.clearInterval(d.current), s.current?.stream.getTracks().forEach((e) => e.stop()), s.current = null, n(!1);
151
+ }, []), g = l(async () => {
152
+ if (e && !s.current) {
153
+ o(!1);
154
+ try {
155
+ let e = await navigator.mediaDevices.getUserMedia({ audio: !0 }), t = new MediaRecorder(e);
156
+ c.current = [], t.ondataavailable = (e) => e.data.size > 0 && c.current.push(e.data), t.onstop = () => {
157
+ let e = c.current.length ? new Blob(c.current, { type: t.mimeType || "audio/webm" }) : null;
158
+ h(), m.current?.(e), m.current = null;
159
+ }, s.current = t, t.start(), i(0), n(!0);
160
+ let r = Date.now();
161
+ d.current = window.setInterval(() => i(Math.floor((Date.now() - r) / 1e3)), 250);
162
+ } catch {
163
+ o(!0), h();
164
+ }
165
+ }
166
+ }, [e, h]), _ = l(() => new Promise((e) => {
167
+ let t = s.current;
168
+ if (!t || t.state === "inactive") return e(null);
169
+ m.current = e, t.stop();
170
+ }), []);
171
+ return u(() => () => h(), [h]), {
172
+ supported: e,
173
+ recording: t,
174
+ seconds: `${Math.floor(r / 60)}:${String(r % 60).padStart(2, "0")}`,
175
+ error: a,
176
+ start: g,
177
+ stop: _
178
+ };
179
+ }
180
+ //#endregion
181
+ //#region src/chat/Chat.tsx
182
+ function x(n) {
183
+ let r = i(), a = e(), [l, u] = p(""), [m, h] = p([]), [g, _] = p(!1), [v, x] = p(null), S = f(null), C = f(null), w = b(), { messages: T, busy: E = !1 } = n, D = T[0]?.id, O = T[T.length - 1], k = O?.text.length, A = O?.steps?.length, j = f({ height: 0 });
184
+ d(() => {
185
+ let e = S.current;
186
+ if (!e) return;
187
+ let t = j.current;
188
+ e.scrollTop = t.first !== void 0 && D !== t.first && T.some((e) => e.id === t.first) ? e.scrollTop + (e.scrollHeight - t.height) : e.scrollHeight, j.current = {
189
+ first: D,
190
+ height: e.scrollHeight
191
+ };
192
+ }, [
193
+ T.length,
194
+ D,
195
+ k,
196
+ A
197
+ ]);
198
+ let M = async (e, t) => {
199
+ let r = e.trim();
200
+ if (!(!r && m.length === 0 || E || n.readOnly)) try {
201
+ await n.onSend(r, m.map((e) => e.id), t), u(""), h([]), x(null);
202
+ } catch {}
203
+ }, N = async (e) => {
204
+ if (e?.length && n.onUpload) {
205
+ _(!0);
206
+ for (let t of Array.from(e)) {
207
+ if (n.upload && t.size > n.upload.maxBytes) {
208
+ a({
209
+ kind: "error",
210
+ title: r("chat.tooLarge"),
211
+ text: t.name
212
+ });
213
+ continue;
214
+ }
215
+ let e = await n.onUpload(t).catch(() => null);
216
+ e && h((t) => [...t, e]);
217
+ }
218
+ _(!1), C.current && (C.current.value = "");
219
+ }
220
+ }, P = async () => {
221
+ let e = await w.stop();
222
+ if (!e || !n.onTranscribe) return;
223
+ let t = await n.onTranscribe(e).catch(() => null);
224
+ t !== null && (t ? x(t) : a({
225
+ kind: "error",
226
+ title: r("chat.voice.notRecognized")
227
+ }));
228
+ }, F = (e) => {
229
+ (e.key === " " || e.key === "Enter") && (e.preventDefault(), !e.repeat && (w.recording ? P() : w.start()));
230
+ }, I = r("chat.placeholder", { name: n.agentName });
231
+ return /* @__PURE__ */ c("section", {
232
+ className: "nb-chat",
233
+ "aria-label": r("chat.title"),
234
+ children: [
235
+ n.header,
236
+ /* @__PURE__ */ c("div", {
237
+ className: "msgs",
238
+ ref: S,
239
+ "aria-live": "polite",
240
+ children: [
241
+ n.hasOlder && n.onLoadOlder && /* @__PURE__ */ s("button", {
242
+ className: "btn ghost sm",
243
+ style: { alignSelf: "center" },
244
+ disabled: n.loadingOlder,
245
+ onClick: n.onLoadOlder,
246
+ children: r("chat.loadOlder")
247
+ }),
248
+ n.historyError && /* @__PURE__ */ s("div", {
249
+ className: "err-text",
250
+ children: n.historyError
251
+ }),
252
+ T.length === 0 && !n.loading && !n.historyError && /* @__PURE__ */ c("div", {
253
+ className: "empty",
254
+ children: [
255
+ /* @__PURE__ */ s("div", {
256
+ className: "ic",
257
+ children: /* @__PURE__ */ s(t, { name: "spark" })
258
+ }),
259
+ /* @__PURE__ */ s("b", { children: r("chat.emptyTitle", { name: n.agentName }) }),
260
+ n.emptyHint
261
+ ]
262
+ }),
263
+ T.map((e) => /* @__PURE__ */ s(y, {
264
+ m: e,
265
+ busy: E,
266
+ onRetry: n.onRetry && (() => n.onRetry?.(e.id))
267
+ }, e.id)),
268
+ n.onConfirm && (n.confirmations ?? []).map((e) => /* @__PURE__ */ c("div", {
269
+ className: "confirm",
270
+ role: "group",
271
+ "aria-label": r("chat.confirm.title"),
272
+ children: [
273
+ /* @__PURE__ */ c("div", {
274
+ className: "h",
275
+ children: [/* @__PURE__ */ s(t, {
276
+ name: "alert",
277
+ size: 16
278
+ }), r("chat.confirm.title")]
279
+ }),
280
+ /* @__PURE__ */ s("div", { children: r("chat.confirm.text", { action: e.summary }) }),
281
+ e.preview !== void 0 && /* @__PURE__ */ s("pre", { children: e.preview }),
282
+ /* @__PURE__ */ c("div", {
283
+ className: "acts",
284
+ children: [/* @__PURE__ */ s("button", {
285
+ className: "btn sm primary",
286
+ disabled: E,
287
+ onClick: () => n.onConfirm?.(e.id, !0),
288
+ children: r("chat.confirm.approve")
289
+ }), /* @__PURE__ */ s("button", {
290
+ className: "btn sm",
291
+ disabled: E,
292
+ onClick: () => n.onConfirm?.(e.id, !1),
293
+ children: r("chat.confirm.reject")
294
+ })]
295
+ })
296
+ ]
297
+ }, e.id))
298
+ ]
299
+ }),
300
+ n.readOnly ? /* @__PURE__ */ s("div", {
301
+ className: "composer",
302
+ style: {
303
+ justifyContent: "space-between",
304
+ alignItems: "center"
305
+ },
306
+ children: n.readOnly
307
+ }) : v === null ? /* @__PURE__ */ c(o, { children: [
308
+ n.aboveComposer,
309
+ m.length > 0 && /* @__PURE__ */ s("div", {
310
+ className: "pending-files",
311
+ children: m.map((e) => /* @__PURE__ */ c("span", {
312
+ className: "chip",
313
+ children: [
314
+ /* @__PURE__ */ s(t, {
315
+ name: "clip",
316
+ size: 12
317
+ }),
318
+ e.fileName,
319
+ /* @__PURE__ */ s("button", {
320
+ className: "iconbtn",
321
+ style: {
322
+ width: 18,
323
+ height: 18
324
+ },
325
+ "aria-label": r("remove"),
326
+ onClick: () => h((t) => t.filter((t) => t.id !== e.id)),
327
+ children: /* @__PURE__ */ s(t, {
328
+ name: "x",
329
+ size: 12
330
+ })
331
+ })
332
+ ]
333
+ }, e.id))
334
+ }),
335
+ /* @__PURE__ */ c("div", {
336
+ className: "composer",
337
+ children: [
338
+ n.onUpload && /* @__PURE__ */ c(o, { children: [/* @__PURE__ */ s("button", {
339
+ className: "iconbtn",
340
+ "aria-label": r("chat.attach"),
341
+ disabled: g,
342
+ onClick: () => C.current?.click(),
343
+ children: /* @__PURE__ */ s(t, { name: "clip" })
344
+ }), /* @__PURE__ */ s("input", {
345
+ ref: C,
346
+ type: "file",
347
+ multiple: !0,
348
+ hidden: !0,
349
+ accept: n.upload?.accept,
350
+ onChange: (e) => N(e.target.files)
351
+ })] }),
352
+ w.recording ? /* @__PURE__ */ s("div", {
353
+ className: "rec-box",
354
+ children: r("chat.voice.recording", { seconds: w.seconds })
355
+ }) : /* @__PURE__ */ s("textarea", {
356
+ rows: 1,
357
+ value: l,
358
+ placeholder: I,
359
+ "aria-label": I,
360
+ onChange: (e) => u(e.target.value),
361
+ onKeyDown: (e) => {
362
+ e.key === "Enter" && !e.shiftKey && !e.nativeEvent.isComposing && (e.preventDefault(), M(l, !1));
363
+ }
364
+ }),
365
+ n.onTranscribe && /* @__PURE__ */ s("button", {
366
+ className: `iconbtn${w.recording ? " rec" : ""}`,
367
+ disabled: !w.supported,
368
+ "aria-label": w.recording ? r("chat.voice.stop") : r("chat.voice.hold"),
369
+ title: w.supported ? r("chat.voice.hold") : r("chat.voice.unsupported"),
370
+ onPointerDown: (e) => {
371
+ e.preventDefault(), w.recording || w.start();
372
+ },
373
+ onPointerUp: () => w.recording && P(),
374
+ onPointerLeave: () => w.recording && P(),
375
+ onKeyDown: F,
376
+ children: /* @__PURE__ */ s(t, { name: "mic" })
377
+ }),
378
+ n.onCancel && E ? /* @__PURE__ */ s("button", {
379
+ className: "iconbtn fill",
380
+ "aria-label": r("chat.stop"),
381
+ onClick: n.onCancel,
382
+ children: /* @__PURE__ */ s(t, { name: "stop" })
383
+ }) : /* @__PURE__ */ s("button", {
384
+ className: "iconbtn fill",
385
+ "aria-label": r("chat.send"),
386
+ disabled: !l.trim() && m.length === 0 || E,
387
+ onClick: () => M(l, !1),
388
+ children: /* @__PURE__ */ s(t, { name: "send" })
389
+ })
390
+ ]
391
+ }),
392
+ w.error && /* @__PURE__ */ s("div", {
393
+ className: "err-text",
394
+ style: { padding: "0 12px 8px" },
395
+ children: r("chat.voice.micDenied")
396
+ })
397
+ ] }) : /* @__PURE__ */ c("div", {
398
+ className: "transcript",
399
+ style: { margin: 10 },
400
+ children: [
401
+ /* @__PURE__ */ s("div", {
402
+ className: "small muted",
403
+ style: { marginBottom: 4 },
404
+ children: r("chat.voice.review")
405
+ }),
406
+ /* @__PURE__ */ s("textarea", {
407
+ className: "inp",
408
+ rows: 3,
409
+ value: v,
410
+ onChange: (e) => x(e.target.value),
411
+ "aria-label": r("chat.voice.review")
412
+ }),
413
+ /* @__PURE__ */ c("div", {
414
+ className: "row2",
415
+ style: { marginTop: 8 },
416
+ children: [/* @__PURE__ */ s("button", {
417
+ className: "btn ghost sm",
418
+ onClick: () => x(null),
419
+ children: r("delete")
420
+ }), /* @__PURE__ */ s("button", {
421
+ className: "btn primary sm",
422
+ disabled: !v.trim() || E,
423
+ onClick: () => M(v, !0),
424
+ children: r("chat.send")
425
+ })]
426
+ })
427
+ ]
428
+ })
429
+ ]
430
+ });
431
+ }
432
+ //#endregion
433
+ //#region src/chat/ConversationList.tsx
434
+ function S({ conversations: e, currentId: n, open: r, onPick: a, onClose: l, onCreate: d }) {
435
+ let f = i(), [m, h] = p(!1);
436
+ u(() => {
437
+ if (!r) return;
438
+ let e = (e) => e.key === "Escape" && l();
439
+ return document.addEventListener("keydown", e), () => document.removeEventListener("keydown", e);
440
+ }, [r, l]);
441
+ let g = (e) => /* @__PURE__ */ c("button", {
442
+ className: `it${e.id === n ? " on" : ""}${e.group === "archive" ? " arch" : ""}`,
443
+ onClick: () => a(e.id),
444
+ "aria-current": e.id === n,
445
+ children: [
446
+ /* @__PURE__ */ s(t, {
447
+ name: e.icon ?? "msg2",
448
+ size: 16
449
+ }),
450
+ /* @__PURE__ */ s("span", {
451
+ className: "nm",
452
+ children: e.title
453
+ }),
454
+ !!e.unread && /* @__PURE__ */ s("span", {
455
+ className: "unread",
456
+ "aria-label": f("chat.unread", { count: e.unread }),
457
+ children: e.unread
458
+ }),
459
+ /* @__PURE__ */ s("span", {
460
+ className: "sub",
461
+ children: e.when
462
+ })
463
+ ]
464
+ }, e.id), _ = (t) => e.filter((e) => e.group === t), v = _("topic"), y = _("archive");
465
+ return /* @__PURE__ */ c(o, { children: [
466
+ /* @__PURE__ */ c("nav", {
467
+ className: `nb-side${r ? " open" : ""}`,
468
+ "aria-label": f("chat.conversations"),
469
+ children: [
470
+ d && /* @__PURE__ */ c("button", {
471
+ className: "btn sm",
472
+ style: {
473
+ width: "100%",
474
+ justifyContent: "center"
475
+ },
476
+ onClick: () => h(!0),
477
+ children: [/* @__PURE__ */ s(t, {
478
+ name: "plus",
479
+ size: 15
480
+ }), f("chat.newTopic")]
481
+ }),
482
+ /* @__PURE__ */ s("div", {
483
+ className: "h",
484
+ children: f("chat.conversation")
485
+ }),
486
+ _("main").map(g),
487
+ /* @__PURE__ */ s("div", {
488
+ className: "h",
489
+ children: f("chat.topics")
490
+ }),
491
+ v.length === 0 && /* @__PURE__ */ s("div", {
492
+ className: "small muted",
493
+ style: { padding: "0 10px" },
494
+ children: f("chat.noTopics")
495
+ }),
496
+ v.map(g),
497
+ y.length > 0 && /* @__PURE__ */ s("div", {
498
+ className: "h",
499
+ children: f("chat.archive")
500
+ }),
501
+ y.map(g)
502
+ ]
503
+ }),
504
+ r && /* @__PURE__ */ s("button", {
505
+ type: "button",
506
+ className: "nb-scrim",
507
+ "aria-label": f("close"),
508
+ onClick: l
509
+ }),
510
+ m && d && /* @__PURE__ */ s(w, {
511
+ onClose: () => h(!1),
512
+ onCreate: d
513
+ })
514
+ ] });
515
+ }
516
+ function C({ narrow: e, children: t }) {
517
+ return /* @__PURE__ */ s("div", {
518
+ className: `nb-app${e ? " narrow" : ""}`,
519
+ children: t
520
+ });
521
+ }
522
+ function w({ onClose: e, onCreate: t }) {
523
+ let r = i(), [a, l] = p(""), [u, d] = p(!1), [f, m] = p(null), h = async () => {
524
+ if (a.trim() && !u) {
525
+ d(!0), m(null);
526
+ try {
527
+ await t(a.trim()), e();
528
+ } catch (e) {
529
+ m(e instanceof Error ? e.message : String(e)), d(!1);
530
+ }
531
+ }
532
+ };
533
+ return /* @__PURE__ */ c(n, {
534
+ title: r("chat.newTopic"),
535
+ onClose: e,
536
+ footer: /* @__PURE__ */ c(o, { children: [/* @__PURE__ */ s("button", {
537
+ className: "btn ghost",
538
+ onClick: e,
539
+ children: r("cancel")
540
+ }), /* @__PURE__ */ s("button", {
541
+ className: "btn primary",
542
+ disabled: !a.trim() || u,
543
+ onClick: h,
544
+ children: r("create")
545
+ })] }),
546
+ children: [/* @__PURE__ */ c("div", {
547
+ className: "field",
548
+ children: [
549
+ /* @__PURE__ */ s("label", {
550
+ htmlFor: "topic-title",
551
+ children: r("chat.topicTitle")
552
+ }),
553
+ /* @__PURE__ */ s("input", {
554
+ id: "topic-title",
555
+ className: "inp",
556
+ value: a,
557
+ maxLength: 120,
558
+ onChange: (e) => l(e.target.value),
559
+ onKeyDown: (e) => e.key === "Enter" && h()
560
+ }),
561
+ /* @__PURE__ */ s("div", {
562
+ className: "hint",
563
+ children: r("chat.topicHint")
564
+ })
565
+ ]
566
+ }), f && /* @__PURE__ */ s("div", {
567
+ className: "err-text",
568
+ children: f
569
+ })]
570
+ });
571
+ }
572
+ //#endregion
573
+ export { x as Chat, C as ChatLayout, S as ConversationList, w as NewTopicModal, b as useRecorder };
574
+
575
+ //# sourceMappingURL=chat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat.js","names":["_Fragment","_Fragment","_Fragment","useToast","Icon","Modal","Markdown","useKitT","UIKIT_NS","intlLocale","lng","markTime","language","iso","visibleSteps","open","steps","STEP","MessageView","useTranslation","setOpen","useState","m","mark","i18n","atts","a","Fragment","t","waiting","v","s","onRetry","busy","useRecorder","supported","recording","setRecording","seconds","setSeconds","error","setError","rec","useRef","chunks","timer","stopped","cleanup","useCallback","tr","start","stream","r","blob","began","stop","resolve","useEffect","Chat","toast","text","setText","pending","setPending","uploading","setUploading","transcript","setTranscript","listRef","fileRef","recorder","props","first","messages","tail","tailText","tailSteps","lastLayout","el","was","send","msg","body","f","voice","attach","files","x","stopAndTranscribe","voiceKey","placeholder","c","y","ConversationList","creating","setCreating","onKey","onClose","item","currentId","onPick","inGroup","conversations","g","topics","archive","onCreate","NewTopicModal","ChatLayout","narrow","title","setTitle","create"],"sources":["../src/chat/MessageView.tsx","../src/chat/useRecorder.ts","../src/chat/Chat.tsx","../src/chat/ConversationList.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { Icon } from \"../components/Icon\";\nimport { Markdown } from \"../components/Markdown\";\nimport { UIKIT_NS } from \"../i18n\";\nimport type { ChatMessage, ChatStep } from \"./types\";\n\n/** The locale of Intl formatting for a language code of the products. */\nconst intlLocale = (lng: string) => (lng === \"zh\" ? \"zh-CN\" : lng);\n\n/** The time of a caption: hours and minutes in the language of the interface. */\nexport function markTime(iso: string, language: string): string {\n return new Intl.DateTimeFormat(intlLocale(language), { hour: \"2-digit\", minute: \"2-digit\" }).format(new Date(iso));\n}\n\n/** More than three steps are folded to the last two (design §6.4). */\nexport function visibleSteps(steps: ChatStep[], open: boolean): ChatStep[] {\n return open || steps.length <= 3 ? steps : steps.slice(-2);\n}\n\n/** The icon of a step and its colour class by the state of the step. */\nconst STEP = {\n done: { icon: \"check\", cls: \"ok\" },\n error: { icon: \"alert\", cls: \"er\" },\n running: { icon: \"clock\", cls: \"run\" },\n} as const;\n\n/** One message of the conversation (design §6.4). */\nexport function MessageView({ m, busy, onRetry }: { m: ChatMessage; busy: boolean; onRetry?: () => void }) {\n const { t, i18n } = useTranslation(UIKIT_NS);\n const [open, setOpen] = useState(false);\n if (m.role === \"note\") return <div className=\"sysnote\">{m.text}</div>;\n const mark = m.mark && <div className=\"chan\"><Icon name={m.mark.icon} size={12} /> {m.mark.text} · {markTime(m.createdAt, i18n.language)}</div>;\n const atts = m.attachments && m.attachments.length > 0 && (\n <div className=\"atts\">\n {m.attachments.map((a) => <a key={a.id} href={a.href}><Icon name=\"clip\" size={12} /> {a.fileName}</a>)}\n </div>\n );\n if (m.role === \"user\") {\n return (\n <div className=\"m u\">\n {mark}\n {m.content}\n {m.text && <div className=\"bub\">{m.text}</div>}\n {atts}\n {m.wait && (\n <div className={`turnstate${m.wait.state === \"queued\" ? \" q\" : \"\"}`} role=\"status\">\n {m.wait.state === \"queued\"\n ? <><Icon name=\"clock\" size={12} />{t(\"chat.wait.queued\", { count: m.wait.position })}</>\n : <><span className=\"spin\" aria-hidden=\"true\" />{t(\"chat.wait.starting\")}</>}\n </div>\n )}\n </div>\n );\n }\n const steps = m.steps ?? [];\n const waiting = (m.status === \"streaming\" || m.status === \"pending\") && !m.text && !m.content;\n return (\n <div className=\"m a\">\n {mark}\n {steps.length > 3 && (\n <button className=\"tools-fold\" onClick={() => setOpen((v) => !v)} aria-expanded={open}>\n {open ? t(\"chat.hideSteps\") : t(\"chat.moreSteps\", { count: steps.length - 2 })}\n </button>\n )}\n {visibleSteps(steps, open).map((s) => (\n <div key={s.id} className=\"tool\" title={s.title}>\n <Icon name={STEP[s.status].icon} size={14} className={STEP[s.status].cls} />\n <span className=\"tx\">{s.text}</span>\n </div>\n ))}\n {waiting && <div className=\"bub\"><span className=\"typing\" aria-label={t(\"chat.typing\")}><i /><i /><i /></span></div>}\n {m.content ?? (m.text && <div className=\"bub\"><Markdown text={m.text} /></div>)}\n {atts}\n {m.error && (\n <div className={`llmerr${m.error.transient ? \" amber\" : \"\"}`} role=\"alert\" style={{ marginTop: 6 }}>\n <span>{m.error.text}</span>\n {onRetry && (\n <div className=\"row\">\n <button className=\"btn sm\" disabled={busy} onClick={onRetry}><Icon name=\"refresh\" size={14} />{t(\"chat.retry\")}</button>\n </div>\n )}\n </div>\n )}\n </div>\n );\n}\n","import { useCallback, useEffect, useRef, useState } from \"react\";\n\n/** Push-to-talk recording with MediaRecorder. */\nexport function useRecorder() {\n const supported = typeof window !== \"undefined\" && \"MediaRecorder\" in window && !!navigator.mediaDevices?.getUserMedia;\n const [recording, setRecording] = useState(false);\n const [seconds, setSeconds] = useState(0);\n const [error, setError] = useState(false);\n const rec = useRef<MediaRecorder | null>(null);\n const chunks = useRef<Blob[]>([]);\n const timer = useRef<number | undefined>(undefined);\n const stopped = useRef<((b: Blob | null) => void) | null>(null);\n\n const cleanup = useCallback(() => {\n window.clearInterval(timer.current);\n rec.current?.stream.getTracks().forEach((tr) => tr.stop());\n rec.current = null;\n setRecording(false);\n }, []);\n\n const start = useCallback(async () => {\n if (!supported || rec.current) return;\n setError(false);\n try {\n const stream = await navigator.mediaDevices.getUserMedia({ audio: true });\n const r = new MediaRecorder(stream);\n chunks.current = [];\n r.ondataavailable = (e) => e.data.size > 0 && chunks.current.push(e.data);\n r.onstop = () => {\n const blob = chunks.current.length ? new Blob(chunks.current, { type: r.mimeType || \"audio/webm\" }) : null;\n cleanup();\n stopped.current?.(blob);\n stopped.current = null;\n };\n rec.current = r;\n r.start();\n setSeconds(0);\n setRecording(true);\n const began = Date.now();\n timer.current = window.setInterval(() => setSeconds(Math.floor((Date.now() - began) / 1000)), 250);\n } catch {\n setError(true);\n cleanup();\n }\n }, [supported, cleanup]);\n\n const stop = useCallback(() => new Promise<Blob | null>((resolve) => {\n const r = rec.current;\n if (!r || r.state === \"inactive\") return resolve(null);\n stopped.current = resolve;\n r.stop();\n }), []);\n\n useEffect(() => () => cleanup(), [cleanup]);\n\n const mm = Math.floor(seconds / 60);\n const ss = String(seconds % 60).padStart(2, \"0\");\n return { supported, recording, seconds: `${mm}:${ss}`, error, start, stop };\n}\n","import { useLayoutEffect, useRef, useState, type KeyboardEvent } from \"react\";\nimport { Icon } from \"../components/Icon\";\nimport { useToast } from \"../components/ui\";\nimport { useKitT } from \"../i18n\";\nimport { MessageView } from \"./MessageView\";\nimport type { ChatProps, ChatUpload } from \"./types\";\nimport { useRecorder } from \"./useRecorder\";\n\n/** The conversation: the messages and the composer (FTR.NAB.CMN-0005 R11–R13,\n * design §6). The behaviour is the one of the chat of Nabu. A control exists\n * only when the product gave its handler: no `onCancel` — no cancel button. */\nexport function Chat(props: ChatProps) {\n const t = useKitT();\n const toast = useToast();\n const [text, setText] = useState(\"\");\n const [pending, setPending] = useState<ChatUpload[]>([]);\n const [uploading, setUploading] = useState(false);\n const [transcript, setTranscript] = useState<string | null>(null);\n const listRef = useRef<HTMLDivElement>(null);\n const fileRef = useRef<HTMLInputElement>(null);\n const recorder = useRecorder();\n const { messages, busy = false } = props;\n\n const first = messages[0]?.id;\n const tail = messages[messages.length - 1];\n const tailText = tail?.text.length;\n const tailSteps = tail?.steps?.length;\n // The first message and the height of the list at the last layout: earlier\n // messages loaded above it keep the place of the list.\n const lastLayout = useRef<{ first?: string; height: number }>({ height: 0 });\n // The list follows new messages and the growth of the last one: the dependencies are the trigger.\n useLayoutEffect(() => {\n const el = listRef.current;\n if (!el) return;\n const was = lastLayout.current;\n // history is prepended when the message that was first is still there, lower\n const prepended = was.first !== undefined && first !== was.first && messages.some((m) => m.id === was.first);\n el.scrollTop = prepended ? el.scrollTop + (el.scrollHeight - was.height) : el.scrollHeight;\n lastLayout.current = { first, height: el.scrollHeight };\n }, [messages.length, first, tailText, tailSteps]); // oxlint-disable-line react/exhaustive-effect-dependencies\n\n const send = async (body: string, voice: boolean) => {\n const msg = body.trim();\n if ((!msg && pending.length === 0) || busy || props.readOnly) return;\n try {\n await props.onSend(msg, pending.map((f) => f.id), voice);\n setText(\"\");\n setPending([]);\n setTranscript(null);\n } catch {\n // the product has told the user; the text stays in the composer\n }\n };\n\n const attach = async (files: FileList | null) => {\n if (!files?.length || !props.onUpload) return;\n setUploading(true);\n for (const f of Array.from(files)) {\n if (props.upload && f.size > props.upload.maxBytes) {\n toast({ kind: \"error\", title: t(\"chat.tooLarge\"), text: f.name });\n continue;\n }\n const a = await props.onUpload(f).catch(() => null);\n if (a) setPending((x) => [...x, a]);\n }\n setUploading(false);\n if (fileRef.current) fileRef.current.value = \"\";\n };\n\n const stopAndTranscribe = async () => {\n const blob = await recorder.stop();\n if (!blob || !props.onTranscribe) return;\n const r = await props.onTranscribe(blob).catch(() => null);\n if (r === null) return;\n if (!r) toast({ kind: \"error\", title: t(\"chat.voice.notRecognized\") });\n else setTranscript(r);\n };\n // Without a pointer the same button starts and stops the recording (R18).\n const voiceKey = (e: KeyboardEvent) => {\n if (e.key !== \" \" && e.key !== \"Enter\") return;\n e.preventDefault();\n if (e.repeat) return;\n if (recorder.recording) void stopAndTranscribe();\n else void recorder.start();\n };\n\n const placeholder = t(\"chat.placeholder\", { name: props.agentName });\n return (\n <section className=\"nb-chat\" aria-label={t(\"chat.title\")}>\n {props.header}\n <div className=\"msgs\" ref={listRef} aria-live=\"polite\">\n {props.hasOlder && props.onLoadOlder && (\n <button className=\"btn ghost sm\" style={{ alignSelf: \"center\" }} disabled={props.loadingOlder} onClick={props.onLoadOlder}>\n {t(\"chat.loadOlder\")}\n </button>\n )}\n {props.historyError && <div className=\"err-text\">{props.historyError}</div>}\n {messages.length === 0 && !props.loading && !props.historyError && (\n <div className=\"empty\"><div className=\"ic\"><Icon name=\"spark\" /></div><b>{t(\"chat.emptyTitle\", { name: props.agentName })}</b>{props.emptyHint}</div>\n )}\n {messages.map((m) => <MessageView key={m.id} m={m} busy={busy} onRetry={props.onRetry && (() => props.onRetry?.(m.id))} />)}\n {props.onConfirm && (props.confirmations ?? []).map((c) => (\n <div className=\"confirm\" key={c.id} role=\"group\" aria-label={t(\"chat.confirm.title\")}>\n <div className=\"h\"><Icon name=\"alert\" size={16} />{t(\"chat.confirm.title\")}</div>\n <div>{t(\"chat.confirm.text\", { action: c.summary })}</div>\n {c.preview !== undefined && <pre>{c.preview}</pre>}\n <div className=\"acts\">\n <button className=\"btn sm primary\" disabled={busy} onClick={() => props.onConfirm?.(c.id, true)}>{t(\"chat.confirm.approve\")}</button>\n <button className=\"btn sm\" disabled={busy} onClick={() => props.onConfirm?.(c.id, false)}>{t(\"chat.confirm.reject\")}</button>\n </div>\n </div>\n ))}\n </div>\n\n {props.readOnly ? (\n <div className=\"composer\" style={{ justifyContent: \"space-between\", alignItems: \"center\" }}>{props.readOnly}</div>\n ) : transcript !== null ? (\n <div className=\"transcript\" style={{ margin: 10 }}>\n <div className=\"small muted\" style={{ marginBottom: 4 }}>{t(\"chat.voice.review\")}</div>\n <textarea className=\"inp\" rows={3} value={transcript} onChange={(e) => setTranscript(e.target.value)} aria-label={t(\"chat.voice.review\")} />\n <div className=\"row2\" style={{ marginTop: 8 }}>\n <button className=\"btn ghost sm\" onClick={() => setTranscript(null)}>{t(\"delete\")}</button>\n <button className=\"btn primary sm\" disabled={!transcript.trim() || busy} onClick={() => send(transcript, true)}>{t(\"chat.send\")}</button>\n </div>\n </div>\n ) : (\n <>\n {props.aboveComposer}\n {pending.length > 0 && (\n <div className=\"pending-files\">\n {pending.map((f) => (\n <span key={f.id} className=\"chip\">\n <Icon name=\"clip\" size={12} />{f.fileName}\n <button className=\"iconbtn\" style={{ width: 18, height: 18 }} aria-label={t(\"remove\")}\n onClick={() => setPending((x) => x.filter((y) => y.id !== f.id))}><Icon name=\"x\" size={12} /></button>\n </span>\n ))}\n </div>\n )}\n <div className=\"composer\">\n {props.onUpload && (\n <>\n <button className=\"iconbtn\" aria-label={t(\"chat.attach\")} disabled={uploading} onClick={() => fileRef.current?.click()}><Icon name=\"clip\" /></button>\n <input ref={fileRef} type=\"file\" multiple hidden accept={props.upload?.accept} onChange={(e) => attach(e.target.files)} />\n </>\n )}\n {recorder.recording ? (\n <div className=\"rec-box\">{t(\"chat.voice.recording\", { seconds: recorder.seconds })}</div>\n ) : (\n <textarea rows={1} value={text} placeholder={placeholder} aria-label={placeholder} onChange={(e) => setText(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && !e.shiftKey && !e.nativeEvent.isComposing) {\n e.preventDefault();\n void send(text, false);\n }\n }} />\n )}\n {props.onTranscribe && (\n <button className={`iconbtn${recorder.recording ? \" rec\" : \"\"}`} disabled={!recorder.supported}\n aria-label={recorder.recording ? t(\"chat.voice.stop\") : t(\"chat.voice.hold\")}\n title={recorder.supported ? t(\"chat.voice.hold\") : t(\"chat.voice.unsupported\")}\n onPointerDown={(e) => { e.preventDefault(); if (!recorder.recording) void recorder.start(); }}\n onPointerUp={() => recorder.recording && stopAndTranscribe()}\n onPointerLeave={() => recorder.recording && stopAndTranscribe()}\n onKeyDown={voiceKey}>\n <Icon name=\"mic\" />\n </button>\n )}\n {props.onCancel && busy ? (\n <button className=\"iconbtn fill\" aria-label={t(\"chat.stop\")} onClick={props.onCancel}><Icon name=\"stop\" /></button>\n ) : (\n <button className=\"iconbtn fill\" aria-label={t(\"chat.send\")} disabled={(!text.trim() && pending.length === 0) || busy} onClick={() => send(text, false)}>\n <Icon name=\"send\" />\n </button>\n )}\n </div>\n {recorder.error && <div className=\"err-text\" style={{ padding: \"0 12px 8px\" }}>{t(\"chat.voice.micDenied\")}</div>}\n </>\n )}\n </section>\n );\n}\n","import { useEffect, useState, type ReactNode } from \"react\";\nimport { Icon } from \"../components/Icon\";\nimport { Modal } from \"../components/ui\";\nimport { useKitT } from \"../i18n\";\nimport type { ChatConversation, ConversationListProps } from \"./types\";\n\n/** The conversations of the user: the main one, the topics, the archive (design\n * §6.2). In a wide place the list stands left of the messages; on a phone and in\n * a narrow place it lies over them while open and closes by a pick, a tap\n * beside it or Escape. */\nexport function ConversationList({ conversations, currentId, open, onPick, onClose, onCreate }: ConversationListProps) {\n const t = useKitT();\n const [creating, setCreating] = useState(false);\n useEffect(() => {\n if (!open) return;\n const onKey = (e: KeyboardEvent) => e.key === \"Escape\" && onClose();\n document.addEventListener(\"keydown\", onKey);\n return () => document.removeEventListener(\"keydown\", onKey);\n }, [open, onClose]);\n\n const item = (c: ChatConversation) => (\n <button key={c.id} className={`it${c.id === currentId ? \" on\" : \"\"}${c.group === \"archive\" ? \" arch\" : \"\"}`}\n onClick={() => onPick(c.id)} aria-current={c.id === currentId}>\n <Icon name={c.icon ?? \"msg2\"} size={16} />\n <span className=\"nm\">{c.title}</span>\n {!!c.unread && <span className=\"unread\" aria-label={t(\"chat.unread\", { count: c.unread })}>{c.unread}</span>}\n <span className=\"sub\">{c.when}</span>\n </button>\n );\n const inGroup = (g: ChatConversation[\"group\"]) => conversations.filter((c) => c.group === g);\n const topics = inGroup(\"topic\");\n const archive = inGroup(\"archive\");\n return (\n <>\n <nav className={`nb-side${open ? \" open\" : \"\"}`} aria-label={t(\"chat.conversations\")}>\n {onCreate && (\n <button className=\"btn sm\" style={{ width: \"100%\", justifyContent: \"center\" }} onClick={() => setCreating(true)}>\n <Icon name=\"plus\" size={15} />{t(\"chat.newTopic\")}\n </button>\n )}\n <div className=\"h\">{t(\"chat.conversation\")}</div>\n {inGroup(\"main\").map(item)}\n <div className=\"h\">{t(\"chat.topics\")}</div>\n {topics.length === 0 && <div className=\"small muted\" style={{ padding: \"0 10px\" }}>{t(\"chat.noTopics\")}</div>}\n {topics.map(item)}\n {archive.length > 0 && <div className=\"h\">{t(\"chat.archive\")}</div>}\n {archive.map(item)}\n </nav>\n {/* over the messages: a tap beside the list closes it */}\n {open && <button type=\"button\" className=\"nb-scrim\" aria-label={t(\"close\")} onClick={onClose} />}\n {creating && onCreate && <NewTopicModal onClose={() => setCreating(false)} onCreate={onCreate} />}\n </>\n );\n}\n\n/** The place of a chat: the list of conversations, the conversation and what the\n * product puts beside them. `narrow` is for a side panel: the list lies over the\n * messages as on a phone, whatever the width of the window. */\nexport function ChatLayout({ narrow, children }: { narrow?: boolean; children: ReactNode }) {\n return <div className={`nb-app${narrow ? \" narrow\" : \"\"}`}>{children}</div>;\n}\n\n/** The dialog of a new topic: one field, Enter creates. */\nexport function NewTopicModal({ onClose, onCreate }: { onClose: () => void; onCreate: (title: string) => Promise<void> }) {\n const t = useKitT();\n const [title, setTitle] = useState(\"\");\n const [pending, setPending] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const create = async () => {\n if (!title.trim() || pending) return;\n setPending(true);\n setError(null);\n try {\n await onCreate(title.trim());\n onClose();\n } catch (e) {\n setError(e instanceof Error ? e.message : String(e));\n setPending(false);\n }\n };\n return (\n <Modal title={t(\"chat.newTopic\")} onClose={onClose} footer={<>\n <button className=\"btn ghost\" onClick={onClose}>{t(\"cancel\")}</button>\n <button className=\"btn primary\" disabled={!title.trim() || pending} onClick={create}>{t(\"create\")}</button>\n </>}>\n <div className=\"field\">\n <label htmlFor=\"topic-title\">{t(\"chat.topicTitle\")}</label>\n <input id=\"topic-title\" className=\"inp\" value={title} maxLength={120} onChange={(e) => setTitle(e.target.value)}\n onKeyDown={(e) => e.key === \"Enter\" && create()} />\n <div className=\"hint\">{t(\"chat.topicHint\")}</div>\n </div>\n {error && <div className=\"err-text\">{error}</div>}\n </Modal>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { ButtonHTMLAttributes } from "react";
2
+ type Native = ButtonHTMLAttributes<HTMLButtonElement>;
3
+ /** `button.btn` with its variants. The classes stay a legitimate way to use a
4
+ * button (FTR.NAB.CMN-0005 tech, decision 1); the component is for new code. */
5
+ export declare function Button({ variant, size, className, type, ...rest }: Native & {
6
+ variant?: "primary" | "ghost" | "danger";
7
+ size?: "sm";
8
+ }): import("react").JSX.Element;
9
+ /** `button.iconbtn`: a button with an icon only, so the label is required. */
10
+ export declare function IconButton({ label, fill, on, className, type, ...rest }: Omit<Native, "aria-label"> & {
11
+ label: string;
12
+ fill?: boolean;
13
+ on?: boolean;
14
+ }): import("react").JSX.Element;
15
+ export {};