Files
element-call/src/lotus/LotusScreensharePrompt.tsx
T

103 lines
3.1 KiB
TypeScript
Raw Normal View History

/*
Copyright 2026 Lotus Guild
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE in the repository root for full details.
*/
import { type FC, useCallback, useEffect, useId, useRef } from "react";
import { Button, Text } from "@vector-im/compound-web";
import { type CallViewModel } from "../state/CallViewModel/CallViewModel";
import { useBehavior } from "../useBehavior";
import {
lotusFrameScreenshareEnabled,
lotusFrameScreenshareVisible$,
lotusScreensharePrompt$,
} from "./lotusControls";
import styles from "./LotusScreensharePrompt.module.css";
/**
* [cinny #43] "Share your screen?" asked inside the call frame, for hosts that
* can't hand the user's click to this frame (Firefox, Safari, WebKitGTK). The
* host's call-bar button sends `io.lotus.prompt_screenshare`; the Share click
* lands here, so getDisplayMedia runs with this frame's own activation. Same
* two clicks as the host's own confirm on Chromium.
*/
export const LotusScreensharePrompt: FC<{ vm: CallViewModel }> = ({ vm }) => {
const open = useBehavior(lotusScreensharePrompt$);
const sharing = useBehavior(vm.sharingScreen$);
const allowed = useBehavior(lotusFrameScreenshareVisible$);
const shareRef = useRef<HTMLButtonElement>(null);
const titleId = useId();
const descriptionId = useId();
const close = useCallback(() => lotusScreensharePrompt$.next(false), []);
// Stale once a share is running (started some other way) or the room's
// policy stops allowing it.
useEffect(() => {
if (open && (sharing || !allowed)) close();
}, [open, sharing, allowed, close]);
useEffect(() => {
if (open) shareRef.current?.focus();
}, [open]);
useEffect(() => {
if (!open) return undefined;
const onKeyDown = (e: KeyboardEvent): void => {
if (e.key !== "Escape") return;
e.preventDefault();
close();
};
window.addEventListener("keydown", onKeyDown, true);
return (): void => window.removeEventListener("keydown", onKeyDown, true);
}, [open, close]);
const toggle = vm.toggleScreenSharing;
if (!open || !lotusFrameScreenshareEnabled() || !toggle) return null;
const onShare = (): void => {
close();
// Synchronously inside this click: getDisplayMedia needs its activation.
toggle();
};
return (
<div
className={styles.prompt}
role="alertdialog"
aria-labelledby={titleId}
aria-describedby={descriptionId}
data-testid="lotus_screenshare_prompt"
>
<Text
as="h2"
id={titleId}
size="md"
weight="semibold"
className={styles.title}
>
Share your screen?
</Text>
<Text id={descriptionId} size="md" className={styles.description}>
Your screen will be visible to everyone in this call.
</Text>
<div className={styles.buttons}>
<Button
ref={shareRef}
size="md"
onClick={onShare}
data-testid="lotus_screenshare_prompt_share"
>
Share
</Button>
<Button size="md" kind="secondary" onClick={close}>
Cancel
</Button>
</div>
</div>
);
};