fix(web): portal overlays into fullscreenElement so they render in voice fullscreen

requestFullscreen() on the voice container puts only its descendants in the
browser's top layer; overlays portaled to document.body were rendered outside
that layer and stayed invisible — most visibly the right-click context menu on
stream tiles and voice user panels.

Add usePortalContainer() hook returning document.fullscreenElement ?? document.body
and re-rendering on fullscreenchange. Migrate every overlay reachable during a
call: ContextMenuRenderer (desktop, submenu, mobile sheet), Tooltip,
ConfirmDialog, ConnectionInfoPopover, ScreenShareSettingsPopover, and
ScreenSharePicker (which previously rendered inline at App root).
This commit is contained in:
Jannis Braun
2026-04-29 23:32:14 +02:00
parent 1ed70a90b1
commit e0861597bc
9 changed files with 67 additions and 9 deletions
@@ -5,6 +5,7 @@ import type { ScreenShareConfig } from '../../stores/voiceStore';
import { useSettingsStore } from '../../stores/settingsStore';
import { buildScreenShareOptions } from '../../utils/screenShare';
import { useFloatingPosition } from '../../hooks/useFloatingPosition';
import { usePortalContainer } from '../../hooks/usePortalContainer';
import { Toggle } from '../ui/Toggle';
import { isElectron } from '../../platform/platform';
import { RESOLUTION_LABELS } from '@backspace/shared/src/constants';
@@ -46,6 +47,7 @@ function formatKbps(kbps: number): string {
export function ScreenShareSettingsPopover({ open, onClose, anchorRef }: ScreenShareSettingsPopoverProps) {
const popoverRef = useRef<HTMLDivElement>(null);
const portalContainer = usePortalContainer();
const config = useVoiceStore((s) => s.screenShareConfig);
const setConfig = useVoiceStore((s) => s.setScreenShareConfig);
const hwOverdrive = useVoiceStore((s) => s.hwOverdrive);
@@ -296,6 +298,6 @@ export function ScreenShareSettingsPopover({ open, onClose, anchorRef }: ScreenS
</span>
</div>
</div>,
document.body,
portalContainer,
);
}