@epicbagel/saas-kit 1.7.0 → 1.11.0

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 (103) hide show
  1. package/README.md +72 -1
  2. package/THIRD_PARTY_NOTICES.md +14 -0
  3. package/dist/chunk-2BSFYU22.cjs +71 -0
  4. package/dist/chunk-5OF6D3GH.js +158 -0
  5. package/dist/chunk-7QTFYEPE.cjs +153 -0
  6. package/dist/{chunk-GTVSRRE3.cjs → chunk-BGCNGYPL.cjs} +2 -2
  7. package/dist/{chunk-QTWJQQDH.cjs → chunk-FBVZRRA4.cjs} +6 -6
  8. package/dist/chunk-GJ7S3L6R.js +71 -0
  9. package/dist/chunk-HLAHOVEI.js +412 -0
  10. package/dist/{chunk-F3B4M6DU.js → chunk-HTPPNW74.js} +1 -1
  11. package/dist/chunk-KQBXAQAY.cjs +221 -0
  12. package/dist/{chunk-JN6JOSZG.js → chunk-LQPJGZIE.js} +7 -7
  13. package/dist/chunk-NKWHDI4C.cjs +158 -0
  14. package/dist/chunk-T3XMHWYV.js +221 -0
  15. package/dist/chunk-UOVA4YKW.js +153 -0
  16. package/dist/chunk-ZZ7ICQR2.cjs +412 -0
  17. package/dist/hooks/use-agent-audio-visualizer-bar.cjs +8 -0
  18. package/dist/hooks/use-agent-audio-visualizer-bar.d.cts +4 -0
  19. package/dist/hooks/use-agent-audio-visualizer-bar.d.ts +4 -0
  20. package/dist/hooks/use-agent-audio-visualizer-bar.js +8 -0
  21. package/dist/hooks/use-dictation.cjs +10 -0
  22. package/dist/hooks/use-dictation.d.cts +61 -0
  23. package/dist/hooks/use-dictation.d.ts +61 -0
  24. package/dist/hooks/use-dictation.js +10 -0
  25. package/dist/primitives/activity-feed.cjs +3 -3
  26. package/dist/primitives/activity-feed.js +4 -4
  27. package/dist/primitives/agent-audio-visualizer-bar.cjs +16 -0
  28. package/dist/primitives/agent-audio-visualizer-bar.d.cts +75 -0
  29. package/dist/primitives/agent-audio-visualizer-bar.d.ts +75 -0
  30. package/dist/primitives/agent-audio-visualizer-bar.js +16 -0
  31. package/dist/primitives/alert.d.cts +1 -1
  32. package/dist/primitives/alert.d.ts +1 -1
  33. package/dist/primitives/archive-confirmation-dialog.cjs +2 -2
  34. package/dist/primitives/archive-confirmation-dialog.js +3 -3
  35. package/dist/primitives/attachment.d.cts +1 -1
  36. package/dist/primitives/attachment.d.ts +1 -1
  37. package/dist/primitives/badge.d.cts +1 -1
  38. package/dist/primitives/badge.d.ts +1 -1
  39. package/dist/primitives/board-view.cjs +6 -6
  40. package/dist/primitives/board-view.js +5 -5
  41. package/dist/primitives/bubble.d.cts +1 -1
  42. package/dist/primitives/bubble.d.ts +1 -1
  43. package/dist/primitives/button.d.cts +2 -2
  44. package/dist/primitives/button.d.ts +2 -2
  45. package/dist/primitives/chat.cjs +59 -28
  46. package/dist/primitives/chat.d.cts +8 -3
  47. package/dist/primitives/chat.d.ts +8 -3
  48. package/dist/primitives/chat.js +56 -25
  49. package/dist/primitives/code-block.cjs +4 -4
  50. package/dist/primitives/code-block.js +3 -3
  51. package/dist/primitives/connection.cjs +6 -6
  52. package/dist/primitives/connection.js +7 -7
  53. package/dist/primitives/copy-button.cjs +3 -3
  54. package/dist/primitives/copy-button.js +2 -2
  55. package/dist/primitives/dictation-provider.cjs +8 -0
  56. package/dist/primitives/dictation-provider.d.cts +2 -0
  57. package/dist/primitives/dictation-provider.d.ts +2 -0
  58. package/dist/primitives/dictation-provider.js +8 -0
  59. package/dist/primitives/editable-list.cjs +1 -1
  60. package/dist/primitives/editable-list.js +1 -1
  61. package/dist/primitives/file-dropzone.cjs +3 -3
  62. package/dist/primitives/file-dropzone.js +2 -2
  63. package/dist/primitives/file-preview.cjs +6 -6
  64. package/dist/primitives/file-preview.js +5 -5
  65. package/dist/primitives/filter-bar.cjs +4 -4
  66. package/dist/primitives/filter-bar.js +3 -3
  67. package/dist/primitives/input-group.d.cts +1 -1
  68. package/dist/primitives/input-group.d.ts +1 -1
  69. package/dist/primitives/item.d.cts +2 -2
  70. package/dist/primitives/item.d.ts +2 -2
  71. package/dist/primitives/resource-list.cjs +6 -6
  72. package/dist/primitives/resource-list.js +5 -5
  73. package/dist/primitives/section-header.d.cts +1 -1
  74. package/dist/primitives/section-header.d.ts +1 -1
  75. package/dist/primitives/section.cjs +2 -2
  76. package/dist/primitives/section.js +3 -3
  77. package/dist/primitives/sheet.d.cts +1 -1
  78. package/dist/primitives/sheet.d.ts +1 -1
  79. package/dist/primitives/switch-field.cjs +2 -2
  80. package/dist/primitives/switch-field.js +3 -3
  81. package/dist/primitives/theme-selector.cjs +3 -3
  82. package/dist/primitives/theme-selector.js +4 -4
  83. package/dist/primitives/toggle-group.d.cts +2 -2
  84. package/dist/primitives/toggle-group.d.ts +2 -2
  85. package/dist/primitives/toggle.d.cts +2 -2
  86. package/dist/primitives/toggle.d.ts +2 -2
  87. package/dist/primitives/voice-dictation-button.cjs +5 -2
  88. package/dist/primitives/voice-dictation-button.d.cts +5 -9
  89. package/dist/primitives/voice-dictation-button.d.ts +5 -9
  90. package/dist/primitives/voice-dictation-button.js +4 -1
  91. package/dist/primitives/voice-session-controls.cjs +12 -0
  92. package/dist/primitives/voice-session-controls.d.cts +31 -0
  93. package/dist/primitives/voice-session-controls.d.ts +31 -0
  94. package/dist/primitives/voice-session-controls.js +12 -0
  95. package/package.json +51 -1
  96. package/dist/chunk-LKPM6DQP.cjs +0 -244
  97. package/dist/chunk-TI57GAQP.js +0 -244
  98. package/dist/{chunk-HREEZUKL.js → chunk-DILYV4FI.js} +3 -3
  99. package/dist/{chunk-MU4F3DSW.cjs → chunk-FARCLWLU.cjs} +2 -2
  100. package/dist/{chunk-CRTH5GJ5.cjs → chunk-MW67PHAQ.cjs} +3 -3
  101. package/dist/{chunk-KNKV25WS.js → chunk-UFFHGKI7.js} +3 -3
  102. package/dist/{chunk-HBRVOGLA.js → chunk-WHDHUYS6.js} +3 -3
  103. package/dist/{chunk-Z3JJSNR5.cjs → chunk-ZLEM2SAU.cjs} +2 -2
@@ -2,12 +2,15 @@
2
2
  "use client";
3
3
 
4
4
 
5
+ var _chunk7QTFYEPEcjs = require('../chunk-7QTFYEPE.cjs');
6
+
7
+
5
8
 
6
9
 
7
10
  var _chunk2BTDBZYNcjs = require('../chunk-2BTDBZYN.cjs');
8
11
 
9
12
 
10
- var _chunkLKPM6DQPcjs = require('../chunk-LKPM6DQP.cjs');
13
+ var _chunkKQBXAQAYcjs = require('../chunk-KQBXAQAY.cjs');
11
14
 
12
15
 
13
16
 
@@ -15,21 +18,21 @@ var _chunkM4V7OJNFcjs = require('../chunk-M4V7OJNF.cjs');
15
18
 
16
19
 
17
20
 
21
+ var _chunkB765DSRGcjs = require('../chunk-B765DSRG.cjs');
18
22
 
19
23
 
20
24
 
21
25
 
22
- var _chunk5VMKDVB6cjs = require('../chunk-5VMKDVB6.cjs');
23
26
 
24
27
 
25
28
 
29
+ var _chunk5VMKDVB6cjs = require('../chunk-5VMKDVB6.cjs');
26
30
 
27
31
 
28
- var _chunkNWDPH2Z7cjs = require('../chunk-NWDPH2Z7.cjs');
29
32
 
30
33
 
31
34
 
32
- var _chunkB765DSRGcjs = require('../chunk-B765DSRG.cjs');
35
+ var _chunkNWDPH2Z7cjs = require('../chunk-NWDPH2Z7.cjs');
33
36
 
34
37
 
35
38
 
@@ -39,7 +42,7 @@ require('../chunk-2HV2KKOE.cjs');
39
42
 
40
43
 
41
44
 
42
- var _chunkZ3JJSNR5cjs = require('../chunk-Z3JJSNR5.cjs');
45
+ var _chunkZLEM2SAUcjs = require('../chunk-ZLEM2SAU.cjs');
43
46
 
44
47
 
45
48
  var _chunkKENBU3NVcjs = require('../chunk-KENBU3NV.cjs');
@@ -50,6 +53,7 @@ require('../chunk-ELPV44S6.cjs');
50
53
 
51
54
 
52
55
  var _chunkZAITUDYDcjs = require('../chunk-ZAITUDYD.cjs');
56
+ require('../chunk-U2NES7VR.cjs');
53
57
 
54
58
 
55
59
 
@@ -67,17 +71,22 @@ require('../chunk-W5HPHEE7.cjs');
67
71
 
68
72
 
69
73
  var _chunkFYRQFEU4cjs = require('../chunk-FYRQFEU4.cjs');
70
- require('../chunk-U2NES7VR.cjs');
71
74
 
72
75
 
73
76
  var _chunk2KFZQJH5cjs = require('../chunk-2KFZQJH5.cjs');
74
77
  require('../chunk-PQUSJEXL.cjs');
78
+ require('../chunk-NKWHDI4C.cjs');
75
79
 
76
80
 
77
81
  var _chunkJDEXZGIYcjs = require('../chunk-JDEXZGIY.cjs');
78
82
 
79
83
 
84
+ var _chunkKWLSBTB2cjs = require('../chunk-KWLSBTB2.cjs');
85
+ require('../chunk-2BSFYU22.cjs');
86
+
87
+
80
88
  var _chunk4LXN6GLZcjs = require('../chunk-4LXN6GLZ.cjs');
89
+ require('../chunk-ZZ7ICQR2.cjs');
81
90
 
82
91
 
83
92
  var _chunkR35FT53Gcjs = require('../chunk-R35FT53G.cjs');
@@ -85,9 +94,6 @@ var _chunkR35FT53Gcjs = require('../chunk-R35FT53G.cjs');
85
94
 
86
95
  var _chunkH2UFRLLNcjs = require('../chunk-H2UFRLLN.cjs');
87
96
 
88
-
89
- var _chunkKWLSBTB2cjs = require('../chunk-KWLSBTB2.cjs');
90
-
91
97
  // src/primitives/chat.tsx
92
98
 
93
99
 
@@ -372,6 +378,7 @@ function ChatInput({
372
378
  size = "md",
373
379
  uploadingLabel,
374
380
  voice = true,
381
+ voiceSession,
375
382
  voiceTitle,
376
383
  voiceLang,
377
384
  submitLabel,
@@ -397,6 +404,7 @@ function ChatInput({
397
404
  const isDisabled = pending || disabled;
398
405
  const attachmentsReady = attachments.length > 0 && attachments.every((item) => item.state !== "uploading");
399
406
  const canSubmit = !isDisabled && (Boolean(value.trim()) || attachmentsReady);
407
+ const liveVoiceActive = voiceSession && voiceSession.state !== "disconnected" && voiceSession.state !== "error";
400
408
  const submit = () => {
401
409
  const trimmed = value.trim();
402
410
  if (!trimmed && !attachmentsReady || isDisabled) return;
@@ -457,6 +465,7 @@ function ChatInput({
457
465
  className
458
466
  ),
459
467
  children: [
468
+ liveVoiceActive && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk7LDJAXRXcjs.InputGroupAddon, { align: "block-start", className: "w-full cursor-default border-b border-border p-0 [.border-b]:pb-0", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk7QTFYEPEcjs.VoiceSessionControls, { ...voiceSession }) }),
460
469
  attachments.length > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
461
470
  ChatAttachmentList,
462
471
  {
@@ -480,11 +489,10 @@ function ChatInput({
480
489
  },
481
490
  placeholder,
482
491
  rows: compact ? 1 : composerSize.rows,
483
- wrap: compact ? "off" : void 0,
484
492
  disabled: isDisabled,
485
493
  autoFocus,
486
494
  className: _chunkKWLSBTB2cjs.cn.call(void 0,
487
- compact ? "h-[44px] min-h-[44px] max-h-[44px] min-w-0 field-sizing-fixed overflow-hidden whitespace-nowrap text-ellipsis" : composerSize.minHeight,
495
+ compact ? "min-h-[44px] max-h-24 min-w-0" : composerSize.minHeight,
488
496
  // Grows with the text, then scrolls rather than pushing the thread away.
489
497
  "leading-relaxed disabled:opacity-70 placeholder:text-sm",
490
498
  !compact && "max-h-48",
@@ -495,14 +503,14 @@ function ChatInput({
495
503
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
496
504
  _chunk7LDJAXRXcjs.InputGroupAddon,
497
505
  {
498
- align: compact ? "inline-end" : "block-end",
506
+ align: "block-end",
499
507
  "data-slot": "chat-input-actions",
500
508
  onClick: (event) => {
501
509
  if (!event.currentTarget.contains(event.target)) return;
502
510
  if (!event.target.closest("button")) _optionalChain([ref, 'access', _3 => _3.current, 'optionalAccess', _4 => _4.focus, 'call', _5 => _5()]);
503
511
  },
504
512
  className: _chunkKWLSBTB2cjs.cn.call(void 0,
505
- compact ? "shrink-0 gap-0 p-1" : "gap-2",
513
+ compact ? "gap-1 px-2 pb-2 pt-0" : "gap-2",
506
514
  !compact && (spacious ? "px-5 pb-5 pt-1" : "border-t border-border px-3 py-2.5")
507
515
  ),
508
516
  children: [
@@ -523,12 +531,22 @@ function ChatInput({
523
531
  addFilesLabel
524
532
  ] }) })
525
533
  ] }),
534
+ helperText ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
535
+ "span",
536
+ {
537
+ "data-slot": "chat-input-helper",
538
+ className: _chunkKWLSBTB2cjs.cn.call(void 0, "min-w-0 flex-1 truncate px-1 text-center text-xs font-normal text-muted-foreground sm:px-2 sm:text-sm", compact && "hidden"),
539
+ children: helperText
540
+ }
541
+ ) : null,
542
+ (!helperText || compact) && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex-1" }),
526
543
  voice && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
527
- _chunkLKPM6DQPcjs.VoiceDictationButton,
544
+ _chunkKQBXAQAYcjs.VoiceDictationButton,
528
545
  {
529
546
  size: "icon",
530
547
  title: voiceTitle,
531
548
  lang: voiceLang,
549
+ disabled: Boolean(isDisabled || liveVoiceActive),
532
550
  onCommit: (text) => onSend(text),
533
551
  className: _chunkKWLSBTB2cjs.cn.call(void 0,
534
552
  spacious && "border-transparent bg-transparent shadow-none hover:bg-muted",
@@ -537,14 +555,7 @@ function ChatInput({
537
555
  )
538
556
  }
539
557
  ),
540
- helperText ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
541
- "span",
542
- {
543
- "data-slot": "chat-input-helper",
544
- className: _chunkKWLSBTB2cjs.cn.call(void 0, "min-w-0 flex-1 truncate px-1 text-center text-xs font-normal text-muted-foreground sm:px-2 sm:text-sm", compact && "hidden"),
545
- children: helperText
546
- }
547
- ) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: compact ? "hidden" : "flex-1" }),
558
+ voiceSession && !liveVoiceActive && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk7QTFYEPEcjs.VoiceSessionControls, { ...voiceSession, disabled: voiceSession.disabled || isDisabled }),
548
559
  submitLabel ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
549
560
  _chunkJDEXZGIYcjs.Button,
550
561
  {
@@ -593,6 +604,8 @@ function ChatInput({
593
604
  }
594
605
  function VoiceHero({
595
606
  onSubmit,
607
+ voice,
608
+ voiceSession,
596
609
  voiceTitle,
597
610
  voiceLang,
598
611
  onSwitchToText,
@@ -600,8 +613,20 @@ function VoiceHero({
600
613
  switchLabel
601
614
  }) {
602
615
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col items-center gap-5 py-6", children: [
603
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
604
- _chunkLKPM6DQPcjs.VoiceDictationButton,
616
+ voiceSession ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
617
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk7QTFYEPEcjs.VoiceSessionControls, { ...voiceSession, size: "hero" }),
618
+ voice && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
619
+ _chunkKQBXAQAYcjs.VoiceDictationButton,
620
+ {
621
+ size: "icon",
622
+ title: voiceTitle,
623
+ lang: voiceLang,
624
+ onCommit: onSubmit,
625
+ disabled: Boolean(voiceSession.disabled || voiceSession.state !== "disconnected" && voiceSession.state !== "error")
626
+ }
627
+ )
628
+ ] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
629
+ _chunkKQBXAQAYcjs.VoiceDictationButton,
605
630
  {
606
631
  size: "lg",
607
632
  title: voiceTitle,
@@ -730,6 +755,7 @@ var Chat = _react.forwardRef.call(void 0, function Chat2({
730
755
  fileDropLabel,
731
756
  fileDropDescription,
732
757
  voice = true,
758
+ voiceSession,
733
759
  voiceTitle,
734
760
  activeVoiceTitle,
735
761
  voiceLang,
@@ -753,7 +779,7 @@ var Chat = _react.forwardRef.call(void 0, function Chat2({
753
779
  const inputRef = _react.useRef.call(void 0, null);
754
780
  const conversationStarted = messages.length > 0;
755
781
  const [userMode, setUserMode] = _react.useState.call(void 0, null);
756
- const mode = _nullishCoalesce(_nullishCoalesce(userMode, () => ( defaultMode)), () => ( (isMobile ? "voice" : "text")));
782
+ const mode = !voice && !voiceSession ? "text" : _nullishCoalesce(_nullishCoalesce(userMode, () => ( defaultMode)), () => ( (isMobile ? "voice" : "text")));
757
783
  const reportSendError = _react.useCallback.call(void 0,
758
784
  (cause) => {
759
785
  if (onSendError) onSendError(cause);
@@ -811,9 +837,10 @@ var Chat = _react.forwardRef.call(void 0, function Chat2({
811
837
  const application = layout === "application";
812
838
  const workspace = layout === "workspace";
813
839
  const showEmptyFileDropzone = emptyFileDropzone && Boolean(onFilesSelected) && attachments.length === 0;
814
- const showEmptyPending = !conversationStarted && pending && Boolean(emptyPendingContent);
840
+ const liveVoiceActive = voiceSession && voiceSession.state !== "disconnected" && voiceSession.state !== "error";
841
+ const showEmptyPending = !conversationStarted && pending && Boolean(emptyPendingContent) && !liveVoiceActive;
815
842
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
816
- _chunkZ3JJSNR5cjs.FileDropArea,
843
+ _chunkZLEM2SAUcjs.FileDropArea,
817
844
  {
818
845
  "data-slot": "chat",
819
846
  "data-layout": layout,
@@ -881,7 +908,7 @@ var Chat = _react.forwardRef.call(void 0, function Chat2({
881
908
  ),
882
909
  children: [
883
910
  showEmptyFileDropzone && onFilesSelected && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
884
- _chunkZ3JJSNR5cjs.FileDropzone,
911
+ _chunkZLEM2SAUcjs.FileDropzone,
885
912
  {
886
913
  multiple: true,
887
914
  onFiles: onFilesSelected,
@@ -896,6 +923,8 @@ var Chat = _react.forwardRef.call(void 0, function Chat2({
896
923
  VoiceHero,
897
924
  {
898
925
  onSubmit: (text) => void send(text),
926
+ voice,
927
+ voiceSession: voiceSession ? { ...voiceSession, disabled: voiceSession.disabled || pending } : void 0,
899
928
  voiceTitle,
900
929
  voiceLang,
901
930
  label: voiceHeroLabel,
@@ -912,6 +941,7 @@ var Chat = _react.forwardRef.call(void 0, function Chat2({
912
941
  placeholder,
913
942
  size: showEmptyFileDropzone || application && isMobile ? "md" : "lg",
914
943
  voice,
944
+ voiceSession,
915
945
  voiceTitle,
916
946
  voiceLang,
917
947
  submitLabel,
@@ -1004,6 +1034,7 @@ var Chat = _react.forwardRef.call(void 0, function Chat2({
1004
1034
  placeholder: activePlaceholder,
1005
1035
  size: composerAppearance === "spacious" ? "lg" : "sm",
1006
1036
  voice,
1037
+ voiceSession,
1007
1038
  voiceTitle: _nullishCoalesce(activeVoiceTitle, () => ( voiceTitle)),
1008
1039
  voiceLang,
1009
1040
  inputRef,
@@ -1,6 +1,7 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as React$1 from 'react';
3
3
  import { ReactNode } from 'react';
4
+ import { VoiceSessionControlsProps } from './voice-session-controls.cjs';
4
5
  import { MarkdownComponents } from './markdown.cjs';
5
6
  import 'react-markdown';
6
7
  import './rich-text.cjs';
@@ -153,6 +154,8 @@ interface ChatInputProps {
153
154
  uploadingLabel?: string;
154
155
  /** Show the inline voice dictation button. Defaults to true. */
155
156
  voice?: boolean;
157
+ /** A separate live voice control alongside dictation. The host owns its transport and lifecycle. */
158
+ voiceSession?: VoiceSessionControlsProps;
156
159
  /** Title shown inside the voice overlay. */
157
160
  voiceTitle?: string;
158
161
  /** Language tag for voice dictation. */
@@ -184,7 +187,7 @@ interface ChatInputProps {
184
187
  /** Visual density for the complete composer surface. */
185
188
  appearance?: "default" | "spacious";
186
189
  /**
187
- * Fold an empty, unfocused composer into one row. Focusing its textarea
190
+ * Fold an empty, unfocused composer into a short text row and control bar. Focusing its textarea
188
191
  * expands it; drafts and staged files always keep it expanded. Chat enables
189
192
  * this only for an active mobile conversation with `mobileCompactComposer`.
190
193
  */
@@ -210,7 +213,7 @@ interface ChatInputProps {
210
213
  * `<Chat>` instead of composing `<ChatInput>` directly if you want
211
214
  * device-aware default modes.
212
215
  */
213
- declare function ChatInput({ value, onChange, onSend, pending, disabled, placeholder, size, uploadingLabel, voice, voiceTitle, voiceLang, submitLabel, autoFocus, className, inputRef, attachments, onFilesSelected, onRemoveAttachment, accept, multiple, addFilesLabel, appearance, compactOnBlur, helperText, privacyNote, }: ChatInputProps): react_jsx_runtime.JSX.Element;
216
+ declare function ChatInput({ value, onChange, onSend, pending, disabled, placeholder, size, uploadingLabel, voice, voiceSession, voiceTitle, voiceLang, submitLabel, autoFocus, className, inputRef, attachments, onFilesSelected, onRemoveAttachment, accept, multiple, addFilesLabel, appearance, compactOnBlur, helperText, privacyNote, }: ChatInputProps): react_jsx_runtime.JSX.Element;
214
217
  interface ChatProps {
215
218
  /** Conversation messages. */
216
219
  messages: ChatMessage[];
@@ -323,7 +326,7 @@ interface ChatProps {
323
326
  composerAppearance?: ChatInputProps["appearance"];
324
327
  /**
325
328
  * On phones (below 768px), fold an active conversation's empty composer
326
- * into one row until its textarea is focused. Drafts and files stay
329
+ * into a short text row above its controls until the textarea is focused. Drafts and files stay
327
330
  * expanded. Desktop and the new-conversation composer are unchanged.
328
331
  */
329
332
  mobileCompactComposer?: boolean;
@@ -354,6 +357,8 @@ interface ChatProps {
354
357
  fileDropDescription?: ReactNode;
355
358
  /** Enable voice dictation. Defaults to true. */
356
359
  voice?: boolean;
360
+ /** Controlled live voice UI, used instead of browser dictation when provided. */
361
+ voiceSession?: VoiceSessionControlsProps;
357
362
  /** Title shown inside the voice overlay. */
358
363
  voiceTitle?: string;
359
364
  /** Title shown inside the voice overlay in the active state. */
@@ -1,6 +1,7 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as React$1 from 'react';
3
3
  import { ReactNode } from 'react';
4
+ import { VoiceSessionControlsProps } from './voice-session-controls.js';
4
5
  import { MarkdownComponents } from './markdown.js';
5
6
  import 'react-markdown';
6
7
  import './rich-text.js';
@@ -153,6 +154,8 @@ interface ChatInputProps {
153
154
  uploadingLabel?: string;
154
155
  /** Show the inline voice dictation button. Defaults to true. */
155
156
  voice?: boolean;
157
+ /** A separate live voice control alongside dictation. The host owns its transport and lifecycle. */
158
+ voiceSession?: VoiceSessionControlsProps;
156
159
  /** Title shown inside the voice overlay. */
157
160
  voiceTitle?: string;
158
161
  /** Language tag for voice dictation. */
@@ -184,7 +187,7 @@ interface ChatInputProps {
184
187
  /** Visual density for the complete composer surface. */
185
188
  appearance?: "default" | "spacious";
186
189
  /**
187
- * Fold an empty, unfocused composer into one row. Focusing its textarea
190
+ * Fold an empty, unfocused composer into a short text row and control bar. Focusing its textarea
188
191
  * expands it; drafts and staged files always keep it expanded. Chat enables
189
192
  * this only for an active mobile conversation with `mobileCompactComposer`.
190
193
  */
@@ -210,7 +213,7 @@ interface ChatInputProps {
210
213
  * `<Chat>` instead of composing `<ChatInput>` directly if you want
211
214
  * device-aware default modes.
212
215
  */
213
- declare function ChatInput({ value, onChange, onSend, pending, disabled, placeholder, size, uploadingLabel, voice, voiceTitle, voiceLang, submitLabel, autoFocus, className, inputRef, attachments, onFilesSelected, onRemoveAttachment, accept, multiple, addFilesLabel, appearance, compactOnBlur, helperText, privacyNote, }: ChatInputProps): react_jsx_runtime.JSX.Element;
216
+ declare function ChatInput({ value, onChange, onSend, pending, disabled, placeholder, size, uploadingLabel, voice, voiceSession, voiceTitle, voiceLang, submitLabel, autoFocus, className, inputRef, attachments, onFilesSelected, onRemoveAttachment, accept, multiple, addFilesLabel, appearance, compactOnBlur, helperText, privacyNote, }: ChatInputProps): react_jsx_runtime.JSX.Element;
214
217
  interface ChatProps {
215
218
  /** Conversation messages. */
216
219
  messages: ChatMessage[];
@@ -323,7 +326,7 @@ interface ChatProps {
323
326
  composerAppearance?: ChatInputProps["appearance"];
324
327
  /**
325
328
  * On phones (below 768px), fold an active conversation's empty composer
326
- * into one row until its textarea is focused. Drafts and files stay
329
+ * into a short text row above its controls until the textarea is focused. Drafts and files stay
327
330
  * expanded. Desktop and the new-conversation composer are unchanged.
328
331
  */
329
332
  mobileCompactComposer?: boolean;
@@ -354,6 +357,8 @@ interface ChatProps {
354
357
  fileDropDescription?: ReactNode;
355
358
  /** Enable voice dictation. Defaults to true. */
356
359
  voice?: boolean;
360
+ /** Controlled live voice UI, used instead of browser dictation when provided. */
361
+ voiceSession?: VoiceSessionControlsProps;
357
362
  /** Title shown inside the voice overlay. */
358
363
  voiceTitle?: string;
359
364
  /** Title shown inside the voice overlay in the active state. */
@@ -1,5 +1,8 @@
1
1
  "use client";
2
2
  "use client";
3
+ import {
4
+ VoiceSessionControls
5
+ } from "../chunk-UOVA4YKW.js";
3
6
  import {
4
7
  Trace,
5
8
  TraceLine,
@@ -7,11 +10,15 @@ import {
7
10
  } from "../chunk-Z45YKVAM.js";
8
11
  import {
9
12
  VoiceDictationButton
10
- } from "../chunk-TI57GAQP.js";
13
+ } from "../chunk-T3XMHWYV.js";
11
14
  import {
12
15
  Suggestion,
13
16
  Suggestions
14
17
  } from "../chunk-IJG2B3Y2.js";
18
+ import {
19
+ Marker,
20
+ MarkerContent
21
+ } from "../chunk-IW4ZIXXG.js";
15
22
  import {
16
23
  MessageScroller,
17
24
  MessageScrollerButton,
@@ -26,10 +33,6 @@ import {
26
33
  MessageActions,
27
34
  MessageContent
28
35
  } from "../chunk-H4XH2PPU.js";
29
- import {
30
- Marker,
31
- MarkerContent
32
- } from "../chunk-IW4ZIXXG.js";
33
36
  import {
34
37
  InputGroup,
35
38
  InputGroupAddon,
@@ -39,7 +42,7 @@ import "../chunk-6FC65AZQ.js";
39
42
  import {
40
43
  FileDropArea,
41
44
  FileDropzone
42
- } from "../chunk-HBRVOGLA.js";
45
+ } from "../chunk-WHDHUYS6.js";
43
46
  import {
44
47
  LazyMarkdown
45
48
  } from "../chunk-VY5U4VGV.js";
@@ -50,6 +53,7 @@ import {
50
53
  DropdownMenuItem,
51
54
  DropdownMenuTrigger
52
55
  } from "../chunk-V4LE2HWP.js";
56
+ import "../chunk-ZRLUUZHK.js";
53
57
  import {
54
58
  Bubble,
55
59
  BubbleContent
@@ -67,26 +71,28 @@ import {
67
71
  AttachmentTitle,
68
72
  AttachmentTrigger
69
73
  } from "../chunk-CYDICVH2.js";
70
- import "../chunk-ZRLUUZHK.js";
71
74
  import {
72
75
  ActionDock
73
76
  } from "../chunk-42RTTHND.js";
74
77
  import "../chunk-QMA3WVB7.js";
78
+ import "../chunk-5OF6D3GH.js";
75
79
  import {
76
80
  Button
77
81
  } from "../chunk-W326GKML.js";
82
+ import {
83
+ cn
84
+ } from "../chunk-G6SRSWXB.js";
85
+ import "../chunk-GJ7S3L6R.js";
78
86
  import {
79
87
  useCopyToClipboard
80
88
  } from "../chunk-ZWZAAGQF.js";
89
+ import "../chunk-HLAHOVEI.js";
81
90
  import {
82
91
  useIsMobile
83
92
  } from "../chunk-PIU5SSUV.js";
84
93
  import {
85
94
  formatRelativeLong
86
95
  } from "../chunk-CS7DM3NV.js";
87
- import {
88
- cn
89
- } from "../chunk-G6SRSWXB.js";
90
96
 
91
97
  // src/primitives/chat.tsx
92
98
  import {
@@ -372,6 +378,7 @@ function ChatInput({
372
378
  size = "md",
373
379
  uploadingLabel,
374
380
  voice = true,
381
+ voiceSession,
375
382
  voiceTitle,
376
383
  voiceLang,
377
384
  submitLabel,
@@ -397,6 +404,7 @@ function ChatInput({
397
404
  const isDisabled = pending || disabled;
398
405
  const attachmentsReady = attachments.length > 0 && attachments.every((item) => item.state !== "uploading");
399
406
  const canSubmit = !isDisabled && (Boolean(value.trim()) || attachmentsReady);
407
+ const liveVoiceActive = voiceSession && voiceSession.state !== "disconnected" && voiceSession.state !== "error";
400
408
  const submit = () => {
401
409
  const trimmed = value.trim();
402
410
  if (!trimmed && !attachmentsReady || isDisabled) return;
@@ -457,6 +465,7 @@ function ChatInput({
457
465
  className
458
466
  ),
459
467
  children: [
468
+ liveVoiceActive && /* @__PURE__ */ jsx(InputGroupAddon, { align: "block-start", className: "w-full cursor-default border-b border-border p-0 [.border-b]:pb-0", children: /* @__PURE__ */ jsx(VoiceSessionControls, { ...voiceSession }) }),
460
469
  attachments.length > 0 && /* @__PURE__ */ jsx(
461
470
  ChatAttachmentList,
462
471
  {
@@ -480,11 +489,10 @@ function ChatInput({
480
489
  },
481
490
  placeholder,
482
491
  rows: compact ? 1 : composerSize.rows,
483
- wrap: compact ? "off" : void 0,
484
492
  disabled: isDisabled,
485
493
  autoFocus,
486
494
  className: cn(
487
- compact ? "h-[44px] min-h-[44px] max-h-[44px] min-w-0 field-sizing-fixed overflow-hidden whitespace-nowrap text-ellipsis" : composerSize.minHeight,
495
+ compact ? "min-h-[44px] max-h-24 min-w-0" : composerSize.minHeight,
488
496
  // Grows with the text, then scrolls rather than pushing the thread away.
489
497
  "leading-relaxed disabled:opacity-70 placeholder:text-sm",
490
498
  !compact && "max-h-48",
@@ -495,14 +503,14 @@ function ChatInput({
495
503
  /* @__PURE__ */ jsxs(
496
504
  InputGroupAddon,
497
505
  {
498
- align: compact ? "inline-end" : "block-end",
506
+ align: "block-end",
499
507
  "data-slot": "chat-input-actions",
500
508
  onClick: (event) => {
501
509
  if (!event.currentTarget.contains(event.target)) return;
502
510
  if (!event.target.closest("button")) ref.current?.focus();
503
511
  },
504
512
  className: cn(
505
- compact ? "shrink-0 gap-0 p-1" : "gap-2",
513
+ compact ? "gap-1 px-2 pb-2 pt-0" : "gap-2",
506
514
  !compact && (spacious ? "px-5 pb-5 pt-1" : "border-t border-border px-3 py-2.5")
507
515
  ),
508
516
  children: [
@@ -523,12 +531,22 @@ function ChatInput({
523
531
  addFilesLabel
524
532
  ] }) })
525
533
  ] }),
534
+ helperText ? /* @__PURE__ */ jsx(
535
+ "span",
536
+ {
537
+ "data-slot": "chat-input-helper",
538
+ className: cn("min-w-0 flex-1 truncate px-1 text-center text-xs font-normal text-muted-foreground sm:px-2 sm:text-sm", compact && "hidden"),
539
+ children: helperText
540
+ }
541
+ ) : null,
542
+ (!helperText || compact) && /* @__PURE__ */ jsx("div", { className: "flex-1" }),
526
543
  voice && /* @__PURE__ */ jsx(
527
544
  VoiceDictationButton,
528
545
  {
529
546
  size: "icon",
530
547
  title: voiceTitle,
531
548
  lang: voiceLang,
549
+ disabled: Boolean(isDisabled || liveVoiceActive),
532
550
  onCommit: (text) => onSend(text),
533
551
  className: cn(
534
552
  spacious && "border-transparent bg-transparent shadow-none hover:bg-muted",
@@ -537,14 +555,7 @@ function ChatInput({
537
555
  )
538
556
  }
539
557
  ),
540
- helperText ? /* @__PURE__ */ jsx(
541
- "span",
542
- {
543
- "data-slot": "chat-input-helper",
544
- className: cn("min-w-0 flex-1 truncate px-1 text-center text-xs font-normal text-muted-foreground sm:px-2 sm:text-sm", compact && "hidden"),
545
- children: helperText
546
- }
547
- ) : /* @__PURE__ */ jsx("div", { className: compact ? "hidden" : "flex-1" }),
558
+ voiceSession && !liveVoiceActive && /* @__PURE__ */ jsx(VoiceSessionControls, { ...voiceSession, disabled: voiceSession.disabled || isDisabled }),
548
559
  submitLabel ? /* @__PURE__ */ jsxs(
549
560
  Button,
550
561
  {
@@ -593,6 +604,8 @@ function ChatInput({
593
604
  }
594
605
  function VoiceHero({
595
606
  onSubmit,
607
+ voice,
608
+ voiceSession,
596
609
  voiceTitle,
597
610
  voiceLang,
598
611
  onSwitchToText,
@@ -600,7 +613,19 @@ function VoiceHero({
600
613
  switchLabel
601
614
  }) {
602
615
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-5 py-6", children: [
603
- /* @__PURE__ */ jsx(
616
+ voiceSession ? /* @__PURE__ */ jsxs(Fragment, { children: [
617
+ /* @__PURE__ */ jsx(VoiceSessionControls, { ...voiceSession, size: "hero" }),
618
+ voice && /* @__PURE__ */ jsx(
619
+ VoiceDictationButton,
620
+ {
621
+ size: "icon",
622
+ title: voiceTitle,
623
+ lang: voiceLang,
624
+ onCommit: onSubmit,
625
+ disabled: Boolean(voiceSession.disabled || voiceSession.state !== "disconnected" && voiceSession.state !== "error")
626
+ }
627
+ )
628
+ ] }) : /* @__PURE__ */ jsx(
604
629
  VoiceDictationButton,
605
630
  {
606
631
  size: "lg",
@@ -730,6 +755,7 @@ var Chat = forwardRef(function Chat2({
730
755
  fileDropLabel,
731
756
  fileDropDescription,
732
757
  voice = true,
758
+ voiceSession,
733
759
  voiceTitle,
734
760
  activeVoiceTitle,
735
761
  voiceLang,
@@ -753,7 +779,7 @@ var Chat = forwardRef(function Chat2({
753
779
  const inputRef = useRef(null);
754
780
  const conversationStarted = messages.length > 0;
755
781
  const [userMode, setUserMode] = useState(null);
756
- const mode = userMode ?? defaultMode ?? (isMobile ? "voice" : "text");
782
+ const mode = !voice && !voiceSession ? "text" : userMode ?? defaultMode ?? (isMobile ? "voice" : "text");
757
783
  const reportSendError = useCallback(
758
784
  (cause) => {
759
785
  if (onSendError) onSendError(cause);
@@ -811,7 +837,8 @@ var Chat = forwardRef(function Chat2({
811
837
  const application = layout === "application";
812
838
  const workspace = layout === "workspace";
813
839
  const showEmptyFileDropzone = emptyFileDropzone && Boolean(onFilesSelected) && attachments.length === 0;
814
- const showEmptyPending = !conversationStarted && pending && Boolean(emptyPendingContent);
840
+ const liveVoiceActive = voiceSession && voiceSession.state !== "disconnected" && voiceSession.state !== "error";
841
+ const showEmptyPending = !conversationStarted && pending && Boolean(emptyPendingContent) && !liveVoiceActive;
815
842
  return /* @__PURE__ */ jsx(
816
843
  FileDropArea,
817
844
  {
@@ -896,6 +923,8 @@ var Chat = forwardRef(function Chat2({
896
923
  VoiceHero,
897
924
  {
898
925
  onSubmit: (text) => void send(text),
926
+ voice,
927
+ voiceSession: voiceSession ? { ...voiceSession, disabled: voiceSession.disabled || pending } : void 0,
899
928
  voiceTitle,
900
929
  voiceLang,
901
930
  label: voiceHeroLabel,
@@ -912,6 +941,7 @@ var Chat = forwardRef(function Chat2({
912
941
  placeholder,
913
942
  size: showEmptyFileDropzone || application && isMobile ? "md" : "lg",
914
943
  voice,
944
+ voiceSession,
915
945
  voiceTitle,
916
946
  voiceLang,
917
947
  submitLabel,
@@ -1004,6 +1034,7 @@ var Chat = forwardRef(function Chat2({
1004
1034
  placeholder: activePlaceholder,
1005
1035
  size: composerAppearance === "spacious" ? "lg" : "sm",
1006
1036
  voice,
1037
+ voiceSession,
1007
1038
  voiceTitle: activeVoiceTitle ?? voiceTitle,
1008
1039
  voiceLang,
1009
1040
  inputRef,
@@ -1,11 +1,11 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true});"use client";
2
2
 
3
3
 
4
- var _chunkGTVSRRE3cjs = require('../chunk-GTVSRRE3.cjs');
5
- require('../chunk-MU4F3DSW.cjs');
4
+ var _chunkBGCNGYPLcjs = require('../chunk-BGCNGYPL.cjs');
5
+ require('../chunk-FARCLWLU.cjs');
6
6
  require('../chunk-JDEXZGIY.cjs');
7
- require('../chunk-4LXN6GLZ.cjs');
8
7
  require('../chunk-KWLSBTB2.cjs');
8
+ require('../chunk-4LXN6GLZ.cjs');
9
9
 
10
10
 
11
- exports.CodeBlock = _chunkGTVSRRE3cjs.CodeBlock;
11
+ exports.CodeBlock = _chunkBGCNGYPLcjs.CodeBlock;
@@ -1,11 +1,11 @@
1
1
  "use client";
2
2
  import {
3
3
  CodeBlock
4
- } from "../chunk-F3B4M6DU.js";
5
- import "../chunk-HREEZUKL.js";
4
+ } from "../chunk-HTPPNW74.js";
5
+ import "../chunk-DILYV4FI.js";
6
6
  import "../chunk-W326GKML.js";
7
- import "../chunk-ZWZAAGQF.js";
8
7
  import "../chunk-G6SRSWXB.js";
8
+ import "../chunk-ZWZAAGQF.js";
9
9
  export {
10
10
  CodeBlock
11
11
  };