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
@@ -1,7 +1,9 @@
import React, { useState, useEffect, useCallback, useMemo } from 'react';
import { createPortal } from 'react-dom';
import { create } from 'zustand';
import { getElectronAPI } from '../../platform/platform';
import { useVoiceStore } from '../../stores/voiceStore';
import { usePortalContainer } from '../../hooks/usePortalContainer';
// ---------------------------------------------------------------------------
// Zustand micro-store — bridges the event-driven API to React state
@@ -40,6 +42,7 @@ export function ScreenSharePicker() {
const [search, setSearch] = useState('');
const shareAudio = useVoiceStore((s) => s.screenShareConfig.shareAudio);
const setScreenShareConfig = useVoiceStore((s) => s.setScreenShareConfig);
const portalContainer = usePortalContainer();
// Register listener for sources from main process (once on mount)
useEffect(() => {
@@ -100,7 +103,7 @@ export function ScreenSharePicker() {
const activeSources = activeTab === 'screens' ? screens : windows;
return (
return createPortal(
<div className="fixed inset-0 z-[200] flex items-center justify-center animate-fade-in">
{/* Backdrop */}
<div
@@ -211,7 +214,8 @@ export function ScreenSharePicker() {
</div>
</div>
</div>
</div>
</div>,
portalContainer,
);
}