@djangocfg/ui-tools 2.1.389 → 2.1.393

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 (183) 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 +9 -17
  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/SpeechRecognition/README.md +1 -1
  29. package/dist/ChatRoot-EFNXQXXN.cjs +0 -15
  30. package/dist/ChatRoot-EFNXQXXN.cjs.map +0 -1
  31. package/dist/ChatRoot-FITF5RVP.mjs +0 -6
  32. package/dist/ChatRoot-FITF5RVP.mjs.map +0 -1
  33. package/dist/ChatRoot-PNNGQCYF.css +0 -7
  34. package/dist/ChatRoot-PNNGQCYF.css.map +0 -1
  35. package/dist/CronScheduler.client-DLMXCPAJ.mjs +0 -67
  36. package/dist/CronScheduler.client-DLMXCPAJ.mjs.map +0 -1
  37. package/dist/CronScheduler.client-WEJF4PWQ.cjs +0 -72
  38. package/dist/CronScheduler.client-WEJF4PWQ.cjs.map +0 -1
  39. package/dist/DictationField-AS2F33WI.cjs +0 -13
  40. package/dist/DictationField-AS2F33WI.cjs.map +0 -1
  41. package/dist/DictationField-WPONUCYE.mjs +0 -4
  42. package/dist/DictationField-WPONUCYE.mjs.map +0 -1
  43. package/dist/DocsLayout-EKASBSP7.mjs +0 -3448
  44. package/dist/DocsLayout-EKASBSP7.mjs.map +0 -1
  45. package/dist/DocsLayout-MBFIB4NO.css +0 -7
  46. package/dist/DocsLayout-MBFIB4NO.css.map +0 -1
  47. package/dist/DocsLayout-OURFYWQE.cjs +0 -3455
  48. package/dist/DocsLayout-OURFYWQE.cjs.map +0 -1
  49. package/dist/JsonSchemaForm-DD7CLRIG.cjs +0 -13
  50. package/dist/JsonSchemaForm-DD7CLRIG.cjs.map +0 -1
  51. package/dist/JsonSchemaForm-XKUIVELK.mjs +0 -4
  52. package/dist/JsonSchemaForm-XKUIVELK.mjs.map +0 -1
  53. package/dist/JsonTree-43PQAJKY.mjs +0 -5
  54. package/dist/JsonTree-43PQAJKY.mjs.map +0 -1
  55. package/dist/JsonTree-MLET23ZA.css +0 -7
  56. package/dist/JsonTree-MLET23ZA.css.map +0 -1
  57. package/dist/JsonTree-X6W5YEVY.cjs +0 -11
  58. package/dist/JsonTree-X6W5YEVY.cjs.map +0 -1
  59. package/dist/LottiePlayer.client-2S7ISJ2S.cjs +0 -168
  60. package/dist/LottiePlayer.client-2S7ISJ2S.cjs.map +0 -1
  61. package/dist/LottiePlayer.client-5LDSSJWS.mjs +0 -161
  62. package/dist/LottiePlayer.client-5LDSSJWS.mjs.map +0 -1
  63. package/dist/MapContainer-AKIPABJK.mjs +0 -4
  64. package/dist/MapContainer-AKIPABJK.mjs.map +0 -1
  65. package/dist/MapContainer-STVDMC36.cjs +0 -17
  66. package/dist/MapContainer-STVDMC36.cjs.map +0 -1
  67. package/dist/Mermaid.client-DDXWXZXY.css +0 -7
  68. package/dist/Mermaid.client-DDXWXZXY.css.map +0 -1
  69. package/dist/Mermaid.client-NL4SVR7F.mjs +0 -481
  70. package/dist/Mermaid.client-NL4SVR7F.mjs.map +0 -1
  71. package/dist/Mermaid.client-NNTI6DFX.cjs +0 -487
  72. package/dist/Mermaid.client-NNTI6DFX.cjs.map +0 -1
  73. package/dist/Player-BRV7XTWR.mjs +0 -4
  74. package/dist/Player-BRV7XTWR.mjs.map +0 -1
  75. package/dist/Player-PM7F7DD7.cjs +0 -13
  76. package/dist/Player-PM7F7DD7.cjs.map +0 -1
  77. package/dist/Player-ZGQKKOWI.css +0 -66
  78. package/dist/Player-ZGQKKOWI.css.map +0 -1
  79. package/dist/PrettyCode.client-GWFAIVFN.css +0 -7
  80. package/dist/PrettyCode.client-GWFAIVFN.css.map +0 -1
  81. package/dist/PrettyCode.client-KOHDVPPN.cjs +0 -285
  82. package/dist/PrettyCode.client-KOHDVPPN.cjs.map +0 -1
  83. package/dist/PrettyCode.client-ZGYGKE7G.mjs +0 -283
  84. package/dist/PrettyCode.client-ZGYGKE7G.mjs.map +0 -1
  85. package/dist/TreeRoot-5COOOSWG.mjs +0 -4
  86. package/dist/TreeRoot-5COOOSWG.mjs.map +0 -1
  87. package/dist/TreeRoot-AABP2J6Y.cjs +0 -19
  88. package/dist/TreeRoot-AABP2J6Y.cjs.map +0 -1
  89. package/dist/chunk-2NG4SXEP.mjs +0 -743
  90. package/dist/chunk-2NG4SXEP.mjs.map +0 -1
  91. package/dist/chunk-4LFB7I5K.cjs +0 -1387
  92. package/dist/chunk-4LFB7I5K.cjs.map +0 -1
  93. package/dist/chunk-5D2OCOPQ.cjs +0 -222
  94. package/dist/chunk-5D2OCOPQ.cjs.map +0 -1
  95. package/dist/chunk-5I5QNGUG.cjs +0 -611
  96. package/dist/chunk-5I5QNGUG.cjs.map +0 -1
  97. package/dist/chunk-6ZX2G25W.mjs +0 -1361
  98. package/dist/chunk-6ZX2G25W.mjs.map +0 -1
  99. package/dist/chunk-76NNDZH6.cjs +0 -1061
  100. package/dist/chunk-76NNDZH6.cjs.map +0 -1
  101. package/dist/chunk-7CWGZPO3.mjs +0 -214
  102. package/dist/chunk-7CWGZPO3.mjs.map +0 -1
  103. package/dist/chunk-7EYHNP3E.cjs +0 -965
  104. package/dist/chunk-7EYHNP3E.cjs.map +0 -1
  105. package/dist/chunk-7IYXZUJO.cjs +0 -769
  106. package/dist/chunk-7IYXZUJO.cjs.map +0 -1
  107. package/dist/chunk-ADEN3UA4.cjs +0 -892
  108. package/dist/chunk-ADEN3UA4.cjs.map +0 -1
  109. package/dist/chunk-B6IR5KSC.mjs +0 -59
  110. package/dist/chunk-B6IR5KSC.mjs.map +0 -1
  111. package/dist/chunk-C6GXVH5J.mjs +0 -338
  112. package/dist/chunk-C6GXVH5J.mjs.map +0 -1
  113. package/dist/chunk-DMX7W4XZ.mjs +0 -1113
  114. package/dist/chunk-DMX7W4XZ.mjs.map +0 -1
  115. package/dist/chunk-ECONRHIG.mjs +0 -212
  116. package/dist/chunk-ECONRHIG.mjs.map +0 -1
  117. package/dist/chunk-FEN5S772.cjs +0 -1227
  118. package/dist/chunk-FEN5S772.cjs.map +0 -1
  119. package/dist/chunk-FP2RLYQZ.cjs +0 -187
  120. package/dist/chunk-FP2RLYQZ.cjs.map +0 -1
  121. package/dist/chunk-FVVF7VCD.cjs +0 -1325
  122. package/dist/chunk-FVVF7VCD.cjs.map +0 -1
  123. package/dist/chunk-GYIO7W7M.mjs +0 -1197
  124. package/dist/chunk-GYIO7W7M.mjs.map +0 -1
  125. package/dist/chunk-KNDLV4PI.cjs +0 -1356
  126. package/dist/chunk-KNDLV4PI.cjs.map +0 -1
  127. package/dist/chunk-KNEQRUBA.mjs +0 -181
  128. package/dist/chunk-KNEQRUBA.mjs.map +0 -1
  129. package/dist/chunk-N2XQF2OL.mjs +0 -14
  130. package/dist/chunk-N4MZYNR4.mjs +0 -1342
  131. package/dist/chunk-N4MZYNR4.mjs.map +0 -1
  132. package/dist/chunk-NTVBIIUD.mjs +0 -1439
  133. package/dist/chunk-NTVBIIUD.mjs.map +0 -1
  134. package/dist/chunk-OBRSGM64.mjs +0 -607
  135. package/dist/chunk-OBRSGM64.mjs.map +0 -1
  136. package/dist/chunk-ODO4GMW7.mjs +0 -79
  137. package/dist/chunk-ODO4GMW7.mjs.map +0 -1
  138. package/dist/chunk-OLISEQHS.cjs +0 -18
  139. package/dist/chunk-PVAX67JG.mjs +0 -1041
  140. package/dist/chunk-PVAX67JG.mjs.map +0 -1
  141. package/dist/chunk-QJ6GTUCO.cjs +0 -81
  142. package/dist/chunk-QJ6GTUCO.cjs.map +0 -1
  143. package/dist/chunk-T3MWM23F.cjs +0 -214
  144. package/dist/chunk-T3MWM23F.cjs.map +0 -1
  145. package/dist/chunk-TBSHZO5R.cjs +0 -1134
  146. package/dist/chunk-TBSHZO5R.cjs.map +0 -1
  147. package/dist/chunk-UNCS5V5F.mjs +0 -887
  148. package/dist/chunk-UNCS5V5F.mjs.map +0 -1
  149. package/dist/chunk-VWQ5WOIL.mjs +0 -2059
  150. package/dist/chunk-VWQ5WOIL.mjs.map +0 -1
  151. package/dist/chunk-W75B7Y6C.cjs +0 -1478
  152. package/dist/chunk-W75B7Y6C.cjs.map +0 -1
  153. package/dist/chunk-Y6UTOBF6.mjs +0 -938
  154. package/dist/chunk-Y6UTOBF6.mjs.map +0 -1
  155. package/dist/chunk-YDPDTOSP.cjs +0 -2061
  156. package/dist/chunk-YDPDTOSP.cjs.map +0 -1
  157. package/dist/chunk-YW5IVWHQ.cjs +0 -346
  158. package/dist/chunk-YW5IVWHQ.cjs.map +0 -1
  159. package/dist/chunk-YXZ6GU7H.cjs +0 -63
  160. package/dist/chunk-YXZ6GU7H.cjs.map +0 -1
  161. package/dist/chunk-ZL7FH4NW.mjs +0 -1274
  162. package/dist/chunk-ZL7FH4NW.mjs.map +0 -1
  163. package/dist/components-EHOGXATG.cjs +0 -22
  164. package/dist/components-EHOGXATG.cjs.map +0 -1
  165. package/dist/components-MQ6DR7TX.cjs +0 -26
  166. package/dist/components-MQ6DR7TX.cjs.map +0 -1
  167. package/dist/components-XRX7QGLB.mjs +0 -5
  168. package/dist/components-XRX7QGLB.mjs.map +0 -1
  169. package/dist/components-YATKRWLH.mjs +0 -5
  170. package/dist/components-YATKRWLH.mjs.map +0 -1
  171. package/dist/index.cjs +0 -3674
  172. package/dist/index.cjs.map +0 -1
  173. package/dist/index.css +0 -234
  174. package/dist/index.css.map +0 -1
  175. package/dist/index.d.cts +0 -4929
  176. package/dist/index.d.ts +0 -4929
  177. package/dist/index.mjs +0 -2912
  178. package/dist/index.mjs.map +0 -1
  179. package/dist/launcher-5Y42OBSN.mjs +0 -6
  180. package/dist/launcher-5Y42OBSN.mjs.map +0 -1
  181. package/dist/launcher-PMW2YB24.cjs +0 -59
  182. package/dist/launcher-PMW2YB24.cjs.map +0 -1
  183. 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