@arbidocs/blocks 0.4.109 → 0.4.110

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 (112) hide show
  1. package/dist/agents/index.cjs +286 -286
  2. package/dist/agents/index.js +10 -10
  3. package/dist/agents/tasks/ConversationListView.d.ts +5 -1
  4. package/dist/agents/tasks/TaskActivityTimeline.d.ts +5 -1
  5. package/dist/calendar/EventDetails.d.ts +1 -1
  6. package/dist/calendar/index.cjs +13 -0
  7. package/dist/calendar/index.cjs.map +1 -1
  8. package/dist/calendar/index.js +13 -0
  9. package/dist/calendar/index.js.map +1 -1
  10. package/dist/calendar/types.d.ts +3 -0
  11. package/dist/calls/CallSidePanel.d.ts +17 -0
  12. package/dist/calls/CallStage.d.ts +57 -0
  13. package/dist/calls/ControlBar.d.ts +91 -0
  14. package/dist/calls/ControlButton.d.ts +44 -0
  15. package/dist/calls/PreJoin.d.ts +31 -0
  16. package/dist/calls/cards.d.ts +54 -0
  17. package/dist/calls/hooks.d.ts +20 -0
  18. package/dist/calls/index.cjs +1853 -0
  19. package/dist/calls/index.cjs.map +1 -0
  20. package/dist/calls/index.d.ts +20 -0
  21. package/dist/calls/index.js +1737 -0
  22. package/dist/calls/index.js.map +1 -0
  23. package/dist/calls/join-choices.d.ts +11 -0
  24. package/dist/calls/layout.d.ts +106 -0
  25. package/dist/calls/panels.d.ts +55 -0
  26. package/dist/calls/status.d.ts +69 -0
  27. package/dist/calls/tiles.d.ts +59 -0
  28. package/dist/chat/Message.d.ts +17 -2
  29. package/dist/chat/TranscriptLine.d.ts +50 -0
  30. package/dist/chat/index.cjs +147 -126
  31. package/dist/chat/index.d.ts +3 -1
  32. package/dist/chat/index.js +5 -4
  33. package/dist/chat/transcript-runs.d.ts +6 -0
  34. package/dist/{chunk-QKWQMOHN.cjs → chunk-2UAJVK3C.cjs} +4 -4
  35. package/dist/{chunk-QKWQMOHN.cjs.map → chunk-2UAJVK3C.cjs.map} +1 -1
  36. package/dist/{chunk-7C35WXYB.js → chunk-5HFPRI3W.js} +5 -5
  37. package/dist/chunk-5HFPRI3W.js.map +1 -0
  38. package/dist/{chunk-ZSV2NQQP.js → chunk-6RHHMBZ5.js} +158 -5
  39. package/dist/chunk-6RHHMBZ5.js.map +1 -0
  40. package/dist/{chunk-FQX6N5G6.js → chunk-A35KT2II.js} +35 -18
  41. package/dist/chunk-A35KT2II.js.map +1 -0
  42. package/dist/{chunk-PGDL26TQ.js → chunk-AY32GGKU.js} +10 -4
  43. package/dist/{chunk-PGDL26TQ.js.map → chunk-AY32GGKU.js.map} +1 -1
  44. package/dist/{chunk-S55VDTX3.js → chunk-CECWAIHL.js} +3 -3
  45. package/dist/{chunk-S55VDTX3.js.map → chunk-CECWAIHL.js.map} +1 -1
  46. package/dist/{chunk-UABPHZWZ.js → chunk-CXZ7FPTQ.js} +3 -3
  47. package/dist/{chunk-UABPHZWZ.js.map → chunk-CXZ7FPTQ.js.map} +1 -1
  48. package/dist/{chunk-C2HRZSAT.cjs → chunk-DJM7DLCT.cjs} +5 -5
  49. package/dist/chunk-DJM7DLCT.cjs.map +1 -0
  50. package/dist/{chunk-I4XQCE6U.cjs → chunk-HBBJYRGI.cjs} +162 -5
  51. package/dist/{chunk-ZSV2NQQP.js.map → chunk-HBBJYRGI.cjs.map} +1 -1
  52. package/dist/chunk-MWDW5UBW.cjs +199 -0
  53. package/dist/chunk-MWDW5UBW.cjs.map +1 -0
  54. package/dist/{chunk-NUTLXVPX.js → chunk-NRUPUDWB.js} +16 -7
  55. package/dist/chunk-NRUPUDWB.js.map +1 -0
  56. package/dist/{chunk-DDF5GPIJ.js → chunk-P5ST47VY.js} +3 -3
  57. package/dist/{chunk-DDF5GPIJ.js.map → chunk-P5ST47VY.js.map} +1 -1
  58. package/dist/{chunk-W7NZRZ54.js → chunk-SQNAJPNR.js} +4 -4
  59. package/dist/{chunk-W7NZRZ54.js.map → chunk-SQNAJPNR.js.map} +1 -1
  60. package/dist/{chunk-PDRYGPZB.cjs → chunk-VP4KJ4LK.cjs} +16 -6
  61. package/dist/chunk-VP4KJ4LK.cjs.map +1 -0
  62. package/dist/{chunk-GBYY3PIC.cjs → chunk-VZKBI2KJ.cjs} +79 -62
  63. package/dist/chunk-VZKBI2KJ.cjs.map +1 -0
  64. package/dist/{chunk-5YXG342J.cjs → chunk-W7ZDBPJ3.cjs} +4 -4
  65. package/dist/{chunk-5YXG342J.cjs.map → chunk-W7ZDBPJ3.cjs.map} +1 -1
  66. package/dist/{chunk-SKSE4OT6.cjs → chunk-WPVIOGDG.cjs} +5 -5
  67. package/dist/{chunk-SKSE4OT6.cjs.map → chunk-WPVIOGDG.cjs.map} +1 -1
  68. package/dist/{chunk-3US5OIDQ.cjs → chunk-XSUOEJB3.cjs} +9 -3
  69. package/dist/chunk-XSUOEJB3.cjs.map +1 -0
  70. package/dist/chunk-Z3AZ7Q5X.js +177 -0
  71. package/dist/chunk-Z3AZ7Q5X.js.map +1 -0
  72. package/dist/{chunk-Z5VUZ6YD.cjs → chunk-ZV3BKLFY.cjs} +3 -3
  73. package/dist/{chunk-Z5VUZ6YD.cjs.map → chunk-ZV3BKLFY.cjs.map} +1 -1
  74. package/dist/collaboration/index.cjs +41 -41
  75. package/dist/collaboration/index.js +1 -1
  76. package/dist/connect/index.cjs +66 -66
  77. package/dist/connect/index.js +13 -13
  78. package/dist/facts/index.cjs +4 -4
  79. package/dist/facts/index.js +4 -4
  80. package/dist/files/index.cjs +6 -6
  81. package/dist/files/index.js +6 -6
  82. package/dist/home/index.cjs +17 -17
  83. package/dist/home/index.js +3 -3
  84. package/dist/index.cjs +846 -825
  85. package/dist/index.cjs.map +1 -1
  86. package/dist/index.js +21 -20
  87. package/dist/index.js.map +1 -1
  88. package/dist/retrieval/index.cjs +1 -1
  89. package/dist/retrieval/index.js +1 -1
  90. package/dist/settings/index.cjs +37 -37
  91. package/dist/settings/index.js +5 -5
  92. package/dist/shell/index.cjs +12 -12
  93. package/dist/shell/index.js +4 -4
  94. package/dist/site/index.cjs +5 -5
  95. package/dist/site/index.js +1 -1
  96. package/dist/studio/index.cjs +5 -5
  97. package/dist/studio/index.js +4 -4
  98. package/dist/workflow-canvas/index.cjs +53 -53
  99. package/dist/workflow-canvas/index.js +10 -10
  100. package/dist/workspaces/index.cjs +2 -2
  101. package/dist/workspaces/index.js +2 -2
  102. package/node_modules/@arbidocs/coedit/package.json +1 -1
  103. package/package.json +15 -5
  104. package/src/calls/calls.css +157 -0
  105. package/dist/chunk-3US5OIDQ.cjs.map +0 -1
  106. package/dist/chunk-7C35WXYB.js.map +0 -1
  107. package/dist/chunk-C2HRZSAT.cjs.map +0 -1
  108. package/dist/chunk-FQX6N5G6.js.map +0 -1
  109. package/dist/chunk-GBYY3PIC.cjs.map +0 -1
  110. package/dist/chunk-I4XQCE6U.cjs.map +0 -1
  111. package/dist/chunk-NUTLXVPX.js.map +0 -1
  112. package/dist/chunk-PDRYGPZB.cjs.map +0 -1
@@ -0,0 +1,1853 @@
1
+ "use client";
2
+ 'use strict';
3
+
4
+ var chunk7RGLTF76_cjs = require('../chunk-7RGLTF76.cjs');
5
+ var chunkMWDW5UBW_cjs = require('../chunk-MWDW5UBW.cjs');
6
+ require('../chunk-PPCATBOY.cjs');
7
+ require('../chunk-MHVNT4J3.cjs');
8
+ require('../chunk-DES3K4SD.cjs');
9
+ var react = require('react');
10
+ var ui = require('@arbidocs/react/ui');
11
+ var jsxRuntime = require('react/jsx-runtime');
12
+ var lucideReact = require('lucide-react');
13
+
14
+ var TONE = {
15
+ neutral: "bg-muted text-foreground hover:bg-accent",
16
+ // Solid: a control whose thing is on reads as on at a glance (CC on, chat open, sharing).
17
+ active: "bg-primary text-primary-foreground hover:bg-primary/90",
18
+ off: "bg-red-bg text-red-text hover:bg-red-bg/80",
19
+ danger: "bg-destructive text-destructive-foreground hover:bg-destructive/90"
20
+ };
21
+ var CallControlButton = react.forwardRef(
22
+ function CallControlButton2({
23
+ label,
24
+ shortcut,
25
+ tone = "neutral",
26
+ side = "top",
27
+ tooltip = true,
28
+ className,
29
+ children,
30
+ ...props
31
+ }, ref) {
32
+ const button = /* @__PURE__ */ jsxRuntime.jsx(
33
+ ui.Button,
34
+ {
35
+ ref,
36
+ type: "button",
37
+ variant: "ghost",
38
+ size: "icon",
39
+ "aria-label": label,
40
+ className: ui.cn("relative shrink-0 [&_svg]:size-[18px]", TONE[tone], className),
41
+ ...props,
42
+ children
43
+ }
44
+ );
45
+ if (!tooltip) return button;
46
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.Tooltip, { children: [
47
+ /* @__PURE__ */ jsxRuntime.jsx(ui.TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex shrink-0", children: button }) }),
48
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.TooltipContent, { side, children: [
49
+ label,
50
+ shortcut && /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "ml-2 rounded-sm border border-border px-1 font-sans text-[11px] text-muted-foreground", children: shortcut })
51
+ ] })
52
+ ] });
53
+ }
54
+ );
55
+ function ControlBadge({
56
+ count,
57
+ tone = "alert",
58
+ testId
59
+ }) {
60
+ return /* @__PURE__ */ jsxRuntime.jsx(
61
+ "span",
62
+ {
63
+ className: ui.cn(
64
+ "pointer-events-none absolute -right-1 min-w-[1.125rem] rounded-full px-1 text-center text-[10px] font-semibold leading-[1.125rem]",
65
+ tone === "alert" ? "-top-1 bg-destructive text-destructive-foreground ring-2 ring-background" : "-bottom-1 bg-background text-muted-foreground ring-1 ring-border"
66
+ ),
67
+ "data-testid": testId,
68
+ children: count > 99 ? "99+" : count
69
+ }
70
+ );
71
+ }
72
+ function CallStatusChip({
73
+ tone,
74
+ icon,
75
+ label,
76
+ compact = false,
77
+ pulse = false,
78
+ title,
79
+ children,
80
+ className,
81
+ testId,
82
+ ...rest
83
+ }) {
84
+ const tones = {
85
+ red: "border-red-border bg-red-bg text-red-text",
86
+ green: "border-green-border bg-green-bg text-green-text",
87
+ yellow: "border-yellow-border bg-yellow-bg text-yellow-text",
88
+ neutral: "border-border bg-muted text-muted-foreground"
89
+ };
90
+ return /* @__PURE__ */ jsxRuntime.jsxs(
91
+ "span",
92
+ {
93
+ className: ui.cn(
94
+ "inline-flex h-6 shrink-0 items-center gap-1.5 rounded-md border px-2 text-xs font-medium",
95
+ tones[tone],
96
+ className
97
+ ),
98
+ title,
99
+ "data-testid": testId,
100
+ ...rest,
101
+ children: [
102
+ pulse && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "relative flex size-2 shrink-0", "aria-hidden": true, children: [
103
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute inline-flex size-full animate-ping rounded-full bg-red-solid opacity-60 motion-reduce:hidden" }),
104
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "relative inline-flex size-2 rounded-full bg-red-solid" })
105
+ ] }),
106
+ icon,
107
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: ui.cn("min-w-0 truncate", compact && "sr-only"), children: label }),
108
+ children
109
+ ]
110
+ }
111
+ );
112
+ }
113
+ function useElementSize() {
114
+ const [size, setSize] = react.useState({ width: 0, height: 0 });
115
+ const observer = react.useRef(null);
116
+ const ref = react.useMemo(
117
+ () => (el) => {
118
+ observer.current?.disconnect();
119
+ observer.current = null;
120
+ if (!el || typeof ResizeObserver === "undefined") return;
121
+ const ro = new ResizeObserver((entries) => {
122
+ const r = entries[0]?.contentRect;
123
+ if (!r) return;
124
+ setSize(
125
+ (s) => s.width === r.width && s.height === r.height ? s : { width: r.width, height: r.height }
126
+ );
127
+ });
128
+ ro.observe(el);
129
+ observer.current = ro;
130
+ },
131
+ []
132
+ );
133
+ react.useEffect(() => () => observer.current?.disconnect(), []);
134
+ return [ref, size];
135
+ }
136
+ function useBriefNotice(announce = true, onFolded, ms = chunkMWDW5UBW_cjs.NOTICE_MS) {
137
+ const [expanded, setExpanded] = react.useState(announce);
138
+ const folded = react.useRef(onFolded);
139
+ folded.current = onFolded;
140
+ react.useEffect(() => {
141
+ if (!expanded) return;
142
+ const id = setTimeout(() => {
143
+ setExpanded(false);
144
+ folded.current?.();
145
+ }, ms);
146
+ return () => clearTimeout(id);
147
+ }, [expanded, ms]);
148
+ return expanded;
149
+ }
150
+ function typing(e) {
151
+ const el = e.target;
152
+ return !!el?.closest?.('input, textarea, select, [contenteditable="true"], [role="textbox"]');
153
+ }
154
+ function useShortcutKeys(ref, enabled) {
155
+ react.useEffect(() => {
156
+ if (!enabled) return;
157
+ const onKey = (e) => {
158
+ if (e.repeat || e.ctrlKey || e.metaKey || e.altKey || typing(e)) return;
159
+ const key = e.key.toLowerCase();
160
+ if (!/^[a-z]$/.test(key)) return;
161
+ const button = ref.current?.querySelector(
162
+ `[data-call-shortcut="${key}"]:not(:disabled)`
163
+ );
164
+ if (!button) return;
165
+ e.preventDefault();
166
+ button.click();
167
+ };
168
+ window.addEventListener("keydown", onKey);
169
+ return () => window.removeEventListener("keydown", onKey);
170
+ }, [ref, enabled]);
171
+ }
172
+ var CallTile = react.forwardRef(function CallTile2({
173
+ name,
174
+ initials,
175
+ video,
176
+ source = "camera",
177
+ local = false,
178
+ mirror = false,
179
+ speaking = false,
180
+ level = 0,
181
+ micMuted = false,
182
+ poorConnection = false,
183
+ size = "normal",
184
+ youLabel,
185
+ className,
186
+ style,
187
+ ...rest
188
+ }, ref) {
189
+ const screen = source === "screen";
190
+ const ring = speaking && !screen ? Math.min(1, Math.max(0, level)) : 0;
191
+ return /* @__PURE__ */ jsxRuntime.jsxs(
192
+ "div",
193
+ {
194
+ ref,
195
+ className: ui.cn("call-tile", className),
196
+ "data-call-tile": "",
197
+ "data-source": source,
198
+ "data-local": local,
199
+ "data-mirror": mirror && source === "camera" && !!video,
200
+ "data-speaking": speaking && !screen,
201
+ style: { "--call-level": ring.toFixed(2), ...style },
202
+ ...rest,
203
+ children: [
204
+ video ?? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "call-tile-placeholder", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: ui.cn("call-tile-avatar", size === "small" && "call-tile-avatar-sm"), children: initials }) }),
205
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "call-tile-name", children: [
206
+ typeof name === "string" ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "call-tile-chip min-w-0", children: [
207
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: name }),
208
+ local && !screen && youLabel && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 opacity-80", children: youLabel })
209
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "call-tile-chip min-w-0 overflow-hidden py-0.5 pl-0.5", children: name }),
210
+ (screen || micMuted || speaking) && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "call-tile-chip shrink-0", children: [
211
+ screen && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MonitorUp, { className: "size-3.5", "aria-label": "Screen" }),
212
+ !screen && micMuted && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MicOff, { className: "size-3.5", "aria-label": "Microphone off" }),
213
+ speaking && !screen && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AudioLines, { className: "call-tile-speaking size-3.5", "aria-label": "Speaking" })
214
+ ] })
215
+ ] }),
216
+ poorConnection && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "call-tile-signal", title: "Poor connection", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.SignalLow, { className: "size-3.5", "aria-label": "Poor connection" }) })
217
+ ]
218
+ }
219
+ );
220
+ });
221
+ var GRID_GAP = 8;
222
+ function CallGrid({
223
+ items,
224
+ getKey,
225
+ renderTile,
226
+ moreLabel = (n) => `${n} more`,
227
+ className
228
+ }) {
229
+ const [ref, size] = useElementSize();
230
+ const { shown, hidden } = chunkMWDW5UBW_cjs.gridSlots(items);
231
+ const count = shown.length + (hidden ? 1 : 0);
232
+ const layout = chunkMWDW5UBW_cjs.gridLayout(count, size.width, size.height, GRID_GAP);
233
+ const box = { width: layout.tileWidth, height: layout.tileHeight };
234
+ const rows = [];
235
+ let next = 0;
236
+ for (const n of layout.rowCounts) rows.push(Array.from({ length: n }, () => next++));
237
+ return /* @__PURE__ */ jsxRuntime.jsx(
238
+ "div",
239
+ {
240
+ ref,
241
+ className: ui.cn("flex size-full min-h-0 flex-col items-center", className),
242
+ style: { gap: GRID_GAP },
243
+ "data-testid": "call-grid",
244
+ "data-cols": layout.cols,
245
+ children: layout.tileWidth > 0 && rows.map((row, r) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center", style: { gap: GRID_GAP }, children: row.map(
246
+ (i) => i < shown.length ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "call-tile-box", style: box, children: renderTile(shown[i]) }, getKey(shown[i])) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "call-tile call-tile-more", style: box, children: [
247
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Users, { className: "size-5", "aria-hidden": true }),
248
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: moreLabel(hidden) })
249
+ ] }, "more")
250
+ ) }, r))
251
+ }
252
+ );
253
+ }
254
+ function CallFocus({
255
+ focus,
256
+ others,
257
+ getKey,
258
+ renderTile,
259
+ className,
260
+ testId = "call-focus"
261
+ }) {
262
+ const [ref, size] = useElementSize();
263
+ const narrow = size.width > 0 && size.width < 640;
264
+ const box = chunkMWDW5UBW_cjs.spotlightBox(size.width, size.height, others.length, narrow);
265
+ return /* @__PURE__ */ jsxRuntime.jsxs(
266
+ "div",
267
+ {
268
+ ref,
269
+ className: ui.cn(
270
+ "flex size-full min-h-0 gap-2",
271
+ narrow ? "flex-col items-center" : "flex-row items-start justify-center",
272
+ className
273
+ ),
274
+ "data-testid": testId,
275
+ children: [
276
+ /* @__PURE__ */ jsxRuntime.jsx(
277
+ "div",
278
+ {
279
+ className: "call-tile-box shrink-0",
280
+ style: { width: box.width, height: box.height },
281
+ "data-testid": "call-spotlight",
282
+ children: box.width > 0 && renderTile(focus, "normal")
283
+ },
284
+ getKey(focus)
285
+ ),
286
+ others.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
287
+ "div",
288
+ {
289
+ className: ui.cn(
290
+ "grid shrink-0 gap-2",
291
+ narrow ? "w-full grid-cols-3 content-start" : "w-60 grid-cols-1 overflow-y-auto"
292
+ ),
293
+ style: narrow ? { width: box.width } : void 0,
294
+ "data-testid": "call-filmstrip",
295
+ children: others.map((t) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "call-tile-box aspect-video w-full min-w-0", children: renderTile(t, "small") }, getKey(t)))
296
+ }
297
+ )
298
+ ]
299
+ }
300
+ );
301
+ }
302
+ function FoldingLabel({
303
+ sentence,
304
+ short,
305
+ expanded
306
+ }) {
307
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
308
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: ui.cn(!expanded && "sr-only"), children: sentence }),
309
+ !expanded && /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, children: short })
310
+ ] });
311
+ }
312
+ function RecordingStatusChip({
313
+ sentence,
314
+ short = "Recording",
315
+ compact = false,
316
+ announce = true,
317
+ onAnnounced,
318
+ className,
319
+ ...rest
320
+ }) {
321
+ const expanded = useBriefNotice(announce, onAnnounced);
322
+ return /* @__PURE__ */ jsxRuntime.jsx(
323
+ CallStatusChip,
324
+ {
325
+ tone: "red",
326
+ pulse: true,
327
+ role: "status",
328
+ "aria-live": "polite",
329
+ label: /* @__PURE__ */ jsxRuntime.jsx(FoldingLabel, { sentence, short, expanded }),
330
+ compact: compact && !expanded,
331
+ title: sentence,
332
+ className,
333
+ "data-expanded": expanded,
334
+ ...rest
335
+ }
336
+ );
337
+ }
338
+ function TranscriptionStatusChip({
339
+ sentence,
340
+ announce = true,
341
+ onAnnounced,
342
+ short = "Transcribing",
343
+ detail,
344
+ muted,
345
+ onMutedChange,
346
+ muteLabel,
347
+ unmuteLabel,
348
+ compact = false,
349
+ className,
350
+ ...rest
351
+ }) {
352
+ const expanded = useBriefNotice(announce, onAnnounced);
353
+ const label = muted ? unmuteLabel : muteLabel;
354
+ return /* @__PURE__ */ jsxRuntime.jsx(
355
+ CallStatusChip,
356
+ {
357
+ tone: "red",
358
+ role: "status",
359
+ "aria-live": "polite",
360
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Captions, { className: "size-3.5 shrink-0", "aria-hidden": true }),
361
+ label: /* @__PURE__ */ jsxRuntime.jsx(FoldingLabel, { sentence, short, expanded }),
362
+ compact: compact && !expanded,
363
+ title: detail ? `${sentence}. ${detail}` : sentence,
364
+ className: ui.cn("pr-0.5", className),
365
+ "data-expanded": expanded,
366
+ ...rest,
367
+ children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Tooltip, { children: [
368
+ /* @__PURE__ */ jsxRuntime.jsx(ui.TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
369
+ "button",
370
+ {
371
+ type: "button",
372
+ className: "inline-flex h-5! w-5! shrink-0 items-center justify-center rounded-sm p-0! hover:bg-red-text/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
373
+ "aria-pressed": muted,
374
+ "aria-label": label,
375
+ onClick: () => onMutedChange(!muted),
376
+ "data-testid": "transcription-mute",
377
+ children: muted ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MicOff, { className: "size-3.5", "aria-hidden": true }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Mic, { className: "size-3.5", "aria-hidden": true })
378
+ }
379
+ ) }),
380
+ /* @__PURE__ */ jsxRuntime.jsx(ui.TooltipContent, { side: "bottom", children: label })
381
+ ] })
382
+ }
383
+ );
384
+ }
385
+ function EncryptionStatusChip({
386
+ state,
387
+ compact = false,
388
+ labels = {
389
+ on: "Encrypted",
390
+ pending: "Encrypting\u2026",
391
+ off: "Not encrypted",
392
+ onTitle: "Media is end-to-end encrypted; the media server only sees ciphertext.",
393
+ offTitle: "This call is not end-to-end encrypted."
394
+ }
395
+ }) {
396
+ const on = state === "on";
397
+ return /* @__PURE__ */ jsxRuntime.jsx(
398
+ CallStatusChip,
399
+ {
400
+ tone: on ? "neutral" : "yellow",
401
+ icon: on ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Lock, { className: "size-3.5 shrink-0", "aria-hidden": true }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.LockOpen, { className: "size-3.5 shrink-0", "aria-hidden": true }),
402
+ label: on ? labels.on : state === "pending" ? labels.pending : labels.off,
403
+ compact,
404
+ title: on ? labels.onTitle : labels.offTitle,
405
+ "data-testid": "call-encryption-badge",
406
+ "data-state": state
407
+ }
408
+ );
409
+ }
410
+ function CaptionsStrip({
411
+ captions,
412
+ reserve = false,
413
+ waitingText = "Captions appear here as people speak.",
414
+ className
415
+ }) {
416
+ const [now, setNow] = react.useState(() => Date.now());
417
+ const visible = captions.filter((c) => now - c.receivedAt < chunkMWDW5UBW_cjs.CAPTION_TTL_MS).slice(-chunkMWDW5UBW_cjs.CAPTION_LINES);
418
+ const showing = visible.length > 0;
419
+ const newest = captions[captions.length - 1]?.receivedAt;
420
+ react.useEffect(() => {
421
+ setNow(Date.now());
422
+ }, [newest]);
423
+ react.useEffect(() => {
424
+ if (!showing) return;
425
+ const id = setInterval(() => setNow(Date.now()), 1e3);
426
+ return () => clearInterval(id);
427
+ }, [showing]);
428
+ if (!showing && !reserve) return null;
429
+ return /* @__PURE__ */ jsxRuntime.jsx(
430
+ "div",
431
+ {
432
+ className: ui.cn(
433
+ "shrink-0 rounded-md bg-muted px-3 py-2 text-sm leading-5 text-foreground",
434
+ className
435
+ ),
436
+ "aria-live": "polite",
437
+ "data-testid": "captions-overlay",
438
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-10 flex-col justify-end overflow-hidden", children: [
439
+ !showing && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "truncate text-muted-foreground", "data-testid": "captions-waiting", children: waitingText }),
440
+ visible.map((c) => /* @__PURE__ */ jsxRuntime.jsxs(
441
+ "p",
442
+ {
443
+ className: "flex min-w-0 shrink-0 gap-1.5",
444
+ "data-testid": "caption-line",
445
+ "data-speaker": c.speakerId,
446
+ children: [
447
+ /* @__PURE__ */ jsxRuntime.jsx(
448
+ "span",
449
+ {
450
+ className: ui.cn(
451
+ "max-w-[40%] shrink-0 truncate font-semibold",
452
+ chunkMWDW5UBW_cjs.speakerAccent(c.speakerId)
453
+ ),
454
+ children: c.name
455
+ }
456
+ ),
457
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: ": " }),
458
+ /* @__PURE__ */ jsxRuntime.jsx(
459
+ "span",
460
+ {
461
+ className: "flex min-w-0 flex-1 flex-col justify-end overflow-hidden",
462
+ style: { height: `${(visible.length > 1 ? 1 : chunkMWDW5UBW_cjs.CAPTION_LINES) * 1.25}rem` },
463
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "break-words", children: c.text })
464
+ }
465
+ )
466
+ ]
467
+ },
468
+ `${c.speakerId}:${c.id}`
469
+ ))
470
+ ] })
471
+ }
472
+ );
473
+ }
474
+ function CallControlBar({
475
+ left,
476
+ right,
477
+ children,
478
+ shortcuts = false,
479
+ className
480
+ }) {
481
+ const ref = react.useRef(null);
482
+ useShortcutKeys(ref, shortcuts);
483
+ return /* @__PURE__ */ jsxRuntime.jsxs(
484
+ "div",
485
+ {
486
+ ref,
487
+ className: ui.cn(
488
+ "grid h-16 shrink-0 grid-cols-[1fr_auto_1fr] items-center gap-2 border-t border-border bg-background px-3 sm:px-4",
489
+ className
490
+ ),
491
+ "data-testid": "call-controls",
492
+ children: [
493
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-w-0 items-center gap-2", children: left }),
494
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2", children }),
495
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-end gap-2", children: right })
496
+ ]
497
+ }
498
+ );
499
+ }
500
+ function ControlGroup({ children }) {
501
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2", children });
502
+ }
503
+ function ControlDivider() {
504
+ return /* @__PURE__ */ jsxRuntime.jsx(ui.Separator, { orientation: "vertical", className: "mx-1 h-6" });
505
+ }
506
+ function ElapsedTime({ since, title }) {
507
+ const [now, setNow] = react.useState(() => Date.now());
508
+ react.useEffect(() => {
509
+ const id = setInterval(() => setNow(Date.now()), 1e3);
510
+ return () => clearInterval(id);
511
+ }, []);
512
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm tabular-nums text-muted-foreground", title, children: chunkMWDW5UBW_cjs.formatElapsed(now - since) });
513
+ }
514
+ function MediaControl({
515
+ kind,
516
+ enabled,
517
+ pending = false,
518
+ onToggle,
519
+ devices,
520
+ activeDeviceId,
521
+ onSelectDevice,
522
+ shortcut,
523
+ testId,
524
+ options = []
525
+ }) {
526
+ const mic = kind === "microphone";
527
+ const label = enabled ? `Turn off ${kind}` : `Turn on ${kind}`;
528
+ const Icon = mic ? enabled ? lucideReact.Mic : lucideReact.MicOff : enabled ? lucideReact.Video : lucideReact.VideoOff;
529
+ const title = mic ? "Microphone" : "Camera";
530
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 items-center", role: "group", "aria-label": title, children: [
531
+ /* @__PURE__ */ jsxRuntime.jsx(
532
+ CallControlButton,
533
+ {
534
+ label,
535
+ shortcut,
536
+ tone: enabled ? "neutral" : "off",
537
+ "aria-pressed": enabled,
538
+ disabled: pending,
539
+ onClick: onToggle,
540
+ className: "rounded-r-none",
541
+ "data-testid": testId,
542
+ "data-call-shortcut": shortcut?.toLowerCase(),
543
+ "data-enabled": enabled,
544
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { "aria-hidden": true })
545
+ }
546
+ ),
547
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
548
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
549
+ ui.Button,
550
+ {
551
+ type: "button",
552
+ variant: "ghost",
553
+ "aria-label": `Choose ${kind}`,
554
+ title: `Choose ${kind}`,
555
+ className: ui.cn(
556
+ "h-9 w-6 shrink-0 rounded-l-none border-l px-0 pointer-coarse:h-11! pointer-coarse:w-8",
557
+ enabled ? "border-background bg-muted text-muted-foreground hover:bg-accent hover:text-foreground" : "border-background bg-red-bg text-red-text hover:bg-red-bg/80"
558
+ ),
559
+ "data-testid": `${testId}-devices`,
560
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronUp, { className: "size-3.5", "aria-hidden": true })
561
+ }
562
+ ) }),
563
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuContent, { side: "top", align: "start", className: "w-72", children: [
564
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuLabel, { className: "text-xs font-medium text-muted-foreground", children: title }),
565
+ devices.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuItem, { disabled: true, children: [
566
+ "No ",
567
+ kind,
568
+ " found"
569
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuRadioGroup, { value: activeDeviceId, onValueChange: onSelectDevice, children: devices.map((d, i) => /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuRadioItem, { value: d.deviceId, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: d.label || `${title} ${i + 1}` }) }, d.deviceId)) }),
570
+ options.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuSeparator, {}),
571
+ options.map((o) => /* @__PURE__ */ jsxRuntime.jsx(
572
+ ui.DropdownMenuCheckboxItem,
573
+ {
574
+ checked: o.checked,
575
+ onCheckedChange: (c) => o.onChange(c === true),
576
+ "data-testid": o.testId,
577
+ children: o.label
578
+ },
579
+ o.label
580
+ ))
581
+ ] })
582
+ ] })
583
+ ] });
584
+ }
585
+ function RecordControl({
586
+ on,
587
+ busy = false,
588
+ modes,
589
+ note,
590
+ onStart,
591
+ onStop
592
+ }) {
593
+ const [choosing, setChoosing] = react.useState(false);
594
+ const menuRef = react.useRef(null);
595
+ react.useEffect(() => {
596
+ if (!choosing) return;
597
+ const onDown = (e) => {
598
+ if (!menuRef.current?.contains(e.target)) setChoosing(false);
599
+ };
600
+ const onKey = (e) => {
601
+ if (e.key === "Escape") setChoosing(false);
602
+ };
603
+ document.addEventListener("pointerdown", onDown);
604
+ document.addEventListener("keydown", onKey);
605
+ return () => {
606
+ document.removeEventListener("pointerdown", onDown);
607
+ document.removeEventListener("keydown", onKey);
608
+ };
609
+ }, [choosing]);
610
+ const base = "h-9 shrink-0 gap-2 px-3 pointer-coarse:h-11!";
611
+ if (on) {
612
+ return /* @__PURE__ */ jsxRuntime.jsxs(
613
+ ui.Button,
614
+ {
615
+ type: "button",
616
+ variant: "ghost",
617
+ className: ui.cn(base, "bg-red-bg text-red-text hover:bg-red-bg/80"),
618
+ disabled: busy,
619
+ onClick: onStop,
620
+ "data-testid": "recording-stop",
621
+ children: [
622
+ busy ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-4 animate-spin", "aria-hidden": true }) : /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "relative flex size-2.5", "aria-hidden": true, children: [
623
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute inline-flex size-full animate-ping rounded-full bg-red-solid opacity-60 motion-reduce:hidden" }),
624
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "relative inline-flex size-2.5 rounded-full bg-red-solid" })
625
+ ] }),
626
+ "Stop recording"
627
+ ]
628
+ }
629
+ );
630
+ }
631
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: menuRef, className: "relative", children: [
632
+ /* @__PURE__ */ jsxRuntime.jsxs(
633
+ ui.Button,
634
+ {
635
+ type: "button",
636
+ variant: "ghost",
637
+ className: ui.cn(base, "bg-muted text-foreground hover:bg-accent"),
638
+ disabled: busy,
639
+ "aria-expanded": choosing,
640
+ "aria-haspopup": "menu",
641
+ onClick: () => setChoosing((c) => !c),
642
+ "data-testid": "recording-start",
643
+ children: [
644
+ busy ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-4 animate-spin", "aria-hidden": true }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Circle, { className: "size-3 fill-red-solid text-red-solid", "aria-hidden": true }),
645
+ "Record"
646
+ ]
647
+ }
648
+ ),
649
+ choosing && /* @__PURE__ */ jsxRuntime.jsxs(
650
+ "div",
651
+ {
652
+ role: "menu",
653
+ "aria-label": "Record",
654
+ className: "absolute bottom-full left-1/2 z-50 mb-2 w-64 -translate-x-1/2 rounded-md border bg-popover p-1 text-popover-foreground shadow-lg",
655
+ children: [
656
+ note && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "px-2 py-1.5 text-xs text-muted-foreground", children: note }),
657
+ modes.map((m) => /* @__PURE__ */ jsxRuntime.jsxs(
658
+ "button",
659
+ {
660
+ type: "button",
661
+ role: "menuitem",
662
+ className: "flex w-full flex-col items-start rounded-sm px-2 py-1.5 text-left text-sm outline-none hover:bg-accent focus-visible:bg-accent pointer-coarse:min-h-11",
663
+ onClick: () => {
664
+ setChoosing(false);
665
+ onStart(m.mode);
666
+ },
667
+ "data-testid": m.testId,
668
+ children: [
669
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: m.label }),
670
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: m.description })
671
+ ]
672
+ },
673
+ m.mode
674
+ ))
675
+ ]
676
+ }
677
+ )
678
+ ] });
679
+ }
680
+ function LeaveButton({
681
+ onLeave,
682
+ compact = false,
683
+ label = "Leave",
684
+ title = "Leave call"
685
+ }) {
686
+ return /* @__PURE__ */ jsxRuntime.jsxs(
687
+ ui.Button,
688
+ {
689
+ type: "button",
690
+ variant: "destructive",
691
+ size: compact ? "icon" : "default",
692
+ className: ui.cn("shrink-0", !compact && "px-4"),
693
+ "aria-label": title,
694
+ title,
695
+ onClick: onLeave,
696
+ "data-testid": "call-leave",
697
+ children: [
698
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PhoneOff, { className: "size-4", "aria-hidden": true }),
699
+ !compact && label
700
+ ]
701
+ }
702
+ );
703
+ }
704
+ function MoreMenu({
705
+ details,
706
+ groups,
707
+ label = "More options"
708
+ }) {
709
+ const shown = groups.filter((g) => g.length > 0);
710
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
711
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(CallControlButton, { label, tooltip: false, "data-testid": "call-more", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoreHorizontal, { "aria-hidden": true }) }) }),
712
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuContent, { side: "top", align: "end", className: "w-72", "data-testid": "call-more-menu", children: [
713
+ details && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
714
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuLabel, { className: "flex flex-col gap-1 font-normal", children: details }),
715
+ shown.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuSeparator, {})
716
+ ] }),
717
+ shown.map((group, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "none", children: [
718
+ i > 0 && /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuSeparator, {}),
719
+ group.map((item) => /* @__PURE__ */ jsxRuntime.jsxs(
720
+ ui.DropdownMenuItem,
721
+ {
722
+ onSelect: item.onSelect,
723
+ disabled: item.disabled,
724
+ "data-testid": item.testId,
725
+ children: [
726
+ item.icon,
727
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate", children: item.label }),
728
+ item.trailing
729
+ ]
730
+ },
731
+ item.key
732
+ ))
733
+ ] }, group[0].key))
734
+ ] })
735
+ ] });
736
+ }
737
+ function HeaderIconButton({
738
+ label,
739
+ onClick,
740
+ children,
741
+ testId,
742
+ pressed
743
+ }) {
744
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.Tooltip, { children: [
745
+ /* @__PURE__ */ jsxRuntime.jsx(ui.TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
746
+ ui.Button,
747
+ {
748
+ type: "button",
749
+ variant: "ghost",
750
+ size: "icon",
751
+ className: "text-muted-foreground hover:text-foreground",
752
+ "aria-label": label,
753
+ "aria-pressed": pressed,
754
+ onClick,
755
+ "data-testid": testId,
756
+ children
757
+ }
758
+ ) }),
759
+ /* @__PURE__ */ jsxRuntime.jsx(ui.TooltipContent, { side: "bottom", children: label })
760
+ ] });
761
+ }
762
+ function CallHeader({
763
+ title,
764
+ icon,
765
+ status,
766
+ view,
767
+ onViewChange,
768
+ onMinimise,
769
+ minimiseLabel = "Minimise \u2014 keep working while the call goes on"
770
+ }) {
771
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "@container", children: /* @__PURE__ */ jsxRuntime.jsx(
772
+ chunk7RGLTF76_cjs.TabHeader,
773
+ {
774
+ tabs: [
775
+ {
776
+ id: "call",
777
+ label: /* @__PURE__ */ jsxRuntime.jsxs(ui.Tooltip, { children: [
778
+ /* @__PURE__ */ jsxRuntime.jsx(ui.TooltipTrigger, { asChild: true, showWithText: true, children: /* @__PURE__ */ jsxRuntime.jsx(
779
+ "span",
780
+ {
781
+ className: "block min-w-0 max-w-[calc(100cqw-16rem)] truncate",
782
+ "data-testid": "call-title",
783
+ children: title
784
+ }
785
+ ) }),
786
+ /* @__PURE__ */ jsxRuntime.jsx(ui.TooltipContent, { side: "bottom", children: title })
787
+ ] }),
788
+ icon: icon ?? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Phone, { className: "size-4" })
789
+ }
790
+ ],
791
+ activeTabId: "call",
792
+ onTabChange: () => void 0,
793
+ testId: "call-header",
794
+ className: "pb-0",
795
+ rightContent: (compact) => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
796
+ typeof status === "function" ? status(compact) : status,
797
+ view && onViewChange && /* @__PURE__ */ jsxRuntime.jsx(
798
+ HeaderIconButton,
799
+ {
800
+ label: view === "speaker" ? "Gallery view (everyone equal)" : "Speaker view (who talks, large)",
801
+ onClick: () => onViewChange(view === "speaker" ? "gallery" : "speaker"),
802
+ testId: "call-view-toggle",
803
+ children: view === "speaker" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.LayoutGrid, { className: "size-4" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.UserRound, { className: "size-4" })
804
+ }
805
+ ),
806
+ onMinimise && /* @__PURE__ */ jsxRuntime.jsx(
807
+ HeaderIconButton,
808
+ {
809
+ label: minimiseLabel,
810
+ onClick: onMinimise,
811
+ testId: "call-dock-toggle",
812
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PictureInPicture2, { className: "size-4" })
813
+ }
814
+ )
815
+ ] })
816
+ }
817
+ ) });
818
+ }
819
+ function SpeakingNow({
820
+ names,
821
+ idleText = "No one is speaking",
822
+ className
823
+ }) {
824
+ const talking = names.length > 0;
825
+ return /* @__PURE__ */ jsxRuntime.jsxs(
826
+ "p",
827
+ {
828
+ className: ui.cn(
829
+ "flex min-w-0 items-center gap-1.5 text-sm",
830
+ talking ? "text-foreground" : "text-muted-foreground",
831
+ className
832
+ ),
833
+ "aria-live": "polite",
834
+ "data-testid": "call-speaking-now",
835
+ children: [
836
+ /* @__PURE__ */ jsxRuntime.jsx(
837
+ lucideReact.AudioLines,
838
+ {
839
+ className: ui.cn(
840
+ "size-4 shrink-0",
841
+ talking ? "text-theme-cyan motion-safe:animate-pulse" : "text-muted-foreground"
842
+ ),
843
+ "aria-hidden": true
844
+ }
845
+ ),
846
+ talking ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 items-center gap-1 overflow-hidden", children: [
847
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-muted-foreground", children: "Speaking:" }),
848
+ names.map((n, i) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex min-w-0 shrink-0 items-center", children: n }, i))
849
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 truncate", children: idleText })
850
+ ]
851
+ }
852
+ );
853
+ }
854
+ function CallNotice({ children }) {
855
+ return /* @__PURE__ */ jsxRuntime.jsxs(
856
+ "p",
857
+ {
858
+ className: "flex min-w-0 items-center gap-1.5 text-sm text-red-text motion-safe:animate-in motion-safe:fade-in-0",
859
+ role: "status",
860
+ "aria-live": "polite",
861
+ "data-testid": "call-notice",
862
+ children: [
863
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "size-2 shrink-0 rounded-full bg-red-solid", "aria-hidden": true }),
864
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 truncate", children })
865
+ ]
866
+ }
867
+ );
868
+ }
869
+ function CallStageFrame({
870
+ header,
871
+ subheader,
872
+ stage,
873
+ stageRef,
874
+ stageOverlay,
875
+ people,
876
+ stageHeight,
877
+ controls,
878
+ className
879
+ }) {
880
+ const [bodyRef, body] = useElementSize();
881
+ const PAD_X = 24;
882
+ const PAD_B = 12;
883
+ const sized = !!people && !!stageHeight && body.width > 0 && body.height > 0 ? Math.ceil(stageHeight(body.width - PAD_X, Math.round(body.height * 0.62)) + PAD_B) : null;
884
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cn("flex size-full min-h-0 flex-col bg-background text-foreground", className), children: [
885
+ header,
886
+ subheader && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-h-9 shrink-0 flex-col justify-center gap-0.5 px-3 py-1", children: subheader }),
887
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: bodyRef, className: "relative flex min-h-0 flex-1 flex-col", children: [
888
+ /* @__PURE__ */ jsxRuntime.jsx(
889
+ "div",
890
+ {
891
+ className: ui.cn("flex min-h-0 flex-col px-3 pb-3", sized == null ? "flex-1" : "shrink-0"),
892
+ style: sized == null ? void 0 : { height: sized },
893
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: stageRef, className: "relative min-h-0 flex-1", "data-testid": "call-stage", children: [
894
+ stage,
895
+ stageOverlay
896
+ ] })
897
+ }
898
+ ),
899
+ people
900
+ ] }),
901
+ controls
902
+ ] });
903
+ }
904
+ function CallSidePanel({
905
+ title,
906
+ icon,
907
+ actions,
908
+ onClose,
909
+ closeLabel,
910
+ closeTestId,
911
+ children,
912
+ className,
913
+ ...rest
914
+ }) {
915
+ return /* @__PURE__ */ jsxRuntime.jsxs(
916
+ "aside",
917
+ {
918
+ className: ui.cn("flex min-h-0 flex-col bg-background text-foreground", className),
919
+ "aria-label": title,
920
+ ...rest,
921
+ children: [
922
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-12 shrink-0 items-center gap-2 border-b border-border pl-3 pr-1.5", children: [
923
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-1 items-center gap-2 text-base font-semibold text-primary", children: [
924
+ icon,
925
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: title })
926
+ ] }),
927
+ actions,
928
+ /* @__PURE__ */ jsxRuntime.jsx(
929
+ ui.Button,
930
+ {
931
+ type: "button",
932
+ variant: "ghost",
933
+ size: "icon",
934
+ className: "size-8 text-muted-foreground hover:text-foreground",
935
+ "aria-label": closeLabel,
936
+ title: closeLabel,
937
+ onClick: onClose,
938
+ "data-testid": closeTestId,
939
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "size-4" })
940
+ }
941
+ )
942
+ ] }),
943
+ children
944
+ ]
945
+ }
946
+ );
947
+ }
948
+ function VoiceMeter({
949
+ level,
950
+ muted = false,
951
+ className
952
+ }) {
953
+ if (muted) {
954
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: ui.cn("flex items-center text-red-text", className), title: "Microphone off", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MicOff, { className: "size-4", "aria-label": "Microphone off" }) });
955
+ }
956
+ const lit = Math.round(Math.min(1, Math.max(0, level)) * 5);
957
+ return /* @__PURE__ */ jsxRuntime.jsx(
958
+ "span",
959
+ {
960
+ className: ui.cn("flex h-4 items-end gap-0.5", className),
961
+ role: "meter",
962
+ "aria-label": "Voice level",
963
+ "aria-valuemin": 0,
964
+ "aria-valuemax": 5,
965
+ "aria-valuenow": lit,
966
+ children: [0.35, 0.55, 0.75, 0.9, 1].map((h, i) => /* @__PURE__ */ jsxRuntime.jsx(
967
+ "span",
968
+ {
969
+ className: ui.cn("w-1 rounded-sm", i < lit ? "bg-theme-cyan" : "bg-muted-foreground/30"),
970
+ style: { height: `${h * 100}%` }
971
+ },
972
+ i
973
+ ))
974
+ }
975
+ );
976
+ }
977
+ function PersonRow({
978
+ p,
979
+ canRemove,
980
+ removingId,
981
+ onRemove,
982
+ onAskToMute,
983
+ onMute
984
+ }) {
985
+ const hasActions = !p.isLocal && (canRemove || (onAskToMute || onMute) && !p.micMuted || onMute && p.cameraOn);
986
+ return /* @__PURE__ */ jsxRuntime.jsxs(
987
+ "li",
988
+ {
989
+ className: "flex h-10 items-center gap-2 rounded-md px-2 hover:bg-muted",
990
+ "data-testid": `call-person-${p.id}`,
991
+ "data-speaking": p.speaking || void 0,
992
+ children: [
993
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-1 items-center gap-1.5 text-sm", children: [
994
+ p.entity ? (
995
+ // The ring hugs the person's pill, not the whole row.
996
+ /* @__PURE__ */ jsxRuntime.jsx(
997
+ "span",
998
+ {
999
+ className: ui.cn(
1000
+ "inline-flex min-w-0 rounded-full",
1001
+ p.speaking && "ring-2 ring-theme-cyan ring-offset-2 ring-offset-background"
1002
+ ),
1003
+ children: p.entity
1004
+ }
1005
+ )
1006
+ ) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1007
+ /* @__PURE__ */ jsxRuntime.jsx(
1008
+ "span",
1009
+ {
1010
+ className: "flex size-7 shrink-0 items-center justify-center rounded-full bg-primary/10 text-xs font-semibold text-primary",
1011
+ "aria-hidden": true,
1012
+ children: chunkMWDW5UBW_cjs.initialsOf(p.name)
1013
+ }
1014
+ ),
1015
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "min-w-0 truncate", children: [
1016
+ p.name,
1017
+ p.isLocal && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: " (me)" })
1018
+ ] })
1019
+ ] }),
1020
+ p.speaking && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: " \u2014 speaking" }),
1021
+ p.note && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: p.note })
1022
+ ] }),
1023
+ /* @__PURE__ */ jsxRuntime.jsx(VoiceMeter, { level: p.level ?? 0, muted: p.micMuted }),
1024
+ /* @__PURE__ */ jsxRuntime.jsx(
1025
+ "span",
1026
+ {
1027
+ className: ui.cn(
1028
+ "flex w-4 justify-center",
1029
+ p.cameraOn ? "text-muted-foreground" : "text-red-text"
1030
+ ),
1031
+ title: p.cameraOn ? "Camera on" : "Camera off",
1032
+ children: p.cameraOn ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Video, { className: "size-4", "aria-label": "Camera on" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.VideoOff, { className: "size-4", "aria-label": "Camera off" })
1033
+ }
1034
+ ),
1035
+ hasActions ? /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
1036
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
1037
+ ui.Button,
1038
+ {
1039
+ type: "button",
1040
+ variant: "ghost",
1041
+ size: "icon",
1042
+ className: "size-8 text-muted-foreground hover:text-foreground",
1043
+ "aria-label": `Actions for ${p.name}`,
1044
+ "data-testid": `call-person-menu-${p.id}`,
1045
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoreHorizontal, { className: "size-4" })
1046
+ }
1047
+ ) }),
1048
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuContent, { align: "end", className: "w-56", children: [
1049
+ onAskToMute && !p.micMuted && /* @__PURE__ */ jsxRuntime.jsxs(
1050
+ ui.DropdownMenuItem,
1051
+ {
1052
+ onSelect: () => onAskToMute(p),
1053
+ "data-testid": `call-ask-mute-${p.id}`,
1054
+ children: [
1055
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MicOff, { "aria-hidden": true }),
1056
+ "Ask to mute"
1057
+ ]
1058
+ }
1059
+ ),
1060
+ onMute && !p.micMuted && /* @__PURE__ */ jsxRuntime.jsxs(
1061
+ ui.DropdownMenuItem,
1062
+ {
1063
+ onSelect: () => onMute(p, "audio"),
1064
+ "data-testid": `call-mute-${p.id}`,
1065
+ children: [
1066
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MicOff, { "aria-hidden": true }),
1067
+ "Mute"
1068
+ ]
1069
+ }
1070
+ ),
1071
+ onMute && p.cameraOn && /* @__PURE__ */ jsxRuntime.jsxs(
1072
+ ui.DropdownMenuItem,
1073
+ {
1074
+ onSelect: () => onMute(p, "video"),
1075
+ "data-testid": `call-camera-off-${p.id}`,
1076
+ children: [
1077
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.VideoOff, { "aria-hidden": true }),
1078
+ "Turn off camera"
1079
+ ]
1080
+ }
1081
+ ),
1082
+ canRemove && /* @__PURE__ */ jsxRuntime.jsxs(
1083
+ ui.DropdownMenuItem,
1084
+ {
1085
+ onSelect: () => onRemove(p),
1086
+ disabled: removingId === p.id,
1087
+ className: "text-destructive focus:text-destructive",
1088
+ "data-testid": `call-remove-${p.id}`,
1089
+ children: [
1090
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.UserX, { "aria-hidden": true }),
1091
+ "Remove from call"
1092
+ ]
1093
+ }
1094
+ )
1095
+ ] })
1096
+ ] }) : (
1097
+ // Keeps every row's meter and icons in the same column.
1098
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "size-8 shrink-0", "aria-hidden": true })
1099
+ )
1100
+ ]
1101
+ }
1102
+ );
1103
+ }
1104
+ function CallParticipants({
1105
+ people,
1106
+ canRemove,
1107
+ removingId,
1108
+ onRemove,
1109
+ onAskToMute,
1110
+ onMute,
1111
+ compact = false,
1112
+ className
1113
+ }) {
1114
+ const [expanded, setExpanded] = react.useState(false);
1115
+ const rows = /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "min-h-0 flex-1 overflow-y-auto px-1 pb-2", "data-testid": "call-people-list", children: people.map((p) => /* @__PURE__ */ jsxRuntime.jsx(
1116
+ PersonRow,
1117
+ {
1118
+ p,
1119
+ canRemove,
1120
+ removingId,
1121
+ onRemove,
1122
+ onAskToMute,
1123
+ onMute
1124
+ },
1125
+ p.id
1126
+ )) });
1127
+ const heading = /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs font-medium uppercase tracking-wide text-muted-foreground", children: [
1128
+ "People (",
1129
+ people.length,
1130
+ ")"
1131
+ ] });
1132
+ if (compact && !expanded) {
1133
+ const talking = people.filter((p) => p.speaking);
1134
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1135
+ "section",
1136
+ {
1137
+ className: ui.cn(
1138
+ "flex h-11 shrink-0 items-center gap-2 border-t border-border px-3",
1139
+ className
1140
+ ),
1141
+ "aria-label": "People",
1142
+ "data-testid": "call-people",
1143
+ "data-compact": "",
1144
+ children: [
1145
+ heading,
1146
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex min-w-0 flex-1 items-center gap-1 overflow-hidden", children: talking.map((p) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex shrink-0 items-center", children: p.entity ?? p.name }, p.id)) }),
1147
+ /* @__PURE__ */ jsxRuntime.jsxs(
1148
+ ui.Button,
1149
+ {
1150
+ type: "button",
1151
+ variant: "ghost",
1152
+ size: "sm",
1153
+ className: "h-8 shrink-0",
1154
+ "aria-expanded": false,
1155
+ onClick: () => setExpanded(true),
1156
+ "data-testid": "call-people-show-all",
1157
+ children: [
1158
+ "Show all (",
1159
+ people.length,
1160
+ ")"
1161
+ ]
1162
+ }
1163
+ )
1164
+ ]
1165
+ }
1166
+ );
1167
+ }
1168
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1169
+ "section",
1170
+ {
1171
+ className: ui.cn(
1172
+ "flex min-h-0 flex-col border-t border-border",
1173
+ compact && "absolute inset-x-0 bottom-0 z-20 max-h-[80%] bg-background shadow-lg",
1174
+ className
1175
+ ),
1176
+ "aria-label": "People",
1177
+ "data-testid": "call-people",
1178
+ children: [
1179
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-9 shrink-0 items-center justify-between px-3", children: [
1180
+ heading,
1181
+ compact && /* @__PURE__ */ jsxRuntime.jsx(
1182
+ ui.Button,
1183
+ {
1184
+ type: "button",
1185
+ variant: "ghost",
1186
+ size: "sm",
1187
+ className: "h-7",
1188
+ "aria-expanded": true,
1189
+ onClick: () => setExpanded(false),
1190
+ "data-testid": "call-people-show-less",
1191
+ children: "Show less"
1192
+ }
1193
+ )
1194
+ ] }),
1195
+ rows
1196
+ ]
1197
+ }
1198
+ );
1199
+ }
1200
+ function LobbyRequests({
1201
+ requests,
1202
+ onDecide
1203
+ }) {
1204
+ if (!requests.length) return null;
1205
+ return /* @__PURE__ */ jsxRuntime.jsx(
1206
+ "div",
1207
+ {
1208
+ className: "absolute left-3 top-3 z-10 flex w-72 max-w-[calc(100%-1.5rem)] flex-col gap-2",
1209
+ role: "region",
1210
+ "aria-label": "Lobby",
1211
+ "data-testid": "call-lobby",
1212
+ children: requests.map((k) => /* @__PURE__ */ jsxRuntime.jsxs(
1213
+ "div",
1214
+ {
1215
+ className: "flex items-center gap-3 rounded-md border border-border bg-popover p-3 text-sm text-popover-foreground shadow-lg",
1216
+ "data-testid": "call-lobby-knock",
1217
+ children: [
1218
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-1 flex-wrap items-center gap-1", children: [
1219
+ k.entity ?? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: k.name }),
1220
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "wants to join." })
1221
+ ] }),
1222
+ /* @__PURE__ */ jsxRuntime.jsx(
1223
+ ui.Button,
1224
+ {
1225
+ type: "button",
1226
+ variant: "ghost",
1227
+ size: "sm",
1228
+ className: "h-8",
1229
+ onClick: () => onDecide(k.id, false),
1230
+ "data-testid": "call-lobby-deny",
1231
+ children: "Deny"
1232
+ }
1233
+ ),
1234
+ /* @__PURE__ */ jsxRuntime.jsx(
1235
+ ui.Button,
1236
+ {
1237
+ type: "button",
1238
+ size: "sm",
1239
+ className: "h-8",
1240
+ onClick: () => onDecide(k.id, true),
1241
+ "data-testid": "call-lobby-admit",
1242
+ children: "Admit"
1243
+ }
1244
+ )
1245
+ ]
1246
+ },
1247
+ k.id
1248
+ ))
1249
+ }
1250
+ );
1251
+ }
1252
+ function MinimisedCall({
1253
+ title,
1254
+ video,
1255
+ status,
1256
+ speaking,
1257
+ micEnabled,
1258
+ onToggleMic,
1259
+ cameraEnabled,
1260
+ onToggleCamera,
1261
+ onRestore,
1262
+ onLeave,
1263
+ restoreLabel = "Back to the call",
1264
+ shortcuts = true,
1265
+ className
1266
+ }) {
1267
+ const ref = react.useRef(null);
1268
+ useShortcutKeys(ref, shortcuts);
1269
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: ui.cn("flex flex-col", className), "data-testid": "call-minimised", children: [
1270
+ /* @__PURE__ */ jsxRuntime.jsx(
1271
+ "button",
1272
+ {
1273
+ type: "button",
1274
+ className: "group relative aspect-video w-full overflow-hidden rounded-t-md bg-hero focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring",
1275
+ onClick: onRestore,
1276
+ "aria-label": restoreLabel,
1277
+ "data-testid": "call-minimised-restore",
1278
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "call-tile-box absolute inset-0", children: video ?? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "call-tile", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "call-tile-placeholder", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "call-tile-avatar call-tile-avatar-sm", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Phone, { className: "size-4", "aria-hidden": true }) }) }) }) })
1279
+ }
1280
+ ),
1281
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2 px-3 py-2", children: [
1282
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [
1283
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate text-sm font-medium", title, children: title }),
1284
+ status && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex shrink-0 items-center gap-1", children: status })
1285
+ ] }),
1286
+ speaking,
1287
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
1288
+ onToggleMic && micEnabled !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(
1289
+ CallControlButton,
1290
+ {
1291
+ label: micEnabled ? "Turn off microphone" : "Turn on microphone",
1292
+ shortcut: "M",
1293
+ tone: micEnabled ? "neutral" : "off",
1294
+ "aria-pressed": micEnabled,
1295
+ onClick: onToggleMic,
1296
+ className: "size-8",
1297
+ "data-testid": "call-minimised-mic",
1298
+ "data-call-shortcut": "m",
1299
+ children: micEnabled ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Mic, { "aria-hidden": true }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MicOff, { "aria-hidden": true })
1300
+ }
1301
+ ),
1302
+ onToggleCamera && cameraEnabled !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(
1303
+ CallControlButton,
1304
+ {
1305
+ label: cameraEnabled ? "Turn off camera" : "Turn on camera",
1306
+ shortcut: "V",
1307
+ tone: cameraEnabled ? "neutral" : "off",
1308
+ "aria-pressed": cameraEnabled,
1309
+ onClick: onToggleCamera,
1310
+ className: "size-8",
1311
+ "data-testid": "call-minimised-camera",
1312
+ "data-call-shortcut": "v",
1313
+ children: cameraEnabled ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Video, { "aria-hidden": true }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.VideoOff, { "aria-hidden": true })
1314
+ }
1315
+ ),
1316
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1" }),
1317
+ /* @__PURE__ */ jsxRuntime.jsx(
1318
+ CallControlButton,
1319
+ {
1320
+ label: restoreLabel,
1321
+ onClick: onRestore,
1322
+ className: "size-8",
1323
+ "data-testid": "call-dock-expand",
1324
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Maximize2, { "aria-hidden": true })
1325
+ }
1326
+ ),
1327
+ /* @__PURE__ */ jsxRuntime.jsx(
1328
+ CallControlButton,
1329
+ {
1330
+ label: "Leave call",
1331
+ tone: "danger",
1332
+ onClick: onLeave,
1333
+ className: "size-8",
1334
+ "data-testid": "call-dock-leave",
1335
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PhoneOff, { "aria-hidden": true })
1336
+ }
1337
+ )
1338
+ ] })
1339
+ ] })
1340
+ ] });
1341
+ }
1342
+ function IncomingCallCard({
1343
+ callerName,
1344
+ caller,
1345
+ context,
1346
+ busy = false,
1347
+ muted,
1348
+ onMutedChange,
1349
+ onAccept,
1350
+ onDecline,
1351
+ className
1352
+ }) {
1353
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1354
+ "div",
1355
+ {
1356
+ role: "alertdialog",
1357
+ "aria-labelledby": "incoming-call-title",
1358
+ "aria-describedby": "incoming-call-desc",
1359
+ "data-testid": "incoming-call-dialog",
1360
+ className: ui.cn(
1361
+ "w-80 max-w-[calc(100vw-2rem)] rounded-md border border-border bg-popover p-4 text-popover-foreground shadow-xl motion-safe:animate-in motion-safe:fade-in-0 motion-safe:slide-in-from-top-2",
1362
+ className
1363
+ ),
1364
+ children: [
1365
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3", children: [
1366
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "relative flex size-10 shrink-0", "aria-hidden": true, children: [
1367
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute inset-0 rounded-full bg-primary/20 motion-safe:animate-ping" }),
1368
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "relative flex size-10 items-center justify-center rounded-full bg-primary/10 text-primary", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Phone, { className: "size-5" }) })
1369
+ ] }),
1370
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1 pt-0.5", children: [
1371
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { id: "incoming-call-title", className: "flex min-w-0 text-sm font-semibold", children: [
1372
+ caller ?? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: callerName }),
1373
+ caller && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: callerName })
1374
+ ] }),
1375
+ /* @__PURE__ */ jsxRuntime.jsx("p", { id: "incoming-call-desc", className: "text-xs text-muted-foreground", children: context })
1376
+ ] }),
1377
+ /* @__PURE__ */ jsxRuntime.jsx(
1378
+ ui.Button,
1379
+ {
1380
+ type: "button",
1381
+ variant: "ghost",
1382
+ size: "icon",
1383
+ className: "-mr-1 -mt-1 size-8 shrink-0 text-muted-foreground hover:text-foreground",
1384
+ "aria-pressed": muted,
1385
+ "aria-label": muted ? "Unmute ringtone" : "Mute ringtone",
1386
+ title: muted ? "Unmute ringtone" : "Mute ringtone",
1387
+ onClick: () => onMutedChange(!muted),
1388
+ "data-testid": "incoming-call-mute",
1389
+ children: muted ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.BellOff, { className: "size-4" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Bell, { className: "size-4" })
1390
+ }
1391
+ )
1392
+ ] }),
1393
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4 grid grid-cols-2 gap-2", children: [
1394
+ /* @__PURE__ */ jsxRuntime.jsxs(
1395
+ ui.Button,
1396
+ {
1397
+ type: "button",
1398
+ variant: "destructive",
1399
+ onClick: onDecline,
1400
+ disabled: busy,
1401
+ "data-testid": "incoming-call-decline",
1402
+ children: [
1403
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PhoneOff, { className: "size-4", "aria-hidden": true }),
1404
+ "Decline"
1405
+ ]
1406
+ }
1407
+ ),
1408
+ /* @__PURE__ */ jsxRuntime.jsxs(
1409
+ ui.Button,
1410
+ {
1411
+ type: "button",
1412
+ onClick: onAccept,
1413
+ disabled: busy,
1414
+ "data-testid": "incoming-call-accept",
1415
+ autoFocus: true,
1416
+ children: [
1417
+ busy ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-4 animate-spin", "aria-hidden": true }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Phone, { className: "size-4", "aria-hidden": true }),
1418
+ "Accept"
1419
+ ]
1420
+ }
1421
+ )
1422
+ ] })
1423
+ ]
1424
+ }
1425
+ );
1426
+ }
1427
+ function CallStateMessage({
1428
+ title,
1429
+ description,
1430
+ spinner = true,
1431
+ action,
1432
+ testId
1433
+ }) {
1434
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1435
+ "div",
1436
+ {
1437
+ className: "flex size-full flex-col items-center justify-center gap-3 p-6 text-center",
1438
+ "data-testid": testId,
1439
+ children: [
1440
+ spinner && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-6 animate-spin text-muted-foreground", "aria-hidden": true }),
1441
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-base font-semibold", children: title }),
1442
+ description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "max-w-sm text-sm text-muted-foreground", children: description }),
1443
+ action
1444
+ ]
1445
+ }
1446
+ );
1447
+ }
1448
+ function ConnectionOverlay({ label }) {
1449
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute inset-0 z-10 flex items-center justify-center rounded-md bg-background/70 text-sm text-muted-foreground", children: [
1450
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "mr-2 size-4 animate-spin", "aria-hidden": true }),
1451
+ label
1452
+ ] });
1453
+ }
1454
+
1455
+ // src/calls/join-choices.ts
1456
+ var DEFAULT_JOIN_CHOICES = { audioEnabled: true, videoEnabled: false };
1457
+ function describeMediaError(err, kind) {
1458
+ const Kind = kind === "camera" ? "Camera" : "Microphone";
1459
+ const name = err?.name;
1460
+ if (name === "NotAllowedError" || name === "SecurityError")
1461
+ return `${Kind} access is blocked. Allow it in the browser's site settings and try again.`;
1462
+ if (name === "NotFoundError" || name === "OverconstrainedError") return `No ${kind} was found.`;
1463
+ if (name === "NotReadableError") return `${Kind} is in use by another app.`;
1464
+ return `${Kind} could not start${err?.message ? `: ${err.message}` : "."}`;
1465
+ }
1466
+ function useDevices(kind, refreshKey) {
1467
+ const [devices, setDevices] = react.useState([]);
1468
+ react.useEffect(() => {
1469
+ const md = navigator.mediaDevices;
1470
+ if (!md?.enumerateDevices) return;
1471
+ let cancelled = false;
1472
+ const load = () => md.enumerateDevices().then((all) => {
1473
+ if (!cancelled) setDevices(all.filter((d) => d.kind === kind && d.deviceId));
1474
+ }).catch(() => {
1475
+ });
1476
+ void load();
1477
+ md.addEventListener?.("devicechange", load);
1478
+ return () => {
1479
+ cancelled = true;
1480
+ md.removeEventListener?.("devicechange", load);
1481
+ };
1482
+ }, [kind, refreshKey]);
1483
+ return devices;
1484
+ }
1485
+ function usePreviewStream(kind, enabled, deviceId, describe) {
1486
+ const [stream, setStream] = react.useState(null);
1487
+ const [error, setError] = react.useState(null);
1488
+ const describeRef = react.useRef(describe);
1489
+ describeRef.current = describe;
1490
+ react.useEffect(() => {
1491
+ if (!enabled) {
1492
+ setStream(null);
1493
+ return;
1494
+ }
1495
+ const md = navigator.mediaDevices;
1496
+ if (!md?.getUserMedia) {
1497
+ setError(
1498
+ window.isSecureContext ? "This browser cannot access the camera or microphone." : "Camera and microphone need HTTPS (or localhost)."
1499
+ );
1500
+ return;
1501
+ }
1502
+ let cancelled = false;
1503
+ let opened = null;
1504
+ const constraint = deviceId ? { deviceId: { exact: deviceId } } : true;
1505
+ md.getUserMedia(kind === "videoinput" ? { video: constraint } : { audio: constraint }).then((s) => {
1506
+ opened = s;
1507
+ if (cancelled) s.getTracks().forEach((t) => t.stop());
1508
+ else {
1509
+ setError(null);
1510
+ setStream(s);
1511
+ }
1512
+ }).catch((err) => {
1513
+ if (!cancelled)
1514
+ setError(describeRef.current(err, kind === "videoinput" ? "camera" : "microphone"));
1515
+ });
1516
+ return () => {
1517
+ cancelled = true;
1518
+ opened?.getTracks().forEach((t) => t.stop());
1519
+ setStream(null);
1520
+ };
1521
+ }, [kind, enabled, deviceId]);
1522
+ return { stream, error };
1523
+ }
1524
+ function useAudioLevel(stream) {
1525
+ const [level, setLevel] = react.useState(0);
1526
+ react.useEffect(() => {
1527
+ if (!stream || typeof AudioContext === "undefined") {
1528
+ setLevel(0);
1529
+ return;
1530
+ }
1531
+ let ctx;
1532
+ try {
1533
+ ctx = new AudioContext();
1534
+ } catch {
1535
+ return;
1536
+ }
1537
+ const analyser = ctx.createAnalyser();
1538
+ analyser.fftSize = 512;
1539
+ ctx.createMediaStreamSource(stream).connect(analyser);
1540
+ const buf = new Uint8Array(analyser.fftSize);
1541
+ let frame = 0;
1542
+ const tick = () => {
1543
+ analyser.getByteTimeDomainData(buf);
1544
+ let peak = 0;
1545
+ for (const v of buf) peak = Math.max(peak, Math.abs(v - 128));
1546
+ setLevel(Math.min(1, peak / 64));
1547
+ frame = requestAnimationFrame(tick);
1548
+ };
1549
+ void ctx.resume().catch(() => {
1550
+ });
1551
+ tick();
1552
+ return () => {
1553
+ cancelAnimationFrame(frame);
1554
+ void ctx.close().catch(() => {
1555
+ });
1556
+ };
1557
+ }, [stream]);
1558
+ return level;
1559
+ }
1560
+ function DeviceSelect({
1561
+ devices,
1562
+ value,
1563
+ onChange,
1564
+ label,
1565
+ icon,
1566
+ disabled,
1567
+ testId
1568
+ }) {
1569
+ const current = value ?? devices[0]?.deviceId;
1570
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-col gap-1.5", children: [
1571
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1.5 text-xs font-medium text-muted-foreground [&_svg]:size-3.5", children: [
1572
+ icon,
1573
+ label
1574
+ ] }),
1575
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Select, { value: current, onValueChange: onChange, disabled: disabled || devices.length < 2, children: [
1576
+ /* @__PURE__ */ jsxRuntime.jsx(ui.SelectTrigger, { "aria-label": label, className: "h-9 min-w-0 text-sm", "data-testid": testId, children: /* @__PURE__ */ jsxRuntime.jsx(ui.SelectValue, { placeholder: `Default ${label.toLowerCase()}` }) }),
1577
+ /* @__PURE__ */ jsxRuntime.jsx(ui.SelectContent, { children: devices.map((d, i) => /* @__PURE__ */ jsxRuntime.jsx(ui.SelectItem, { value: d.deviceId, children: d.label || `${label} ${i + 1}` }, d.deviceId)) })
1578
+ ] })
1579
+ ] });
1580
+ }
1581
+ function PreJoin({
1582
+ title,
1583
+ heading = "Ready to join?",
1584
+ children,
1585
+ joinLabel = "Join",
1586
+ busy = false,
1587
+ error,
1588
+ onJoin,
1589
+ onCancel,
1590
+ describeError = describeMediaError,
1591
+ mirror = true,
1592
+ className
1593
+ }) {
1594
+ const [choices, setChoices] = react.useState(DEFAULT_JOIN_CHOICES);
1595
+ const video = usePreviewStream(
1596
+ "videoinput",
1597
+ choices.videoEnabled,
1598
+ choices.videoDeviceId,
1599
+ describeError
1600
+ );
1601
+ const audio = usePreviewStream(
1602
+ "audioinput",
1603
+ choices.audioEnabled,
1604
+ choices.audioDeviceId,
1605
+ describeError
1606
+ );
1607
+ const level = useAudioLevel(audio.stream);
1608
+ const cameras = useDevices("videoinput", video.stream);
1609
+ const mics = useDevices("audioinput", audio.stream);
1610
+ const videoRef = react.useRef(null);
1611
+ react.useEffect(() => {
1612
+ if (videoRef.current) videoRef.current.srcObject = video.stream;
1613
+ }, [video.stream]);
1614
+ const set = (patch) => setChoices((c) => ({ ...c, ...patch }));
1615
+ const deviceError = video.error ?? audio.error;
1616
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: ui.cn("@container flex w-full", className), "data-testid": "call-prejoin", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mx-auto grid w-full max-w-4xl items-center gap-6 @2xl:grid-cols-[3fr_2fr] @2xl:gap-8", children: [
1617
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [
1618
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative aspect-video w-full overflow-hidden rounded-md bg-hero", children: choices.videoEnabled && video.stream ? /* @__PURE__ */ jsxRuntime.jsx(
1619
+ "video",
1620
+ {
1621
+ ref: videoRef,
1622
+ autoPlay: true,
1623
+ muted: true,
1624
+ playsInline: true,
1625
+ className: ui.cn("size-full object-cover", mirror && "-scale-x-100"),
1626
+ "data-testid": "call-prejoin-video"
1627
+ }
1628
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex size-full items-center justify-center text-sm text-white/80", children: choices.videoEnabled ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-5 animate-spin", "aria-label": "Starting camera" }) : "Camera is off" }) }),
1629
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center gap-3", children: [
1630
+ /* @__PURE__ */ jsxRuntime.jsx(
1631
+ CallControlButton,
1632
+ {
1633
+ label: choices.audioEnabled ? "Turn off microphone" : "Turn on microphone",
1634
+ tone: choices.audioEnabled ? "neutral" : "off",
1635
+ "aria-pressed": choices.audioEnabled,
1636
+ onClick: () => set({ audioEnabled: !choices.audioEnabled }),
1637
+ "data-testid": "call-prejoin-mic-toggle",
1638
+ children: choices.audioEnabled ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Mic, { "aria-hidden": true }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MicOff, { "aria-hidden": true })
1639
+ }
1640
+ ),
1641
+ /* @__PURE__ */ jsxRuntime.jsx(
1642
+ CallControlButton,
1643
+ {
1644
+ label: choices.videoEnabled ? "Turn off camera" : "Turn on camera",
1645
+ tone: choices.videoEnabled ? "neutral" : "off",
1646
+ "aria-pressed": choices.videoEnabled,
1647
+ onClick: () => set({ videoEnabled: !choices.videoEnabled }),
1648
+ "data-testid": "call-prejoin-camera-toggle",
1649
+ children: choices.videoEnabled ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Video, { "aria-hidden": true }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.VideoOff, { "aria-hidden": true })
1650
+ }
1651
+ )
1652
+ ] })
1653
+ ] }),
1654
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-col gap-4", children: [
1655
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
1656
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-xl font-semibold", children: heading }),
1657
+ title && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "truncate text-sm text-muted-foreground", children: title })
1658
+ ] }),
1659
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [
1660
+ /* @__PURE__ */ jsxRuntime.jsx(
1661
+ DeviceSelect,
1662
+ {
1663
+ devices: mics,
1664
+ value: choices.audioDeviceId,
1665
+ onChange: (id) => set({ audioDeviceId: id }),
1666
+ label: "Microphone",
1667
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Mic, {}),
1668
+ disabled: !choices.audioEnabled,
1669
+ testId: "call-prejoin-mic-select"
1670
+ }
1671
+ ),
1672
+ /* @__PURE__ */ jsxRuntime.jsx(
1673
+ "div",
1674
+ {
1675
+ className: "h-1.5 w-full overflow-hidden rounded-full bg-muted",
1676
+ role: "meter",
1677
+ "aria-label": "Microphone level",
1678
+ "aria-valuemin": 0,
1679
+ "aria-valuemax": 100,
1680
+ "aria-valuenow": Math.round(level * 100),
1681
+ "data-testid": "call-prejoin-mic-level",
1682
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1683
+ "div",
1684
+ {
1685
+ className: "h-full bg-primary transition-[width] duration-75 motion-reduce:transition-none",
1686
+ style: { width: `${Math.round(level * 100)}%` }
1687
+ }
1688
+ )
1689
+ }
1690
+ ),
1691
+ /* @__PURE__ */ jsxRuntime.jsx(
1692
+ DeviceSelect,
1693
+ {
1694
+ devices: cameras,
1695
+ value: choices.videoDeviceId,
1696
+ onChange: (id) => set({ videoDeviceId: id }),
1697
+ label: "Camera",
1698
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Video, {}),
1699
+ disabled: !choices.videoEnabled,
1700
+ testId: "call-prejoin-camera-select"
1701
+ }
1702
+ )
1703
+ ] }),
1704
+ children,
1705
+ (error || deviceError) && /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", className: "text-sm text-destructive", "data-testid": "call-prejoin-error", children: error ?? deviceError }),
1706
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2", children: [
1707
+ /* @__PURE__ */ jsxRuntime.jsxs(
1708
+ ui.Button,
1709
+ {
1710
+ type: "button",
1711
+ className: "flex-1",
1712
+ disabled: busy,
1713
+ onClick: () => onJoin(choices),
1714
+ "data-testid": "call-prejoin-join",
1715
+ children: [
1716
+ busy && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-4 animate-spin", "aria-hidden": true }),
1717
+ joinLabel
1718
+ ]
1719
+ }
1720
+ ),
1721
+ onCancel && /* @__PURE__ */ jsxRuntime.jsx(
1722
+ ui.Button,
1723
+ {
1724
+ type: "button",
1725
+ variant: "outline",
1726
+ onClick: onCancel,
1727
+ "data-testid": "call-prejoin-cancel",
1728
+ children: "Cancel"
1729
+ }
1730
+ )
1731
+ ] })
1732
+ ] })
1733
+ ] }) });
1734
+ }
1735
+
1736
+ Object.defineProperty(exports, "CAPTION_LINES", {
1737
+ enumerable: true,
1738
+ get: function () { return chunkMWDW5UBW_cjs.CAPTION_LINES; }
1739
+ });
1740
+ Object.defineProperty(exports, "CAPTION_TTL_MS", {
1741
+ enumerable: true,
1742
+ get: function () { return chunkMWDW5UBW_cjs.CAPTION_TTL_MS; }
1743
+ });
1744
+ Object.defineProperty(exports, "INITIAL_SPOTLIGHT", {
1745
+ enumerable: true,
1746
+ get: function () { return chunkMWDW5UBW_cjs.INITIAL_SPOTLIGHT; }
1747
+ });
1748
+ Object.defineProperty(exports, "MAX_GRID_TILES", {
1749
+ enumerable: true,
1750
+ get: function () { return chunkMWDW5UBW_cjs.MAX_GRID_TILES; }
1751
+ });
1752
+ Object.defineProperty(exports, "NOTICE_MS", {
1753
+ enumerable: true,
1754
+ get: function () { return chunkMWDW5UBW_cjs.NOTICE_MS; }
1755
+ });
1756
+ Object.defineProperty(exports, "SPEAKER_ACCENTS", {
1757
+ enumerable: true,
1758
+ get: function () { return chunkMWDW5UBW_cjs.SPEAKER_ACCENTS; }
1759
+ });
1760
+ Object.defineProperty(exports, "SPEAKING_LEVEL", {
1761
+ enumerable: true,
1762
+ get: function () { return chunkMWDW5UBW_cjs.SPEAKING_LEVEL; }
1763
+ });
1764
+ Object.defineProperty(exports, "TILE_ASPECT", {
1765
+ enumerable: true,
1766
+ get: function () { return chunkMWDW5UBW_cjs.TILE_ASPECT; }
1767
+ });
1768
+ Object.defineProperty(exports, "formatElapsed", {
1769
+ enumerable: true,
1770
+ get: function () { return chunkMWDW5UBW_cjs.formatElapsed; }
1771
+ });
1772
+ Object.defineProperty(exports, "gridLayout", {
1773
+ enumerable: true,
1774
+ get: function () { return chunkMWDW5UBW_cjs.gridLayout; }
1775
+ });
1776
+ Object.defineProperty(exports, "gridSlots", {
1777
+ enumerable: true,
1778
+ get: function () { return chunkMWDW5UBW_cjs.gridSlots; }
1779
+ });
1780
+ Object.defineProperty(exports, "initialsOf", {
1781
+ enumerable: true,
1782
+ get: function () { return chunkMWDW5UBW_cjs.initialsOf; }
1783
+ });
1784
+ Object.defineProperty(exports, "nearestCorner", {
1785
+ enumerable: true,
1786
+ get: function () { return chunkMWDW5UBW_cjs.nearestCorner; }
1787
+ });
1788
+ Object.defineProperty(exports, "nextSpotlight", {
1789
+ enumerable: true,
1790
+ get: function () { return chunkMWDW5UBW_cjs.nextSpotlight; }
1791
+ });
1792
+ Object.defineProperty(exports, "pickSpotlight", {
1793
+ enumerable: true,
1794
+ get: function () { return chunkMWDW5UBW_cjs.pickSpotlight; }
1795
+ });
1796
+ Object.defineProperty(exports, "rowCounts", {
1797
+ enumerable: true,
1798
+ get: function () { return chunkMWDW5UBW_cjs.rowCounts; }
1799
+ });
1800
+ Object.defineProperty(exports, "speakerAccent", {
1801
+ enumerable: true,
1802
+ get: function () { return chunkMWDW5UBW_cjs.speakerAccent; }
1803
+ });
1804
+ Object.defineProperty(exports, "speakerBorder", {
1805
+ enumerable: true,
1806
+ get: function () { return chunkMWDW5UBW_cjs.speakerBorder; }
1807
+ });
1808
+ Object.defineProperty(exports, "spotlightBox", {
1809
+ enumerable: true,
1810
+ get: function () { return chunkMWDW5UBW_cjs.spotlightBox; }
1811
+ });
1812
+ Object.defineProperty(exports, "stageContentHeight", {
1813
+ enumerable: true,
1814
+ get: function () { return chunkMWDW5UBW_cjs.stageContentHeight; }
1815
+ });
1816
+ exports.CallControlBar = CallControlBar;
1817
+ exports.CallControlButton = CallControlButton;
1818
+ exports.CallFocus = CallFocus;
1819
+ exports.CallGrid = CallGrid;
1820
+ exports.CallHeader = CallHeader;
1821
+ exports.CallNotice = CallNotice;
1822
+ exports.CallParticipants = CallParticipants;
1823
+ exports.CallSidePanel = CallSidePanel;
1824
+ exports.CallStageFrame = CallStageFrame;
1825
+ exports.CallStateMessage = CallStateMessage;
1826
+ exports.CallStatusChip = CallStatusChip;
1827
+ exports.CallTile = CallTile;
1828
+ exports.CaptionsStrip = CaptionsStrip;
1829
+ exports.ConnectionOverlay = ConnectionOverlay;
1830
+ exports.ControlBadge = ControlBadge;
1831
+ exports.ControlDivider = ControlDivider;
1832
+ exports.ControlGroup = ControlGroup;
1833
+ exports.DEFAULT_JOIN_CHOICES = DEFAULT_JOIN_CHOICES;
1834
+ exports.ElapsedTime = ElapsedTime;
1835
+ exports.EncryptionStatusChip = EncryptionStatusChip;
1836
+ exports.IncomingCallCard = IncomingCallCard;
1837
+ exports.LeaveButton = LeaveButton;
1838
+ exports.LobbyRequests = LobbyRequests;
1839
+ exports.MediaControl = MediaControl;
1840
+ exports.MinimisedCall = MinimisedCall;
1841
+ exports.MoreMenu = MoreMenu;
1842
+ exports.PreJoin = PreJoin;
1843
+ exports.RecordControl = RecordControl;
1844
+ exports.RecordingStatusChip = RecordingStatusChip;
1845
+ exports.SpeakingNow = SpeakingNow;
1846
+ exports.TranscriptionStatusChip = TranscriptionStatusChip;
1847
+ exports.VoiceMeter = VoiceMeter;
1848
+ exports.describeMediaError = describeMediaError;
1849
+ exports.useBriefNotice = useBriefNotice;
1850
+ exports.useElementSize = useElementSize;
1851
+ exports.useShortcutKeys = useShortcutKeys;
1852
+ //# sourceMappingURL=index.cjs.map
1853
+ //# sourceMappingURL=index.cjs.map