created a new hook for handling fullscreen rather than using react-full-screen, hopefully that will solve the issues some users are seeing where it goes into full screnn and then immediately exits
This commit is contained in:
parent
e6796b1672
commit
74025290f1
4 changed files with 125 additions and 27 deletions
|
|
@ -36,7 +36,6 @@ import { pond } from "protobuf-ts/pond";
|
|||
import { quack } from "protobuf-ts/quack";
|
||||
import { useGlobalState, useSnackbar } from "providers";
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import { FullScreen, useFullScreenHandle } from "react-full-screen";
|
||||
import moment, { Moment } from "moment";
|
||||
import ResponsiveDialog from "common/ResponsiveDialog";
|
||||
import { getThemeType } from "theme";
|
||||
|
|
@ -72,6 +71,7 @@ import ButtonGroup from "common/ButtonGroup";
|
|||
import ModeChangeDialog from "./conditioning/modeChangeDialog";
|
||||
import CustomGrainSelector from "grain/CustomGrainSelector";
|
||||
import BinControllerDisplay from "./BinControllerDisplay";
|
||||
import { useFullScreen } from "hooks/FullScreenHandle";
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) => {
|
||||
return ({
|
||||
|
|
@ -217,7 +217,7 @@ export default function BinVisualizer(props: Props) {
|
|||
const isMobile = useMobile();
|
||||
const classes = useStyles();
|
||||
const theme = useTheme();
|
||||
const fullScreenHandler = useFullScreenHandle();
|
||||
const {fullScreenHandler, FullScreenWrapper} = useFullScreen()
|
||||
const viewport = useViewport();
|
||||
const { openSnack } = useSnackbar();
|
||||
const [fillPercentage, setFillPercentage] = useState<number | null>(0);
|
||||
|
|
@ -1344,7 +1344,7 @@ export default function BinVisualizer(props: Props) {
|
|||
|
||||
return (
|
||||
<Box display="flex" width={1} justifyContent="flex-end">
|
||||
<FullScreen handle={fullScreenHandler}>
|
||||
<FullScreenWrapper>
|
||||
<Box
|
||||
position="relative"
|
||||
height={1}
|
||||
|
|
@ -1441,7 +1441,7 @@ export default function BinVisualizer(props: Props) {
|
|||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
</FullScreen>
|
||||
</FullScreenWrapper>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
121
src/hooks/FullScreenHandle.tsx
Normal file
121
src/hooks/FullScreenHandle.tsx
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
|
||||
/**
|
||||
* Drop-in replacement for react-full-screen's useFullScreenHandle + FullScreen component.
|
||||
*
|
||||
* Motivation: react-full-screen 1.1.1 doesn't debounce fullscreenchange events, so on
|
||||
* Windows systems with DPI scaling > 100%, the resize triggered during fullscreen entry
|
||||
* fires a fullscreenchange event that the library misinterprets as an exit, immediately
|
||||
* popping back out of fullscreen.
|
||||
*
|
||||
* This hook bypasses the library entirely and calls the native Fullscreen API directly,
|
||||
* ignoring fullscreenchange events fired within DEBOUNCE_MS of entry to absorb the
|
||||
* DPI-scaling resize blip.
|
||||
*
|
||||
* Usage — replace in BinVisualizerV2.tsx:
|
||||
*
|
||||
* // Remove:
|
||||
* import { FullScreen, useFullScreenHandle } from "react-full-screen";
|
||||
* const fullScreenHandler = useFullScreenHandle();
|
||||
* <FullScreen handle={fullScreenHandler}> ... </FullScreen>
|
||||
*
|
||||
* // Add:
|
||||
* import { useFullScreen } from "hooks/useFullScreen";
|
||||
* const { fullScreenHandler, FullScreenWrapper } = useFullScreen();
|
||||
* <FullScreenWrapper> ... </FullScreenWrapper>
|
||||
*
|
||||
* // Everything else (fullScreenHandler.active, .enter(), .exit()) stays the same.
|
||||
*/
|
||||
|
||||
const DEBOUNCE_MS = 500;
|
||||
|
||||
export interface FullScreenHandle {
|
||||
active: boolean;
|
||||
enter: () => void;
|
||||
exit: () => void;
|
||||
}
|
||||
|
||||
export function useFullScreen(): {
|
||||
fullScreenHandler: FullScreenHandle;
|
||||
FullScreenWrapper: React.FC<{ children: React.ReactNode }>;
|
||||
} {
|
||||
const [active, setActive] = useState(false);
|
||||
const containerRef = useRef<HTMLDivElement | null>(null);
|
||||
// Timestamp of the last enter() call — used to debounce spurious exit events
|
||||
const enterTimeRef = useRef<number>(0);
|
||||
|
||||
const enter = useCallback(() => {
|
||||
const el = containerRef.current;
|
||||
if (!el) return;
|
||||
enterTimeRef.current = Date.now();
|
||||
if (el.requestFullscreen) {
|
||||
el.requestFullscreen().catch(() => {
|
||||
// Some browsers (e.g. iOS Safari) reject the promise — silently ignore
|
||||
});
|
||||
} else if ((el as any).webkitRequestFullscreen) {
|
||||
(el as any).webkitRequestFullscreen();
|
||||
} else if ((el as any).mozRequestFullScreen) {
|
||||
(el as any).mozRequestFullScreen();
|
||||
} else if ((el as any).msRequestFullscreen) {
|
||||
(el as any).msRequestFullscreen();
|
||||
}
|
||||
}, []);
|
||||
|
||||
const exit = useCallback(() => {
|
||||
if (document.exitFullscreen) {
|
||||
document.exitFullscreen().catch(() => {});
|
||||
} else if ((document as any).webkitExitFullscreen) {
|
||||
(document as any).webkitExitFullscreen();
|
||||
} else if ((document as any).mozCancelFullScreen) {
|
||||
(document as any).mozCancelFullScreen();
|
||||
} else if ((document as any).msExitFullscreen) {
|
||||
(document as any).msExitFullscreen();
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const handleChange = () => {
|
||||
const fullscreenEl =
|
||||
document.fullscreenElement ||
|
||||
(document as any).webkitFullscreenElement ||
|
||||
(document as any).mozFullScreenElement ||
|
||||
(document as any).msFullscreenElement;
|
||||
|
||||
const isNowFullscreen = fullscreenEl === containerRef.current;
|
||||
|
||||
// If we just called enter() and this event fires within DEBOUNCE_MS,
|
||||
// and it looks like an exit, ignore it — it's the DPI-scaling resize blip
|
||||
if (!isNowFullscreen && Date.now() - enterTimeRef.current < DEBOUNCE_MS) {
|
||||
return;
|
||||
}
|
||||
|
||||
setActive(isNowFullscreen);
|
||||
};
|
||||
|
||||
document.addEventListener("fullscreenchange", handleChange);
|
||||
document.addEventListener("webkitfullscreenchange", handleChange);
|
||||
document.addEventListener("mozfullscreenchange", handleChange);
|
||||
document.addEventListener("MSFullscreenChange", handleChange);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener("fullscreenchange", handleChange);
|
||||
document.removeEventListener("webkitfullscreenchange", handleChange);
|
||||
document.removeEventListener("mozfullscreenchange", handleChange);
|
||||
document.removeEventListener("MSFullscreenChange", handleChange);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const FullScreenWrapper: React.FC<{ children: React.ReactNode }> = useCallback(
|
||||
({ children }) => (
|
||||
<div ref={containerRef} style={{ width: "100%", height: "100%" }}>
|
||||
{children}
|
||||
</div>
|
||||
),
|
||||
[]
|
||||
);
|
||||
|
||||
return {
|
||||
fullScreenHandler: { active, enter, exit },
|
||||
FullScreenWrapper,
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue