Initial commit: modern React video player library
Add all source files for a feature-rich, reusable video player built with React, TypeScript, and Vite. Includes core components, context, hooks, utilities, styles, demo app, and configuration files.
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { PlayerProvider } from '../contexts/PlayerContext'
|
||||
import { VideoElement } from './VideoElement'
|
||||
import { ControlsLayer } from './ControlsLayer'
|
||||
import type { VideoPlayerProps, AudioTrack } from '../types'
|
||||
import { initializePolyfills } from '../utils/polyfills'
|
||||
import '../styles/variables.css'
|
||||
import './VideoPlayer.css'
|
||||
|
||||
// Initialize polyfills once
|
||||
let polyfillsInitialized = false
|
||||
if (!polyfillsInitialized) {
|
||||
initializePolyfills()
|
||||
polyfillsInitialized = true
|
||||
}
|
||||
|
||||
export const VideoPlayer: React.FC<VideoPlayerProps> = ({
|
||||
src,
|
||||
poster,
|
||||
autoplay = false,
|
||||
loop = false,
|
||||
muted = false,
|
||||
controls = true,
|
||||
subtitles = [],
|
||||
theme,
|
||||
keyboardShortcuts = true,
|
||||
pictureInPicture = true,
|
||||
className = '',
|
||||
style,
|
||||
onPlay,
|
||||
onPause,
|
||||
onEnded,
|
||||
onTimeUpdate,
|
||||
onVolumeChange,
|
||||
onError,
|
||||
onLoadedMetadata,
|
||||
onSeeking,
|
||||
onSeeked,
|
||||
}) => {
|
||||
const [audioTracks, setAudioTracks] = useState<AudioTrack[]>([])
|
||||
|
||||
// Apply theme CSS variables
|
||||
useEffect(() => {
|
||||
if (theme) {
|
||||
const root = document.documentElement
|
||||
if (theme.primaryColor) root.style.setProperty('--player-primary', theme.primaryColor)
|
||||
if (theme.accentColor) root.style.setProperty('--player-primary-hover', theme.accentColor)
|
||||
if (theme.backgroundColor) root.style.setProperty('--player-bg', theme.backgroundColor)
|
||||
if (theme.textColor) root.style.setProperty('--player-text', theme.textColor)
|
||||
}
|
||||
}, [theme])
|
||||
|
||||
const handleAudioTracksLoaded = useCallback((tracks: AudioTrack[]) => {
|
||||
setAudioTracks(tracks)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<PlayerProvider initialMuted={muted}>
|
||||
<div className={`video-player ${className}`} style={style}>
|
||||
<VideoElement
|
||||
src={src}
|
||||
poster={poster}
|
||||
autoplay={autoplay}
|
||||
loop={loop}
|
||||
muted={muted}
|
||||
subtitles={subtitles}
|
||||
onPlay={onPlay}
|
||||
onPause={onPause}
|
||||
onEnded={onEnded}
|
||||
onTimeUpdate={onTimeUpdate}
|
||||
onVolumeChange={onVolumeChange}
|
||||
onError={onError}
|
||||
onLoadedMetadata={onLoadedMetadata}
|
||||
onSeeking={onSeeking}
|
||||
onSeeked={onSeeked}
|
||||
onAudioTracksLoaded={handleAudioTracksLoaded}
|
||||
/>
|
||||
{controls && (
|
||||
<ControlsLayer
|
||||
keyboardShortcuts={keyboardShortcuts}
|
||||
pictureInPicture={pictureInPicture}
|
||||
subtitles={subtitles}
|
||||
audioTracks={audioTracks}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</PlayerProvider>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user