import { createContext, useCallback, useContext, useEffect, useRef, useState, type PropsWithChildren, } from "react"; import { createPortal } from "react-dom"; import { X } from "lucide-react"; import type { Attachment } from "../../../types/post"; type PlayerState = { attachment: Attachment; currentTime: number; } | null; type Ctx = { openVideo: (attachment: Attachment, currentTime?: number) => void; closeVideo: () => void; }; const VideoPlayerContext = createContext(null); export function useVideoPlayer(): Ctx { const ctx = useContext(VideoPlayerContext); if (!ctx) throw new Error("useVideoPlayer must be used inside VideoPlayerProvider"); return ctx; } export function VideoPlayerProvider({ children }: PropsWithChildren) { const [state, setState] = useState(null); const openVideo = useCallback( (attachment: Attachment, currentTime = 0) => setState({ attachment, currentTime }), [], ); const closeVideo = useCallback(() => setState(null), []); return ( {children} {state ? ( ) : null} ); } function PlayerView({ attachment, startAt, onClose, }: { attachment: Attachment; startAt: number; onClose: () => void; }) { const videoRef = useRef(null); useEffect(() => { const onKey = (e: KeyboardEvent) => { if (e.key === "Escape") onClose(); }; window.addEventListener("keydown", onKey); // iOS-compatible scroll lock: pin the body in place at the current scroll // offset, then restore both styles and scroll position on cleanup. Plain // `overflow: hidden` doesn't work on iOS Safari and can reset scroll to 0. const scrollY = window.scrollY; const body = document.body; const prev = { position: body.style.position, top: body.style.top, left: body.style.left, right: body.style.right, width: body.style.width, overflow: body.style.overflow, }; body.style.position = "fixed"; body.style.top = `-${scrollY}px`; body.style.left = "0"; body.style.right = "0"; body.style.width = "100%"; body.style.overflow = "hidden"; return () => { window.removeEventListener("keydown", onKey); body.style.position = prev.position; body.style.top = prev.top; body.style.left = prev.left; body.style.right = prev.right; body.style.width = prev.width; body.style.overflow = prev.overflow; window.scrollTo(0, scrollY); }; }, [onClose]); useEffect(() => { const v = videoRef.current; if (!v) return; if (startAt > 0) v.currentTime = startAt; v.play().catch(() => {}); }, [startAt]); return createPortal(
, document.body, ); }