@meshagent/meshagent-tailwind 0.41.4 → 0.41.6

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 (48) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +33 -0
  3. package/dist/cjs/chat/chat-thread.js +15 -10
  4. package/dist/cjs/chat/dataset-chat-thread.d.ts +4 -1
  5. package/dist/cjs/chat/dataset-chat-thread.js +130 -157
  6. package/dist/cjs/chat/multi-thread-view.d.ts +4 -1
  7. package/dist/cjs/chat/multi-thread-view.js +4 -0
  8. package/dist/cjs/chat/new-chat-thread.d.ts +4 -1
  9. package/dist/cjs/chat/new-chat-thread.js +43 -87
  10. package/dist/cjs/file-preview/file-preview.d.ts +6 -0
  11. package/dist/cjs/file-preview/file-preview.js +220 -0
  12. package/dist/cjs/meetings/camera-grid.d.ts +46 -0
  13. package/dist/cjs/meetings/camera-grid.js +435 -0
  14. package/dist/cjs/meetings/controls.d.ts +4 -2
  15. package/dist/cjs/meetings/controls.js +9 -3
  16. package/dist/cjs/meetings/lobby.d.ts +17 -0
  17. package/dist/cjs/meetings/lobby.js +595 -0
  18. package/dist/cjs/meetings/meeting-scope.d.ts +7 -6
  19. package/dist/cjs/meetings/meeting-scope.js +64 -15
  20. package/dist/cjs/meetings/meeting-view.d.ts +6 -0
  21. package/dist/cjs/meetings/meeting-view.js +635 -0
  22. package/dist/cjs/meetings/meetings.d.ts +3 -0
  23. package/dist/cjs/meetings/meetings.js +3 -0
  24. package/dist/cjs/meetings/wake-lock.js +2 -2
  25. package/dist/esm/chat/chat-thread.js +15 -10
  26. package/dist/esm/chat/dataset-chat-thread.d.ts +4 -1
  27. package/dist/esm/chat/dataset-chat-thread.js +129 -133
  28. package/dist/esm/chat/multi-thread-view.d.ts +4 -1
  29. package/dist/esm/chat/multi-thread-view.js +4 -0
  30. package/dist/esm/chat/new-chat-thread.d.ts +4 -1
  31. package/dist/esm/chat/new-chat-thread.js +43 -87
  32. package/dist/esm/file-preview/file-preview.d.ts +6 -0
  33. package/dist/esm/file-preview/file-preview.js +220 -0
  34. package/dist/esm/meetings/camera-grid.d.ts +46 -0
  35. package/dist/esm/meetings/camera-grid.js +405 -0
  36. package/dist/esm/meetings/controls.d.ts +4 -2
  37. package/dist/esm/meetings/controls.js +9 -3
  38. package/dist/esm/meetings/lobby.d.ts +17 -0
  39. package/dist/esm/meetings/lobby.js +595 -0
  40. package/dist/esm/meetings/meeting-scope.d.ts +7 -6
  41. package/dist/esm/meetings/meeting-scope.js +71 -16
  42. package/dist/esm/meetings/meeting-view.d.ts +6 -0
  43. package/dist/esm/meetings/meeting-view.js +630 -0
  44. package/dist/esm/meetings/meetings.d.ts +3 -0
  45. package/dist/esm/meetings/meetings.js +3 -0
  46. package/dist/esm/meetings/wake-lock.js +2 -2
  47. package/dist/index.css +1 -1
  48. package/package.json +9 -5
@@ -0,0 +1,595 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var lobby_exports = {};
20
+ __export(lobby_exports, {
21
+ MeetingLobby: () => MeetingLobby,
22
+ meetingFastConnectOptions: () => meetingFastConnectOptions
23
+ });
24
+ module.exports = __toCommonJS(lobby_exports);
25
+ var import_jsx_runtime = require("react/jsx-runtime");
26
+ var import_livekit_client = require("livekit-client");
27
+ var import_lucide_react = require("lucide-react");
28
+ var import_react = require("react");
29
+ var import_button = require("../components/ui/button");
30
+ var import_dialog = require("../components/ui/dialog");
31
+ var import_select = require("../components/ui/select");
32
+ var import_spinner = require("../components/ui/spinner");
33
+ var import_utils = require("../lib/utils");
34
+ var import_meeting_scope = require("./meeting-scope");
35
+ const audioInputStorageKey = "audioInput";
36
+ const audioOutputStorageKey = "audioOutput";
37
+ const videoInputStorageKey = "videoInput";
38
+ const minimumLobbyPendingDuration = 350;
39
+ function storedDeviceId(key) {
40
+ if (typeof window === "undefined") {
41
+ return "";
42
+ }
43
+ return window.localStorage.getItem(key) ?? "";
44
+ }
45
+ function storeDeviceId(key, value) {
46
+ if (typeof window === "undefined") {
47
+ return;
48
+ }
49
+ if (value === "") {
50
+ window.localStorage.removeItem(key);
51
+ return;
52
+ }
53
+ window.localStorage.setItem(key, value);
54
+ }
55
+ function deviceLabel(device, fallbackPrefix) {
56
+ const label = device?.label.trim();
57
+ return label != null && label !== "" ? label.replace(/^Default - /u, "") : `Default ${fallbackPrefix}`;
58
+ }
59
+ function devicesForKind(devices, kind) {
60
+ return devices.filter(
61
+ (device) => device.kind === kind && device.deviceId !== ""
62
+ );
63
+ }
64
+ function captureDeviceConstraint(deviceId) {
65
+ return deviceId === "" ? void 0 : { exact: deviceId };
66
+ }
67
+ function videoCaptureOptions(deviceId) {
68
+ const constraint = captureDeviceConstraint(deviceId);
69
+ return constraint == null ? void 0 : { deviceId: constraint };
70
+ }
71
+ function audioCaptureOptions(deviceId) {
72
+ const constraint = captureDeviceConstraint(deviceId);
73
+ return constraint == null ? void 0 : { deviceId: constraint };
74
+ }
75
+ function stopLocalVideoTrack(track) {
76
+ track?.stop();
77
+ }
78
+ function stopLocalAudioTrack(track) {
79
+ track?.stop();
80
+ }
81
+ async function createPreviewVideoTrack(deviceId) {
82
+ const constraints = deviceId === "" ? true : { deviceId: { exact: deviceId } };
83
+ const stream = await navigator.mediaDevices.getUserMedia({
84
+ video: constraints,
85
+ audio: false
86
+ });
87
+ const track = stream.getVideoTracks()[0];
88
+ if (track == null) {
89
+ throw new Error("No video track was created");
90
+ }
91
+ return new import_livekit_client.LocalVideoTrack(
92
+ track,
93
+ constraints === true ? void 0 : constraints
94
+ );
95
+ }
96
+ async function createPreviewAudioTrack(deviceId) {
97
+ const constraints = deviceId === "" ? true : { deviceId: { exact: deviceId } };
98
+ const stream = await navigator.mediaDevices.getUserMedia({
99
+ video: false,
100
+ audio: constraints
101
+ });
102
+ const track = stream.getAudioTracks()[0];
103
+ if (track == null) {
104
+ throw new Error("No audio track was created");
105
+ }
106
+ return new import_livekit_client.LocalAudioTrack(
107
+ track,
108
+ constraints === true ? void 0 : constraints
109
+ );
110
+ }
111
+ function useLobbyDevices() {
112
+ const [devices, setDevices] = (0, import_react.useState)([]);
113
+ const refreshDevices = (0, import_react.useCallback)(() => {
114
+ void import_livekit_client.Room.getLocalDevices(void 0, false).then(setDevices).catch(() => setDevices([]));
115
+ }, []);
116
+ (0, import_react.useEffect)(() => {
117
+ refreshDevices();
118
+ navigator.mediaDevices?.addEventListener?.("devicechange", refreshDevices);
119
+ return () => navigator.mediaDevices?.removeEventListener?.(
120
+ "devicechange",
121
+ refreshDevices
122
+ );
123
+ }, [refreshDevices]);
124
+ return { devices, refreshDevices };
125
+ }
126
+ async function runWithMinimumPendingDuration(action) {
127
+ const startedAt = Date.now();
128
+ await action();
129
+ const remaining = minimumLobbyPendingDuration - (Date.now() - startedAt);
130
+ if (remaining > 0) {
131
+ await new Promise((resolve) => window.setTimeout(resolve, remaining));
132
+ }
133
+ }
134
+ function useMeetingLobbyState() {
135
+ const { devices, refreshDevices } = useLobbyDevices();
136
+ const [loaded, setLoaded] = (0, import_react.useState)(false);
137
+ const [audioOn, setAudioOn] = (0, import_react.useState)(true);
138
+ const [videoOn, setVideoOn] = (0, import_react.useState)(true);
139
+ const [audioProcessing, setAudioProcessing] = (0, import_react.useState)(false);
140
+ const [videoProcessing, setVideoProcessing] = (0, import_react.useState)(false);
141
+ const [audioUnavailable, setAudioUnavailable] = (0, import_react.useState)(false);
142
+ const [videoUnavailable, setVideoUnavailable] = (0, import_react.useState)(false);
143
+ const [audioDeviceId, setAudioDeviceIdState] = (0, import_react.useState)(() => storedDeviceId(audioInputStorageKey));
144
+ const [audioOutputDeviceId, setAudioOutputDeviceIdState] = (0, import_react.useState)(() => storedDeviceId(audioOutputStorageKey));
145
+ const [videoDeviceId, setVideoDeviceIdState] = (0, import_react.useState)(() => storedDeviceId(videoInputStorageKey));
146
+ const [audioTrack, setAudioTrack] = (0, import_react.useState)(null);
147
+ const [videoTrack, setVideoTrack] = (0, import_react.useState)(null);
148
+ const disposedRef = (0, import_react.useRef)(false);
149
+ const audioTrackRef = (0, import_react.useRef)(null);
150
+ const videoTrackRef = (0, import_react.useRef)(null);
151
+ const audioTrackRequestRef = (0, import_react.useRef)(0);
152
+ const videoTrackRequestRef = (0, import_react.useRef)(0);
153
+ const audioDeviceIdRef = (0, import_react.useRef)(audioDeviceId);
154
+ const videoDeviceIdRef = (0, import_react.useRef)(videoDeviceId);
155
+ const replaceAudioTrackState = (0, import_react.useCallback)(
156
+ (nextTrack) => {
157
+ const currentTrack = audioTrackRef.current;
158
+ if (currentTrack !== nextTrack) {
159
+ stopLocalAudioTrack(currentTrack);
160
+ }
161
+ if (disposedRef.current) {
162
+ stopLocalAudioTrack(nextTrack);
163
+ audioTrackRef.current = null;
164
+ return;
165
+ }
166
+ audioTrackRef.current = nextTrack;
167
+ setAudioTrack(nextTrack);
168
+ },
169
+ []
170
+ );
171
+ const replaceVideoTrackState = (0, import_react.useCallback)(
172
+ (nextTrack) => {
173
+ const currentTrack = videoTrackRef.current;
174
+ if (currentTrack !== nextTrack) {
175
+ stopLocalVideoTrack(currentTrack);
176
+ }
177
+ if (disposedRef.current) {
178
+ stopLocalVideoTrack(nextTrack);
179
+ videoTrackRef.current = null;
180
+ return;
181
+ }
182
+ videoTrackRef.current = nextTrack;
183
+ setVideoTrack(nextTrack);
184
+ },
185
+ []
186
+ );
187
+ const replaceAudioTrack = (0, import_react.useCallback)(
188
+ async (deviceId) => {
189
+ const requestId = audioTrackRequestRef.current + 1;
190
+ audioTrackRequestRef.current = requestId;
191
+ setAudioProcessing(true);
192
+ await runWithMinimumPendingDuration(async () => {
193
+ try {
194
+ const nextTrack = await createPreviewAudioTrack(deviceId);
195
+ if (disposedRef.current || requestId !== audioTrackRequestRef.current) {
196
+ stopLocalAudioTrack(nextTrack);
197
+ return;
198
+ }
199
+ replaceAudioTrackState(nextTrack);
200
+ setAudioUnavailable(false);
201
+ } catch (error) {
202
+ if (!disposedRef.current && requestId === audioTrackRequestRef.current) {
203
+ replaceAudioTrackState(null);
204
+ setAudioUnavailable(true);
205
+ console.warn("Unable to start microphone preview", error);
206
+ }
207
+ }
208
+ });
209
+ if (!disposedRef.current && requestId === audioTrackRequestRef.current) {
210
+ setAudioProcessing(false);
211
+ }
212
+ },
213
+ [replaceAudioTrackState]
214
+ );
215
+ const replaceVideoTrack = (0, import_react.useCallback)(
216
+ async (deviceId) => {
217
+ const requestId = videoTrackRequestRef.current + 1;
218
+ videoTrackRequestRef.current = requestId;
219
+ setVideoProcessing(true);
220
+ await runWithMinimumPendingDuration(async () => {
221
+ try {
222
+ const nextTrack = await createPreviewVideoTrack(deviceId);
223
+ if (disposedRef.current || requestId !== videoTrackRequestRef.current) {
224
+ stopLocalVideoTrack(nextTrack);
225
+ return;
226
+ }
227
+ replaceVideoTrackState(nextTrack);
228
+ setVideoUnavailable(false);
229
+ } catch (error) {
230
+ if (!disposedRef.current && requestId === videoTrackRequestRef.current) {
231
+ replaceVideoTrackState(null);
232
+ setVideoUnavailable(true);
233
+ console.warn("Unable to start camera preview", error);
234
+ }
235
+ }
236
+ });
237
+ if (!disposedRef.current && requestId === videoTrackRequestRef.current) {
238
+ setVideoProcessing(false);
239
+ }
240
+ },
241
+ [replaceVideoTrackState]
242
+ );
243
+ (0, import_react.useEffect)(() => {
244
+ audioDeviceIdRef.current = audioDeviceId;
245
+ }, [audioDeviceId]);
246
+ (0, import_react.useEffect)(() => {
247
+ videoDeviceIdRef.current = videoDeviceId;
248
+ }, [videoDeviceId]);
249
+ (0, import_react.useEffect)(() => {
250
+ let cancelled = false;
251
+ disposedRef.current = false;
252
+ void Promise.all([
253
+ replaceAudioTrack(audioDeviceIdRef.current),
254
+ replaceVideoTrack(videoDeviceIdRef.current)
255
+ ]).finally(() => {
256
+ if (!cancelled) {
257
+ setLoaded(true);
258
+ refreshDevices();
259
+ }
260
+ });
261
+ return () => {
262
+ cancelled = true;
263
+ disposedRef.current = true;
264
+ audioTrackRequestRef.current += 1;
265
+ videoTrackRequestRef.current += 1;
266
+ replaceAudioTrackState(null);
267
+ replaceVideoTrackState(null);
268
+ };
269
+ }, [
270
+ refreshDevices,
271
+ replaceAudioTrack,
272
+ replaceAudioTrackState,
273
+ replaceVideoTrack,
274
+ replaceVideoTrackState
275
+ ]);
276
+ const setAudioDeviceId = (0, import_react.useCallback)(
277
+ (deviceId) => {
278
+ setAudioDeviceIdState(deviceId);
279
+ storeDeviceId(audioInputStorageKey, deviceId);
280
+ void replaceAudioTrack(deviceId);
281
+ },
282
+ [replaceAudioTrack]
283
+ );
284
+ const setAudioOutputDeviceId = (0, import_react.useCallback)((deviceId) => {
285
+ setAudioOutputDeviceIdState(deviceId);
286
+ storeDeviceId(audioOutputStorageKey, deviceId);
287
+ }, []);
288
+ const setVideoDeviceId = (0, import_react.useCallback)(
289
+ (deviceId) => {
290
+ setVideoDeviceIdState(deviceId);
291
+ storeDeviceId(videoInputStorageKey, deviceId);
292
+ void replaceVideoTrack(deviceId);
293
+ },
294
+ [replaceVideoTrack]
295
+ );
296
+ const toggleAudio = (0, import_react.useCallback)(() => {
297
+ if (audioProcessing) {
298
+ return;
299
+ }
300
+ if (audioTrack != null) {
301
+ replaceAudioTrackState(null);
302
+ setAudioOn(false);
303
+ return;
304
+ }
305
+ setAudioOn(true);
306
+ void replaceAudioTrack(audioDeviceId);
307
+ }, [
308
+ audioDeviceId,
309
+ audioProcessing,
310
+ audioTrack,
311
+ replaceAudioTrack,
312
+ replaceAudioTrackState
313
+ ]);
314
+ const toggleVideo = (0, import_react.useCallback)(() => {
315
+ if (videoProcessing) {
316
+ return;
317
+ }
318
+ if (videoTrack != null) {
319
+ replaceVideoTrackState(null);
320
+ setVideoOn(false);
321
+ return;
322
+ }
323
+ setVideoOn(true);
324
+ void replaceVideoTrack(videoDeviceId);
325
+ }, [
326
+ replaceVideoTrack,
327
+ replaceVideoTrackState,
328
+ videoDeviceId,
329
+ videoProcessing,
330
+ videoTrack
331
+ ]);
332
+ return {
333
+ loaded,
334
+ videoTrack,
335
+ audioTrack,
336
+ audioOn,
337
+ videoOn,
338
+ audioProcessing,
339
+ videoProcessing,
340
+ audioUnavailable,
341
+ videoUnavailable,
342
+ audioDeviceId,
343
+ audioOutputDeviceId,
344
+ videoDeviceId,
345
+ devices,
346
+ setAudioDeviceId,
347
+ setAudioOutputDeviceId,
348
+ setVideoDeviceId,
349
+ refreshDevices,
350
+ toggleAudio,
351
+ toggleVideo
352
+ };
353
+ }
354
+ function useAttachedPreviewVideo(track) {
355
+ const attachedElementRef = (0, import_react.useRef)(null);
356
+ (0, import_react.useEffect)(() => {
357
+ const element = attachedElementRef.current;
358
+ if (element == null || track == null) {
359
+ return void 0;
360
+ }
361
+ track.attach(element);
362
+ return () => {
363
+ track.detach(element);
364
+ };
365
+ }, [track]);
366
+ return (0, import_react.useCallback)((element) => {
367
+ attachedElementRef.current = element;
368
+ }, []);
369
+ }
370
+ function LobbyDeviceSelect({
371
+ label,
372
+ devices,
373
+ kind,
374
+ value,
375
+ onValueChange
376
+ }) {
377
+ const options = devicesForKind(devices, kind);
378
+ const selectedValue = value === "" ? "default" : value;
379
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "grid gap-2", children: [
380
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "text-sm font-medium", children: label }),
381
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
382
+ import_select.Select,
383
+ {
384
+ value: selectedValue,
385
+ onValueChange: (nextValue) => onValueChange(nextValue === "default" ? "" : nextValue),
386
+ children: [
387
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_select.SelectTrigger, { className: "w-full", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_select.SelectValue, { placeholder: deviceLabel(options[0] ?? null, label) }) }),
388
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_select.SelectContent, { children: [
389
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_select.SelectItem, { value: "default", children: [
390
+ "Default ",
391
+ label.toLowerCase()
392
+ ] }),
393
+ options.map((device) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_select.SelectItem, { value: device.deviceId, children: deviceLabel(device, label) }, device.deviceId))
394
+ ] })
395
+ ]
396
+ }
397
+ )
398
+ ] });
399
+ }
400
+ function LobbyDeviceSettings({ state }) {
401
+ const hasAudioOutput = (0, import_react.useMemo)(
402
+ () => state.devices.some((device) => device.kind === "audiooutput"),
403
+ [state.devices]
404
+ );
405
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_dialog.Dialog, { children: [
406
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dialog.DialogTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
407
+ import_button.Button,
408
+ {
409
+ type: "button",
410
+ title: "Device settings",
411
+ "aria-label": "Device settings",
412
+ variant: "outline",
413
+ className: "h-10",
414
+ children: [
415
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Settings, {}),
416
+ "Device settings"
417
+ ]
418
+ }
419
+ ) }),
420
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_dialog.DialogContent, { className: "max-w-[min(92vw,560px)]", children: [
421
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_dialog.DialogHeader, { children: [
422
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dialog.DialogTitle, { children: "Device settings" }),
423
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dialog.DialogDescription, { children: "Choose the devices used for this meeting." })
424
+ ] }),
425
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "grid gap-4", children: [
426
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
427
+ LobbyDeviceSelect,
428
+ {
429
+ label: "Camera",
430
+ devices: state.devices,
431
+ kind: "videoinput",
432
+ value: state.videoDeviceId,
433
+ onValueChange: state.setVideoDeviceId
434
+ }
435
+ ),
436
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
437
+ LobbyDeviceSelect,
438
+ {
439
+ label: "Microphone",
440
+ devices: state.devices,
441
+ kind: "audioinput",
442
+ value: state.audioDeviceId,
443
+ onValueChange: state.setAudioDeviceId
444
+ }
445
+ ),
446
+ hasAudioOutput && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
447
+ LobbyDeviceSelect,
448
+ {
449
+ label: "Speaker",
450
+ devices: state.devices,
451
+ kind: "audiooutput",
452
+ value: state.audioOutputDeviceId,
453
+ onValueChange: state.setAudioOutputDeviceId
454
+ }
455
+ )
456
+ ] }),
457
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dialog.DialogFooter, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_button.Button, { type: "button", variant: "outline", onClick: state.refreshDevices, children: "Refresh" }) })
458
+ ] })
459
+ ] });
460
+ }
461
+ function LobbyToggleButton({
462
+ text,
463
+ on,
464
+ unavailable,
465
+ loading,
466
+ icon,
467
+ offIcon,
468
+ onClick
469
+ }) {
470
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
471
+ import_button.Button,
472
+ {
473
+ type: "button",
474
+ title: text,
475
+ "aria-label": text,
476
+ size: "icon",
477
+ variant: unavailable ? "destructive" : on ? "default" : "outline",
478
+ disabled: loading,
479
+ onClick,
480
+ className: (0, import_utils.cn)(
481
+ "h-10 w-10",
482
+ on && !unavailable ? "bg-emerald-600 text-white hover:bg-emerald-700" : null
483
+ ),
484
+ children: loading ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_spinner.Spinner, { className: "h-5 w-5" }) : on ? icon : offIcon
485
+ }
486
+ );
487
+ }
488
+ function joinOptions(state) {
489
+ const enableVideo = state.videoTrack != null && !state.videoUnavailable;
490
+ const enableAudio = state.audioTrack != null && !state.audioUnavailable;
491
+ return {
492
+ enableVideo,
493
+ enableAudio,
494
+ videoUnavailable: state.videoUnavailable,
495
+ audioUnavailable: state.audioUnavailable,
496
+ videoDeviceId: state.videoDeviceId === "" ? void 0 : state.videoDeviceId,
497
+ audioDeviceId: state.audioDeviceId === "" ? void 0 : state.audioDeviceId,
498
+ audioOutputDeviceId: state.audioOutputDeviceId === "" ? void 0 : state.audioOutputDeviceId
499
+ };
500
+ }
501
+ function meetingFastConnectOptions(options) {
502
+ return {
503
+ camera: {
504
+ enabled: options.enableVideo,
505
+ options: videoCaptureOptions(options.videoDeviceId ?? "")
506
+ },
507
+ microphone: {
508
+ enabled: options.enableAudio,
509
+ options: audioCaptureOptions(options.audioDeviceId ?? "")
510
+ }
511
+ };
512
+ }
513
+ function MeetingLobby({
514
+ controller: providedController,
515
+ onCancel,
516
+ onJoin
517
+ }) {
518
+ const controller = (0, import_meeting_scope.useMeetingController)(providedController);
519
+ const state = useMeetingLobbyState();
520
+ const previewRef = useAttachedPreviewVideo(state.videoTrack);
521
+ const videoPending = state.videoOn && state.videoTrack == null && !state.videoUnavailable;
522
+ const audioPending = state.audioOn && state.audioTrack == null && !state.audioUnavailable;
523
+ const starting = videoPending || audioPending || state.videoProcessing || state.audioProcessing;
524
+ const canJoin = controller.config != null && !starting;
525
+ const statusText = state.loaded ? "Get ready to meet" : "Preparing devices";
526
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex h-full min-h-0 flex-col px-6 py-5", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex min-h-0 flex-1 items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "grid w-full max-w-[800px] gap-5", children: [
527
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "text-center text-base font-semibold", children: statusText }),
528
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "aspect-[3/2] overflow-hidden rounded-md bg-[#222]", children: state.videoTrack != null ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
529
+ "video",
530
+ {
531
+ ref: previewRef,
532
+ autoPlay: true,
533
+ muted: true,
534
+ playsInline: true,
535
+ className: "h-full w-full object-cover"
536
+ }
537
+ ) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex h-full w-full items-center justify-center text-sm font-medium text-white/70", children: "Camera off" }) }),
538
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex justify-between gap-2", children: [
539
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex gap-2", children: [
540
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
541
+ LobbyToggleButton,
542
+ {
543
+ text: audioPending ? "Starting microphone" : state.audioTrack != null ? "Turn off microphone" : "Turn on microphone",
544
+ on: state.audioTrack != null || audioPending,
545
+ unavailable: state.audioUnavailable,
546
+ loading: state.audioProcessing || audioPending,
547
+ icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Mic, {}),
548
+ offIcon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.MicOff, {}),
549
+ onClick: state.toggleAudio
550
+ }
551
+ ),
552
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
553
+ LobbyToggleButton,
554
+ {
555
+ text: videoPending ? "Starting camera" : state.videoTrack != null ? "Turn off camera" : "Turn on camera",
556
+ on: state.videoTrack != null || videoPending,
557
+ unavailable: state.videoUnavailable,
558
+ loading: state.videoProcessing || videoPending,
559
+ icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Video, {}),
560
+ offIcon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.VideoOff, {}),
561
+ onClick: state.toggleVideo
562
+ }
563
+ ),
564
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LobbyDeviceSettings, { state })
565
+ ] }),
566
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex gap-3", children: [
567
+ onCancel != null && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
568
+ import_button.Button,
569
+ {
570
+ type: "button",
571
+ variant: "outline",
572
+ className: "h-10 sm:w-[120px]",
573
+ onClick: onCancel,
574
+ children: "Cancel"
575
+ }
576
+ ),
577
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
578
+ import_button.Button,
579
+ {
580
+ type: "button",
581
+ className: "h-10 bg-emerald-600 text-white hover:bg-emerald-700 sm:w-[120px]",
582
+ disabled: !canJoin,
583
+ onClick: () => {
584
+ onJoin?.(joinOptions(state));
585
+ },
586
+ children: starting ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
587
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_spinner.Spinner, { className: "h-4 w-4" }),
588
+ "Starting"
589
+ ] }) : "Meet now"
590
+ }
591
+ )
592
+ ] })
593
+ ] })
594
+ ] }) }) });
595
+ }
@@ -1,17 +1,18 @@
1
1
  import type { ReactElement, ReactNode } from "react";
2
- import { RoomClient } from "@meshagent/meshagent";
3
- import { Room, type LocalParticipant, type Participant, type RoomConnectOptions, type RoomOptions, type TrackPublication } from "livekit-client";
2
+ import type { RoomClient } from "@meshagent/meshagent";
3
+ import "@meshagent/meshagent-react";
4
+ import type { LivekitConnectionInfo } from "@meshagent/meshagent-react";
5
+ import { Room } from "livekit-client";
6
+ import type { AudioCaptureOptions, LocalParticipant, Participant, RoomConnectOptions, RoomOptions, TrackPublication, VideoCaptureOptions } from "livekit-client";
4
7
  type Listener = () => void;
5
- export interface LivekitConnectionInfo {
6
- url: string;
7
- token: string;
8
- }
9
8
  export type MeetingFastConnectOptions = RoomConnectOptions & {
10
9
  camera?: {
11
10
  enabled?: boolean;
11
+ options?: VideoCaptureOptions;
12
12
  };
13
13
  microphone?: {
14
14
  enabled?: boolean;
15
+ options?: AudioCaptureOptions;
15
16
  };
16
17
  };
17
18
  export declare class PendingLocalMediaState {