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,120 @@
|
||||
import { useEffect } from 'react'
|
||||
import { usePlayerContext } from '../contexts/PlayerContext'
|
||||
|
||||
export const useKeyboardShortcuts = (enabled: boolean = true) => {
|
||||
const {
|
||||
videoState,
|
||||
togglePlay,
|
||||
seek,
|
||||
setVolume,
|
||||
toggleMute,
|
||||
toggleFullscreen,
|
||||
togglePictureInPicture,
|
||||
} = usePlayerContext()
|
||||
|
||||
useEffect(() => {
|
||||
if (!enabled) return
|
||||
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
// Don't trigger if user is typing in an input
|
||||
if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement) {
|
||||
return
|
||||
}
|
||||
|
||||
switch (e.key.toLowerCase()) {
|
||||
case ' ':
|
||||
case 'k':
|
||||
e.preventDefault()
|
||||
togglePlay()
|
||||
break
|
||||
|
||||
case 'arrowleft':
|
||||
e.preventDefault()
|
||||
seek(Math.max(0, videoState.currentTime - 5))
|
||||
break
|
||||
|
||||
case 'arrowright':
|
||||
e.preventDefault()
|
||||
seek(Math.min(videoState.duration, videoState.currentTime + 5))
|
||||
break
|
||||
|
||||
case 'j':
|
||||
e.preventDefault()
|
||||
seek(Math.max(0, videoState.currentTime - 10))
|
||||
break
|
||||
|
||||
case 'l':
|
||||
e.preventDefault()
|
||||
seek(Math.min(videoState.duration, videoState.currentTime + 10))
|
||||
break
|
||||
|
||||
case 'arrowup':
|
||||
e.preventDefault()
|
||||
setVolume(Math.min(1, videoState.volume + 0.1))
|
||||
break
|
||||
|
||||
case 'arrowdown':
|
||||
e.preventDefault()
|
||||
setVolume(Math.max(0, videoState.volume - 0.1))
|
||||
break
|
||||
|
||||
case 'm':
|
||||
e.preventDefault()
|
||||
toggleMute()
|
||||
break
|
||||
|
||||
case 'f':
|
||||
e.preventDefault()
|
||||
toggleFullscreen()
|
||||
break
|
||||
|
||||
case 'p':
|
||||
e.preventDefault()
|
||||
togglePictureInPicture()
|
||||
break
|
||||
|
||||
case '0':
|
||||
case 'home':
|
||||
e.preventDefault()
|
||||
seek(0)
|
||||
break
|
||||
|
||||
case 'end':
|
||||
e.preventDefault()
|
||||
seek(videoState.duration)
|
||||
break
|
||||
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
e.preventDefault()
|
||||
const percent = parseInt(e.key) / 10
|
||||
seek(videoState.duration * percent)
|
||||
break
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('keydown', handleKeyDown)
|
||||
return () => window.removeEventListener('keydown', handleKeyDown)
|
||||
}, [
|
||||
enabled,
|
||||
videoState.currentTime,
|
||||
videoState.duration,
|
||||
videoState.volume,
|
||||
togglePlay,
|
||||
seek,
|
||||
setVolume,
|
||||
toggleMute,
|
||||
toggleFullscreen,
|
||||
togglePictureInPicture,
|
||||
])
|
||||
}
|
||||
Reference in New Issue
Block a user