@djangocfg/ui-tools 2.1.390 → 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 +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/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,1439 +0,0 @@
1
- import { getSpeechLogger, useSpeechPrefs, useResolvedLanguage } from './chunk-UNCS5V5F.mjs';
2
- import { __name } from './chunk-N2XQF2OL.mjs';
3
- import { Bot, X, PanelRightClose, PanelRightOpen, VolumeX, Volume2, RotateCcw, Globe } from 'lucide-react';
4
- import { useIsPhone, useIsTabletOrBelow, useIsMobile, useHotkey } from '@djangocfg/ui-core/hooks';
5
- import { cn } from '@djangocfg/ui-core/lib';
6
- import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
7
- import * as React from 'react';
8
- import { forwardRef, createContext, useState, useRef, useEffect, useCallback, Suspense, useMemo } from 'react';
9
- import { Button, Portal, Combobox, Flag, Avatar, AvatarImage, AvatarFallback } from '@djangocfg/ui-core/components';
10
- import { useAppT } from '@djangocfg/i18n';
11
-
12
- var SIZE_PX = { sm: 44, md: 56, lg: 64 };
13
- var ICON_PX = { sm: 18, md: 22, lg: 26 };
14
- function useEffectiveFABSize(size, inline) {
15
- const isPhone = useIsPhone();
16
- const isBelowDesktop = useIsTabletOrBelow();
17
- if (size !== "responsive") return size;
18
- if (inline) return "md";
19
- if (isPhone) return "sm";
20
- if (isBelowDesktop) return "md";
21
- return "lg";
22
- }
23
- __name(useEffectiveFABSize, "useEffectiveFABSize");
24
- function positionStyle(position, offset) {
25
- const [vert, horiz] = position.split("-");
26
- return { [vert]: offset, [horiz]: offset };
27
- }
28
- __name(positionStyle, "positionStyle");
29
- function tooltipSideClasses(position) {
30
- return position.endsWith("right") ? "right-full mr-3 origin-right" : "left-full ml-3 origin-left";
31
- }
32
- __name(tooltipSideClasses, "tooltipSideClasses");
33
- function Badge({ value }) {
34
- const display = value > 9 ? "9+" : String(value);
35
- return /* @__PURE__ */ jsx(
36
- "span",
37
- {
38
- "aria-hidden": "true",
39
- className: cn(
40
- "absolute -right-1 -top-1 inline-flex min-w-[18px] h-[18px] items-center justify-center",
41
- "rounded-full bg-destructive px-1 text-[10px] font-semibold leading-none text-destructive-foreground",
42
- "ring-2 ring-background"
43
- ),
44
- children: display
45
- }
46
- );
47
- }
48
- __name(Badge, "Badge");
49
- function PulseDot() {
50
- return /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "absolute right-1 top-1", children: /* @__PURE__ */ jsxs("span", { className: "relative inline-flex h-2.5 w-2.5", children: [
51
- /* @__PURE__ */ jsx("span", { className: "absolute inset-0 rounded-full bg-destructive opacity-75 animate-ping" }),
52
- /* @__PURE__ */ jsx("span", { className: "relative inline-flex h-2.5 w-2.5 rounded-full bg-destructive ring-2 ring-background" })
53
- ] }) });
54
- }
55
- __name(PulseDot, "PulseDot");
56
- function Tooltip({ text, side }) {
57
- return /* @__PURE__ */ jsx(
58
- "span",
59
- {
60
- role: "tooltip",
61
- className: cn(
62
- "pointer-events-none absolute top-1/2 -translate-y-1/2 whitespace-nowrap",
63
- "rounded-md bg-popover px-2.5 py-1 text-xs font-medium text-popover-foreground shadow-md",
64
- "border border-border opacity-0 scale-95 transition-all duration-150",
65
- "group-hover:opacity-100 group-hover:scale-100",
66
- "group-focus-within:opacity-100 group-focus-within:scale-100",
67
- side
68
- ),
69
- children: text
70
- }
71
- );
72
- }
73
- __name(Tooltip, "Tooltip");
74
- function ChatFAB({
75
- onClick,
76
- ariaLabel = "Open chat",
77
- icon,
78
- variant = "simple",
79
- size = "responsive",
80
- position = "bottom-right",
81
- offset = 24,
82
- zIndex = 9999,
83
- pulse = false,
84
- badge,
85
- tooltip,
86
- inline = false,
87
- className,
88
- style
89
- }) {
90
- const effectiveSize = useEffectiveFABSize(size, inline);
91
- const px = SIZE_PX[effectiveSize];
92
- const iconPx = ICON_PX[effectiveSize];
93
- const renderedIcon = icon ?? /* @__PURE__ */ jsx(Bot, { size: iconPx });
94
- const baseButton = cn(
95
- "relative grid place-items-center rounded-full focus:outline-none focus-visible:ring-2 focus-visible:ring-ring",
96
- "transition-transform hover:scale-105"
97
- );
98
- return /* @__PURE__ */ jsxs(
99
- "div",
100
- {
101
- className: cn("group", inline ? "relative inline-flex" : "fixed"),
102
- style: inline ? void 0 : { ...positionStyle(position, offset), zIndex },
103
- children: [
104
- variant === "animated" && /* @__PURE__ */ jsx(
105
- AnimatedFAB,
106
- {
107
- ariaLabel,
108
- onClick,
109
- size: px,
110
- className,
111
- style,
112
- children: renderedIcon
113
- }
114
- ),
115
- variant === "glass" && /* @__PURE__ */ jsxs(
116
- "button",
117
- {
118
- type: "button",
119
- "aria-label": ariaLabel,
120
- onClick,
121
- className: cn(
122
- baseButton,
123
- "border border-border/40 bg-background/60 text-foreground shadow-lg backdrop-blur-xl",
124
- "hover:bg-background/80",
125
- className
126
- ),
127
- style: { width: px, height: px, ...style },
128
- children: [
129
- renderedIcon,
130
- badge !== void 0 ? /* @__PURE__ */ jsx(Badge, { value: badge }) : pulse ? /* @__PURE__ */ jsx(PulseDot, {}) : null
131
- ]
132
- }
133
- ),
134
- variant === "simple" && /* @__PURE__ */ jsxs(
135
- "button",
136
- {
137
- type: "button",
138
- "aria-label": ariaLabel,
139
- onClick,
140
- className: cn(
141
- baseButton,
142
- "bg-primary text-primary-foreground hover:bg-primary/90 shadow-2xl",
143
- className
144
- ),
145
- style: { width: px, height: px, ...style },
146
- children: [
147
- renderedIcon,
148
- badge !== void 0 ? /* @__PURE__ */ jsx(Badge, { value: badge }) : pulse ? /* @__PURE__ */ jsx(PulseDot, {}) : null
149
- ]
150
- }
151
- ),
152
- tooltip && /* @__PURE__ */ jsx(Tooltip, { text: tooltip, side: tooltipSideClasses(position) })
153
- ]
154
- }
155
- );
156
- }
157
- __name(ChatFAB, "ChatFAB");
158
- function AnimatedFAB({ ariaLabel, onClick, size, className, style, children }) {
159
- return /* @__PURE__ */ jsxs(Fragment, { children: [
160
- /* @__PURE__ */ jsx("style", { children: ANIMATED_CSS }),
161
- /* @__PURE__ */ jsx(
162
- "div",
163
- {
164
- className: cn("cmdop-fab-anim", className),
165
- style: { width: size, height: size, ...style },
166
- children: /* @__PURE__ */ jsx("div", { className: "cmdop-fab-anim-glow", children: /* @__PURE__ */ jsxs("div", { className: "cmdop-fab-anim-wrap", children: [
167
- /* @__PURE__ */ jsx("div", { className: "cmdop-fab-anim-grad cmdop-fab-anim-grad-1" }),
168
- /* @__PURE__ */ jsx("div", { className: "cmdop-fab-anim-grad cmdop-fab-anim-grad-2" }),
169
- /* @__PURE__ */ jsx("div", { className: "cmdop-fab-anim-inner" }),
170
- /* @__PURE__ */ jsx(
171
- "button",
172
- {
173
- type: "button",
174
- "aria-label": ariaLabel,
175
- onClick,
176
- className: "cmdop-fab-anim-btn",
177
- children: /* @__PURE__ */ jsx("span", { className: "cmdop-fab-anim-icon", children })
178
- }
179
- )
180
- ] }) })
181
- }
182
- )
183
- ] });
184
- }
185
- __name(AnimatedFAB, "AnimatedFAB");
186
- var ANIMATED_CSS = `
187
- .cmdop-fab-anim {
188
- position: relative;
189
- pointer-events: auto;
190
- }
191
- .cmdop-fab-anim-glow {
192
- width: 100%; height: 100%;
193
- border-radius: 50%;
194
- overflow: hidden;
195
- animation:
196
- cmdop-fab-entrance 0.6s cubic-bezier(0.34, 1.45, 0.64, 1) forwards,
197
- cmdop-fab-glow-shift 8s ease-in-out 0.6s infinite;
198
- }
199
- .cmdop-fab-anim-wrap {
200
- position: relative; width: 100%; height: 100%;
201
- border-radius: 50%; overflow: hidden;
202
- }
203
- .cmdop-fab-anim-grad { position: absolute; inset: 0; border-radius: 50%; }
204
- .cmdop-fab-anim-grad-1 {
205
- background: conic-gradient(
206
- from 0deg,
207
- #fbbf24 0%, rgba(251,191,36,0) 15%,
208
- rgba(168,85,247,0) 20%, #a855f7 35%, rgba(168,85,247,0) 50%,
209
- rgba(20,184,166,0) 55%, #14b8a6 70%, rgba(20,184,166,0) 85%,
210
- rgba(236,72,153,0) 88%, #ec4899 97%, #fbbf24 100%
211
- );
212
- animation: cmdop-fab-rotate 7s linear infinite;
213
- filter: blur(1px); opacity: 0.95;
214
- }
215
- .cmdop-fab-anim-grad-2 {
216
- inset: 1px;
217
- background: conic-gradient(
218
- from 180deg,
219
- #a855f7 0%, rgba(168,85,247,0) 20%,
220
- rgba(20,184,166,0) 30%, #14b8a6 50%, rgba(20,184,166,0) 70%,
221
- rgba(251,191,36,0) 75%, #fbbf24 95%, #a855f7 100%
222
- );
223
- animation: cmdop-fab-rotate-rev 9s linear infinite;
224
- filter: blur(0.75px); opacity: 0.7;
225
- }
226
- .cmdop-fab-anim-inner {
227
- position: absolute; inset: 3px; border-radius: 50%;
228
- background: rgba(10, 10, 10, 0.65);
229
- backdrop-filter: blur(12px) saturate(1.8);
230
- -webkit-backdrop-filter: blur(12px) saturate(1.8);
231
- animation: cmdop-fab-inner-glow 5s ease-in-out infinite;
232
- }
233
- .cmdop-fab-anim-btn {
234
- position: absolute; inset: 2px;
235
- border-radius: 50%; border: none; background: transparent;
236
- cursor: pointer; display: flex; align-items: center; justify-content: center;
237
- transition: transform 0.2s;
238
- }
239
- .cmdop-fab-anim-btn:hover { transform: scale(1.06); }
240
- .cmdop-fab-anim-icon {
241
- color: #fbbf24; display: flex;
242
- filter: drop-shadow(0 0 6px rgba(251,191,36,0.8));
243
- animation: cmdop-fab-icon-pulse 2.5s ease-in-out infinite;
244
- }
245
- @keyframes cmdop-fab-rotate { to { transform: rotate(360deg); } }
246
- @keyframes cmdop-fab-rotate-rev { to { transform: rotate(-360deg); } }
247
- @keyframes cmdop-fab-entrance {
248
- 0% { transform: scale(0); }
249
- 50% { transform: scale(1.08); }
250
- 70% { transform: scale(0.98); }
251
- 100% { transform: scale(1); }
252
- }
253
- @keyframes cmdop-fab-glow-shift {
254
- 0%, 100% { box-shadow: 0 0 20px rgba(251,191,36,0.5), 0 0 40px rgba(168,85,247,0.3); }
255
- 33% { box-shadow: 0 0 20px rgba(168,85,247,0.5), 0 0 40px rgba(20,184,166,0.3); }
256
- 66% { box-shadow: 0 0 20px rgba(20,184,166,0.5), 0 0 40px rgba(236,72,153,0.3); }
257
- }
258
- @keyframes cmdop-fab-icon-pulse {
259
- 0%, 100% { opacity: 1; transform: scale(1); }
260
- 50% { opacity: 0.85; transform: scale(1.15); }
261
- }
262
- @keyframes cmdop-fab-inner-glow {
263
- 0%, 100% { box-shadow: inset 0 0 20px rgba(251,191,36,0.25), inset 0 0 40px rgba(168,85,247,0.15); }
264
- 50% { box-shadow: inset 0 0 25px rgba(168,85,247,0.3), inset 0 0 45px rgba(20,184,166,0.2); }
265
- }
266
- `;
267
- function ChatHeader({
268
- title,
269
- icon,
270
- actions,
271
- showClose = true,
272
- onClose,
273
- closeLabel = "Close",
274
- closeSlot,
275
- className
276
- }) {
277
- return /* @__PURE__ */ jsxs(
278
- "header",
279
- {
280
- className: cn(
281
- "border-border bg-muted/30 flex shrink-0 items-center justify-between border-b px-4 py-2.5",
282
- className
283
- ),
284
- children: [
285
- /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-2 text-sm font-semibold", children: [
286
- icon ?? /* @__PURE__ */ jsx(Bot, { className: "text-primary h-4 w-4 shrink-0" }),
287
- /* @__PURE__ */ jsx("span", { className: "truncate", children: title })
288
- ] }),
289
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-0.5", children: [
290
- actions,
291
- closeSlot ?? (showClose && onClose && /* @__PURE__ */ jsx(
292
- Button,
293
- {
294
- variant: "ghost",
295
- size: "sm",
296
- onClick: onClose,
297
- "aria-label": closeLabel,
298
- className: "-mr-1 h-7 w-7 p-0",
299
- children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4" })
300
- }
301
- ))
302
- ] })
303
- ]
304
- }
305
- );
306
- }
307
- __name(ChatHeader, "ChatHeader");
308
- function useChatPresence(open, exitDurationMs = 200) {
309
- const [phase, setPhase] = useState("hidden");
310
- const timerRef = useRef(null);
311
- useEffect(() => {
312
- if (timerRef.current) clearTimeout(timerRef.current);
313
- if (open) {
314
- setPhase("entering");
315
- timerRef.current = setTimeout(() => setPhase("visible"), 16);
316
- } else {
317
- setPhase("leaving");
318
- timerRef.current = setTimeout(() => setPhase("hidden"), exitDurationMs);
319
- }
320
- return () => {
321
- if (timerRef.current) clearTimeout(timerRef.current);
322
- };
323
- }, [open, exitDurationMs]);
324
- return phase;
325
- }
326
- __name(useChatPresence, "useChatPresence");
327
- function dockPositionStyle(position, horizontal, vertical) {
328
- const [vert, horiz] = position.split("-");
329
- return { [vert]: vertical, [horiz]: horizontal };
330
- }
331
- __name(dockPositionStyle, "dockPositionStyle");
332
- function ChatDock({
333
- open,
334
- onClose,
335
- children,
336
- mode = "popover",
337
- side = "right",
338
- title = "Chat",
339
- icon,
340
- headerActions,
341
- hideHeader = false,
342
- closeLabel,
343
- width,
344
- height = 720,
345
- position = "bottom-right",
346
- offset,
347
- exitDurationMs = 200,
348
- zIndex = 1e4,
349
- ariaLabel,
350
- className,
351
- mobileFullscreen = true,
352
- disablePortal = false,
353
- inline = false,
354
- reserveBodySpace
355
- }) {
356
- const phase = useChatPresence(open, exitDurationMs);
357
- const isMobile = useIsMobile();
358
- const isBelowDesktop = useIsTabletOrBelow();
359
- const effectiveMode = mode === "side" && !isBelowDesktop ? "side" : "popover";
360
- const fullscreen = mobileFullscreen && isMobile;
361
- const wantsReserve = !inline && !fullscreen && effectiveMode === "side" && (reserveBodySpace ?? true);
362
- const resolvedSideWidth = width ?? 420;
363
- useEffect(() => {
364
- if (!wantsReserve || phase === "hidden") return;
365
- const body = document.body;
366
- if (!body) return;
367
- const cssVar = `${resolvedSideWidth}px`;
368
- const padKey = side === "right" ? "paddingRight" : "paddingLeft";
369
- const prevPad = body.style[padKey];
370
- const prevVar = body.style.getPropertyValue("--chat-dock-reserve");
371
- body.style[padKey] = cssVar;
372
- body.style.setProperty("--chat-dock-reserve", cssVar);
373
- return () => {
374
- body.style[padKey] = prevPad;
375
- if (prevVar) body.style.setProperty("--chat-dock-reserve", prevVar);
376
- else body.style.removeProperty("--chat-dock-reserve");
377
- };
378
- }, [wantsReserve, phase, side, resolvedSideWidth]);
379
- if (phase === "hidden") return null;
380
- const animating = phase === "entering" || phase === "leaving";
381
- const horizontal = offset?.horizontal ?? 24;
382
- const vertical = offset?.vertical ?? 96;
383
- const resolvedWidth = width ?? (effectiveMode === "side" ? resolvedSideWidth : 480);
384
- let containerStyle;
385
- let cornerClass;
386
- const dynVH = "100dvh";
387
- if (inline) {
388
- containerStyle = {
389
- position: "relative",
390
- width: resolvedWidth,
391
- height,
392
- maxHeight: `calc(${dynVH} - 16px)`,
393
- pointerEvents: phase === "visible" ? "auto" : "none"
394
- };
395
- cornerClass = "rounded-xl border";
396
- } else if (fullscreen) {
397
- containerStyle = {
398
- position: "fixed",
399
- top: 0,
400
- [side === "left" ? "left" : "right"]: 0,
401
- width: "100vw",
402
- height: dynVH,
403
- zIndex,
404
- pointerEvents: phase === "visible" ? "auto" : "none"
405
- };
406
- cornerClass = "rounded-none border-0";
407
- } else if (effectiveMode === "side") {
408
- containerStyle = {
409
- position: "fixed",
410
- top: 0,
411
- [side]: 0,
412
- height: dynVH,
413
- zIndex,
414
- width: `min(${resolvedWidth}px, 100vw)`,
415
- pointerEvents: phase === "visible" ? "auto" : "none"
416
- };
417
- cornerClass = side === "right" ? "rounded-none border-l" : "rounded-none border-r";
418
- } else {
419
- const heightCap = `calc(${dynVH} - ${vertical + 24}px)`;
420
- containerStyle = {
421
- position: "fixed",
422
- ...dockPositionStyle(position, horizontal, vertical),
423
- zIndex,
424
- width: `min(${resolvedWidth}px, calc(100vw - 32px))`,
425
- height: `min(${height}px, ${heightCap})`,
426
- minHeight: `min(320px, ${heightCap})`,
427
- pointerEvents: phase === "visible" ? "auto" : "none"
428
- };
429
- cornerClass = "rounded-xl border";
430
- }
431
- const enterClass = (() => {
432
- if (fullscreen) return "opacity-0";
433
- if (effectiveMode === "side") {
434
- return side === "right" ? "opacity-0 translate-x-4" : "opacity-0 -translate-x-4";
435
- }
436
- return "opacity-0 scale-95 translate-y-2";
437
- })();
438
- const visibleClass = "opacity-100 scale-100 translate-y-0 translate-x-0";
439
- return /* @__PURE__ */ jsx(Portal, { disablePortal: disablePortal || inline, children: /* @__PURE__ */ jsxs(
440
- "div",
441
- {
442
- role: "dialog",
443
- "aria-label": ariaLabel ?? (typeof title === "string" ? title : "Chat"),
444
- "aria-hidden": phase === "leaving",
445
- className: cn(
446
- "bg-popover text-popover-foreground border-border",
447
- "flex flex-col overflow-hidden shadow-2xl",
448
- cornerClass,
449
- "transition-all duration-200 ease-out",
450
- animating ? enterClass : visibleClass,
451
- className
452
- ),
453
- style: containerStyle,
454
- children: [
455
- !hideHeader && /* @__PURE__ */ jsx(
456
- ChatHeader,
457
- {
458
- title,
459
- icon,
460
- actions: headerActions,
461
- onClose,
462
- closeLabel
463
- }
464
- ),
465
- /* @__PURE__ */ jsx("div", { className: "min-h-0 min-w-0 flex-1 overflow-hidden", children })
466
- ]
467
- }
468
- ) });
469
- }
470
- __name(ChatDock, "ChatDock");
471
- var ChatHeaderActionButton = forwardRef(
472
- /* @__PURE__ */ __name(function ChatHeaderActionButton2({ icon, ariaLabel, badge, destructive, loading, disabled, className, ...rest }, ref) {
473
- return /* @__PURE__ */ jsxs(
474
- "button",
475
- {
476
- ref,
477
- type: "button",
478
- "aria-label": ariaLabel,
479
- title: ariaLabel,
480
- disabled: disabled || loading,
481
- className: cn(
482
- "relative inline-flex h-7 w-7 items-center justify-center rounded-md",
483
- "text-muted-foreground transition-colors",
484
- "hover:bg-accent hover:text-foreground",
485
- "focus:outline-none focus-visible:ring-2 focus-visible:ring-ring",
486
- "disabled:opacity-50 disabled:cursor-not-allowed",
487
- destructive && "hover:bg-destructive/15 hover:text-destructive",
488
- loading && "animate-pulse",
489
- className
490
- ),
491
- ...rest,
492
- children: [
493
- icon,
494
- badge !== void 0 && /* @__PURE__ */ jsx(
495
- "span",
496
- {
497
- "aria-hidden": "true",
498
- className: "absolute -right-0.5 -top-0.5 inline-flex min-w-[14px] h-[14px] items-center justify-center rounded-full bg-destructive px-1 text-[9px] font-semibold leading-none text-destructive-foreground ring-2 ring-background",
499
- children: badge > 9 ? "9+" : badge
500
- }
501
- )
502
- ]
503
- }
504
- );
505
- }, "ChatHeaderActionButton")
506
- );
507
- function ChatHeaderModeToggle({
508
- mode,
509
- onToggle,
510
- expandLabel = "Dock to side",
511
- collapseLabel = "Back to popover",
512
- forceVisible = false
513
- }) {
514
- const isBelowDesktop = useIsTabletOrBelow();
515
- if (isBelowDesktop && !forceVisible) return null;
516
- const isSide = mode === "side";
517
- return /* @__PURE__ */ jsx(
518
- ChatHeaderActionButton,
519
- {
520
- icon: isSide ? /* @__PURE__ */ jsx(PanelRightClose, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx(PanelRightOpen, { className: "h-3.5 w-3.5" }),
521
- ariaLabel: isSide ? collapseLabel : expandLabel,
522
- onClick: onToggle
523
- }
524
- );
525
- }
526
- __name(ChatHeaderModeToggle, "ChatHeaderModeToggle");
527
- function ChatHeaderAudioToggle({
528
- muted,
529
- onToggle,
530
- unmuteLabel = "Unmute notifications",
531
- muteLabel = "Mute notifications"
532
- }) {
533
- return /* @__PURE__ */ jsx(
534
- ChatHeaderActionButton,
535
- {
536
- icon: muted ? /* @__PURE__ */ jsx(VolumeX, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx(Volume2, { className: "h-3.5 w-3.5" }),
537
- ariaLabel: muted ? unmuteLabel : muteLabel,
538
- onClick: onToggle
539
- }
540
- );
541
- }
542
- __name(ChatHeaderAudioToggle, "ChatHeaderAudioToggle");
543
- function useChatReset(opts) {
544
- const { onReset, onSuccess, onError } = opts;
545
- const [isResetting, setIsResetting] = useState(false);
546
- const reset = useCallback(async () => {
547
- if (isResetting) return false;
548
- setIsResetting(true);
549
- try {
550
- const ok = await onReset();
551
- if (ok) onSuccess?.();
552
- else onError?.();
553
- return ok;
554
- } catch (err) {
555
- onError?.(err);
556
- return false;
557
- } finally {
558
- setIsResetting(false);
559
- }
560
- }, [isResetting, onReset, onSuccess, onError]);
561
- return { reset, isResetting };
562
- }
563
- __name(useChatReset, "useChatReset");
564
- var DEFAULT_TITLE = "Clear conversation?";
565
- var DEFAULT_MESSAGE = "The assistant will forget this session and start a new one. This cannot be undone.";
566
- var DEFAULT_LABEL = "Clear conversation";
567
- function ChatHeaderResetButton({
568
- onReset,
569
- onSuccess,
570
- onError,
571
- confirm = true,
572
- confirmTitle = DEFAULT_TITLE,
573
- confirmMessage = DEFAULT_MESSAGE,
574
- ariaLabel = DEFAULT_LABEL
575
- }) {
576
- const { reset, isResetting } = useChatReset({ onReset, onSuccess, onError });
577
- const handleClick = /* @__PURE__ */ __name(async () => {
578
- if (confirm) {
579
- const api = typeof window !== "undefined" ? window.dialog : void 0;
580
- if (api?.confirm) {
581
- const ok = await api.confirm({
582
- title: confirmTitle,
583
- message: confirmMessage,
584
- variant: "destructive",
585
- confirmText: "Clear",
586
- cancelText: "Cancel"
587
- });
588
- if (!ok) return;
589
- } else if (typeof window !== "undefined" && typeof window.confirm === "function") {
590
- const ok = window.confirm(`${confirmTitle}
591
-
592
- ${confirmMessage}`);
593
- if (!ok) return;
594
- }
595
- }
596
- await reset();
597
- }, "handleClick");
598
- return /* @__PURE__ */ jsx(
599
- ChatHeaderActionButton,
600
- {
601
- icon: /* @__PURE__ */ jsx(RotateCcw, { className: "h-3.5 w-3.5" }),
602
- ariaLabel,
603
- onClick: handleClick,
604
- loading: isResetting,
605
- destructive: true
606
- }
607
- );
608
- }
609
- __name(ChatHeaderResetButton, "ChatHeaderResetButton");
610
-
611
- // src/tools/SpeechRecognition/core/languages-catalog.ts
612
- var WEB_SPEECH_LANGUAGES = [
613
- { name: "Afrikaans", iso: "af", englishName: "afrikaans", dialects: [{ code: "af-ZA", region: "South Africa" }] },
614
- { name: "\u12A0\u121B\u122D\u129B", iso: "am", englishName: "amharic", dialects: [{ code: "am-ET", region: "Ethiopia" }] },
615
- { name: "Az\u0259rbaycanca", iso: "az", englishName: "azerbaijani", dialects: [{ code: "az-AZ", region: "Azerbaijan" }] },
616
- {
617
- name: "\u09AC\u09BE\u0982\u09B2\u09BE",
618
- iso: "bn",
619
- englishName: "bengali",
620
- dialects: [
621
- { code: "bn-BD", region: "Bangladesh" },
622
- { code: "bn-IN", region: "India" }
623
- ]
624
- },
625
- { name: "Bahasa Indonesia", iso: "id", englishName: "indonesian", dialects: [{ code: "id-ID", region: "Indonesia" }] },
626
- { name: "Bahasa Melayu", iso: "ms", englishName: "malay", dialects: [{ code: "ms-MY", region: "Malaysia" }] },
627
- { name: "Catal\xE0", iso: "ca", englishName: "catalan", dialects: [{ code: "ca-ES", region: "Spain" }] },
628
- { name: "\u010Ce\u0161tina", iso: "cs", englishName: "czech", dialects: [{ code: "cs-CZ", region: "Czechia" }] },
629
- { name: "Dansk", iso: "da", englishName: "danish", dialects: [{ code: "da-DK", region: "Denmark" }] },
630
- { name: "Deutsch", iso: "de", englishName: "german", dialects: [{ code: "de-DE", region: "Germany" }] },
631
- {
632
- name: "English",
633
- iso: "en",
634
- englishName: "english",
635
- dialects: [
636
- { code: "en-US", region: "United States" },
637
- { code: "en-GB", region: "United Kingdom" },
638
- { code: "en-AU", region: "Australia" },
639
- { code: "en-CA", region: "Canada" },
640
- { code: "en-IN", region: "India" },
641
- { code: "en-NZ", region: "New Zealand" },
642
- { code: "en-PH", region: "Philippines" },
643
- { code: "en-ZA", region: "South Africa" },
644
- { code: "en-NG", region: "Nigeria" },
645
- { code: "en-GH", region: "Ghana" },
646
- { code: "en-KE", region: "Kenya" },
647
- { code: "en-TZ", region: "Tanzania" }
648
- ]
649
- },
650
- {
651
- name: "Espa\xF1ol",
652
- iso: "es",
653
- englishName: "spanish",
654
- dialects: [
655
- { code: "es-ES", region: "Espa\xF1a" },
656
- { code: "es-MX", region: "M\xE9xico" },
657
- { code: "es-US", region: "Estados Unidos" },
658
- { code: "es-AR", region: "Argentina" },
659
- { code: "es-CL", region: "Chile" },
660
- { code: "es-CO", region: "Colombia" },
661
- { code: "es-PE", region: "Per\xFA" },
662
- { code: "es-VE", region: "Venezuela" },
663
- { code: "es-EC", region: "Ecuador" },
664
- { code: "es-GT", region: "Guatemala" },
665
- { code: "es-CR", region: "Costa Rica" },
666
- { code: "es-PA", region: "Panam\xE1" },
667
- { code: "es-DO", region: "Rep. Dominicana" },
668
- { code: "es-UY", region: "Uruguay" },
669
- { code: "es-PY", region: "Paraguay" },
670
- { code: "es-BO", region: "Bolivia" },
671
- { code: "es-SV", region: "El Salvador" },
672
- { code: "es-HN", region: "Honduras" },
673
- { code: "es-NI", region: "Nicaragua" },
674
- { code: "es-PR", region: "Puerto Rico" }
675
- ]
676
- },
677
- { name: "Euskara", iso: "eu", englishName: "basque", dialects: [{ code: "eu-ES", region: "Spain" }] },
678
- { name: "Filipino", iso: "fil", englishName: "filipino tagalog", dialects: [{ code: "fil-PH", region: "Philippines" }] },
679
- { name: "Fran\xE7ais", iso: "fr", englishName: "french", dialects: [{ code: "fr-FR", region: "France" }] },
680
- { name: "Basa Jawa", iso: "jv", englishName: "javanese", dialects: [{ code: "jv-ID", region: "Indonesia" }] },
681
- { name: "Galego", iso: "gl", englishName: "galician", dialects: [{ code: "gl-ES", region: "Spain" }] },
682
- { name: "\u0A97\u0AC1\u0A9C\u0AB0\u0ABE\u0AA4\u0AC0", iso: "gu", englishName: "gujarati", dialects: [{ code: "gu-IN", region: "India" }] },
683
- { name: "Hrvatski", iso: "hr", englishName: "croatian", dialects: [{ code: "hr-HR", region: "Croatia" }] },
684
- { name: "IsiZulu", iso: "zu", englishName: "zulu", dialects: [{ code: "zu-ZA", region: "South Africa" }] },
685
- { name: "\xCDslenska", iso: "is", englishName: "icelandic", dialects: [{ code: "is-IS", region: "Iceland" }] },
686
- {
687
- name: "Italiano",
688
- iso: "it",
689
- englishName: "italian",
690
- dialects: [
691
- { code: "it-IT", region: "Italia" },
692
- { code: "it-CH", region: "Svizzera" }
693
- ]
694
- },
695
- { name: "\u0C95\u0CA8\u0CCD\u0CA8\u0CA1", iso: "kn", englishName: "kannada", dialects: [{ code: "kn-IN", region: "India" }] },
696
- { name: "\u1797\u17B6\u179F\u17B6\u1781\u17D2\u1798\u17C2\u179A", iso: "km", englishName: "khmer cambodian", dialects: [{ code: "km-KH", region: "Cambodia" }] },
697
- { name: "Latvie\u0161u", iso: "lv", englishName: "latvian", dialects: [{ code: "lv-LV", region: "Latvia" }] },
698
- { name: "Lietuvi\u0173", iso: "lt", englishName: "lithuanian", dialects: [{ code: "lt-LT", region: "Lithuania" }] },
699
- { name: "\u0D2E\u0D32\u0D2F\u0D3E\u0D33\u0D02", iso: "ml", englishName: "malayalam", dialects: [{ code: "ml-IN", region: "India" }] },
700
- { name: "\u092E\u0930\u093E\u0920\u0940", iso: "mr", englishName: "marathi", dialects: [{ code: "mr-IN", region: "India" }] },
701
- { name: "Magyar", iso: "hu", englishName: "hungarian", dialects: [{ code: "hu-HU", region: "Hungary" }] },
702
- { name: "\u0EA5\u0EB2\u0EA7", iso: "lo", englishName: "lao laotian", dialects: [{ code: "lo-LA", region: "Laos" }] },
703
- { name: "Nederlands", iso: "nl", englishName: "dutch", dialects: [{ code: "nl-NL", region: "Netherlands" }] },
704
- { name: "\u0928\u0947\u092A\u093E\u0932\u0940 \u092D\u093E\u0937\u093E", iso: "ne", englishName: "nepali", dialects: [{ code: "ne-NP", region: "Nepal" }] },
705
- { name: "Norsk bokm\xE5l", iso: "nb", englishName: "norwegian bokmal", dialects: [{ code: "nb-NO", region: "Norway" }] },
706
- { name: "Polski", iso: "pl", englishName: "polish", dialects: [{ code: "pl-PL", region: "Poland" }] },
707
- {
708
- name: "Portugu\xEAs",
709
- iso: "pt",
710
- englishName: "portuguese",
711
- dialects: [
712
- { code: "pt-BR", region: "Brasil" },
713
- { code: "pt-PT", region: "Portugal" }
714
- ]
715
- },
716
- { name: "Rom\xE2n\u0103", iso: "ro", englishName: "romanian", dialects: [{ code: "ro-RO", region: "Romania" }] },
717
- { name: "\u0DC3\u0DD2\u0D82\u0DC4\u0DBD", iso: "si", englishName: "sinhala sinhalese", dialects: [{ code: "si-LK", region: "Sri Lanka" }] },
718
- { name: "Sloven\u0161\u010Dina", iso: "sl", englishName: "slovenian", dialects: [{ code: "sl-SI", region: "Slovenia" }] },
719
- { name: "Basa Sunda", iso: "su", englishName: "sundanese", dialects: [{ code: "su-ID", region: "Indonesia" }] },
720
- { name: "Sloven\u010Dina", iso: "sk", englishName: "slovak", dialects: [{ code: "sk-SK", region: "Slovakia" }] },
721
- { name: "Suomi", iso: "fi", englishName: "finnish", dialects: [{ code: "fi-FI", region: "Finland" }] },
722
- { name: "Svenska", iso: "sv", englishName: "swedish", dialects: [{ code: "sv-SE", region: "Sweden" }] },
723
- {
724
- name: "Kiswahili",
725
- iso: "sw",
726
- englishName: "swahili",
727
- dialects: [
728
- { code: "sw-TZ", region: "Tanzania" },
729
- { code: "sw-KE", region: "Kenya" }
730
- ]
731
- },
732
- { name: "\u10E5\u10D0\u10E0\u10D7\u10E3\u10DA\u10D8", iso: "ka", englishName: "georgian", dialects: [{ code: "ka-GE", region: "Georgia" }] },
733
- { name: "\u0540\u0561\u0575\u0565\u0580\u0565\u0576", iso: "hy", englishName: "armenian", dialects: [{ code: "hy-AM", region: "Armenia" }] },
734
- {
735
- name: "\u0BA4\u0BAE\u0BBF\u0BB4\u0BCD",
736
- iso: "ta",
737
- englishName: "tamil",
738
- dialects: [
739
- { code: "ta-IN", region: "\u0B87\u0BA8\u0BCD\u0BA4\u0BBF\u0BAF\u0BBE" },
740
- { code: "ta-SG", region: "\u0B9A\u0BBF\u0B99\u0BCD\u0B95\u0BAA\u0BCD\u0BAA\u0BC2\u0BB0\u0BCD" },
741
- { code: "ta-LK", region: "\u0B87\u0BB2\u0B99\u0BCD\u0B95\u0BC8" },
742
- { code: "ta-MY", region: "\u0BAE\u0BB2\u0BC7\u0B9A\u0BBF\u0BAF\u0BBE" }
743
- ]
744
- },
745
- { name: "\u0C24\u0C46\u0C32\u0C41\u0C17\u0C41", iso: "te", englishName: "telugu", dialects: [{ code: "te-IN", region: "India" }] },
746
- { name: "Ti\u1EBFng Vi\u1EC7t", iso: "vi", englishName: "vietnamese", dialects: [{ code: "vi-VN", region: "Vietnam" }] },
747
- { name: "T\xFCrk\xE7e", iso: "tr", englishName: "turkish", dialects: [{ code: "tr-TR", region: "T\xFCrkiye" }] },
748
- {
749
- name: "\u0627\u064F\u0631\u062F\u064F\u0648",
750
- iso: "ur",
751
- englishName: "urdu",
752
- dialects: [
753
- { code: "ur-PK", region: "\u067E\u0627\u06A9\u0633\u062A\u0627\u0646" },
754
- { code: "ur-IN", region: "\u0628\u06BE\u0627\u0631\u062A" }
755
- ]
756
- },
757
- { name: "\u0395\u03BB\u03BB\u03B7\u03BD\u03B9\u03BA\u03AC", iso: "el", englishName: "greek", dialects: [{ code: "el-GR", region: "Greece" }] },
758
- { name: "\u0431\u044A\u043B\u0433\u0430\u0440\u0441\u043A\u0438", iso: "bg", englishName: "bulgarian", dialects: [{ code: "bg-BG", region: "Bulgaria" }] },
759
- { name: "\u0420\u0443\u0441\u0441\u043A\u0438\u0439", iso: "ru", englishName: "russian", dialects: [{ code: "ru-RU", region: "Russia" }] },
760
- { name: "\u0421\u0440\u043F\u0441\u043A\u0438", iso: "sr", englishName: "serbian", dialects: [{ code: "sr-RS", region: "Serbia" }] },
761
- { name: "\u0423\u043A\u0440\u0430\u0457\u043D\u0441\u044C\u043A\u0430", iso: "uk", englishName: "ukrainian", dialects: [{ code: "uk-UA", region: "Ukraine" }] },
762
- { name: "\uD55C\uAD6D\uC5B4", iso: "ko", englishName: "korean", dialects: [{ code: "ko-KR", region: "Korea" }] },
763
- {
764
- name: "\u4E2D\u6587",
765
- iso: "cmn",
766
- englishName: "chinese mandarin cantonese",
767
- dialects: [
768
- { code: "cmn-Hans-CN", region: "\u666E\u901A\u8BDD (\u4E2D\u56FD\u5927\u9646)" },
769
- { code: "cmn-Hans-HK", region: "\u666E\u901A\u8BDD (\u9999\u6E2F)" },
770
- { code: "cmn-Hant-TW", region: "\u4E2D\u6587 (\u53F0\u7063)" },
771
- { code: "yue-Hant-HK", region: "\u7CB5\u8A9E (\u9999\u6E2F)" }
772
- ]
773
- },
774
- { name: "\u65E5\u672C\u8A9E", iso: "ja", englishName: "japanese", dialects: [{ code: "ja-JP", region: "Japan" }] },
775
- { name: "\u0939\u093F\u0928\u094D\u0926\u0940", iso: "hi", englishName: "hindi", dialects: [{ code: "hi-IN", region: "India" }] },
776
- { name: "\u0E20\u0E32\u0E29\u0E32\u0E44\u0E17\u0E22", iso: "th", englishName: "thai", dialects: [{ code: "th-TH", region: "Thailand" }] }
777
- ];
778
- WEB_SPEECH_LANGUAGES.flatMap(
779
- (l) => l.dialects.map((d) => d.code)
780
- );
781
- function findSpeechLanguage(tag) {
782
- if (!tag) return null;
783
- const lower = tag.toLowerCase();
784
- for (const language of WEB_SPEECH_LANGUAGES) {
785
- for (const dialect of language.dialects) {
786
- if (dialect.code.toLowerCase() === lower) return { language, dialect };
787
- }
788
- }
789
- return null;
790
- }
791
- __name(findSpeechLanguage, "findSpeechLanguage");
792
- function countryFromTag(tag) {
793
- if (!tag) return null;
794
- const parts = tag.split("-");
795
- for (let i = parts.length - 1; i >= 0; i -= 1) {
796
- const p = parts[i];
797
- if (p.length === 2 && /^[A-Za-z]{2}$/.test(p)) return p.toUpperCase();
798
- }
799
- return null;
800
- }
801
- __name(countryFromTag, "countryFromTag");
802
- getSpeechLogger();
803
- createContext(null);
804
- function Spinner({ className }) {
805
- const t = useAppT();
806
- const loadingLabel = t("ui.states.loading");
807
- return /* @__PURE__ */ jsx(
808
- "div",
809
- {
810
- className: cn(
811
- "inline-block h-8 w-8 animate-spin rounded-full",
812
- "border-4 border-solid border-current border-r-transparent",
813
- "align-[-0.125em] motion-reduce:animate-[spin_1.5s_linear_infinite]",
814
- className
815
- ),
816
- role: "status",
817
- "aria-label": loadingLabel
818
- }
819
- );
820
- }
821
- __name(Spinner, "Spinner");
822
- function LoadingFallback({
823
- minHeight = 200,
824
- showText = true,
825
- text,
826
- className
827
- }) {
828
- const t = useAppT();
829
- const loadingText = text ?? t("ui.form.loading");
830
- const height = typeof minHeight === "number" ? `${minHeight}px` : minHeight;
831
- return /* @__PURE__ */ jsx(
832
- "div",
833
- {
834
- className: cn(
835
- "flex items-center justify-center bg-muted/30 rounded-lg",
836
- className
837
- ),
838
- style: { minHeight: height },
839
- children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
840
- /* @__PURE__ */ jsx(Spinner, { className: "text-primary" }),
841
- showText && /* @__PURE__ */ jsx("p", { className: "mt-3 text-sm text-muted-foreground", children: loadingText })
842
- ] })
843
- }
844
- );
845
- }
846
- __name(LoadingFallback, "LoadingFallback");
847
- function CardLoadingFallback({
848
- title,
849
- description,
850
- minHeight = 200,
851
- className
852
- }) {
853
- const t = useAppT();
854
- const cardTitle = title ?? t("ui.states.loading");
855
- const height = typeof minHeight === "number" ? `${minHeight}px` : minHeight;
856
- return /* @__PURE__ */ jsxs(
857
- "div",
858
- {
859
- className: cn(
860
- "relative bg-card rounded-lg border border-border overflow-hidden",
861
- className
862
- ),
863
- children: [
864
- /* @__PURE__ */ jsxs("div", { className: "p-4 border-b border-border bg-muted/50", children: [
865
- /* @__PURE__ */ jsx("h6", { className: "text-sm font-semibold text-foreground", children: cardTitle }),
866
- description && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-1", children: description })
867
- ] }),
868
- /* @__PURE__ */ jsx("div", { className: "p-4", children: /* @__PURE__ */ jsx(
869
- "div",
870
- {
871
- className: "flex justify-center items-center",
872
- style: { minHeight: height },
873
- children: /* @__PURE__ */ jsx(Spinner, { className: "text-primary" })
874
- }
875
- ) })
876
- ]
877
- }
878
- );
879
- }
880
- __name(CardLoadingFallback, "CardLoadingFallback");
881
- function MapLoadingFallback({
882
- minHeight = 400,
883
- className
884
- }) {
885
- const t = useAppT();
886
- const loadingText = t("ui.form.loading");
887
- const height = typeof minHeight === "number" ? `${minHeight}px` : minHeight;
888
- return /* @__PURE__ */ jsx(
889
- "div",
890
- {
891
- className: cn(
892
- "relative bg-muted/50 rounded-lg overflow-hidden",
893
- "flex items-center justify-center",
894
- className
895
- ),
896
- style: { minHeight: height },
897
- children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
898
- /* @__PURE__ */ jsxs("div", { className: "relative", children: [
899
- /* @__PURE__ */ jsx(Spinner, { className: "text-primary h-10 w-10" }),
900
- /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center", children: /* @__PURE__ */ jsxs(
901
- "svg",
902
- {
903
- className: "h-5 w-5 text-muted-foreground",
904
- fill: "none",
905
- viewBox: "0 0 24 24",
906
- stroke: "currentColor",
907
- children: [
908
- /* @__PURE__ */ jsx(
909
- "path",
910
- {
911
- strokeLinecap: "round",
912
- strokeLinejoin: "round",
913
- strokeWidth: 2,
914
- d: "M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z"
915
- }
916
- ),
917
- /* @__PURE__ */ jsx(
918
- "path",
919
- {
920
- strokeLinecap: "round",
921
- strokeLinejoin: "round",
922
- strokeWidth: 2,
923
- d: "M15 11a3 3 0 11-6 0 3 3 0 016 0z"
924
- }
925
- )
926
- ]
927
- }
928
- ) })
929
- ] }),
930
- /* @__PURE__ */ jsx("p", { className: "mt-3 text-sm text-muted-foreground", children: loadingText })
931
- ] })
932
- }
933
- );
934
- }
935
- __name(MapLoadingFallback, "MapLoadingFallback");
936
- function LazyWrapper({
937
- children,
938
- fallback,
939
- card = false,
940
- cardTitle,
941
- cardDescription,
942
- minHeight = 200,
943
- className
944
- }) {
945
- const defaultFallback = card ? /* @__PURE__ */ jsx(
946
- CardLoadingFallback,
947
- {
948
- title: cardTitle,
949
- description: cardDescription,
950
- minHeight,
951
- className
952
- }
953
- ) : /* @__PURE__ */ jsx(LoadingFallback, { minHeight, className });
954
- return /* @__PURE__ */ jsx(Suspense, { fallback: fallback ?? defaultFallback, children });
955
- }
956
- __name(LazyWrapper, "LazyWrapper");
957
- function createLazyComponent(loader, options = {}) {
958
- const LazyComponent = React.lazy(loader);
959
- const WrappedComponent = /* @__PURE__ */ __name((props) => {
960
- const fallback = typeof options.fallback === "function" ? options.fallback(props) : options.fallback ?? /* @__PURE__ */ jsx(LoadingFallback, {});
961
- return /* @__PURE__ */ jsx(Suspense, { fallback, children: /* @__PURE__ */ jsx(LazyComponent, { ...props }) });
962
- }, "WrappedComponent");
963
- WrappedComponent.displayName = options.displayName ?? "LazyComponent";
964
- return WrappedComponent;
965
- }
966
- __name(createLazyComponent, "createLazyComponent");
967
- createLazyComponent(
968
- () => import('./DictationField-WPONUCYE.mjs').then((mod) => ({
969
- default: mod.DictationField
970
- })),
971
- {
972
- displayName: "LazyDictationField",
973
- fallback: /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-border/60 bg-card px-3 py-2 text-xs text-muted-foreground", children: "Loading dictation\u2026" })
974
- }
975
- );
976
- function ChatHeaderLanguageButton({
977
- ariaLabel = "Speech language",
978
- allowedTags,
979
- hideFallbackIcon,
980
- className
981
- }) {
982
- const prefs = useSpeechPrefs();
983
- const active = useResolvedLanguage();
984
- const options = useMemo(() => {
985
- const allow = allowedTags ? new Set(allowedTags) : null;
986
- const out = [];
987
- for (const lang of WEB_SPEECH_LANGUAGES) {
988
- for (const d of lang.dialects) {
989
- if (allow && !allow.has(d.code)) continue;
990
- out.push({
991
- value: d.code,
992
- // "Русский" / "Español — Argentina" / "English — United States"
993
- label: lang.dialects.length === 1 ? lang.name : `${lang.name} \u2014 ${d.region}`,
994
- // Search-only index: English name, BCP-47 tag, ISO, region.
995
- // Lets users type "russian" / "ru-RU" / "ru" / "argentina"
996
- // and still find the row regardless of native script.
997
- description: `${lang.englishName} ${d.code} ${lang.iso} ${d.region}`.toLowerCase()
998
- });
999
- }
1000
- }
1001
- return out;
1002
- }, [allowedTags]);
1003
- return /* @__PURE__ */ jsx(
1004
- Combobox,
1005
- {
1006
- options,
1007
- value: prefs.language ?? active,
1008
- onValueChange: (v) => prefs.setLanguage(v || null),
1009
- placeholder: ariaLabel,
1010
- searchPlaceholder: "Search language\u2026",
1011
- filterFunction: (opt, search) => {
1012
- const s = search.toLowerCase();
1013
- return opt.label.toLowerCase().includes(s) || opt.value.toLowerCase().includes(s) || (opt.description?.includes(s) ?? false);
1014
- },
1015
- contentClassName: "w-[280px]",
1016
- contentStyle: { zIndex: 10001 },
1017
- renderOption: (option) => {
1018
- const country = countryFromTag(option.value);
1019
- return /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
1020
- country ? /* @__PURE__ */ jsx(
1021
- Flag,
1022
- {
1023
- countryCode: country,
1024
- className: "h-4 w-5 shrink-0 overflow-hidden rounded-[2px] border border-border/60 ring-1 ring-black/5"
1025
- }
1026
- ) : /* @__PURE__ */ jsx(Globe, { className: "h-4 w-4 shrink-0 text-muted-foreground", "aria-hidden": true }),
1027
- /* @__PURE__ */ jsx("span", { className: "truncate text-sm", children: option.label })
1028
- ] });
1029
- },
1030
- renderTrigger: (selected, open) => {
1031
- const tag = selected?.value ?? active;
1032
- const country = countryFromTag(tag);
1033
- const found = findSpeechLanguage(tag);
1034
- const tooltipLabel = found ? `${found.language.name}${found.language.dialects.length > 1 ? ` \u2014 ${found.dialect.region}` : ""} \xB7 ${tag}` : tag;
1035
- return /* @__PURE__ */ jsx(
1036
- "button",
1037
- {
1038
- type: "button",
1039
- "aria-label": `${ariaLabel}: ${tooltipLabel}`,
1040
- "aria-expanded": open,
1041
- title: tooltipLabel,
1042
- className: cn(
1043
- "inline-flex h-7 w-7 items-center justify-center rounded-md",
1044
- "text-muted-foreground transition-colors",
1045
- "hover:bg-accent hover:text-foreground",
1046
- "focus:outline-none focus-visible:ring-2 focus-visible:ring-ring",
1047
- className
1048
- ),
1049
- children: country ? /* @__PURE__ */ jsx(
1050
- Flag,
1051
- {
1052
- countryCode: country,
1053
- className: "h-4 w-5 overflow-hidden rounded-[2px] border border-border/60 ring-1 ring-black/5"
1054
- }
1055
- ) : hideFallbackIcon ? null : /* @__PURE__ */ jsx(Globe, { className: "h-3.5 w-3.5", "aria-hidden": true })
1056
- }
1057
- );
1058
- }
1059
- }
1060
- );
1061
- }
1062
- __name(ChatHeaderLanguageButton, "ChatHeaderLanguageButton");
1063
- function anchorStyle(position, fabOffset, fabClearance) {
1064
- const [vert, horiz] = position.split("-");
1065
- return { [vert]: fabClearance, [horiz]: fabOffset };
1066
- }
1067
- __name(anchorStyle, "anchorStyle");
1068
- function originClass(position) {
1069
- if (position === "bottom-right") return "origin-bottom-right";
1070
- if (position === "bottom-left") return "origin-bottom-left";
1071
- if (position === "top-right") return "origin-top-right";
1072
- return "origin-top-left";
1073
- }
1074
- __name(originClass, "originClass");
1075
- function ChatGreeting({
1076
- open,
1077
- children,
1078
- onClick,
1079
- onDismiss,
1080
- position = "bottom-right",
1081
- fabOffset = 24,
1082
- fabClearance = 96,
1083
- delayMs = 1500,
1084
- zIndex = 9998,
1085
- className,
1086
- style,
1087
- avatar,
1088
- senderName,
1089
- dismissLabel = "Dismiss",
1090
- inline = false
1091
- }) {
1092
- const [delayed, setDelayed] = useState(delayMs <= 0);
1093
- useEffect(() => {
1094
- if (!open || delayMs <= 0) return;
1095
- const t = setTimeout(() => setDelayed(true), delayMs);
1096
- return () => clearTimeout(t);
1097
- }, [open, delayMs]);
1098
- const shouldShow = open && delayed;
1099
- const phase = useChatPresence(shouldShow, 220);
1100
- if (phase === "hidden") return null;
1101
- const animating = phase === "entering" || phase === "leaving";
1102
- const clickable = !!onClick;
1103
- return /* @__PURE__ */ jsxs(
1104
- "div",
1105
- {
1106
- role: clickable ? "button" : "status",
1107
- "aria-live": "polite",
1108
- tabIndex: clickable ? 0 : -1,
1109
- onClick: clickable ? onClick : void 0,
1110
- onKeyDown: clickable ? (e) => {
1111
- if (e.key === "Enter" || e.key === " ") {
1112
- e.preventDefault();
1113
- onClick?.();
1114
- }
1115
- } : void 0,
1116
- className: cn(
1117
- inline ? "relative inline-flex" : "fixed",
1118
- "flex items-start gap-2.5 max-w-[280px]",
1119
- "rounded-2xl border border-border bg-popover text-popover-foreground",
1120
- "px-3.5 py-2.5 shadow-2xl transition-all duration-200 ease-out",
1121
- clickable && "cursor-pointer hover:bg-accent/40 focus:outline-none focus-visible:ring-2 focus-visible:ring-ring",
1122
- originClass(position),
1123
- animating ? "opacity-0 scale-95 translate-y-1" : "opacity-100 scale-100 translate-y-0",
1124
- className
1125
- ),
1126
- style: {
1127
- ...inline ? {} : anchorStyle(position, fabOffset, fabClearance),
1128
- ...inline ? {} : { zIndex },
1129
- pointerEvents: phase === "visible" ? "auto" : "none",
1130
- ...style
1131
- },
1132
- children: [
1133
- avatar && /* @__PURE__ */ jsx("div", { className: "mt-0.5 shrink-0", children: avatar }),
1134
- /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 text-sm leading-snug", children: [
1135
- senderName && /* @__PURE__ */ jsx("div", { className: "mb-0.5 text-[11px] font-medium text-muted-foreground", children: senderName }),
1136
- /* @__PURE__ */ jsx("div", { className: "text-foreground", children })
1137
- ] }),
1138
- onDismiss && /* @__PURE__ */ jsx(
1139
- "button",
1140
- {
1141
- type: "button",
1142
- "aria-label": dismissLabel,
1143
- onClick: (e) => {
1144
- e.stopPropagation();
1145
- onDismiss();
1146
- },
1147
- className: cn(
1148
- "-mr-1 -mt-1 flex h-6 w-6 shrink-0 items-center justify-center rounded-full",
1149
- "text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
1150
- "focus:outline-none focus-visible:ring-2 focus-visible:ring-ring"
1151
- ),
1152
- children: /* @__PURE__ */ jsx(X, { className: "h-3.5 w-3.5" })
1153
- }
1154
- )
1155
- ]
1156
- }
1157
- );
1158
- }
1159
- __name(ChatGreeting, "ChatGreeting");
1160
- var TIME_FORMAT = new Intl.DateTimeFormat(void 0, {
1161
- hour: "2-digit",
1162
- minute: "2-digit"
1163
- });
1164
- function anchorStyle2(position, fabOffset, fabClearance) {
1165
- const [vert, horiz] = position.split("-");
1166
- return { [vert]: fabClearance, [horiz]: fabOffset };
1167
- }
1168
- __name(anchorStyle2, "anchorStyle");
1169
- function originClass2(position) {
1170
- if (position === "bottom-right") return "origin-bottom-right";
1171
- if (position === "bottom-left") return "origin-bottom-left";
1172
- if (position === "top-right") return "origin-top-right";
1173
- return "origin-top-left";
1174
- }
1175
- __name(originClass2, "originClass");
1176
- function deriveAvatar(persona, name) {
1177
- const initials = persona?.initials ?? (name ?? persona?.name ?? "?").split(/\s+/).map((p) => p[0]).filter(Boolean).slice(0, 2).join("").toUpperCase();
1178
- return /* @__PURE__ */ jsxs(Avatar, { className: "h-9 w-9", children: [
1179
- persona?.avatarUrl ? /* @__PURE__ */ jsx(AvatarImage, { src: persona.avatarUrl }) : null,
1180
- /* @__PURE__ */ jsx(AvatarFallback, { children: initials || "?" })
1181
- ] });
1182
- }
1183
- __name(deriveAvatar, "deriveAvatar");
1184
- function ChatUnreadPreview({
1185
- open,
1186
- message,
1187
- onClick,
1188
- onDismiss,
1189
- position = "bottom-right",
1190
- fabOffset = 24,
1191
- fabClearance = 96,
1192
- truncate = 2,
1193
- zIndex = 9998,
1194
- inline = false,
1195
- className,
1196
- style,
1197
- dismissLabel = "Mark as read",
1198
- avatar,
1199
- senderName
1200
- }) {
1201
- const shouldShow = open && !!message;
1202
- const phase = useChatPresence(shouldShow, 200);
1203
- if (phase === "hidden" || !message) return null;
1204
- const animating = phase === "entering" || phase === "leaving";
1205
- const clickable = !!onClick;
1206
- const displayName = senderName ?? message.sender?.name ?? "New message";
1207
- const stamp = TIME_FORMAT.format(new Date(message.createdAt));
1208
- return /* @__PURE__ */ jsxs(
1209
- "div",
1210
- {
1211
- role: clickable ? "button" : "status",
1212
- "aria-live": "polite",
1213
- tabIndex: clickable ? 0 : -1,
1214
- onClick: clickable ? onClick : void 0,
1215
- onKeyDown: clickable ? (e) => {
1216
- if (e.key === "Enter" || e.key === " ") {
1217
- e.preventDefault();
1218
- onClick?.();
1219
- }
1220
- } : void 0,
1221
- className: cn(
1222
- inline ? "relative inline-flex" : "fixed",
1223
- "flex items-start gap-2.5 max-w-[300px]",
1224
- "rounded-2xl border border-border bg-popover text-popover-foreground",
1225
- "px-3.5 py-2.5 shadow-2xl transition-all duration-200 ease-out",
1226
- clickable && "cursor-pointer hover:bg-accent/40 focus:outline-none focus-visible:ring-2 focus-visible:ring-ring",
1227
- originClass2(position),
1228
- animating ? "opacity-0 scale-95 translate-y-1" : "opacity-100 scale-100 translate-y-0",
1229
- className
1230
- ),
1231
- style: {
1232
- ...inline ? {} : anchorStyle2(position, fabOffset, fabClearance),
1233
- ...inline ? {} : { zIndex },
1234
- pointerEvents: phase === "visible" ? "auto" : "none",
1235
- ...style
1236
- },
1237
- children: [
1238
- /* @__PURE__ */ jsx("div", { className: "mt-0.5 shrink-0", children: avatar ?? deriveAvatar(message.sender, displayName) }),
1239
- /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 text-sm leading-snug", children: [
1240
- /* @__PURE__ */ jsxs("div", { className: "flex items-baseline justify-between gap-2", children: [
1241
- /* @__PURE__ */ jsx("div", { className: "truncate text-[12px] font-semibold text-foreground", children: displayName }),
1242
- /* @__PURE__ */ jsx("div", { className: "shrink-0 text-[10px] text-muted-foreground", children: stamp })
1243
- ] }),
1244
- /* @__PURE__ */ jsx(
1245
- "div",
1246
- {
1247
- className: "text-foreground/90 mt-0.5 break-words",
1248
- style: {
1249
- display: "-webkit-box",
1250
- WebkitLineClamp: truncate,
1251
- WebkitBoxOrient: "vertical",
1252
- overflow: "hidden"
1253
- },
1254
- children: message.content
1255
- }
1256
- )
1257
- ] }),
1258
- onDismiss ? /* @__PURE__ */ jsx(
1259
- "button",
1260
- {
1261
- type: "button",
1262
- "aria-label": dismissLabel,
1263
- onClick: (e) => {
1264
- e.stopPropagation();
1265
- onDismiss();
1266
- },
1267
- className: cn(
1268
- "-mr-1 -mt-1 flex h-6 w-6 shrink-0 items-center justify-center rounded-full",
1269
- "text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
1270
- "focus:outline-none focus-visible:ring-2 focus-visible:ring-ring"
1271
- ),
1272
- children: /* @__PURE__ */ jsx(X, { className: "h-3.5 w-3.5" })
1273
- }
1274
- ) : null
1275
- ]
1276
- }
1277
- );
1278
- }
1279
- __name(ChatUnreadPreview, "ChatUnreadPreview");
1280
- function readDismissed(storageKey) {
1281
- if (!storageKey) return false;
1282
- if (typeof window === "undefined") return false;
1283
- try {
1284
- return window.localStorage.getItem(storageKey) === "1";
1285
- } catch {
1286
- return false;
1287
- }
1288
- }
1289
- __name(readDismissed, "readDismissed");
1290
- function writeDismissed(storageKey) {
1291
- if (!storageKey) return;
1292
- if (typeof window === "undefined") return;
1293
- try {
1294
- window.localStorage.setItem(storageKey, "1");
1295
- } catch {
1296
- }
1297
- }
1298
- __name(writeDismissed, "writeDismissed");
1299
- function ChatLauncher({
1300
- children,
1301
- fab,
1302
- dock,
1303
- greeting,
1304
- hotkey,
1305
- defaultOpen = false,
1306
- open: controlledOpen,
1307
- onOpenChange,
1308
- autoFocusComposerOnOpen = true,
1309
- closeOnEscape = true,
1310
- unreadMessage,
1311
- onMarkRead,
1312
- unreadPreview,
1313
- audio,
1314
- hideAudioToggle = false
1315
- }) {
1316
- const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);
1317
- const isControlled = controlledOpen !== void 0;
1318
- const open = isControlled ? controlledOpen : uncontrolledOpen;
1319
- const dockContentRef = useRef(null);
1320
- useEffect(() => {
1321
- if (!autoFocusComposerOnOpen || !open) return;
1322
- const t = setTimeout(() => {
1323
- const root = dockContentRef.current;
1324
- if (!root) return;
1325
- const target = root.querySelector(
1326
- 'textarea:not([disabled]):not([readonly]), input[type="text"]:not([disabled]):not([readonly])'
1327
- );
1328
- target?.focus();
1329
- }, 120);
1330
- return () => clearTimeout(t);
1331
- }, [open, autoFocusComposerOnOpen]);
1332
- const setOpen = useCallback(
1333
- (next) => {
1334
- if (!isControlled) setUncontrolledOpen(next);
1335
- onOpenChange?.(next);
1336
- },
1337
- [isControlled, onOpenChange]
1338
- );
1339
- const toggleOpen = useCallback(() => setOpen(!open), [open, setOpen]);
1340
- useHotkey(
1341
- "escape",
1342
- (e) => {
1343
- const target = e?.target ?? null;
1344
- const inEditable = !!target && (target.matches?.('input, textarea, [contenteditable="true"]') ?? false);
1345
- if (inEditable) {
1346
- target.blur();
1347
- return;
1348
- }
1349
- setOpen(false);
1350
- },
1351
- { enabled: closeOnEscape && open }
1352
- );
1353
- const greetingConfig = greeting === void 0 ? null : typeof greeting === "string" ? { content: greeting } : greeting;
1354
- const [dismissed, setDismissed] = useState(
1355
- () => readDismissed(greetingConfig?.dismissStorageKey)
1356
- );
1357
- useEffect(() => {
1358
- if (!hotkey) return;
1359
- const handler = /* @__PURE__ */ __name((e) => {
1360
- const metaOk = hotkey.meta ? e.metaKey || e.ctrlKey : !e.metaKey && !e.ctrlKey;
1361
- const shiftOk = hotkey.shift ? e.shiftKey : !e.shiftKey;
1362
- const altOk = hotkey.alt ? e.altKey : !e.altKey;
1363
- if (!metaOk || !shiftOk || !altOk) return;
1364
- if (e.key !== hotkey.key) return;
1365
- e.preventDefault();
1366
- setOpen(!open);
1367
- }, "handler");
1368
- window.addEventListener("keydown", handler);
1369
- return () => window.removeEventListener("keydown", handler);
1370
- }, [hotkey?.key, hotkey?.meta, hotkey?.shift, hotkey?.alt, open, setOpen, hotkey]);
1371
- const greetingOpen = !!greetingConfig && !dismissed && (greetingConfig.hideOnOpen === false || !open);
1372
- const fabPosition = fab?.position ?? "bottom-right";
1373
- const fabOffset = fab?.offset ?? 24;
1374
- const handleGreetingDismiss = /* @__PURE__ */ __name(() => {
1375
- setDismissed(true);
1376
- writeDismissed(greetingConfig?.dismissStorageKey);
1377
- }, "handleGreetingDismiss");
1378
- const handleGreetingClick = /* @__PURE__ */ __name(() => {
1379
- setOpen(true);
1380
- setDismissed(true);
1381
- writeDismissed(greetingConfig?.dismissStorageKey);
1382
- }, "handleGreetingClick");
1383
- useEffect(() => {
1384
- if (open && unreadMessage) onMarkRead?.();
1385
- }, [open, unreadMessage, onMarkRead]);
1386
- const unreadOpen = !open && !!unreadMessage;
1387
- const handleUnreadClick = /* @__PURE__ */ __name(() => {
1388
- setOpen(true);
1389
- onMarkRead?.();
1390
- }, "handleUnreadClick");
1391
- const handleUnreadDismiss = /* @__PURE__ */ __name(() => {
1392
- onMarkRead?.();
1393
- }, "handleUnreadDismiss");
1394
- const resolvedFab = unreadMessage && fab?.badge === void 0 ? { ...fab, badge: 1 } : fab;
1395
- return /* @__PURE__ */ jsxs(Fragment, { children: [
1396
- /* @__PURE__ */ jsx(ChatFAB, { ...resolvedFab, onClick: toggleOpen }),
1397
- unreadMessage ? /* @__PURE__ */ jsx(
1398
- ChatUnreadPreview,
1399
- {
1400
- ...unreadPreview,
1401
- open: unreadOpen,
1402
- message: unreadMessage,
1403
- onClick: handleUnreadClick,
1404
- onDismiss: handleUnreadDismiss,
1405
- position: fabPosition,
1406
- fabOffset
1407
- }
1408
- ) : greetingConfig ? /* @__PURE__ */ jsx(
1409
- ChatGreeting,
1410
- {
1411
- ...greetingConfig,
1412
- open: greetingOpen,
1413
- onClick: handleGreetingClick,
1414
- onDismiss: handleGreetingDismiss,
1415
- position: fabPosition,
1416
- fabOffset,
1417
- children: greetingConfig.content
1418
- }
1419
- ) : null,
1420
- /* @__PURE__ */ jsx(
1421
- ChatDock,
1422
- {
1423
- ...dock,
1424
- open,
1425
- onClose: () => setOpen(false),
1426
- headerActions: audio && !audio.isSilent && !hideAudioToggle || dock?.headerActions ? /* @__PURE__ */ jsxs(Fragment, { children: [
1427
- dock?.headerActions,
1428
- audio && !audio.isSilent && !hideAudioToggle ? /* @__PURE__ */ jsx(ChatHeaderAudioToggle, { muted: audio.muted, onToggle: audio.toggleMute }) : null
1429
- ] }) : void 0,
1430
- children: /* @__PURE__ */ jsx("div", { ref: dockContentRef, className: "flex h-full min-h-0 min-w-0 flex-col", children })
1431
- }
1432
- )
1433
- ] });
1434
- }
1435
- __name(ChatLauncher, "ChatLauncher");
1436
-
1437
- export { CardLoadingFallback, ChatDock, ChatFAB, ChatGreeting, ChatHeader, ChatHeaderActionButton, ChatHeaderAudioToggle, ChatHeaderLanguageButton, ChatHeaderModeToggle, ChatHeaderResetButton, ChatLauncher, ChatUnreadPreview, LazyWrapper, LoadingFallback, MapLoadingFallback, Spinner, createLazyComponent, useChatPresence, useChatReset };
1438
- //# sourceMappingURL=chunk-NTVBIIUD.mjs.map
1439
- //# sourceMappingURL=chunk-NTVBIIUD.mjs.map