@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
@@ -1,6 +1,6 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
3
- import { JsonContent } from "@meshagent/meshagent";
3
+ import { MessagingChatClient } from "@meshagent/meshagent-agents";
4
4
  import { ChatInput } from "./chat-input";
5
5
  import { MeshagentFileUpload, fileToAsyncIterable } from "./file-attachment";
6
6
  import { Toaster } from "../components/ui/sonner";
@@ -15,7 +15,7 @@ function normalizeThreadPath(path) {
15
15
  return normalizedPath ? normalizedPath : null;
16
16
  }
17
17
  function getParticipantName(participant) {
18
- const name = participant.getAttribute("name");
18
+ const name = participant?.getAttribute("name");
19
19
  return typeof name === "string" ? name.trim() : "";
20
20
  }
21
21
  function displayParticipantName(name) {
@@ -46,53 +46,6 @@ function ensureOperationActive(operationId, activeOperationRef) {
46
46
  throw new NewThreadCancelledError();
47
47
  }
48
48
  }
49
- function delay(milliseconds) {
50
- return new Promise((resolve) => {
51
- window.setTimeout(resolve, milliseconds);
52
- });
53
- }
54
- async function waitForTargetAgent(params) {
55
- const { room, agentName, operationId, activeOperationRef } = params;
56
- while (true) {
57
- ensureOperationActive(operationId, activeOperationRef);
58
- const targetAgent = findTargetAgent(room, agentName);
59
- if (targetAgent) {
60
- return targetAgent;
61
- }
62
- await delay(250);
63
- }
64
- }
65
- async function waitForToolkitAvailable(params) {
66
- const {
67
- room,
68
- participantId,
69
- toolkit,
70
- operationId,
71
- activeOperationRef
72
- } = params;
73
- while (true) {
74
- ensureOperationActive(operationId, activeOperationRef);
75
- try {
76
- const toolkits = await room.agents.listToolkits({ participantId, timeout: 1e3 });
77
- if (toolkits.some((toolkitDescription) => toolkitDescription.name === toolkit)) {
78
- return;
79
- }
80
- } catch {
81
- }
82
- await delay(250);
83
- }
84
- }
85
- function getStringField(record, key) {
86
- const value = record[key];
87
- return typeof value === "string" && value.trim() !== "" ? value.trim() : null;
88
- }
89
- function parseThreadToolResult(toolkit, tool, content) {
90
- const path = getStringField(content.json, "path");
91
- if (!path) {
92
- throw new Error(`${toolkit}.${tool} response missing path`);
93
- }
94
- return [path, getStringField(content.json, "name")];
95
- }
96
49
  function describeError(error) {
97
50
  if (error instanceof Error && error.message.trim() !== "") {
98
51
  return error.message;
@@ -113,10 +66,10 @@ function ErrorBanner({ message }) {
113
66
  }
114
67
  function NewChatThread({
115
68
  room,
69
+ chatClient,
70
+ disposeChatClient = false,
116
71
  agentName,
117
72
  builder,
118
- toolkit = "chat",
119
- tool = "new_thread",
120
73
  selectedThreadPath,
121
74
  onThreadPathChanged,
122
75
  onThreadResolved,
@@ -133,11 +86,30 @@ function NewChatThread({
133
86
  const activeOperationRef = useRef(0);
134
87
  const controlledThreadPath = selectedThreadPath !== void 0 ? normalizeThreadPath(selectedThreadPath) : void 0;
135
88
  const activePath = controlledThreadPath ?? internalThreadPath;
89
+ const ownsChatClient = chatClient == null;
90
+ const activeChatClient = useMemo(
91
+ () => chatClient ?? new MessagingChatClient({ room, agentName }),
92
+ [agentName, chatClient, room]
93
+ );
94
+ const [clientVersion, setClientVersion] = useState(0);
136
95
  useEffect(() => {
137
96
  return () => {
138
97
  activeOperationRef.current += 1;
139
98
  };
140
99
  }, []);
100
+ useEffect(() => {
101
+ void activeChatClient.start();
102
+ const handleChange = () => {
103
+ setClientVersion((current) => current + 1);
104
+ };
105
+ activeChatClient.addListener(handleChange);
106
+ return () => {
107
+ activeChatClient.removeListener(handleChange);
108
+ if (ownsChatClient || disposeChatClient) {
109
+ void activeChatClient.stop();
110
+ }
111
+ };
112
+ }, [activeChatClient, disposeChatClient, ownsChatClient]);
141
113
  useEffect(() => {
142
114
  if (controlledThreadPath === void 0) {
143
115
  return;
@@ -179,46 +151,30 @@ function NewChatThread({
179
151
  }
180
152
  const operationId = activeOperationRef.current + 1;
181
153
  activeOperationRef.current = operationId;
182
- const initialTargetAgent = findTargetAgent(room, agentName);
183
- setWaitingForAgent(initialTargetAgent === null);
184
- setCreatingNewThread(initialTargetAgent !== null);
154
+ const initialTargetAgent = activeChatClient.agentParticipant() ?? findTargetAgent(room, agentName);
155
+ setWaitingForAgent(initialTargetAgent === null && chatClient == null);
156
+ setCreatingNewThread(initialTargetAgent !== null || chatClient != null);
185
157
  setNewThreadError(null);
186
158
  try {
187
- const targetAgent = initialTargetAgent ?? await waitForTargetAgent({
188
- room,
189
- agentName,
190
- operationId,
191
- activeOperationRef
192
- });
159
+ if (initialTargetAgent === null && chatClient == null) {
160
+ if (!(activeChatClient instanceof MessagingChatClient)) {
161
+ throw new Error("No online agent supports agent messages.");
162
+ }
163
+ await activeChatClient.waitForAgentParticipant({ waitKey: String(operationId) });
164
+ }
193
165
  ensureOperationActive(operationId, activeOperationRef);
194
- if (initialTargetAgent === null) {
166
+ if (initialTargetAgent === null && chatClient == null) {
195
167
  setWaitingForAgent(false);
196
168
  setCreatingNewThread(true);
197
169
  }
198
- await waitForToolkitAvailable({
199
- room,
200
- participantId: targetAgent.id,
201
- toolkit,
202
- operationId,
203
- activeOperationRef
204
- });
205
- ensureOperationActive(operationId, activeOperationRef);
206
- const response = await room.invoke({
207
- participantId: targetAgent.id,
208
- toolkit,
209
- tool,
210
- arguments: {
211
- message: {
212
- text,
213
- attachments: newThreadAttachments.map((attachment) => ({ path: attachment.path }))
214
- }
215
- }
170
+ const result = await activeChatClient.startThread({
171
+ message: text,
172
+ attachments: newThreadAttachments.map((attachment) => attachment.path),
173
+ senderName: getParticipantName(room.localParticipant) || void 0
216
174
  });
217
175
  ensureOperationActive(operationId, activeOperationRef);
218
- if (!(response instanceof JsonContent)) {
219
- throw new Error(`${toolkit}.${tool} returned non-JSON content`);
220
- }
221
- const [threadPath, displayName] = parseThreadToolResult(toolkit, tool, response);
176
+ const threadPath = result.threadPath;
177
+ const displayName = null;
222
178
  const normalizedPath = normalizeThreadPath(threadPath);
223
179
  if (controlledThreadPath === void 0) {
224
180
  setInternalThreadPath(normalizedPath);
@@ -239,7 +195,9 @@ function NewChatThread({
239
195
  setNewThreadError(describeError(error));
240
196
  }
241
197
  }, [
198
+ activeChatClient,
242
199
  agentName,
200
+ chatClient,
243
201
  controlledThreadPath,
244
202
  creatingNewThread,
245
203
  newThreadAttachments,
@@ -247,8 +205,6 @@ function NewChatThread({
247
205
  onThreadPathChanged,
248
206
  onThreadResolved,
249
207
  room,
250
- toolkit,
251
- tool,
252
208
  waitingForAgent
253
209
  ]);
254
210
  const targetAgentLabel = useMemo(() => {
@@ -256,9 +212,9 @@ function NewChatThread({
256
212
  if (knownAgentName) {
257
213
  return displayParticipantName(knownAgentName);
258
214
  }
259
- const targetAgent = findTargetAgent(room);
215
+ const targetAgent = activeChatClient.agentParticipant() ?? findTargetAgent(room);
260
216
  return displayParticipantName(targetAgent ? getParticipantName(targetAgent) : null);
261
- }, [agentName, room]);
217
+ }, [activeChatClient, agentName, clientVersion, room]);
262
218
  const pendingStatusText = waitingForAgent ? `Waiting for ${targetAgentLabel} to be ready.` : creatingNewThread ? `Starting a thread with ${targetAgentLabel}.` : null;
263
219
  if (activePath !== null) {
264
220
  return builder(activePath);
@@ -4,6 +4,8 @@ export declare enum FileKind {
4
4
  Image = "image",
5
5
  Video = "video",
6
6
  Pdf = "pdf",
7
+ Source = "source",
8
+ Thread = "thread",
7
9
  Unknown = "unknown"
8
10
  }
9
11
  export declare function filePreviewName(path: string): string;
@@ -22,6 +24,10 @@ export declare function PdfPreview({ room, path }: {
22
24
  room: RoomClient;
23
25
  path: string;
24
26
  }): ReactElement;
27
+ export declare function SourcePreview({ room, path }: {
28
+ room: RoomClient;
29
+ path: string;
30
+ }): ReactElement;
25
31
  export declare function FilePreview({ room, path }: {
26
32
  room: RoomClient;
27
33
  path: string;
@@ -2,6 +2,8 @@ import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { useEffect, useMemo, useRef, useState } from "react";
3
3
  import { Download, FileText } from "lucide-react";
4
4
  import { Document, Page, pdfjs } from "react-pdf";
5
+ import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
6
+ import { oneLight } from "react-syntax-highlighter/dist/esm/styles/prism";
5
7
  import {
6
8
  Dialog,
7
9
  DialogContent,
@@ -13,11 +15,14 @@ import {
13
15
  import { Button } from "../components/ui/button";
14
16
  import { Spinner } from "../components/ui/spinner";
15
17
  import { cn } from "../lib/utils";
18
+ import { ChatThread } from "../chat/chat-thread";
16
19
  pdfjs.GlobalWorkerOptions.workerSrc = `https://unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.mjs`;
17
20
  var FileKind = /* @__PURE__ */ ((FileKind2) => {
18
21
  FileKind2["Image"] = "image";
19
22
  FileKind2["Video"] = "video";
20
23
  FileKind2["Pdf"] = "pdf";
24
+ FileKind2["Source"] = "source";
25
+ FileKind2["Thread"] = "thread";
21
26
  FileKind2["Unknown"] = "unknown";
22
27
  return FileKind2;
23
28
  })(FileKind || {});
@@ -39,6 +44,123 @@ const imageExtensions = /* @__PURE__ */ new Set([
39
44
  ]);
40
45
  const videoExtensions = /* @__PURE__ */ new Set(["m4v", "mkv", "mov", "mp4", "webm"]);
41
46
  const pdfExtensions = /* @__PURE__ */ new Set(["pdf"]);
47
+ const sourceExtensions = /* @__PURE__ */ new Set([
48
+ "bash",
49
+ "c",
50
+ "cc",
51
+ "cfg",
52
+ "cmake",
53
+ "cpp",
54
+ "cs",
55
+ "css",
56
+ "csv",
57
+ "dart",
58
+ "diff",
59
+ "dockerfile",
60
+ "env",
61
+ "fish",
62
+ "go",
63
+ "gradle",
64
+ "graphql",
65
+ "h",
66
+ "hpp",
67
+ "htm",
68
+ "html",
69
+ "ini",
70
+ "java",
71
+ "js",
72
+ "json",
73
+ "jsx",
74
+ "kt",
75
+ "kts",
76
+ "lua",
77
+ "md",
78
+ "mjs",
79
+ "patch",
80
+ "php",
81
+ "proto",
82
+ "py",
83
+ "rb",
84
+ "rs",
85
+ "scss",
86
+ "sh",
87
+ "sql",
88
+ "swift",
89
+ "toml",
90
+ "ts",
91
+ "tsx",
92
+ "txt",
93
+ "xml",
94
+ "yaml",
95
+ "yml",
96
+ "zsh"
97
+ ]);
98
+ const sourceFilenames = /* @__PURE__ */ new Set([
99
+ ".dockerignore",
100
+ ".env",
101
+ ".gitignore",
102
+ "dockerfile",
103
+ "makefile"
104
+ ]);
105
+ const sourceLanguagesByExtension = /* @__PURE__ */ new Map([
106
+ ["bash", "bash"],
107
+ ["c", "c"],
108
+ ["cc", "cpp"],
109
+ ["cfg", "ini"],
110
+ ["cmake", "cmake"],
111
+ ["cpp", "cpp"],
112
+ ["cs", "csharp"],
113
+ ["css", "css"],
114
+ ["csv", "csv"],
115
+ ["dart", "dart"],
116
+ ["diff", "diff"],
117
+ ["dockerfile", "docker"],
118
+ ["env", "ini"],
119
+ ["fish", "fish"],
120
+ ["go", "go"],
121
+ ["gradle", "gradle"],
122
+ ["graphql", "graphql"],
123
+ ["h", "c"],
124
+ ["hpp", "cpp"],
125
+ ["htm", "html"],
126
+ ["html", "html"],
127
+ ["ini", "ini"],
128
+ ["java", "java"],
129
+ ["js", "javascript"],
130
+ ["json", "json"],
131
+ ["jsx", "jsx"],
132
+ ["kt", "kotlin"],
133
+ ["kts", "kotlin"],
134
+ ["lua", "lua"],
135
+ ["md", "markdown"],
136
+ ["mjs", "javascript"],
137
+ ["patch", "diff"],
138
+ ["php", "php"],
139
+ ["proto", "protobuf"],
140
+ ["py", "python"],
141
+ ["rb", "ruby"],
142
+ ["rs", "rust"],
143
+ ["scss", "scss"],
144
+ ["sh", "bash"],
145
+ ["sql", "sql"],
146
+ ["swift", "swift"],
147
+ ["toml", "toml"],
148
+ ["ts", "typescript"],
149
+ ["tsx", "tsx"],
150
+ ["txt", "text"],
151
+ ["xml", "xml"],
152
+ ["yaml", "yaml"],
153
+ ["yml", "yaml"],
154
+ ["zsh", "bash"]
155
+ ]);
156
+ const sourceLanguagesByFilename = /* @__PURE__ */ new Map([
157
+ [".dockerignore", "docker"],
158
+ [".env", "ini"],
159
+ [".gitignore", "git"],
160
+ ["dockerfile", "docker"],
161
+ ["makefile", "makefile"]
162
+ ]);
163
+ const threadExtensions = /* @__PURE__ */ new Set(["thread"]);
42
164
  function basename(path) {
43
165
  const withoutQuery = path.split("?")[0] ?? path;
44
166
  const withoutHash = withoutQuery.split("#")[0] ?? withoutQuery;
@@ -70,6 +192,12 @@ function classifyFile(path) {
70
192
  if (pdfExtensions.has(ext)) {
71
193
  return "pdf" /* Pdf */;
72
194
  }
195
+ if (sourceExtensions.has(ext) || sourceFilenames.has(filePreviewName(path).toLowerCase())) {
196
+ return "source" /* Source */;
197
+ }
198
+ if (threadExtensions.has(ext)) {
199
+ return "thread" /* Thread */;
200
+ }
73
201
  return "unknown" /* Unknown */;
74
202
  }
75
203
  function isImagePath(path) {
@@ -141,6 +269,55 @@ function usePdfUrl(room, path) {
141
269
  }, [path, room]);
142
270
  return { url, error };
143
271
  }
272
+ function sourceLanguage(path) {
273
+ const name = filePreviewName(path).toLowerCase();
274
+ const byFilename = sourceLanguagesByFilename.get(name);
275
+ if (byFilename != null) {
276
+ return byFilename;
277
+ }
278
+ return sourceLanguagesByExtension.get(extension(path)) ?? "text";
279
+ }
280
+ function useSourceText(room, path) {
281
+ const [text, setText] = useState(null);
282
+ const [error, setError] = useState(null);
283
+ useEffect(() => {
284
+ let cancelled = false;
285
+ const controller = new AbortController();
286
+ const normalizedPath = path.trim();
287
+ setText(null);
288
+ setError(null);
289
+ if (normalizedPath === "") {
290
+ return () => {
291
+ controller.abort();
292
+ };
293
+ }
294
+ const loadText = async () => {
295
+ if (isHttpUrl(normalizedPath)) {
296
+ const response = await fetch(normalizedPath, { signal: controller.signal });
297
+ if (!response.ok) {
298
+ throw new Error(`HTTP ${response.status}`);
299
+ }
300
+ return await response.text();
301
+ }
302
+ const content = await room.storage.download(normalizedPath);
303
+ return new TextDecoder().decode(content.data);
304
+ };
305
+ void loadText().then((nextText) => {
306
+ if (!cancelled) {
307
+ setText(nextText);
308
+ }
309
+ }).catch((nextError) => {
310
+ if (!cancelled) {
311
+ setError(nextError);
312
+ }
313
+ });
314
+ return () => {
315
+ cancelled = true;
316
+ controller.abort();
317
+ };
318
+ }, [path, room]);
319
+ return { text, error };
320
+ }
144
321
  function ErrorPreview({ message }) {
145
322
  return /* @__PURE__ */ jsx("div", { className: "flex h-full min-h-48 items-center justify-center p-6 text-center text-sm text-destructive", children: message });
146
323
  }
@@ -252,6 +429,44 @@ function PdfPreview({ room, path }) {
252
429
  }
253
430
  ) });
254
431
  }
432
+ function SourcePreview({ room, path }) {
433
+ const { text, error } = useSourceText(room, path);
434
+ const language = useMemo(() => sourceLanguage(path), [path]);
435
+ if (error != null) {
436
+ return /* @__PURE__ */ jsx(ErrorPreview, { message: `Unable to load source preview: ${String(error)}` });
437
+ }
438
+ if (text == null) {
439
+ return /* @__PURE__ */ jsx(LoadingPreview, {});
440
+ }
441
+ return /* @__PURE__ */ jsx("div", { className: "h-full overflow-auto bg-[#fafafa] text-sm", children: /* @__PURE__ */ jsx(
442
+ SyntaxHighlighter,
443
+ {
444
+ language,
445
+ style: oneLight,
446
+ showLineNumbers: true,
447
+ wrapLongLines: true,
448
+ customStyle: {
449
+ margin: 0,
450
+ minHeight: "100%",
451
+ background: "transparent",
452
+ padding: "1rem"
453
+ },
454
+ codeTagProps: {
455
+ style: {
456
+ fontFamily: "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace"
457
+ }
458
+ },
459
+ lineNumberStyle: {
460
+ minWidth: "2.75em",
461
+ paddingRight: "1em",
462
+ color: "var(--muted-foreground)",
463
+ textAlign: "right",
464
+ userSelect: "none"
465
+ },
466
+ children: text
467
+ }
468
+ ) });
469
+ }
255
470
  function UnsupportedPreview({ room, path }) {
256
471
  const filename = filePreviewName(path);
257
472
  return /* @__PURE__ */ jsxs("div", { className: "flex h-full min-h-64 flex-col items-center justify-center gap-4 p-8 text-center", children: [
@@ -272,6 +487,10 @@ function FilePreview({ room, path }) {
272
487
  return /* @__PURE__ */ jsx(VideoPreview, { room, path });
273
488
  case "pdf" /* Pdf */:
274
489
  return /* @__PURE__ */ jsx(PdfPreview, { room, path });
490
+ case "source" /* Source */:
491
+ return /* @__PURE__ */ jsx(SourcePreview, { room, path });
492
+ case "thread" /* Thread */:
493
+ return /* @__PURE__ */ jsx(ChatThread, { room, path });
275
494
  case "unknown" /* Unknown */:
276
495
  return /* @__PURE__ */ jsx(UnsupportedPreview, { room, path });
277
496
  }
@@ -309,6 +528,7 @@ export {
309
528
  FilePreviewDialog,
310
529
  ImagePreview,
311
530
  PdfPreview,
531
+ SourcePreview,
312
532
  VideoPreview,
313
533
  classifyFile,
314
534
  filePreviewName,
@@ -0,0 +1,46 @@
1
+ import { ReactNode } from "react";
2
+ import { Track } from "livekit-client";
3
+ import type { Participant, TrackPublication, VideoTrack } from "livekit-client";
4
+ export declare const TrackSource: {
5
+ readonly Camera: Track.Source.Camera;
6
+ readonly ScreenShareVideo: Track.Source.ScreenShare;
7
+ };
8
+ export type TrackSource = (typeof TrackSource)[keyof typeof TrackSource];
9
+ export interface CameraGridFrameArgs {
10
+ participant: Participant;
11
+ publication: TrackPublication | null;
12
+ trackNode: ReactNode;
13
+ showName: boolean;
14
+ }
15
+ export interface CameraGridProps {
16
+ participants: Participant[];
17
+ room?: unknown | null;
18
+ spacing?: number;
19
+ showNames?: boolean;
20
+ showAllVideos?: boolean;
21
+ preferredSource?: TrackSource;
22
+ rowsDesired?: number;
23
+ columnsDesired?: number;
24
+ tryFill?: boolean;
25
+ /** Equivalent to activeVideoPublicationForSource(p, source). */
26
+ activeVideoPublicationForSource: (participant: Participant, source: TrackSource) => TrackPublication | null | undefined;
27
+ /** Equivalent to activeVideoPublications(p, { source? }). */
28
+ activeVideoPublications: (participant: Participant, options?: {
29
+ source?: TrackSource;
30
+ }) => TrackPublication[];
31
+ /** Equivalent to VideoTrackRenderer. */
32
+ renderVideoTrack: (args: {
33
+ track: VideoTrack;
34
+ fit: "contain" | "cover";
35
+ publication: TrackPublication;
36
+ participant: Participant;
37
+ }) => ReactNode;
38
+ /** Equivalent to AudioStats. Used only for `.agent` camera placeholders. */
39
+ renderAudioStats?: (args: {
40
+ room: unknown;
41
+ participant: Participant;
42
+ }) => ReactNode;
43
+ /** Equivalent to frameBuilder. */
44
+ frameBuilder: (args: CameraGridFrameArgs) => ReactNode;
45
+ }
46
+ export declare function CameraGrid({ participants, room, spacing, showNames, showAllVideos, preferredSource, rowsDesired, columnsDesired, tryFill, activeVideoPublicationForSource, activeVideoPublications, renderVideoTrack, renderAudioStats, frameBuilder, }: CameraGridProps): import("react/jsx-runtime").JSX.Element | null;