@werk1/w1-system-videoblock
Version:
Universal video player supporting YouTube, Vimeo, HLS, DASH with coordination and GSAP integration for W1 System
303 lines (291 loc) • 10.7 kB
TypeScript
import React from 'react';
import { StateCreator } from 'zustand';
export { StateCreator } from 'zustand';
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;
}
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>;
}
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>;
}
interface W1VideoControlsMethods {
showControls: () => void;
}
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>;
}
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>;
}
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;
};
}
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;
}
/**
* W1VideoControls - Full-featured UI controls layer for video player
*
* Provides comprehensive video controls with auto-hide, themes, positioning, and keyboard shortcuts
*/
declare const W1VideoControls: React.FC<W1VideoControlsProps>;
/**
* W1VideoPlayer - Pure video engine with modular hook architecture
*
* This component focuses solely on video playback functionality.
* For complete video solutions with coordination, use W1VideoBlock.
*
* Features:
* - Universal video format support (YouTube, Vimeo, HLS, DASH, MP4/WebM)
* - Picture-in-Picture and fullscreen support
* - Modular hook architecture for maintainability
* - Pure video engine - no coordination concerns
*/
declare const W1VideoPlayer: React.FC<W1VideoPlayerProps>;
/**
* W1VideoBlock - Complete video solution with coordination
*
* This component provides a complete video experience including:
* - Video coordination between multiple players
* - Click-to-play/pause interaction
* - Store management and state coordination
* - Visibility management and autoplay control
*
* GSAP animations are handled externally by parent components.
* Uses W1VideoPlayer as the pure video engine underneath.
*/
declare const W1VideoBlock: React.FC<W1VideoBlockProps>;
/**
* Props interface for the PlayIcon component
*/
interface PlayIconProps {
/** Color of the icon */
color?: string;
/** Size of the icon */
size?: number;
/** CSS class name */
className?: string;
}
/**
* Modern SVG play icon component for W1VideoBlock controls
*
* @component
* @param {Object} props - Component props
* @param {string} [props.color='currentColor'] - Color of the icon
* @param {number} [props.size=20] - Size of the icon in pixels
* @param {string} [props.className=''] - Additional CSS class name
* @returns {JSX.Element} Rendered play icon
*/
declare const PlayIcon: React.FC<PlayIconProps>;
/**
* Props interface for the PauseIcon component
*/
interface PauseIconProps {
/** Color of the icon */
color?: string;
/** Size of the icon */
size?: number;
/** CSS class name */
className?: string;
}
/**
* Modern SVG pause icon component for W1VideoBlock controls
*
* @component
* @param {Object} props - Component props
* @param {string} [props.color='currentColor'] - Color of the icon
* @param {number} [props.size=20] - Size of the icon in pixels
* @param {string} [props.className=''] - Additional CSS class name
* @returns {JSX.Element} Rendered pause icon
*/
declare const PauseIcon: React.FC<PauseIconProps>;
/**
* Props interface for the VolumeIcon component
*/
interface VolumeIconProps {
/** Volume level: 0 = muted, 0-0.5 = low, 0.5+ = high */
level: number;
/** Whether the volume is muted */
isMuted?: boolean;
/** Color of the icon */
color?: string;
/** Size of the icon */
size?: number;
/** CSS class name */
className?: string;
}
/**
* Modern SVG volume icon component for W1VideoBlock controls
* Displays different icons based on volume level and mute state
*
* @component
* @param {Object} props - Component props
* @param {number} props.level - Volume level (0-1)
* @param {boolean} [props.isMuted=false] - Whether volume is muted
* @param {string} [props.color='currentColor'] - Color of the icon
* @param {number} [props.size=20] - Size of the icon in pixels
* @param {string} [props.className=''] - Additional CSS class name
* @returns {JSX.Element} Rendered volume icon
*/
declare const VolumeIcon: React.FC<VolumeIconProps>;
/**
* Props interface for the FullscreenIcon component
*/
interface FullscreenIconProps {
/** Whether currently in fullscreen mode */
isFullscreen?: boolean;
/** Color of the icon */
color?: string;
/** Size of the icon */
size?: number;
/** CSS class name */
className?: string;
}
/**
* Modern SVG fullscreen icon component for W1VideoBlock controls
* Shows enter or exit fullscreen icon based on current state
*
* @component
* @param {Object} props - Component props
* @param {boolean} [props.isFullscreen=false] - Whether currently in fullscreen
* @param {string} [props.color='currentColor'] - Color of the icon
* @param {number} [props.size=20] - Size of the icon in pixels
* @param {string} [props.className=''] - Additional CSS class name
* @returns {JSX.Element} Rendered fullscreen icon
*/
declare const FullscreenIcon: React.FC<FullscreenIconProps>;
/**
* Props interface for the PictureInPictureIcon component
*/
interface PictureInPictureIconProps {
/** Whether currently in picture-in-picture mode */
isPictureInPicture?: boolean;
/** Color of the icon */
color?: string;
/** Size of the icon */
size?: number;
/** CSS class name */
className?: string;
}
/**
* Modern SVG picture-in-picture icon component for W1VideoBlock controls
* Shows enter or exit PiP icon based on current state
*
* @component
* @param {Object} props - Component props
* @param {boolean} [props.isPictureInPicture=false] - Whether currently in PiP mode
* @param {string} [props.color='currentColor'] - Color of the icon
* @param {number} [props.size=20] - Size of the icon in pixels
* @param {string} [props.className=''] - Additional CSS class name
* @returns {JSX.Element} Rendered picture-in-picture icon
*/
declare const PictureInPictureIcon: React.FC<PictureInPictureIconProps>;
declare const createVideoCoordinationSlice: StateCreator<VideoCoordinationSlice>;
export { FullscreenIcon, PauseIcon, PictureInPictureIcon, PlayIcon, VolumeIcon, W1VideoBlock, W1VideoControls, W1VideoPlayer, createVideoCoordinationSlice };
export type { FullscreenIconProps, PauseIconProps, PictureInPictureIconProps, PlayIconProps, VideoBlockInfo, VideoCoordinationSlice, VolumeIconProps, W1VideoBlockProps, W1VideoControlsMethods, W1VideoControlsProps, W1VideoPlayerMethods, W1VideoPlayerProps, W1VideoPlayerState };