@veevarts/design-system 2.0.0-alpha.59 → 2.0.0-alpha.60

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/README.md +22 -0
  2. package/dist/assistant.cjs +1 -0
  3. package/dist/assistant.d.ts +10 -0
  4. package/dist/assistant.js +790 -0
  5. package/dist/hasContent-BCRxiry-.js +1200 -0
  6. package/dist/hasContent-JfCtoDIu.cjs +1 -0
  7. package/dist/index.cjs +9 -9
  8. package/dist/index.js +6253 -7432
  9. package/dist/patterns/AssistantActivity/AssistantActivity.d.ts +15 -0
  10. package/dist/patterns/AssistantActivity/formatAssistantDuration.d.ts +10 -0
  11. package/dist/patterns/AssistantActivity/index.d.ts +3 -0
  12. package/dist/patterns/AssistantActivity/styles.d.ts +31 -0
  13. package/dist/patterns/AssistantActivity/types.d.ts +42 -0
  14. package/dist/patterns/AssistantComposer/AssistantComposer.d.ts +15 -0
  15. package/dist/patterns/AssistantComposer/index.d.ts +2 -0
  16. package/dist/patterns/AssistantComposer/styles.d.ts +33 -0
  17. package/dist/patterns/AssistantComposer/types.d.ts +62 -0
  18. package/dist/patterns/AssistantMessage/AssistantMessage.d.ts +17 -0
  19. package/dist/patterns/AssistantMessage/index.d.ts +2 -0
  20. package/dist/patterns/AssistantMessage/styles.d.ts +45 -0
  21. package/dist/patterns/AssistantMessage/types.d.ts +84 -0
  22. package/dist/patterns/AssistantNotice/AssistantNotice.d.ts +18 -0
  23. package/dist/patterns/AssistantNotice/index.d.ts +2 -0
  24. package/dist/patterns/AssistantNotice/styles.d.ts +49 -0
  25. package/dist/patterns/AssistantNotice/types.d.ts +58 -0
  26. package/dist/patterns/ScrollToLatest/ScrollToLatest.d.ts +18 -0
  27. package/dist/patterns/ScrollToLatest/index.d.ts +2 -0
  28. package/dist/patterns/ScrollToLatest/styles.d.ts +11 -0
  29. package/dist/patterns/ScrollToLatest/types.d.ts +36 -0
  30. package/dist/test/backdrop.d.ts +12 -0
  31. package/package.json +21 -2
@@ -0,0 +1,790 @@
1
+ import { jsx as e, jsxs as N } from "react/jsx-runtime";
2
+ import { useId as q, useState as H, useRef as M, useLayoutEffect as Y, useEffect as P, useCallback as G } from "react";
3
+ import { h as L, I as F, a as te, s as le, B as R } from "./hasContent-BCRxiry-.js";
4
+ import { cn as l, Accordion as oe, AccordionItem as ce, Chip as de, Alert as ue, Spinner as fe, Textarea as pe, ScrollShadow as me } from "@heroui/react";
5
+ import "lucide-react";
6
+ const x = {
7
+ base: "flex w-full min-w-0 flex-col gap-1.5",
8
+ baseUser: "items-end",
9
+ baseAssistant: "items-start",
10
+ header: "flex min-w-0 max-w-full flex-wrap items-center gap-x-2 gap-y-0.5",
11
+ mark: "inline-flex size-6 flex-none items-center justify-center rounded-full bg-ai-fill text-ai-accent",
12
+ author: "min-w-0 text-sm font-semibold text-ai-accent [overflow-wrap:anywhere]",
13
+ meta: "min-w-0 text-xs tabular-nums text-default-500 [overflow-wrap:anywhere]",
14
+ body: "min-w-0 text-sm leading-relaxed text-foreground [overflow-wrap:anywhere]",
15
+ bodyUser: "max-w-[85%] rounded-2xl rounded-br-md bg-ai-user-bubble px-4 py-2.5",
16
+ bodyAssistant: "w-full",
17
+ /** A plain string keeps the line breaks the person typed. */
18
+ plain: "whitespace-pre-wrap",
19
+ status: "m-0 flex min-w-0 items-center gap-1.5 text-xs font-medium [overflow-wrap:anywhere]",
20
+ /**
21
+ * The status mark's own 14px box. Without words it is all a sighted reader
22
+ * sees, so it keeps its place before Iconify has loaded the icon.
23
+ */
24
+ statusIcon: "inline-flex size-3.5 flex-none",
25
+ actions: "flex flex-wrap items-center gap-1",
26
+ /** The person's name, for screen readers only. */
27
+ userLabel: "sr-only",
28
+ /** The default status word when `statusLabel` is empty, for screen readers only: the icon shows it. */
29
+ statusFallback: "sr-only"
30
+ }, he = {
31
+ stopped: "text-default-600",
32
+ error: "text-danger-600 dark:text-danger-500"
33
+ }, ge = {
34
+ stopped: "solar:stop-circle-linear",
35
+ error: "solar:danger-circle-linear"
36
+ }, xe = "solar:stars-minimalistic-linear", be = {
37
+ stopped: "Stopped",
38
+ error: "Failed"
39
+ };
40
+ function ae(t) {
41
+ return typeof t == "string" ? t.trim() !== "" : Array.isArray(t) ? t.some(ae) : L(t);
42
+ }
43
+ function we({
44
+ author: t,
45
+ authorLabel: o,
46
+ children: b,
47
+ status: u = "complete",
48
+ statusLabel: f,
49
+ meta: c,
50
+ actions: y,
51
+ icon: p = xe,
52
+ className: v,
53
+ classNames: n = {},
54
+ "data-testid": m = "assistant-message"
55
+ }) {
56
+ const h = q(), r = t === "user", d = u === "complete" ? null : u === "stopped" ? "stopped" : "error", S = L(c) ? /* @__PURE__ */ e("span", { "data-testid": `${m}-meta`, className: l(x.meta, n.meta), children: c }) : null;
57
+ return /* @__PURE__ */ N(
58
+ "article",
59
+ {
60
+ "aria-labelledby": h,
61
+ "data-author": t,
62
+ "data-status": u,
63
+ "data-testid": m,
64
+ className: l(
65
+ x.base,
66
+ r ? x.baseUser : x.baseAssistant,
67
+ v,
68
+ n.base
69
+ ),
70
+ children: [
71
+ r ? /* @__PURE__ */ e("span", { id: h, className: x.userLabel, children: o }) : /* @__PURE__ */ N(
72
+ "header",
73
+ {
74
+ "data-testid": `${m}-header`,
75
+ className: l(x.header, n.header),
76
+ children: [
77
+ p ? /* @__PURE__ */ e(
78
+ "span",
79
+ {
80
+ "aria-hidden": "true",
81
+ "data-testid": `${m}-mark`,
82
+ className: x.mark,
83
+ children: /* @__PURE__ */ e(F, { icon: p, width: 14, height: 14 })
84
+ }
85
+ ) : null,
86
+ /* @__PURE__ */ e("span", { id: h, "data-testid": `${m}-author`, className: x.author, children: o }),
87
+ S
88
+ ]
89
+ }
90
+ ),
91
+ L(b) ? /* @__PURE__ */ e(
92
+ "div",
93
+ {
94
+ "data-testid": `${m}-body`,
95
+ className: l(
96
+ x.body,
97
+ r ? x.bodyUser : x.bodyAssistant,
98
+ typeof b == "string" && x.plain,
99
+ n.body
100
+ ),
101
+ children: b
102
+ }
103
+ ) : null,
104
+ d ? /* @__PURE__ */ N(
105
+ "p",
106
+ {
107
+ "data-testid": `${m}-status`,
108
+ className: l(
109
+ x.status,
110
+ he[d],
111
+ n.status
112
+ ),
113
+ children: [
114
+ /* @__PURE__ */ e(
115
+ "span",
116
+ {
117
+ "aria-hidden": "true",
118
+ "data-testid": `${m}-status-icon`,
119
+ className: x.statusIcon,
120
+ children: /* @__PURE__ */ e(F, { icon: ge[d], width: 14, height: 14 })
121
+ }
122
+ ),
123
+ ae(f) ? /* @__PURE__ */ e("span", { children: f }) : /* @__PURE__ */ e("span", { className: x.statusFallback, children: be[d] })
124
+ ]
125
+ }
126
+ ) : null,
127
+ r ? S : null,
128
+ L(y) ? /* @__PURE__ */ e(
129
+ "div",
130
+ {
131
+ "data-testid": `${m}-actions`,
132
+ className: l(x.actions, n.actions),
133
+ children: y
134
+ }
135
+ ) : null
136
+ ]
137
+ }
138
+ );
139
+ }
140
+ we.displayName = "AssistantMessage";
141
+ const A = {
142
+ base: "w-full px-0",
143
+ item: "shadow-none",
144
+ trigger: "gap-2 py-1.5",
145
+ title: "text-sm font-medium text-default-700",
146
+ indicator: "text-default-500",
147
+ content: "pb-2 pt-0",
148
+ list: "m-0 flex list-none flex-col gap-1.5 p-0",
149
+ row: "flex min-w-0 items-start gap-2 text-sm",
150
+ icon: "mt-0.5 flex-none",
151
+ label: "min-w-0 flex-1 text-foreground [overflow-wrap:anywhere]",
152
+ /**
153
+ * HeroUI's flat danger chip is `text-danger-600 dark:text-danger-500`,
154
+ * which measures 4.25:1 on its own fill in dark. The 700 step clears AA in
155
+ * both themes (HeroUI's dark scale is reversed, so it is a light tint
156
+ * there); the `dark:` repeat is what overrides HeroUI's `dark:` class.
157
+ */
158
+ failed: "flex-none text-danger-700 dark:text-danger-700",
159
+ duration: "mt-px flex-none text-xs tabular-nums text-default-500",
160
+ /** "Done:" before a done row, for screen readers only. */
161
+ stateLabel: "sr-only"
162
+ }, ye = {
163
+ done: { icon: "solar:check-circle-linear", className: "text-success-600" },
164
+ failed: { icon: "solar:close-circle-linear", className: "text-danger-600" }
165
+ };
166
+ function ve(t) {
167
+ if (!Number.isFinite(t) || t < 0) return "";
168
+ if (t < 1e3) return `${Math.floor(t)} ms`;
169
+ if (t < 1e4) return `${(Math.floor(t / 100) / 10).toFixed(1)} s`;
170
+ const o = Math.floor(t / 1e3);
171
+ return o < 60 ? `${o} s` : `${Math.floor(o / 60)} min ${String(o % 60).padStart(2, "0")} s`;
172
+ }
173
+ const J = "activity", Ne = { done: "Done", failed: "Failed" };
174
+ function Se({
175
+ items: t,
176
+ title: o,
177
+ titleText: b,
178
+ isExpanded: u,
179
+ defaultExpanded: f = !0,
180
+ onExpandedChange: c,
181
+ stateLabels: y,
182
+ formatDuration: p = ve,
183
+ className: v,
184
+ "data-testid": n = "assistant-activity"
185
+ }) {
186
+ const [m, h] = H(f), r = te(), d = u ?? m, S = { ...Ne, ...y };
187
+ return t.length === 0 ? null : /* @__PURE__ */ e(
188
+ oe,
189
+ {
190
+ "data-testid": n,
191
+ disableAnimation: r,
192
+ selectedKeys: d ? /* @__PURE__ */ new Set([J]) : /* @__PURE__ */ new Set(),
193
+ onSelectionChange: (a) => {
194
+ const $ = a === "all" || a.has(J);
195
+ u === void 0 && h($), c?.($);
196
+ },
197
+ className: l(A.base, v),
198
+ children: /* @__PURE__ */ e(
199
+ ce,
200
+ {
201
+ "data-testid": `${n}-group`,
202
+ title: o,
203
+ textValue: typeof o == "string" ? o : b,
204
+ classNames: {
205
+ base: A.item,
206
+ trigger: A.trigger,
207
+ title: A.title,
208
+ indicator: A.indicator,
209
+ content: A.content
210
+ },
211
+ children: /* @__PURE__ */ e("ol", { "data-testid": `${n}-list`, className: A.list, children: t.map((a) => {
212
+ const $ = ye[a.state], D = `${n}-item-${a.id}`;
213
+ return /* @__PURE__ */ N(
214
+ "li",
215
+ {
216
+ "data-testid": D,
217
+ "data-state": a.state,
218
+ className: A.row,
219
+ children: [
220
+ /* @__PURE__ */ e(
221
+ F,
222
+ {
223
+ icon: $.icon,
224
+ width: 16,
225
+ height: 16,
226
+ "aria-hidden": "true",
227
+ className: l(A.icon, $.className)
228
+ }
229
+ ),
230
+ /* @__PURE__ */ N("span", { className: A.label, children: [
231
+ a.state === "done" ? /* @__PURE__ */ N("span", { className: A.stateLabel, children: [
232
+ S.done,
233
+ ": "
234
+ ] }) : null,
235
+ a.label
236
+ ] }),
237
+ a.state === "failed" ? /* @__PURE__ */ e(
238
+ de,
239
+ {
240
+ size: "sm",
241
+ variant: "flat",
242
+ color: "danger",
243
+ "data-testid": `${D}-failed`,
244
+ className: A.failed,
245
+ children: S.failed
246
+ }
247
+ ) : null,
248
+ a.durationMs !== void 0 ? /* @__PURE__ */ e(
249
+ "span",
250
+ {
251
+ "data-testid": `${D}-duration`,
252
+ className: A.duration,
253
+ children: p(a.durationMs)
254
+ }
255
+ ) : null
256
+ ]
257
+ },
258
+ a.id
259
+ );
260
+ }) })
261
+ },
262
+ J
263
+ )
264
+ }
265
+ );
266
+ }
267
+ Se.displayName = "AssistantActivity";
268
+ const V = "dark:bg-default-100", Ae = {
269
+ thinking: {
270
+ color: "default",
271
+ base: "bg-ai-fill dark:bg-ai-fill",
272
+ title: "text-ai-accent",
273
+ description: "text-default-600",
274
+ icon: ""
275
+ },
276
+ info: {
277
+ color: "default",
278
+ base: "bg-ai-fill dark:bg-ai-fill",
279
+ title: "text-ai-accent",
280
+ description: "text-default-600",
281
+ icon: "solar:info-circle-linear"
282
+ },
283
+ empty: {
284
+ color: "default",
285
+ base: V,
286
+ title: "text-foreground",
287
+ description: "text-default-600",
288
+ icon: "solar:chat-round-line-linear"
289
+ },
290
+ error: {
291
+ color: "danger",
292
+ base: "",
293
+ title: "text-danger-700",
294
+ description: "text-danger-700",
295
+ icon: "solar:danger-triangle-linear"
296
+ },
297
+ caution: {
298
+ color: "warning",
299
+ base: "",
300
+ title: "text-warning-700",
301
+ description: "text-warning-700",
302
+ icon: "solar:hourglass-line-linear"
303
+ },
304
+ offline: {
305
+ color: "default",
306
+ base: V,
307
+ title: "text-foreground",
308
+ description: "text-default-600",
309
+ icon: "solar:cloud-cross-linear"
310
+ },
311
+ blocked: {
312
+ color: "default",
313
+ base: V,
314
+ title: "text-foreground",
315
+ description: "text-default-600",
316
+ icon: "solar:lock-keyhole-minimalistic-linear"
317
+ }
318
+ }, w = {
319
+ /** Alert centres a body with no title prop; the copy here is children, so pin it to the top-left. */
320
+ base: "items-start gap-x-3 px-4 py-3",
321
+ mainWrapper: "ms-0 min-h-0 min-w-0 items-start justify-start gap-0.5",
322
+ icon: "mt-0.5 inline-flex size-5 flex-none items-center justify-center",
323
+ /**
324
+ * The live region: title and description only. The clock, the action and
325
+ * the details sit outside it, so a ticking clock or opening "Details" on
326
+ * an error does not re-announce anything.
327
+ */
328
+ live: "col-span-full row-start-1 grid min-w-0 grid-cols-subgrid gap-y-0.5",
329
+ /**
330
+ * Title, description and clock. The live region spans every column as a
331
+ * subgrid (title in the first, description across all), and the clock
332
+ * sits outside it, so a ticking clock never changes the region. Without a
333
+ * clock there is one column, and the title has the full width.
334
+ */
335
+ text: "grid w-full min-w-0 grid-cols-1 items-baseline gap-x-2",
336
+ /**
337
+ * With a clock, two columns: the title, then the clock on the title's
338
+ * baseline, in the second column of the first row. Both the region and the
339
+ * clock have an explicit row, or auto-placement would move the region below
340
+ * the clock. A title too long for its line wraps beside the clock.
341
+ */
342
+ textWithClock: "grid-cols-[auto_1fr]",
343
+ title: "col-start-1 m-0 min-w-0 justify-self-start text-sm font-medium [overflow-wrap:anywhere]",
344
+ elapsed: "col-start-2 row-start-1 justify-self-start whitespace-nowrap text-sm tabular-nums",
345
+ description: "col-span-full m-0 min-w-0 text-sm [overflow-wrap:anywhere]",
346
+ action: "mt-2 flex flex-wrap items-center gap-2",
347
+ detailsToggle: "-ms-1.5 h-7 min-w-0 gap-1 px-1.5 text-xs font-medium text-current",
348
+ detailsWrapper: "w-full min-w-0",
349
+ detailsChevron: `transition-transform ${le}`,
350
+ detailsChevronOpen: "rotate-180",
351
+ details: "mt-1 max-h-48 overflow-auto whitespace-pre-wrap rounded-md bg-content1 p-2 font-mono text-xs text-foreground [overflow-wrap:anywhere]"
352
+ }, $e = {
353
+ thinking: "status",
354
+ info: "status",
355
+ empty: "status",
356
+ error: "alert",
357
+ caution: "status",
358
+ offline: "status",
359
+ blocked: "status"
360
+ };
361
+ function Ce({
362
+ kind: t,
363
+ title: o,
364
+ description: b,
365
+ elapsed: u,
366
+ action: f,
367
+ details: c,
368
+ detailsLabel: y = "Details",
369
+ icon: p,
370
+ role: v = $e[t],
371
+ ariaLive: n = v === "alert" ? "assertive" : "polite",
372
+ className: m,
373
+ classNames: h = {},
374
+ "data-testid": r = "assistant-notice"
375
+ }) {
376
+ const d = Ae[t], S = u != null && u !== !1, a = p === void 0 ? d.icon : p, $ = t === "thinking" && p === void 0 ? /* @__PURE__ */ e(fe, { size: "sm", color: "current" }) : a ? /* @__PURE__ */ e(F, { icon: a, width: 20, height: 20 }) : null;
377
+ return /* @__PURE__ */ N(
378
+ ue,
379
+ {
380
+ role: "none",
381
+ "data-kind": t,
382
+ "data-testid": r,
383
+ color: d.color,
384
+ variant: "flat",
385
+ hideIcon: !0,
386
+ startContent: $ ? /* @__PURE__ */ e(
387
+ "span",
388
+ {
389
+ "aria-hidden": "true",
390
+ "data-testid": `${r}-icon`,
391
+ className: l(w.icon, d.title),
392
+ children: $
393
+ }
394
+ ) : void 0,
395
+ classNames: {
396
+ base: l(w.base, d.base, m, h.base),
397
+ mainWrapper: w.mainWrapper
398
+ },
399
+ children: [
400
+ /* @__PURE__ */ N("div", { className: l(w.text, S && w.textWithClock), children: [
401
+ /* @__PURE__ */ N(
402
+ "div",
403
+ {
404
+ role: v,
405
+ "aria-live": n,
406
+ "aria-atomic": "true",
407
+ "data-testid": `${r}-live`,
408
+ className: w.live,
409
+ children: [
410
+ /* @__PURE__ */ e(
411
+ "p",
412
+ {
413
+ "data-testid": `${r}-title`,
414
+ className: l(w.title, d.title, h.title),
415
+ children: o
416
+ }
417
+ ),
418
+ b != null && b !== !1 ? /* @__PURE__ */ e(
419
+ "p",
420
+ {
421
+ "data-testid": `${r}-description`,
422
+ className: l(w.description, d.description, h.description),
423
+ children: b
424
+ }
425
+ ) : null
426
+ ]
427
+ }
428
+ ),
429
+ S ? /* @__PURE__ */ e(
430
+ "span",
431
+ {
432
+ "aria-hidden": "true",
433
+ "data-testid": `${r}-elapsed`,
434
+ className: l(w.elapsed, d.title),
435
+ children: u
436
+ }
437
+ ) : null
438
+ ] }),
439
+ f != null && f !== !1 ? /* @__PURE__ */ e(
440
+ "div",
441
+ {
442
+ "data-testid": `${r}-action`,
443
+ className: l(w.action, h.action),
444
+ children: f
445
+ }
446
+ ) : null,
447
+ c != null && c !== !1 ? /* @__PURE__ */ e(
448
+ ke,
449
+ {
450
+ label: y,
451
+ toneClass: d.description,
452
+ className: h.details,
453
+ dataTestId: r,
454
+ children: c
455
+ }
456
+ ) : null
457
+ ]
458
+ }
459
+ );
460
+ }
461
+ function ke({
462
+ label: t,
463
+ toneClass: o,
464
+ className: b,
465
+ dataTestId: u,
466
+ children: f
467
+ }) {
468
+ const [c, y] = H(!1), p = q();
469
+ return /* @__PURE__ */ N("div", { className: w.detailsWrapper, children: [
470
+ /* @__PURE__ */ e(
471
+ R,
472
+ {
473
+ size: "sm",
474
+ variant: "light",
475
+ color: "default",
476
+ radius: "sm",
477
+ "aria-expanded": c,
478
+ "aria-controls": p,
479
+ onPress: () => y((v) => !v),
480
+ testId: `${u}-details-toggle`,
481
+ className: l(w.detailsToggle, o),
482
+ endContent: /* @__PURE__ */ e(
483
+ F,
484
+ {
485
+ icon: "solar:alt-arrow-down-linear",
486
+ width: 14,
487
+ height: 14,
488
+ "aria-hidden": "true",
489
+ className: l(
490
+ w.detailsChevron,
491
+ c && w.detailsChevronOpen
492
+ )
493
+ }
494
+ ),
495
+ children: t
496
+ }
497
+ ),
498
+ /* @__PURE__ */ e(
499
+ "div",
500
+ {
501
+ id: p,
502
+ hidden: !c,
503
+ "data-testid": `${u}-details`,
504
+ className: l(w.details, b),
505
+ children: f
506
+ }
507
+ )
508
+ ] });
509
+ }
510
+ Ce.displayName = "AssistantNotice";
511
+ const k = {
512
+ base: "flex w-full min-w-0 flex-col gap-2",
513
+ suggestions: "flex flex-wrap gap-2",
514
+ /**
515
+ * Pill tones are set here rather than taken from HeroUI's flat variant,
516
+ * whose text tone differs between HeroUI versions and read dim on a dark
517
+ * card in an app on HeroUI 2.7. Measured in both themes in the stories.
518
+ */
519
+ suggestion: "h-auto min-h-8 max-w-full whitespace-normal bg-default-100 py-1.5 text-left text-foreground data-[hover=true]:bg-default-200",
520
+ row: "flex min-w-0 items-end gap-2",
521
+ field: "min-w-0 flex-1",
522
+ /**
523
+ * The focus border is `ai-focus` with the pointer over the field too:
524
+ * HeroUI's bordered variant has its own focused-and-hovered rule
525
+ * (`border-default-foreground`, black in light and white in dark), more
526
+ * specific than the focus one, so it is replaced here by name.
527
+ */
528
+ inputWrapper: "border-default-200 bg-content1 data-[hover=true]:border-default-300 group-data-[focus=true]:border-ai-focus group-data-[focus=true]:data-[hover=true]:border-ai-focus",
529
+ input: "text-sm text-foreground placeholder:text-default-500",
530
+ /**
531
+ * The hint sits under the whole row, not inside the field's column: inside
532
+ * it, a long hint pushed the bottom-aligned button down beside the hint.
533
+ * Our own element, so its tone is ours too: `default-500` clears 4.5:1 in
534
+ * both themes (HeroUI's description slot is `foreground-400`, 2.56:1).
535
+ */
536
+ helper: "m-0 flex w-full justify-between gap-2 text-xs text-default-500",
537
+ count: "ms-auto flex-none tabular-nums",
538
+ button: "flex-none"
539
+ };
540
+ function Ee({
541
+ value: t,
542
+ onValueChange: o,
543
+ onSubmit: b,
544
+ onStop: u,
545
+ isRunning: f = !1,
546
+ isStopDisabled: c = !1,
547
+ isDisabled: y = !1,
548
+ label: p,
549
+ placeholder: v,
550
+ description: n,
551
+ sendLabel: m = "Send",
552
+ stopLabel: h = "Stop",
553
+ suggestions: r,
554
+ suggestionsLabel: d = "Suggestions",
555
+ onSuggestionSelect: S,
556
+ maxLength: a,
557
+ minRows: $ = 2,
558
+ maxRows: D = 8,
559
+ className: T,
560
+ "data-testid": E = "assistant-composer"
561
+ }) {
562
+ const C = M(null), _ = q(), j = t.trim(), B = a === void 0 || t.length <= a, W = !y && !f && j.length > 0 && B, s = f && u !== void 0, g = () => {
563
+ W && b(j);
564
+ }, U = () => C.current?.focus(), se = (i) => {
565
+ i.target === C.current && (i.key !== "Enter" || i.shiftKey || i.nativeEvent.isComposing || i.keyCode === 229 || (i.preventDefault(), g()));
566
+ }, ne = (i) => {
567
+ i.preventDefault(), g(), U();
568
+ }, z = M(!1), I = M(s);
569
+ Y(() => {
570
+ I.current && !s && z.current && (z.current = !1, C.current?.focus()), I.current = s;
571
+ }, [s]), Y(() => {
572
+ c && z.current && (z.current = !1, C.current?.focus());
573
+ }, [c]);
574
+ const re = () => {
575
+ U(), u?.();
576
+ }, ie = (i) => {
577
+ const X = i.prompt ?? i.label;
578
+ o(a === void 0 ? X : X.slice(0, a)), C.current?.focus(), S?.(i);
579
+ }, K = a !== void 0 ? `${t.length}/${a}` : null, Q = L(n) || K ? /* @__PURE__ */ N("p", { id: _, "data-testid": `${E}-helper`, className: k.helper, children: [
580
+ L(n) ? /* @__PURE__ */ e("span", { children: n }) : null,
581
+ K ? /* @__PURE__ */ e("span", { "data-testid": `${E}-count`, className: k.count, children: K }) : null
582
+ ] }) : null;
583
+ return /* @__PURE__ */ N(
584
+ "form",
585
+ {
586
+ noValidate: !0,
587
+ "data-testid": E,
588
+ "data-running": f || void 0,
589
+ onSubmit: ne,
590
+ onKeyDown: se,
591
+ className: l(k.base, T),
592
+ children: [
593
+ r && r.length > 0 ? /* @__PURE__ */ e(
594
+ "div",
595
+ {
596
+ role: "group",
597
+ "aria-label": d,
598
+ "data-testid": `${E}-suggestions`,
599
+ className: k.suggestions,
600
+ children: r.map((i) => /* @__PURE__ */ e(
601
+ R,
602
+ {
603
+ type: "button",
604
+ size: "sm",
605
+ variant: "flat",
606
+ color: "default",
607
+ isDisabled: y,
608
+ onPress: () => ie(i),
609
+ testId: `${E}-suggestion-${i.key}`,
610
+ className: k.suggestion,
611
+ children: i.label
612
+ },
613
+ i.key
614
+ ))
615
+ }
616
+ ) : null,
617
+ /* @__PURE__ */ N(
618
+ "div",
619
+ {
620
+ className: k.row,
621
+ onMouseDown: (i) => {
622
+ i.target === i.currentTarget && i.preventDefault();
623
+ },
624
+ children: [
625
+ /* @__PURE__ */ e(
626
+ pe,
627
+ {
628
+ ref: C,
629
+ "aria-label": p,
630
+ placeholder: v,
631
+ value: t,
632
+ onValueChange: o,
633
+ isDisabled: y,
634
+ maxLength: a,
635
+ minRows: $,
636
+ maxRows: D,
637
+ variant: "bordered",
638
+ "aria-describedby": Q ? _ : void 0,
639
+ "data-testid": `${E}-field`,
640
+ className: k.field,
641
+ classNames: {
642
+ inputWrapper: k.inputWrapper,
643
+ input: k.input
644
+ }
645
+ }
646
+ ),
647
+ s ? /* @__PURE__ */ e(
648
+ R,
649
+ {
650
+ type: "button",
651
+ isIconOnly: !0,
652
+ color: "default",
653
+ variant: "flat",
654
+ "aria-label": h,
655
+ isDisabled: c,
656
+ onPress: re,
657
+ onFocus: () => {
658
+ z.current = !0;
659
+ },
660
+ onBlur: (i) => {
661
+ i.target.disabled || (z.current = !1);
662
+ },
663
+ testId: `${E}-stop`,
664
+ className: k.button,
665
+ children: /* @__PURE__ */ e(F, { icon: "solar:stop-bold", width: 18, height: 18, "aria-hidden": "true" })
666
+ },
667
+ "stop"
668
+ ) : /* @__PURE__ */ e(
669
+ R,
670
+ {
671
+ type: "submit",
672
+ isIconOnly: !0,
673
+ color: "primary",
674
+ "aria-label": m,
675
+ isDisabled: !W,
676
+ testId: `${E}-send`,
677
+ className: k.button,
678
+ children: /* @__PURE__ */ e(F, { icon: "solar:arrow-up-linear", width: 18, height: 18, "aria-hidden": "true" })
679
+ },
680
+ "send"
681
+ )
682
+ ]
683
+ }
684
+ ),
685
+ Q
686
+ ]
687
+ }
688
+ );
689
+ }
690
+ Ee.displayName = "AssistantComposer";
691
+ const O = {
692
+ base: "relative flex min-h-0 w-full flex-col",
693
+ scroller: "min-h-0 flex-1 overflow-y-auto overscroll-contain rounded-[inherit] outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ai-focus",
694
+ content: "min-w-0",
695
+ jumpBar: "pointer-events-none absolute inset-x-0 bottom-3 flex justify-center",
696
+ jump: "pointer-events-auto border border-divider bg-content1 text-foreground shadow-medium"
697
+ }, Z = (t, o) => t.scrollHeight - t.scrollTop - t.clientHeight <= o, ee = (t) => t.clientHeight > 0;
698
+ function Me({
699
+ children: t,
700
+ label: o,
701
+ followKey: b,
702
+ jumpLabel: u = "Jump to newest",
703
+ onFollowChange: f,
704
+ threshold: c = 32,
705
+ className: y,
706
+ classNames: p = {},
707
+ "data-testid": v = "scroll-to-latest"
708
+ }) {
709
+ const n = M(null), m = M(null), h = M(!0), r = M(0), d = M(f), S = M(c), [a, $] = H(!0), [D, T] = H(!1), E = te();
710
+ P(() => {
711
+ d.current = f;
712
+ }, [f]), P(() => {
713
+ S.current = c;
714
+ }, [c]);
715
+ const C = G((s) => {
716
+ h.current !== s && (h.current = s, $(s), d.current?.(s));
717
+ }, []), _ = G(() => {
718
+ const s = n.current;
719
+ s && (T(s.scrollHeight > s.clientHeight), ee(s) && Z(s, S.current) && C(!0));
720
+ }, [C]), j = G((s) => {
721
+ const g = n.current;
722
+ g && (typeof g.scrollTo == "function" ? g.scrollTo({ top: g.scrollHeight, behavior: s }) : g.scrollTop = g.scrollHeight, r.current = g.scrollTop);
723
+ }, []);
724
+ Y(() => {
725
+ h.current && j("auto"), _();
726
+ }, [b, j, _]), P(() => {
727
+ const s = m.current, g = n.current;
728
+ if (!s || !g || typeof ResizeObserver > "u") return;
729
+ const U = new ResizeObserver(() => {
730
+ h.current && j("auto"), _();
731
+ });
732
+ return U.observe(s), U.observe(g), () => U.disconnect();
733
+ }, [j, _]);
734
+ const B = () => {
735
+ const s = n.current;
736
+ if (!s || !ee(s)) return;
737
+ const g = s.scrollTop;
738
+ Z(s, c) ? C(!0) : g < r.current - 1 && C(!1), r.current = g, _();
739
+ }, W = () => {
740
+ C(!0), j(E ? "auto" : "smooth"), n.current?.focus({ preventScroll: !0 });
741
+ };
742
+ return /* @__PURE__ */ N(
743
+ "div",
744
+ {
745
+ "data-testid": v,
746
+ "data-following": a,
747
+ className: l(O.base, y, p.base),
748
+ children: [
749
+ /* @__PURE__ */ e(
750
+ me,
751
+ {
752
+ ref: n,
753
+ role: "region",
754
+ "aria-label": o,
755
+ tabIndex: 0,
756
+ size: 24,
757
+ onScroll: B,
758
+ "data-testid": `${v}-scroller`,
759
+ className: l(O.scroller, p.scroller),
760
+ children: /* @__PURE__ */ e("div", { ref: m, className: l(O.content, p.content), children: t })
761
+ }
762
+ ),
763
+ !a && D ? /* @__PURE__ */ e("div", { className: O.jumpBar, children: /* @__PURE__ */ e(
764
+ R,
765
+ {
766
+ type: "button",
767
+ size: "sm",
768
+ radius: "full",
769
+ color: "default",
770
+ variant: "solid",
771
+ onPress: W,
772
+ testId: `${v}-jump`,
773
+ startContent: /* @__PURE__ */ e(F, { icon: "solar:arrow-down-linear", width: 16, height: 16, "aria-hidden": "true" }),
774
+ className: l(O.jump, p.jump),
775
+ children: u
776
+ }
777
+ ) }) : null
778
+ ]
779
+ }
780
+ );
781
+ }
782
+ Me.displayName = "ScrollToLatest";
783
+ export {
784
+ Se as AssistantActivity,
785
+ Ee as AssistantComposer,
786
+ we as AssistantMessage,
787
+ Ce as AssistantNotice,
788
+ Me as ScrollToLatest,
789
+ ve as formatAssistantDuration
790
+ };