@epicbagel/saas-kit 1.7.0 → 1.10.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 (97) hide show
  1. package/README.md +60 -0
  2. package/THIRD_PARTY_NOTICES.md +14 -0
  3. package/dist/chunk-2BSFYU22.cjs +71 -0
  4. package/dist/{chunk-GTVSRRE3.cjs → chunk-BGCNGYPL.cjs} +2 -2
  5. package/dist/{chunk-QTWJQQDH.cjs → chunk-FBVZRRA4.cjs} +6 -6
  6. package/dist/chunk-GJ7S3L6R.js +71 -0
  7. package/dist/{chunk-LKPM6DQP.cjs → chunk-HTCW6AEH.cjs} +51 -72
  8. package/dist/{chunk-F3B4M6DU.js → chunk-HTPPNW74.js} +1 -1
  9. package/dist/chunk-KUG4ONYC.js +127 -0
  10. package/dist/{chunk-TI57GAQP.js → chunk-KWV5KTOA.js} +48 -69
  11. package/dist/{chunk-JN6JOSZG.js → chunk-LQPJGZIE.js} +7 -7
  12. package/dist/chunk-M2ZNC3TK.js +316 -0
  13. package/dist/chunk-O6F3LVZY.cjs +316 -0
  14. package/dist/chunk-UW67GSZ4.cjs +127 -0
  15. package/dist/chunk-VBKJXNEL.js +157 -0
  16. package/dist/chunk-XB2D4NQK.cjs +157 -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 +56 -0
  23. package/dist/hooks/use-dictation.d.ts +56 -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/archive-confirmation-dialog.cjs +2 -2
  32. package/dist/primitives/archive-confirmation-dialog.js +3 -3
  33. package/dist/primitives/attachment.d.cts +1 -1
  34. package/dist/primitives/attachment.d.ts +1 -1
  35. package/dist/primitives/badge.d.cts +1 -1
  36. package/dist/primitives/badge.d.ts +1 -1
  37. package/dist/primitives/board-view.cjs +6 -6
  38. package/dist/primitives/board-view.js +5 -5
  39. package/dist/primitives/bubble.d.cts +1 -1
  40. package/dist/primitives/bubble.d.ts +1 -1
  41. package/dist/primitives/button.d.cts +3 -3
  42. package/dist/primitives/button.d.ts +3 -3
  43. package/dist/primitives/chat.cjs +55 -24
  44. package/dist/primitives/chat.d.cts +6 -1
  45. package/dist/primitives/chat.d.ts +6 -1
  46. package/dist/primitives/chat.js +52 -21
  47. package/dist/primitives/code-block.cjs +4 -4
  48. package/dist/primitives/code-block.js +3 -3
  49. package/dist/primitives/connection.cjs +6 -6
  50. package/dist/primitives/connection.js +7 -7
  51. package/dist/primitives/copy-button.cjs +3 -3
  52. package/dist/primitives/copy-button.js +2 -2
  53. package/dist/primitives/dictation-provider.cjs +8 -0
  54. package/dist/primitives/dictation-provider.d.cts +2 -0
  55. package/dist/primitives/dictation-provider.d.ts +2 -0
  56. package/dist/primitives/dictation-provider.js +8 -0
  57. package/dist/primitives/editable-list.cjs +1 -1
  58. package/dist/primitives/editable-list.js +1 -1
  59. package/dist/primitives/file-dropzone.cjs +3 -3
  60. package/dist/primitives/file-dropzone.js +2 -2
  61. package/dist/primitives/file-preview.cjs +6 -6
  62. package/dist/primitives/file-preview.js +5 -5
  63. package/dist/primitives/filter-bar.cjs +4 -4
  64. package/dist/primitives/filter-bar.js +3 -3
  65. package/dist/primitives/input-group.d.cts +1 -1
  66. package/dist/primitives/input-group.d.ts +1 -1
  67. package/dist/primitives/item.d.cts +2 -2
  68. package/dist/primitives/item.d.ts +2 -2
  69. package/dist/primitives/resource-list.cjs +6 -6
  70. package/dist/primitives/resource-list.js +5 -5
  71. package/dist/primitives/section-header.d.cts +1 -1
  72. package/dist/primitives/section-header.d.ts +1 -1
  73. package/dist/primitives/section.cjs +2 -2
  74. package/dist/primitives/section.js +3 -3
  75. package/dist/primitives/sheet.d.cts +1 -1
  76. package/dist/primitives/sheet.d.ts +1 -1
  77. package/dist/primitives/switch-field.cjs +2 -2
  78. package/dist/primitives/switch-field.js +3 -3
  79. package/dist/primitives/theme-selector.cjs +3 -3
  80. package/dist/primitives/theme-selector.js +4 -4
  81. package/dist/primitives/toggle-group.d.cts +2 -2
  82. package/dist/primitives/toggle-group.d.ts +2 -2
  83. package/dist/primitives/toggle.d.cts +2 -2
  84. package/dist/primitives/toggle.d.ts +2 -2
  85. package/dist/primitives/voice-dictation-button.cjs +3 -2
  86. package/dist/primitives/voice-dictation-button.js +2 -1
  87. package/dist/primitives/voice-session-controls.cjs +12 -0
  88. package/dist/primitives/voice-session-controls.d.cts +29 -0
  89. package/dist/primitives/voice-session-controls.d.ts +29 -0
  90. package/dist/primitives/voice-session-controls.js +12 -0
  91. package/package.json +51 -1
  92. package/dist/{chunk-HREEZUKL.js → chunk-DILYV4FI.js} +3 -3
  93. package/dist/{chunk-MU4F3DSW.cjs → chunk-FARCLWLU.cjs} +2 -2
  94. package/dist/{chunk-CRTH5GJ5.cjs → chunk-MW67PHAQ.cjs} +3 -3
  95. package/dist/{chunk-KNKV25WS.js → chunk-UFFHGKI7.js} +3 -3
  96. package/dist/{chunk-HBRVOGLA.js → chunk-WHDHUYS6.js} +3 -3
  97. package/dist/{chunk-Z3JJSNR5.cjs → chunk-ZLEM2SAU.cjs} +2 -2
@@ -0,0 +1,316 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }"use client";
2
+
3
+ // src/hooks/use-dictation.ts
4
+ var _react = require('react');
5
+ var DictationContext = _react.createContext.call(void 0, null);
6
+ function DictationProvider({ transcribe, scopeKey, children }) {
7
+ const scope = _react.useRef.call(void 0, { key: scopeKey, generation: 0 });
8
+ if (scope.current.key !== scopeKey) scope.current = { key: scopeKey, generation: scope.current.generation + 1 };
9
+ const generation = scope.current.generation;
10
+ const value = _react.useMemo.call(void 0, () => ({ transcribe, scope, generation }), [transcribe, generation]);
11
+ return _react.createElement.call(void 0, DictationContext.Provider, { value }, children);
12
+ }
13
+ var EMPTY = { state: "idle", transcript: "", interimTranscript: "", error: null, canRetry: false };
14
+ var MIME_TYPES = ["audio/webm;codecs=opus", "audio/mp4", "audio/ogg;codecs=opus", "audio/webm"];
15
+ function recognitionConstructor() {
16
+ if (typeof window === "undefined") return void 0;
17
+ const speech = window;
18
+ return _nullishCoalesce(speech.SpeechRecognition, () => ( speech.webkitSpeechRecognition));
19
+ }
20
+ function microphoneError(reason) {
21
+ const name = _optionalChain([reason, 'optionalAccess', _ => _.name]);
22
+ if (name === "NotAllowedError" || name === "SecurityError") return "Microphone access is blocked. Allow it in your browser and try again.";
23
+ if (name === "NotFoundError" || name === "NotReadableError") return "The microphone is unavailable. Check your microphone and try again.";
24
+ return "Recording could not start. Check your microphone and try again.";
25
+ }
26
+ function recognitionError(code) {
27
+ if (code === "not-allowed" || code === "service-not-allowed") return microphoneError({ name: "NotAllowedError" });
28
+ if (code === "audio-capture") return microphoneError({ name: "NotFoundError" });
29
+ if (code === "no-speech") return "No speech was detected. Try again.";
30
+ return "Speech recognition stopped. Try again.";
31
+ }
32
+ function releaseTracks(session) {
33
+ _optionalChain([session, 'access', _2 => _2.stream, 'optionalAccess', _3 => _3.getTracks, 'call', _4 => _4(), 'access', _5 => _5.forEach, 'call', _6 => _6((track) => track.stop())]);
34
+ session.stream = void 0;
35
+ }
36
+ function dispose(session) {
37
+ session.controller.abort();
38
+ if (session.nativeTimer) clearTimeout(session.nativeTimer);
39
+ const recorder = session.recorder;
40
+ if (recorder) {
41
+ recorder.ondataavailable = null;
42
+ recorder.onstop = null;
43
+ recorder.onerror = null;
44
+ if (recorder.state !== "inactive") {
45
+ try {
46
+ recorder.stop();
47
+ } catch (e) {
48
+ }
49
+ }
50
+ }
51
+ const recognition = session.recognition;
52
+ if (recognition) {
53
+ recognition.onresult = null;
54
+ recognition.onerror = null;
55
+ recognition.onend = null;
56
+ try {
57
+ recognition.abort();
58
+ } catch (e2) {
59
+ }
60
+ }
61
+ releaseTracks(session);
62
+ session.resolveCapture(null);
63
+ session.resolveNativeEnd();
64
+ }
65
+ function useDictation({ lang = "en-US", continuous = true, onTranscript } = {}) {
66
+ const provider = _react.useContext.call(void 0, DictationContext);
67
+ const transcribe = _nullishCoalesce(_optionalChain([provider, 'optionalAccess', _7 => _7.transcribe]), () => ( null));
68
+ const scope = _nullishCoalesce(_optionalChain([provider, 'optionalAccess', _8 => _8.scope]), () => ( null));
69
+ const scopeGeneration = _nullishCoalesce(_optionalChain([provider, 'optionalAccess', _9 => _9.generation]), () => ( 0));
70
+ const [snapshot, setSnapshot] = _react.useState.call(void 0, EMPTY);
71
+ const [supported, setSupported] = _react.useState.call(void 0, false);
72
+ const current = _react.useRef.call(void 0, null);
73
+ const mounted = _react.useRef.call(void 0, true);
74
+ const callback = _react.useRef.call(void 0, onTranscript);
75
+ const activeScope = _react.useRef.call(void 0, scope);
76
+ activeScope.current = scope;
77
+ callback.current = onTranscript;
78
+ _react.useEffect.call(void 0, () => {
79
+ setSupported(transcribe ? typeof navigator !== "undefined" && !!_optionalChain([navigator, 'access', _10 => _10.mediaDevices, 'optionalAccess', _11 => _11.getUserMedia]) && typeof MediaRecorder !== "undefined" : typeof recognitionConstructor() === "function");
80
+ }, [transcribe]);
81
+ const cancel = _react.useCallback.call(void 0, () => {
82
+ const session = current.current;
83
+ current.current = null;
84
+ if (session) dispose(session);
85
+ if (mounted.current) setSnapshot(EMPTY);
86
+ }, []);
87
+ _react.useEffect.call(void 0, () => {
88
+ const session = current.current;
89
+ if (session && (session.scope !== scope || session.scopeGeneration !== scopeGeneration)) cancel();
90
+ }, [cancel, scope, scopeGeneration]);
91
+ _react.useEffect.call(void 0, () => {
92
+ mounted.current = true;
93
+ return () => {
94
+ mounted.current = false;
95
+ const session = current.current;
96
+ current.current = null;
97
+ if (session) dispose(session);
98
+ };
99
+ }, []);
100
+ const isCurrent = _react.useCallback.call(void 0, (session) => mounted.current && current.current === session && session.scope === activeScope.current && session.scopeGeneration === (_nullishCoalesce(_optionalChain([session, 'access', _12 => _12.scope, 'optionalAccess', _13 => _13.current, 'access', _14 => _14.generation]), () => ( 0))) && !session.controller.signal.aborted, []);
101
+ const start = _react.useCallback.call(void 0, async () => {
102
+ if (scope !== activeScope.current || scopeGeneration !== (_nullishCoalesce(_optionalChain([scope, 'optionalAccess', _15 => _15.current, 'access', _16 => _16.generation]), () => ( 0)))) return;
103
+ if (current.current && isCurrent(current.current) && ["requesting", "recording", "transcribing"].includes(current.current.phase)) return;
104
+ cancel();
105
+ let resolveCapture;
106
+ let resolveNativeEnd;
107
+ const session = {
108
+ language: lang,
109
+ transcribe,
110
+ scope,
111
+ scopeGeneration,
112
+ controller: new AbortController(),
113
+ phase: "requesting",
114
+ chunks: [],
115
+ capture: new Promise((resolve) => {
116
+ resolveCapture = resolve;
117
+ }),
118
+ resolveCapture: (blob) => resolveCapture(blob),
119
+ nativeEnd: new Promise((resolve) => {
120
+ resolveNativeEnd = resolve;
121
+ }),
122
+ resolveNativeEnd: () => resolveNativeEnd(),
123
+ nativeEnded: false,
124
+ transcript: "",
125
+ interim: "",
126
+ notified: /* @__PURE__ */ new Set()
127
+ };
128
+ current.current = session;
129
+ setSnapshot({ ...EMPTY, state: "requesting" });
130
+ if (transcribe) {
131
+ try {
132
+ if (!_optionalChain([navigator, 'access', _17 => _17.mediaDevices, 'optionalAccess', _18 => _18.getUserMedia]) || typeof MediaRecorder === "undefined") throw new Error("unsupported");
133
+ const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
134
+ if (!isCurrent(session)) {
135
+ stream.getTracks().forEach((track) => track.stop());
136
+ return;
137
+ }
138
+ session.stream = stream;
139
+ const mimeType = MIME_TYPES.find((mime) => _optionalChain([MediaRecorder, 'access', _19 => _19.isTypeSupported, 'optionalCall', _20 => _20(mime)]));
140
+ const recorder = mimeType ? new MediaRecorder(stream, { mimeType }) : new MediaRecorder(stream);
141
+ session.recorder = recorder;
142
+ recorder.ondataavailable = (event) => {
143
+ if (isCurrent(session) && event.data.size) session.chunks.push(event.data);
144
+ };
145
+ recorder.onstop = () => {
146
+ releaseTracks(session);
147
+ if (!isCurrent(session)) {
148
+ session.resolveCapture(null);
149
+ return;
150
+ }
151
+ const type = recorder.mimeType || _optionalChain([session, 'access', _21 => _21.chunks, 'access', _22 => _22[0], 'optionalAccess', _23 => _23.type]) || mimeType || "audio/webm";
152
+ const blob = new Blob(session.chunks, { type });
153
+ session.blob = blob;
154
+ session.chunks = [];
155
+ session.resolveCapture(blob);
156
+ };
157
+ recorder.onerror = () => {
158
+ if (!isCurrent(session)) return;
159
+ releaseTracks(session);
160
+ session.phase = "error";
161
+ session.resolveCapture(null);
162
+ setSnapshot({ ...EMPTY, state: "error", error: "Recording was interrupted. Try again." });
163
+ };
164
+ recorder.start();
165
+ session.phase = "recording";
166
+ setSnapshot({ ...EMPTY, state: "recording" });
167
+ } catch (error) {
168
+ releaseTracks(session);
169
+ if (!isCurrent(session)) return;
170
+ session.phase = "error";
171
+ setSnapshot({ ...EMPTY, state: "error", error: microphoneError(error) });
172
+ }
173
+ return;
174
+ }
175
+ try {
176
+ const Constructor = recognitionConstructor();
177
+ if (!Constructor) throw new Error("unsupported");
178
+ const recognition = new Constructor();
179
+ session.recognition = recognition;
180
+ recognition.lang = lang;
181
+ recognition.continuous = continuous;
182
+ recognition.interimResults = true;
183
+ recognition.onresult = (event) => {
184
+ if (!isCurrent(session) || session.phase === "error") return;
185
+ const final = [];
186
+ const interim = [];
187
+ const chunks = [];
188
+ for (let i = 0; i < event.results.length; i++) {
189
+ const result = event.results[i];
190
+ if (!result) continue;
191
+ const text = result[0].transcript.trim();
192
+ if (result.isFinal) {
193
+ final.push(text);
194
+ if (!session.notified.has(i)) {
195
+ session.notified.add(i);
196
+ if (text) chunks.push(text);
197
+ }
198
+ } else interim.push(text);
199
+ }
200
+ session.transcript = final.join(" ");
201
+ session.interim = interim.join(" ");
202
+ setSnapshot((previous) => ({ ...previous, transcript: session.transcript, interimTranscript: session.interim }));
203
+ if (chunks.length) _optionalChain([callback, 'access', _24 => _24.current, 'optionalCall', _25 => _25(chunks.join(" "))]);
204
+ };
205
+ recognition.onend = () => {
206
+ session.nativeEnded = true;
207
+ session.resolveNativeEnd();
208
+ if (isCurrent(session) && session.phase === "recording") {
209
+ session.phase = "ready";
210
+ setSnapshot((previous) => ({ ...previous, state: "ready" }));
211
+ }
212
+ };
213
+ recognition.onerror = (event) => {
214
+ if (!isCurrent(session)) return;
215
+ session.phase = "error";
216
+ session.nativeEnded = true;
217
+ session.resolveNativeEnd();
218
+ setSnapshot((previous) => ({ ...previous, state: "error", error: recognitionError(event.error) }));
219
+ };
220
+ recognition.start();
221
+ session.phase = "recording";
222
+ setSnapshot({ ...EMPTY, state: "recording" });
223
+ } catch (error) {
224
+ if (!isCurrent(session)) return;
225
+ session.phase = "error";
226
+ setSnapshot({ ...EMPTY, state: "error", error: microphoneError(error) });
227
+ }
228
+ }, [cancel, continuous, isCurrent, lang, scope, scopeGeneration, transcribe]);
229
+ const finish = _react.useCallback.call(void 0, async (session) => {
230
+ if (!isCurrent(session)) return null;
231
+ session.phase = "transcribing";
232
+ setSnapshot((previous) => ({ ...previous, state: "transcribing", error: null, canRetry: false }));
233
+ if (!session.transcribe) {
234
+ if (!session.nativeEnded) {
235
+ session.nativeTimer = setTimeout(() => {
236
+ try {
237
+ _optionalChain([session, 'access', _26 => _26.recognition, 'optionalAccess', _27 => _27.abort, 'call', _28 => _28()]);
238
+ } catch (e3) {
239
+ }
240
+ session.resolveNativeEnd();
241
+ }, 1e3);
242
+ try {
243
+ _optionalChain([session, 'access', _29 => _29.recognition, 'optionalAccess', _30 => _30.stop, 'call', _31 => _31()]);
244
+ } catch (e4) {
245
+ session.resolveNativeEnd();
246
+ }
247
+ await session.nativeEnd;
248
+ clearTimeout(session.nativeTimer);
249
+ }
250
+ if (!isCurrent(session) || session.phase === "error") return null;
251
+ const text2 = [session.transcript, session.interim].filter(Boolean).join(" ").trim();
252
+ session.phase = "ready";
253
+ setSnapshot({ ...EMPTY, state: "ready", transcript: text2 });
254
+ return text2;
255
+ }
256
+ let text;
257
+ try {
258
+ if (!session.blob) {
259
+ if (_optionalChain([session, 'access', _32 => _32.recorder, 'optionalAccess', _33 => _33.state]) !== "inactive") _optionalChain([session, 'access', _34 => _34.recorder, 'optionalAccess', _35 => _35.stop, 'call', _36 => _36()]);
260
+ const blob = await session.capture;
261
+ if (!isCurrent(session) || !blob) return null;
262
+ session.blob = blob;
263
+ }
264
+ if (!session.blob.size) throw new Error("No audio was recorded. Try again.");
265
+ text = (await session.transcribe(session.blob, { language: session.language, signal: session.controller.signal })).trim();
266
+ if (!isCurrent(session)) return null;
267
+ if (!text) throw new Error("No speech was detected. Record again.");
268
+ } catch (error) {
269
+ if (!isCurrent(session)) return null;
270
+ releaseTracks(session);
271
+ session.phase = "error";
272
+ const message = error instanceof Error && error.message ? error.message : "Transcription failed. Try again.";
273
+ setSnapshot({ ...EMPTY, state: "error", error: message, canRetry: !!_optionalChain([session, 'access', _37 => _37.blob, 'optionalAccess', _38 => _38.size]) });
274
+ return null;
275
+ }
276
+ session.transcript = text;
277
+ session.phase = "ready";
278
+ setSnapshot({ ...EMPTY, state: "ready", transcript: text });
279
+ _optionalChain([callback, 'access', _39 => _39.current, 'optionalCall', _40 => _40(text)]);
280
+ return text;
281
+ }, [isCurrent]);
282
+ const stop = _react.useCallback.call(void 0, () => {
283
+ const session = current.current;
284
+ if (!session) return Promise.resolve(null);
285
+ if (!isCurrent(session)) {
286
+ cancel();
287
+ return Promise.resolve(null);
288
+ }
289
+ if (session.phase === "requesting") {
290
+ cancel();
291
+ return Promise.resolve(null);
292
+ }
293
+ if (session.finish) return session.finish;
294
+ if (session.phase === "error") return Promise.resolve(null);
295
+ session.finish = finish(session);
296
+ return session.finish;
297
+ }, [cancel, finish, isCurrent]);
298
+ const retry = _react.useCallback.call(void 0, () => {
299
+ const session = current.current;
300
+ if (session && !isCurrent(session)) {
301
+ cancel();
302
+ return Promise.resolve(null);
303
+ }
304
+ if (!_optionalChain([session, 'optionalAccess', _41 => _41.transcribe]) || !_optionalChain([session, 'access', _42 => _42.blob, 'optionalAccess', _43 => _43.size])) return Promise.resolve(null);
305
+ if (session.phase !== "error") return _nullishCoalesce(session.finish, () => ( Promise.resolve(null)));
306
+ session.finish = finish(session);
307
+ return session.finish;
308
+ }, [cancel, finish, isCurrent]);
309
+ const visibleSnapshot = current.current && !isCurrent(current.current) ? EMPTY : snapshot;
310
+ return { ...visibleSnapshot, supported, start, stop, retry, cancel };
311
+ }
312
+
313
+
314
+
315
+
316
+ exports.DictationProvider = DictationProvider; exports.useDictation = useDictation;
@@ -0,0 +1,127 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }"use client";
2
+
3
+
4
+ var _chunkXB2D4NQKcjs = require('./chunk-XB2D4NQK.cjs');
5
+
6
+
7
+ var _chunkJDEXZGIYcjs = require('./chunk-JDEXZGIY.cjs');
8
+
9
+
10
+ var _chunkKWLSBTB2cjs = require('./chunk-KWLSBTB2.cjs');
11
+
12
+ // src/primitives/voice-session-controls.tsx
13
+ var _react = require('react');
14
+ var _lucidereact = require('lucide-react');
15
+ var _jsxruntime = require('react/jsx-runtime');
16
+ var SILENCE = [];
17
+ var silence = () => SILENCE;
18
+ var noSubscription = () => () => {
19
+ };
20
+ var DEFAULT_LABELS = {
21
+ disconnected: "Voice chat",
22
+ connecting: "Connecting\u2026",
23
+ listening: "Listening",
24
+ thinking: "Thinking\u2026",
25
+ speaking: "Speaking",
26
+ reconnecting: "Reconnecting\u2026",
27
+ error: "Voice chat unavailable",
28
+ start: "Start voice chat",
29
+ end: "End voice chat",
30
+ mute: "Mute microphone",
31
+ unmute: "Unmute microphone",
32
+ muted: "Microphone muted",
33
+ retry: "Retry voice chat"
34
+ };
35
+ function VoiceSessionControls({
36
+ state,
37
+ onStart,
38
+ onEnd,
39
+ muted = false,
40
+ onMutedChange,
41
+ disabled = false,
42
+ error,
43
+ volumeBands,
44
+ audioLevels,
45
+ labels,
46
+ size = "icon",
47
+ className
48
+ }) {
49
+ const liveBands = _react.useSyncExternalStore.call(void 0, _nullishCoalesce(_optionalChain([audioLevels, 'optionalAccess', _ => _.subscribe]), () => ( noSubscription)), _nullishCoalesce(_optionalChain([audioLevels, 'optionalAccess', _2 => _2.getSnapshot]), () => ( silence)), silence);
50
+ const copy = { ...DEFAULT_LABELS, ...labels };
51
+ const active = state !== "disconnected" && state !== "error";
52
+ const waiting = state === "connecting" || state === "reconnecting";
53
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
54
+ "div",
55
+ {
56
+ "data-slot": "voice-session-controls",
57
+ "data-state": state,
58
+ className: _chunkKWLSBTB2cjs.cn.call(void 0, "flex min-w-0 items-center gap-2", active && "w-full flex-col gap-3 py-4", !active && "flex-wrap", className),
59
+ children: [
60
+ active ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
61
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
62
+ _chunkXB2D4NQKcjs.AgentAudioVisualizerBar,
63
+ {
64
+ "aria-hidden": "true",
65
+ size: "sm",
66
+ barCount: 5,
67
+ state: state === "reconnecting" ? "connecting" : state,
68
+ volumeBands: _nullishCoalesce(volumeBands, () => ( liveBands))
69
+ }
70
+ ),
71
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { role: "status", className: "text-sm text-muted-foreground", children: muted && state === "listening" ? copy.muted : copy[state] }),
72
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-2", children: [
73
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
74
+ _chunkJDEXZGIYcjs.Button,
75
+ {
76
+ type: "button",
77
+ variant: "ghost",
78
+ size: "icon",
79
+ className: "min-h-[44px] min-w-[44px] shrink-0",
80
+ "aria-label": muted ? copy.unmute : copy.mute,
81
+ title: muted ? copy.unmute : copy.mute,
82
+ "aria-pressed": muted,
83
+ disabled: waiting,
84
+ onClick: () => onMutedChange(!muted),
85
+ children: muted ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.MicOff, { "aria-hidden": "true" }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.Mic, { "aria-hidden": "true" })
86
+ }
87
+ ),
88
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
89
+ _chunkJDEXZGIYcjs.Button,
90
+ {
91
+ type: "button",
92
+ variant: "outline",
93
+ shape: "pill",
94
+ className: "min-h-[44px] shrink-0",
95
+ "aria-label": copy.end,
96
+ title: copy.end,
97
+ onClick: onEnd,
98
+ children: [
99
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.PhoneOff, { "aria-hidden": "true" }),
100
+ copy.end
101
+ ]
102
+ }
103
+ )
104
+ ] })
105
+ ] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
106
+ _chunkJDEXZGIYcjs.Button,
107
+ {
108
+ type: "button",
109
+ size: "icon",
110
+ shape: "circle",
111
+ disabled,
112
+ onClick: onStart,
113
+ "aria-label": state === "error" ? copy.retry : copy.start,
114
+ title: state === "error" ? copy.retry : copy.start,
115
+ className: _chunkKWLSBTB2cjs.cn.call(void 0, "min-h-[44px] min-w-[44px] shrink-0 rounded-full", size === "hero" && "size-24 [&_svg]:size-7"),
116
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.AudioLines, { "aria-hidden": "true" })
117
+ }
118
+ ),
119
+ state === "error" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { role: "alert", className: "basis-full text-xs text-destructive", children: error || copy.error })
120
+ ]
121
+ }
122
+ );
123
+ }
124
+
125
+
126
+
127
+ exports.VoiceSessionControls = VoiceSessionControls;
@@ -0,0 +1,157 @@
1
+ "use client";
2
+ import {
3
+ cn
4
+ } from "./chunk-G6SRSWXB.js";
5
+ import {
6
+ useAgentAudioVisualizerBarAnimator
7
+ } from "./chunk-GJ7S3L6R.js";
8
+
9
+ // src/primitives/agent-audio-visualizer-bar.tsx
10
+ import React, {
11
+ Children,
12
+ cloneElement,
13
+ isValidElement,
14
+ useMemo
15
+ } from "react";
16
+ import { cva } from "class-variance-authority";
17
+ import { jsx } from "react/jsx-runtime";
18
+ function normalizeVolumeBands(bands, count) {
19
+ if (bands.length === count) return bands;
20
+ if (bands.length > count) return bands.slice(0, count);
21
+ const lastValue = bands[bands.length - 1] ?? 0;
22
+ return [...bands, ...new Array(count - bands.length).fill(lastValue)];
23
+ }
24
+ function cloneSingleChild(children, props, key) {
25
+ return Children.map(children, (child) => {
26
+ if (isValidElement(child) && Children.only(children)) {
27
+ const childProps = child.props;
28
+ if (childProps.className) {
29
+ props ??= {};
30
+ props.className = cn(childProps.className, props.className);
31
+ props.style = {
32
+ ...childProps.style,
33
+ ...props.style
34
+ };
35
+ }
36
+ return cloneElement(child, { ...props, key: key ? String(key) : void 0 });
37
+ }
38
+ return child;
39
+ });
40
+ }
41
+ var AgentAudioVisualizerBarElementVariants = cva(
42
+ [
43
+ "rounded-full transition-colors duration-250 ease-linear motion-reduce:transition-none",
44
+ "bg-current/10 data-[lk-highlighted=true]:bg-current"
45
+ ],
46
+ {
47
+ variants: {
48
+ size: {
49
+ icon: "w-[4px] min-h-[4px]",
50
+ sm: "w-[8px] min-h-[8px]",
51
+ md: "w-[16px] min-h-[16px]",
52
+ lg: "w-[32px] min-h-[32px]",
53
+ xl: "w-[64px] min-h-[64px]"
54
+ }
55
+ },
56
+ defaultVariants: {
57
+ size: "md"
58
+ }
59
+ }
60
+ );
61
+ var AgentAudioVisualizerBarVariants = cva("relative flex items-center justify-center", {
62
+ variants: {
63
+ size: {
64
+ icon: "h-[24px] gap-[2px]",
65
+ sm: "h-[56px] gap-[4px]",
66
+ md: "h-[112px] gap-[8px]",
67
+ lg: "h-[224px] gap-[16px]",
68
+ xl: "h-[448px] gap-[32px]"
69
+ }
70
+ },
71
+ defaultVariants: {
72
+ size: "md"
73
+ }
74
+ });
75
+ function AgentAudioVisualizerBar({
76
+ size = "md",
77
+ state = "connecting",
78
+ color,
79
+ barCount,
80
+ volumeBands,
81
+ className,
82
+ children,
83
+ style,
84
+ ...props
85
+ }) {
86
+ const _barCount = useMemo(() => {
87
+ if (barCount && Number.isFinite(barCount)) {
88
+ return Math.max(1, Math.min(64, Math.floor(barCount)));
89
+ }
90
+ switch (size) {
91
+ case "icon":
92
+ case "sm":
93
+ return 3;
94
+ default:
95
+ return 5;
96
+ }
97
+ }, [barCount, size]);
98
+ const resolvedVolumeBands = normalizeVolumeBands(volumeBands ?? [], _barCount).map((value) => Number.isFinite(value) ? Math.max(0, Math.min(1, value)) : 0);
99
+ const sequencerInterval = useMemo(() => {
100
+ switch (state) {
101
+ case "connecting":
102
+ return 2e3 / _barCount;
103
+ case "initializing":
104
+ return 2e3;
105
+ case "listening":
106
+ return 500;
107
+ case "thinking":
108
+ return 150;
109
+ default:
110
+ return 1e3;
111
+ }
112
+ }, [state, _barCount]);
113
+ const highlightedIndices = useAgentAudioVisualizerBarAnimator(
114
+ state,
115
+ _barCount,
116
+ sequencerInterval
117
+ );
118
+ const bands = useMemo(
119
+ () => state === "speaking" ? resolvedVolumeBands : new Array(_barCount).fill(0),
120
+ [state, resolvedVolumeBands, _barCount]
121
+ );
122
+ if (children && Array.isArray(children)) {
123
+ throw new Error("AgentAudioVisualizerBar children must be a single element.");
124
+ }
125
+ return /* @__PURE__ */ jsx(
126
+ "div",
127
+ {
128
+ "data-lk-state": state,
129
+ style: { ...style, color },
130
+ className: cn(AgentAudioVisualizerBarVariants({ size }), className),
131
+ ...props,
132
+ children: bands.map(
133
+ (band, idx) => children ? /* @__PURE__ */ jsx(React.Fragment, { children: cloneSingleChild(children, {
134
+ "data-lk-index": idx,
135
+ "data-lk-highlighted": highlightedIndices.includes(idx),
136
+ style: { height: `${band * 100}%` }
137
+ }) }, idx) : /* @__PURE__ */ jsx(
138
+ "div",
139
+ {
140
+ "data-lk-index": idx,
141
+ "data-lk-highlighted": highlightedIndices.includes(idx),
142
+ style: { height: `${band * 100}%` },
143
+ className: cn(AgentAudioVisualizerBarElementVariants({ size }))
144
+ },
145
+ idx
146
+ )
147
+ )
148
+ }
149
+ );
150
+ }
151
+
152
+ export {
153
+ normalizeVolumeBands,
154
+ AgentAudioVisualizerBarElementVariants,
155
+ AgentAudioVisualizerBarVariants,
156
+ AgentAudioVisualizerBar
157
+ };