@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.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { A as AiPanel, a as AttendanceNotice, b as Avatar, C as Captions, c as ChatPanel, d as ConnectionDot, e as ConsentNotice, f as ControlBar, g as ControlButton, H as HostMenu, L as LobbyPanel, M as MeetSkinRoom, h as MeetingOverlays, i as MenuItem, P as PanelShell, j as ParticipantTile, k as PeoplePanel, l as PersonMenu, m as Popover, n as PreJoin, Q as QualityBars, R as ReactionOverlay, o as RecordingIndicator, S as SettingsPanel, p as ShortcutsSheet, q as Stage, T as Toast } from '../components-
|
|
1
|
+
export { A as AiPanel, a as AttendanceNotice, b as Avatar, C as Captions, c as ChatPanel, d as ConnectionDot, e as ConsentNotice, f as ControlBar, g as ControlButton, H as HostMenu, L as LobbyPanel, M as MeetSkinRoom, h as MeetingOverlays, i as MenuItem, P as PanelShell, j as ParticipantTile, k as PeoplePanel, l as PersonMenu, m as Popover, n as PreJoin, Q as QualityBars, R as ReactionOverlay, o as RecordingIndicator, S as SettingsPanel, p as ShortcutsSheet, q as Stage, T as Toast } from '../components-BxK993iW.cjs';
|
|
2
2
|
import { ReactNode, SVGProps } from 'react';
|
|
3
|
-
import { C as CollabPanel } from '../collab-
|
|
3
|
+
import { C as CollabPanel } from '../collab-BNJNgXFB.cjs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* POLLS, Q&A, THE SHARED WHITEBOARD AND BREAKOUT ROOMS — the in-room surfaces (Meet wave 5).
|
|
@@ -73,6 +73,8 @@ declare function ChatIcon(props: IconProps): React.ReactElement;
|
|
|
73
73
|
declare function PeopleIcon(props: IconProps): React.ReactElement;
|
|
74
74
|
declare function RecordIcon(props: IconProps): React.ReactElement;
|
|
75
75
|
declare function SparklesIcon(props: IconProps): React.ReactElement;
|
|
76
|
+
declare function CaptionsIcon(props: IconProps): React.ReactElement;
|
|
77
|
+
declare function NotesIcon(props: IconProps): React.ReactElement;
|
|
76
78
|
declare function LockIcon(props: IconProps): React.ReactElement;
|
|
77
79
|
declare function LayoutIcon(props: IconProps): React.ReactElement;
|
|
78
80
|
declare function SettingsIcon(props: IconProps): React.ReactElement;
|
|
@@ -110,4 +112,4 @@ declare function HighlighterIcon(props: IconProps): React.ReactElement;
|
|
|
110
112
|
/** Lucide `undo-2`. */
|
|
111
113
|
declare function UndoIcon(props: IconProps): React.ReactElement;
|
|
112
114
|
|
|
113
|
-
export { ActivitiesControl, ActivitiesIcon, BreakoutBanner, BreakoutIcon, BreakoutsPanel, CameraIcon, CameraOffIcon, CaptionLanguageSettings, ChatIcon, CheckIcon, CloseIcon, EraserIcon, FlagIcon, HandIcon, HighlighterIcon, KeyboardIcon, LayoutIcon, LockIcon, MicIcon, MicOffIcon, MoreIcon, PencilIcon, PeopleIcon, PhoneIcon, PhoneOffIcon, PinIcon, PollIcon, PollsPanel, QaPanel, QuestionIcon, RecordIcon, ScreenShareIcon, SearchIcon, SettingsIcon, SignalIcon, SmileIcon, SparklesIcon, SpeakerIcon, SpotlightIcon, UndoIcon, UpvoteIcon, WhiteboardIcon, WhiteboardPanel, WifiLowIcon };
|
|
115
|
+
export { ActivitiesControl, ActivitiesIcon, BreakoutBanner, BreakoutIcon, BreakoutsPanel, CameraIcon, CameraOffIcon, CaptionLanguageSettings, CaptionsIcon, ChatIcon, CheckIcon, CloseIcon, EraserIcon, FlagIcon, HandIcon, HighlighterIcon, KeyboardIcon, LayoutIcon, LockIcon, MicIcon, MicOffIcon, MoreIcon, NotesIcon, PencilIcon, PeopleIcon, PhoneIcon, PhoneOffIcon, PinIcon, PollIcon, PollsPanel, QaPanel, QuestionIcon, RecordIcon, ScreenShareIcon, SearchIcon, SettingsIcon, SignalIcon, SmileIcon, SparklesIcon, SpeakerIcon, SpotlightIcon, UndoIcon, UpvoteIcon, WhiteboardIcon, WhiteboardPanel, WifiLowIcon };
|
package/dist/skins/meet.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { A as AiPanel, a as AttendanceNotice, b as Avatar, C as Captions, c as ChatPanel, d as ConnectionDot, e as ConsentNotice, f as ControlBar, g as ControlButton, H as HostMenu, L as LobbyPanel, M as MeetSkinRoom, h as MeetingOverlays, i as MenuItem, P as PanelShell, j as ParticipantTile, k as PeoplePanel, l as PersonMenu, m as Popover, n as PreJoin, Q as QualityBars, R as ReactionOverlay, o as RecordingIndicator, S as SettingsPanel, p as ShortcutsSheet, q as Stage, T as Toast } from '../components-
|
|
1
|
+
export { A as AiPanel, a as AttendanceNotice, b as Avatar, C as Captions, c as ChatPanel, d as ConnectionDot, e as ConsentNotice, f as ControlBar, g as ControlButton, H as HostMenu, L as LobbyPanel, M as MeetSkinRoom, h as MeetingOverlays, i as MenuItem, P as PanelShell, j as ParticipantTile, k as PeoplePanel, l as PersonMenu, m as Popover, n as PreJoin, Q as QualityBars, R as ReactionOverlay, o as RecordingIndicator, S as SettingsPanel, p as ShortcutsSheet, q as Stage, T as Toast } from '../components-BDtGzHf4.js';
|
|
2
2
|
import { ReactNode, SVGProps } from 'react';
|
|
3
|
-
import { C as CollabPanel } from '../collab-
|
|
3
|
+
import { C as CollabPanel } from '../collab-BNJNgXFB.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* POLLS, Q&A, THE SHARED WHITEBOARD AND BREAKOUT ROOMS — the in-room surfaces (Meet wave 5).
|
|
@@ -73,6 +73,8 @@ declare function ChatIcon(props: IconProps): React.ReactElement;
|
|
|
73
73
|
declare function PeopleIcon(props: IconProps): React.ReactElement;
|
|
74
74
|
declare function RecordIcon(props: IconProps): React.ReactElement;
|
|
75
75
|
declare function SparklesIcon(props: IconProps): React.ReactElement;
|
|
76
|
+
declare function CaptionsIcon(props: IconProps): React.ReactElement;
|
|
77
|
+
declare function NotesIcon(props: IconProps): React.ReactElement;
|
|
76
78
|
declare function LockIcon(props: IconProps): React.ReactElement;
|
|
77
79
|
declare function LayoutIcon(props: IconProps): React.ReactElement;
|
|
78
80
|
declare function SettingsIcon(props: IconProps): React.ReactElement;
|
|
@@ -110,4 +112,4 @@ declare function HighlighterIcon(props: IconProps): React.ReactElement;
|
|
|
110
112
|
/** Lucide `undo-2`. */
|
|
111
113
|
declare function UndoIcon(props: IconProps): React.ReactElement;
|
|
112
114
|
|
|
113
|
-
export { ActivitiesControl, ActivitiesIcon, BreakoutBanner, BreakoutIcon, BreakoutsPanel, CameraIcon, CameraOffIcon, CaptionLanguageSettings, ChatIcon, CheckIcon, CloseIcon, EraserIcon, FlagIcon, HandIcon, HighlighterIcon, KeyboardIcon, LayoutIcon, LockIcon, MicIcon, MicOffIcon, MoreIcon, PencilIcon, PeopleIcon, PhoneIcon, PhoneOffIcon, PinIcon, PollIcon, PollsPanel, QaPanel, QuestionIcon, RecordIcon, ScreenShareIcon, SearchIcon, SettingsIcon, SignalIcon, SmileIcon, SparklesIcon, SpeakerIcon, SpotlightIcon, UndoIcon, UpvoteIcon, WhiteboardIcon, WhiteboardPanel, WifiLowIcon };
|
|
115
|
+
export { ActivitiesControl, ActivitiesIcon, BreakoutBanner, BreakoutIcon, BreakoutsPanel, CameraIcon, CameraOffIcon, CaptionLanguageSettings, CaptionsIcon, ChatIcon, CheckIcon, CloseIcon, EraserIcon, FlagIcon, HandIcon, HighlighterIcon, KeyboardIcon, LayoutIcon, LockIcon, MicIcon, MicOffIcon, MoreIcon, NotesIcon, PencilIcon, PeopleIcon, PhoneIcon, PhoneOffIcon, PinIcon, PollIcon, PollsPanel, QaPanel, QuestionIcon, RecordIcon, ScreenShareIcon, SearchIcon, SettingsIcon, SignalIcon, SmileIcon, SparklesIcon, SpeakerIcon, SpotlightIcon, UndoIcon, UpvoteIcon, WhiteboardIcon, WhiteboardPanel, WifiLowIcon };
|
package/dist/skins/meet.js
CHANGED
|
@@ -160,6 +160,8 @@ var MEET_ROUTES = {
|
|
|
160
160
|
noteTakerStop: "/api/v1/meet/agent/stop",
|
|
161
161
|
/** In-meeting Q&A. Streams NDJSON; body is `{meeting_id, question}` only. */
|
|
162
162
|
intelligenceAsk: "/api/v1/meet/intelligence/ask",
|
|
163
|
+
/** Anyone in the meeting (guests with the room pass included) asks for captions for themselves. */
|
|
164
|
+
noteTakerCaptions: "/api/v1/meet/agent/captions",
|
|
163
165
|
/** A host ends the meeting for everyone. Served by MRI-A6. */
|
|
164
166
|
meetingEnd: "/api/v1/meet/end",
|
|
165
167
|
/**
|
|
@@ -255,6 +257,31 @@ function recordingLabel(state) {
|
|
|
255
257
|
}
|
|
256
258
|
}
|
|
257
259
|
|
|
260
|
+
// src/core/live-policy.ts
|
|
261
|
+
var DEFAULT_LIVE_POLICY = {
|
|
262
|
+
chatMode: "everyone",
|
|
263
|
+
avLock: "off",
|
|
264
|
+
timeLimitMinutes: 0,
|
|
265
|
+
timeLimitWarningMinutes: 5,
|
|
266
|
+
recordingConsent: "notice"
|
|
267
|
+
};
|
|
268
|
+
var MODERATORS = /* @__PURE__ */ new Set(["host", "cohost"]);
|
|
269
|
+
function isLockedFor(policy, role, kind) {
|
|
270
|
+
if (MODERATORS.has(role)) return false;
|
|
271
|
+
return policy.avLock === "both" || (kind === "microphone" ? policy.avLock === "mic" : policy.avLock === "camera");
|
|
272
|
+
}
|
|
273
|
+
function consentPending(policy, role, recordingOn, given) {
|
|
274
|
+
return recordingOn && !given && policy.recordingConsent !== "notice" && !MODERATORS.has(role);
|
|
275
|
+
}
|
|
276
|
+
function canChat(policy, role) {
|
|
277
|
+
if (policy.chatMode === "everyone") return true;
|
|
278
|
+
return policy.chatMode === "hosts_only" && MODERATORS.has(role);
|
|
279
|
+
}
|
|
280
|
+
function minutesLeft(policy, startedAtMs, nowMs) {
|
|
281
|
+
if (policy.timeLimitMinutes <= 0 || startedAtMs === null) return null;
|
|
282
|
+
return Math.ceil((startedAtMs + policy.timeLimitMinutes * 6e4 - nowMs) / 6e4);
|
|
283
|
+
}
|
|
284
|
+
|
|
258
285
|
// src/core/attendance.ts
|
|
259
286
|
var IDLE_MEDIA_REGION = {
|
|
260
287
|
permission: { microphone: "unknown", camera: "unknown" },
|
|
@@ -347,9 +374,17 @@ function autoAssign(identities, rooms, exclude = []) {
|
|
|
347
374
|
return out;
|
|
348
375
|
}
|
|
349
376
|
function breakoutRemainingMs(plan, now) {
|
|
350
|
-
if (plan === null || plan.state !== "open"
|
|
351
|
-
const
|
|
352
|
-
|
|
377
|
+
if (plan === null || plan.state !== "open") return null;
|
|
378
|
+
const ends = [plan.endsAt, plan.closingAt].map((stamp) => stamp === null ? Number.NaN : Date.parse(stamp)).filter((time) => !Number.isNaN(time));
|
|
379
|
+
if (ends.length === 0) return null;
|
|
380
|
+
return Math.max(0, Math.min(...ends) - now);
|
|
381
|
+
}
|
|
382
|
+
var BREAKOUT_COUNTDOWN_MS = 3e4;
|
|
383
|
+
function breakoutClosingMs(plan, now) {
|
|
384
|
+
if (plan === null || plan.state !== "open") return null;
|
|
385
|
+
const remaining = breakoutRemainingMs(plan, now);
|
|
386
|
+
if (remaining === null) return null;
|
|
387
|
+
return plan.closingAt !== null || remaining <= BREAKOUT_COUNTDOWN_MS ? remaining : null;
|
|
353
388
|
}
|
|
354
389
|
function defaultCaptionLanguage(settings, viewerLanguage) {
|
|
355
390
|
const configured = settings?.captionTranslationLanguage.trim() ?? "";
|
|
@@ -557,11 +592,13 @@ function webMediaPlatform() {
|
|
|
557
592
|
|
|
558
593
|
// src/core/observation.ts
|
|
559
594
|
function observedRole(role, standing) {
|
|
560
|
-
if (role === "host" || role === "cohost") return role;
|
|
595
|
+
if (role === "host" || role === "cohost" || role === "presenter") return role;
|
|
561
596
|
return isLinkFollower(standing) ? "guest" : "participant";
|
|
562
597
|
}
|
|
563
|
-
function observedDevice(track, permission = "unknown") {
|
|
598
|
+
function observedDevice(track, permission = "unknown", held = null) {
|
|
599
|
+
if (held === "locked") return "locked";
|
|
564
600
|
if (track.enabled) return "on";
|
|
601
|
+
if (held === "muted_by_host") return "muted_by_host";
|
|
565
602
|
const reason = deviceUnavailableReason(track, permission);
|
|
566
603
|
return reason === null ? "muted_by_me" : `unavailable:${reason}`;
|
|
567
604
|
}
|
|
@@ -598,10 +635,20 @@ function observe(input) {
|
|
|
598
635
|
recording: snapshot?.recording === "recording" || snapshot?.recording === "stopping",
|
|
599
636
|
// S6c: the autoplay region is known only inside the room (no remote audio exists elsewhere).
|
|
600
637
|
audioBlocked: inCall && snapshot !== null ? snapshot.mediaRegion.audioOutput === "blocked" : null,
|
|
601
|
-
camera: deviceInPlay && snapshot !== null ? observedDevice(snapshot.media.camera, snapshot.mediaRegion.permission.camera) : null,
|
|
602
|
-
microphone: deviceInPlay && snapshot !== null ? observedDevice(snapshot.media.microphone, snapshot.mediaRegion.permission.microphone) : null
|
|
638
|
+
camera: deviceInPlay && snapshot !== null ? observedDevice(snapshot.media.camera, snapshot.mediaRegion.permission.camera, lockedFor(snapshot, "camera", inCall)) : null,
|
|
639
|
+
microphone: deviceInPlay && snapshot !== null ? observedDevice(snapshot.media.microphone, snapshot.mediaRegion.permission.microphone, lockedFor(snapshot, "microphone", inCall)) : null
|
|
603
640
|
};
|
|
604
641
|
}
|
|
642
|
+
function lockedFor(snapshot, kind, inCall) {
|
|
643
|
+
if (!inCall) return null;
|
|
644
|
+
const role = effectiveRole(snapshot);
|
|
645
|
+
if (isLockedFor(snapshot.livePolicy, role, kind)) return "locked";
|
|
646
|
+
if (snapshot.livePolicy.recordingConsent === "view_only_until_agree" && consentPending(snapshot.livePolicy, role, snapshot.recording === "recording", snapshot.recordingConsentGiven)) {
|
|
647
|
+
return "locked";
|
|
648
|
+
}
|
|
649
|
+
if (kind === "microphone" && snapshot.mutedByHost) return "muted_by_host";
|
|
650
|
+
return null;
|
|
651
|
+
}
|
|
605
652
|
function staticObservation(phase, reason = null) {
|
|
606
653
|
return {
|
|
607
654
|
phase,
|
|
@@ -704,7 +751,7 @@ function exactNoteTakerParticipant(meeting, participants) {
|
|
|
704
751
|
}
|
|
705
752
|
function noteTakerStatus(args) {
|
|
706
753
|
const present = exactNoteTakerParticipant(args.meeting, args.participants) !== null;
|
|
707
|
-
const raw = args.meeting?.metadata[NOTE_TAKER_METADATA_KEY];
|
|
754
|
+
const raw = args.meeting?.metadata?.[NOTE_TAKER_METADATA_KEY];
|
|
708
755
|
const row = typeof raw === "object" && raw !== null && !Array.isArray(raw) ? raw : {};
|
|
709
756
|
const recorded = readState(row["state"]);
|
|
710
757
|
const detail = typeof row["reason"] === "string" && row["reason"].length > 0 ? row["reason"] : null;
|
|
@@ -1457,6 +1504,45 @@ function useMeetAi() {
|
|
|
1457
1504
|
}, [ai, meeting, dispatchNoteTaker])
|
|
1458
1505
|
};
|
|
1459
1506
|
}
|
|
1507
|
+
function useCaptions() {
|
|
1508
|
+
const host = useMeetHost();
|
|
1509
|
+
const snapshot = useMeetSnapshot();
|
|
1510
|
+
const ai = useMeetAi();
|
|
1511
|
+
const on = snapshot?.captionsOn === true;
|
|
1512
|
+
const refusal = snapshot?.captionsRefusal ?? null;
|
|
1513
|
+
const taker = ai.noteTaker;
|
|
1514
|
+
const meeting = snapshot?.meeting ?? null;
|
|
1515
|
+
const request = useCallback2(() => {
|
|
1516
|
+
if (host === null || meeting === null) return;
|
|
1517
|
+
void host.ai.requestCaptions({ meetingId: meeting.id });
|
|
1518
|
+
}, [host, meeting]);
|
|
1519
|
+
const toggle = useCallback2(() => {
|
|
1520
|
+
if (host === null) return;
|
|
1521
|
+
const next = !on;
|
|
1522
|
+
host.store.patch({ captionsOn: next, captionsRefusal: null });
|
|
1523
|
+
if (next && taker.state !== "joining" && taker.state !== "transcribing") request();
|
|
1524
|
+
}, [host, on, taker.state, request]);
|
|
1525
|
+
let state = "off";
|
|
1526
|
+
let reason = null;
|
|
1527
|
+
let remedy = null;
|
|
1528
|
+
if (on) {
|
|
1529
|
+
if (taker.state === "transcribing" && taker.present) {
|
|
1530
|
+
state = "live";
|
|
1531
|
+
} else if (taker.state === "joining") {
|
|
1532
|
+
state = "starting";
|
|
1533
|
+
} else if (refusal !== null && refusal.reason.length > 0) {
|
|
1534
|
+
state = "unavailable";
|
|
1535
|
+
reason = refusal.reason;
|
|
1536
|
+
remedy = refusal.remedy.length > 0 ? refusal.remedy : null;
|
|
1537
|
+
} else if (taker.state === "ended" || taker.state === "handoff_pending") {
|
|
1538
|
+
state = "unavailable";
|
|
1539
|
+
reason = noteTakerLabel(taker);
|
|
1540
|
+
} else {
|
|
1541
|
+
state = "starting";
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1544
|
+
return { on, state, reason, remedy, toggle };
|
|
1545
|
+
}
|
|
1460
1546
|
function useEndMeeting() {
|
|
1461
1547
|
const host = useMeetHost();
|
|
1462
1548
|
const snapshot = useMeetSnapshot();
|
|
@@ -1494,7 +1580,7 @@ function useConsentNotice() {
|
|
|
1494
1580
|
const snapshot = useMeetSnapshot();
|
|
1495
1581
|
const agent = noteTakerParticipant(snapshot?.participants ?? []);
|
|
1496
1582
|
if (agent === null) return null;
|
|
1497
|
-
return
|
|
1583
|
+
return `AI notes are on. ${agent.displayName} is in this meeting, transcribing what is said and writing notes everyone here can read.`;
|
|
1498
1584
|
}
|
|
1499
1585
|
function useMediaSupervisor() {
|
|
1500
1586
|
const host = useMeetHost();
|
|
@@ -1742,6 +1828,38 @@ function useGuestRecordAccess(meeting) {
|
|
|
1742
1828
|
)
|
|
1743
1829
|
};
|
|
1744
1830
|
}
|
|
1831
|
+
function useLivePolicy() {
|
|
1832
|
+
const snapshot = useMeetSnapshot();
|
|
1833
|
+
const role = useRole();
|
|
1834
|
+
const [now, setNow] = useState2(() => Date.now());
|
|
1835
|
+
const limited = (snapshot?.livePolicy.timeLimitMinutes ?? 0) > 0;
|
|
1836
|
+
useEffect3(() => {
|
|
1837
|
+
if (!limited) return void 0;
|
|
1838
|
+
const timer = setInterval(() => setNow(Date.now()), 1e3);
|
|
1839
|
+
return () => clearInterval(timer);
|
|
1840
|
+
}, [limited]);
|
|
1841
|
+
const policy = snapshot?.livePolicy ?? DEFAULT_LIVE_POLICY;
|
|
1842
|
+
const left = minutesLeft(policy, snapshot?.sessionStartedAt ?? null, now);
|
|
1843
|
+
const host = useMeetHost();
|
|
1844
|
+
const pending = consentPending(policy, role, snapshot?.recording === "recording", snapshot?.recordingConsentGiven === true);
|
|
1845
|
+
const viewOnly = pending && policy.recordingConsent === "view_only_until_agree";
|
|
1846
|
+
const idle = snapshot !== null && snapshot.recording !== "recording" && snapshot.recording !== "starting" && snapshot.recording !== "stopping";
|
|
1847
|
+
const given = snapshot?.recordingConsentGiven === true;
|
|
1848
|
+
const store = host?.store ?? null;
|
|
1849
|
+
useEffect3(() => {
|
|
1850
|
+
if (idle && given) store?.patch({ recordingConsentGiven: false });
|
|
1851
|
+
}, [idle, given, store]);
|
|
1852
|
+
return {
|
|
1853
|
+
canChat: canChat(policy, role),
|
|
1854
|
+
chatMode: policy.chatMode,
|
|
1855
|
+
micLocked: isLockedFor(policy, role, "microphone") || viewOnly,
|
|
1856
|
+
cameraLocked: isLockedFor(policy, role, "camera") || viewOnly,
|
|
1857
|
+
consent: pending ? policy.recordingConsent === "ok_or_leave" ? "ok_or_leave" : "view_only_until_agree" : null,
|
|
1858
|
+
agree: () => store?.patch({ recordingConsentGiven: true }),
|
|
1859
|
+
minutesLeft: left,
|
|
1860
|
+
timeWarning: left !== null && left <= policy.timeLimitWarningMinutes
|
|
1861
|
+
};
|
|
1862
|
+
}
|
|
1745
1863
|
|
|
1746
1864
|
// src/react/collab-hooks.ts
|
|
1747
1865
|
import { useEffect as useEffect4, useRef as useRef4 } from "react";
|
|
@@ -1957,6 +2075,18 @@ function SparklesIcon(props) {
|
|
|
1957
2075
|
/* @__PURE__ */ jsx4("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" })
|
|
1958
2076
|
] });
|
|
1959
2077
|
}
|
|
2078
|
+
function CaptionsIcon(props) {
|
|
2079
|
+
return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
|
|
2080
|
+
/* @__PURE__ */ jsx4("rect", { x: "3", y: "5", width: "18", height: "14", rx: "2" }),
|
|
2081
|
+
/* @__PURE__ */ jsx4("path", { d: "M10 10.5a2 2 0 1 0 0 3M16 10.5a2 2 0 1 0 0 3" })
|
|
2082
|
+
] });
|
|
2083
|
+
}
|
|
2084
|
+
function NotesIcon(props) {
|
|
2085
|
+
return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
|
|
2086
|
+
/* @__PURE__ */ jsx4("path", { d: "M4 20l1-4L16.5 4.5a2.1 2.1 0 0 1 3 3L8 19l-4 1Z" }),
|
|
2087
|
+
/* @__PURE__ */ jsx4("path", { d: "M14 7l3 3" })
|
|
2088
|
+
] });
|
|
2089
|
+
}
|
|
1960
2090
|
function LockIcon(props) {
|
|
1961
2091
|
return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
|
|
1962
2092
|
/* @__PURE__ */ jsx4("rect", { x: "4", y: "10", width: "16", height: "11", rx: "2" }),
|
|
@@ -2875,7 +3005,7 @@ function BreakoutRun({ plan }) {
|
|
|
2875
3005
|
type: "button",
|
|
2876
3006
|
className: "mx-meet__primary mx-meet__primary--small",
|
|
2877
3007
|
onClick: () => void act({ action: "breakout_close" }).then(show),
|
|
2878
|
-
children: "
|
|
3008
|
+
children: "Close rooms"
|
|
2879
3009
|
}
|
|
2880
3010
|
) : null
|
|
2881
3011
|
] });
|
|
@@ -2893,9 +3023,14 @@ function BreakoutBanner() {
|
|
|
2893
3023
|
const { collab, act, moveTo, localIdentity, breakoutRoomId } = useCollab();
|
|
2894
3024
|
const plan = collab?.breakout ?? null;
|
|
2895
3025
|
const open = plan?.state === "open" ? plan : null;
|
|
2896
|
-
const now = useNow(open?.endsAt != null);
|
|
3026
|
+
const now = useNow(open?.endsAt != null || open?.closingAt != null);
|
|
2897
3027
|
const remaining = breakoutRemainingMs(open, now);
|
|
3028
|
+
const closing = breakoutClosingMs(open, now);
|
|
2898
3029
|
const assigned = assignedRoom(open, localIdentity);
|
|
3030
|
+
const [later, setLater] = useState3(null);
|
|
3031
|
+
const [autoSince, setAutoSince] = useState3(null);
|
|
3032
|
+
const AUTO_MOVE_MS = 1e4;
|
|
3033
|
+
const autoLeft = open?.moveMode === "auto" && assigned !== null && autoSince?.id === open.id && later !== open.id ? Math.max(0, AUTO_MOVE_MS - (now - autoSince.at)) : null;
|
|
2899
3034
|
const [dismissedBroadcast, setDismissedBroadcast] = useState3(null);
|
|
2900
3035
|
const [failure, setFailure] = useState3(null);
|
|
2901
3036
|
const expireAsked = useRef5(null);
|
|
@@ -2908,6 +3043,19 @@ function BreakoutBanner() {
|
|
|
2908
3043
|
if ((here ?? null) === request.roomId) return;
|
|
2909
3044
|
void moveTo(request.roomId).then((result) => setFailure(result.ok ? null : result.message));
|
|
2910
3045
|
}, [moveAt, host, moveTo]);
|
|
3046
|
+
const joinAssigned = async () => {
|
|
3047
|
+
if (assigned === null) return;
|
|
3048
|
+
const said = await act({ action: "breakout_join", roomId: assigned.id });
|
|
3049
|
+
const result = said.ok ? await moveTo(assigned.id) : said;
|
|
3050
|
+
setFailure(result.ok ? null : result.message);
|
|
3051
|
+
};
|
|
3052
|
+
useEffect5(() => {
|
|
3053
|
+
if (open === null || open.moveMode !== "auto" || assigned === null || breakoutRoomId !== null) return;
|
|
3054
|
+
if (autoSince?.id !== open.id) setAutoSince({ id: open.id, at: Date.now() });
|
|
3055
|
+
}, [open, assigned, breakoutRoomId, autoSince]);
|
|
3056
|
+
useEffect5(() => {
|
|
3057
|
+
if (autoLeft === 0) void joinAssigned();
|
|
3058
|
+
}, [autoLeft]);
|
|
2911
3059
|
useEffect5(() => {
|
|
2912
3060
|
if (open === null || remaining === null || remaining > 0) return;
|
|
2913
3061
|
const asked = expireAsked.current;
|
|
@@ -2921,27 +3069,25 @@ function BreakoutBanner() {
|
|
|
2921
3069
|
if (open === null && failure === null) return null;
|
|
2922
3070
|
return /* @__PURE__ */ jsxs2("div", { className: "mx-meet__breakout-banner", role: "status", children: [
|
|
2923
3071
|
failure !== null ? /* @__PURE__ */ jsx5("span", { className: "mx-meet__collab-error", children: failure }) : null,
|
|
3072
|
+
closing !== null ? /* @__PURE__ */ jsxs2("span", { role: "status", "data-meet-notice": "breakout-closing", children: [
|
|
3073
|
+
"Rooms closing in ",
|
|
3074
|
+
Math.ceil(closing / 1e3),
|
|
3075
|
+
room !== null ? " \u2014 you return to the main meeting" : ""
|
|
3076
|
+
] }) : null,
|
|
2924
3077
|
room !== null ? /* @__PURE__ */ jsxs2("span", { children: [
|
|
2925
3078
|
/* @__PURE__ */ jsx5("strong", { children: room.name }),
|
|
2926
|
-
remaining !== null ? ` \xB7 ${clock(remaining)} left` : "",
|
|
3079
|
+
remaining !== null && closing === null ? ` \xB7 ${clock(remaining)} left` : "",
|
|
2927
3080
|
/* @__PURE__ */ jsx5("button", { type: "button", className: "mx-meet__chip", onClick: () => void moveTo(null), children: "Return to main room" })
|
|
3081
|
+
] }) : assigned !== null && later !== open?.id ? /* @__PURE__ */ jsxs2("span", { children: [
|
|
3082
|
+
autoLeft !== null ? `You're being moved to ${assigned.name} in ${Math.ceil(autoLeft / 1e3)} s` : `You're invited to ${assigned.name}`,
|
|
3083
|
+
remaining !== null && closing === null ? ` \xB7 ${clock(remaining)} left` : "",
|
|
3084
|
+
/* @__PURE__ */ jsx5("button", { type: "button", className: "mx-meet__primary mx-meet__primary--small", onClick: () => void joinAssigned(), children: "Join room" }),
|
|
3085
|
+
/* @__PURE__ */ jsx5("button", { type: "button", className: "mx-meet__chip", onClick: () => setLater(open?.id ?? null), children: "Later" })
|
|
2928
3086
|
] }) : assigned !== null ? /* @__PURE__ */ jsxs2("span", { children: [
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
"button",
|
|
2934
|
-
{
|
|
2935
|
-
type: "button",
|
|
2936
|
-
className: "mx-meet__primary mx-meet__primary--small",
|
|
2937
|
-
onClick: () => void act({ action: "breakout_join", roomId: assigned.id }).then(async (said) => {
|
|
2938
|
-
const result = said.ok ? await moveTo(assigned.id) : said;
|
|
2939
|
-
setFailure(result.ok ? null : result.message);
|
|
2940
|
-
}),
|
|
2941
|
-
children: "Join"
|
|
2942
|
-
}
|
|
2943
|
-
)
|
|
2944
|
-
] }) : open?.allowChoose ? /* @__PURE__ */ jsx5("span", { children: "Breakout rooms are open \u2014 pick one under Activities." }) : null,
|
|
3087
|
+
assigned.name,
|
|
3088
|
+
" is open",
|
|
3089
|
+
/* @__PURE__ */ jsx5("button", { type: "button", className: "mx-meet__chip", onClick: () => void joinAssigned(), children: "Join room" })
|
|
3090
|
+
] }) : open?.allowChoose ? /* @__PURE__ */ jsx5("span", { children: "Rooms are open \u2014 pick one under Activities." }) : null,
|
|
2945
3091
|
showBroadcast ? /* @__PURE__ */ jsxs2("span", { className: "mx-meet__breakout-broadcast", children: [
|
|
2946
3092
|
/* @__PURE__ */ jsxs2("strong", { children: [
|
|
2947
3093
|
broadcast.by,
|
|
@@ -2989,6 +3135,33 @@ function CaptionLanguageSettings() {
|
|
|
2989
3135
|
collab?.captionTranslationError != null ? /* @__PURE__ */ jsx5("p", { className: "mx-meet__panel-note mx-meet__collab-error", children: collab.captionTranslationError }) : null
|
|
2990
3136
|
] });
|
|
2991
3137
|
}
|
|
3138
|
+
function CaptionsControl() {
|
|
3139
|
+
const captions = useCaptions();
|
|
3140
|
+
return /* @__PURE__ */ jsx5(
|
|
3141
|
+
ControlButton,
|
|
3142
|
+
{
|
|
3143
|
+
label: captions.on ? "Turn off captions" : "Turn on captions",
|
|
3144
|
+
active: captions.on,
|
|
3145
|
+
pressed: captions.on,
|
|
3146
|
+
onClick: captions.toggle,
|
|
3147
|
+
children: /* @__PURE__ */ jsx5(CaptionsIcon, {})
|
|
3148
|
+
}
|
|
3149
|
+
);
|
|
3150
|
+
}
|
|
3151
|
+
function TakeNotesControl() {
|
|
3152
|
+
const ai = useMeetAi();
|
|
3153
|
+
if (!ai.canControlNoteTaker) return null;
|
|
3154
|
+
const running = ai.noteTaker.state === "joining" || ai.noteTaker.state === "transcribing";
|
|
3155
|
+
return /* @__PURE__ */ jsx5(
|
|
3156
|
+
ControlButton,
|
|
3157
|
+
{
|
|
3158
|
+
label: running ? "Stop taking notes" : "Take notes for me",
|
|
3159
|
+
active: running,
|
|
3160
|
+
onClick: () => void (running ? ai.stopNoteTaker() : ai.startNoteTaker()),
|
|
3161
|
+
children: /* @__PURE__ */ jsx5(NotesIcon, {})
|
|
3162
|
+
}
|
|
3163
|
+
);
|
|
3164
|
+
}
|
|
2992
3165
|
|
|
2993
3166
|
// src/skins/meet/components.tsx
|
|
2994
3167
|
import { Fragment, jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
@@ -3039,6 +3212,7 @@ function ControlButton({
|
|
|
3039
3212
|
label,
|
|
3040
3213
|
active = false,
|
|
3041
3214
|
danger = false,
|
|
3215
|
+
pressed,
|
|
3042
3216
|
onClick,
|
|
3043
3217
|
children
|
|
3044
3218
|
}) {
|
|
@@ -3053,26 +3227,49 @@ function ControlButton({
|
|
|
3053
3227
|
].filter(Boolean).join(" "),
|
|
3054
3228
|
"aria-label": label,
|
|
3055
3229
|
title: label,
|
|
3230
|
+
...pressed !== void 0 ? { "aria-pressed": pressed } : {},
|
|
3056
3231
|
onClick,
|
|
3057
3232
|
children
|
|
3058
3233
|
}
|
|
3059
3234
|
);
|
|
3060
3235
|
}
|
|
3061
3236
|
function RecordingIndicator() {
|
|
3062
|
-
const { state, label } = useRecording();
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
]
|
|
3237
|
+
const { state, label, canStart } = useRecording();
|
|
3238
|
+
const snapshot = useMeetSnapshot();
|
|
3239
|
+
const previous = useRef6(state);
|
|
3240
|
+
const [stoppedAt, setStoppedAt] = useState4(null);
|
|
3241
|
+
useEffect6(() => {
|
|
3242
|
+
const was = previous.current;
|
|
3243
|
+
previous.current = state;
|
|
3244
|
+
if ((was === "recording" || was === "starting") && state !== "recording" && state !== "starting") {
|
|
3245
|
+
setStoppedAt(Date.now());
|
|
3246
|
+
const timer = setTimeout(() => setStoppedAt(null), 1e4);
|
|
3247
|
+
return () => clearTimeout(timer);
|
|
3074
3248
|
}
|
|
3075
|
-
|
|
3249
|
+
return void 0;
|
|
3250
|
+
}, [state]);
|
|
3251
|
+
const meetingId = snapshot?.meeting?.id ?? null;
|
|
3252
|
+
if (label === null && stoppedAt === null) return null;
|
|
3253
|
+
return /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
3254
|
+
label !== null ? /* @__PURE__ */ jsxs3(
|
|
3255
|
+
"span",
|
|
3256
|
+
{
|
|
3257
|
+
className: `mx-meet__recording mx-meet__recording--${state}`,
|
|
3258
|
+
role: "status",
|
|
3259
|
+
"aria-live": "polite",
|
|
3260
|
+
children: [
|
|
3261
|
+
/* @__PURE__ */ jsx6(RecordIcon, { width: 10, height: 10 }),
|
|
3262
|
+
label
|
|
3263
|
+
]
|
|
3264
|
+
}
|
|
3265
|
+
) : null,
|
|
3266
|
+
stoppedAt !== null ? /* @__PURE__ */ jsx6("span", { className: "mx-meet__recording", role: "status", "data-meet-notice": "recording-stopped", children: "Recording stopped" }) : null,
|
|
3267
|
+
state === "processing" ? (
|
|
3268
|
+
// rec-processing: the host is told it is being made ready (the indicator says Processing…).
|
|
3269
|
+
/* @__PURE__ */ jsx6("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." })
|
|
3270
|
+
) : null,
|
|
3271
|
+
state === "available" && canStart && meetingId !== null ? /* @__PURE__ */ jsx6("a", { className: "mx-meet__link", href: `/meetings/${meetingId}`, target: "_blank", rel: "noreferrer", children: "View recording" }) : null
|
|
3272
|
+
] });
|
|
3076
3273
|
}
|
|
3077
3274
|
function ConnectionDot({ quality }) {
|
|
3078
3275
|
if (quality === "excellent" || quality === "good" || quality === "unknown") return null;
|
|
@@ -3228,6 +3425,7 @@ function ControlBar({ onLeave }) {
|
|
|
3228
3425
|
const controls = useHostControls();
|
|
3229
3426
|
const queue = useHandQueue();
|
|
3230
3427
|
const micUnavailable = useLocalMedia().microphone.unavailable;
|
|
3428
|
+
const live = useLivePolicy();
|
|
3231
3429
|
const unread = useUnreadChat(panel === "chat");
|
|
3232
3430
|
const [whiteboard, setWhiteboard] = useState4(false);
|
|
3233
3431
|
const app = useMeetAppPanel();
|
|
@@ -3295,7 +3493,7 @@ function ControlBar({ onLeave }) {
|
|
|
3295
3493
|
panel !== "people" ? /* @__PURE__ */ jsx6(KnockNotice, { onView: () => setPanel("people") }) : null,
|
|
3296
3494
|
controls.notice !== null && panel !== "people" ? /* @__PURE__ */ jsx6(Toast, { text: controls.notice.text, failed: controls.notice.failed, onDone: controls.clearNotice }) : null,
|
|
3297
3495
|
/* @__PURE__ */ jsxs3("div", { className: "mx-meet__controls", children: [
|
|
3298
|
-
/* @__PURE__ */ jsx6(
|
|
3496
|
+
live.micLocked ? null : /* @__PURE__ */ jsx6(
|
|
3299
3497
|
ControlButton,
|
|
3300
3498
|
{
|
|
3301
3499
|
label: micUnavailable !== null ? `Unmute \u2014 ${micUnavailable.remedy}` : room.local?.micEnabled === true ? "Mute (\u2318D)" : "Unmute (\u2318D)",
|
|
@@ -3304,7 +3502,7 @@ function ControlBar({ onLeave }) {
|
|
|
3304
3502
|
children: room.local?.micEnabled === true ? /* @__PURE__ */ jsx6(MicIcon, {}) : /* @__PURE__ */ jsx6(MicOffIcon, {})
|
|
3305
3503
|
}
|
|
3306
3504
|
),
|
|
3307
|
-
/* @__PURE__ */ jsx6(
|
|
3505
|
+
live.cameraLocked ? null : /* @__PURE__ */ jsx6(
|
|
3308
3506
|
ControlButton,
|
|
3309
3507
|
{
|
|
3310
3508
|
label: room.local?.cameraEnabled === true ? "Stop video (\u2318E)" : "Start video (\u2318E)",
|
|
@@ -3313,6 +3511,7 @@ function ControlBar({ onLeave }) {
|
|
|
3313
3511
|
children: room.local?.cameraEnabled === true ? /* @__PURE__ */ jsx6(CameraIcon, {}) : /* @__PURE__ */ jsx6(CameraOffIcon, {})
|
|
3314
3512
|
}
|
|
3315
3513
|
),
|
|
3514
|
+
/* @__PURE__ */ jsx6(CaptionsControl, {}),
|
|
3316
3515
|
room.canShareScreen || room.local?.screenSharing === true ? /* @__PURE__ */ jsx6(
|
|
3317
3516
|
ControlButton,
|
|
3318
3517
|
{
|
|
@@ -3377,6 +3576,7 @@ function ControlBar({ onLeave }) {
|
|
|
3377
3576
|
onOpen: openActivity
|
|
3378
3577
|
}
|
|
3379
3578
|
),
|
|
3579
|
+
/* @__PURE__ */ jsx6(TakeNotesControl, {}),
|
|
3380
3580
|
/* @__PURE__ */ jsx6(AiControl, { active: panel === "ai", onToggle: () => toggle("ai") }),
|
|
3381
3581
|
recording.canStart ? /* @__PURE__ */ jsx6(ControlButton, { label: "Start recording", onClick: () => void recording.start(), children: /* @__PURE__ */ jsx6(RecordIcon, {}) }) : null,
|
|
3382
3582
|
recording.canStop ? /* @__PURE__ */ jsx6(ControlButton, { label: "Stop recording", active: true, onClick: () => void recording.stop(), children: /* @__PURE__ */ jsx6(RecordIcon, {}) }) : null,
|
|
@@ -3432,6 +3632,23 @@ function ControlBar({ onLeave }) {
|
|
|
3432
3632
|
]
|
|
3433
3633
|
}
|
|
3434
3634
|
),
|
|
3635
|
+
/* @__PURE__ */ jsxs3(
|
|
3636
|
+
MenuItem,
|
|
3637
|
+
{
|
|
3638
|
+
onSelect: () => {
|
|
3639
|
+
setPopover("none");
|
|
3640
|
+
void controls.run({
|
|
3641
|
+
action: "set_av_lock",
|
|
3642
|
+
value: snapshot?.livePolicy.avLock === "both" ? "off" : "both"
|
|
3643
|
+
});
|
|
3644
|
+
},
|
|
3645
|
+
children: [
|
|
3646
|
+
/* @__PURE__ */ jsx6(MicOffIcon, { width: 16, height: 16 }),
|
|
3647
|
+
" ",
|
|
3648
|
+
snapshot?.livePolicy.avLock === "both" ? "Turn on attendees' microphone and camera" : "Turn off attendees' microphone and camera"
|
|
3649
|
+
]
|
|
3650
|
+
}
|
|
3651
|
+
),
|
|
3435
3652
|
/* @__PURE__ */ jsxs3(
|
|
3436
3653
|
MenuItem,
|
|
3437
3654
|
{
|
|
@@ -3759,9 +3976,45 @@ function MeetingOverlays() {
|
|
|
3759
3976
|
const reactions = useReactions();
|
|
3760
3977
|
const { notice, dismiss } = useModerationNotice();
|
|
3761
3978
|
const room = useRoom();
|
|
3979
|
+
const live = useLivePolicy();
|
|
3980
|
+
const snapshot = useMeetSnapshot();
|
|
3981
|
+
const controls = useHostControls();
|
|
3982
|
+
const isHostNow = useRole() === "host";
|
|
3762
3983
|
return /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
3763
3984
|
/* @__PURE__ */ jsx6(ReactionOverlay, { reactions }),
|
|
3764
3985
|
/* @__PURE__ */ jsx6(MediaNotices, {}),
|
|
3986
|
+
snapshot !== null && snapshot.phase === "in_call" && snapshot.participants.length >= 2 && !snapshot.participants.some((p) => p.role === "host" || p.role === "cohost") ? (
|
|
3987
|
+
// meeting-without-host: the call goes on; host-only controls are simply not on screen.
|
|
3988
|
+
/* @__PURE__ */ jsx6("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." })
|
|
3989
|
+
) : null,
|
|
3990
|
+
live.consent !== null ? /* @__PURE__ */ jsx6("div", { className: "mx-meet__sheet-backdrop", children: /* @__PURE__ */ jsxs3("div", { className: "mx-meet__sheet", role: "alertdialog", "aria-label": "This meeting is being recorded", "data-meet-notice": "recording-consent", children: [
|
|
3991
|
+
/* @__PURE__ */ jsx6("h2", { className: "mx-meet__panel-title", children: "This meeting is being recorded" }),
|
|
3992
|
+
/* @__PURE__ */ jsx6("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." }),
|
|
3993
|
+
/* @__PURE__ */ jsxs3("div", { className: "mx-meet__menu-actions", children: [
|
|
3994
|
+
/* @__PURE__ */ jsx6("button", { type: "button", className: "mx-meet__send", onClick: live.agree, children: live.consent === "ok_or_leave" ? "OK" : "I agree" }),
|
|
3995
|
+
live.consent === "ok_or_leave" ? /* @__PURE__ */ jsx6("button", { type: "button", className: "mx-meet__link", onClick: () => void room.leave(), children: "Leave meeting" }) : null
|
|
3996
|
+
] })
|
|
3997
|
+
] }) }) : null,
|
|
3998
|
+
snapshot?.canReclaim === true && !isHostNow ? /* @__PURE__ */ jsxs3("div", { className: "mx-meet__notice-bar", role: "status", "data-meet-notice": "host-reclaim", children: [
|
|
3999
|
+
/* @__PURE__ */ jsx6("span", { children: "You started this meeting. Take back the host?" }),
|
|
4000
|
+
/* @__PURE__ */ jsx6(
|
|
4001
|
+
"button",
|
|
4002
|
+
{
|
|
4003
|
+
type: "button",
|
|
4004
|
+
className: "mx-meet__primary mx-meet__primary--small",
|
|
4005
|
+
onClick: () => void controls.run({ action: "reclaim_host" }),
|
|
4006
|
+
children: "Reclaim host"
|
|
4007
|
+
}
|
|
4008
|
+
)
|
|
4009
|
+
] }) : null,
|
|
4010
|
+
live.micLocked || live.cameraLocked ? /* @__PURE__ */ jsx6("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,
|
|
4011
|
+
live.timeWarning && live.minutesLeft !== null && live.minutesLeft > 0 ? /* @__PURE__ */ jsxs3("p", { className: "mx-meet__banner", role: "status", "data-meet-notice": "time-warning", children: [
|
|
4012
|
+
"This meeting will end in ",
|
|
4013
|
+
live.minutesLeft,
|
|
4014
|
+
" ",
|
|
4015
|
+
live.minutesLeft === 1 ? "minute" : "minutes",
|
|
4016
|
+
" (time limit)."
|
|
4017
|
+
] }) : null,
|
|
3765
4018
|
notice !== null && notice.kind !== "removed" ? (
|
|
3766
4019
|
// A host's request ("the host is asking you to unmute"), not an error:
|
|
3767
4020
|
// an assertive status, so it is announced at once without being filed
|
|
@@ -3852,6 +4105,7 @@ function ChatPanel({
|
|
|
3852
4105
|
}) {
|
|
3853
4106
|
const snapshot = useMeetSnapshot();
|
|
3854
4107
|
const room = useRoom();
|
|
4108
|
+
const live = useLivePolicy();
|
|
3855
4109
|
const [draft, setDraft] = useState4("");
|
|
3856
4110
|
const [recipient, setRecipient] = useState4(to);
|
|
3857
4111
|
const listRef = useRef6(null);
|
|
@@ -3876,7 +4130,7 @@ function ChatPanel({
|
|
|
3876
4130
|
snapshot?.chatLoaded !== true && messages.length === 0 ? /* @__PURE__ */ jsx6("li", { className: "mx-meet__panel-note", children: "Reading earlier messages\u2026" }) : messages.length === 0 && snapshot?.chatHistoryError == null ? /* @__PURE__ */ jsx6("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,
|
|
3877
4131
|
messages.map((message) => /* @__PURE__ */ jsx6(ChatLine, { message, local, people }, message.id))
|
|
3878
4132
|
] }),
|
|
3879
|
-
/* @__PURE__ */ jsxs3(
|
|
4133
|
+
!live.canChat ? /* @__PURE__ */ jsx6("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__ */ jsxs3(
|
|
3880
4134
|
"form",
|
|
3881
4135
|
{
|
|
3882
4136
|
className: "mx-meet__composer mx-meet__composer--chat",
|
|
@@ -4248,6 +4502,13 @@ function PersonMenu({
|
|
|
4248
4502
|
/* @__PURE__ */ jsx6(PeopleIcon, { width: 16, height: 16 }),
|
|
4249
4503
|
" Make co-host"
|
|
4250
4504
|
] }) : null,
|
|
4505
|
+
!participant.isAgent && participant.role !== "cohost" && participant.role !== "host" ? participant.role === "presenter" ? /* @__PURE__ */ jsxs3(MenuItem, { onSelect: () => act({ action: "revoke_presenter", identity: participant.identity }), children: [
|
|
4506
|
+
/* @__PURE__ */ jsx6(ScreenShareIcon, { width: 16, height: 16 }),
|
|
4507
|
+
" Remove presenter"
|
|
4508
|
+
] }) : /* @__PURE__ */ jsxs3(MenuItem, { onSelect: () => act({ action: "make_presenter", identity: participant.identity }), children: [
|
|
4509
|
+
/* @__PURE__ */ jsx6(ScreenShareIcon, { width: 16, height: 16 }),
|
|
4510
|
+
" Make presenter"
|
|
4511
|
+
] }) : null,
|
|
4251
4512
|
!participant.isAgent ? /* @__PURE__ */ jsxs3(
|
|
4252
4513
|
MenuItem,
|
|
4253
4514
|
{
|
|
@@ -4753,8 +5014,19 @@ function Captions({ lines = 3 }) {
|
|
|
4753
5014
|
const ai = useMeetAi();
|
|
4754
5015
|
const visible = ai.transcript.slice(-lines);
|
|
4755
5016
|
const translation = useCaptionTranslation(visible);
|
|
4756
|
-
|
|
4757
|
-
|
|
5017
|
+
const captions = useCaptions();
|
|
5018
|
+
if (!captions.on) return null;
|
|
5019
|
+
if (captions.state === "unavailable") {
|
|
5020
|
+
return /* @__PURE__ */ jsx6("div", { className: "mx-meet__captions", role: "status", "data-meet-notice": "captions-unavailable", children: /* @__PURE__ */ jsxs3("p", { className: "mx-meet__caption", children: [
|
|
5021
|
+
"Captions are unavailable. ",
|
|
5022
|
+
captions.reason,
|
|
5023
|
+
captions.remedy !== null ? ` ${captions.remedy}` : ""
|
|
5024
|
+
] }) });
|
|
5025
|
+
}
|
|
5026
|
+
if (visible.length === 0) {
|
|
5027
|
+
return /* @__PURE__ */ jsx6("div", { className: "mx-meet__captions", "aria-live": "polite", "aria-label": "Live captions", "data-meet-caption": captions.state, children: /* @__PURE__ */ jsx6("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." }) });
|
|
5028
|
+
}
|
|
5029
|
+
return /* @__PURE__ */ jsxs3("div", { className: "mx-meet__captions", "aria-live": "polite", "aria-label": "Live captions", "data-meet-caption": "live", children: [
|
|
4758
5030
|
visible.map((line) => {
|
|
4759
5031
|
const translated = translation.language === null ? void 0 : translation.translations[line.id];
|
|
4760
5032
|
return /* @__PURE__ */ jsxs3(
|
|
@@ -4777,7 +5049,7 @@ function Captions({ lines = 3 }) {
|
|
|
4777
5049
|
function ConsentNotice() {
|
|
4778
5050
|
const notice = useConsentNotice();
|
|
4779
5051
|
if (notice === null) return null;
|
|
4780
|
-
return /* @__PURE__ */ jsx6("p", { className: "mx-meet__consent", role: "status", children: notice });
|
|
5052
|
+
return /* @__PURE__ */ jsx6("p", { className: "mx-meet__consent", role: "status", "data-meet-notice": "notes-started", children: notice });
|
|
4781
5053
|
}
|
|
4782
5054
|
function AttendanceNotice() {
|
|
4783
5055
|
const media = useLocalMedia();
|
|
@@ -5491,6 +5763,7 @@ export {
|
|
|
5491
5763
|
CameraOffIcon,
|
|
5492
5764
|
CaptionLanguageSettings,
|
|
5493
5765
|
Captions,
|
|
5766
|
+
CaptionsIcon,
|
|
5494
5767
|
ChatIcon,
|
|
5495
5768
|
ChatPanel,
|
|
5496
5769
|
CheckIcon,
|
|
@@ -5514,6 +5787,7 @@ export {
|
|
|
5514
5787
|
MicIcon,
|
|
5515
5788
|
MicOffIcon,
|
|
5516
5789
|
MoreIcon,
|
|
5790
|
+
NotesIcon,
|
|
5517
5791
|
PanelShell,
|
|
5518
5792
|
ParticipantTile,
|
|
5519
5793
|
PencilIcon,
|