···11+import {
22+ useCallback,
33+ useEffect,
44+ useRef,
55+ useState,
66+ useSyncExternalStore,
77+} from 'react'
88+99+import {isFirefox, isSafari} from '#/lib/browser'
1010+import {isWeb} from '#/platform/detection'
1111+1212+function fullscreenSubscribe(onChange: () => void) {
1313+ document.addEventListener('fullscreenchange', onChange)
1414+ return () => document.removeEventListener('fullscreenchange', onChange)
1515+}
1616+1717+export function useFullscreen(ref?: React.RefObject<HTMLElement>) {
1818+ if (!isWeb) throw new Error("'useFullscreen' is a web-only hook")
1919+ const isFullscreen = useSyncExternalStore(fullscreenSubscribe, () =>
2020+ Boolean(document.fullscreenElement),
2121+ )
2222+ const scrollYRef = useRef<null | number>(null)
2323+ const [prevIsFullscreen, setPrevIsFullscreen] = useState(isFullscreen)
2424+2525+ const toggleFullscreen = useCallback(() => {
2626+ if (isFullscreen) {
2727+ document.exitFullscreen()
2828+ } else {
2929+ if (!ref) throw new Error('No ref provided')
3030+ if (!ref.current) return
3131+ scrollYRef.current = window.scrollY
3232+ ref.current.requestFullscreen()
3333+ }
3434+ }, [isFullscreen, ref])
3535+3636+ useEffect(() => {
3737+ if (prevIsFullscreen === isFullscreen) return
3838+ setPrevIsFullscreen(isFullscreen)
3939+4040+ // Chrome has an issue where it doesn't scroll back to the top after exiting fullscreen
4141+ // Let's play it safe and do it if not FF or Safari, since anything else will probably be chromium
4242+ if (prevIsFullscreen && !isFirefox && !isSafari) {
4343+ setTimeout(() => {
4444+ if (scrollYRef.current !== null) {
4545+ window.scrollTo(0, scrollYRef.current)
4646+ scrollYRef.current = null
4747+ }
4848+ }, 100)
4949+ }
5050+ }, [isFullscreen, prevIsFullscreen])
5151+5252+ return [isFullscreen, toggleFullscreen] as const
5353+}
+12-1
src/view/com/util/post-embeds/VideoEmbed.web.tsx
···1212 VideoNotFoundError,
1313} from '#/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerWeb'
1414import {atoms as a} from '#/alf'
1515+import {useFullscreen} from '#/components/hooks/useFullscreen'
1516import {ErrorBoundary} from '../ErrorBoundary'
1617import {useActiveVideoWeb} from './ActiveVideoWebContext'
1718import * as VideoFallback from './VideoEmbedInner/VideoFallback'
···106107}) {
107108 const ref = useRef<HTMLDivElement>(null)
108109 const [nearScreen, setNearScreen] = useState(false)
110110+ const [isFullscreen] = useFullscreen()
111111+ const [nearScreenOrFullscreen, setNearScreenOrFullscreen] = useState(false)
109112110113 // Send position when scrolling. This is done with an IntersectionObserver
111114 // observing a div of 100vh height
···135138 }
136139 }, [isAnyViewActive, sendPosition])
137140141141+ // disguesting effect - it should be `nearScreen` except when fullscreen
142142+ // when it should be whatever it was before fullscreen changed
143143+ useEffect(() => {
144144+ if (!isFullscreen) {
145145+ setNearScreenOrFullscreen(nearScreen)
146146+ }
147147+ }, [isFullscreen, nearScreen])
148148+138149 return (
139150 <View style={[a.flex_1, a.flex_row]}>
140140- {nearScreen && children}
151151+ {nearScreenOrFullscreen && children}
141152 <div
142153 ref={ref}
143154 style={{