import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useRef, } from 'react'; import type {VideoRef, ReactVideoProps} from './types'; const Video = forwardRef( ( { source, paused, muted, volume, onBuffer, onLoad, onProgress, onError, onEnd, onPlaybackStateChanged, }, ref, ) => { const nativeRef = useRef(null); const errorHandler = useRef(onError); errorHandler.current = onError; const seek = useCallback(async (time: number, _tolerance?: number) => { if (isNaN(time)) { throw new Error('Specified time is not a number'); } if (!nativeRef.current) { console.warn('Video Component is not mounted'); return; } nativeRef.current.currentTime = time; }, []); const pause = useCallback(() => { if (!nativeRef.current) { return; } nativeRef.current.pause(); }, []); const resume = useCallback(() => { if (!nativeRef.current) { return; } nativeRef.current.play(); }, []); const unsupported = useCallback(() => { throw new Error('This is unsupported on the web'); }, []); useImperativeHandle( ref, () => ({ seek, pause, resume, // making the video fullscreen does not work with some subtitles polyfils // so I decided to not include it. presentFullscreenPlayer: unsupported, dismissFullscreenPlayer: unsupported, save: unsupported, restoreUserInterfaceForPictureInPictureStopCompleted: unsupported, }), [seek, pause, resume, unsupported], ); useEffect(() => { if (paused) { pause(); } else { resume(); } }, [paused, pause, resume]); useEffect(() => { if (!nativeRef.current || !volume) { return; } nativeRef.current.volume = Math.max(0, Math.min(volume, 100)) / 100; }, [volume]); const setPlay = useSetAtom(playAtom); useEffect(() => { if (!nativeRef.current) return; // Set play state to the player's value (if autoplay is denied) setPlay(!nativeRef.current.paused); }, [setPlay]); const setProgress = useSetAtom(progressAtom); return ( <>