import { useCallback, useMemo } from "react"; import { isSafari } from "react-device-detect"; import { LuPause, LuPlay } from "react-icons/lu"; import { DropdownMenu, DropdownMenuContent, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuTrigger, } from "../ui/dropdown-menu"; import { MdForward10, MdReplay10, MdVolumeDown, MdVolumeMute, MdVolumeOff, MdVolumeUp, } from "react-icons/md"; import { Slider } from "../ui/slider-volume"; type VideoControls = { volume?: boolean; seek?: boolean; playbackRate?: boolean; }; const CONTROLS_DEFAULT: VideoControls = { volume: true, seek: true, playbackRate: true, }; type VideoControlsProps = { className?: string; video?: HTMLVideoElement | null; features?: VideoControls; isPlaying: boolean; show: boolean; controlsOpen?: boolean; setControlsOpen?: (open: boolean) => void; onPlayPause: (play: boolean) => void; onSeek: (diff: number) => void; }; export default function VideoControls({ className, video, features = CONTROLS_DEFAULT, isPlaying, show, controlsOpen, setControlsOpen, onPlayPause, onSeek, }: VideoControlsProps) { const playbackRates = useMemo(() => { if (isSafari) { return [0.5, 1, 2]; } else { return [0.5, 1, 2, 4, 8, 16]; } }, []); const onReplay = useCallback( (e: React.MouseEvent) => { e.stopPropagation(); onSeek(-10); }, [onSeek], ); const onSkip = useCallback( (e: React.MouseEvent) => { e.stopPropagation(); onSeek(10); }, [onSeek], ); const onTogglePlay = useCallback( (e: React.MouseEvent) => { e.stopPropagation(); onPlayPause(!isPlaying); }, [isPlaying, onPlayPause], ); // volume control const VolumeIcon = useMemo(() => { if (!video || video?.muted) { return MdVolumeOff; } else if (video.volume <= 0.33) { return MdVolumeMute; } else if (video.volume <= 0.67) { return MdVolumeDown; } else { return MdVolumeUp; } // only update when specific fields change // eslint-disable-next-line react-hooks/exhaustive-deps }, [video?.volume, video?.muted]); if (!show) { return; } return (
{video && features.volume && (
{ e.stopPropagation(); video.muted = !video.muted; }} /> {video.muted == false && ( (video.volume = value[0])} /> )}
)} {features.seek && ( )}
{isPlaying ? ( ) : ( )}
{features.seek && ( )} {video && features.playbackRate && ( { if (setControlsOpen) { setControlsOpen(open); } }} > {`${video.playbackRate}x`} (video.playbackRate = parseFloat(rate))} > {playbackRates.map((rate) => ( {rate}x ))} )}
); }