@epicbagel/saas-kit 1.11.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.
@@ -33,8 +33,7 @@ var DEFAULT_LABELS = {
33
33
  retry: "Retry voice chat",
34
34
  endShort: "End voice",
35
35
  muteShort: "Mute",
36
- unmuteShort: "Unmute",
37
- transcriptPlaceholder: "Speak to continue the conversation."
36
+ unmuteShort: "Unmute"
38
37
  };
39
38
  function VoiceSessionControls({
40
39
  state,
@@ -44,7 +43,6 @@ function VoiceSessionControls({
44
43
  onMutedChange,
45
44
  disabled = false,
46
45
  error,
47
- transcript,
48
46
  volumeBands,
49
47
  audioLevels,
50
48
  labels,
@@ -79,18 +77,7 @@ function VoiceSessionControls({
79
77
  volumeBands: muted && state === "listening" ? SILENCE : volumeBands ?? liveBands
80
78
  }
81
79
  ),
82
- /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 space-y-1", children: [
83
- /* @__PURE__ */ jsx("span", { role: "status", className: "block text-sm font-medium text-primary", children: muted && state === "listening" ? copy.muted : copy[state] }),
84
- /* @__PURE__ */ jsx(
85
- "p",
86
- {
87
- "data-slot": "voice-session-transcript",
88
- title: transcript || void 0,
89
- className: cn("truncate text-sm font-normal", transcript ? "text-foreground" : "text-muted-foreground"),
90
- children: transcript || copy.transcriptPlaceholder
91
- }
92
- )
93
- ] })
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] })
94
81
  ] }),
95
82
  /* @__PURE__ */ jsxs("div", { className: "ml-auto flex shrink-0 items-center gap-2", children: [
96
83
  /* @__PURE__ */ jsxs(
@@ -33,8 +33,7 @@ var DEFAULT_LABELS = {
33
33
  retry: "Retry voice chat",
34
34
  endShort: "End voice",
35
35
  muteShort: "Mute",
36
- unmuteShort: "Unmute",
37
- transcriptPlaceholder: "Speak to continue the conversation."
36
+ unmuteShort: "Unmute"
38
37
  };
39
38
  function VoiceSessionControls({
40
39
  state,
@@ -44,7 +43,6 @@ function VoiceSessionControls({
44
43
  onMutedChange,
45
44
  disabled = false,
46
45
  error,
47
- transcript,
48
46
  volumeBands,
49
47
  audioLevels,
50
48
  labels,
@@ -79,18 +77,7 @@ function VoiceSessionControls({
79
77
  volumeBands: muted && state === "listening" ? SILENCE : _nullishCoalesce(volumeBands, () => ( liveBands))
80
78
  }
81
79
  ),
82
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "min-w-0 flex-1 space-y-1", children: [
83
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { role: "status", className: "block text-sm font-medium text-primary", children: muted && state === "listening" ? copy.muted : copy[state] }),
84
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
85
- "p",
86
- {
87
- "data-slot": "voice-session-transcript",
88
- title: transcript || void 0,
89
- className: _chunkKWLSBTB2cjs.cn.call(void 0, "truncate text-sm font-normal", transcript ? "text-foreground" : "text-muted-foreground"),
90
- children: transcript || copy.transcriptPlaceholder
91
- }
92
- )
93
- ] })
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] })
94
81
  ] }),
95
82
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "ml-auto flex shrink-0 items-center gap-2", children: [
96
83
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
@@ -2,7 +2,7 @@
2
2
  "use client";
3
3
 
4
4
 
5
- var _chunk7QTFYEPEcjs = require('../chunk-7QTFYEPE.cjs');
5
+ var _chunkYMI3X2YLcjs = require('../chunk-YMI3X2YL.cjs');
6
6
 
7
7
 
8
8
 
@@ -10,7 +10,7 @@ var _chunk7QTFYEPEcjs = require('../chunk-7QTFYEPE.cjs');
10
10
  var _chunk2BTDBZYNcjs = require('../chunk-2BTDBZYN.cjs');
11
11
 
12
12
 
13
- var _chunkKQBXAQAYcjs = require('../chunk-KQBXAQAY.cjs');
13
+ var _chunkD47AMKT4cjs = require('../chunk-D47AMKT4.cjs');
14
14
 
15
15
 
16
16
 
@@ -465,7 +465,7 @@ function ChatInput({
465
465
  className
466
466
  ),
467
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 }) }),
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, _chunkYMI3X2YLcjs.VoiceSessionControls, { ...voiceSession }) }),
469
469
  attachments.length > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
470
470
  ChatAttachmentList,
471
471
  {
@@ -541,7 +541,7 @@ function ChatInput({
541
541
  ) : null,
542
542
  (!helperText || compact) && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex-1" }),
543
543
  voice && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
544
- _chunkKQBXAQAYcjs.VoiceDictationButton,
544
+ _chunkD47AMKT4cjs.VoiceDictationButton,
545
545
  {
546
546
  size: "icon",
547
547
  title: voiceTitle,
@@ -555,7 +555,7 @@ function ChatInput({
555
555
  )
556
556
  }
557
557
  ),
558
- voiceSession && !liveVoiceActive && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk7QTFYEPEcjs.VoiceSessionControls, { ...voiceSession, disabled: voiceSession.disabled || isDisabled }),
558
+ voiceSession && !liveVoiceActive && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkYMI3X2YLcjs.VoiceSessionControls, { ...voiceSession, disabled: voiceSession.disabled || isDisabled }),
559
559
  submitLabel ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
560
560
  _chunkJDEXZGIYcjs.Button,
561
561
  {
@@ -614,9 +614,9 @@ function VoiceHero({
614
614
  }) {
615
615
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col items-center gap-5 py-6", children: [
616
616
  voiceSession ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
617
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk7QTFYEPEcjs.VoiceSessionControls, { ...voiceSession, size: "hero" }),
617
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkYMI3X2YLcjs.VoiceSessionControls, { ...voiceSession, size: "hero" }),
618
618
  voice && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
619
- _chunkKQBXAQAYcjs.VoiceDictationButton,
619
+ _chunkD47AMKT4cjs.VoiceDictationButton,
620
620
  {
621
621
  size: "icon",
622
622
  title: voiceTitle,
@@ -626,7 +626,7 @@ function VoiceHero({
626
626
  }
627
627
  )
628
628
  ] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
629
- _chunkKQBXAQAYcjs.VoiceDictationButton,
629
+ _chunkD47AMKT4cjs.VoiceDictationButton,
630
630
  {
631
631
  size: "lg",
632
632
  title: voiceTitle,
@@ -2,7 +2,7 @@
2
2
  "use client";
3
3
  import {
4
4
  VoiceSessionControls
5
- } from "../chunk-UOVA4YKW.js";
5
+ } from "../chunk-KF4X37DP.js";
6
6
  import {
7
7
  Trace,
8
8
  TraceLine,
@@ -10,7 +10,7 @@ import {
10
10
  } from "../chunk-Z45YKVAM.js";
11
11
  import {
12
12
  VoiceDictationButton
13
- } from "../chunk-T3XMHWYV.js";
13
+ } from "../chunk-EDEN7TAL.js";
14
14
  import {
15
15
  Suggestion,
16
16
  Suggestions
@@ -2,7 +2,7 @@
2
2
  "use client";
3
3
 
4
4
 
5
- var _chunkKQBXAQAYcjs = require('../chunk-KQBXAQAY.cjs');
5
+ var _chunkD47AMKT4cjs = require('../chunk-D47AMKT4.cjs');
6
6
  require('../chunk-NKWHDI4C.cjs');
7
7
  require('../chunk-JDEXZGIY.cjs');
8
8
  require('../chunk-KWLSBTB2.cjs');
@@ -10,4 +10,4 @@ require('../chunk-2BSFYU22.cjs');
10
10
  require('../chunk-ZZ7ICQR2.cjs');
11
11
 
12
12
 
13
- exports.VoiceDictationButton = _chunkKQBXAQAYcjs.VoiceDictationButton;
13
+ exports.VoiceDictationButton = _chunkD47AMKT4cjs.VoiceDictationButton;
@@ -1,12 +1,12 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { ReactNode } from 'react';
2
+ import { ReactNode, RefObject } from 'react';
3
3
 
4
4
  interface VoiceDictationButtonProps {
5
5
  /** Fired when the user taps "Done" with the captured transcript. */
6
6
  onCommit: (text: string) => void;
7
7
  /** Fired if the user closes the overlay without committing. */
8
8
  onCancel?: () => void;
9
- /** Title shown in the compact recorder. */
9
+ /** Title shown in the recorder. */
10
10
  title?: ReactNode;
11
11
  /** Recording status label. Defaults to "Recording". */
12
12
  caption?: string;
@@ -26,12 +26,14 @@ interface VoiceDictationButtonProps {
26
26
  disabled?: boolean;
27
27
  visibility?: "visible" | "hidden";
28
28
  shrink?: boolean;
29
+ /** Visible desktop anchor for a custom/programmatic trigger. Hidden anchors are ignored. */
30
+ anchorRef?: RefObject<HTMLElement | null>;
29
31
  }
30
32
  /**
31
- * Opens a compact portaled recorder. A fixed panel also works when its
32
- * trigger is hidden or sits inside another dialog. Done finishes the take
33
- * and commits its transcript once; Cancel discards it.
33
+ * Opens beside the invoking control on desktop and fills the screen on
34
+ * mobile, or when no visible anchor exists. Placement changes keep the same
35
+ * recording alive. Done commits its transcript once; Cancel discards it.
34
36
  */
35
- declare function VoiceDictationButton({ onCommit, onCancel, title, caption, lang, continuous, className, size, showLabel, children, disabled, visibility, shrink, }: VoiceDictationButtonProps): react_jsx_runtime.JSX.Element | null;
37
+ declare function VoiceDictationButton({ onCommit, onCancel, title, caption, lang, continuous, className, size, showLabel, children, disabled, visibility, shrink, anchorRef, }: VoiceDictationButtonProps): react_jsx_runtime.JSX.Element | null;
36
38
 
37
39
  export { VoiceDictationButton, type VoiceDictationButtonProps };
@@ -1,12 +1,12 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { ReactNode } from 'react';
2
+ import { ReactNode, RefObject } from 'react';
3
3
 
4
4
  interface VoiceDictationButtonProps {
5
5
  /** Fired when the user taps "Done" with the captured transcript. */
6
6
  onCommit: (text: string) => void;
7
7
  /** Fired if the user closes the overlay without committing. */
8
8
  onCancel?: () => void;
9
- /** Title shown in the compact recorder. */
9
+ /** Title shown in the recorder. */
10
10
  title?: ReactNode;
11
11
  /** Recording status label. Defaults to "Recording". */
12
12
  caption?: string;
@@ -26,12 +26,14 @@ interface VoiceDictationButtonProps {
26
26
  disabled?: boolean;
27
27
  visibility?: "visible" | "hidden";
28
28
  shrink?: boolean;
29
+ /** Visible desktop anchor for a custom/programmatic trigger. Hidden anchors are ignored. */
30
+ anchorRef?: RefObject<HTMLElement | null>;
29
31
  }
30
32
  /**
31
- * Opens a compact portaled recorder. A fixed panel also works when its
32
- * trigger is hidden or sits inside another dialog. Done finishes the take
33
- * and commits its transcript once; Cancel discards it.
33
+ * Opens beside the invoking control on desktop and fills the screen on
34
+ * mobile, or when no visible anchor exists. Placement changes keep the same
35
+ * recording alive. Done commits its transcript once; Cancel discards it.
34
36
  */
35
- declare function VoiceDictationButton({ onCommit, onCancel, title, caption, lang, continuous, className, size, showLabel, children, disabled, visibility, shrink, }: VoiceDictationButtonProps): react_jsx_runtime.JSX.Element | null;
37
+ declare function VoiceDictationButton({ onCommit, onCancel, title, caption, lang, continuous, className, size, showLabel, children, disabled, visibility, shrink, anchorRef, }: VoiceDictationButtonProps): react_jsx_runtime.JSX.Element | null;
36
38
 
37
39
  export { VoiceDictationButton, type VoiceDictationButtonProps };
@@ -2,7 +2,7 @@
2
2
  "use client";
3
3
  import {
4
4
  VoiceDictationButton
5
- } from "../chunk-T3XMHWYV.js";
5
+ } from "../chunk-EDEN7TAL.js";
6
6
  import "../chunk-5OF6D3GH.js";
7
7
  import "../chunk-W326GKML.js";
8
8
  import "../chunk-G6SRSWXB.js";
@@ -2,11 +2,11 @@
2
2
  "use client";
3
3
 
4
4
 
5
- var _chunk7QTFYEPEcjs = require('../chunk-7QTFYEPE.cjs');
5
+ var _chunkYMI3X2YLcjs = require('../chunk-YMI3X2YL.cjs');
6
6
  require('../chunk-NKWHDI4C.cjs');
7
7
  require('../chunk-JDEXZGIY.cjs');
8
8
  require('../chunk-KWLSBTB2.cjs');
9
9
  require('../chunk-2BSFYU22.cjs');
10
10
 
11
11
 
12
- exports.VoiceSessionControls = _chunk7QTFYEPEcjs.VoiceSessionControls;
12
+ exports.VoiceSessionControls = _chunkYMI3X2YLcjs.VoiceSessionControls;
@@ -15,7 +15,7 @@ interface VoiceSessionControlsProps {
15
15
  /** Prevent starting a new session; ending an active session stays available. */
16
16
  disabled?: boolean;
17
17
  error?: string | null;
18
- /** The latest user utterance supplied by the host; never submits a message. */
18
+ /** @deprecated Render transcripts in the conversation thread. Ignored by the controls. */
19
19
  transcript?: string;
20
20
  /** Audio levels supplied by the host; no media connection is created by the kit. */
21
21
  volumeBands?: number[];
@@ -26,6 +26,6 @@ interface VoiceSessionControlsProps {
26
26
  className?: string;
27
27
  }
28
28
  /** Transport-independent voice controls. The conversation stays visible while speaking. */
29
- declare function VoiceSessionControls({ state, onStart, onEnd, muted, onMutedChange, disabled, error, transcript, volumeBands, audioLevels, labels, size, className, }: VoiceSessionControlsProps): react_jsx_runtime.JSX.Element;
29
+ declare function VoiceSessionControls({ state, onStart, onEnd, muted, onMutedChange, disabled, error, volumeBands, audioLevels, labels, size, className, }: VoiceSessionControlsProps): react_jsx_runtime.JSX.Element;
30
30
 
31
31
  export { type VoiceAudioLevelsSource, VoiceSessionControls, type VoiceSessionControlsProps, type VoiceSessionState };
@@ -15,7 +15,7 @@ interface VoiceSessionControlsProps {
15
15
  /** Prevent starting a new session; ending an active session stays available. */
16
16
  disabled?: boolean;
17
17
  error?: string | null;
18
- /** The latest user utterance supplied by the host; never submits a message. */
18
+ /** @deprecated Render transcripts in the conversation thread. Ignored by the controls. */
19
19
  transcript?: string;
20
20
  /** Audio levels supplied by the host; no media connection is created by the kit. */
21
21
  volumeBands?: number[];
@@ -26,6 +26,6 @@ interface VoiceSessionControlsProps {
26
26
  className?: string;
27
27
  }
28
28
  /** Transport-independent voice controls. The conversation stays visible while speaking. */
29
- declare function VoiceSessionControls({ state, onStart, onEnd, muted, onMutedChange, disabled, error, transcript, volumeBands, audioLevels, labels, size, className, }: VoiceSessionControlsProps): react_jsx_runtime.JSX.Element;
29
+ declare function VoiceSessionControls({ state, onStart, onEnd, muted, onMutedChange, disabled, error, volumeBands, audioLevels, labels, size, className, }: VoiceSessionControlsProps): react_jsx_runtime.JSX.Element;
30
30
 
31
31
  export { type VoiceAudioLevelsSource, VoiceSessionControls, type VoiceSessionControlsProps, type VoiceSessionState };
@@ -2,7 +2,7 @@
2
2
  "use client";
3
3
  import {
4
4
  VoiceSessionControls
5
- } from "../chunk-UOVA4YKW.js";
5
+ } from "../chunk-KF4X37DP.js";
6
6
  import "../chunk-5OF6D3GH.js";
7
7
  import "../chunk-W326GKML.js";
8
8
  import "../chunk-G6SRSWXB.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@epicbagel/saas-kit",
3
- "version": "1.11.0",
3
+ "version": "1.11.1",
4
4
  "description": "Accessible React primitives, layout components and design tokens for SaaS apps, built on Radix UI and Tailwind CSS v4.",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -1,221 +0,0 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } 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 _chunkNKWHDI4Ccjs = require('./chunk-NKWHDI4C.cjs');
5
-
6
-
7
- var _chunkJDEXZGIYcjs = require('./chunk-JDEXZGIY.cjs');
8
-
9
-
10
- var _chunkKWLSBTB2cjs = require('./chunk-KWLSBTB2.cjs');
11
-
12
-
13
- var _chunkZZ7ICQR2cjs = require('./chunk-ZZ7ICQR2.cjs');
14
-
15
- // src/primitives/voice-dictation-button.tsx
16
-
17
-
18
-
19
-
20
-
21
-
22
- var _react = require('react');
23
- var _reactdialog = require('@radix-ui/react-dialog'); var DialogPrimitive = _interopRequireWildcard(_reactdialog);
24
- var _lucidereact = require('lucide-react');
25
- var _jsxruntime = require('react/jsx-runtime');
26
- function VoiceDictationButton({
27
- onCommit,
28
- onCancel,
29
- title = "Dictate your message",
30
- caption = "Recording",
31
- lang = "en-US",
32
- continuous = true,
33
- className,
34
- size = "sm",
35
- showLabel = false,
36
- children,
37
- disabled = false,
38
- visibility = "visible",
39
- shrink = true
40
- }) {
41
- const [open, setOpen] = _react.useState.call(void 0, false);
42
- const capture = _chunkZZ7ICQR2cjs.useDictation.call(void 0, { lang, continuous });
43
- const { transcript, interimTranscript: interim, supported, error } = capture;
44
- const generation = _react.useRef.call(void 0, 0);
45
- const finishing = _react.useRef.call(void 0, false);
46
- const previousFocus = _react.useRef.call(void 0, null);
47
- const elapsed = useRecordingTime(capture.state);
48
- const busy = capture.state === "requesting" || capture.state === "transcribing";
49
- const openOverlay = _react.useCallback.call(void 0, () => {
50
- previousFocus.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
51
- generation.current++;
52
- finishing.current = false;
53
- setOpen(true);
54
- void capture.start();
55
- }, [capture.start]);
56
- const closeOverlay = _react.useCallback.call(void 0, () => {
57
- generation.current++;
58
- finishing.current = false;
59
- capture.cancel();
60
- setOpen(false);
61
- }, [capture.cancel]);
62
- const handleDone = _react.useCallback.call(void 0, async () => {
63
- if (finishing.current || busy) return;
64
- if (capture.state === "error" && !capture.canRetry) {
65
- void capture.start();
66
- return;
67
- }
68
- finishing.current = true;
69
- const started = generation.current;
70
- const final = await (capture.canRetry ? capture.retry() : capture.stop());
71
- if (started !== generation.current) return;
72
- finishing.current = false;
73
- if (final === null) return;
74
- closeOverlay();
75
- if (final) onCommit(final);
76
- else _optionalChain([onCancel, 'optionalCall', _ => _()]);
77
- }, [busy, capture.canRetry, capture.retry, capture.start, capture.state, capture.stop, onCommit, onCancel, closeOverlay]);
78
- const handleCancel = _react.useCallback.call(void 0, () => {
79
- closeOverlay();
80
- _optionalChain([onCancel, 'optionalCall', _2 => _2()]);
81
- }, [closeOverlay, onCancel]);
82
- _react.useEffect.call(void 0, () => {
83
- if (open && capture.state === "idle") handleCancel();
84
- }, [capture.state, handleCancel, open]);
85
- _react.useEffect.call(void 0, () => {
86
- return () => {
87
- generation.current++;
88
- };
89
- }, []);
90
- if (!supported) return null;
91
- const displayTranscript = `${transcript}${interim ? (transcript ? " " : "") + interim : ""}`;
92
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
93
- children ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
94
- "button",
95
- {
96
- type: "button",
97
- onClick: openOverlay,
98
- disabled,
99
- "aria-label": "Start dictation",
100
- className: _chunkKWLSBTB2cjs.cn.call(void 0, visibility === "hidden" && "hidden", className),
101
- children
102
- }
103
- ) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
104
- _chunkJDEXZGIYcjs.Button,
105
- {
106
- type: "button",
107
- onClick: openOverlay,
108
- disabled,
109
- variant: "outline",
110
- size,
111
- "aria-label": "Start dictation",
112
- className: _chunkKWLSBTB2cjs.cn.call(void 0, "transition-colors", visibility === "hidden" && "hidden", !shrink && "shrink-0", className),
113
- children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "flex items-center justify-center gap-2", children: [
114
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.Mic, { className: "h-4 w-4" }),
115
- showLabel && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: "Speak" })
116
- ] })
117
- }
118
- ),
119
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
120
- DialogPrimitive.Root,
121
- {
122
- open,
123
- onOpenChange: (next) => {
124
- if (!next) handleCancel();
125
- },
126
- children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DialogPrimitive.Portal, { children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
127
- DialogPrimitive.Content,
128
- {
129
- "aria-label": "Voice dictation",
130
- "aria-labelledby": void 0,
131
- "data-slot": "voice-dictation-panel",
132
- "data-state": capture.state,
133
- onCloseAutoFocus: (event) => {
134
- event.preventDefault();
135
- if (_optionalChain([previousFocus, 'access', _3 => _3.current, 'optionalAccess', _4 => _4.isConnected])) previousFocus.current.focus();
136
- },
137
- onKeyDown: (event) => {
138
- if (event.key === "Enter" && !event.shiftKey && !(event.target instanceof HTMLElement && event.target.closest("button, input, textarea, select"))) {
139
- event.preventDefault();
140
- void handleDone();
141
- }
142
- },
143
- className: "fixed bottom-4 left-1/2 z-[200] flex max-h-[calc(100dvh-2rem)] w-[calc(100%-2rem)] max-w-sm -translate-x-1/2 flex-col gap-3 overflow-y-auto rounded-2xl border border-border bg-background p-4 text-foreground shadow-lg outline-hidden sm:bottom-6",
144
- children: [
145
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex min-w-0 items-start justify-between gap-3", children: [
146
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "min-w-0 space-y-1", children: [
147
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DialogPrimitive.Title, { className: "text-sm font-medium", children: title || "Voice dictation" }),
148
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { role: "status", className: "flex items-center gap-1.5 text-xs text-muted-foreground", children: [
149
- busy ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.LoaderCircle, { "aria-hidden": "true", className: "size-3.5 animate-spin motion-reduce:animate-none" }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.Mic, { "aria-hidden": "true", className: "size-3.5" }),
150
- capture.state === "transcribing" ? "Transcribing\u2026" : capture.state === "requesting" ? "Waiting for microphone\u2026" : error ? "Recording not saved" : capture.state === "ready" ? "Ready" : caption
151
- ] })
152
- ] }),
153
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "time", { "aria-label": "Recording duration", dateTime: `PT${elapsed}S`, className: "pt-0.5 font-mono text-xs tabular-nums text-muted-foreground", children: [
154
- Math.floor(elapsed / 60).toString().padStart(2, "0"),
155
- ":",
156
- (elapsed % 60).toString().padStart(2, "0")
157
- ] })
158
- ] }),
159
- capture.audioLevels && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DictationWaveform, { source: capture.audioLevels, state: capture.state }),
160
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DialogPrimitive.Description, { className: "text-xs text-muted-foreground", children: capture.state === "transcribing" ? "Converting your recording to text\u2026" : capture.state === "requesting" ? "Allow microphone access to start." : error ? capture.canRetry ? "Retry this take or record again." : "Check microphone access, then try again." : "Speak, then choose Done to add the text." }),
161
- displayTranscript && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { className: "max-h-24 overflow-y-auto text-sm leading-relaxed", children: [
162
- transcript,
163
- interim && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "text-muted-foreground", children: [
164
- transcript ? " " : "",
165
- interim
166
- ] })
167
- ] }),
168
- error && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { role: "alert", className: "text-xs text-destructive", children: error }),
169
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-wrap items-center justify-end gap-2", children: [
170
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkJDEXZGIYcjs.Button, { type: "button", variant: "ghost", size: "sm", className: "min-h-[44px]", onClick: handleCancel, children: "Cancel" }),
171
- capture.canRetry && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkJDEXZGIYcjs.Button, { type: "button", variant: "outline", size: "sm", className: "min-h-[44px]", onClick: () => void capture.start(), children: "Record again" }),
172
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkJDEXZGIYcjs.Button, { type: "button", size: "sm", className: "min-h-[44px]", onClick: () => void handleDone(), disabled: busy, children: capture.state === "transcribing" ? "Transcribing\u2026" : capture.canRetry ? "Retry transcription" : error ? "Try again" : "Done" })
173
- ] })
174
- ]
175
- }
176
- ) })
177
- }
178
- )
179
- ] });
180
- }
181
- var SILENCE = [];
182
- var silence = () => SILENCE;
183
- function DictationWaveform({ source, state }) {
184
- const bands = _react.useSyncExternalStore.call(void 0, source.subscribe, source.getSnapshot, silence);
185
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
186
- _chunkNKWHDI4Ccjs.AgentAudioVisualizerBar,
187
- {
188
- "aria-hidden": "true",
189
- "data-slot": "dictation-waveform",
190
- size: "icon",
191
- barCount: 24,
192
- state: state === "recording" ? "listening" : state === "transcribing" ? "thinking" : state === "requesting" ? "connecting" : "disconnected",
193
- volumeBands: state === "recording" ? bands : void 0,
194
- className: "h-9 w-full text-foreground"
195
- }
196
- );
197
- }
198
- function useRecordingTime(state) {
199
- const [elapsed, setElapsed] = _react.useState.call(void 0, 0);
200
- const startedAt = _react.useRef.call(void 0, null);
201
- _react.useEffect.call(void 0, () => {
202
- if (state !== "recording") {
203
- if (state === "idle" || state === "requesting") setElapsed(0);
204
- else if (startedAt.current !== null) setElapsed(Math.floor((performance.now() - startedAt.current) / 1e3));
205
- startedAt.current = null;
206
- return;
207
- }
208
- startedAt.current = performance.now();
209
- const update = () => setElapsed(Math.floor((performance.now() - startedAt.current) / 1e3));
210
- update();
211
- const timer = setInterval(update, 1e3);
212
- return () => {
213
- clearInterval(timer);
214
- };
215
- }, [state]);
216
- return elapsed;
217
- }
218
-
219
-
220
-
221
- exports.VoiceDictationButton = VoiceDictationButton;