/** * FullscreenSwitchController — the ONE place fullscreen enter/exit lives. * * Framework-agnostic (no React): the consumer passes callbacks (and, for * page-level surfaces, the mask classes); the controller owns the * Fullscreen API calls, webkit fallbacks, and the flicker-free switch * choreography. Originally extracted from the hub's company-hub deck (PR * #737); moved into the lib so EVERY fullscreen surface — the deck, the * embed viewers — shares one implementation instead of re-deriving the * event-ordering lessons below. The hub's `lib/utils/fullscreen-switch.ts` * re-exports from here (extractItems shim precedent). * * Two shapes of consumer: * - PAGE-LEVEL (the deck): no `target` — fullscreens * `document.documentElement`, uses the mask classes + geometry pulses. * - ELEMENT-LEVEL (embed viewers): pass `target` — fullscreens one * element; classes/pulses are optional and simply skipped when absent. * * Invariants (each guards a bug found while building the deck's fullscreen): * - Fullscreen STATE follows the fullscreenchange event exclusively (never * set optimistically): Esc, keyboard shortcuts, buttons and browser * chrome all converge on one listener. * - The switching mask (when configured) goes up PRE-EMPTIVELY: * Chrome/Safari PAINT resized frames BEFORE fullscreenchange fires * (whatwg/fullscreen#74), so masking inside the change event is already * too late. `toggle()` masks before requesting; an Escape keydown * listener (capture) masks the one exit path that skips toggle(); the * change event remains the fallback for browser-chrome-initiated * transitions. * - The swap is a multi-frame viewport animation (macOS especially): one * rAF re-anchor is NOT enough. While masked, every resize fires * onGeometryPulse (re-measure + re-anchor under a constant scrollY); * quiet resizes for `quietMs` (or the `capMs` hard cap — a rejected * fullscreen request after a pre-emptive mask must never wedge the mask * up) end the switch. */ export interface FullscreenSwitchOptions { /** The element to fullscreen. Omit for page-level surfaces (the deck): * `document.documentElement` — window scrolling survives, which * element-level fullscreen would freeze. A callback so refs resolve at * toggle time, not construction time. */ target?: () => HTMLElement | null; /** Held on while fullscreen is ACTIVE (steady-state styling). * Optional — element-level consumers style off their own state. */ activeClass?: string; /** Held on for the DURATION of an enter/exit swap (the * mask/curtain). Optional — see `activeClass`. */ switchingClass?: string; /** New fullscreen state, straight from the change event. For a `target` * consumer this is "MY element is the fullscreen element". */ onFullscreenChange: (isFullscreen: boolean) => void; /** Geometry moved under a constant scrollY — re-measure + re-anchor. * Optional; fired once per resize during the swap and once more when * the switch ends. */ onGeometryPulse?: () => void; /** Switch ends after resizes have been quiet this long (default 200ms). */ quietMs?: number; /** Hard cap on a switch, mask-wedge failsafe (default 1000ms). */ capMs?: number; } export declare class FullscreenSwitchController { private readonly opts; private quietTimer; private capTimer; private attached; constructor(opts: FullscreenSwitchOptions); /** SSR-safe feature detection — call post-mount to gate the affordance. */ static isSupported(): boolean; get isFullscreen(): boolean; attach(): void; detach(): void; /** Mask first (pre-emptive — see header), then request/exit. */ toggle: () => void; /** Raise the mask + start tracking. Idempotent — safe from the pre-emptive * paths (toggle, Escape) AND again from the change event. */ private beginSwitch; private endSwitch; private armQuiet; private onResize; /** Escape is the one exit path that skips toggle() — pre-mask on the * keydown (capture phase), before the browser begins the swap. */ private onEscape; private onChange; } //# sourceMappingURL=fullscreen-switch.d.ts.map