@djangocfg/ui-tools 2.1.390 → 2.1.394

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 (184) hide show
  1. package/README.md +7 -10
  2. package/dist/chunk-PAWJFY3S.mjs +6 -0
  3. package/dist/{chunk-N2XQF2OL.mjs.map → chunk-PAWJFY3S.mjs.map} +1 -1
  4. package/dist/chunk-PK6SKIKE.cjs +8 -0
  5. package/dist/{chunk-OLISEQHS.cjs.map → chunk-PK6SKIKE.cjs.map} +1 -1
  6. package/dist/file-icon/index.cjs +6 -6
  7. package/dist/file-icon/index.d.cts +1 -1
  8. package/dist/file-icon/index.d.ts +1 -1
  9. package/dist/file-icon/index.mjs +1 -1
  10. package/dist/tree/index.cjs +1372 -143
  11. package/dist/tree/index.cjs.map +1 -1
  12. package/dist/tree/index.d.cts +2 -2
  13. package/dist/tree/index.d.ts +2 -2
  14. package/dist/tree/index.mjs +1322 -3
  15. package/dist/tree/index.mjs.map +1 -1
  16. package/dist/{types-CevSbyfD.d.cts → types-B_zhyAqR.d.cts} +1 -1
  17. package/dist/{types-CevSbyfD.d.ts → types-B_zhyAqR.d.ts} +1 -1
  18. package/package.json +6 -14
  19. package/src/tools/AudioPlayer/README.md +4 -4
  20. package/src/tools/Chat/README.md +6 -6
  21. package/src/tools/CronScheduler/index.tsx +1 -1
  22. package/src/tools/CronScheduler/lazy.tsx +1 -1
  23. package/src/tools/ImageViewer/README.md +1 -1
  24. package/src/tools/JsonForm/README.md +2 -2
  25. package/src/tools/MarkdownEditor/README.md +3 -3
  26. package/src/tools/MarkdownMessage/README.md +2 -2
  27. package/src/tools/OpenapiViewer/components/DocsLayout/grouping.ts +5 -1
  28. package/src/tools/PrettyCode/lazy.tsx +6 -0
  29. package/src/tools/SpeechRecognition/README.md +1 -1
  30. package/dist/ChatRoot-EFNXQXXN.cjs +0 -15
  31. package/dist/ChatRoot-EFNXQXXN.cjs.map +0 -1
  32. package/dist/ChatRoot-FITF5RVP.mjs +0 -6
  33. package/dist/ChatRoot-FITF5RVP.mjs.map +0 -1
  34. package/dist/ChatRoot-PNNGQCYF.css +0 -7
  35. package/dist/ChatRoot-PNNGQCYF.css.map +0 -1
  36. package/dist/CronScheduler.client-DLMXCPAJ.mjs +0 -67
  37. package/dist/CronScheduler.client-DLMXCPAJ.mjs.map +0 -1
  38. package/dist/CronScheduler.client-WEJF4PWQ.cjs +0 -72
  39. package/dist/CronScheduler.client-WEJF4PWQ.cjs.map +0 -1
  40. package/dist/DictationField-AS2F33WI.cjs +0 -13
  41. package/dist/DictationField-AS2F33WI.cjs.map +0 -1
  42. package/dist/DictationField-WPONUCYE.mjs +0 -4
  43. package/dist/DictationField-WPONUCYE.mjs.map +0 -1
  44. package/dist/DocsLayout-EKASBSP7.mjs +0 -3448
  45. package/dist/DocsLayout-EKASBSP7.mjs.map +0 -1
  46. package/dist/DocsLayout-MBFIB4NO.css +0 -7
  47. package/dist/DocsLayout-MBFIB4NO.css.map +0 -1
  48. package/dist/DocsLayout-OURFYWQE.cjs +0 -3455
  49. package/dist/DocsLayout-OURFYWQE.cjs.map +0 -1
  50. package/dist/JsonSchemaForm-DD7CLRIG.cjs +0 -13
  51. package/dist/JsonSchemaForm-DD7CLRIG.cjs.map +0 -1
  52. package/dist/JsonSchemaForm-XKUIVELK.mjs +0 -4
  53. package/dist/JsonSchemaForm-XKUIVELK.mjs.map +0 -1
  54. package/dist/JsonTree-43PQAJKY.mjs +0 -5
  55. package/dist/JsonTree-43PQAJKY.mjs.map +0 -1
  56. package/dist/JsonTree-MLET23ZA.css +0 -7
  57. package/dist/JsonTree-MLET23ZA.css.map +0 -1
  58. package/dist/JsonTree-X6W5YEVY.cjs +0 -11
  59. package/dist/JsonTree-X6W5YEVY.cjs.map +0 -1
  60. package/dist/LottiePlayer.client-2S7ISJ2S.cjs +0 -168
  61. package/dist/LottiePlayer.client-2S7ISJ2S.cjs.map +0 -1
  62. package/dist/LottiePlayer.client-5LDSSJWS.mjs +0 -161
  63. package/dist/LottiePlayer.client-5LDSSJWS.mjs.map +0 -1
  64. package/dist/MapContainer-AKIPABJK.mjs +0 -4
  65. package/dist/MapContainer-AKIPABJK.mjs.map +0 -1
  66. package/dist/MapContainer-STVDMC36.cjs +0 -17
  67. package/dist/MapContainer-STVDMC36.cjs.map +0 -1
  68. package/dist/Mermaid.client-DDXWXZXY.css +0 -7
  69. package/dist/Mermaid.client-DDXWXZXY.css.map +0 -1
  70. package/dist/Mermaid.client-NL4SVR7F.mjs +0 -481
  71. package/dist/Mermaid.client-NL4SVR7F.mjs.map +0 -1
  72. package/dist/Mermaid.client-NNTI6DFX.cjs +0 -487
  73. package/dist/Mermaid.client-NNTI6DFX.cjs.map +0 -1
  74. package/dist/Player-BRV7XTWR.mjs +0 -4
  75. package/dist/Player-BRV7XTWR.mjs.map +0 -1
  76. package/dist/Player-PM7F7DD7.cjs +0 -13
  77. package/dist/Player-PM7F7DD7.cjs.map +0 -1
  78. package/dist/Player-ZGQKKOWI.css +0 -66
  79. package/dist/Player-ZGQKKOWI.css.map +0 -1
  80. package/dist/PrettyCode.client-GWFAIVFN.css +0 -7
  81. package/dist/PrettyCode.client-GWFAIVFN.css.map +0 -1
  82. package/dist/PrettyCode.client-KOHDVPPN.cjs +0 -285
  83. package/dist/PrettyCode.client-KOHDVPPN.cjs.map +0 -1
  84. package/dist/PrettyCode.client-ZGYGKE7G.mjs +0 -283
  85. package/dist/PrettyCode.client-ZGYGKE7G.mjs.map +0 -1
  86. package/dist/TreeRoot-5COOOSWG.mjs +0 -4
  87. package/dist/TreeRoot-5COOOSWG.mjs.map +0 -1
  88. package/dist/TreeRoot-AABP2J6Y.cjs +0 -19
  89. package/dist/TreeRoot-AABP2J6Y.cjs.map +0 -1
  90. package/dist/chunk-2NG4SXEP.mjs +0 -743
  91. package/dist/chunk-2NG4SXEP.mjs.map +0 -1
  92. package/dist/chunk-4LFB7I5K.cjs +0 -1387
  93. package/dist/chunk-4LFB7I5K.cjs.map +0 -1
  94. package/dist/chunk-5D2OCOPQ.cjs +0 -222
  95. package/dist/chunk-5D2OCOPQ.cjs.map +0 -1
  96. package/dist/chunk-5I5QNGUG.cjs +0 -611
  97. package/dist/chunk-5I5QNGUG.cjs.map +0 -1
  98. package/dist/chunk-6ZX2G25W.mjs +0 -1361
  99. package/dist/chunk-6ZX2G25W.mjs.map +0 -1
  100. package/dist/chunk-76NNDZH6.cjs +0 -1061
  101. package/dist/chunk-76NNDZH6.cjs.map +0 -1
  102. package/dist/chunk-7CWGZPO3.mjs +0 -214
  103. package/dist/chunk-7CWGZPO3.mjs.map +0 -1
  104. package/dist/chunk-7EYHNP3E.cjs +0 -965
  105. package/dist/chunk-7EYHNP3E.cjs.map +0 -1
  106. package/dist/chunk-7IYXZUJO.cjs +0 -769
  107. package/dist/chunk-7IYXZUJO.cjs.map +0 -1
  108. package/dist/chunk-ADEN3UA4.cjs +0 -892
  109. package/dist/chunk-ADEN3UA4.cjs.map +0 -1
  110. package/dist/chunk-B6IR5KSC.mjs +0 -59
  111. package/dist/chunk-B6IR5KSC.mjs.map +0 -1
  112. package/dist/chunk-C6GXVH5J.mjs +0 -338
  113. package/dist/chunk-C6GXVH5J.mjs.map +0 -1
  114. package/dist/chunk-DMX7W4XZ.mjs +0 -1113
  115. package/dist/chunk-DMX7W4XZ.mjs.map +0 -1
  116. package/dist/chunk-ECONRHIG.mjs +0 -212
  117. package/dist/chunk-ECONRHIG.mjs.map +0 -1
  118. package/dist/chunk-FEN5S772.cjs +0 -1227
  119. package/dist/chunk-FEN5S772.cjs.map +0 -1
  120. package/dist/chunk-FP2RLYQZ.cjs +0 -187
  121. package/dist/chunk-FP2RLYQZ.cjs.map +0 -1
  122. package/dist/chunk-FVVF7VCD.cjs +0 -1325
  123. package/dist/chunk-FVVF7VCD.cjs.map +0 -1
  124. package/dist/chunk-GYIO7W7M.mjs +0 -1197
  125. package/dist/chunk-GYIO7W7M.mjs.map +0 -1
  126. package/dist/chunk-KNDLV4PI.cjs +0 -1356
  127. package/dist/chunk-KNDLV4PI.cjs.map +0 -1
  128. package/dist/chunk-KNEQRUBA.mjs +0 -181
  129. package/dist/chunk-KNEQRUBA.mjs.map +0 -1
  130. package/dist/chunk-N2XQF2OL.mjs +0 -14
  131. package/dist/chunk-N4MZYNR4.mjs +0 -1342
  132. package/dist/chunk-N4MZYNR4.mjs.map +0 -1
  133. package/dist/chunk-NTVBIIUD.mjs +0 -1439
  134. package/dist/chunk-NTVBIIUD.mjs.map +0 -1
  135. package/dist/chunk-OBRSGM64.mjs +0 -607
  136. package/dist/chunk-OBRSGM64.mjs.map +0 -1
  137. package/dist/chunk-ODO4GMW7.mjs +0 -79
  138. package/dist/chunk-ODO4GMW7.mjs.map +0 -1
  139. package/dist/chunk-OLISEQHS.cjs +0 -18
  140. package/dist/chunk-PVAX67JG.mjs +0 -1041
  141. package/dist/chunk-PVAX67JG.mjs.map +0 -1
  142. package/dist/chunk-QJ6GTUCO.cjs +0 -81
  143. package/dist/chunk-QJ6GTUCO.cjs.map +0 -1
  144. package/dist/chunk-T3MWM23F.cjs +0 -214
  145. package/dist/chunk-T3MWM23F.cjs.map +0 -1
  146. package/dist/chunk-TBSHZO5R.cjs +0 -1134
  147. package/dist/chunk-TBSHZO5R.cjs.map +0 -1
  148. package/dist/chunk-UNCS5V5F.mjs +0 -887
  149. package/dist/chunk-UNCS5V5F.mjs.map +0 -1
  150. package/dist/chunk-VWQ5WOIL.mjs +0 -2059
  151. package/dist/chunk-VWQ5WOIL.mjs.map +0 -1
  152. package/dist/chunk-W75B7Y6C.cjs +0 -1478
  153. package/dist/chunk-W75B7Y6C.cjs.map +0 -1
  154. package/dist/chunk-Y6UTOBF6.mjs +0 -938
  155. package/dist/chunk-Y6UTOBF6.mjs.map +0 -1
  156. package/dist/chunk-YDPDTOSP.cjs +0 -2061
  157. package/dist/chunk-YDPDTOSP.cjs.map +0 -1
  158. package/dist/chunk-YW5IVWHQ.cjs +0 -346
  159. package/dist/chunk-YW5IVWHQ.cjs.map +0 -1
  160. package/dist/chunk-YXZ6GU7H.cjs +0 -63
  161. package/dist/chunk-YXZ6GU7H.cjs.map +0 -1
  162. package/dist/chunk-ZL7FH4NW.mjs +0 -1274
  163. package/dist/chunk-ZL7FH4NW.mjs.map +0 -1
  164. package/dist/components-EHOGXATG.cjs +0 -22
  165. package/dist/components-EHOGXATG.cjs.map +0 -1
  166. package/dist/components-MQ6DR7TX.cjs +0 -26
  167. package/dist/components-MQ6DR7TX.cjs.map +0 -1
  168. package/dist/components-XRX7QGLB.mjs +0 -5
  169. package/dist/components-XRX7QGLB.mjs.map +0 -1
  170. package/dist/components-YATKRWLH.mjs +0 -5
  171. package/dist/components-YATKRWLH.mjs.map +0 -1
  172. package/dist/index.cjs +0 -3674
  173. package/dist/index.cjs.map +0 -1
  174. package/dist/index.css +0 -234
  175. package/dist/index.css.map +0 -1
  176. package/dist/index.d.cts +0 -4929
  177. package/dist/index.d.ts +0 -4929
  178. package/dist/index.mjs +0 -2912
  179. package/dist/index.mjs.map +0 -1
  180. package/dist/launcher-5Y42OBSN.mjs +0 -6
  181. package/dist/launcher-5Y42OBSN.mjs.map +0 -1
  182. package/dist/launcher-PMW2YB24.cjs +0 -59
  183. package/dist/launcher-PMW2YB24.cjs.map +0 -1
  184. package/src/index.ts +0 -157
@@ -1,892 +0,0 @@
1
- 'use strict';
2
-
3
- var chunkOLISEQHS_cjs = require('./chunk-OLISEQHS.cjs');
4
- var lib = require('@djangocfg/ui-core/lib');
5
- var lucideReact = require('lucide-react');
6
- var jsxRuntime = require('react/jsx-runtime');
7
- var react = require('react');
8
- var consola = require('consola');
9
- var zustand = require('zustand');
10
- var middleware = require('zustand/middleware');
11
- var i18n = require('@djangocfg/i18n');
12
-
13
- var SIZE_CLS = {
14
- sm: "h-8 w-8 [&_svg]:h-4 [&_svg]:w-4",
15
- md: "h-10 w-10 [&_svg]:h-5 [&_svg]:w-5",
16
- lg: "h-12 w-12 [&_svg]:h-6 [&_svg]:w-6"
17
- };
18
- function DictationButton({
19
- status,
20
- onClick,
21
- isSupported = true,
22
- size = "md",
23
- className,
24
- style,
25
- ariaLabel,
26
- idleIcon,
27
- listeningIcon,
28
- disabled
29
- }) {
30
- const listening = status === "listening" || status === "starting";
31
- const stopping = status === "stopping";
32
- const off = !isSupported;
33
- return /* @__PURE__ */ jsxRuntime.jsxs(
34
- "button",
35
- {
36
- type: "button",
37
- onClick,
38
- disabled: disabled || off,
39
- "aria-pressed": listening,
40
- "aria-label": ariaLabel ?? (listening ? "Stop dictation" : off ? "Dictation not supported" : "Start dictation"),
41
- className: lib.cn(
42
- "relative inline-flex items-center justify-center rounded-full transition-colors",
43
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
44
- "disabled:cursor-not-allowed disabled:opacity-50",
45
- SIZE_CLS[size],
46
- listening ? "bg-destructive text-destructive-foreground hover:bg-destructive/90" : "bg-primary text-primary-foreground hover:bg-primary/90",
47
- className
48
- ),
49
- style,
50
- children: [
51
- listening && /* @__PURE__ */ jsxRuntime.jsx(
52
- "span",
53
- {
54
- "aria-hidden": true,
55
- className: "absolute inset-0 rounded-full bg-destructive/40 animate-ping"
56
- }
57
- ),
58
- stopping ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "animate-spin" }) : off ? listeningIcon ?? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MicOff, {}) : listening ? listeningIcon ?? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Mic, {}) : idleIcon ?? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Mic, {})
59
- ]
60
- }
61
- );
62
- }
63
- chunkOLISEQHS_cjs.__name(DictationButton, "DictationButton");
64
- var FRIENDLY = {
65
- unsupported: "Speech recognition isn't available in this browser.",
66
- "permission-denied": "Microphone access was denied. Allow it in your browser settings to dictate.",
67
- "no-microphone": "No microphone found.",
68
- network: "Network error talking to the speech service.",
69
- aborted: "Recognition was interrupted.",
70
- "no-speech": "No speech was detected. Try again.",
71
- language: "The requested language isn't supported by the engine.",
72
- engine: "The speech engine reported an error.",
73
- unknown: "Something went wrong with the microphone."
74
- };
75
- function ErrorBanner({ error, className, onDismiss }) {
76
- if (!error) return null;
77
- return /* @__PURE__ */ jsxRuntime.jsxs(
78
- "div",
79
- {
80
- role: "alert",
81
- className: lib.cn(
82
- "flex items-start gap-2 rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive",
83
- className
84
- ),
85
- children: [
86
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "mt-0.5 h-3.5 w-3.5 shrink-0" }),
87
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1", children: FRIENDLY[error.code] ?? error.message }),
88
- onDismiss && /* @__PURE__ */ jsxRuntime.jsx(
89
- "button",
90
- {
91
- type: "button",
92
- onClick: onDismiss,
93
- className: "text-destructive hover:underline",
94
- children: "Dismiss"
95
- }
96
- )
97
- ]
98
- }
99
- );
100
- }
101
- chunkOLISEQHS_cjs.__name(ErrorBanner, "ErrorBanner");
102
- function MicMeter({
103
- level,
104
- bars = 12,
105
- gap = 2,
106
- barWidth = 3,
107
- height = 24,
108
- className
109
- }) {
110
- const clamped = Math.min(1, Math.max(0, level));
111
- return /* @__PURE__ */ jsxRuntime.jsx(
112
- "div",
113
- {
114
- role: "meter",
115
- "aria-valuemin": 0,
116
- "aria-valuemax": 1,
117
- "aria-valuenow": clamped,
118
- className: lib.cn("inline-flex items-center", className),
119
- style: { gap, height },
120
- children: Array.from({ length: bars }).map((_, i) => {
121
- const ratio = (i + 1) / bars;
122
- const active = clamped >= ratio - 0.5 / bars;
123
- const heightRatio = 1 - Math.abs(i - (bars - 1) / 2) / ((bars - 1) / 2 || 1);
124
- const barH = Math.max(2, height * (0.35 + heightRatio * 0.65));
125
- return /* @__PURE__ */ jsxRuntime.jsx(
126
- "span",
127
- {
128
- className: lib.cn(
129
- "rounded-sm transition-colors",
130
- active ? "bg-primary" : "bg-border"
131
- ),
132
- style: { width: barWidth, height: barH }
133
- },
134
- i
135
- );
136
- })
137
- }
138
- );
139
- }
140
- chunkOLISEQHS_cjs.__name(MicMeter, "MicMeter");
141
- function PushToTalkHint({ chord, className }) {
142
- const formatted = chord.split("+").map((p) => p.trim().toLowerCase()).map((p) => {
143
- switch (p) {
144
- case "mod":
145
- case "meta":
146
- return "\u2318";
147
- case "alt":
148
- return "\u2325";
149
- case "shift":
150
- return "\u21E7";
151
- case "ctrl":
152
- return "\u2303";
153
- default:
154
- return p.length === 1 ? p.toUpperCase() : p;
155
- }
156
- }).join("");
157
- return /* @__PURE__ */ jsxRuntime.jsxs(
158
- "span",
159
- {
160
- className: lib.cn(
161
- "inline-flex items-center gap-1 text-[11px] text-muted-foreground",
162
- className
163
- ),
164
- children: [
165
- "Hold",
166
- /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "rounded border border-border bg-muted px-1 py-0.5 font-mono text-[10px] text-foreground", children: formatted }),
167
- "to talk"
168
- ]
169
- }
170
- );
171
- }
172
- chunkOLISEQHS_cjs.__name(PushToTalkHint, "PushToTalkHint");
173
-
174
- // src/tools/SpeechRecognition/core/transcript.ts
175
- var EMPTY_TRANSCRIPT = {
176
- interim: "",
177
- final: "",
178
- segments: []
179
- };
180
- function joinFinal(segments) {
181
- let out = "";
182
- for (const seg of segments) {
183
- if (!seg.isFinal) continue;
184
- const text = seg.text.trim();
185
- if (!text) continue;
186
- out = out ? `${out} ${text}` : text;
187
- }
188
- return out;
189
- }
190
- chunkOLISEQHS_cjs.__name(joinFinal, "joinFinal");
191
- function buildTranscript(segments) {
192
- const last = segments[segments.length - 1];
193
- const interim = last && !last.isFinal ? last.text : "";
194
- return {
195
- interim,
196
- final: joinFinal(segments),
197
- segments
198
- };
199
- }
200
- chunkOLISEQHS_cjs.__name(buildTranscript, "buildTranscript");
201
- function normaliseFinal(text) {
202
- return text.replace(/\s+/g, " ").replace(/\s+([,.!?])/g, "$1").trim();
203
- }
204
- chunkOLISEQHS_cjs.__name(normaliseFinal, "normaliseFinal");
205
-
206
- // src/tools/SpeechRecognition/core/ids.ts
207
- var counter = 0;
208
- function newSegmentId() {
209
- counter = (counter + 1) % Number.MAX_SAFE_INTEGER;
210
- return `seg_${Date.now().toString(36)}_${counter.toString(36)}`;
211
- }
212
- chunkOLISEQHS_cjs.__name(newSegmentId, "newSegmentId");
213
- var SCOPES = [
214
- "engine",
215
- "dictation",
216
- "slot",
217
- "composer",
218
- "mic",
219
- "push",
220
- "error"
221
- ];
222
- var STORAGE_KEY = "djangocfg:speech-debug";
223
- function readStorageFlag() {
224
- if (!lib.isBrowser) return false;
225
- try {
226
- return window.localStorage.getItem(STORAGE_KEY) === "1";
227
- } catch {
228
- return false;
229
- }
230
- }
231
- chunkOLISEQHS_cjs.__name(readStorageFlag, "readStorageFlag");
232
- var cache = /* @__PURE__ */ new Map();
233
- function buildLogger(enabled) {
234
- const root = consola.consola.withTag("speech");
235
- const subs = Object.fromEntries(
236
- SCOPES.map((scope) => [scope, root.withTag(scope)])
237
- );
238
- if (!enabled) {
239
- for (const scope of SCOPES) {
240
- if (scope === "error") continue;
241
- subs[scope].level = -999;
242
- }
243
- }
244
- return { ...subs, enabled };
245
- }
246
- chunkOLISEQHS_cjs.__name(buildLogger, "buildLogger");
247
- function getSpeechLogger(debug) {
248
- const enabled = debug ?? (lib.isDev || readStorageFlag());
249
- let logger = cache.get(enabled);
250
- if (!logger) {
251
- logger = buildLogger(enabled);
252
- cache.set(enabled, logger);
253
- }
254
- return logger;
255
- }
256
- chunkOLISEQHS_cjs.__name(getSpeechLogger, "getSpeechLogger");
257
- var sttLogger = consola.consola.withTag("ui-tools:speech");
258
-
259
- // src/tools/SpeechRecognition/core/reducer.ts
260
- var INITIAL_STATE = {
261
- status: "idle",
262
- segments: [],
263
- error: null,
264
- startedAt: null
265
- };
266
- function nowSinceStart(state) {
267
- return state.startedAt ? Date.now() - state.startedAt : 0;
268
- }
269
- chunkOLISEQHS_cjs.__name(nowSinceStart, "nowSinceStart");
270
- function upsertSegment(segments, patch) {
271
- const idx = segments.findIndex((s) => s.id === patch.id);
272
- if (idx === -1) return [...segments, patch];
273
- const next = segments.slice();
274
- next[idx] = { ...next[idx], ...patch };
275
- return next;
276
- }
277
- chunkOLISEQHS_cjs.__name(upsertSegment, "upsertSegment");
278
- function reducer(state, action) {
279
- switch (action.type) {
280
- case "START":
281
- return {
282
- ...state,
283
- status: "starting",
284
- error: null,
285
- startedAt: Date.now()
286
- };
287
- case "STARTED":
288
- return { ...state, status: "listening" };
289
- case "STOP":
290
- return { ...state, status: "stopping" };
291
- case "STOPPED":
292
- case "ABORT":
293
- return { ...state, status: "idle" };
294
- case "PARTIAL": {
295
- const seg = {
296
- id: action.segmentId,
297
- text: action.text,
298
- isFinal: false,
299
- confidence: action.confidence,
300
- startedAt: nowSinceStart(state)
301
- };
302
- return { ...state, segments: upsertSegment(state.segments, seg) };
303
- }
304
- case "FINAL": {
305
- const seg = {
306
- id: action.segmentId || newSegmentId(),
307
- text: action.text,
308
- isFinal: true,
309
- confidence: action.confidence,
310
- startedAt: nowSinceStart(state),
311
- endedAt: nowSinceStart(state)
312
- };
313
- return { ...state, segments: upsertSegment(state.segments, seg) };
314
- }
315
- case "ERROR":
316
- return { ...state, status: "error", error: action.error };
317
- case "RESET":
318
- return { ...INITIAL_STATE };
319
- default:
320
- return state;
321
- }
322
- }
323
- chunkOLISEQHS_cjs.__name(reducer, "reducer");
324
-
325
- // src/tools/SpeechRecognition/core/engine/index.ts
326
- function createEngineBus() {
327
- const listeners = {
328
- partial: /* @__PURE__ */ new Set(),
329
- final: /* @__PURE__ */ new Set(),
330
- error: /* @__PURE__ */ new Set(),
331
- state: /* @__PURE__ */ new Set()
332
- };
333
- return {
334
- on(event, cb) {
335
- const set = listeners[event];
336
- set.add(cb);
337
- return () => {
338
- set.delete(cb);
339
- };
340
- },
341
- emit(event, ...args) {
342
- const set = listeners[event];
343
- for (const cb of set) {
344
- try {
345
- cb(...args);
346
- } catch {
347
- }
348
- }
349
- },
350
- clear() {
351
- for (const key of Object.keys(listeners)) {
352
- listeners[key].clear();
353
- }
354
- }
355
- };
356
- }
357
- chunkOLISEQHS_cjs.__name(createEngineBus, "createEngineBus");
358
-
359
- // src/tools/SpeechRecognition/core/engine/webspeech.ts
360
- function resolveCtor() {
361
- if (typeof window === "undefined") return null;
362
- const w = window;
363
- return w.SpeechRecognition ?? w.webkitSpeechRecognition ?? null;
364
- }
365
- chunkOLISEQHS_cjs.__name(resolveCtor, "resolveCtor");
366
- var ERROR_MAP = {
367
- "no-speech": "no-speech",
368
- aborted: "aborted",
369
- "audio-capture": "no-microphone",
370
- network: "network",
371
- "not-allowed": "permission-denied",
372
- "service-not-allowed": "permission-denied",
373
- "bad-grammar": "engine",
374
- "language-not-supported": "language"
375
- };
376
- function createWebSpeechEngine(opts = {}) {
377
- const Ctor = resolveCtor();
378
- const bus = createEngineBus();
379
- let instance = null;
380
- let currentSegmentId = null;
381
- function teardown() {
382
- if (!instance) return;
383
- instance.onresult = null;
384
- instance.onerror = null;
385
- instance.onstart = null;
386
- instance.onend = null;
387
- instance = null;
388
- currentSegmentId = null;
389
- }
390
- chunkOLISEQHS_cjs.__name(teardown, "teardown");
391
- return {
392
- id: "webspeech",
393
- isSupported: Ctor !== null,
394
- on(event, cb) {
395
- return bus.on(event, cb);
396
- },
397
- async start(start) {
398
- if (!Ctor) {
399
- const err = {
400
- code: "unsupported",
401
- message: "Web Speech API is not available in this browser."
402
- };
403
- bus.emit("error", err);
404
- throw err;
405
- }
406
- if (instance) {
407
- sttLogger.debug("[webspeech] start() called while running \u2014 ignoring");
408
- return;
409
- }
410
- bus.emit("state", "connecting");
411
- const rec = new Ctor();
412
- rec.lang = start.language;
413
- rec.interimResults = start.interim;
414
- rec.continuous = opts.continuous ?? true;
415
- rec.maxAlternatives = opts.maxAlternatives ?? 1;
416
- rec.onstart = () => {
417
- bus.emit("state", "listening");
418
- };
419
- rec.onend = () => {
420
- bus.emit("state", "closed");
421
- teardown();
422
- };
423
- rec.onerror = (e) => {
424
- const code = ERROR_MAP[e.error] ?? "engine";
425
- const err = {
426
- code,
427
- message: e.message || `Web Speech error: ${e.error}`
428
- };
429
- bus.emit("error", err);
430
- };
431
- rec.onresult = (e) => {
432
- for (let i = e.resultIndex; i < e.results.length; i += 1) {
433
- const res = e.results[i];
434
- const alt = res[0];
435
- const text = alt.transcript;
436
- if (!currentSegmentId) currentSegmentId = newSegmentId();
437
- if (res.isFinal) {
438
- bus.emit("final", text, currentSegmentId, alt.confidence);
439
- currentSegmentId = null;
440
- } else {
441
- bus.emit("partial", text, currentSegmentId);
442
- }
443
- }
444
- };
445
- if (start.signal) {
446
- start.signal.addEventListener("abort", () => {
447
- rec.abort();
448
- });
449
- }
450
- instance = rec;
451
- try {
452
- rec.start();
453
- } catch (cause) {
454
- const err = {
455
- code: "engine",
456
- message: "Failed to start Web Speech recognition.",
457
- cause
458
- };
459
- bus.emit("error", err);
460
- teardown();
461
- throw err;
462
- }
463
- },
464
- async stop() {
465
- if (!instance) return;
466
- bus.emit("state", "closing");
467
- instance.stop();
468
- },
469
- abort() {
470
- if (!instance) return;
471
- instance.abort();
472
- }
473
- };
474
- }
475
- chunkOLISEQHS_cjs.__name(createWebSpeechEngine, "createWebSpeechEngine");
476
- var DEFAULTS = {
477
- language: null,
478
- deviceId: null,
479
- engineId: null,
480
- earcons: false
481
- };
482
- var useSpeechPrefs = zustand.create()(
483
- middleware.persist(
484
- (set) => ({
485
- ...DEFAULTS,
486
- setLanguage: /* @__PURE__ */ chunkOLISEQHS_cjs.__name((language) => set({ language }), "setLanguage"),
487
- setDeviceId: /* @__PURE__ */ chunkOLISEQHS_cjs.__name((deviceId) => set({ deviceId }), "setDeviceId"),
488
- setEngineId: /* @__PURE__ */ chunkOLISEQHS_cjs.__name((engineId) => set({ engineId }), "setEngineId"),
489
- setEarcons: /* @__PURE__ */ chunkOLISEQHS_cjs.__name((earcons) => set({ earcons }), "setEarcons"),
490
- reset: /* @__PURE__ */ chunkOLISEQHS_cjs.__name(() => set({ ...DEFAULTS }), "reset")
491
- }),
492
- {
493
- name: "djangocfg-stt:prefs",
494
- storage: middleware.createJSONStorage(
495
- () => typeof window === "undefined" ? void 0 : window.localStorage
496
- )
497
- }
498
- )
499
- );
500
- function useMicLevel(stream) {
501
- const [level, setLevel] = react.useState(0);
502
- const raf = react.useRef(null);
503
- react.useEffect(() => {
504
- if (!stream) {
505
- setLevel(0);
506
- return void 0;
507
- }
508
- const AC = window.AudioContext ?? window.webkitAudioContext;
509
- if (!AC) return void 0;
510
- const ctx = new AC();
511
- const source = ctx.createMediaStreamSource(stream);
512
- const analyser = ctx.createAnalyser();
513
- analyser.fftSize = 1024;
514
- analyser.smoothingTimeConstant = 0.7;
515
- source.connect(analyser);
516
- const buf = new Float32Array(analyser.fftSize);
517
- const tick = /* @__PURE__ */ chunkOLISEQHS_cjs.__name(() => {
518
- analyser.getFloatTimeDomainData(buf);
519
- let sum = 0;
520
- for (let i = 0; i < buf.length; i += 1) sum += buf[i] * buf[i];
521
- const rms = Math.sqrt(sum / buf.length);
522
- setLevel(Math.min(1, rms * 2.5));
523
- raf.current = requestAnimationFrame(tick);
524
- }, "tick");
525
- tick();
526
- return () => {
527
- if (raf.current != null) cancelAnimationFrame(raf.current);
528
- raf.current = null;
529
- source.disconnect();
530
- analyser.disconnect();
531
- void ctx.close();
532
- };
533
- }, [stream]);
534
- return level;
535
- }
536
- chunkOLISEQHS_cjs.__name(useMicLevel, "useMicLevel");
537
-
538
- // src/tools/SpeechRecognition/core/language.ts
539
- var ISO_TO_BCP47 = {
540
- en: "en-US",
541
- ru: "ru-RU",
542
- ko: "ko-KR",
543
- ja: "ja-JP",
544
- zh: "zh-CN",
545
- de: "de-DE",
546
- fr: "fr-FR",
547
- it: "it-IT",
548
- es: "es-ES",
549
- nl: "nl-NL",
550
- ar: "ar-SA",
551
- tr: "tr-TR",
552
- pl: "pl-PL",
553
- sv: "sv-SE",
554
- no: "nb-NO",
555
- da: "da-DK",
556
- pt: "pt-BR"
557
- };
558
- function toBCP47(code, table = ISO_TO_BCP47) {
559
- if (!code) return void 0;
560
- const trimmed = code.trim();
561
- if (!trimmed) return void 0;
562
- if (trimmed.includes("-")) return trimmed;
563
- const lower = trimmed.toLowerCase();
564
- return table[lower] ?? `${lower}-${lower.toUpperCase()}`;
565
- }
566
- chunkOLISEQHS_cjs.__name(toBCP47, "toBCP47");
567
- function resolveSpeechLanguage(opts) {
568
- return toBCP47(opts.explicit) ?? toBCP47(opts.prefs) ?? toBCP47(opts.i18n) ?? toBCP47(typeof navigator !== "undefined" ? navigator.language : null) ?? "en-US";
569
- }
570
- chunkOLISEQHS_cjs.__name(resolveSpeechLanguage, "resolveSpeechLanguage");
571
-
572
- // src/tools/SpeechRecognition/hooks/useResolvedLanguage.ts
573
- function useResolvedLanguage(explicit) {
574
- const prefs = useSpeechPrefs();
575
- const locale = i18n.useLocaleOptional();
576
- return resolveSpeechLanguage({
577
- explicit,
578
- prefs: prefs.language,
579
- i18n: locale
580
- });
581
- }
582
- chunkOLISEQHS_cjs.__name(useResolvedLanguage, "useResolvedLanguage");
583
-
584
- // src/tools/SpeechRecognition/hooks/useSpeechRecognition.ts
585
- var log = getSpeechLogger();
586
- function useSpeechRecognition(config = {}) {
587
- const prefs = useSpeechPrefs();
588
- const language = useResolvedLanguage(config.language);
589
- const engine = react.useMemo(
590
- () => config.engine ?? createWebSpeechEngine(),
591
- [config.engine]
592
- );
593
- const [state, dispatch] = react.useReducer(reducer, INITIAL_STATE);
594
- const [stream, setStream] = react.useState(null);
595
- const level = useMicLevel(stream);
596
- const cbRef = react.useRef(config);
597
- cbRef.current = config;
598
- react.useEffect(() => {
599
- log.engine.debug("subscribe", { engineId: engine.id });
600
- const offs = [
601
- engine.on("partial", (text, segmentId) => {
602
- log.engine.debug("partial", { len: text.length, segmentId });
603
- dispatch({ type: "PARTIAL", text, segmentId });
604
- const seg = {
605
- id: segmentId,
606
- text,
607
- isFinal: false,
608
- startedAt: Date.now()
609
- };
610
- cbRef.current.onPartial?.(text, seg);
611
- }),
612
- engine.on("final", (text, segmentId, confidence) => {
613
- log.engine.info("final", {
614
- len: text.length,
615
- segmentId,
616
- confidence
617
- });
618
- dispatch({ type: "FINAL", text, segmentId, confidence });
619
- const seg = {
620
- id: segmentId,
621
- text,
622
- isFinal: true,
623
- confidence,
624
- startedAt: Date.now(),
625
- endedAt: Date.now()
626
- };
627
- cbRef.current.onFinal?.(text, seg);
628
- }),
629
- engine.on("error", (err) => {
630
- log.error.error("engine error", err);
631
- dispatch({ type: "ERROR", error: err });
632
- cbRef.current.onError?.(err);
633
- }),
634
- engine.on("state", (s) => {
635
- log.engine.debug("state", s);
636
- if (s === "listening") {
637
- dispatch({ type: "STARTED" });
638
- cbRef.current.onStart?.();
639
- setStream(engine.getStream?.() ?? null);
640
- } else if (s === "closed") {
641
- dispatch({ type: "STOPPED" });
642
- cbRef.current.onStop?.();
643
- setStream(null);
644
- }
645
- })
646
- ];
647
- return () => {
648
- offs.forEach((off) => off());
649
- };
650
- }, [engine]);
651
- const silenceTimer = react.useRef(null);
652
- const maxTimer = react.useRef(null);
653
- react.useEffect(() => {
654
- if (state.status !== "listening") return void 0;
655
- const { silenceMs, maxMs, silenceThreshold = 0.02 } = config.autoStop ?? {};
656
- if (maxMs) {
657
- maxTimer.current = window.setTimeout(() => {
658
- log.engine.debug("autoStop max duration hit");
659
- void engine.stop();
660
- }, maxMs);
661
- }
662
- if (silenceMs) {
663
- const checkInterval = window.setInterval(() => {
664
- if (level < silenceThreshold) {
665
- if (silenceTimer.current == null) {
666
- silenceTimer.current = window.setTimeout(() => {
667
- log.engine.debug("autoStop silence detected");
668
- void engine.stop();
669
- }, silenceMs);
670
- }
671
- } else if (silenceTimer.current != null) {
672
- clearTimeout(silenceTimer.current);
673
- silenceTimer.current = null;
674
- }
675
- }, 200);
676
- return () => {
677
- clearInterval(checkInterval);
678
- if (silenceTimer.current != null) clearTimeout(silenceTimer.current);
679
- silenceTimer.current = null;
680
- if (maxTimer.current != null) clearTimeout(maxTimer.current);
681
- maxTimer.current = null;
682
- };
683
- }
684
- return () => {
685
- if (maxTimer.current != null) clearTimeout(maxTimer.current);
686
- maxTimer.current = null;
687
- };
688
- }, [state.status, config.autoStop, level, engine]);
689
- const start = react.useCallback(async () => {
690
- if (state.status === "listening" || state.status === "starting") return;
691
- dispatch({ type: "START" });
692
- try {
693
- await engine.start({
694
- language,
695
- interim: config.interim ?? true,
696
- deviceId: config.deviceId ?? prefs.deviceId ?? void 0
697
- });
698
- } catch (cause) {
699
- log.engine.warn("start threw", cause);
700
- }
701
- }, [engine, language, config.interim, config.deviceId, prefs.deviceId, state.status]);
702
- const stop = react.useCallback(async () => {
703
- if (state.status === "idle" || state.status === "stopping") return;
704
- dispatch({ type: "STOP" });
705
- await engine.stop();
706
- }, [engine, state.status]);
707
- const abort = react.useCallback(() => {
708
- engine.abort();
709
- dispatch({ type: "ABORT" });
710
- }, [engine]);
711
- const toggle = react.useCallback(async () => {
712
- if (state.status === "listening" || state.status === "starting") {
713
- await stop();
714
- } else {
715
- await start();
716
- }
717
- }, [state.status, start, stop]);
718
- const reset = react.useCallback(() => {
719
- dispatch({ type: "RESET" });
720
- }, []);
721
- const transcript = react.useMemo(
722
- () => state.segments.length === 0 ? EMPTY_TRANSCRIPT : buildTranscript(state.segments),
723
- [state.segments]
724
- );
725
- return {
726
- status: state.status,
727
- isSupported: engine.isSupported,
728
- transcript,
729
- error: state.error,
730
- level,
731
- start,
732
- stop,
733
- abort,
734
- toggle,
735
- reset
736
- };
737
- }
738
- chunkOLISEQHS_cjs.__name(useSpeechRecognition, "useSpeechRecognition");
739
-
740
- // src/tools/SpeechRecognition/hooks/useDictation.ts
741
- function useDictation(config) {
742
- const { value, onChange, separator = " ", ...rest } = config;
743
- const valueRef = react.useRef(value);
744
- valueRef.current = value;
745
- const onChangeRef = react.useRef(onChange);
746
- onChangeRef.current = onChange;
747
- const rec = useSpeechRecognition({
748
- ...rest,
749
- onFinal: /* @__PURE__ */ chunkOLISEQHS_cjs.__name((text) => {
750
- const clean = normaliseFinal(text);
751
- if (!clean) return;
752
- const prev = valueRef.current;
753
- const next = prev ? `${prev}${separator}${clean}` : clean;
754
- onChangeRef.current(next);
755
- }, "onFinal")
756
- });
757
- react.useEffect(() => {
758
- valueRef.current = value;
759
- }, [value]);
760
- return {
761
- ...rec,
762
- toggleDictation: rec.toggle
763
- };
764
- }
765
- chunkOLISEQHS_cjs.__name(useDictation, "useDictation");
766
- var MOD_KEYS = /* @__PURE__ */ new Set(["shift", "ctrl", "alt", "meta", "mod"]);
767
- function parseChord(chord) {
768
- const parts = chord.toLowerCase().split("+").map((s) => s.trim());
769
- const mods = /* @__PURE__ */ new Set();
770
- let main = null;
771
- for (const part of parts) {
772
- if (MOD_KEYS.has(part)) {
773
- mods.add(part === "mod" ? "meta" : part);
774
- } else {
775
- main = part;
776
- }
777
- }
778
- return { mods, main };
779
- }
780
- chunkOLISEQHS_cjs.__name(parseChord, "parseChord");
781
- function matches(e, mods, main) {
782
- if (mods.has("shift") !== e.shiftKey) return false;
783
- if (mods.has("ctrl") !== e.ctrlKey) return false;
784
- if (mods.has("alt") !== e.altKey) return false;
785
- if (mods.has("meta") !== (e.metaKey || !e.metaKey && false)) return false;
786
- if (main && e.key.toLowerCase() !== main) return false;
787
- return true;
788
- }
789
- chunkOLISEQHS_cjs.__name(matches, "matches");
790
- function usePushToTalk(recognition, opts) {
791
- const { key, enabled = true } = opts;
792
- react.useEffect(() => {
793
- if (!enabled || typeof window === "undefined") return void 0;
794
- const { mods, main } = parseChord(key);
795
- const onDown = /* @__PURE__ */ chunkOLISEQHS_cjs.__name((e) => {
796
- if (e.repeat) return;
797
- if (!main && mods.size === 0) return;
798
- const target = e.target;
799
- const inField = target?.tagName === "INPUT" || target?.tagName === "TEXTAREA" || target?.isContentEditable;
800
- if (inField && mods.size === 0) return;
801
- if (!matches(e, mods, main)) return;
802
- if (recognition.status === "listening" || recognition.status === "starting") return;
803
- e.preventDefault();
804
- void recognition.start();
805
- }, "onDown");
806
- const onUp = /* @__PURE__ */ chunkOLISEQHS_cjs.__name((e) => {
807
- if (!matches(e, mods, main) && main && e.key.toLowerCase() !== main) return;
808
- if (recognition.status !== "listening" && recognition.status !== "starting") return;
809
- void recognition.stop();
810
- }, "onUp");
811
- window.addEventListener("keydown", onDown);
812
- window.addEventListener("keyup", onUp);
813
- return () => {
814
- window.removeEventListener("keydown", onDown);
815
- window.removeEventListener("keyup", onUp);
816
- };
817
- }, [enabled, key, recognition]);
818
- }
819
- chunkOLISEQHS_cjs.__name(usePushToTalk, "usePushToTalk");
820
- function DictationField({
821
- value,
822
- onChange,
823
- engine,
824
- language,
825
- pushToTalk,
826
- placeholder = "Type or press the mic to dictate\u2026",
827
- rows = 3,
828
- disabled,
829
- showInterim = true,
830
- showMeter = true,
831
- className,
832
- textareaClassName
833
- }) {
834
- const rec = useDictation({
835
- value,
836
- onChange,
837
- engine,
838
- language
839
- });
840
- usePushToTalk(rec, {
841
- key: pushToTalk?.key ?? "alt",
842
- enabled: !!pushToTalk && pushToTalk.enabled !== false
843
- });
844
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: lib.cn("flex flex-col gap-2", className), children: [
845
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
846
- /* @__PURE__ */ jsxRuntime.jsx(
847
- "textarea",
848
- {
849
- value,
850
- onChange: (e) => onChange(e.target.value),
851
- placeholder,
852
- rows,
853
- disabled,
854
- className: lib.cn(
855
- "w-full resize-y rounded-md border border-input bg-background px-3 py-2 text-sm",
856
- "placeholder:text-muted-foreground",
857
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
858
- "disabled:cursor-not-allowed disabled:opacity-50",
859
- textareaClassName
860
- )
861
- }
862
- ),
863
- showInterim && rec.transcript.interim && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pointer-events-none mt-1 text-xs italic text-muted-foreground", children: [
864
- "\u2026 ",
865
- rec.transcript.interim
866
- ] })
867
- ] }),
868
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
869
- /* @__PURE__ */ jsxRuntime.jsx(
870
- DictationButton,
871
- {
872
- status: rec.status,
873
- isSupported: rec.isSupported,
874
- onClick: () => void rec.toggleDictation(),
875
- size: "sm",
876
- disabled
877
- }
878
- ),
879
- showMeter && /* @__PURE__ */ jsxRuntime.jsx(MicMeter, { level: rec.level, bars: 10, height: 20 }),
880
- pushToTalk && /* @__PURE__ */ jsxRuntime.jsx(PushToTalkHint, { chord: pushToTalk.key, className: "ml-auto" })
881
- ] }),
882
- /* @__PURE__ */ jsxRuntime.jsx(ErrorBanner, { error: rec.error })
883
- ] });
884
- }
885
- chunkOLISEQHS_cjs.__name(DictationField, "DictationField");
886
-
887
- exports.DictationField = DictationField;
888
- exports.getSpeechLogger = getSpeechLogger;
889
- exports.useResolvedLanguage = useResolvedLanguage;
890
- exports.useSpeechPrefs = useSpeechPrefs;
891
- //# sourceMappingURL=chunk-ADEN3UA4.cjs.map
892
- //# sourceMappingURL=chunk-ADEN3UA4.cjs.map