@quickmeet/react 0.1.0
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.
- package/LICENSE +17 -0
- package/README.md +42 -0
- package/dist/QuickMeetConference.d.ts +13 -0
- package/dist/QuickMeetConference.d.ts.map +1 -0
- package/dist/icons.d.ts +15 -0
- package/dist/icons.d.ts.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +424 -0
- package/dist/index.js.map +1 -0
- package/dist/styles.css +1 -0
- package/package.json +52 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
Copyright 2026 QuickMeet contributors
|
|
6
|
+
|
|
7
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
you may not use this file except in compliance with the License.
|
|
9
|
+
You may obtain a copy of the License at
|
|
10
|
+
|
|
11
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
|
|
13
|
+
Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
See the License for the specific language governing permissions and
|
|
17
|
+
limitations under the License.
|
package/README.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# @quickmeet/react
|
|
2
|
+
|
|
3
|
+
Responsive, drop-in React conference UI for the self-hosted QuickMeet stack.
|
|
4
|
+
It includes camera, microphone, screen sharing, chat, participant grids, and
|
|
5
|
+
host/co-host-aware room controls.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @quickmeet/react
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
React 18 or newer is required.
|
|
14
|
+
|
|
15
|
+
## Use
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import { QuickMeetConference } from '@quickmeet/react';
|
|
19
|
+
import '@quickmeet/react/styles.css';
|
|
20
|
+
|
|
21
|
+
export function Call({ credentials }) {
|
|
22
|
+
return (
|
|
23
|
+
<div style={{ height: '100dvh' }}>
|
|
24
|
+
<QuickMeetConference
|
|
25
|
+
credentials={credentials}
|
|
26
|
+
brandName="Acme"
|
|
27
|
+
initialCameraEnabled
|
|
28
|
+
initialMicrophoneEnabled
|
|
29
|
+
onLeave={() => window.location.assign('/dashboard')}
|
|
30
|
+
/>
|
|
31
|
+
</div>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Obtain `credentials` from your authenticated backend using `@quickmeet/node`, or
|
|
37
|
+
from an invitation exchange using `@quickmeet/sdk`. The parent element must have
|
|
38
|
+
a defined height.
|
|
39
|
+
|
|
40
|
+
## License
|
|
41
|
+
|
|
42
|
+
Apache-2.0
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { JoinCredentials } from '@quickmeet/sdk';
|
|
2
|
+
export interface QuickMeetConferenceProps {
|
|
3
|
+
credentials: JoinCredentials;
|
|
4
|
+
initialCameraEnabled?: boolean;
|
|
5
|
+
initialMicrophoneEnabled?: boolean;
|
|
6
|
+
className?: string;
|
|
7
|
+
brandName?: string;
|
|
8
|
+
inviteUrl?: string;
|
|
9
|
+
onLeave?: () => void;
|
|
10
|
+
onError?: (error: Error) => void;
|
|
11
|
+
}
|
|
12
|
+
export declare function QuickMeetConference({ credentials, initialCameraEnabled, initialMicrophoneEnabled, className, brandName, inviteUrl, onLeave, onError, }: QuickMeetConferenceProps): import("react").JSX.Element;
|
|
13
|
+
//# sourceMappingURL=QuickMeetConference.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"QuickMeetConference.d.ts","sourceRoot":"","sources":["../src/QuickMeetConference.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AA8BtD,MAAM,WAAW,wBAAwB;IACvC,WAAW,EAAE,eAAe,CAAC;IAC7B,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC;AAqZD,wBAAgB,mBAAmB,CAAC,EAClC,WAAW,EACX,oBAA2B,EAC3B,wBAA+B,EAC/B,SAAc,EACd,SAAuB,EACvB,SAAS,EACT,OAAO,EACP,OAAO,GACR,EAAE,wBAAwB,+BA6E1B"}
|
package/dist/icons.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { SVGProps } from 'react';
|
|
2
|
+
type IconProps = SVGProps<SVGSVGElement>;
|
|
3
|
+
export declare const MicIcon: (props: IconProps) => import("react").JSX.Element;
|
|
4
|
+
export declare const MicOffIcon: (props: IconProps) => import("react").JSX.Element;
|
|
5
|
+
export declare const CameraIcon: (props: IconProps) => import("react").JSX.Element;
|
|
6
|
+
export declare const CameraOffIcon: (props: IconProps) => import("react").JSX.Element;
|
|
7
|
+
export declare const ScreenIcon: (props: IconProps) => import("react").JSX.Element;
|
|
8
|
+
export declare const ChatIcon: (props: IconProps) => import("react").JSX.Element;
|
|
9
|
+
export declare const PeopleIcon: (props: IconProps) => import("react").JSX.Element;
|
|
10
|
+
export declare const LinkIcon: (props: IconProps) => import("react").JSX.Element;
|
|
11
|
+
export declare const PhoneIcon: (props: IconProps) => import("react").JSX.Element;
|
|
12
|
+
export declare const SendIcon: (props: IconProps) => import("react").JSX.Element;
|
|
13
|
+
export declare const CloseIcon: (props: IconProps) => import("react").JSX.Element;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=icons.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"icons.d.ts","sourceRoot":"","sources":["../src/icons.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEtC,KAAK,SAAS,GAAG,QAAQ,CAAC,aAAa,CAAC,CAAC;AAqBzC,eAAO,MAAM,OAAO,GAAI,OAAO,SAAS,gCAKvC,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,OAAO,SAAS,gCAI1C,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,OAAO,SAAS,gCAK1C,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,OAAO,SAAS,gCAI7C,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,OAAO,SAAS,gCAK1C,CAAC;AAEF,eAAO,MAAM,QAAQ,GAAI,OAAO,SAAS,gCAIxC,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,OAAO,SAAS,gCAK1C,CAAC;AAEF,eAAO,MAAM,QAAQ,GAAI,OAAO,SAAS,gCAIxC,CAAC;AAEF,eAAO,MAAM,SAAS,GAAI,OAAO,SAAS,gCAIzC,CAAC;AAEF,eAAO,MAAM,QAAQ,GAAI,OAAO,SAAS,gCAIxC,CAAC;AAEF,eAAO,MAAM,SAAS,GAAI,OAAO,SAAS,gCAIzC,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,YAAY,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AACzE,OAAO,cAAc,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
import { jsx as e, jsxs as n } from "react/jsx-runtime";
|
|
2
|
+
import { RoomContext as W, useTracks as A, useParticipants as H, useLocalParticipant as K, ParticipantTile as B, RoomAudioRenderer as Y, useChat as z } from "@livekit/components-react";
|
|
3
|
+
import { Room as F, RoomEvent as w, ConnectionState as N, Track as k } from "livekit-client";
|
|
4
|
+
import { useState as q, useEffect as O, useMemo as U, useRef as X } from "react";
|
|
5
|
+
function f({ children: a, ...i }) {
|
|
6
|
+
return /* @__PURE__ */ e(
|
|
7
|
+
"svg",
|
|
8
|
+
{
|
|
9
|
+
viewBox: "0 0 24 24",
|
|
10
|
+
width: "20",
|
|
11
|
+
height: "20",
|
|
12
|
+
fill: "none",
|
|
13
|
+
stroke: "currentColor",
|
|
14
|
+
strokeWidth: "1.8",
|
|
15
|
+
strokeLinecap: "round",
|
|
16
|
+
strokeLinejoin: "round",
|
|
17
|
+
"aria-hidden": "true",
|
|
18
|
+
...i,
|
|
19
|
+
children: a
|
|
20
|
+
}
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
const _ = (a) => /* @__PURE__ */ n(f, { ...a, children: [
|
|
24
|
+
/* @__PURE__ */ e("rect", { x: "9", y: "3", width: "6", height: "12", rx: "3" }),
|
|
25
|
+
/* @__PURE__ */ e("path", { d: "M5.5 11.5a6.5 6.5 0 0 0 13 0M12 18v3M8.5 21h7" })
|
|
26
|
+
] }), ee = (a) => /* @__PURE__ */ e(f, { ...a, children: /* @__PURE__ */ e("path", { d: "m3 3 18 18M9 5.5V12a3 3 0 0 0 4.8 2.4M15 10.5V6a3 3 0 0 0-5.1-2.1M5.5 11.5a6.5 6.5 0 0 0 10.8 4.9M18.5 11.5a6.5 6.5 0 0 1-.5 2.5M12 18v3M8.5 21h7" }) }), ae = (a) => /* @__PURE__ */ n(f, { ...a, children: [
|
|
27
|
+
/* @__PURE__ */ e("rect", { x: "3", y: "6.5", width: "13", height: "11", rx: "2" }),
|
|
28
|
+
/* @__PURE__ */ e("path", { d: "m16 10 5-2.5v9L16 14" })
|
|
29
|
+
] }), ne = (a) => /* @__PURE__ */ e(f, { ...a, children: /* @__PURE__ */ e("path", { d: "m3 3 18 18M10.5 6.5H5a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h11M16 10l5-2.5v9l-2.5-1.25M14 6.5a2 2 0 0 1 2 2V14" }) }), te = (a) => /* @__PURE__ */ n(f, { ...a, children: [
|
|
30
|
+
/* @__PURE__ */ e("rect", { x: "3", y: "4", width: "18", height: "13", rx: "2" }),
|
|
31
|
+
/* @__PURE__ */ e("path", { d: "M8 21h8M12 17v4M9 9l3-3 3 3M12 6v7" })
|
|
32
|
+
] }), Z = (a) => /* @__PURE__ */ e(f, { ...a, children: /* @__PURE__ */ e("path", { d: "M20 14a3 3 0 0 1-3 3H9l-5 4v-4a3 3 0 0 1-2-3V6a3 3 0 0 1 3-3h12a3 3 0 0 1 3 3Z" }) }), ce = (a) => /* @__PURE__ */ n(f, { ...a, children: [
|
|
33
|
+
/* @__PURE__ */ e("circle", { cx: "9", cy: "8", r: "3" }),
|
|
34
|
+
/* @__PURE__ */ e("path", { d: "M3 20a6 6 0 0 1 12 0M16 4.5a3 3 0 0 1 0 5.8M17 14a5 5 0 0 1 4 4.9" })
|
|
35
|
+
] }), ie = (a) => /* @__PURE__ */ e(f, { ...a, children: /* @__PURE__ */ e("path", { d: "M10 13a5 5 0 0 0 7.5.5l2-2a5 5 0 0 0-7-7l-1.2 1.2M14 11a5 5 0 0 0-7.5-.5l-2 2a5 5 0 0 0 7 7l1.2-1.2" }) }), se = (a) => /* @__PURE__ */ e(f, { ...a, children: /* @__PURE__ */ e("path", { d: "M4.5 5.5c0 7.7 6.3 14 14 14l2-4.1-4.5-2-1.7 2a11 11 0 0 1-5.7-5.7l2-1.7-2-4.5Z" }) }), re = (a) => /* @__PURE__ */ e(f, { ...a, children: /* @__PURE__ */ e("path", { d: "m21 3-8.5 18-2.3-7.2L3 11.5ZM10.2 13.8 21 3" }) }), E = (a) => /* @__PURE__ */ e(f, { ...a, children: /* @__PURE__ */ e("path", { d: "m6 6 12 12M18 6 6 18" }) });
|
|
36
|
+
function V(a) {
|
|
37
|
+
return `${a.participant.identity}:${a.source}`;
|
|
38
|
+
}
|
|
39
|
+
function le(a) {
|
|
40
|
+
const i = Math.max(1, Math.ceil(Math.sqrt(a)));
|
|
41
|
+
return {
|
|
42
|
+
columns: i,
|
|
43
|
+
rows: Math.max(1, Math.ceil(a / i))
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function oe(a, i) {
|
|
47
|
+
if (a.isLocal) return i ?? "participant";
|
|
48
|
+
try {
|
|
49
|
+
return JSON.parse(a.metadata ?? "{}").role ?? a.attributes["quickmeet.role"] ?? "participant";
|
|
50
|
+
} catch {
|
|
51
|
+
return a.attributes["quickmeet.role"] ?? "participant";
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function J({ name: a }) {
|
|
55
|
+
const i = a.split(/\s+/).slice(0, 2).map((s) => {
|
|
56
|
+
var c;
|
|
57
|
+
return (c = s[0]) == null ? void 0 : c.toUpperCase();
|
|
58
|
+
}).join("");
|
|
59
|
+
return /* @__PURE__ */ e("span", { className: "qm-avatar", children: i || "?" });
|
|
60
|
+
}
|
|
61
|
+
function x({
|
|
62
|
+
active: a,
|
|
63
|
+
danger: i,
|
|
64
|
+
disabled: s,
|
|
65
|
+
label: c,
|
|
66
|
+
children: l,
|
|
67
|
+
onClick: o
|
|
68
|
+
}) {
|
|
69
|
+
return /* @__PURE__ */ n(
|
|
70
|
+
"button",
|
|
71
|
+
{
|
|
72
|
+
type: "button",
|
|
73
|
+
className: [
|
|
74
|
+
"qm-control",
|
|
75
|
+
a ? "is-active" : "",
|
|
76
|
+
i ? "is-danger" : ""
|
|
77
|
+
].filter(Boolean).join(" "),
|
|
78
|
+
disabled: s,
|
|
79
|
+
onClick: o,
|
|
80
|
+
"aria-label": c,
|
|
81
|
+
title: c,
|
|
82
|
+
children: [
|
|
83
|
+
/* @__PURE__ */ e("span", { className: "qm-control-icon", children: l }),
|
|
84
|
+
/* @__PURE__ */ e("span", { children: c })
|
|
85
|
+
]
|
|
86
|
+
}
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
function de({ onClose: a }) {
|
|
90
|
+
const { chatMessages: i, send: s, isSending: c } = z(), [l, o] = q(""), m = X(null);
|
|
91
|
+
O(() => {
|
|
92
|
+
var t;
|
|
93
|
+
(t = m.current) == null || t.scrollTo({ top: m.current.scrollHeight });
|
|
94
|
+
}, [i]);
|
|
95
|
+
async function u(t) {
|
|
96
|
+
t.preventDefault();
|
|
97
|
+
const p = l.trim();
|
|
98
|
+
!p || c || (o(""), await s(p));
|
|
99
|
+
}
|
|
100
|
+
return /* @__PURE__ */ n("aside", { className: "qm-side-panel", "aria-label": "Meeting chat", children: [
|
|
101
|
+
/* @__PURE__ */ n("header", { className: "qm-panel-header", children: [
|
|
102
|
+
/* @__PURE__ */ n("div", { children: [
|
|
103
|
+
/* @__PURE__ */ e("span", { className: "qm-eyebrow", children: "In the room" }),
|
|
104
|
+
/* @__PURE__ */ e("h2", { children: "Messages" })
|
|
105
|
+
] }),
|
|
106
|
+
/* @__PURE__ */ e("button", { type: "button", className: "qm-icon-button", onClick: a, "aria-label": "Close chat", children: /* @__PURE__ */ e(E, {}) })
|
|
107
|
+
] }),
|
|
108
|
+
/* @__PURE__ */ e("div", { className: "qm-chat-list", ref: m, children: i.length === 0 ? /* @__PURE__ */ n("div", { className: "qm-empty-state", children: [
|
|
109
|
+
/* @__PURE__ */ e(Z, {}),
|
|
110
|
+
/* @__PURE__ */ e("strong", { children: "Start the conversation" }),
|
|
111
|
+
/* @__PURE__ */ e("span", { children: "Messages are shared with everyone in this meeting." })
|
|
112
|
+
] }) : i.map((t) => {
|
|
113
|
+
var p, g, b;
|
|
114
|
+
return /* @__PURE__ */ n("div", { className: "qm-chat-message", children: [
|
|
115
|
+
/* @__PURE__ */ e(J, { name: ((p = t.from) == null ? void 0 : p.name) ?? "Guest" }),
|
|
116
|
+
/* @__PURE__ */ n("div", { children: [
|
|
117
|
+
/* @__PURE__ */ n("div", { className: "qm-message-meta", children: [
|
|
118
|
+
/* @__PURE__ */ e("strong", { children: (g = t.from) != null && g.isLocal ? "You" : ((b = t.from) == null ? void 0 : b.name) ?? "Guest" }),
|
|
119
|
+
/* @__PURE__ */ e("time", { children: new Date(t.timestamp).toLocaleTimeString([], {
|
|
120
|
+
hour: "2-digit",
|
|
121
|
+
minute: "2-digit"
|
|
122
|
+
}) })
|
|
123
|
+
] }),
|
|
124
|
+
/* @__PURE__ */ e("p", { children: t.message })
|
|
125
|
+
] })
|
|
126
|
+
] }, t.id);
|
|
127
|
+
}) }),
|
|
128
|
+
/* @__PURE__ */ n("form", { className: "qm-chat-form", onSubmit: u, children: [
|
|
129
|
+
/* @__PURE__ */ e(
|
|
130
|
+
"input",
|
|
131
|
+
{
|
|
132
|
+
value: l,
|
|
133
|
+
onChange: (t) => o(t.target.value),
|
|
134
|
+
placeholder: "Write a message…",
|
|
135
|
+
"aria-label": "Chat message",
|
|
136
|
+
maxLength: 2e3
|
|
137
|
+
}
|
|
138
|
+
),
|
|
139
|
+
/* @__PURE__ */ e("button", { type: "submit", disabled: !l.trim() || c, "aria-label": "Send message", children: /* @__PURE__ */ e(re, {}) })
|
|
140
|
+
] })
|
|
141
|
+
] });
|
|
142
|
+
}
|
|
143
|
+
function he({
|
|
144
|
+
localRole: a,
|
|
145
|
+
onClose: i
|
|
146
|
+
}) {
|
|
147
|
+
const s = H();
|
|
148
|
+
return /* @__PURE__ */ n("aside", { className: "qm-side-panel", "aria-label": "Meeting participants", children: [
|
|
149
|
+
/* @__PURE__ */ n("header", { className: "qm-panel-header", children: [
|
|
150
|
+
/* @__PURE__ */ n("div", { children: [
|
|
151
|
+
/* @__PURE__ */ n("span", { className: "qm-eyebrow", children: [
|
|
152
|
+
s.length,
|
|
153
|
+
" connected"
|
|
154
|
+
] }),
|
|
155
|
+
/* @__PURE__ */ e("h2", { children: "People" })
|
|
156
|
+
] }),
|
|
157
|
+
/* @__PURE__ */ e("button", { type: "button", className: "qm-icon-button", onClick: i, "aria-label": "Close people", children: /* @__PURE__ */ e(E, {}) })
|
|
158
|
+
] }),
|
|
159
|
+
/* @__PURE__ */ e("div", { className: "qm-people-list", children: s.map((c) => {
|
|
160
|
+
var o;
|
|
161
|
+
const l = oe(c, a);
|
|
162
|
+
return /* @__PURE__ */ n("div", { className: "qm-person", children: [
|
|
163
|
+
/* @__PURE__ */ e(J, { name: c.name ?? c.identity }),
|
|
164
|
+
/* @__PURE__ */ n("div", { children: [
|
|
165
|
+
/* @__PURE__ */ n("strong", { children: [
|
|
166
|
+
c.name ?? c.identity,
|
|
167
|
+
c.isLocal ? " (you)" : ""
|
|
168
|
+
] }),
|
|
169
|
+
/* @__PURE__ */ e("span", { children: l === "cohost" ? "Co-host" : ((o = l[0]) == null ? void 0 : o.toUpperCase()) + l.slice(1) })
|
|
170
|
+
] }),
|
|
171
|
+
/* @__PURE__ */ e("span", { className: `qm-status-dot ${c.isSpeaking ? "is-speaking" : ""}` })
|
|
172
|
+
] }, c.identity);
|
|
173
|
+
}) })
|
|
174
|
+
] });
|
|
175
|
+
}
|
|
176
|
+
function me({
|
|
177
|
+
credentials: a,
|
|
178
|
+
brandName: i,
|
|
179
|
+
inviteUrl: s,
|
|
180
|
+
connectionState: c,
|
|
181
|
+
onLeave: l,
|
|
182
|
+
onError: o
|
|
183
|
+
}) {
|
|
184
|
+
var G;
|
|
185
|
+
const m = A([
|
|
186
|
+
{ source: k.Source.Camera, withPlaceholder: !0 },
|
|
187
|
+
{ source: k.Source.ScreenShare, withPlaceholder: !1 }
|
|
188
|
+
], { onlySubscribed: !1 }), u = H(), {
|
|
189
|
+
localParticipant: t,
|
|
190
|
+
isCameraEnabled: p,
|
|
191
|
+
isMicrophoneEnabled: g,
|
|
192
|
+
isScreenShareEnabled: b
|
|
193
|
+
} = K(), [r, C] = q(null), [y, S] = q(!1), [d, P] = q(null), v = a.meeting.features, M = U(
|
|
194
|
+
() => m.filter((h) => h.source === k.Source.Camera),
|
|
195
|
+
[m]
|
|
196
|
+
), j = U(
|
|
197
|
+
() => m.find((h) => h.source === k.Source.ScreenShare),
|
|
198
|
+
[m]
|
|
199
|
+
), D = le(M.length), R = M.slice(0, 4), I = Math.max(0, M.length - R.length);
|
|
200
|
+
async function T(h, L) {
|
|
201
|
+
P(h);
|
|
202
|
+
try {
|
|
203
|
+
await L();
|
|
204
|
+
} catch ($) {
|
|
205
|
+
o == null || o($ instanceof Error ? $ : new Error(String($)));
|
|
206
|
+
} finally {
|
|
207
|
+
P(null);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
async function Q() {
|
|
211
|
+
const h = s ?? window.location.href;
|
|
212
|
+
await navigator.clipboard.writeText(h), S(!0), window.setTimeout(() => S(!1), 1800);
|
|
213
|
+
}
|
|
214
|
+
return /* @__PURE__ */ n("div", { className: `qm-conference ${r ? "has-panel" : ""}`, children: [
|
|
215
|
+
/* @__PURE__ */ n("header", { className: "qm-topbar", children: [
|
|
216
|
+
/* @__PURE__ */ n("div", { className: "qm-brand", children: [
|
|
217
|
+
/* @__PURE__ */ n("span", { className: "qm-brand-mark", "aria-hidden": "true", children: [
|
|
218
|
+
/* @__PURE__ */ e("i", {}),
|
|
219
|
+
/* @__PURE__ */ e("i", {}),
|
|
220
|
+
/* @__PURE__ */ e("i", {})
|
|
221
|
+
] }),
|
|
222
|
+
/* @__PURE__ */ e("span", { children: i })
|
|
223
|
+
] }),
|
|
224
|
+
/* @__PURE__ */ n("div", { className: "qm-meeting-title", children: [
|
|
225
|
+
/* @__PURE__ */ e("strong", { children: a.meeting.name }),
|
|
226
|
+
/* @__PURE__ */ n("span", { className: `qm-connection ${c === N.Connected ? "is-live" : ""}`, children: [
|
|
227
|
+
/* @__PURE__ */ e("i", {}),
|
|
228
|
+
c === N.Connected ? "Live" : c
|
|
229
|
+
] })
|
|
230
|
+
] }),
|
|
231
|
+
/* @__PURE__ */ n("div", { className: "qm-top-actions", children: [
|
|
232
|
+
s && /* @__PURE__ */ n("button", { type: "button", className: "qm-copy-button", onClick: Q, children: [
|
|
233
|
+
/* @__PURE__ */ e(ie, {}),
|
|
234
|
+
/* @__PURE__ */ e("span", { children: y ? "Copied" : "Invite" })
|
|
235
|
+
] }),
|
|
236
|
+
/* @__PURE__ */ e("span", { className: "qm-role-pill", children: a.participant.role === "cohost" ? "Co-host" : ((G = a.participant.role[0]) == null ? void 0 : G.toUpperCase()) + a.participant.role.slice(1) })
|
|
237
|
+
] })
|
|
238
|
+
] }),
|
|
239
|
+
/* @__PURE__ */ n("main", { className: "qm-stage", children: [
|
|
240
|
+
j ? /* @__PURE__ */ n("div", { className: "qm-presentation-layout", children: [
|
|
241
|
+
/* @__PURE__ */ e(
|
|
242
|
+
B,
|
|
243
|
+
{
|
|
244
|
+
trackRef: j,
|
|
245
|
+
className: "qm-screen-tile"
|
|
246
|
+
}
|
|
247
|
+
),
|
|
248
|
+
/* @__PURE__ */ e("aside", { className: "qm-participant-rail", "aria-label": "Participant videos", children: R.map((h, L) => /* @__PURE__ */ n("div", { className: "qm-rail-item", children: [
|
|
249
|
+
/* @__PURE__ */ e(B, { trackRef: h }),
|
|
250
|
+
L === R.length - 1 && I > 0 && /* @__PURE__ */ n(
|
|
251
|
+
"span",
|
|
252
|
+
{
|
|
253
|
+
className: "qm-overflow-badge",
|
|
254
|
+
"aria-label": `${I} more participants`,
|
|
255
|
+
children: [
|
|
256
|
+
"+",
|
|
257
|
+
I,
|
|
258
|
+
" more"
|
|
259
|
+
]
|
|
260
|
+
}
|
|
261
|
+
)
|
|
262
|
+
] }, V(h))) })
|
|
263
|
+
] }) : /* @__PURE__ */ e(
|
|
264
|
+
"div",
|
|
265
|
+
{
|
|
266
|
+
className: "qm-grid",
|
|
267
|
+
style: {
|
|
268
|
+
gridTemplateColumns: `repeat(${D.columns}, minmax(0, 1fr))`,
|
|
269
|
+
gridTemplateRows: `repeat(${D.rows}, minmax(0, 1fr))`
|
|
270
|
+
},
|
|
271
|
+
children: M.map((h) => /* @__PURE__ */ e(B, { trackRef: h }, V(h)))
|
|
272
|
+
}
|
|
273
|
+
),
|
|
274
|
+
/* @__PURE__ */ e(Y, {}),
|
|
275
|
+
c !== N.Connected && /* @__PURE__ */ n("div", { className: "qm-connecting", children: [
|
|
276
|
+
/* @__PURE__ */ e("span", { className: "qm-spinner" }),
|
|
277
|
+
/* @__PURE__ */ e("strong", { children: c === N.Reconnecting ? "Reconnecting…" : "Joining the room…" })
|
|
278
|
+
] })
|
|
279
|
+
] }),
|
|
280
|
+
r === "chat" && v.chat && /* @__PURE__ */ e(de, { onClose: () => C(null) }),
|
|
281
|
+
r === "people" && /* @__PURE__ */ e(
|
|
282
|
+
he,
|
|
283
|
+
{
|
|
284
|
+
localRole: a.participant.role,
|
|
285
|
+
onClose: () => C(null)
|
|
286
|
+
}
|
|
287
|
+
),
|
|
288
|
+
/* @__PURE__ */ n("footer", { className: "qm-toolbar", children: [
|
|
289
|
+
/* @__PURE__ */ e("div", { className: "qm-toolbar-spacer", children: /* @__PURE__ */ n("span", { children: [
|
|
290
|
+
u.length,
|
|
291
|
+
" ",
|
|
292
|
+
u.length === 1 ? "person" : "people"
|
|
293
|
+
] }) }),
|
|
294
|
+
/* @__PURE__ */ n("div", { className: "qm-main-controls", children: [
|
|
295
|
+
v.microphone && /* @__PURE__ */ e(
|
|
296
|
+
x,
|
|
297
|
+
{
|
|
298
|
+
active: !g,
|
|
299
|
+
disabled: d === "microphone",
|
|
300
|
+
label: g ? "Mute" : "Unmute",
|
|
301
|
+
onClick: () => T(
|
|
302
|
+
"microphone",
|
|
303
|
+
() => t.setMicrophoneEnabled(!g)
|
|
304
|
+
),
|
|
305
|
+
children: g ? /* @__PURE__ */ e(_, {}) : /* @__PURE__ */ e(ee, {})
|
|
306
|
+
}
|
|
307
|
+
),
|
|
308
|
+
v.camera && /* @__PURE__ */ e(
|
|
309
|
+
x,
|
|
310
|
+
{
|
|
311
|
+
active: !p,
|
|
312
|
+
disabled: d === "camera",
|
|
313
|
+
label: p ? "Stop video" : "Start video",
|
|
314
|
+
onClick: () => T(
|
|
315
|
+
"camera",
|
|
316
|
+
() => t.setCameraEnabled(!p)
|
|
317
|
+
),
|
|
318
|
+
children: p ? /* @__PURE__ */ e(ae, {}) : /* @__PURE__ */ e(ne, {})
|
|
319
|
+
}
|
|
320
|
+
),
|
|
321
|
+
v.screenShare && /* @__PURE__ */ e(
|
|
322
|
+
x,
|
|
323
|
+
{
|
|
324
|
+
active: b,
|
|
325
|
+
disabled: d === "screen",
|
|
326
|
+
label: b ? "Stop sharing" : "Share screen",
|
|
327
|
+
onClick: () => T(
|
|
328
|
+
"screen",
|
|
329
|
+
() => t.setScreenShareEnabled(!b)
|
|
330
|
+
),
|
|
331
|
+
children: /* @__PURE__ */ e(te, {})
|
|
332
|
+
}
|
|
333
|
+
),
|
|
334
|
+
/* @__PURE__ */ e(x, { danger: !0, label: "Leave", onClick: l, children: /* @__PURE__ */ e(se, {}) })
|
|
335
|
+
] }),
|
|
336
|
+
/* @__PURE__ */ n("div", { className: "qm-secondary-controls", children: [
|
|
337
|
+
/* @__PURE__ */ n(
|
|
338
|
+
"button",
|
|
339
|
+
{
|
|
340
|
+
type: "button",
|
|
341
|
+
className: r === "people" ? "is-active" : "",
|
|
342
|
+
onClick: () => C(r === "people" ? null : "people"),
|
|
343
|
+
"aria-label": "Show people",
|
|
344
|
+
children: [
|
|
345
|
+
/* @__PURE__ */ e(ce, {}),
|
|
346
|
+
/* @__PURE__ */ e("span", { children: u.length })
|
|
347
|
+
]
|
|
348
|
+
}
|
|
349
|
+
),
|
|
350
|
+
v.chat && /* @__PURE__ */ e(
|
|
351
|
+
"button",
|
|
352
|
+
{
|
|
353
|
+
type: "button",
|
|
354
|
+
className: r === "chat" ? "is-active" : "",
|
|
355
|
+
onClick: () => C(r === "chat" ? null : "chat"),
|
|
356
|
+
"aria-label": "Show chat",
|
|
357
|
+
children: /* @__PURE__ */ e(Z, {})
|
|
358
|
+
}
|
|
359
|
+
)
|
|
360
|
+
] })
|
|
361
|
+
] })
|
|
362
|
+
] });
|
|
363
|
+
}
|
|
364
|
+
function ve({
|
|
365
|
+
credentials: a,
|
|
366
|
+
initialCameraEnabled: i = !0,
|
|
367
|
+
initialMicrophoneEnabled: s = !0,
|
|
368
|
+
className: c = "",
|
|
369
|
+
brandName: l = "QuickMeet",
|
|
370
|
+
inviteUrl: o,
|
|
371
|
+
onLeave: m,
|
|
372
|
+
onError: u
|
|
373
|
+
}) {
|
|
374
|
+
const [t] = q(() => new F({
|
|
375
|
+
adaptiveStream: !0,
|
|
376
|
+
dynacast: !0
|
|
377
|
+
})), [p, g] = q(t.state);
|
|
378
|
+
O(() => {
|
|
379
|
+
let r = !0;
|
|
380
|
+
const C = (d) => {
|
|
381
|
+
r && g(d);
|
|
382
|
+
}, y = () => {
|
|
383
|
+
r && g(N.Disconnected);
|
|
384
|
+
};
|
|
385
|
+
t.on(w.ConnectionStateChanged, C), t.on(w.Disconnected, y);
|
|
386
|
+
async function S() {
|
|
387
|
+
if (await t.disconnect(), !r || (await t.connect(a.serverUrl, a.participantToken), !r)) return;
|
|
388
|
+
const d = [];
|
|
389
|
+
a.meeting.features.camera && i && d.push(t.localParticipant.setCameraEnabled(!0)), a.meeting.features.microphone && s && d.push(t.localParticipant.setMicrophoneEnabled(!0));
|
|
390
|
+
const v = (await Promise.allSettled(d)).find((M) => M.status === "rejected");
|
|
391
|
+
if ((v == null ? void 0 : v.status) === "rejected")
|
|
392
|
+
throw v.reason;
|
|
393
|
+
}
|
|
394
|
+
return S().catch((d) => {
|
|
395
|
+
r && (u == null || u(d instanceof Error ? d : new Error(String(d))));
|
|
396
|
+
}), () => {
|
|
397
|
+
r = !1, t.off(w.ConnectionStateChanged, C), t.off(w.Disconnected, y), t.disconnect();
|
|
398
|
+
};
|
|
399
|
+
}, [
|
|
400
|
+
a,
|
|
401
|
+
i,
|
|
402
|
+
s,
|
|
403
|
+
u,
|
|
404
|
+
t
|
|
405
|
+
]);
|
|
406
|
+
function b() {
|
|
407
|
+
t.disconnect(), m == null || m();
|
|
408
|
+
}
|
|
409
|
+
return /* @__PURE__ */ e("div", { className: `qm-root ${c}`, children: /* @__PURE__ */ e(W.Provider, { value: t, children: /* @__PURE__ */ e(
|
|
410
|
+
me,
|
|
411
|
+
{
|
|
412
|
+
credentials: a,
|
|
413
|
+
brandName: l,
|
|
414
|
+
inviteUrl: o,
|
|
415
|
+
connectionState: p,
|
|
416
|
+
onLeave: b,
|
|
417
|
+
onError: u
|
|
418
|
+
}
|
|
419
|
+
) }) });
|
|
420
|
+
}
|
|
421
|
+
export {
|
|
422
|
+
ve as QuickMeetConference
|
|
423
|
+
};
|
|
424
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/icons.tsx","../src/QuickMeetConference.tsx"],"sourcesContent":["import type { SVGProps } from 'react';\n\ntype IconProps = SVGProps<SVGSVGElement>;\n\nfunction IconBase({ children, ...props }: IconProps) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n width=\"20\"\n height=\"20\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.8\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n {...props}\n >\n {children}\n </svg>\n );\n}\n\nexport const MicIcon = (props: IconProps) => (\n <IconBase {...props}>\n <rect x=\"9\" y=\"3\" width=\"6\" height=\"12\" rx=\"3\" />\n <path d=\"M5.5 11.5a6.5 6.5 0 0 0 13 0M12 18v3M8.5 21h7\" />\n </IconBase>\n);\n\nexport const MicOffIcon = (props: IconProps) => (\n <IconBase {...props}>\n <path d=\"m3 3 18 18M9 5.5V12a3 3 0 0 0 4.8 2.4M15 10.5V6a3 3 0 0 0-5.1-2.1M5.5 11.5a6.5 6.5 0 0 0 10.8 4.9M18.5 11.5a6.5 6.5 0 0 1-.5 2.5M12 18v3M8.5 21h7\" />\n </IconBase>\n);\n\nexport const CameraIcon = (props: IconProps) => (\n <IconBase {...props}>\n <rect x=\"3\" y=\"6.5\" width=\"13\" height=\"11\" rx=\"2\" />\n <path d=\"m16 10 5-2.5v9L16 14\" />\n </IconBase>\n);\n\nexport const CameraOffIcon = (props: IconProps) => (\n <IconBase {...props}>\n <path d=\"m3 3 18 18M10.5 6.5H5a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h11M16 10l5-2.5v9l-2.5-1.25M14 6.5a2 2 0 0 1 2 2V14\" />\n </IconBase>\n);\n\nexport const ScreenIcon = (props: IconProps) => (\n <IconBase {...props}>\n <rect x=\"3\" y=\"4\" width=\"18\" height=\"13\" rx=\"2\" />\n <path d=\"M8 21h8M12 17v4M9 9l3-3 3 3M12 6v7\" />\n </IconBase>\n);\n\nexport const ChatIcon = (props: IconProps) => (\n <IconBase {...props}>\n <path d=\"M20 14a3 3 0 0 1-3 3H9l-5 4v-4a3 3 0 0 1-2-3V6a3 3 0 0 1 3-3h12a3 3 0 0 1 3 3Z\" />\n </IconBase>\n);\n\nexport const PeopleIcon = (props: IconProps) => (\n <IconBase {...props}>\n <circle cx=\"9\" cy=\"8\" r=\"3\" />\n <path d=\"M3 20a6 6 0 0 1 12 0M16 4.5a3 3 0 0 1 0 5.8M17 14a5 5 0 0 1 4 4.9\" />\n </IconBase>\n);\n\nexport const LinkIcon = (props: IconProps) => (\n <IconBase {...props}>\n <path d=\"M10 13a5 5 0 0 0 7.5.5l2-2a5 5 0 0 0-7-7l-1.2 1.2M14 11a5 5 0 0 0-7.5-.5l-2 2a5 5 0 0 0 7 7l1.2-1.2\" />\n </IconBase>\n);\n\nexport const PhoneIcon = (props: IconProps) => (\n <IconBase {...props}>\n <path d=\"M4.5 5.5c0 7.7 6.3 14 14 14l2-4.1-4.5-2-1.7 2a11 11 0 0 1-5.7-5.7l2-1.7-2-4.5Z\" />\n </IconBase>\n);\n\nexport const SendIcon = (props: IconProps) => (\n <IconBase {...props}>\n <path d=\"m21 3-8.5 18-2.3-7.2L3 11.5ZM10.2 13.8 21 3\" />\n </IconBase>\n);\n\nexport const CloseIcon = (props: IconProps) => (\n <IconBase {...props}>\n <path d=\"m6 6 12 12M18 6 6 18\" />\n </IconBase>\n);\n","import {\n ParticipantTile,\n RoomAudioRenderer,\n RoomContext,\n type TrackReferenceOrPlaceholder,\n useChat,\n useLocalParticipant,\n useParticipants,\n useTracks,\n} from '@livekit/components-react';\nimport type { JoinCredentials } from '@quickmeet/sdk';\nimport {\n ConnectionState,\n Room,\n RoomEvent,\n Track,\n type Participant,\n} from 'livekit-client';\nimport {\n type FormEvent,\n type ReactNode,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport {\n CameraIcon,\n CameraOffIcon,\n ChatIcon,\n CloseIcon,\n LinkIcon,\n MicIcon,\n MicOffIcon,\n PeopleIcon,\n PhoneIcon,\n ScreenIcon,\n SendIcon,\n} from './icons.js';\n\nexport interface QuickMeetConferenceProps {\n credentials: JoinCredentials;\n initialCameraEnabled?: boolean;\n initialMicrophoneEnabled?: boolean;\n className?: string;\n brandName?: string;\n inviteUrl?: string;\n onLeave?: () => void;\n onError?: (error: Error) => void;\n}\n\ntype QuickMeetSidePanel = 'chat' | 'people' | null;\n\nfunction trackKey(track: TrackReferenceOrPlaceholder): string {\n return `${track.participant.identity}:${track.source}`;\n}\n\nfunction getBalancedGrid(itemCount: number): { columns: number; rows: number } {\n const columns = Math.max(1, Math.ceil(Math.sqrt(itemCount)));\n return {\n columns,\n rows: Math.max(1, Math.ceil(itemCount / columns)),\n };\n}\n\nfunction displayRole(participant: Participant, localRole?: string): string {\n if (participant.isLocal) return localRole ?? 'participant';\n try {\n const metadata = JSON.parse(participant.metadata ?? '{}') as { role?: string };\n return metadata.role ?? participant.attributes['quickmeet.role'] ?? 'participant';\n } catch {\n return participant.attributes['quickmeet.role'] ?? 'participant';\n }\n}\n\nfunction Initials({ name }: { name: string }) {\n const initials = name\n .split(/\\s+/)\n .slice(0, 2)\n .map((part) => part[0]?.toUpperCase())\n .join('');\n return <span className=\"qm-avatar\">{initials || '?'}</span>;\n}\n\nfunction ControlButton({\n active,\n danger,\n disabled,\n label,\n children,\n onClick,\n}: {\n active?: boolean;\n danger?: boolean;\n disabled?: boolean;\n label: string;\n children: ReactNode;\n onClick: () => void;\n}) {\n return (\n <button\n type=\"button\"\n className={[\n 'qm-control',\n active ? 'is-active' : '',\n danger ? 'is-danger' : '',\n ].filter(Boolean).join(' ')}\n disabled={disabled}\n onClick={onClick}\n aria-label={label}\n title={label}\n >\n <span className=\"qm-control-icon\">{children}</span>\n <span>{label}</span>\n </button>\n );\n}\n\nfunction ChatPanel({ onClose }: { onClose: () => void }) {\n const { chatMessages, send, isSending } = useChat();\n const [message, setMessage] = useState('');\n const listRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n listRef.current?.scrollTo({ top: listRef.current.scrollHeight });\n }, [chatMessages]);\n\n async function submit(event: FormEvent) {\n event.preventDefault();\n const trimmed = message.trim();\n if (!trimmed || isSending) return;\n setMessage('');\n await send(trimmed);\n }\n\n return (\n <aside className=\"qm-side-panel\" aria-label=\"Meeting chat\">\n <header className=\"qm-panel-header\">\n <div>\n <span className=\"qm-eyebrow\">In the room</span>\n <h2>Messages</h2>\n </div>\n <button type=\"button\" className=\"qm-icon-button\" onClick={onClose} aria-label=\"Close chat\">\n <CloseIcon />\n </button>\n </header>\n <div className=\"qm-chat-list\" ref={listRef}>\n {chatMessages.length === 0 ? (\n <div className=\"qm-empty-state\">\n <ChatIcon />\n <strong>Start the conversation</strong>\n <span>Messages are shared with everyone in this meeting.</span>\n </div>\n ) : chatMessages.map((item) => (\n <div className=\"qm-chat-message\" key={item.id}>\n <Initials name={item.from?.name ?? 'Guest'} />\n <div>\n <div className=\"qm-message-meta\">\n <strong>{item.from?.isLocal ? 'You' : item.from?.name ?? 'Guest'}</strong>\n <time>{new Date(item.timestamp).toLocaleTimeString([], {\n hour: '2-digit',\n minute: '2-digit',\n })}</time>\n </div>\n <p>{item.message}</p>\n </div>\n </div>\n ))}\n </div>\n <form className=\"qm-chat-form\" onSubmit={submit}>\n <input\n value={message}\n onChange={(event) => setMessage(event.target.value)}\n placeholder=\"Write a message…\"\n aria-label=\"Chat message\"\n maxLength={2000}\n />\n <button type=\"submit\" disabled={!message.trim() || isSending} aria-label=\"Send message\">\n <SendIcon />\n </button>\n </form>\n </aside>\n );\n}\n\nfunction PeoplePanel({\n localRole,\n onClose,\n}: {\n localRole: string;\n onClose: () => void;\n}) {\n const participants = useParticipants();\n return (\n <aside className=\"qm-side-panel\" aria-label=\"Meeting participants\">\n <header className=\"qm-panel-header\">\n <div>\n <span className=\"qm-eyebrow\">{participants.length} connected</span>\n <h2>People</h2>\n </div>\n <button type=\"button\" className=\"qm-icon-button\" onClick={onClose} aria-label=\"Close people\">\n <CloseIcon />\n </button>\n </header>\n <div className=\"qm-people-list\">\n {participants.map((participant) => {\n const role = displayRole(participant, localRole);\n return (\n <div className=\"qm-person\" key={participant.identity}>\n <Initials name={participant.name ?? participant.identity} />\n <div>\n <strong>\n {participant.name ?? participant.identity}\n {participant.isLocal ? ' (you)' : ''}\n </strong>\n <span>{role === 'cohost' ? 'Co-host' : role[0]?.toUpperCase() + role.slice(1)}</span>\n </div>\n <span className={`qm-status-dot ${participant.isSpeaking ? 'is-speaking' : ''}`} />\n </div>\n );\n })}\n </div>\n </aside>\n );\n}\n\nfunction ConnectedConferenceShell({\n credentials,\n brandName,\n inviteUrl,\n connectionState,\n onLeave,\n onError,\n}: {\n credentials: JoinCredentials;\n brandName: string;\n inviteUrl?: string;\n connectionState: ConnectionState;\n onLeave: () => void;\n onError?: (error: Error) => void;\n}) {\n const tracks = useTracks([\n { source: Track.Source.Camera, withPlaceholder: true },\n { source: Track.Source.ScreenShare, withPlaceholder: false },\n ], { onlySubscribed: false });\n const participants = useParticipants();\n const {\n localParticipant,\n isCameraEnabled,\n isMicrophoneEnabled,\n isScreenShareEnabled,\n } = useLocalParticipant();\n const [panel, setPanel] = useState<QuickMeetSidePanel>(null);\n const [copied, setCopied] = useState(false);\n const [mediaBusy, setMediaBusy] = useState<string | null>(null);\n const features = credentials.meeting.features;\n const cameraTracks = useMemo(\n () => tracks.filter((track) => track.source === Track.Source.Camera),\n [tracks],\n );\n const screenTrack = useMemo(\n () => tracks.find((track) => track.source === Track.Source.ScreenShare),\n [tracks],\n );\n const cameraGrid = getBalancedGrid(cameraTracks.length);\n const railTracks = cameraTracks.slice(0, 4);\n const hiddenRailCount = Math.max(0, cameraTracks.length - railTracks.length);\n\n async function toggleMedia(\n kind: 'camera' | 'microphone' | 'screen',\n action: () => Promise<unknown>,\n ) {\n setMediaBusy(kind);\n try {\n await action();\n } catch (error) {\n onError?.(error instanceof Error ? error : new Error(String(error)));\n } finally {\n setMediaBusy(null);\n }\n }\n\n async function copyInvite() {\n const link = inviteUrl ?? window.location.href;\n await navigator.clipboard.writeText(link);\n setCopied(true);\n window.setTimeout(() => setCopied(false), 1800);\n }\n\n return (\n <div className={`qm-conference ${panel ? 'has-panel' : ''}`}>\n <header className=\"qm-topbar\">\n <div className=\"qm-brand\">\n <span className=\"qm-brand-mark\" aria-hidden=\"true\">\n <i />\n <i />\n <i />\n </span>\n <span>{brandName}</span>\n </div>\n <div className=\"qm-meeting-title\">\n <strong>{credentials.meeting.name}</strong>\n <span className={`qm-connection ${connectionState === ConnectionState.Connected ? 'is-live' : ''}`}>\n <i />\n {connectionState === ConnectionState.Connected ? 'Live' : connectionState}\n </span>\n </div>\n <div className=\"qm-top-actions\">\n {inviteUrl && (\n <button type=\"button\" className=\"qm-copy-button\" onClick={copyInvite}>\n <LinkIcon />\n <span>{copied ? 'Copied' : 'Invite'}</span>\n </button>\n )}\n <span className=\"qm-role-pill\">\n {credentials.participant.role === 'cohost'\n ? 'Co-host'\n : credentials.participant.role[0]?.toUpperCase()\n + credentials.participant.role.slice(1)}\n </span>\n </div>\n </header>\n\n <main className=\"qm-stage\">\n {screenTrack ? (\n <div className=\"qm-presentation-layout\">\n <ParticipantTile\n trackRef={screenTrack}\n className=\"qm-screen-tile\"\n />\n <aside className=\"qm-participant-rail\" aria-label=\"Participant videos\">\n {railTracks.map((track, index) => (\n <div className=\"qm-rail-item\" key={trackKey(track)}>\n <ParticipantTile trackRef={track} />\n {index === railTracks.length - 1 && hiddenRailCount > 0 && (\n <span\n className=\"qm-overflow-badge\"\n aria-label={`${hiddenRailCount} more participants`}\n >\n +{hiddenRailCount} more\n </span>\n )}\n </div>\n ))}\n </aside>\n </div>\n ) : (\n <div\n className=\"qm-grid\"\n style={{\n gridTemplateColumns: `repeat(${cameraGrid.columns}, minmax(0, 1fr))`,\n gridTemplateRows: `repeat(${cameraGrid.rows}, minmax(0, 1fr))`,\n }}\n >\n {cameraTracks.map((track) => (\n <ParticipantTile key={trackKey(track)} trackRef={track} />\n ))}\n </div>\n )}\n <RoomAudioRenderer />\n {connectionState !== ConnectionState.Connected && (\n <div className=\"qm-connecting\">\n <span className=\"qm-spinner\" />\n <strong>\n {connectionState === ConnectionState.Reconnecting\n ? 'Reconnecting…'\n : 'Joining the room…'}\n </strong>\n </div>\n )}\n </main>\n\n {panel === 'chat' && features.chat && <ChatPanel onClose={() => setPanel(null)} />}\n {panel === 'people' && (\n <PeoplePanel\n localRole={credentials.participant.role}\n onClose={() => setPanel(null)}\n />\n )}\n\n <footer className=\"qm-toolbar\">\n <div className=\"qm-toolbar-spacer\">\n <span>{participants.length} {participants.length === 1 ? 'person' : 'people'}</span>\n </div>\n <div className=\"qm-main-controls\">\n {features.microphone && (\n <ControlButton\n active={!isMicrophoneEnabled}\n disabled={mediaBusy === 'microphone'}\n label={isMicrophoneEnabled ? 'Mute' : 'Unmute'}\n onClick={() => toggleMedia(\n 'microphone',\n () => localParticipant.setMicrophoneEnabled(!isMicrophoneEnabled),\n )}\n >\n {isMicrophoneEnabled ? <MicIcon /> : <MicOffIcon />}\n </ControlButton>\n )}\n {features.camera && (\n <ControlButton\n active={!isCameraEnabled}\n disabled={mediaBusy === 'camera'}\n label={isCameraEnabled ? 'Stop video' : 'Start video'}\n onClick={() => toggleMedia(\n 'camera',\n () => localParticipant.setCameraEnabled(!isCameraEnabled),\n )}\n >\n {isCameraEnabled ? <CameraIcon /> : <CameraOffIcon />}\n </ControlButton>\n )}\n {features.screenShare && (\n <ControlButton\n active={isScreenShareEnabled}\n disabled={mediaBusy === 'screen'}\n label={isScreenShareEnabled ? 'Stop sharing' : 'Share screen'}\n onClick={() => toggleMedia(\n 'screen',\n () => localParticipant.setScreenShareEnabled(!isScreenShareEnabled),\n )}\n >\n <ScreenIcon />\n </ControlButton>\n )}\n <ControlButton danger label=\"Leave\" onClick={onLeave}>\n <PhoneIcon />\n </ControlButton>\n </div>\n <div className=\"qm-secondary-controls\">\n <button\n type=\"button\"\n className={panel === 'people' ? 'is-active' : ''}\n onClick={() => setPanel(panel === 'people' ? null : 'people')}\n aria-label=\"Show people\"\n >\n <PeopleIcon />\n <span>{participants.length}</span>\n </button>\n {features.chat && (\n <button\n type=\"button\"\n className={panel === 'chat' ? 'is-active' : ''}\n onClick={() => setPanel(panel === 'chat' ? null : 'chat')}\n aria-label=\"Show chat\"\n >\n <ChatIcon />\n </button>\n )}\n </div>\n </footer>\n </div>\n );\n}\n\nexport function QuickMeetConference({\n credentials,\n initialCameraEnabled = true,\n initialMicrophoneEnabled = true,\n className = '',\n brandName = 'QuickMeet',\n inviteUrl,\n onLeave,\n onError,\n}: QuickMeetConferenceProps) {\n const [room] = useState(() => new Room({\n adaptiveStream: true,\n dynacast: true,\n }));\n const [connectionState, setConnectionState] = useState(room.state);\n\n useEffect(() => {\n let active = true;\n\n const handleState = (state: ConnectionState) => {\n if (active) setConnectionState(state);\n };\n const handleDisconnected = () => {\n if (active) setConnectionState(ConnectionState.Disconnected);\n };\n room.on(RoomEvent.ConnectionStateChanged, handleState);\n room.on(RoomEvent.Disconnected, handleDisconnected);\n\n async function connectRoom() {\n await room.disconnect();\n if (!active) return;\n await room.connect(credentials.serverUrl, credentials.participantToken);\n if (!active) return;\n const tasks: Promise<unknown>[] = [];\n if (credentials.meeting.features.camera && initialCameraEnabled) {\n tasks.push(room.localParticipant.setCameraEnabled(true));\n }\n if (credentials.meeting.features.microphone && initialMicrophoneEnabled) {\n tasks.push(room.localParticipant.setMicrophoneEnabled(true));\n }\n const results = await Promise.allSettled(tasks);\n const rejected = results.find((result) => result.status === 'rejected');\n if (rejected?.status === 'rejected') {\n throw rejected.reason;\n }\n }\n\n void connectRoom().catch((error) => {\n if (active) {\n onError?.(error instanceof Error ? error : new Error(String(error)));\n }\n });\n\n return () => {\n active = false;\n room.off(RoomEvent.ConnectionStateChanged, handleState);\n room.off(RoomEvent.Disconnected, handleDisconnected);\n void room.disconnect();\n };\n }, [\n credentials,\n initialCameraEnabled,\n initialMicrophoneEnabled,\n onError,\n room,\n ]);\n\n function leave() {\n void room.disconnect();\n onLeave?.();\n }\n\n return (\n <div className={`qm-root ${className}`}>\n <RoomContext.Provider value={room}>\n <ConnectedConferenceShell\n credentials={credentials}\n brandName={brandName}\n inviteUrl={inviteUrl}\n connectionState={connectionState}\n onLeave={leave}\n onError={onError}\n />\n </RoomContext.Provider>\n </div>\n );\n}\n"],"names":["IconBase","children","props","jsx","MicIcon","jsxs","MicOffIcon","CameraIcon","CameraOffIcon","ScreenIcon","ChatIcon","PeopleIcon","LinkIcon","PhoneIcon","SendIcon","CloseIcon","trackKey","track","getBalancedGrid","itemCount","columns","displayRole","participant","localRole","Initials","name","initials","part","_a","ControlButton","active","danger","disabled","label","onClick","ChatPanel","onClose","chatMessages","send","isSending","useChat","message","setMessage","useState","listRef","useRef","useEffect","submit","event","trimmed","item","_c","PeoplePanel","participants","useParticipants","role","ConnectedConferenceShell","credentials","brandName","inviteUrl","connectionState","onLeave","onError","tracks","useTracks","Track","localParticipant","isCameraEnabled","isMicrophoneEnabled","isScreenShareEnabled","useLocalParticipant","panel","setPanel","copied","setCopied","mediaBusy","setMediaBusy","features","cameraTracks","useMemo","screenTrack","cameraGrid","railTracks","hiddenRailCount","toggleMedia","kind","action","error","copyInvite","link","ConnectionState","ParticipantTile","index","RoomAudioRenderer","QuickMeetConference","initialCameraEnabled","initialMicrophoneEnabled","className","room","Room","setConnectionState","handleState","state","handleDisconnected","RoomEvent","connectRoom","tasks","rejected","result","leave","RoomContext"],"mappings":"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"}
|
package/dist/styles.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@import"https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&family=Manrope:wght@600;700&display=swap";.qm-root{--qm-ink: #f8fafb;--qm-muted: #9ca7b7;--qm-line: rgba(255, 255, 255, .1);--qm-panel: #171c23;--qm-panel-2: #20262f;--qm-stage: #0f1318;--qm-coral: #ff765c;--qm-mint: #7be0bc;min-height:600px;height:100%;color:var(--qm-ink);background:var(--qm-stage);font-family:DM Sans,system-ui,sans-serif;container-type:inline-size}.qm-root *,.qm-root *:before,.qm-root *:after{box-sizing:border-box}.qm-root button,.qm-root input{font:inherit}.qm-conference{display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:68px minmax(0,1fr) 92px;grid-template-areas:"topbar" "stage" "toolbar";width:100%;height:100%;min-height:600px;overflow:hidden;background:radial-gradient(circle at 60% 20%,rgba(90,109,119,.09),transparent 32%),var(--qm-stage)}.qm-conference.has-panel{grid-template-columns:minmax(0,1fr) 340px;grid-template-areas:"topbar topbar" "stage panel" "toolbar panel"}.qm-topbar{grid-area:topbar;z-index:3;display:grid;grid-template-columns:1fr auto 1fr;align-items:center;padding:0 24px;border-bottom:1px solid var(--qm-line);background:#0f1318e6;-webkit-backdrop-filter:blur(16px);backdrop-filter:blur(16px)}.qm-brand,.qm-meeting-title,.qm-top-actions,.qm-copy-button,.qm-connection{display:flex;align-items:center}.qm-brand{gap:10px;font-family:Manrope,sans-serif;font-weight:700;letter-spacing:-.02em}.qm-brand-mark{display:flex;align-items:flex-end;gap:2px;width:21px;height:21px;padding:4px;border-radius:7px;color:#11211d;background:var(--qm-mint)}.qm-brand-mark i{display:block;width:3px;border-radius:3px;background:currentColor}.qm-brand-mark i:nth-child(1){height:6px}.qm-brand-mark i:nth-child(2){height:11px}.qm-brand-mark i:nth-child(3){height:8px}.qm-meeting-title{justify-content:center;gap:12px}.qm-meeting-title strong{max-width:34vw;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:600}.qm-connection{gap:6px;color:var(--qm-muted);font-size:12px;text-transform:capitalize}.qm-connection i{width:7px;height:7px;border-radius:50%;background:#e2b65c}.qm-connection.is-live i{background:var(--qm-mint);box-shadow:0 0 0 4px #7be0bc1a}.qm-top-actions{justify-content:flex-end;gap:10px}.qm-copy-button,.qm-role-pill{border:1px solid var(--qm-line);border-radius:10px;color:var(--qm-ink);background:var(--qm-panel)}.qm-copy-button{gap:7px;height:36px;padding:0 12px;cursor:pointer}.qm-copy-button:hover{border-color:#7be0bc73;background:#1c252b}.qm-copy-button svg{width:17px}.qm-role-pill{padding:8px 11px;color:var(--qm-mint);font-size:12px;font-weight:600}.qm-stage{position:relative;grid-area:stage;min-width:0;min-height:0;padding:18px 22px 14px}.qm-grid{display:grid;width:100%;height:100%;gap:12px}.qm-presentation-layout{display:grid;grid-template-columns:minmax(0,9fr) clamp(104px,10%,150px);width:100%;height:100%;min-width:0;min-height:0;gap:12px}.qm-participant-rail{display:grid;grid-template-rows:repeat(4,minmax(0,1fr));min-width:0;min-height:0;gap:10px}.qm-rail-item{position:relative;min-width:0;min-height:0}.qm-rail-item>.lk-participant-tile{width:100%;height:100%}.qm-stage .lk-participant-tile{position:relative;min-width:0;min-height:0;overflow:hidden;border:1px solid rgba(255,255,255,.07);border-radius:18px;background:linear-gradient(145deg,#35404bad,#191f26f2);box-shadow:0 12px 34px #0000002e}.qm-stage .lk-participant-tile[data-lk-speaking=true]{border-color:#7be0bcd9;box-shadow:0 0 0 2px #7be0bc1a}.qm-stage .lk-participant-media-video,.qm-stage video{width:100%;height:100%;object-fit:cover}.qm-stage .qm-screen-tile video{object-fit:contain;background:#080a0d}.qm-stage .qm-screen-tile{border-radius:14px;background:#080a0d}.qm-participant-rail .lk-participant-tile{border-radius:12px}.qm-stage .qm-participant-rail .lk-participant-placeholder{width:44px;height:44px}.qm-stage .qm-participant-rail .lk-participant-metadata{right:6px;bottom:6px;left:6px;padding:5px 6px}.qm-stage .qm-participant-rail .lk-participant-name{max-width:100%;overflow:hidden;font-size:10px;text-overflow:ellipsis;white-space:nowrap}.qm-overflow-badge{position:absolute;top:6px;right:6px;z-index:2;padding:4px 6px;border:1px solid rgba(255,255,255,.12);border-radius:7px;color:#fff;background:#080a0dc7;-webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px);font-size:10px;font-weight:700;white-space:nowrap}.qm-stage .lk-participant-placeholder{width:92px;height:92px;color:#ffffffb3}.qm-stage .lk-participant-metadata{position:absolute;right:12px;bottom:12px;left:12px;display:flex;align-items:center;justify-content:space-between;padding:8px 10px;border:1px solid rgba(255,255,255,.08);border-radius:10px;background:#0a0d11a6;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px)}.qm-stage .lk-participant-name{font-size:13px;font-weight:600}.qm-stage .lk-participant-metadata-item{display:flex;align-items:center}.qm-stage .lk-focus-toggle-button,.qm-stage .lk-connection-quality{display:none}.qm-connecting{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;background:#0f1318d1;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px)}.qm-spinner{width:30px;height:30px;border:2px solid rgba(255,255,255,.15);border-top-color:var(--qm-mint);border-radius:50%;animation:qm-spin .8s linear infinite}@keyframes qm-spin{to{transform:rotate(360deg)}}.qm-toolbar{grid-area:toolbar;display:grid;grid-template-columns:1fr auto 1fr;align-items:center;padding:12px 24px 18px;border-top:1px solid var(--qm-line);background:#12171d}.qm-toolbar-spacer{color:var(--qm-muted);font-size:13px}.qm-main-controls,.qm-secondary-controls{display:flex;align-items:center;gap:9px}.qm-control{display:flex;flex-direction:column;align-items:center;gap:5px;min-width:62px;border:0;color:var(--qm-muted);background:transparent;font-size:11px;cursor:pointer}.qm-control-icon{display:grid;width:43px;height:43px;place-items:center;border:1px solid var(--qm-line);border-radius:13px;color:var(--qm-ink);background:var(--qm-panel-2);transition:transform .15s ease,background .15s ease}.qm-control:hover .qm-control-icon{transform:translateY(-2px);background:#2a323d}.qm-control.is-active .qm-control-icon{color:#ffd8d0;background:#ff765c2e;border-color:#ff765c59}.qm-control.is-danger .qm-control-icon{color:#fff;background:var(--qm-coral);border-color:transparent}.qm-control:disabled{opacity:.5;cursor:wait}.qm-secondary-controls{justify-content:flex-end}.qm-secondary-controls button,.qm-icon-button{display:inline-flex;align-items:center;justify-content:center;gap:5px;min-width:40px;height:40px;border:1px solid var(--qm-line);border-radius:11px;color:var(--qm-muted);background:var(--qm-panel);cursor:pointer}.qm-secondary-controls button.is-active,.qm-secondary-controls button:hover,.qm-icon-button:hover{color:var(--qm-mint);border-color:#7be0bc4d}.qm-side-panel{grid-area:panel;z-index:4;display:flex;flex-direction:column;min-width:0;border-left:1px solid var(--qm-line);background:#171c23}.qm-panel-header{display:flex;align-items:center;justify-content:space-between;min-height:86px;padding:18px 20px;border-bottom:1px solid var(--qm-line)}.qm-panel-header h2{margin:3px 0 0;font-family:Manrope,sans-serif;font-size:20px;letter-spacing:-.03em}.qm-eyebrow{color:var(--qm-mint);font-size:10px;font-weight:700;letter-spacing:.12em;text-transform:uppercase}.qm-icon-button{min-width:36px;height:36px}.qm-chat-list,.qm-people-list{flex:1;min-height:0;overflow-y:auto}.qm-chat-list{padding:18px}.qm-empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:100%;padding:30px;color:var(--qm-muted);text-align:center}.qm-empty-state svg{width:28px;height:28px;margin-bottom:14px;color:var(--qm-mint)}.qm-empty-state strong{margin-bottom:5px;color:var(--qm-ink)}.qm-empty-state span{font-size:13px;line-height:1.5}.qm-chat-message{display:grid;grid-template-columns:34px 1fr;gap:10px;margin-bottom:18px}.qm-avatar{display:inline-grid;width:34px;height:34px;place-items:center;flex:0 0 auto;border:1px solid rgba(123,224,188,.18);border-radius:10px;color:var(--qm-mint);background:#7be0bc17;font-size:11px;font-weight:700}.qm-message-meta{display:flex;align-items:baseline;justify-content:space-between;gap:8px}.qm-message-meta strong{font-size:13px}.qm-message-meta time{color:#737d8b;font-size:10px}.qm-chat-message p{margin:4px 0 0;color:#c7ced8;font-size:13px;line-height:1.45;overflow-wrap:anywhere}.qm-chat-form{display:grid;grid-template-columns:1fr 40px;gap:8px;padding:16px;border-top:1px solid var(--qm-line)}.qm-chat-form input{min-width:0;height:42px;padding:0 12px;border:1px solid var(--qm-line);border-radius:11px;outline:none;color:var(--qm-ink);background:#10151a}.qm-chat-form input:focus{border-color:#7be0bc73}.qm-chat-form button{display:grid;border:0;border-radius:11px;place-items:center;color:#0d241d;background:var(--qm-mint);cursor:pointer}.qm-chat-form button:disabled{opacity:.35;cursor:not-allowed}.qm-people-list{padding:10px}.qm-person{display:grid;grid-template-columns:38px 1fr 10px;align-items:center;gap:10px;padding:11px 10px;border-radius:12px}.qm-person:hover{background:#ffffff09}.qm-person strong,.qm-person span{display:block}.qm-person strong{font-size:13px}.qm-person div>span{margin-top:2px;color:var(--qm-muted);font-size:11px}.qm-status-dot{width:7px;height:7px;border-radius:50%;background:#596270}.qm-status-dot.is-speaking{background:var(--qm-mint);box-shadow:0 0 0 4px #7be0bc1a}@container (max-width: 820px){.qm-conference.has-panel{grid-template-columns:minmax(0,1fr);grid-template-areas:"topbar" "stage" "toolbar"}.qm-side-panel{position:absolute;z-index:10;inset:68px 0 0 auto;width:min(340px,90%);box-shadow:-20px 0 50px #00000040}.qm-topbar{grid-template-columns:1fr auto}.qm-meeting-title{display:none}.qm-toolbar{grid-template-columns:auto 1fr;padding-inline:12px}.qm-toolbar-spacer{display:none}.qm-main-controls{justify-content:flex-start;overflow-x:auto}.qm-secondary-controls{margin-left:8px}.qm-control{min-width:52px}}@container (max-width: 520px){.qm-root,.qm-conference{min-height:520px}.qm-topbar{padding:0 14px}.qm-copy-button span,.qm-role-pill{display:none}.qm-copy-button{width:38px;padding:0;justify-content:center}.qm-stage{padding:10px}.qm-grid,.qm-presentation-layout{gap:7px}.qm-presentation-layout{grid-template-columns:minmax(0,1fr) 88px}.qm-participant-rail{gap:7px}.qm-stage .qm-participant-rail .lk-participant-metadata{display:none}.qm-main-controls{gap:3px}.qm-control{min-width:46px;font-size:9px}.qm-control-icon{width:38px;height:38px}.qm-secondary-controls button{min-width:36px}}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@quickmeet/react",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Drop-in React video conference UI for QuickMeet",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"quickmeet",
|
|
8
|
+
"react",
|
|
9
|
+
"video-conferencing",
|
|
10
|
+
"webrtc",
|
|
11
|
+
"livekit"
|
|
12
|
+
],
|
|
13
|
+
"type": "module",
|
|
14
|
+
"sideEffects": [
|
|
15
|
+
"./dist/styles.css"
|
|
16
|
+
],
|
|
17
|
+
"main": "./dist/index.js",
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"import": "./dist/index.js"
|
|
23
|
+
},
|
|
24
|
+
"./styles.css": "./dist/styles.css"
|
|
25
|
+
},
|
|
26
|
+
"files": ["dist"],
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"access": "public"
|
|
29
|
+
},
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "vite build && node scripts/check-bundle.mjs && tsc -p tsconfig.build.json",
|
|
32
|
+
"prepublishOnly": "npm run build",
|
|
33
|
+
"typecheck": "tsc -p tsconfig.build.json --noEmit"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@livekit/components-react": "^2.9.17",
|
|
37
|
+
"@quickmeet/sdk": "0.1.0",
|
|
38
|
+
"livekit-client": "^2.15.2"
|
|
39
|
+
},
|
|
40
|
+
"peerDependencies": {
|
|
41
|
+
"react": ">=18",
|
|
42
|
+
"react-dom": ">=18"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/react": "^19.1.5",
|
|
46
|
+
"@types/react-dom": "^19.1.5",
|
|
47
|
+
"react": "^19.1.0",
|
|
48
|
+
"react-dom": "^19.1.0",
|
|
49
|
+
"typescript": "^5.8.3",
|
|
50
|
+
"vite": "^6.3.5"
|
|
51
|
+
}
|
|
52
|
+
}
|