Files
player/src/components/controls/VolumeControl.tsx
T
hibna b57b24d051 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.
2025-10-29 07:49:06 +03:00

68 lines
2.0 KiB
TypeScript

import React, { useState, useRef, useCallback } from 'react'
import { usePlayerContext } from '../../contexts/PlayerContext'
import { VolumeUpIcon, VolumeDownIcon, VolumeMuteIcon } from '../../icons'
import './VolumeControl.css'
export const VolumeControl: React.FC = () => {
const { videoState, setVolume, toggleMute } = usePlayerContext()
const [showSlider, setShowSlider] = useState(false)
const timeoutRef = useRef<number>()
const handleMouseEnter = useCallback(() => {
if (timeoutRef.current) {
window.clearTimeout(timeoutRef.current)
}
setShowSlider(true)
}, [])
const handleMouseLeave = useCallback(() => {
timeoutRef.current = window.setTimeout(() => {
setShowSlider(false)
}, 300)
}, [])
const handleSliderChange = useCallback(
(e: React.ChangeEvent<HTMLInputElement>) => {
const volume = parseFloat(e.target.value)
setVolume(volume)
},
[setVolume]
)
const VolumeIcon = videoState.muted ? VolumeMuteIcon : videoState.volume > 0.5 ? VolumeUpIcon : VolumeDownIcon
return (
<div
className="volume-control"
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
<button
className="control-button volume-button"
onClick={toggleMute}
aria-label={videoState.muted ? 'Unmute' : 'Mute'}
title={videoState.muted ? 'Unmute (M)' : 'Mute (M)'}
>
<VolumeIcon size={24} color="var(--player-text)" />
</button>
<div className={`volume-slider-container ${showSlider ? 'visible' : ''}`}>
<input
type="range"
min="0"
max="1"
step="0.01"
value={videoState.muted ? 0 : videoState.volume}
onChange={handleSliderChange}
className="volume-slider"
aria-label="Volume"
/>
<div
className="volume-slider-fill"
style={{ width: `${(videoState.muted ? 0 : videoState.volume) * 100}%` }}
/>
</div>
</div>
)
}