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