mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
1import {
2 useCallback,
3 useEffect,
4 useRef,
5 useState,
6 useSyncExternalStore,
7} from 'react'
8
9import {isFirefox, isSafari} from '#/lib/browser'
10import {isWeb} from '#/platform/detection'
11
12function fullscreenSubscribe(onChange: () => void) {
13 document.addEventListener('fullscreenchange', onChange)
14 return () => document.removeEventListener('fullscreenchange', onChange)
15}
16
17export function useFullscreen(ref?: React.RefObject<HTMLElement>) {
18 if (!isWeb) throw new Error("'useFullscreen' is a web-only hook")
19 const isFullscreen = useSyncExternalStore(fullscreenSubscribe, () =>
20 Boolean(document.fullscreenElement),
21 )
22 const scrollYRef = useRef<null | number>(null)
23 const [prevIsFullscreen, setPrevIsFullscreen] = useState(isFullscreen)
24
25 const toggleFullscreen = useCallback(() => {
26 if (isFullscreen) {
27 document.exitFullscreen()
28 } else {
29 if (!ref) throw new Error('No ref provided')
30 if (!ref.current) return
31 scrollYRef.current = window.scrollY
32 ref.current.requestFullscreen()
33 }
34 }, [isFullscreen, ref])
35
36 useEffect(() => {
37 if (prevIsFullscreen === isFullscreen) return
38 setPrevIsFullscreen(isFullscreen)
39
40 // Chrome has an issue where it doesn't scroll back to the top after exiting fullscreen
41 // Let's play it safe and do it if not FF or Safari, since anything else will probably be chromium
42 if (prevIsFullscreen && !isFirefox && !isSafari) {
43 setTimeout(() => {
44 if (scrollYRef.current !== null) {
45 window.scrollTo(0, scrollYRef.current)
46 scrollYRef.current = null
47 }
48 }, 100)
49 }
50 }, [isFullscreen, prevIsFullscreen])
51
52 return [isFullscreen, toggleFullscreen] as const
53}