1import type { BrowserSurfaceRect } from "./browserSurfaceStore";
2
3export interface HostedBrowserWebviewSize {
4 readonly width: number;
5 readonly height: number;
6}
7
8export interface HostedBrowserWebviewWrapperStyle {
9 readonly left: number;
10 readonly top: number;
11 readonly width: number;
12 readonly height: number;
13 readonly zIndex: number;
14 readonly pointerEvents: "auto" | "none";
15 readonly borderRadius?: number;
16 readonly visibility?: "hidden" | "visible";
17}
18
19export const HIDDEN_BROWSER_WEBVIEW_OFFSET = -100_000;
20
21export function resolveHostedBrowserWebviewWrapperStyle(input: {
22 readonly active: boolean;
23 readonly renderingActive: boolean;
24 readonly keepPaintableWhenInactive?: boolean;
25 readonly cornerRadius?: number;
26 readonly zIndex?: number;
27 readonly rect: BrowserSurfaceRect | null;
28 readonly hiddenSize: HostedBrowserWebviewSize;
29}): HostedBrowserWebviewWrapperStyle {
30 const {
31 active,
32 cornerRadius = 0,
33 hiddenSize,
34 keepPaintableWhenInactive = false,
35 rect,
36 renderingActive,
37 zIndex = 30,
38 } = input;
39 if (active && rect) {
40 return {
41 left: rect.x,
42 top: rect.y,
43 width: rect.width,
44 height: rect.height,
45 zIndex,
46 pointerEvents: "auto",
47 ...(cornerRadius > 0 ? { borderRadius: cornerRadius } : {}),
48 };
49 }
50
51 if (renderingActive) {
52 // Electron stops compositing a guest that is fully outside the window, even
53 // when background throttling is disabled. Keep capture-active guests inside
54 // the viewport but behind the app so recordings receive complete frames.
55 return {
56 left: 0,
57 top: 0,
58 width: hiddenSize.width,
59 height: hiddenSize.height,
60 zIndex: -1,
61 pointerEvents: "none",
62 visibility: "visible",
63 };
64 }
65
66 return {
67 left: HIDDEN_BROWSER_WEBVIEW_OFFSET,
68 top: HIDDEN_BROWSER_WEBVIEW_OFFSET,
69 width: hiddenSize.width,
70 height: hiddenSize.height,
71 zIndex: -1,
72 pointerEvents: "none",
73 visibility: keepPaintableWhenInactive ? "visible" : "hidden",
74 };
75}