@epicbagel/saas-kit 1.16.0 → 1.17.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.
- package/README.md +8 -4
- package/dist/{chunk-QWUMIAYD.cjs → chunk-PH2TV7XI.cjs} +58 -25
- package/dist/{chunk-JKVVTFAP.js → chunk-ZGTPNSR7.js} +59 -26
- package/dist/primitives/chat.cjs +4 -4
- package/dist/primitives/chat.js +1 -1
- package/dist/primitives/voice-dictation-button.cjs +2 -2
- package/dist/primitives/voice-dictation-button.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -42,16 +42,20 @@ does not import a voice provider. Stop and release audio tracks before setting
|
|
|
42
42
|
Wrap the application in `DictationProvider` to use an authenticated transcription
|
|
43
43
|
API for every `VoiceDictationButton`, including buttons nested in chat, forms or
|
|
44
44
|
another component library. The recorder opens beside its microphone on desktop
|
|
45
|
-
and fills the screen below 768px
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
and fills the screen below 768px. Its roomy panel puts the title and close control
|
|
46
|
+
above a microphone, live audio bars and elapsed time, followed by the transcript
|
|
47
|
+
and Done/Cancel controls. The microphone and bars share the palette's first chart
|
|
48
|
+
colour; surfaces and buttons keep their normal theme. The bars use the recording
|
|
49
|
+
stream without opening a second microphone; native recognition has no meter and
|
|
50
|
+
shows no waveform. No device selector is shown because the capture API does not
|
|
51
|
+
offer device selection. Resizing keeps the current recording alive.
|
|
48
52
|
|
|
49
53
|
For hidden/programmatic triggers, it uses the focused visible button as the
|
|
50
54
|
desktop anchor. Hosts can pass an explicit `anchorRef` for a custom trigger.
|
|
51
55
|
Without a visible anchor it opens full-screen. Nested and sibling dialogs keep
|
|
52
56
|
their focus and cancellation behavior.
|
|
53
57
|
The recorder runs until **Done**, finishes the last words, then commits the returned text once. Failed requests keep the
|
|
54
|
-
take available for retry. Cancel
|
|
58
|
+
take available for retry. Cancel and the header's close control stop microphone tracks, abort the request and
|
|
55
59
|
ignores a late answer. The kit never persists audio or knows provider credentials.
|
|
56
60
|
|
|
57
61
|
```tsx
|
|
@@ -118,40 +118,72 @@ function VoiceDictationButton({
|
|
|
118
118
|
}
|
|
119
119
|
};
|
|
120
120
|
const content = /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
121
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunkKWLSBTB2cjs.cn.call(void 0, "flex min-w-0 items-start justify-between gap-
|
|
122
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "min-w-0 space-y-1", children: [
|
|
123
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { className:
|
|
124
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { role: "status", className: "flex items-center gap-
|
|
125
|
-
busy
|
|
121
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunkKWLSBTB2cjs.cn.call(void 0, "flex min-w-0 shrink-0 items-start justify-between gap-4", !anchored && "w-full max-w-xl self-center"), children: [
|
|
122
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "min-w-0 space-y-2 pt-1", children: [
|
|
123
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { className: "break-words text-xl font-semibold leading-tight", children: title || "Voice dictation" }),
|
|
124
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { role: "status", className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
|
|
125
|
+
busy && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.LoaderCircle, { "aria-hidden": "true", className: "size-4 shrink-0 animate-spin motion-reduce:animate-none" }),
|
|
126
126
|
capture.state === "transcribing" ? "Finishing transcript\u2026" : capture.state === "requesting" ? "Starting dictation\u2026" : error ? "Recording not saved" : capture.state === "ready" ? "Ready" : caption
|
|
127
127
|
] })
|
|
128
128
|
] }),
|
|
129
|
-
/* @__PURE__ */ _jsxruntime.
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
129
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
130
|
+
_chunkJDEXZGIYcjs.Button,
|
|
131
|
+
{
|
|
132
|
+
type: "button",
|
|
133
|
+
variant: "ghost",
|
|
134
|
+
size: "icon",
|
|
135
|
+
shape: "circle",
|
|
136
|
+
"aria-label": "Cancel dictation",
|
|
137
|
+
className: "size-[44px] shrink-0 text-muted-foreground [&_svg]:size-5",
|
|
138
|
+
onClick: handleCancel,
|
|
139
|
+
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.X, { "aria-hidden": "true", className: "size-5" })
|
|
140
|
+
}
|
|
141
|
+
)
|
|
134
142
|
] }),
|
|
135
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunkKWLSBTB2cjs.cn.call(void 0, "flex
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
143
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunkKWLSBTB2cjs.cn.call(void 0, "flex flex-col gap-5", !anchored && "w-full max-w-xl flex-1 justify-center self-center py-6"), children: [
|
|
144
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { "data-slot": "dictation-meter", className: "flex min-w-0 items-center gap-3 py-5 text-[hsl(var(--chart-1))] sm:gap-5 sm:py-7", children: [
|
|
145
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
146
|
+
"div",
|
|
147
|
+
{
|
|
148
|
+
"aria-hidden": "true",
|
|
149
|
+
"data-slot": "dictation-microphone",
|
|
150
|
+
className: "flex size-[72px] shrink-0 items-center justify-center rounded-full bg-current/10 sm:size-[96px]",
|
|
151
|
+
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex size-[52px] items-center justify-center rounded-full bg-[hsl(var(--chart-1))] text-popover sm:size-[72px]", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.Mic, { className: "size-7 sm:size-9" }) })
|
|
152
|
+
}
|
|
153
|
+
),
|
|
154
|
+
capture.audioLevels && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DictationWaveform, { source: capture.audioLevels, state: capture.state }),
|
|
155
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
156
|
+
"time",
|
|
157
|
+
{
|
|
158
|
+
"aria-label": "Recording duration",
|
|
159
|
+
dateTime: `PT${elapsed}S`,
|
|
160
|
+
className: "ml-auto shrink-0 font-mono text-xl tabular-nums text-muted-foreground sm:text-2xl",
|
|
161
|
+
children: [
|
|
162
|
+
Math.floor(elapsed / 60).toString().padStart(2, "0"),
|
|
163
|
+
":",
|
|
164
|
+
(elapsed % 60).toString().padStart(2, "0")
|
|
165
|
+
]
|
|
166
|
+
}
|
|
167
|
+
)
|
|
168
|
+
] }),
|
|
169
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { id: descriptionId, className: "text-base leading-relaxed text-muted-foreground", children: capture.state === "transcribing" ? "Finishing your last words\u2026" : capture.state === "requesting" ? "Allow microphone access to start." : error ? capture.canRetry ? "Retry this take or record again." : "Try recording again." : "Speak, then choose Done to add the text." }),
|
|
170
|
+
displayTranscript && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { className: "max-h-48 overflow-y-auto break-words text-base leading-relaxed", children: [
|
|
139
171
|
transcript,
|
|
140
172
|
interim && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "text-muted-foreground", children: [
|
|
141
173
|
transcript ? " " : "",
|
|
142
174
|
interim
|
|
143
175
|
] })
|
|
144
176
|
] }),
|
|
145
|
-
error && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { role: "alert", className: "text-
|
|
146
|
-
!error && capture.previewError && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { role: "status", className: "text-
|
|
177
|
+
error && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { role: "alert", className: "text-sm leading-relaxed text-destructive", children: error }),
|
|
178
|
+
!error && capture.previewError && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { role: "status", className: "text-sm leading-relaxed text-muted-foreground", children: capture.previewError })
|
|
147
179
|
] }),
|
|
148
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunkKWLSBTB2cjs.cn.call(void 0, "gap-2", anchored ? "flex flex-wrap items-center justify-end" : "mt-auto grid w-full max-w-xl grid-cols-
|
|
149
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkJDEXZGIYcjs.Button, { ref: cancelControl, type: "button", variant: "ghost",
|
|
150
|
-
capture.canRetry && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkJDEXZGIYcjs.Button, { type: "button", variant: "outline",
|
|
180
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunkKWLSBTB2cjs.cn.call(void 0, "shrink-0 gap-3 pt-2", anchored ? "flex flex-wrap items-center justify-end" : "mt-auto grid w-full max-w-xl grid-cols-[auto_minmax(0,1fr)] self-center"), children: [
|
|
181
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkJDEXZGIYcjs.Button, { ref: cancelControl, type: "button", variant: "ghost", className: "min-h-[48px] px-5", onClick: handleCancel, children: "Cancel" }),
|
|
182
|
+
capture.canRetry && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkJDEXZGIYcjs.Button, { type: "button", variant: "outline", className: _chunkKWLSBTB2cjs.cn.call(void 0, "min-h-[48px] px-5", !anchored && "order-first col-span-2"), onClick: () => {
|
|
151
183
|
_optionalChain([cancelControl, 'access', _13 => _13.current, 'optionalAccess', _14 => _14.focus, 'call', _15 => _15({ preventScroll: true })]);
|
|
152
184
|
void capture.start();
|
|
153
185
|
}, children: "Record again" }),
|
|
154
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkJDEXZGIYcjs.Button, { type: "button",
|
|
186
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkJDEXZGIYcjs.Button, { type: "button", className: "min-h-[48px] min-w-24 px-6", onClick: () => void handleDone(), disabled: busy, children: capture.state === "transcribing" ? "Transcribing\u2026" : capture.canRetry ? "Retry transcription" : error ? "Try again" : "Done" })
|
|
155
187
|
] })
|
|
156
188
|
] });
|
|
157
189
|
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
@@ -195,13 +227,13 @@ function VoiceDictationButton({
|
|
|
195
227
|
"data-placement": "anchored",
|
|
196
228
|
side: "top",
|
|
197
229
|
align: "center",
|
|
198
|
-
sideOffset:
|
|
230
|
+
sideOffset: 12,
|
|
199
231
|
collisionPadding: 12,
|
|
200
232
|
avoidCollisions: true,
|
|
201
233
|
onCloseAutoFocus: closeAutoFocus,
|
|
202
234
|
onKeyDown,
|
|
203
235
|
onEscapeKeyDown: (event) => event.stopPropagation(),
|
|
204
|
-
className: "z-[200] flex max-h-[var(--radix-popover-content-available-height)] w-
|
|
236
|
+
className: "z-[200] flex max-h-[var(--radix-popover-content-available-height)] w-[560px] max-w-[calc(100vw-24px)] flex-col gap-6 overflow-y-auto rounded-2xl border border-border bg-popover p-6 text-popover-foreground shadow-xl outline-hidden",
|
|
205
237
|
children: content
|
|
206
238
|
}
|
|
207
239
|
) })
|
|
@@ -221,7 +253,7 @@ function VoiceDictationButton({
|
|
|
221
253
|
onCloseAutoFocus: closeAutoFocus,
|
|
222
254
|
onKeyDown,
|
|
223
255
|
onEscapeKeyDown: (event) => event.stopPropagation(),
|
|
224
|
-
className: "fixed inset-0 z-[200] flex h-dvh w-screen flex-col gap-6 overflow-y-auto overscroll-contain bg-
|
|
256
|
+
className: "fixed inset-0 z-[200] flex h-dvh w-screen flex-col gap-6 overflow-y-auto overscroll-contain bg-popover px-5 pt-[max(1.5rem,env(safe-area-inset-top))] pb-[max(1.5rem,env(safe-area-inset-bottom))] text-popover-foreground outline-hidden",
|
|
225
257
|
children: [
|
|
226
258
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, DialogPrimitive.Title, { className: "sr-only", children: "Voice dictation" }),
|
|
227
259
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, DialogPrimitive.Description, { className: "sr-only", children: "Record your message, then choose Done to add the text. Cancel discards the recording." }),
|
|
@@ -234,7 +266,7 @@ function VoiceDictationButton({
|
|
|
234
266
|
}
|
|
235
267
|
var SILENCE = [];
|
|
236
268
|
var silence = () => SILENCE;
|
|
237
|
-
function DictationWaveform({ source, state
|
|
269
|
+
function DictationWaveform({ source, state }) {
|
|
238
270
|
const bands = _react.useSyncExternalStore.call(void 0, source.subscribe, source.getSnapshot, silence);
|
|
239
271
|
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
240
272
|
_chunkNKWHDI4Ccjs.AgentAudioVisualizerBar,
|
|
@@ -245,7 +277,8 @@ function DictationWaveform({ source, state, className }) {
|
|
|
245
277
|
barCount: 24,
|
|
246
278
|
state: state === "recording" ? "listening" : state === "transcribing" ? "thinking" : state === "requesting" ? "connecting" : "disconnected",
|
|
247
279
|
volumeBands: state === "recording" ? bands : void 0,
|
|
248
|
-
className:
|
|
280
|
+
className: "h-[64px] min-w-0 flex-1 gap-[3px] sm:h-[88px] sm:gap-[4px]",
|
|
281
|
+
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "min-h-[4px] max-w-[6px] flex-1 rounded-full bg-current/15 transition-colors duration-200 motion-reduce:transition-none data-[lk-highlighted=true]:bg-current" })
|
|
249
282
|
}
|
|
250
283
|
);
|
|
251
284
|
}
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
} from "react";
|
|
24
24
|
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
|
25
25
|
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
|
26
|
-
import { Mic, LoaderCircle } from "lucide-react";
|
|
26
|
+
import { Mic, LoaderCircle, X } from "lucide-react";
|
|
27
27
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
28
28
|
function VoiceDictationButton({
|
|
29
29
|
onCommit,
|
|
@@ -118,40 +118,72 @@ function VoiceDictationButton({
|
|
|
118
118
|
}
|
|
119
119
|
};
|
|
120
120
|
const content = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
121
|
-
/* @__PURE__ */ jsxs("div", { className: cn("flex min-w-0 items-start justify-between gap-
|
|
122
|
-
/* @__PURE__ */ jsxs("div", { className: "min-w-0 space-y-1", children: [
|
|
123
|
-
/* @__PURE__ */ jsx("h2", { className:
|
|
124
|
-
/* @__PURE__ */ jsxs("span", { role: "status", className: "flex items-center gap-
|
|
125
|
-
busy
|
|
121
|
+
/* @__PURE__ */ jsxs("div", { className: cn("flex min-w-0 shrink-0 items-start justify-between gap-4", !anchored && "w-full max-w-xl self-center"), children: [
|
|
122
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 space-y-2 pt-1", children: [
|
|
123
|
+
/* @__PURE__ */ jsx("h2", { className: "break-words text-xl font-semibold leading-tight", children: title || "Voice dictation" }),
|
|
124
|
+
/* @__PURE__ */ jsxs("span", { role: "status", className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
|
|
125
|
+
busy && /* @__PURE__ */ jsx(LoaderCircle, { "aria-hidden": "true", className: "size-4 shrink-0 animate-spin motion-reduce:animate-none" }),
|
|
126
126
|
capture.state === "transcribing" ? "Finishing transcript\u2026" : capture.state === "requesting" ? "Starting dictation\u2026" : error ? "Recording not saved" : capture.state === "ready" ? "Ready" : caption
|
|
127
127
|
] })
|
|
128
128
|
] }),
|
|
129
|
-
/* @__PURE__ */
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
129
|
+
/* @__PURE__ */ jsx(
|
|
130
|
+
Button,
|
|
131
|
+
{
|
|
132
|
+
type: "button",
|
|
133
|
+
variant: "ghost",
|
|
134
|
+
size: "icon",
|
|
135
|
+
shape: "circle",
|
|
136
|
+
"aria-label": "Cancel dictation",
|
|
137
|
+
className: "size-[44px] shrink-0 text-muted-foreground [&_svg]:size-5",
|
|
138
|
+
onClick: handleCancel,
|
|
139
|
+
children: /* @__PURE__ */ jsx(X, { "aria-hidden": "true", className: "size-5" })
|
|
140
|
+
}
|
|
141
|
+
)
|
|
134
142
|
] }),
|
|
135
|
-
/* @__PURE__ */ jsxs("div", { className: cn("flex
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
143
|
+
/* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-5", !anchored && "w-full max-w-xl flex-1 justify-center self-center py-6"), children: [
|
|
144
|
+
/* @__PURE__ */ jsxs("div", { "data-slot": "dictation-meter", className: "flex min-w-0 items-center gap-3 py-5 text-[hsl(var(--chart-1))] sm:gap-5 sm:py-7", children: [
|
|
145
|
+
/* @__PURE__ */ jsx(
|
|
146
|
+
"div",
|
|
147
|
+
{
|
|
148
|
+
"aria-hidden": "true",
|
|
149
|
+
"data-slot": "dictation-microphone",
|
|
150
|
+
className: "flex size-[72px] shrink-0 items-center justify-center rounded-full bg-current/10 sm:size-[96px]",
|
|
151
|
+
children: /* @__PURE__ */ jsx("div", { className: "flex size-[52px] items-center justify-center rounded-full bg-[hsl(var(--chart-1))] text-popover sm:size-[72px]", children: /* @__PURE__ */ jsx(Mic, { className: "size-7 sm:size-9" }) })
|
|
152
|
+
}
|
|
153
|
+
),
|
|
154
|
+
capture.audioLevels && /* @__PURE__ */ jsx(DictationWaveform, { source: capture.audioLevels, state: capture.state }),
|
|
155
|
+
/* @__PURE__ */ jsxs(
|
|
156
|
+
"time",
|
|
157
|
+
{
|
|
158
|
+
"aria-label": "Recording duration",
|
|
159
|
+
dateTime: `PT${elapsed}S`,
|
|
160
|
+
className: "ml-auto shrink-0 font-mono text-xl tabular-nums text-muted-foreground sm:text-2xl",
|
|
161
|
+
children: [
|
|
162
|
+
Math.floor(elapsed / 60).toString().padStart(2, "0"),
|
|
163
|
+
":",
|
|
164
|
+
(elapsed % 60).toString().padStart(2, "0")
|
|
165
|
+
]
|
|
166
|
+
}
|
|
167
|
+
)
|
|
168
|
+
] }),
|
|
169
|
+
/* @__PURE__ */ jsx("p", { id: descriptionId, className: "text-base leading-relaxed text-muted-foreground", children: capture.state === "transcribing" ? "Finishing your last words\u2026" : capture.state === "requesting" ? "Allow microphone access to start." : error ? capture.canRetry ? "Retry this take or record again." : "Try recording again." : "Speak, then choose Done to add the text." }),
|
|
170
|
+
displayTranscript && /* @__PURE__ */ jsxs("p", { className: "max-h-48 overflow-y-auto break-words text-base leading-relaxed", children: [
|
|
139
171
|
transcript,
|
|
140
172
|
interim && /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
|
|
141
173
|
transcript ? " " : "",
|
|
142
174
|
interim
|
|
143
175
|
] })
|
|
144
176
|
] }),
|
|
145
|
-
error && /* @__PURE__ */ jsx("p", { role: "alert", className: "text-
|
|
146
|
-
!error && capture.previewError && /* @__PURE__ */ jsx("p", { role: "status", className: "text-
|
|
177
|
+
error && /* @__PURE__ */ jsx("p", { role: "alert", className: "text-sm leading-relaxed text-destructive", children: error }),
|
|
178
|
+
!error && capture.previewError && /* @__PURE__ */ jsx("p", { role: "status", className: "text-sm leading-relaxed text-muted-foreground", children: capture.previewError })
|
|
147
179
|
] }),
|
|
148
|
-
/* @__PURE__ */ jsxs("div", { className: cn("gap-2", anchored ? "flex flex-wrap items-center justify-end" : "mt-auto grid w-full max-w-xl grid-cols-
|
|
149
|
-
/* @__PURE__ */ jsx(Button, { ref: cancelControl, type: "button", variant: "ghost",
|
|
150
|
-
capture.canRetry && /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline",
|
|
180
|
+
/* @__PURE__ */ jsxs("div", { className: cn("shrink-0 gap-3 pt-2", anchored ? "flex flex-wrap items-center justify-end" : "mt-auto grid w-full max-w-xl grid-cols-[auto_minmax(0,1fr)] self-center"), children: [
|
|
181
|
+
/* @__PURE__ */ jsx(Button, { ref: cancelControl, type: "button", variant: "ghost", className: "min-h-[48px] px-5", onClick: handleCancel, children: "Cancel" }),
|
|
182
|
+
capture.canRetry && /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", className: cn("min-h-[48px] px-5", !anchored && "order-first col-span-2"), onClick: () => {
|
|
151
183
|
cancelControl.current?.focus({ preventScroll: true });
|
|
152
184
|
void capture.start();
|
|
153
185
|
}, children: "Record again" }),
|
|
154
|
-
/* @__PURE__ */ jsx(Button, { type: "button",
|
|
186
|
+
/* @__PURE__ */ jsx(Button, { type: "button", className: "min-h-[48px] min-w-24 px-6", onClick: () => void handleDone(), disabled: busy, children: capture.state === "transcribing" ? "Transcribing\u2026" : capture.canRetry ? "Retry transcription" : error ? "Try again" : "Done" })
|
|
155
187
|
] })
|
|
156
188
|
] });
|
|
157
189
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
@@ -195,13 +227,13 @@ function VoiceDictationButton({
|
|
|
195
227
|
"data-placement": "anchored",
|
|
196
228
|
side: "top",
|
|
197
229
|
align: "center",
|
|
198
|
-
sideOffset:
|
|
230
|
+
sideOffset: 12,
|
|
199
231
|
collisionPadding: 12,
|
|
200
232
|
avoidCollisions: true,
|
|
201
233
|
onCloseAutoFocus: closeAutoFocus,
|
|
202
234
|
onKeyDown,
|
|
203
235
|
onEscapeKeyDown: (event) => event.stopPropagation(),
|
|
204
|
-
className: "z-[200] flex max-h-[var(--radix-popover-content-available-height)] w-
|
|
236
|
+
className: "z-[200] flex max-h-[var(--radix-popover-content-available-height)] w-[560px] max-w-[calc(100vw-24px)] flex-col gap-6 overflow-y-auto rounded-2xl border border-border bg-popover p-6 text-popover-foreground shadow-xl outline-hidden",
|
|
205
237
|
children: content
|
|
206
238
|
}
|
|
207
239
|
) })
|
|
@@ -221,7 +253,7 @@ function VoiceDictationButton({
|
|
|
221
253
|
onCloseAutoFocus: closeAutoFocus,
|
|
222
254
|
onKeyDown,
|
|
223
255
|
onEscapeKeyDown: (event) => event.stopPropagation(),
|
|
224
|
-
className: "fixed inset-0 z-[200] flex h-dvh w-screen flex-col gap-6 overflow-y-auto overscroll-contain bg-
|
|
256
|
+
className: "fixed inset-0 z-[200] flex h-dvh w-screen flex-col gap-6 overflow-y-auto overscroll-contain bg-popover px-5 pt-[max(1.5rem,env(safe-area-inset-top))] pb-[max(1.5rem,env(safe-area-inset-bottom))] text-popover-foreground outline-hidden",
|
|
225
257
|
children: [
|
|
226
258
|
/* @__PURE__ */ jsx(DialogPrimitive.Title, { className: "sr-only", children: "Voice dictation" }),
|
|
227
259
|
/* @__PURE__ */ jsx(DialogPrimitive.Description, { className: "sr-only", children: "Record your message, then choose Done to add the text. Cancel discards the recording." }),
|
|
@@ -234,7 +266,7 @@ function VoiceDictationButton({
|
|
|
234
266
|
}
|
|
235
267
|
var SILENCE = [];
|
|
236
268
|
var silence = () => SILENCE;
|
|
237
|
-
function DictationWaveform({ source, state
|
|
269
|
+
function DictationWaveform({ source, state }) {
|
|
238
270
|
const bands = useSyncExternalStore(source.subscribe, source.getSnapshot, silence);
|
|
239
271
|
return /* @__PURE__ */ jsx(
|
|
240
272
|
AgentAudioVisualizerBar,
|
|
@@ -245,7 +277,8 @@ function DictationWaveform({ source, state, className }) {
|
|
|
245
277
|
barCount: 24,
|
|
246
278
|
state: state === "recording" ? "listening" : state === "transcribing" ? "thinking" : state === "requesting" ? "connecting" : "disconnected",
|
|
247
279
|
volumeBands: state === "recording" ? bands : void 0,
|
|
248
|
-
className:
|
|
280
|
+
className: "h-[64px] min-w-0 flex-1 gap-[3px] sm:h-[88px] sm:gap-[4px]",
|
|
281
|
+
children: /* @__PURE__ */ jsx("div", { className: "min-h-[4px] max-w-[6px] flex-1 rounded-full bg-current/15 transition-colors duration-200 motion-reduce:transition-none data-[lk-highlighted=true]:bg-current" })
|
|
249
282
|
}
|
|
250
283
|
);
|
|
251
284
|
}
|
package/dist/primitives/chat.cjs
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
var _chunk2BTDBZYNcjs = require('../chunk-2BTDBZYN.cjs');
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
var
|
|
10
|
+
var _chunkPH2TV7XIcjs = require('../chunk-PH2TV7XI.cjs');
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
var _chunkYMI3X2YLcjs = require('../chunk-YMI3X2YL.cjs');
|
|
@@ -545,7 +545,7 @@ function ChatInput({
|
|
|
545
545
|
) : null,
|
|
546
546
|
(!helperText || compact) && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex-1" }),
|
|
547
547
|
voice && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
548
|
-
|
|
548
|
+
_chunkPH2TV7XIcjs.VoiceDictationButton,
|
|
549
549
|
{
|
|
550
550
|
size: "icon",
|
|
551
551
|
title: voiceTitle,
|
|
@@ -623,7 +623,7 @@ function VoiceHero({
|
|
|
623
623
|
voiceSession ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
624
624
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkYMI3X2YLcjs.VoiceSessionControls, { ...voiceSession, size: "hero" }),
|
|
625
625
|
voice && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
626
|
-
|
|
626
|
+
_chunkPH2TV7XIcjs.VoiceDictationButton,
|
|
627
627
|
{
|
|
628
628
|
size: "icon",
|
|
629
629
|
title: voiceTitle,
|
|
@@ -633,7 +633,7 @@ function VoiceHero({
|
|
|
633
633
|
}
|
|
634
634
|
)
|
|
635
635
|
] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
636
|
-
|
|
636
|
+
_chunkPH2TV7XIcjs.VoiceDictationButton,
|
|
637
637
|
{
|
|
638
638
|
size: "lg",
|
|
639
639
|
title: voiceTitle,
|
package/dist/primitives/chat.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"use client";
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
var
|
|
5
|
+
var _chunkPH2TV7XIcjs = require('../chunk-PH2TV7XI.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-7Q4EFCUI.cjs');
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
exports.VoiceDictationButton =
|
|
13
|
+
exports.VoiceDictationButton = _chunkPH2TV7XIcjs.VoiceDictationButton;
|
package/package.json
CHANGED