@ai-matrx/meet 0.11.42 → 0.11.43
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/CHANGELOG.md +6 -0
- package/dist/{collab-Bf5evcLO.d.cts → collab-BNJNgXFB.d.cts} +10 -1
- package/dist/{collab-Bf5evcLO.d.ts → collab-BNJNgXFB.d.ts} +10 -1
- package/dist/{components-Frpvls4N.d.ts → components-BDtGzHf4.d.ts} +4 -2
- package/dist/{components-roCEgyFH.d.cts → components-BxK993iW.d.cts} +4 -2
- package/dist/core.cjs +182 -14
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +56 -6
- package/dist/core.d.ts +56 -6
- package/dist/core.js +182 -14
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +182 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +182 -14
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +456 -54
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +21 -4
- package/dist/react.d.ts +21 -4
- package/dist/react.js +456 -54
- package/dist/react.js.map +1 -1
- package/dist/skins/meet.cjs +321 -47
- package/dist/skins/meet.cjs.map +1 -1
- package/dist/skins/meet.d.cts +5 -3
- package/dist/skins/meet.d.ts +5 -3
- package/dist/skins/meet.js +321 -47
- package/dist/skins/meet.js.map +1 -1
- package/package.json +3 -3
package/dist/skins/meet.cjs
CHANGED
|
@@ -44,6 +44,7 @@ __export(meet_exports, {
|
|
|
44
44
|
CameraOffIcon: () => CameraOffIcon,
|
|
45
45
|
CaptionLanguageSettings: () => CaptionLanguageSettings,
|
|
46
46
|
Captions: () => Captions,
|
|
47
|
+
CaptionsIcon: () => CaptionsIcon,
|
|
47
48
|
ChatIcon: () => ChatIcon,
|
|
48
49
|
ChatPanel: () => ChatPanel,
|
|
49
50
|
CheckIcon: () => CheckIcon,
|
|
@@ -67,6 +68,7 @@ __export(meet_exports, {
|
|
|
67
68
|
MicIcon: () => MicIcon,
|
|
68
69
|
MicOffIcon: () => MicOffIcon,
|
|
69
70
|
MoreIcon: () => MoreIcon,
|
|
71
|
+
NotesIcon: () => NotesIcon,
|
|
70
72
|
PanelShell: () => PanelShell,
|
|
71
73
|
ParticipantTile: () => ParticipantTile,
|
|
72
74
|
PencilIcon: () => PencilIcon,
|
|
@@ -265,6 +267,8 @@ var MEET_ROUTES = {
|
|
|
265
267
|
noteTakerStop: "/api/v1/meet/agent/stop",
|
|
266
268
|
/** In-meeting Q&A. Streams NDJSON; body is `{meeting_id, question}` only. */
|
|
267
269
|
intelligenceAsk: "/api/v1/meet/intelligence/ask",
|
|
270
|
+
/** Anyone in the meeting (guests with the room pass included) asks for captions for themselves. */
|
|
271
|
+
noteTakerCaptions: "/api/v1/meet/agent/captions",
|
|
268
272
|
/** A host ends the meeting for everyone. Served by MRI-A6. */
|
|
269
273
|
meetingEnd: "/api/v1/meet/end",
|
|
270
274
|
/**
|
|
@@ -360,6 +364,31 @@ function recordingLabel(state) {
|
|
|
360
364
|
}
|
|
361
365
|
}
|
|
362
366
|
|
|
367
|
+
// src/core/live-policy.ts
|
|
368
|
+
var DEFAULT_LIVE_POLICY = {
|
|
369
|
+
chatMode: "everyone",
|
|
370
|
+
avLock: "off",
|
|
371
|
+
timeLimitMinutes: 0,
|
|
372
|
+
timeLimitWarningMinutes: 5,
|
|
373
|
+
recordingConsent: "notice"
|
|
374
|
+
};
|
|
375
|
+
var MODERATORS = /* @__PURE__ */ new Set(["host", "cohost"]);
|
|
376
|
+
function isLockedFor(policy, role, kind) {
|
|
377
|
+
if (MODERATORS.has(role)) return false;
|
|
378
|
+
return policy.avLock === "both" || (kind === "microphone" ? policy.avLock === "mic" : policy.avLock === "camera");
|
|
379
|
+
}
|
|
380
|
+
function consentPending(policy, role, recordingOn, given) {
|
|
381
|
+
return recordingOn && !given && policy.recordingConsent !== "notice" && !MODERATORS.has(role);
|
|
382
|
+
}
|
|
383
|
+
function canChat(policy, role) {
|
|
384
|
+
if (policy.chatMode === "everyone") return true;
|
|
385
|
+
return policy.chatMode === "hosts_only" && MODERATORS.has(role);
|
|
386
|
+
}
|
|
387
|
+
function minutesLeft(policy, startedAtMs, nowMs) {
|
|
388
|
+
if (policy.timeLimitMinutes <= 0 || startedAtMs === null) return null;
|
|
389
|
+
return Math.ceil((startedAtMs + policy.timeLimitMinutes * 6e4 - nowMs) / 6e4);
|
|
390
|
+
}
|
|
391
|
+
|
|
363
392
|
// src/core/attendance.ts
|
|
364
393
|
var IDLE_MEDIA_REGION = {
|
|
365
394
|
permission: { microphone: "unknown", camera: "unknown" },
|
|
@@ -452,9 +481,17 @@ function autoAssign(identities, rooms, exclude = []) {
|
|
|
452
481
|
return out;
|
|
453
482
|
}
|
|
454
483
|
function breakoutRemainingMs(plan, now) {
|
|
455
|
-
if (plan === null || plan.state !== "open"
|
|
456
|
-
const
|
|
457
|
-
|
|
484
|
+
if (plan === null || plan.state !== "open") return null;
|
|
485
|
+
const ends = [plan.endsAt, plan.closingAt].map((stamp) => stamp === null ? Number.NaN : Date.parse(stamp)).filter((time) => !Number.isNaN(time));
|
|
486
|
+
if (ends.length === 0) return null;
|
|
487
|
+
return Math.max(0, Math.min(...ends) - now);
|
|
488
|
+
}
|
|
489
|
+
var BREAKOUT_COUNTDOWN_MS = 3e4;
|
|
490
|
+
function breakoutClosingMs(plan, now) {
|
|
491
|
+
if (plan === null || plan.state !== "open") return null;
|
|
492
|
+
const remaining = breakoutRemainingMs(plan, now);
|
|
493
|
+
if (remaining === null) return null;
|
|
494
|
+
return plan.closingAt !== null || remaining <= BREAKOUT_COUNTDOWN_MS ? remaining : null;
|
|
458
495
|
}
|
|
459
496
|
function defaultCaptionLanguage(settings, viewerLanguage) {
|
|
460
497
|
const configured = settings?.captionTranslationLanguage.trim() ?? "";
|
|
@@ -662,11 +699,13 @@ function webMediaPlatform() {
|
|
|
662
699
|
|
|
663
700
|
// src/core/observation.ts
|
|
664
701
|
function observedRole(role, standing) {
|
|
665
|
-
if (role === "host" || role === "cohost") return role;
|
|
702
|
+
if (role === "host" || role === "cohost" || role === "presenter") return role;
|
|
666
703
|
return isLinkFollower(standing) ? "guest" : "participant";
|
|
667
704
|
}
|
|
668
|
-
function observedDevice(track, permission = "unknown") {
|
|
705
|
+
function observedDevice(track, permission = "unknown", held = null) {
|
|
706
|
+
if (held === "locked") return "locked";
|
|
669
707
|
if (track.enabled) return "on";
|
|
708
|
+
if (held === "muted_by_host") return "muted_by_host";
|
|
670
709
|
const reason = deviceUnavailableReason(track, permission);
|
|
671
710
|
return reason === null ? "muted_by_me" : `unavailable:${reason}`;
|
|
672
711
|
}
|
|
@@ -703,10 +742,20 @@ function observe(input) {
|
|
|
703
742
|
recording: snapshot?.recording === "recording" || snapshot?.recording === "stopping",
|
|
704
743
|
// S6c: the autoplay region is known only inside the room (no remote audio exists elsewhere).
|
|
705
744
|
audioBlocked: inCall && snapshot !== null ? snapshot.mediaRegion.audioOutput === "blocked" : null,
|
|
706
|
-
camera: deviceInPlay && snapshot !== null ? observedDevice(snapshot.media.camera, snapshot.mediaRegion.permission.camera) : null,
|
|
707
|
-
microphone: deviceInPlay && snapshot !== null ? observedDevice(snapshot.media.microphone, snapshot.mediaRegion.permission.microphone) : null
|
|
745
|
+
camera: deviceInPlay && snapshot !== null ? observedDevice(snapshot.media.camera, snapshot.mediaRegion.permission.camera, lockedFor(snapshot, "camera", inCall)) : null,
|
|
746
|
+
microphone: deviceInPlay && snapshot !== null ? observedDevice(snapshot.media.microphone, snapshot.mediaRegion.permission.microphone, lockedFor(snapshot, "microphone", inCall)) : null
|
|
708
747
|
};
|
|
709
748
|
}
|
|
749
|
+
function lockedFor(snapshot, kind, inCall) {
|
|
750
|
+
if (!inCall) return null;
|
|
751
|
+
const role = effectiveRole(snapshot);
|
|
752
|
+
if (isLockedFor(snapshot.livePolicy, role, kind)) return "locked";
|
|
753
|
+
if (snapshot.livePolicy.recordingConsent === "view_only_until_agree" && consentPending(snapshot.livePolicy, role, snapshot.recording === "recording", snapshot.recordingConsentGiven)) {
|
|
754
|
+
return "locked";
|
|
755
|
+
}
|
|
756
|
+
if (kind === "microphone" && snapshot.mutedByHost) return "muted_by_host";
|
|
757
|
+
return null;
|
|
758
|
+
}
|
|
710
759
|
function staticObservation(phase, reason = null) {
|
|
711
760
|
return {
|
|
712
761
|
phase,
|
|
@@ -796,7 +845,7 @@ function exactNoteTakerParticipant(meeting, participants) {
|
|
|
796
845
|
}
|
|
797
846
|
function noteTakerStatus(args) {
|
|
798
847
|
const present = exactNoteTakerParticipant(args.meeting, args.participants) !== null;
|
|
799
|
-
const raw = args.meeting?.metadata[NOTE_TAKER_METADATA_KEY];
|
|
848
|
+
const raw = args.meeting?.metadata?.[NOTE_TAKER_METADATA_KEY];
|
|
800
849
|
const row = typeof raw === "object" && raw !== null && !Array.isArray(raw) ? raw : {};
|
|
801
850
|
const recorded = readState(row["state"]);
|
|
802
851
|
const detail = typeof row["reason"] === "string" && row["reason"].length > 0 ? row["reason"] : null;
|
|
@@ -1549,6 +1598,45 @@ function useMeetAi() {
|
|
|
1549
1598
|
}, [ai, meeting, dispatchNoteTaker])
|
|
1550
1599
|
};
|
|
1551
1600
|
}
|
|
1601
|
+
function useCaptions() {
|
|
1602
|
+
const host = useMeetHost();
|
|
1603
|
+
const snapshot = useMeetSnapshot();
|
|
1604
|
+
const ai = useMeetAi();
|
|
1605
|
+
const on = snapshot?.captionsOn === true;
|
|
1606
|
+
const refusal = snapshot?.captionsRefusal ?? null;
|
|
1607
|
+
const taker = ai.noteTaker;
|
|
1608
|
+
const meeting = snapshot?.meeting ?? null;
|
|
1609
|
+
const request = (0, import_react5.useCallback)(() => {
|
|
1610
|
+
if (host === null || meeting === null) return;
|
|
1611
|
+
void host.ai.requestCaptions({ meetingId: meeting.id });
|
|
1612
|
+
}, [host, meeting]);
|
|
1613
|
+
const toggle = (0, import_react5.useCallback)(() => {
|
|
1614
|
+
if (host === null) return;
|
|
1615
|
+
const next = !on;
|
|
1616
|
+
host.store.patch({ captionsOn: next, captionsRefusal: null });
|
|
1617
|
+
if (next && taker.state !== "joining" && taker.state !== "transcribing") request();
|
|
1618
|
+
}, [host, on, taker.state, request]);
|
|
1619
|
+
let state = "off";
|
|
1620
|
+
let reason = null;
|
|
1621
|
+
let remedy = null;
|
|
1622
|
+
if (on) {
|
|
1623
|
+
if (taker.state === "transcribing" && taker.present) {
|
|
1624
|
+
state = "live";
|
|
1625
|
+
} else if (taker.state === "joining") {
|
|
1626
|
+
state = "starting";
|
|
1627
|
+
} else if (refusal !== null && refusal.reason.length > 0) {
|
|
1628
|
+
state = "unavailable";
|
|
1629
|
+
reason = refusal.reason;
|
|
1630
|
+
remedy = refusal.remedy.length > 0 ? refusal.remedy : null;
|
|
1631
|
+
} else if (taker.state === "ended" || taker.state === "handoff_pending") {
|
|
1632
|
+
state = "unavailable";
|
|
1633
|
+
reason = noteTakerLabel(taker);
|
|
1634
|
+
} else {
|
|
1635
|
+
state = "starting";
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
return { on, state, reason, remedy, toggle };
|
|
1639
|
+
}
|
|
1552
1640
|
function useEndMeeting() {
|
|
1553
1641
|
const host = useMeetHost();
|
|
1554
1642
|
const snapshot = useMeetSnapshot();
|
|
@@ -1586,7 +1674,7 @@ function useConsentNotice() {
|
|
|
1586
1674
|
const snapshot = useMeetSnapshot();
|
|
1587
1675
|
const agent = noteTakerParticipant(snapshot?.participants ?? []);
|
|
1588
1676
|
if (agent === null) return null;
|
|
1589
|
-
return
|
|
1677
|
+
return `AI notes are on. ${agent.displayName} is in this meeting, transcribing what is said and writing notes everyone here can read.`;
|
|
1590
1678
|
}
|
|
1591
1679
|
function useMediaSupervisor() {
|
|
1592
1680
|
const host = useMeetHost();
|
|
@@ -1834,6 +1922,38 @@ function useGuestRecordAccess(meeting) {
|
|
|
1834
1922
|
)
|
|
1835
1923
|
};
|
|
1836
1924
|
}
|
|
1925
|
+
function useLivePolicy() {
|
|
1926
|
+
const snapshot = useMeetSnapshot();
|
|
1927
|
+
const role = useRole();
|
|
1928
|
+
const [now, setNow] = (0, import_react5.useState)(() => Date.now());
|
|
1929
|
+
const limited = (snapshot?.livePolicy.timeLimitMinutes ?? 0) > 0;
|
|
1930
|
+
(0, import_react5.useEffect)(() => {
|
|
1931
|
+
if (!limited) return void 0;
|
|
1932
|
+
const timer = setInterval(() => setNow(Date.now()), 1e3);
|
|
1933
|
+
return () => clearInterval(timer);
|
|
1934
|
+
}, [limited]);
|
|
1935
|
+
const policy = snapshot?.livePolicy ?? DEFAULT_LIVE_POLICY;
|
|
1936
|
+
const left = minutesLeft(policy, snapshot?.sessionStartedAt ?? null, now);
|
|
1937
|
+
const host = useMeetHost();
|
|
1938
|
+
const pending = consentPending(policy, role, snapshot?.recording === "recording", snapshot?.recordingConsentGiven === true);
|
|
1939
|
+
const viewOnly = pending && policy.recordingConsent === "view_only_until_agree";
|
|
1940
|
+
const idle = snapshot !== null && snapshot.recording !== "recording" && snapshot.recording !== "starting" && snapshot.recording !== "stopping";
|
|
1941
|
+
const given = snapshot?.recordingConsentGiven === true;
|
|
1942
|
+
const store = host?.store ?? null;
|
|
1943
|
+
(0, import_react5.useEffect)(() => {
|
|
1944
|
+
if (idle && given) store?.patch({ recordingConsentGiven: false });
|
|
1945
|
+
}, [idle, given, store]);
|
|
1946
|
+
return {
|
|
1947
|
+
canChat: canChat(policy, role),
|
|
1948
|
+
chatMode: policy.chatMode,
|
|
1949
|
+
micLocked: isLockedFor(policy, role, "microphone") || viewOnly,
|
|
1950
|
+
cameraLocked: isLockedFor(policy, role, "camera") || viewOnly,
|
|
1951
|
+
consent: pending ? policy.recordingConsent === "ok_or_leave" ? "ok_or_leave" : "view_only_until_agree" : null,
|
|
1952
|
+
agree: () => store?.patch({ recordingConsentGiven: true }),
|
|
1953
|
+
minutesLeft: left,
|
|
1954
|
+
timeWarning: left !== null && left <= policy.timeLimitWarningMinutes
|
|
1955
|
+
};
|
|
1956
|
+
}
|
|
1837
1957
|
|
|
1838
1958
|
// src/react/collab-hooks.ts
|
|
1839
1959
|
var import_react7 = require("react");
|
|
@@ -2049,6 +2169,18 @@ function SparklesIcon(props) {
|
|
|
2049
2169
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M19 15l.9 2.1 2.1.9-2.1.9-.9 2.1-.9-2.1-2.1-.9 2.1-.9L19 15Z" })
|
|
2050
2170
|
] });
|
|
2051
2171
|
}
|
|
2172
|
+
function CaptionsIcon(props) {
|
|
2173
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(Icon, { ...props, children: [
|
|
2174
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("rect", { x: "3", y: "5", width: "18", height: "14", rx: "2" }),
|
|
2175
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M10 10.5a2 2 0 1 0 0 3M16 10.5a2 2 0 1 0 0 3" })
|
|
2176
|
+
] });
|
|
2177
|
+
}
|
|
2178
|
+
function NotesIcon(props) {
|
|
2179
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(Icon, { ...props, children: [
|
|
2180
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M4 20l1-4L16.5 4.5a2.1 2.1 0 0 1 3 3L8 19l-4 1Z" }),
|
|
2181
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M14 7l3 3" })
|
|
2182
|
+
] });
|
|
2183
|
+
}
|
|
2052
2184
|
function LockIcon(props) {
|
|
2053
2185
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(Icon, { ...props, children: [
|
|
2054
2186
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("rect", { x: "4", y: "10", width: "16", height: "11", rx: "2" }),
|
|
@@ -2967,7 +3099,7 @@ function BreakoutRun({ plan }) {
|
|
|
2967
3099
|
type: "button",
|
|
2968
3100
|
className: "mx-meet__primary mx-meet__primary--small",
|
|
2969
3101
|
onClick: () => void act({ action: "breakout_close" }).then(show),
|
|
2970
|
-
children: "
|
|
3102
|
+
children: "Close rooms"
|
|
2971
3103
|
}
|
|
2972
3104
|
) : null
|
|
2973
3105
|
] });
|
|
@@ -2985,9 +3117,14 @@ function BreakoutBanner() {
|
|
|
2985
3117
|
const { collab, act, moveTo, localIdentity, breakoutRoomId } = useCollab();
|
|
2986
3118
|
const plan = collab?.breakout ?? null;
|
|
2987
3119
|
const open = plan?.state === "open" ? plan : null;
|
|
2988
|
-
const now = useNow(open?.endsAt != null);
|
|
3120
|
+
const now = useNow(open?.endsAt != null || open?.closingAt != null);
|
|
2989
3121
|
const remaining = breakoutRemainingMs(open, now);
|
|
3122
|
+
const closing = breakoutClosingMs(open, now);
|
|
2990
3123
|
const assigned = assignedRoom(open, localIdentity);
|
|
3124
|
+
const [later, setLater] = (0, import_react9.useState)(null);
|
|
3125
|
+
const [autoSince, setAutoSince] = (0, import_react9.useState)(null);
|
|
3126
|
+
const AUTO_MOVE_MS = 1e4;
|
|
3127
|
+
const autoLeft = open?.moveMode === "auto" && assigned !== null && autoSince?.id === open.id && later !== open.id ? Math.max(0, AUTO_MOVE_MS - (now - autoSince.at)) : null;
|
|
2991
3128
|
const [dismissedBroadcast, setDismissedBroadcast] = (0, import_react9.useState)(null);
|
|
2992
3129
|
const [failure, setFailure] = (0, import_react9.useState)(null);
|
|
2993
3130
|
const expireAsked = (0, import_react9.useRef)(null);
|
|
@@ -3000,6 +3137,19 @@ function BreakoutBanner() {
|
|
|
3000
3137
|
if ((here ?? null) === request.roomId) return;
|
|
3001
3138
|
void moveTo(request.roomId).then((result) => setFailure(result.ok ? null : result.message));
|
|
3002
3139
|
}, [moveAt, host, moveTo]);
|
|
3140
|
+
const joinAssigned = async () => {
|
|
3141
|
+
if (assigned === null) return;
|
|
3142
|
+
const said = await act({ action: "breakout_join", roomId: assigned.id });
|
|
3143
|
+
const result = said.ok ? await moveTo(assigned.id) : said;
|
|
3144
|
+
setFailure(result.ok ? null : result.message);
|
|
3145
|
+
};
|
|
3146
|
+
(0, import_react9.useEffect)(() => {
|
|
3147
|
+
if (open === null || open.moveMode !== "auto" || assigned === null || breakoutRoomId !== null) return;
|
|
3148
|
+
if (autoSince?.id !== open.id) setAutoSince({ id: open.id, at: Date.now() });
|
|
3149
|
+
}, [open, assigned, breakoutRoomId, autoSince]);
|
|
3150
|
+
(0, import_react9.useEffect)(() => {
|
|
3151
|
+
if (autoLeft === 0) void joinAssigned();
|
|
3152
|
+
}, [autoLeft]);
|
|
3003
3153
|
(0, import_react9.useEffect)(() => {
|
|
3004
3154
|
if (open === null || remaining === null || remaining > 0) return;
|
|
3005
3155
|
const asked = expireAsked.current;
|
|
@@ -3013,27 +3163,25 @@ function BreakoutBanner() {
|
|
|
3013
3163
|
if (open === null && failure === null) return null;
|
|
3014
3164
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "mx-meet__breakout-banner", role: "status", children: [
|
|
3015
3165
|
failure !== null ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "mx-meet__collab-error", children: failure }) : null,
|
|
3166
|
+
closing !== null ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { role: "status", "data-meet-notice": "breakout-closing", children: [
|
|
3167
|
+
"Rooms closing in ",
|
|
3168
|
+
Math.ceil(closing / 1e3),
|
|
3169
|
+
room !== null ? " \u2014 you return to the main meeting" : ""
|
|
3170
|
+
] }) : null,
|
|
3016
3171
|
room !== null ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { children: [
|
|
3017
3172
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("strong", { children: room.name }),
|
|
3018
|
-
remaining !== null ? ` \xB7 ${clock(remaining)} left` : "",
|
|
3173
|
+
remaining !== null && closing === null ? ` \xB7 ${clock(remaining)} left` : "",
|
|
3019
3174
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: "mx-meet__chip", onClick: () => void moveTo(null), children: "Return to main room" })
|
|
3175
|
+
] }) : assigned !== null && later !== open?.id ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { children: [
|
|
3176
|
+
autoLeft !== null ? `You're being moved to ${assigned.name} in ${Math.ceil(autoLeft / 1e3)} s` : `You're invited to ${assigned.name}`,
|
|
3177
|
+
remaining !== null && closing === null ? ` \xB7 ${clock(remaining)} left` : "",
|
|
3178
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: "mx-meet__primary mx-meet__primary--small", onClick: () => void joinAssigned(), children: "Join room" }),
|
|
3179
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: "mx-meet__chip", onClick: () => setLater(open?.id ?? null), children: "Later" })
|
|
3020
3180
|
] }) : assigned !== null ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { children: [
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
"button",
|
|
3026
|
-
{
|
|
3027
|
-
type: "button",
|
|
3028
|
-
className: "mx-meet__primary mx-meet__primary--small",
|
|
3029
|
-
onClick: () => void act({ action: "breakout_join", roomId: assigned.id }).then(async (said) => {
|
|
3030
|
-
const result = said.ok ? await moveTo(assigned.id) : said;
|
|
3031
|
-
setFailure(result.ok ? null : result.message);
|
|
3032
|
-
}),
|
|
3033
|
-
children: "Join"
|
|
3034
|
-
}
|
|
3035
|
-
)
|
|
3036
|
-
] }) : open?.allowChoose ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Breakout rooms are open \u2014 pick one under Activities." }) : null,
|
|
3181
|
+
assigned.name,
|
|
3182
|
+
" is open",
|
|
3183
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: "mx-meet__chip", onClick: () => void joinAssigned(), children: "Join room" })
|
|
3184
|
+
] }) : open?.allowChoose ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Rooms are open \u2014 pick one under Activities." }) : null,
|
|
3037
3185
|
showBroadcast ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "mx-meet__breakout-broadcast", children: [
|
|
3038
3186
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("strong", { children: [
|
|
3039
3187
|
broadcast.by,
|
|
@@ -3081,6 +3229,33 @@ function CaptionLanguageSettings() {
|
|
|
3081
3229
|
collab?.captionTranslationError != null ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "mx-meet__panel-note mx-meet__collab-error", children: collab.captionTranslationError }) : null
|
|
3082
3230
|
] });
|
|
3083
3231
|
}
|
|
3232
|
+
function CaptionsControl() {
|
|
3233
|
+
const captions = useCaptions();
|
|
3234
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3235
|
+
ControlButton,
|
|
3236
|
+
{
|
|
3237
|
+
label: captions.on ? "Turn off captions" : "Turn on captions",
|
|
3238
|
+
active: captions.on,
|
|
3239
|
+
pressed: captions.on,
|
|
3240
|
+
onClick: captions.toggle,
|
|
3241
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CaptionsIcon, {})
|
|
3242
|
+
}
|
|
3243
|
+
);
|
|
3244
|
+
}
|
|
3245
|
+
function TakeNotesControl() {
|
|
3246
|
+
const ai = useMeetAi();
|
|
3247
|
+
if (!ai.canControlNoteTaker) return null;
|
|
3248
|
+
const running = ai.noteTaker.state === "joining" || ai.noteTaker.state === "transcribing";
|
|
3249
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3250
|
+
ControlButton,
|
|
3251
|
+
{
|
|
3252
|
+
label: running ? "Stop taking notes" : "Take notes for me",
|
|
3253
|
+
active: running,
|
|
3254
|
+
onClick: () => void (running ? ai.stopNoteTaker() : ai.startNoteTaker()),
|
|
3255
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(NotesIcon, {})
|
|
3256
|
+
}
|
|
3257
|
+
);
|
|
3258
|
+
}
|
|
3084
3259
|
|
|
3085
3260
|
// src/skins/meet/components.tsx
|
|
3086
3261
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
@@ -3131,6 +3306,7 @@ function ControlButton({
|
|
|
3131
3306
|
label,
|
|
3132
3307
|
active = false,
|
|
3133
3308
|
danger = false,
|
|
3309
|
+
pressed,
|
|
3134
3310
|
onClick,
|
|
3135
3311
|
children
|
|
3136
3312
|
}) {
|
|
@@ -3145,26 +3321,49 @@ function ControlButton({
|
|
|
3145
3321
|
].filter(Boolean).join(" "),
|
|
3146
3322
|
"aria-label": label,
|
|
3147
3323
|
title: label,
|
|
3324
|
+
...pressed !== void 0 ? { "aria-pressed": pressed } : {},
|
|
3148
3325
|
onClick,
|
|
3149
3326
|
children
|
|
3150
3327
|
}
|
|
3151
3328
|
);
|
|
3152
3329
|
}
|
|
3153
3330
|
function RecordingIndicator() {
|
|
3154
|
-
const { state, label } = useRecording();
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
]
|
|
3331
|
+
const { state, label, canStart } = useRecording();
|
|
3332
|
+
const snapshot = useMeetSnapshot();
|
|
3333
|
+
const previous = (0, import_react10.useRef)(state);
|
|
3334
|
+
const [stoppedAt, setStoppedAt] = (0, import_react10.useState)(null);
|
|
3335
|
+
(0, import_react10.useEffect)(() => {
|
|
3336
|
+
const was = previous.current;
|
|
3337
|
+
previous.current = state;
|
|
3338
|
+
if ((was === "recording" || was === "starting") && state !== "recording" && state !== "starting") {
|
|
3339
|
+
setStoppedAt(Date.now());
|
|
3340
|
+
const timer = setTimeout(() => setStoppedAt(null), 1e4);
|
|
3341
|
+
return () => clearTimeout(timer);
|
|
3166
3342
|
}
|
|
3167
|
-
|
|
3343
|
+
return void 0;
|
|
3344
|
+
}, [state]);
|
|
3345
|
+
const meetingId = snapshot?.meeting?.id ?? null;
|
|
3346
|
+
if (label === null && stoppedAt === null) return null;
|
|
3347
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
3348
|
+
label !== null ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
3349
|
+
"span",
|
|
3350
|
+
{
|
|
3351
|
+
className: `mx-meet__recording mx-meet__recording--${state}`,
|
|
3352
|
+
role: "status",
|
|
3353
|
+
"aria-live": "polite",
|
|
3354
|
+
children: [
|
|
3355
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(RecordIcon, { width: 10, height: 10 }),
|
|
3356
|
+
label
|
|
3357
|
+
]
|
|
3358
|
+
}
|
|
3359
|
+
) : null,
|
|
3360
|
+
stoppedAt !== null ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "mx-meet__recording", role: "status", "data-meet-notice": "recording-stopped", children: "Recording stopped" }) : null,
|
|
3361
|
+
state === "processing" ? (
|
|
3362
|
+
// rec-processing: the host is told it is being made ready (the indicator says Processing…).
|
|
3363
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "mx-meet__recording", role: "status", "data-meet-notice": "recording-processing", children: "Your recording is being processed. A link appears here when it is ready." })
|
|
3364
|
+
) : null,
|
|
3365
|
+
state === "available" && canStart && meetingId !== null ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("a", { className: "mx-meet__link", href: `/meetings/${meetingId}`, target: "_blank", rel: "noreferrer", children: "View recording" }) : null
|
|
3366
|
+
] });
|
|
3168
3367
|
}
|
|
3169
3368
|
function ConnectionDot({ quality }) {
|
|
3170
3369
|
if (quality === "excellent" || quality === "good" || quality === "unknown") return null;
|
|
@@ -3320,6 +3519,7 @@ function ControlBar({ onLeave }) {
|
|
|
3320
3519
|
const controls = useHostControls();
|
|
3321
3520
|
const queue = useHandQueue();
|
|
3322
3521
|
const micUnavailable = useLocalMedia().microphone.unavailable;
|
|
3522
|
+
const live = useLivePolicy();
|
|
3323
3523
|
const unread = useUnreadChat(panel === "chat");
|
|
3324
3524
|
const [whiteboard, setWhiteboard] = (0, import_react10.useState)(false);
|
|
3325
3525
|
const app = useMeetAppPanel();
|
|
@@ -3387,7 +3587,7 @@ function ControlBar({ onLeave }) {
|
|
|
3387
3587
|
panel !== "people" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(KnockNotice, { onView: () => setPanel("people") }) : null,
|
|
3388
3588
|
controls.notice !== null && panel !== "people" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Toast, { text: controls.notice.text, failed: controls.notice.failed, onDone: controls.clearNotice }) : null,
|
|
3389
3589
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "mx-meet__controls", children: [
|
|
3390
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3590
|
+
live.micLocked ? null : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3391
3591
|
ControlButton,
|
|
3392
3592
|
{
|
|
3393
3593
|
label: micUnavailable !== null ? `Unmute \u2014 ${micUnavailable.remedy}` : room.local?.micEnabled === true ? "Mute (\u2318D)" : "Unmute (\u2318D)",
|
|
@@ -3396,7 +3596,7 @@ function ControlBar({ onLeave }) {
|
|
|
3396
3596
|
children: room.local?.micEnabled === true ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MicIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MicOffIcon, {})
|
|
3397
3597
|
}
|
|
3398
3598
|
),
|
|
3399
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3599
|
+
live.cameraLocked ? null : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3400
3600
|
ControlButton,
|
|
3401
3601
|
{
|
|
3402
3602
|
label: room.local?.cameraEnabled === true ? "Stop video (\u2318E)" : "Start video (\u2318E)",
|
|
@@ -3405,6 +3605,7 @@ function ControlBar({ onLeave }) {
|
|
|
3405
3605
|
children: room.local?.cameraEnabled === true ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CameraIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CameraOffIcon, {})
|
|
3406
3606
|
}
|
|
3407
3607
|
),
|
|
3608
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CaptionsControl, {}),
|
|
3408
3609
|
room.canShareScreen || room.local?.screenSharing === true ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3409
3610
|
ControlButton,
|
|
3410
3611
|
{
|
|
@@ -3469,6 +3670,7 @@ function ControlBar({ onLeave }) {
|
|
|
3469
3670
|
onOpen: openActivity
|
|
3470
3671
|
}
|
|
3471
3672
|
),
|
|
3673
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(TakeNotesControl, {}),
|
|
3472
3674
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(AiControl, { active: panel === "ai", onToggle: () => toggle("ai") }),
|
|
3473
3675
|
recording.canStart ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ControlButton, { label: "Start recording", onClick: () => void recording.start(), children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(RecordIcon, {}) }) : null,
|
|
3474
3676
|
recording.canStop ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ControlButton, { label: "Stop recording", active: true, onClick: () => void recording.stop(), children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(RecordIcon, {}) }) : null,
|
|
@@ -3524,6 +3726,23 @@ function ControlBar({ onLeave }) {
|
|
|
3524
3726
|
]
|
|
3525
3727
|
}
|
|
3526
3728
|
),
|
|
3729
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
3730
|
+
MenuItem,
|
|
3731
|
+
{
|
|
3732
|
+
onSelect: () => {
|
|
3733
|
+
setPopover("none");
|
|
3734
|
+
void controls.run({
|
|
3735
|
+
action: "set_av_lock",
|
|
3736
|
+
value: snapshot?.livePolicy.avLock === "both" ? "off" : "both"
|
|
3737
|
+
});
|
|
3738
|
+
},
|
|
3739
|
+
children: [
|
|
3740
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MicOffIcon, { width: 16, height: 16 }),
|
|
3741
|
+
" ",
|
|
3742
|
+
snapshot?.livePolicy.avLock === "both" ? "Turn on attendees' microphone and camera" : "Turn off attendees' microphone and camera"
|
|
3743
|
+
]
|
|
3744
|
+
}
|
|
3745
|
+
),
|
|
3527
3746
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
3528
3747
|
MenuItem,
|
|
3529
3748
|
{
|
|
@@ -3851,9 +4070,45 @@ function MeetingOverlays() {
|
|
|
3851
4070
|
const reactions = useReactions();
|
|
3852
4071
|
const { notice, dismiss } = useModerationNotice();
|
|
3853
4072
|
const room = useRoom();
|
|
4073
|
+
const live = useLivePolicy();
|
|
4074
|
+
const snapshot = useMeetSnapshot();
|
|
4075
|
+
const controls = useHostControls();
|
|
4076
|
+
const isHostNow = useRole() === "host";
|
|
3854
4077
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
3855
4078
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ReactionOverlay, { reactions }),
|
|
3856
4079
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MediaNotices, {}),
|
|
4080
|
+
snapshot !== null && snapshot.phase === "in_call" && snapshot.participants.length >= 2 && !snapshot.participants.some((p) => p.role === "host" || p.role === "cohost") ? (
|
|
4081
|
+
// meeting-without-host: the call goes on; host-only controls are simply not on screen.
|
|
4082
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "mx-meet__banner", role: "status", "data-meet-notice": "host-absent", children: "The host has left the meeting. Host controls are not available until a host is back." })
|
|
4083
|
+
) : null,
|
|
4084
|
+
live.consent !== null ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "mx-meet__sheet-backdrop", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "mx-meet__sheet", role: "alertdialog", "aria-label": "This meeting is being recorded", "data-meet-notice": "recording-consent", children: [
|
|
4085
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h2", { className: "mx-meet__panel-title", children: "This meeting is being recorded" }),
|
|
4086
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "mx-meet__confirm-text", children: live.consent === "ok_or_leave" ? "By staying you agree to be recorded. You can leave now if you do not agree." : "Until you agree to the recording you can watch and listen, but not use your microphone or camera." }),
|
|
4087
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "mx-meet__menu-actions", children: [
|
|
4088
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "mx-meet__send", onClick: live.agree, children: live.consent === "ok_or_leave" ? "OK" : "I agree" }),
|
|
4089
|
+
live.consent === "ok_or_leave" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "mx-meet__link", onClick: () => void room.leave(), children: "Leave meeting" }) : null
|
|
4090
|
+
] })
|
|
4091
|
+
] }) }) : null,
|
|
4092
|
+
snapshot?.canReclaim === true && !isHostNow ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "mx-meet__notice-bar", role: "status", "data-meet-notice": "host-reclaim", children: [
|
|
4093
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: "You started this meeting. Take back the host?" }),
|
|
4094
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
4095
|
+
"button",
|
|
4096
|
+
{
|
|
4097
|
+
type: "button",
|
|
4098
|
+
className: "mx-meet__primary mx-meet__primary--small",
|
|
4099
|
+
onClick: () => void controls.run({ action: "reclaim_host" }),
|
|
4100
|
+
children: "Reclaim host"
|
|
4101
|
+
}
|
|
4102
|
+
)
|
|
4103
|
+
] }) : null,
|
|
4104
|
+
live.micLocked || live.cameraLocked ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "mx-meet__banner", role: "status", "data-meet-notice": "mic-locked", children: live.micLocked && live.cameraLocked ? "Your microphone and camera are turned off by the organizer." : live.micLocked ? "Your microphone is turned off by the organizer." : "Your camera is turned off by the organizer." }) : null,
|
|
4105
|
+
live.timeWarning && live.minutesLeft !== null && live.minutesLeft > 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { className: "mx-meet__banner", role: "status", "data-meet-notice": "time-warning", children: [
|
|
4106
|
+
"This meeting will end in ",
|
|
4107
|
+
live.minutesLeft,
|
|
4108
|
+
" ",
|
|
4109
|
+
live.minutesLeft === 1 ? "minute" : "minutes",
|
|
4110
|
+
" (time limit)."
|
|
4111
|
+
] }) : null,
|
|
3857
4112
|
notice !== null && notice.kind !== "removed" ? (
|
|
3858
4113
|
// A host's request ("the host is asking you to unmute"), not an error:
|
|
3859
4114
|
// an assertive status, so it is announced at once without being filed
|
|
@@ -3944,6 +4199,7 @@ function ChatPanel({
|
|
|
3944
4199
|
}) {
|
|
3945
4200
|
const snapshot = useMeetSnapshot();
|
|
3946
4201
|
const room = useRoom();
|
|
4202
|
+
const live = useLivePolicy();
|
|
3947
4203
|
const [draft, setDraft] = (0, import_react10.useState)("");
|
|
3948
4204
|
const [recipient, setRecipient] = (0, import_react10.useState)(to);
|
|
3949
4205
|
const listRef = (0, import_react10.useRef)(null);
|
|
@@ -3968,7 +4224,7 @@ function ChatPanel({
|
|
|
3968
4224
|
snapshot?.chatLoaded !== true && messages.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("li", { className: "mx-meet__panel-note", children: "Reading earlier messages\u2026" }) : messages.length === 0 && snapshot?.chatHistoryError == null ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("li", { className: "mx-meet__panel-note", children: "No messages yet. Messages to everyone stay with the meeting, so people who join later see them." }) : null,
|
|
3969
4225
|
messages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ChatLine, { message, local, people }, message.id))
|
|
3970
4226
|
] }),
|
|
3971
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
4227
|
+
!live.canChat ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "mx-meet__panel-note", role: "status", "data-meet-notice": "chat-restricted", children: live.chatMode === "off" ? "Chat is turned off for this meeting." : "Chat is limited to the host and co-hosts in this meeting." }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
3972
4228
|
"form",
|
|
3973
4229
|
{
|
|
3974
4230
|
className: "mx-meet__composer mx-meet__composer--chat",
|
|
@@ -4340,6 +4596,13 @@ function PersonMenu({
|
|
|
4340
4596
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PeopleIcon, { width: 16, height: 16 }),
|
|
4341
4597
|
" Make co-host"
|
|
4342
4598
|
] }) : null,
|
|
4599
|
+
!participant.isAgent && participant.role !== "cohost" && participant.role !== "host" ? participant.role === "presenter" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(MenuItem, { onSelect: () => act({ action: "revoke_presenter", identity: participant.identity }), children: [
|
|
4600
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ScreenShareIcon, { width: 16, height: 16 }),
|
|
4601
|
+
" Remove presenter"
|
|
4602
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(MenuItem, { onSelect: () => act({ action: "make_presenter", identity: participant.identity }), children: [
|
|
4603
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ScreenShareIcon, { width: 16, height: 16 }),
|
|
4604
|
+
" Make presenter"
|
|
4605
|
+
] }) : null,
|
|
4343
4606
|
!participant.isAgent ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
4344
4607
|
MenuItem,
|
|
4345
4608
|
{
|
|
@@ -4845,8 +5108,19 @@ function Captions({ lines = 3 }) {
|
|
|
4845
5108
|
const ai = useMeetAi();
|
|
4846
5109
|
const visible = ai.transcript.slice(-lines);
|
|
4847
5110
|
const translation = useCaptionTranslation(visible);
|
|
4848
|
-
|
|
4849
|
-
|
|
5111
|
+
const captions = useCaptions();
|
|
5112
|
+
if (!captions.on) return null;
|
|
5113
|
+
if (captions.state === "unavailable") {
|
|
5114
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "mx-meet__captions", role: "status", "data-meet-notice": "captions-unavailable", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { className: "mx-meet__caption", children: [
|
|
5115
|
+
"Captions are unavailable. ",
|
|
5116
|
+
captions.reason,
|
|
5117
|
+
captions.remedy !== null ? ` ${captions.remedy}` : ""
|
|
5118
|
+
] }) });
|
|
5119
|
+
}
|
|
5120
|
+
if (visible.length === 0) {
|
|
5121
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "mx-meet__captions", "aria-live": "polite", "aria-label": "Live captions", "data-meet-caption": captions.state, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "mx-meet__caption mx-meet__caption--interim", children: captions.state === "starting" ? "Starting captions. They appear as people speak." : "Captions are on. They appear as people speak." }) });
|
|
5122
|
+
}
|
|
5123
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "mx-meet__captions", "aria-live": "polite", "aria-label": "Live captions", "data-meet-caption": "live", children: [
|
|
4850
5124
|
visible.map((line) => {
|
|
4851
5125
|
const translated = translation.language === null ? void 0 : translation.translations[line.id];
|
|
4852
5126
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
@@ -4869,7 +5143,7 @@ function Captions({ lines = 3 }) {
|
|
|
4869
5143
|
function ConsentNotice() {
|
|
4870
5144
|
const notice = useConsentNotice();
|
|
4871
5145
|
if (notice === null) return null;
|
|
4872
|
-
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "mx-meet__consent", role: "status", children: notice });
|
|
5146
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "mx-meet__consent", role: "status", "data-meet-notice": "notes-started", children: notice });
|
|
4873
5147
|
}
|
|
4874
5148
|
function AttendanceNotice() {
|
|
4875
5149
|
const media = useLocalMedia();
|