@epicbagel/saas-kit 1.10.0 → 1.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +21 -3
  2. package/dist/{chunk-VBKJXNEL.js → chunk-5OF6D3GH.js} +4 -3
  3. package/dist/chunk-D47AMKT4.cjs +293 -0
  4. package/dist/chunk-EDEN7TAL.js +293 -0
  5. package/dist/{chunk-M2ZNC3TK.js → chunk-HLAHOVEI.js} +98 -2
  6. package/dist/{chunk-KUG4ONYC.js → chunk-KF4X37DP.js} +40 -27
  7. package/dist/{chunk-XB2D4NQK.cjs → chunk-NKWHDI4C.cjs} +4 -3
  8. package/dist/{chunk-UW67GSZ4.cjs → chunk-YMI3X2YL.cjs} +38 -25
  9. package/dist/{chunk-O6F3LVZY.cjs → chunk-ZZ7ICQR2.cjs} +120 -24
  10. package/dist/hooks/use-dictation.cjs +2 -2
  11. package/dist/hooks/use-dictation.d.cts +5 -0
  12. package/dist/hooks/use-dictation.d.ts +5 -0
  13. package/dist/hooks/use-dictation.js +1 -1
  14. package/dist/primitives/agent-audio-visualizer-bar.cjs +2 -2
  15. package/dist/primitives/agent-audio-visualizer-bar.d.cts +1 -1
  16. package/dist/primitives/agent-audio-visualizer-bar.d.ts +1 -1
  17. package/dist/primitives/agent-audio-visualizer-bar.js +1 -1
  18. package/dist/primitives/alert.d.cts +1 -1
  19. package/dist/primitives/alert.d.ts +1 -1
  20. package/dist/primitives/badge.d.cts +1 -1
  21. package/dist/primitives/badge.d.ts +1 -1
  22. package/dist/primitives/bubble.d.cts +1 -1
  23. package/dist/primitives/bubble.d.ts +1 -1
  24. package/dist/primitives/button.d.cts +2 -2
  25. package/dist/primitives/button.d.ts +2 -2
  26. package/dist/primitives/chat.cjs +15 -15
  27. package/dist/primitives/chat.d.cts +2 -2
  28. package/dist/primitives/chat.d.ts +2 -2
  29. package/dist/primitives/chat.js +10 -10
  30. package/dist/primitives/dictation-provider.cjs +2 -2
  31. package/dist/primitives/dictation-provider.js +1 -1
  32. package/dist/primitives/voice-dictation-button.cjs +5 -3
  33. package/dist/primitives/voice-dictation-button.d.cts +9 -11
  34. package/dist/primitives/voice-dictation-button.d.ts +9 -11
  35. package/dist/primitives/voice-dictation-button.js +4 -2
  36. package/dist/primitives/voice-session-controls.cjs +3 -3
  37. package/dist/primitives/voice-session-controls.d.cts +3 -1
  38. package/dist/primitives/voice-session-controls.d.ts +3 -1
  39. package/dist/primitives/voice-session-controls.js +2 -2
  40. package/package.json +1 -1
  41. package/dist/chunk-HTCW6AEH.cjs +0 -223
  42. package/dist/chunk-KWV5KTOA.js +0 -223
@@ -12,6 +12,94 @@ function DictationProvider({ transcribe, scopeKey, children }) {
12
12
  }
13
13
  var EMPTY = { state: "idle", transcript: "", interimTranscript: "", error: null, canRetry: false };
14
14
  var MIME_TYPES = ["audio/webm;codecs=opus", "audio/mp4", "audio/ogg;codecs=opus", "audio/webm"];
15
+ var SILENCE = [];
16
+ function createAudioLevels() {
17
+ let bands = SILENCE;
18
+ const listeners = /* @__PURE__ */ new Set();
19
+ return {
20
+ subscribe: (listener) => {
21
+ listeners.add(listener);
22
+ return () => {
23
+ listeners.delete(listener);
24
+ };
25
+ },
26
+ getSnapshot: () => bands,
27
+ update: (next) => {
28
+ if (next.length === bands.length && next.every((value, index) => value === bands[index])) return;
29
+ bands = next;
30
+ listeners.forEach((listener) => listener());
31
+ }
32
+ };
33
+ }
34
+ function meterStream(stream, levels, active) {
35
+ let context;
36
+ let source;
37
+ let analyser;
38
+ let frame;
39
+ let stopped = false;
40
+ const stop = () => {
41
+ if (stopped) return;
42
+ stopped = true;
43
+ if (frame !== void 0) cancelAnimationFrame(frame);
44
+ try {
45
+ source?.disconnect();
46
+ } catch {
47
+ }
48
+ try {
49
+ analyser?.disconnect();
50
+ } catch {
51
+ }
52
+ try {
53
+ void context?.close().catch(() => {
54
+ });
55
+ } catch {
56
+ }
57
+ levels.update(SILENCE);
58
+ };
59
+ try {
60
+ const Constructor = window.AudioContext ?? window.webkitAudioContext;
61
+ if (!Constructor || typeof requestAnimationFrame !== "function") return stop;
62
+ context = new Constructor();
63
+ source = context.createMediaStreamSource(stream);
64
+ analyser = context.createAnalyser();
65
+ analyser.fftSize = 512;
66
+ analyser.smoothingTimeConstant = 0.7;
67
+ source.connect(analyser);
68
+ const bins = new Uint8Array(analyser.frequencyBinCount);
69
+ const binWidth = context.sampleRate / analyser.fftSize;
70
+ const highest = Math.min(8e3, context.sampleRate / 2);
71
+ let sampledAt = -Infinity;
72
+ const sample = (time) => {
73
+ if (stopped) return;
74
+ if (!active()) {
75
+ stop();
76
+ return;
77
+ }
78
+ try {
79
+ if (time - sampledAt >= 40) {
80
+ sampledAt = time;
81
+ analyser.getByteFrequencyData(bins);
82
+ const bands = Array.from({ length: 24 }, (_, index) => {
83
+ const from = Math.min(bins.length - 1, Math.floor(80 * (highest / 80) ** (index / 24) / binWidth));
84
+ const to = Math.min(bins.length, Math.max(from + 1, Math.ceil(80 * (highest / 80) ** ((index + 1) / 24) / binWidth)));
85
+ let total = 0;
86
+ for (let bin = from; bin < to; bin++) total += bins[bin];
87
+ return Math.round(total / (to - from) / 255 * 1e3) / 1e3;
88
+ });
89
+ levels.update(bands);
90
+ }
91
+ frame = requestAnimationFrame(sample);
92
+ } catch {
93
+ stop();
94
+ }
95
+ };
96
+ if (context.state === "suspended") void context.resume().catch(stop);
97
+ frame = requestAnimationFrame(sample);
98
+ } catch {
99
+ stop();
100
+ }
101
+ return stop;
102
+ }
15
103
  function recognitionConstructor() {
16
104
  if (typeof window === "undefined") return void 0;
17
105
  const speech = window;
@@ -29,7 +117,12 @@ function recognitionError(code) {
29
117
  if (code === "no-speech") return "No speech was detected. Try again.";
30
118
  return "Speech recognition stopped. Try again.";
31
119
  }
120
+ function releaseMeter(session) {
121
+ session.stopMeter?.();
122
+ session.stopMeter = void 0;
123
+ }
32
124
  function releaseTracks(session) {
125
+ releaseMeter(session);
33
126
  session.stream?.getTracks().forEach((track) => track.stop());
34
127
  session.stream = void 0;
35
128
  }
@@ -123,7 +216,8 @@ function useDictation({ lang = "en-US", continuous = true, onTranscript } = {})
123
216
  nativeEnded: false,
124
217
  transcript: "",
125
218
  interim: "",
126
- notified: /* @__PURE__ */ new Set()
219
+ notified: /* @__PURE__ */ new Set(),
220
+ audioLevels: transcribe ? createAudioLevels() : void 0
127
221
  };
128
222
  current.current = session;
129
223
  setSnapshot({ ...EMPTY, state: "requesting" });
@@ -163,6 +257,7 @@ function useDictation({ lang = "en-US", continuous = true, onTranscript } = {})
163
257
  };
164
258
  recorder.start();
165
259
  session.phase = "recording";
260
+ session.stopMeter = meterStream(stream, session.audioLevels, () => isCurrent(session) && session.phase === "recording");
166
261
  setSnapshot({ ...EMPTY, state: "recording" });
167
262
  } catch (error) {
168
263
  releaseTracks(session);
@@ -228,6 +323,7 @@ function useDictation({ lang = "en-US", continuous = true, onTranscript } = {})
228
323
  }, [cancel, continuous, isCurrent, lang, scope, scopeGeneration, transcribe]);
229
324
  const finish = useCallback(async (session) => {
230
325
  if (!isCurrent(session)) return null;
326
+ releaseMeter(session);
231
327
  session.phase = "transcribing";
232
328
  setSnapshot((previous) => ({ ...previous, state: "transcribing", error: null, canRetry: false }));
233
329
  if (!session.transcribe) {
@@ -307,7 +403,7 @@ function useDictation({ lang = "en-US", continuous = true, onTranscript } = {})
307
403
  return session.finish;
308
404
  }, [cancel, finish, isCurrent]);
309
405
  const visibleSnapshot = current.current && !isCurrent(current.current) ? EMPTY : snapshot;
310
- return { ...visibleSnapshot, supported, start, stop, retry, cancel };
406
+ return { ...visibleSnapshot, audioLevels: current.current && isCurrent(current.current) ? current.current.audioLevels : void 0, supported, start, stop, retry, cancel };
311
407
  }
312
408
 
313
409
  export {
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import {
3
3
  AgentAudioVisualizerBar
4
- } from "./chunk-VBKJXNEL.js";
4
+ } from "./chunk-5OF6D3GH.js";
5
5
  import {
6
6
  Button
7
7
  } from "./chunk-W326GKML.js";
@@ -11,8 +11,8 @@ import {
11
11
 
12
12
  // src/primitives/voice-session-controls.tsx
13
13
  import { useSyncExternalStore } from "react";
14
- import { Mic, MicOff, PhoneOff, AudioLines } from "lucide-react";
15
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
14
+ import { Mic, MicOff, Square, AudioLines } from "lucide-react";
15
+ import { jsx, jsxs } from "react/jsx-runtime";
16
16
  var SILENCE = [];
17
17
  var silence = () => SILENCE;
18
18
  var noSubscription = () => () => {
@@ -20,7 +20,7 @@ var noSubscription = () => () => {
20
20
  var DEFAULT_LABELS = {
21
21
  disconnected: "Voice chat",
22
22
  connecting: "Connecting\u2026",
23
- listening: "Listening",
23
+ listening: "Listening\u2026",
24
24
  thinking: "Thinking\u2026",
25
25
  speaking: "Speaking",
26
26
  reconnecting: "Reconnecting\u2026",
@@ -30,7 +30,10 @@ var DEFAULT_LABELS = {
30
30
  mute: "Mute microphone",
31
31
  unmute: "Unmute microphone",
32
32
  muted: "Microphone muted",
33
- retry: "Retry voice chat"
33
+ retry: "Retry voice chat",
34
+ endShort: "End voice",
35
+ muteShort: "Mute",
36
+ unmuteShort: "Unmute"
34
37
  };
35
38
  function VoiceSessionControls({
36
39
  state,
@@ -55,34 +58,44 @@ function VoiceSessionControls({
55
58
  {
56
59
  "data-slot": "voice-session-controls",
57
60
  "data-state": state,
58
- className: cn("flex min-w-0 items-center gap-2", active && "w-full flex-col gap-3 py-4", !active && "flex-wrap", className),
61
+ className: cn("min-w-0", active ? "@container/voice w-full" : "flex flex-wrap items-center gap-2", className),
59
62
  children: [
60
- active ? /* @__PURE__ */ jsxs(Fragment, { children: [
61
- /* @__PURE__ */ jsx(
62
- AgentAudioVisualizerBar,
63
- {
64
- "aria-hidden": "true",
65
- size: "sm",
66
- barCount: 5,
67
- state: state === "reconnecting" ? "connecting" : state,
68
- volumeBands: volumeBands ?? liveBands
69
- }
70
- ),
71
- /* @__PURE__ */ jsx("span", { role: "status", className: "text-sm text-muted-foreground", children: muted && state === "listening" ? copy.muted : copy[state] }),
72
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
63
+ active ? /* @__PURE__ */ jsxs("div", { "data-slot": "voice-session-strip", className: "flex w-full flex-wrap items-center gap-4 bg-primary/5 p-4 @2xl/voice:flex-nowrap @2xl/voice:px-5", children: [
64
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 basis-full items-center gap-3 @2xl/voice:basis-auto @2xl/voice:gap-4", children: [
65
+ /* @__PURE__ */ jsx("div", { "aria-hidden": "true", className: cn(
66
+ "flex size-12 shrink-0 items-center justify-center rounded-full ring-8 ring-primary/5 @sm/voice:size-14",
67
+ muted ? "bg-muted text-muted-foreground" : "bg-primary text-primary-foreground"
68
+ ), children: muted ? /* @__PURE__ */ jsx(MicOff, { className: "size-5" }) : /* @__PURE__ */ jsx(Mic, { className: "size-5" }) }),
73
69
  /* @__PURE__ */ jsx(
70
+ AgentAudioVisualizerBar,
71
+ {
72
+ "aria-hidden": "true",
73
+ size: "sm",
74
+ barCount: 5,
75
+ className: "shrink-0 text-primary [&>div]:w-1",
76
+ state: muted && state === "listening" ? "disconnected" : state === "reconnecting" ? "connecting" : state,
77
+ volumeBands: muted && state === "listening" ? SILENCE : volumeBands ?? liveBands
78
+ }
79
+ ),
80
+ /* @__PURE__ */ jsx("span", { role: "status", className: "min-w-0 flex-1 text-sm font-medium text-primary", children: muted && state === "listening" ? copy.muted : copy[state] })
81
+ ] }),
82
+ /* @__PURE__ */ jsxs("div", { className: "ml-auto flex shrink-0 items-center gap-2", children: [
83
+ /* @__PURE__ */ jsxs(
74
84
  Button,
75
85
  {
76
86
  type: "button",
77
- variant: "ghost",
78
- size: "icon",
79
- className: "min-h-[44px] min-w-[44px] shrink-0",
87
+ variant: "outline",
88
+ size: "sm",
89
+ className: "min-h-[44px] shrink-0 rounded-xl bg-background px-3 text-foreground",
80
90
  "aria-label": muted ? copy.unmute : copy.mute,
81
91
  title: muted ? copy.unmute : copy.mute,
82
92
  "aria-pressed": muted,
83
93
  disabled: waiting,
84
94
  onClick: () => onMutedChange(!muted),
85
- children: muted ? /* @__PURE__ */ jsx(MicOff, { "aria-hidden": "true" }) : /* @__PURE__ */ jsx(Mic, { "aria-hidden": "true" })
95
+ children: [
96
+ muted ? /* @__PURE__ */ jsx(Mic, { "aria-hidden": "true" }) : /* @__PURE__ */ jsx(MicOff, { "aria-hidden": "true" }),
97
+ muted ? copy.unmuteShort : copy.muteShort
98
+ ]
86
99
  }
87
100
  ),
88
101
  /* @__PURE__ */ jsxs(
@@ -90,14 +103,14 @@ function VoiceSessionControls({
90
103
  {
91
104
  type: "button",
92
105
  variant: "outline",
93
- shape: "pill",
94
- className: "min-h-[44px] shrink-0",
106
+ size: "sm",
107
+ className: "min-h-[44px] shrink-0 rounded-xl bg-background px-3 text-foreground",
95
108
  "aria-label": copy.end,
96
109
  title: copy.end,
97
110
  onClick: onEnd,
98
111
  children: [
99
- /* @__PURE__ */ jsx(PhoneOff, { "aria-hidden": "true" }),
100
- copy.end
112
+ /* @__PURE__ */ jsx(Square, { "aria-hidden": "true", className: "fill-current" }),
113
+ copy.endShort
101
114
  ]
102
115
  }
103
116
  )
@@ -110,14 +110,15 @@ function AgentAudioVisualizerBar({
110
110
  return 1e3;
111
111
  }
112
112
  }, [state, _barCount]);
113
+ const meteredListening = state === "listening" && volumeBands !== void 0;
113
114
  const highlightedIndices = _chunk2BSFYU22cjs.useAgentAudioVisualizerBarAnimator.call(void 0,
114
- state,
115
+ meteredListening ? "speaking" : state,
115
116
  _barCount,
116
117
  sequencerInterval
117
118
  );
118
119
  const bands = _react.useMemo.call(void 0,
119
- () => state === "speaking" ? resolvedVolumeBands : new Array(_barCount).fill(0),
120
- [state, resolvedVolumeBands, _barCount]
120
+ () => state === "speaking" || meteredListening ? resolvedVolumeBands : new Array(_barCount).fill(0),
121
+ [state, meteredListening, resolvedVolumeBands, _barCount]
121
122
  );
122
123
  if (children && Array.isArray(children)) {
123
124
  throw new Error("AgentAudioVisualizerBar children must be a single element.");
@@ -1,7 +1,7 @@
1
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
2
 
3
3
 
4
- var _chunkXB2D4NQKcjs = require('./chunk-XB2D4NQK.cjs');
4
+ var _chunkNKWHDI4Ccjs = require('./chunk-NKWHDI4C.cjs');
5
5
 
6
6
 
7
7
  var _chunkJDEXZGIYcjs = require('./chunk-JDEXZGIY.cjs');
@@ -20,7 +20,7 @@ var noSubscription = () => () => {
20
20
  var DEFAULT_LABELS = {
21
21
  disconnected: "Voice chat",
22
22
  connecting: "Connecting\u2026",
23
- listening: "Listening",
23
+ listening: "Listening\u2026",
24
24
  thinking: "Thinking\u2026",
25
25
  speaking: "Speaking",
26
26
  reconnecting: "Reconnecting\u2026",
@@ -30,7 +30,10 @@ var DEFAULT_LABELS = {
30
30
  mute: "Mute microphone",
31
31
  unmute: "Unmute microphone",
32
32
  muted: "Microphone muted",
33
- retry: "Retry voice chat"
33
+ retry: "Retry voice chat",
34
+ endShort: "End voice",
35
+ muteShort: "Mute",
36
+ unmuteShort: "Unmute"
34
37
  };
35
38
  function VoiceSessionControls({
36
39
  state,
@@ -55,34 +58,44 @@ function VoiceSessionControls({
55
58
  {
56
59
  "data-slot": "voice-session-controls",
57
60
  "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),
61
+ className: _chunkKWLSBTB2cjs.cn.call(void 0, "min-w-0", active ? "@container/voice w-full" : "flex flex-wrap items-center gap-2", className),
59
62
  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: [
63
+ active ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { "data-slot": "voice-session-strip", className: "flex w-full flex-wrap items-center gap-4 bg-primary/5 p-4 @2xl/voice:flex-nowrap @2xl/voice:px-5", children: [
64
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex min-w-0 flex-1 basis-full items-center gap-3 @2xl/voice:basis-auto @2xl/voice:gap-4", children: [
65
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { "aria-hidden": "true", className: _chunkKWLSBTB2cjs.cn.call(void 0,
66
+ "flex size-12 shrink-0 items-center justify-center rounded-full ring-8 ring-primary/5 @sm/voice:size-14",
67
+ muted ? "bg-muted text-muted-foreground" : "bg-primary text-primary-foreground"
68
+ ), children: muted ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.MicOff, { className: "size-5" }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.Mic, { className: "size-5" }) }),
73
69
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
70
+ _chunkNKWHDI4Ccjs.AgentAudioVisualizerBar,
71
+ {
72
+ "aria-hidden": "true",
73
+ size: "sm",
74
+ barCount: 5,
75
+ className: "shrink-0 text-primary [&>div]:w-1",
76
+ state: muted && state === "listening" ? "disconnected" : state === "reconnecting" ? "connecting" : state,
77
+ volumeBands: muted && state === "listening" ? SILENCE : _nullishCoalesce(volumeBands, () => ( liveBands))
78
+ }
79
+ ),
80
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { role: "status", className: "min-w-0 flex-1 text-sm font-medium text-primary", children: muted && state === "listening" ? copy.muted : copy[state] })
81
+ ] }),
82
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "ml-auto flex shrink-0 items-center gap-2", children: [
83
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
74
84
  _chunkJDEXZGIYcjs.Button,
75
85
  {
76
86
  type: "button",
77
- variant: "ghost",
78
- size: "icon",
79
- className: "min-h-[44px] min-w-[44px] shrink-0",
87
+ variant: "outline",
88
+ size: "sm",
89
+ className: "min-h-[44px] shrink-0 rounded-xl bg-background px-3 text-foreground",
80
90
  "aria-label": muted ? copy.unmute : copy.mute,
81
91
  title: muted ? copy.unmute : copy.mute,
82
92
  "aria-pressed": muted,
83
93
  disabled: waiting,
84
94
  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" })
95
+ children: [
96
+ muted ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.Mic, { "aria-hidden": "true" }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.MicOff, { "aria-hidden": "true" }),
97
+ muted ? copy.unmuteShort : copy.muteShort
98
+ ]
86
99
  }
87
100
  ),
88
101
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
@@ -90,14 +103,14 @@ function VoiceSessionControls({
90
103
  {
91
104
  type: "button",
92
105
  variant: "outline",
93
- shape: "pill",
94
- className: "min-h-[44px] shrink-0",
106
+ size: "sm",
107
+ className: "min-h-[44px] shrink-0 rounded-xl bg-background px-3 text-foreground",
95
108
  "aria-label": copy.end,
96
109
  title: copy.end,
97
110
  onClick: onEnd,
98
111
  children: [
99
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.PhoneOff, { "aria-hidden": "true" }),
100
- copy.end
112
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.Square, { "aria-hidden": "true", className: "fill-current" }),
113
+ copy.endShort
101
114
  ]
102
115
  }
103
116
  )