@werk1/w1-system-videoblock
Version:
Universal video player supporting YouTube, Vimeo, HLS, DASH with coordination and GSAP integration for W1 System
132 lines (131 loc) • 4.82 kB
TypeScript
import React from "react";
import { StateCreator } from "zustand";
export interface W1VideoPlayerState {
isPlaying: boolean;
isBuffering: boolean;
currentTime: number;
duration: number;
volume: number;
isMuted: boolean;
playbackRate: number;
isFullscreen: boolean;
isPictureInPicture: boolean;
isMobileFullscreen: boolean;
bufferedRanges: TimeRanges | [];
error: MediaError | null;
isLoading: boolean;
hasError: boolean;
buffered: TimeRanges | null;
}
export interface W1VideoPlayerMethods {
play: () => Promise<void>;
pause: () => Promise<void>;
seek: (time: number) => void;
setVolume: (volume: number) => void;
setMuted: (muted: boolean) => void;
toggleFullscreen: () => void;
toggleMobileFullscreen: () => void;
togglePictureInPicture: () => void;
setPlaybackRate: (rate: number) => void;
getVideoElement: () => HTMLVideoElement | null;
getWrapperElement: () => HTMLDivElement | null;
pauseForCoordination?: () => Promise<void>;
}
export interface W1VideoPlayerProps {
src: string;
objectFit?: "cover" | "contain" | "fill" | "scale-down" | "none";
muted?: boolean;
loop?: boolean;
preload?: "none" | "metadata" | "auto";
playsInline?: boolean;
autoplay?: boolean;
poster?: string;
className?: string;
style?: React.CSSProperties;
onStateChange?: (state: W1VideoPlayerState) => void;
onReady?: (video: HTMLVideoElement) => void;
onError?: (error: MediaError | null) => void;
onPictureInPictureChange?: (isPictureInPicture: boolean) => void;
onProgress?: (progress: number) => void;
onTimeUpdate?: (currentTime: number) => void;
playbackRates?: number[];
skipIntervals?: number;
enableStreamingLibs?: boolean;
enableKeyboardControls?: boolean;
ref?: React.Ref<W1VideoPlayerMethods>;
}
export interface W1VideoControlsMethods {
showControls: () => void;
}
export interface W1VideoControlsProps {
playerState: W1VideoPlayerState;
playerMethods: W1VideoPlayerMethods | null;
className?: string;
showVolumeControl?: boolean;
showPlaybackRate?: boolean;
showFullscreen?: boolean;
showPictureInPicture?: boolean;
showTimeDisplay?: boolean;
showProgressBar?: boolean;
autoHide?: boolean;
autoHideDelay?: number;
initiallyVisible?: boolean;
showOnInteraction?: boolean;
customButtons?: React.ReactNode;
theme?: "dark" | "light" | "transparent";
position?: "bottom" | "top" | "overlay";
compact?: boolean;
playbackRates?: number[];
skipIntervals?: number;
videoBlockId?: string;
videoCoordinationStore?: () => VideoCoordinationSlice;
enableKeyboardControls?: boolean;
isMobileDevice: boolean;
ref?: React.Ref<W1VideoControlsMethods>;
}
export interface W1VideoBlockProps extends Omit<W1VideoPlayerProps, "onStateChange" | "isActiveDebounced" | "priority" | "videoCoordinationStore" | "externalVideoBlockId" | "ref"> {
showControls?: boolean;
isActiveDebounced?: boolean;
priority?: number;
videoCoordinationStore?: () => VideoCoordinationSlice;
onVisibilityChange?: (isActiveDebounced: boolean) => void;
onVideoStateChange?: (state: W1VideoPlayerState) => void;
allowPipOverride?: boolean;
isMobileDevice: boolean;
ref?: React.Ref<HTMLDivElement>;
}
export interface VideoBlockInfo {
id: string;
priority: number;
playerRef?: React.RefObject<W1VideoPlayerMethods | null>;
autoplay: boolean;
isActiveDebounced: boolean;
allowPipOverride?: boolean;
isExternalPlatform?: boolean;
viewportData?: {
intersectionRatio?: number;
distanceFromCenter?: number;
progress?: number;
velocity?: number;
};
}
export interface VideoCoordinationSlice {
currentlyPlayingVideoBlock: VideoBlockInfo | null;
registeredVideoBlocks: Map<string, VideoBlockInfo>;
singleVideoMode: boolean;
allowManualOverride: boolean;
pipVideoBlocks: Set<string>;
registerVideoBlock: (id: string, info: VideoBlockInfo) => void;
unregisterVideoBlock: (id: string) => void;
updateVideoState: (id: string, updates: Partial<Pick<VideoBlockInfo, "autoplay" | "isActiveDebounced" | "viewportData">>) => void;
calculateWhoShouldPlay: () => string | null;
shouldVideoPlay: (videoId: string) => boolean;
recalculateDecisions: () => void;
setCurrentlyPlaying: (id: string, info: VideoBlockInfo) => void;
clearCurrentlyPlaying: (id?: string) => void;
setSingleVideoMode: (enabled: boolean) => void;
pauseAllVideos: () => void;
pauseAllExcept: (videoBlockId: string) => void;
setPipStatus: (videoId: string, isPip: boolean) => void;
}
export type VideoCoordinationSliceCreator = StateCreator<VideoCoordinationSlice>;