@mieweb/ui 0.11.0-dev.1 → 0.11.0-dev.10

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 (171) hide show
  1. package/dist/ag-grid.cjs +11 -2
  2. package/dist/ag-grid.cjs.map +1 -1
  3. package/dist/ag-grid.d.cts +8 -0
  4. package/dist/ag-grid.d.ts +8 -0
  5. package/dist/ag-grid.js +11 -2
  6. package/dist/ag-grid.js.map +1 -1
  7. package/dist/brands/index.cjs +12 -12
  8. package/dist/brands/index.js +3 -3
  9. package/dist/{chunk-U2RS574O.cjs → chunk-2GBVJHWN.cjs} +120 -63
  10. package/dist/chunk-2GBVJHWN.cjs.map +1 -0
  11. package/dist/{chunk-7UTBDFFL.cjs → chunk-2S76TRBJ.cjs} +4 -4
  12. package/dist/{chunk-7UTBDFFL.cjs.map → chunk-2S76TRBJ.cjs.map} +1 -1
  13. package/dist/{chunk-IJYTASQQ.cjs → chunk-3AD4HFYI.cjs} +15 -7
  14. package/dist/chunk-3AD4HFYI.cjs.map +1 -0
  15. package/dist/{chunk-CFI3TQMA.cjs → chunk-56C7K4MV.cjs} +9 -4
  16. package/dist/chunk-56C7K4MV.cjs.map +1 -0
  17. package/dist/{chunk-TNUL4LGG.js → chunk-5ILCNY74.js} +15 -7
  18. package/dist/chunk-5ILCNY74.js.map +1 -0
  19. package/dist/{chunk-AFDW64EF.cjs → chunk-5K7PRPSV.cjs} +30 -2
  20. package/dist/chunk-5K7PRPSV.cjs.map +1 -0
  21. package/dist/{chunk-QQCHM7BZ.cjs → chunk-5VA2HJ5B.cjs} +6 -6
  22. package/dist/{chunk-QQCHM7BZ.cjs.map → chunk-5VA2HJ5B.cjs.map} +1 -1
  23. package/dist/{chunk-PJ6CC53R.cjs → chunk-AKMTPCLC.cjs} +13 -8
  24. package/dist/chunk-AKMTPCLC.cjs.map +1 -0
  25. package/dist/{chunk-OODVC2UD.cjs → chunk-AWSSWNJY.cjs} +2 -2
  26. package/dist/{chunk-OODVC2UD.cjs.map → chunk-AWSSWNJY.cjs.map} +1 -1
  27. package/dist/chunk-BFVYM6IT.cjs +345 -0
  28. package/dist/chunk-BFVYM6IT.cjs.map +1 -0
  29. package/dist/{chunk-VVDE4CHU.js → chunk-C4GEPUE7.js} +13 -8
  30. package/dist/chunk-C4GEPUE7.js.map +1 -0
  31. package/dist/{chunk-TJ4GWQPM.js → chunk-DAAJ3B2T.js} +121 -65
  32. package/dist/chunk-DAAJ3B2T.js.map +1 -0
  33. package/dist/{chunk-QJ2L5RU6.js → chunk-DSQCYX7L.js} +2 -2
  34. package/dist/{chunk-QJ2L5RU6.js.map → chunk-DSQCYX7L.js.map} +1 -1
  35. package/dist/{chunk-NUB5HRKS.js → chunk-DT3X3RBM.js} +3 -3
  36. package/dist/{chunk-NUB5HRKS.js.map → chunk-DT3X3RBM.js.map} +1 -1
  37. package/dist/{chunk-AG5EKCE4.js → chunk-EBQG3NGT.js} +30 -2
  38. package/dist/chunk-EBQG3NGT.js.map +1 -0
  39. package/dist/{chunk-MYAU2ZUC.cjs → chunk-GDKOYVX3.cjs} +14 -10
  40. package/dist/chunk-GDKOYVX3.cjs.map +1 -0
  41. package/dist/{chunk-JTSKPDPH.cjs → chunk-HIYQ3M5V.cjs} +4 -3
  42. package/dist/chunk-HIYQ3M5V.cjs.map +1 -0
  43. package/dist/{chunk-7IBZA7G6.js → chunk-I6Y2KLTZ.js} +5 -2
  44. package/dist/chunk-I6Y2KLTZ.js.map +1 -0
  45. package/dist/chunk-IZY4CMOO.js +715 -0
  46. package/dist/chunk-IZY4CMOO.js.map +1 -0
  47. package/dist/{chunk-753ENNB6.js → chunk-J3QEMZCH.js} +2 -2
  48. package/dist/{chunk-753ENNB6.js.map → chunk-J3QEMZCH.js.map} +1 -1
  49. package/dist/{chunk-S2JZL4JC.js → chunk-JM4YFLO4.js} +22 -15
  50. package/dist/chunk-JM4YFLO4.js.map +1 -0
  51. package/dist/{chunk-QX6AAVDE.cjs → chunk-L4APW65W.cjs} +15 -6
  52. package/dist/chunk-L4APW65W.cjs.map +1 -0
  53. package/dist/{chunk-OHKO5THF.cjs → chunk-MGFRGPWI.cjs} +3 -2
  54. package/dist/chunk-MGFRGPWI.cjs.map +1 -0
  55. package/dist/{chunk-RM2HPQIC.js → chunk-MQ5WJ3NO.js} +4 -4
  56. package/dist/chunk-MQ5WJ3NO.js.map +1 -0
  57. package/dist/{chunk-VNWJTCBQ.js → chunk-MQOYDQTF.js} +4 -3
  58. package/dist/chunk-MQOYDQTF.js.map +1 -0
  59. package/dist/chunk-MZA2LDS4.js +321 -0
  60. package/dist/chunk-MZA2LDS4.js.map +1 -0
  61. package/dist/{chunk-VYNFJVRZ.js → chunk-N6XBE47W.js} +3 -3
  62. package/dist/{chunk-VYNFJVRZ.js.map → chunk-N6XBE47W.js.map} +1 -1
  63. package/dist/{chunk-T5BBZQ66.js → chunk-OTIKWEFZ.js} +9 -4
  64. package/dist/chunk-OTIKWEFZ.js.map +1 -0
  65. package/dist/{chunk-YZCM7CXK.js → chunk-OZKJYLN6.js} +3 -3
  66. package/dist/{chunk-YZCM7CXK.js.map → chunk-OZKJYLN6.js.map} +1 -1
  67. package/dist/{chunk-ZSGEGISB.cjs → chunk-PHUTJKHL.cjs} +5 -2
  68. package/dist/chunk-PHUTJKHL.cjs.map +1 -0
  69. package/dist/{chunk-FMEA6WAY.cjs → chunk-Q6QLGCL7.cjs} +9 -9
  70. package/dist/{chunk-FMEA6WAY.cjs.map → chunk-Q6QLGCL7.cjs.map} +1 -1
  71. package/dist/{chunk-XOIIUO6O.js → chunk-QDNHN7R2.js} +3 -2
  72. package/dist/chunk-QDNHN7R2.js.map +1 -0
  73. package/dist/{chunk-XRVMYT5G.cjs → chunk-QKW2QCGI.cjs} +5 -5
  74. package/dist/chunk-QKW2QCGI.cjs.map +1 -0
  75. package/dist/{chunk-NAH65KPK.cjs → chunk-TOJ56HKQ.cjs} +2 -2
  76. package/dist/{chunk-NAH65KPK.cjs.map → chunk-TOJ56HKQ.cjs.map} +1 -1
  77. package/dist/chunk-TRZLN32I.cjs +740 -0
  78. package/dist/chunk-TRZLN32I.cjs.map +1 -0
  79. package/dist/{chunk-O6XDA3SI.js → chunk-UY2EZYIC.js} +15 -6
  80. package/dist/chunk-UY2EZYIC.js.map +1 -0
  81. package/dist/{chunk-2BPIVWAK.js → chunk-V5VPECJI.js} +14 -10
  82. package/dist/chunk-V5VPECJI.js.map +1 -0
  83. package/dist/{chunk-O6BJMVGT.cjs → chunk-XZNHS7YQ.cjs} +24 -17
  84. package/dist/chunk-XZNHS7YQ.cjs.map +1 -0
  85. package/dist/components/AudioPlayer/index.cjs +7 -6
  86. package/dist/components/AudioPlayer/index.js +2 -1
  87. package/dist/components/CollabStatus/index.cjs +5 -4
  88. package/dist/components/CollabStatus/index.js +2 -1
  89. package/dist/components/CountryCodeDropdown/index.cjs +4 -4
  90. package/dist/components/CountryCodeDropdown/index.js +1 -1
  91. package/dist/components/DateInput/index.cjs +2 -2
  92. package/dist/components/DateInput/index.js +1 -1
  93. package/dist/components/DictationButton/index.cjs +23 -0
  94. package/dist/components/DictationButton/index.cjs.map +1 -0
  95. package/dist/components/DictationButton/index.d.cts +78 -0
  96. package/dist/components/DictationButton/index.d.ts +78 -0
  97. package/dist/components/DictationButton/index.js +6 -0
  98. package/dist/components/DictationButton/index.js.map +1 -0
  99. package/dist/components/Markdown/index.cjs +10 -10
  100. package/dist/components/Markdown/index.js +2 -2
  101. package/dist/components/MediaEditor/index.cjs +8 -7
  102. package/dist/components/MediaEditor/index.js +3 -2
  103. package/dist/components/PhoneInput/index.cjs +3 -3
  104. package/dist/components/PhoneInput/index.js +1 -1
  105. package/dist/components/RecordButton/index.cjs +4 -4
  106. package/dist/components/RecordButton/index.js +1 -1
  107. package/dist/components/Slider/index.cjs +6 -5
  108. package/dist/components/Slider/index.js +2 -1
  109. package/dist/components/SliderCalculator/index.cjs +5 -4
  110. package/dist/components/SliderCalculator/index.js +3 -2
  111. package/dist/components/SuperChat/index.cjs +14 -14
  112. package/dist/components/SuperChat/index.cjs.map +1 -1
  113. package/dist/components/SuperChat/index.d.cts +10 -6
  114. package/dist/components/SuperChat/index.d.ts +10 -6
  115. package/dist/components/SuperChat/index.js +4 -4
  116. package/dist/components/SuperChat/index.js.map +1 -1
  117. package/dist/components/SuperChat/plugins/index.cjs +3 -3
  118. package/dist/components/SuperChat/plugins/index.d.cts +2 -2
  119. package/dist/components/SuperChat/plugins/index.d.ts +2 -2
  120. package/dist/components/SuperChat/plugins/index.js +2 -2
  121. package/dist/components/Table/index.cjs +9 -9
  122. package/dist/components/Table/index.d.cts +17 -1
  123. package/dist/components/Table/index.d.ts +17 -1
  124. package/dist/components/Table/index.js +1 -1
  125. package/dist/deck.cjs +1 -1
  126. package/dist/deck.cjs.map +1 -1
  127. package/dist/deck.js +1 -1
  128. package/dist/deck.js.map +1 -1
  129. package/dist/esheet.cjs +5 -5
  130. package/dist/esheet.js +2 -2
  131. package/dist/index.cjs +600 -1134
  132. package/dist/index.cjs.map +1 -1
  133. package/dist/index.d.cts +154 -14
  134. package/dist/index.d.ts +154 -14
  135. package/dist/index.js +230 -834
  136. package/dist/index.js.map +1 -1
  137. package/dist/styles/init.css +39 -0
  138. package/dist/styles.css +1 -1
  139. package/dist/tailwind-preset.cjs +4 -4
  140. package/dist/tailwind-preset.js +1 -1
  141. package/dist/{types-Cx1FHLq2.d.ts → types-DSWbrVkM.d.cts} +1 -1
  142. package/dist/{types-Cx1FHLq2.d.cts → types-DSWbrVkM.d.ts} +1 -1
  143. package/dist/whisperTranscribe-AV752TZI.cjs +81 -0
  144. package/dist/whisperTranscribe-AV752TZI.cjs.map +1 -0
  145. package/dist/whisperTranscribe-UBNUWXUQ.js +4 -0
  146. package/dist/whisperTranscribe-UBNUWXUQ.js.map +1 -0
  147. package/package.json +1 -1
  148. package/dist/chunk-2BPIVWAK.js.map +0 -1
  149. package/dist/chunk-7IBZA7G6.js.map +0 -1
  150. package/dist/chunk-AFDW64EF.cjs.map +0 -1
  151. package/dist/chunk-AG5EKCE4.js.map +0 -1
  152. package/dist/chunk-CFI3TQMA.cjs.map +0 -1
  153. package/dist/chunk-IJYTASQQ.cjs.map +0 -1
  154. package/dist/chunk-JTSKPDPH.cjs.map +0 -1
  155. package/dist/chunk-MYAU2ZUC.cjs.map +0 -1
  156. package/dist/chunk-O6BJMVGT.cjs.map +0 -1
  157. package/dist/chunk-O6XDA3SI.js.map +0 -1
  158. package/dist/chunk-OHKO5THF.cjs.map +0 -1
  159. package/dist/chunk-PJ6CC53R.cjs.map +0 -1
  160. package/dist/chunk-QX6AAVDE.cjs.map +0 -1
  161. package/dist/chunk-RM2HPQIC.js.map +0 -1
  162. package/dist/chunk-S2JZL4JC.js.map +0 -1
  163. package/dist/chunk-T5BBZQ66.js.map +0 -1
  164. package/dist/chunk-TJ4GWQPM.js.map +0 -1
  165. package/dist/chunk-TNUL4LGG.js.map +0 -1
  166. package/dist/chunk-U2RS574O.cjs.map +0 -1
  167. package/dist/chunk-VNWJTCBQ.js.map +0 -1
  168. package/dist/chunk-VVDE4CHU.js.map +0 -1
  169. package/dist/chunk-XOIIUO6O.js.map +0 -1
  170. package/dist/chunk-XRVMYT5G.cjs.map +0 -1
  171. package/dist/chunk-ZSGEGISB.cjs.map +0 -1
@@ -0,0 +1,321 @@
1
+ import { RecordButton, formatDuration } from './chunk-MQOYDQTF.js';
2
+ import { cn } from './chunk-TQONQSJO.js';
3
+ import * as React from 'react';
4
+ import { jsxs, jsx } from 'react/jsx-runtime';
5
+
6
+ var onDeviceTranscribe = async (audio, signal) => {
7
+ const { transcribeBlob } = await import('./whisperTranscribe-UBNUWXUQ.js');
8
+ if (signal.aborted) throw new Error("Dictation cancelled");
9
+ return transcribeBlob(audio);
10
+ };
11
+ function toError(value) {
12
+ if (value instanceof Error) return value;
13
+ if (value && typeof value === "object" && "name" in value && "message" in value)
14
+ return value;
15
+ return new Error(String(value));
16
+ }
17
+ function liveAudio(stream) {
18
+ return stream?.getAudioTracks().some((track) => track.readyState === "live") ? stream : null;
19
+ }
20
+ function useDictation({
21
+ onText,
22
+ transcribe,
23
+ onError,
24
+ maxDurationSeconds = 300,
25
+ getStream
26
+ }) {
27
+ const [status, setStatus] = React.useState("idle");
28
+ const [error, setError] = React.useState(null);
29
+ const [elapsedMs, setElapsedMs] = React.useState(0);
30
+ const callbacksRef = React.useRef({ onText, onError, transcribe, getStream });
31
+ callbacksRef.current = { onText, onError, transcribe, getStream };
32
+ const maxMsRef = React.useRef(maxDurationSeconds * 1e3);
33
+ maxMsRef.current = maxDurationSeconds * 1e3;
34
+ const sessionRef = React.useRef(0);
35
+ const busyRef = React.useRef(false);
36
+ const mountedRef = React.useRef(true);
37
+ const streamRef = React.useRef(null);
38
+ const recorderRef = React.useRef(null);
39
+ const timerRef = React.useRef(null);
40
+ const abortRef = React.useRef(null);
41
+ const releaseMic = React.useCallback(() => {
42
+ if (timerRef.current) clearInterval(timerRef.current);
43
+ timerRef.current = null;
44
+ streamRef.current?.getTracks().forEach((track) => track.stop());
45
+ streamRef.current = null;
46
+ }, []);
47
+ const fail = React.useCallback(
48
+ (err) => {
49
+ releaseMic();
50
+ recorderRef.current = null;
51
+ busyRef.current = false;
52
+ const e = toError(err);
53
+ if (mountedRef.current) {
54
+ setError(e);
55
+ setStatus("error");
56
+ }
57
+ callbacksRef.current.onError?.(e);
58
+ },
59
+ [releaseMic]
60
+ );
61
+ const finish = React.useCallback(
62
+ async (session, chunks, mimeType) => {
63
+ if (session !== sessionRef.current) return;
64
+ releaseMic();
65
+ recorderRef.current = null;
66
+ const audio = new Blob(chunks, { type: mimeType });
67
+ if (audio.size === 0) {
68
+ busyRef.current = false;
69
+ if (mountedRef.current) setStatus("idle");
70
+ return;
71
+ }
72
+ const controller = new AbortController();
73
+ abortRef.current = controller;
74
+ if (mountedRef.current) setStatus("transcribing");
75
+ try {
76
+ const run = callbacksRef.current.transcribe ?? onDeviceTranscribe;
77
+ const text = (await run(audio, controller.signal)).trim();
78
+ if (session !== sessionRef.current || controller.signal.aborted) return;
79
+ busyRef.current = false;
80
+ abortRef.current = null;
81
+ if (mountedRef.current) setStatus("idle");
82
+ if (text) callbacksRef.current.onText(text);
83
+ } catch (err) {
84
+ if (session !== sessionRef.current || controller.signal.aborted) return;
85
+ abortRef.current = null;
86
+ fail(err);
87
+ }
88
+ },
89
+ [releaseMic, fail]
90
+ );
91
+ const cancel = React.useCallback(() => {
92
+ sessionRef.current += 1;
93
+ abortRef.current?.abort();
94
+ abortRef.current = null;
95
+ const recorder = recorderRef.current;
96
+ recorderRef.current = null;
97
+ if (recorder && recorder.state !== "inactive") recorder.stop();
98
+ releaseMic();
99
+ busyRef.current = false;
100
+ if (mountedRef.current) {
101
+ setStatus("idle");
102
+ setError(null);
103
+ setElapsedMs(0);
104
+ }
105
+ }, [releaseMic]);
106
+ const stop = React.useCallback(() => {
107
+ const recorder = recorderRef.current;
108
+ if (recorder) {
109
+ if (recorder.state !== "inactive") recorder.stop();
110
+ } else if (busyRef.current && !abortRef.current) {
111
+ cancel();
112
+ }
113
+ }, [cancel]);
114
+ const start = React.useCallback(async () => {
115
+ if (busyRef.current) return;
116
+ busyRef.current = true;
117
+ const session = ++sessionRef.current;
118
+ setStatus("idle");
119
+ setError(null);
120
+ setElapsedMs(0);
121
+ let shared;
122
+ try {
123
+ shared = liveAudio(callbacksRef.current.getStream?.());
124
+ } catch (err) {
125
+ fail(err);
126
+ return;
127
+ }
128
+ if (typeof MediaRecorder === "undefined" || !shared && (typeof navigator === "undefined" || !navigator.mediaDevices?.getUserMedia)) {
129
+ fail(new Error("Microphone is not available in this context"));
130
+ return;
131
+ }
132
+ let stream;
133
+ if (shared) {
134
+ stream = shared;
135
+ } else {
136
+ try {
137
+ stream = await navigator.mediaDevices.getUserMedia({ audio: true });
138
+ } catch (err) {
139
+ if (session === sessionRef.current) fail(err);
140
+ return;
141
+ }
142
+ if (session !== sessionRef.current) {
143
+ stream.getTracks().forEach((track) => track.stop());
144
+ return;
145
+ }
146
+ streamRef.current = stream;
147
+ }
148
+ let recorder;
149
+ try {
150
+ recorder = new MediaRecorder(stream);
151
+ } catch (err) {
152
+ fail(err);
153
+ return;
154
+ }
155
+ const chunks = [];
156
+ recorder.ondataavailable = (e) => {
157
+ if (e.data.size > 0) chunks.push(e.data);
158
+ };
159
+ recorder.onstop = () => {
160
+ void finish(session, chunks, recorder.mimeType || "audio/webm");
161
+ };
162
+ recorder.onerror = (e) => {
163
+ if (session !== sessionRef.current) return;
164
+ sessionRef.current += 1;
165
+ recorderRef.current = null;
166
+ fail(e.error ?? e);
167
+ };
168
+ if (!shared) {
169
+ stream.getAudioTracks().forEach((track) => {
170
+ track.addEventListener("ended", () => {
171
+ if (recorderRef.current === recorder && recorder.state !== "inactive")
172
+ recorder.stop();
173
+ });
174
+ });
175
+ }
176
+ recorderRef.current = recorder;
177
+ try {
178
+ recorder.start();
179
+ } catch (err) {
180
+ recorderRef.current = null;
181
+ fail(err);
182
+ return;
183
+ }
184
+ setStatus("recording");
185
+ const startedAt = Date.now();
186
+ timerRef.current = setInterval(() => {
187
+ const elapsed = Date.now() - startedAt;
188
+ setElapsedMs(elapsed);
189
+ if (maxMsRef.current > 0 && elapsed >= maxMsRef.current) {
190
+ if (recorder.state !== "inactive") recorder.stop();
191
+ }
192
+ }, 250);
193
+ }, [fail, finish]);
194
+ React.useEffect(() => {
195
+ mountedRef.current = true;
196
+ return () => {
197
+ mountedRef.current = false;
198
+ cancel();
199
+ };
200
+ }, [cancel]);
201
+ return { status, error, elapsedMs, start, stop, cancel };
202
+ }
203
+ var defaultDictationLabels = {
204
+ start: "Start dictation",
205
+ stop: "Stop dictation",
206
+ listening: "Listening\u2026",
207
+ transcribing: "Transcribing\u2026",
208
+ error: "Dictation failed. Try again.",
209
+ micBlocked: "Microphone access is blocked."
210
+ };
211
+ var buttonState = {
212
+ idle: "idle",
213
+ recording: "recording",
214
+ transcribing: "processing",
215
+ error: "error"
216
+ };
217
+ var DictationButton = React.forwardRef(
218
+ ({
219
+ onText,
220
+ transcribe,
221
+ onError,
222
+ maxDurationSeconds,
223
+ getStream,
224
+ disabled = false,
225
+ size = "sm",
226
+ variant = "ghost",
227
+ showDuration = false,
228
+ showStatus = false,
229
+ labels: labelOverrides,
230
+ className,
231
+ handleRef,
232
+ ...rest
233
+ }, ref) => {
234
+ const labels = { ...defaultDictationLabels, ...labelOverrides };
235
+ const { status, error, elapsedMs, start, stop, cancel } = useDictation({
236
+ onText,
237
+ transcribe,
238
+ onError,
239
+ maxDurationSeconds,
240
+ getStream
241
+ });
242
+ React.useEffect(() => {
243
+ if (disabled) cancel();
244
+ }, [disabled, cancel]);
245
+ React.useImperativeHandle(
246
+ handleRef,
247
+ () => ({
248
+ start: () => {
249
+ if (!disabled) void start();
250
+ },
251
+ stop,
252
+ cancel
253
+ }),
254
+ [disabled, start, stop, cancel]
255
+ );
256
+ React.useEffect(() => {
257
+ if (status !== "recording") return;
258
+ const onEscape = (e) => {
259
+ if (e.key !== "Escape" || e.defaultPrevented) return;
260
+ e.preventDefault();
261
+ cancel();
262
+ };
263
+ document.addEventListener("keydown", onEscape);
264
+ return () => document.removeEventListener("keydown", onEscape);
265
+ }, [status, cancel]);
266
+ const errorText = error?.name === "NotAllowedError" ? labels.micBlocked : labels.error;
267
+ const statusText = status === "recording" ? labels.listening : status === "transcribing" ? labels.transcribing : status === "error" ? errorText : "";
268
+ const ariaLabel = status === "recording" ? labels.stop : status === "transcribing" ? labels.transcribing : status === "error" ? errorText : labels.start;
269
+ return /* @__PURE__ */ jsxs(
270
+ "div",
271
+ {
272
+ "data-slot": "dictation-button",
273
+ className: cn("inline-flex items-center gap-2", className),
274
+ children: [
275
+ /* @__PURE__ */ jsx(
276
+ RecordButton,
277
+ {
278
+ ...rest,
279
+ ref,
280
+ state: disabled ? "disabled" : buttonState[status],
281
+ disabled,
282
+ size,
283
+ variant,
284
+ "aria-label": ariaLabel,
285
+ onClick: () => {
286
+ if (status === "recording") stop();
287
+ else void start();
288
+ }
289
+ }
290
+ ),
291
+ showDuration && status === "recording" && /* @__PURE__ */ jsx(
292
+ "span",
293
+ {
294
+ "data-slot": "dictation-button-duration",
295
+ className: "text-destructive font-mono text-xs tabular-nums",
296
+ children: formatDuration(elapsedMs / 1e3)
297
+ }
298
+ ),
299
+ /* @__PURE__ */ jsx(
300
+ "span",
301
+ {
302
+ role: "status",
303
+ "data-slot": "dictation-button-status",
304
+ className: cn(
305
+ "text-xs",
306
+ status === "error" ? "text-destructive" : "text-muted-foreground",
307
+ !showStatus && "sr-only"
308
+ ),
309
+ children: statusText
310
+ }
311
+ )
312
+ ]
313
+ }
314
+ );
315
+ }
316
+ );
317
+ DictationButton.displayName = "DictationButton";
318
+
319
+ export { DictationButton, defaultDictationLabels, useDictation };
320
+ //# sourceMappingURL=chunk-MZA2LDS4.js.map
321
+ //# sourceMappingURL=chunk-MZA2LDS4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/DictationButton/useDictation.ts","../src/components/DictationButton/DictationButton.tsx"],"names":["React2"],"mappings":"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","file":"chunk-MZA2LDS4.js","sourcesContent":["import * as React from 'react';\n\nexport type DictationStatus = 'idle' | 'recording' | 'transcribing' | 'error';\n\n/** Turns recorded audio into text. Reject to report an error; honor `signal` to support cancel. */\nexport type DictationTranscribe = (\n audio: Blob,\n signal: AbortSignal\n) => Promise<string>;\n\nexport interface UseDictationOptions {\n /** Called with the final, trimmed transcript. Not called for empty results or after cancel. */\n onText: (text: string) => void;\n /** Transcription provider. Defaults to on-device Whisper (audio never leaves the browser). */\n transcribe?: DictationTranscribe;\n /** Called with the underlying error (permission denied, provider failure, …). */\n onError?: (error: Error) => void;\n /** Auto-stop after this many seconds. `0` disables the limit. Default 300. */\n maxDurationSeconds?: number;\n /**\n * Reuse a mic stream the host already holds (e.g. a wake-word listener) instead of opening one.\n * Its tracks are never stopped by the hook. Falls back to `getUserMedia` when it returns no live audio.\n */\n getStream?: () => MediaStream | null | undefined;\n}\n\nexport interface UseDictationResult {\n status: DictationStatus;\n error: Error | null;\n /** Milliseconds recorded so far in the current session. */\n elapsedMs: number;\n start: () => Promise<void>;\n /** Stop recording and transcribe. */\n stop: () => void;\n /** Discard the recording or in-flight transcription. `onText` will not fire. */\n cancel: () => void;\n}\n\nconst onDeviceTranscribe: DictationTranscribe = async (audio, signal) => {\n // Loaded lazily so hosts using a server provider never pull in Whisper.\n const { transcribeBlob } = await import('../AI/whisperTranscribe');\n // The shared worker cannot stop a running decode, so cancel only discards its result.\n if (signal.aborted) throw new Error('Dictation cancelled');\n return transcribeBlob(audio);\n};\n\nfunction toError(value: unknown): Error {\n if (value instanceof Error) return value;\n // DOMException (e.g. NotAllowedError) is not an Error subclass in every runtime; keep its `name`.\n if (\n value &&\n typeof value === 'object' &&\n 'name' in value &&\n 'message' in value\n )\n return value as Error;\n return new Error(String(value));\n}\n\nfunction liveAudio(stream: MediaStream | null | undefined) {\n return stream?.getAudioTracks().some((track) => track.readyState === 'live')\n ? stream\n : null;\n}\n\n/**\n * Headless speech-to-text for a single speaker: record, then transcribe to editable text.\n * Owns the mic lifecycle; every async step is tied to a session id so stale results are dropped.\n */\nexport function useDictation({\n onText,\n transcribe,\n onError,\n maxDurationSeconds = 300,\n getStream,\n}: UseDictationOptions): UseDictationResult {\n const [status, setStatus] = React.useState<DictationStatus>('idle');\n const [error, setError] = React.useState<Error | null>(null);\n const [elapsedMs, setElapsedMs] = React.useState(0);\n\n const callbacksRef = React.useRef({ onText, onError, transcribe, getStream });\n callbacksRef.current = { onText, onError, transcribe, getStream };\n const maxMsRef = React.useRef(maxDurationSeconds * 1000);\n maxMsRef.current = maxDurationSeconds * 1000;\n\n const sessionRef = React.useRef(0);\n const busyRef = React.useRef(false);\n const mountedRef = React.useRef(true);\n // Only streams the hook opened; a host-shared stream is never stored here, so it is never stopped.\n const streamRef = React.useRef<MediaStream | null>(null);\n const recorderRef = React.useRef<MediaRecorder | null>(null);\n const timerRef = React.useRef<ReturnType<typeof setInterval> | null>(null);\n const abortRef = React.useRef<AbortController | null>(null);\n\n const releaseMic = React.useCallback(() => {\n if (timerRef.current) clearInterval(timerRef.current);\n timerRef.current = null;\n streamRef.current?.getTracks().forEach((track) => track.stop());\n streamRef.current = null;\n }, []);\n\n const fail = React.useCallback(\n (err: unknown) => {\n releaseMic();\n recorderRef.current = null;\n busyRef.current = false;\n const e = toError(err);\n if (mountedRef.current) {\n setError(e);\n setStatus('error');\n }\n callbacksRef.current.onError?.(e);\n },\n [releaseMic]\n );\n\n const finish = React.useCallback(\n async (session: number, chunks: Blob[], mimeType: string) => {\n // A stale session must not touch refs that may already belong to a new one.\n if (session !== sessionRef.current) return;\n releaseMic();\n recorderRef.current = null;\n\n const audio = new Blob(chunks, { type: mimeType });\n if (audio.size === 0) {\n busyRef.current = false;\n if (mountedRef.current) setStatus('idle');\n return;\n }\n\n const controller = new AbortController();\n abortRef.current = controller;\n if (mountedRef.current) setStatus('transcribing');\n try {\n const run = callbacksRef.current.transcribe ?? onDeviceTranscribe;\n const text = (await run(audio, controller.signal)).trim();\n if (session !== sessionRef.current || controller.signal.aborted) return;\n busyRef.current = false;\n abortRef.current = null;\n if (mountedRef.current) setStatus('idle');\n if (text) callbacksRef.current.onText(text);\n } catch (err) {\n if (session !== sessionRef.current || controller.signal.aborted) return;\n abortRef.current = null;\n fail(err);\n }\n },\n [releaseMic, fail]\n );\n\n const cancel = React.useCallback(() => {\n sessionRef.current += 1;\n abortRef.current?.abort();\n abortRef.current = null;\n const recorder = recorderRef.current;\n recorderRef.current = null;\n if (recorder && recorder.state !== 'inactive') recorder.stop();\n releaseMic();\n busyRef.current = false;\n if (mountedRef.current) {\n setStatus('idle');\n setError(null);\n setElapsedMs(0);\n }\n }, [releaseMic]);\n\n const stop = React.useCallback(() => {\n const recorder = recorderRef.current;\n if (recorder) {\n // Already inactive means onstop is queued; cancelling here would drop the take.\n if (recorder.state !== 'inactive') recorder.stop();\n } else if (busyRef.current && !abortRef.current) {\n // Still waiting on the permission prompt: nothing recorded yet.\n cancel();\n }\n }, [cancel]);\n\n const start = React.useCallback(async () => {\n if (busyRef.current) return;\n busyRef.current = true;\n const session = ++sessionRef.current;\n setStatus('idle');\n setError(null);\n setElapsedMs(0);\n\n let shared: MediaStream | null;\n try {\n shared = liveAudio(callbacksRef.current.getStream?.());\n } catch (err) {\n fail(err);\n return;\n }\n if (\n typeof MediaRecorder === 'undefined' ||\n (!shared &&\n (typeof navigator === 'undefined' ||\n !navigator.mediaDevices?.getUserMedia))\n ) {\n fail(new Error('Microphone is not available in this context'));\n return;\n }\n\n let stream: MediaStream;\n if (shared) {\n stream = shared;\n } else {\n try {\n stream = await navigator.mediaDevices.getUserMedia({ audio: true });\n } catch (err) {\n if (session === sessionRef.current) fail(err);\n return;\n }\n if (session !== sessionRef.current) {\n // Cancelled or unmounted while the permission prompt was open.\n stream.getTracks().forEach((track) => track.stop());\n return;\n }\n streamRef.current = stream;\n }\n\n let recorder: MediaRecorder;\n try {\n recorder = new MediaRecorder(stream);\n } catch (err) {\n fail(err);\n return;\n }\n\n const chunks: Blob[] = [];\n recorder.ondataavailable = (e) => {\n if (e.data.size > 0) chunks.push(e.data);\n };\n recorder.onstop = () => {\n void finish(session, chunks, recorder.mimeType || 'audio/webm');\n };\n recorder.onerror = (e) => {\n if (session !== sessionRef.current) return;\n sessionRef.current += 1;\n recorderRef.current = null;\n fail((e as Event & { error?: unknown }).error ?? e);\n };\n // Shared tracks live longer than one take; MediaRecorder stops by itself if they end.\n if (!shared) {\n stream.getAudioTracks().forEach((track) => {\n track.addEventListener('ended', () => {\n if (recorderRef.current === recorder && recorder.state !== 'inactive')\n recorder.stop();\n });\n });\n }\n\n recorderRef.current = recorder;\n try {\n recorder.start();\n } catch (err) {\n recorderRef.current = null;\n fail(err);\n return;\n }\n setStatus('recording');\n\n const startedAt = Date.now();\n timerRef.current = setInterval(() => {\n const elapsed = Date.now() - startedAt;\n setElapsedMs(elapsed);\n if (maxMsRef.current > 0 && elapsed >= maxMsRef.current) {\n if (recorder.state !== 'inactive') recorder.stop();\n }\n }, 250);\n }, [fail, finish]);\n\n React.useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n cancel();\n };\n }, [cancel]);\n\n return { status, error, elapsedMs, start, stop, cancel };\n}\n","import * as React from 'react';\nimport {\n RecordButton,\n formatDuration,\n type RecordButtonSize,\n type RecordButtonState,\n type RecordButtonVariant,\n} from '../RecordButton';\nimport { cn } from '../../utils/cn';\nimport {\n useDictation,\n type DictationStatus,\n type UseDictationOptions,\n} from './useDictation';\n\nexport interface DictationButtonLabels {\n start: string;\n stop: string;\n listening: string;\n transcribing: string;\n error: string;\n micBlocked: string;\n}\n\nexport const defaultDictationLabels: DictationButtonLabels = {\n start: 'Start dictation',\n stop: 'Stop dictation',\n listening: 'Listening…',\n transcribing: 'Transcribing…',\n error: 'Dictation failed. Try again.',\n micBlocked: 'Microphone access is blocked.',\n};\n\n/** Drive dictation from code, e.g. when a wake word fires. */\nexport interface DictationButtonHandle {\n /** Does nothing while `disabled` or while a take is already in progress. */\n start: () => void;\n /** Stop recording and transcribe. */\n stop: () => void;\n /** Discard the take; `onText` will not fire. */\n cancel: () => void;\n}\n\nexport interface DictationButtonProps\n extends\n UseDictationOptions,\n Omit<\n React.ButtonHTMLAttributes<HTMLButtonElement>,\n // The ARIA attributes follow the dictation state; customise text through `labels`.\n | 'children'\n | 'onClick'\n | 'onError'\n | 'disabled'\n | 'className'\n | 'aria-label'\n | 'aria-pressed'\n | 'aria-busy'\n > {\n disabled?: boolean;\n size?: RecordButtonSize;\n variant?: RecordButtonVariant;\n /** Show `m:ss` while recording. */\n showDuration?: boolean;\n /** Show the listening/transcribing/error caption. It is always announced to screen readers. */\n showStatus?: boolean;\n /** Override any user-facing string (i18n). */\n labels?: Partial<DictationButtonLabels>;\n className?: string;\n /** Start, stop or cancel from code. `ref` stays the `<button>`. */\n handleRef?: React.Ref<DictationButtonHandle>;\n}\n\nconst buttonState: Record<DictationStatus, RecordButtonState> = {\n idle: 'idle',\n recording: 'recording',\n transcribing: 'processing',\n error: 'error',\n};\n\n/**\n * Mic button that turns speech into editable text via `onText`. Never sends anything itself.\n * Escape while recording discards the take.\n */\nexport const DictationButton = React.forwardRef<\n HTMLButtonElement,\n DictationButtonProps\n>(\n (\n {\n onText,\n transcribe,\n onError,\n maxDurationSeconds,\n getStream,\n disabled = false,\n size = 'sm',\n variant = 'ghost',\n showDuration = false,\n showStatus = false,\n labels: labelOverrides,\n className,\n handleRef,\n ...rest\n },\n ref\n ) => {\n const labels = { ...defaultDictationLabels, ...labelOverrides };\n const { status, error, elapsedMs, start, stop, cancel } = useDictation({\n onText,\n transcribe,\n onError,\n maxDurationSeconds,\n getStream,\n });\n\n // Covers a pending permission prompt (status still idle) and transcribing, not just recording.\n React.useEffect(() => {\n if (disabled) cancel();\n }, [disabled, cancel]);\n\n React.useImperativeHandle(\n handleRef,\n () => ({\n start: () => {\n if (!disabled) void start();\n },\n stop,\n cancel,\n }),\n [disabled, start, stop, cancel]\n );\n\n // Document-level so Escape works while focus stays in the composer.\n React.useEffect(() => {\n if (status !== 'recording') return;\n const onEscape = (e: KeyboardEvent) => {\n if (e.key !== 'Escape' || e.defaultPrevented) return;\n e.preventDefault();\n cancel();\n };\n document.addEventListener('keydown', onEscape);\n return () => document.removeEventListener('keydown', onEscape);\n }, [status, cancel]);\n\n const errorText =\n error?.name === 'NotAllowedError' ? labels.micBlocked : labels.error;\n const statusText =\n status === 'recording'\n ? labels.listening\n : status === 'transcribing'\n ? labels.transcribing\n : status === 'error'\n ? errorText\n : '';\n const ariaLabel =\n status === 'recording'\n ? labels.stop\n : status === 'transcribing'\n ? labels.transcribing\n : status === 'error'\n ? errorText\n : labels.start;\n\n return (\n <div\n data-slot=\"dictation-button\"\n className={cn('inline-flex items-center gap-2', className)}\n >\n <RecordButton\n {...rest}\n ref={ref}\n state={disabled ? 'disabled' : buttonState[status]}\n disabled={disabled}\n size={size}\n variant={variant}\n aria-label={ariaLabel}\n onClick={() => {\n if (status === 'recording') stop();\n else void start();\n }}\n />\n {showDuration && status === 'recording' && (\n <span\n data-slot=\"dictation-button-duration\"\n className=\"text-destructive font-mono text-xs tabular-nums\"\n >\n {formatDuration(elapsedMs / 1000)}\n </span>\n )}\n <span\n role=\"status\"\n data-slot=\"dictation-button-status\"\n className={cn(\n 'text-xs',\n status === 'error' ? 'text-destructive' : 'text-muted-foreground',\n !showStatus && 'sr-only'\n )}\n >\n {statusText}\n </span>\n </div>\n );\n }\n);\n\nDictationButton.displayName = 'DictationButton';\n"]}
@@ -1,7 +1,7 @@
1
1
  import { Tooltip } from './chunk-YFWDS6MX.js';
2
2
  import { RadioGroup, Radio } from './chunk-EPSB4WTL.js';
3
3
  import { Label } from './chunk-I3WGZPI6.js';
4
- import { DateInput } from './chunk-7IBZA7G6.js';
4
+ import { DateInput } from './chunk-I6Y2KLTZ.js';
5
5
  import { Textarea } from './chunk-H3YO5GBM.js';
6
6
  import { Select } from './chunk-VCI2Y7ST.js';
7
7
  import { Card, CardHeader, CardContent } from './chunk-QYSUYB3S.js';
@@ -1592,5 +1592,5 @@ function MedicationReconciliation({
1592
1592
  }
1593
1593
 
1594
1594
  export { ALLERGY_TYPE_LABELS, AllergyList, AllergyManager, CodeLookupProvider, MEDICATION_STATUS_LABELS, MedicationEditor, MedicationList, MedicationReconciliation, RowActionToolbar, RowIconButton, labelToMedicationFields, lookupToMedicationFields, parseMedicationLabel, parseSig, toolbarKeyNav, useCodeLookupConfig };
1595
- //# sourceMappingURL=chunk-VYNFJVRZ.js.map
1596
- //# sourceMappingURL=chunk-VYNFJVRZ.js.map
1595
+ //# sourceMappingURL=chunk-N6XBE47W.js.map
1596
+ //# sourceMappingURL=chunk-N6XBE47W.js.map