anvilsign in

collin/mahjong

1import { useSyncExternalStore } from 'react';
2
3/**
4 * Firefox on Android keeps its address bar above the page, and on a phone held
5 * sideways that bar is a sixth of the height the whole table has to work with.
6 * The Fullscreen API is the only thing that takes it back, and browsers grant
7 * it only from inside a click — so this is always a button somebody presses,
8 * never something the table asks for on its own.
9 *
10 * Installing the page to the home screen does the same thing for good; see
11 * public/manifest.webmanifest.
12 */
13
14const subscribe = (cb: () => void) => {
15 document.addEventListener('fullscreenchange', cb);
16 return () => document.removeEventListener('fullscreenchange', cb);
17};
18
19/** Absent on iPhone, where only a <video> may go fullscreen. */
20export const fullscreenSupported = () =>
21 typeof document !== 'undefined' &&
22 document.fullscreenEnabled &&
23 typeof document.documentElement.requestFullscreen === 'function';
24
25export function enterFullscreen() {
26 // `navigationUI` is a hint at the browser's own chrome; the ones that don't
27 // take it ignore it. Refusals — no gesture behind the call, or a frame that
28 // disallows it — are nothing to report: the page is simply not fullscreen.
29 document.documentElement.requestFullscreen({ navigationUI: 'hide' }).catch(() => {});
30}
31
32export function exitFullscreen() {
33 if (document.fullscreenElement) document.exitFullscreen().catch(() => {});
34}
35
36/** Whether the page holds the screen right now. */
37export function useFullscreen(): boolean {
38 return useSyncExternalStore(
39 subscribe,
40 () => document.fullscreenElement !== null,
41 () => false,
42 );
43}