UNPKG

unified-video-framework

Version:

Cross-platform video player framework supporting iOS, Android, Web, Smart TVs (Samsung/LG), Roku, and more

156 lines 5.54 kB
import React, { useState, useEffect, useRef } from 'react'; import { DEFAULT_SKIP_LABELS } from '../../chapters/types/ChapterTypes.js'; export const SkipButton = ({ segment, visible = false, position = 'bottom-right', autoHideDelay = 5000, skipLabel, onSkip, onShow, onHide, className = '', style = {}, enableAutoSkip = false, autoSkipDelay = 10 }) => { const [isVisible, setIsVisible] = useState(visible); const [isAutoSkip, setIsAutoSkip] = useState(false); const [countdown, setCountdown] = useState(null); const autoHideTimeoutRef = useRef(null); const autoSkipTimeoutRef = useRef(null); const countdownIntervalRef = useRef(null); const previousSegmentRef = useRef(null); const clearTimeouts = () => { if (autoHideTimeoutRef.current) { clearTimeout(autoHideTimeoutRef.current); autoHideTimeoutRef.current = null; } if (autoSkipTimeoutRef.current) { clearTimeout(autoSkipTimeoutRef.current); autoSkipTimeoutRef.current = null; } if (countdownIntervalRef.current) { clearInterval(countdownIntervalRef.current); countdownIntervalRef.current = null; } }; const startAutoSkip = (segment, delay) => { setIsAutoSkip(true); setCountdown(delay); countdownIntervalRef.current = setInterval(() => { setCountdown((prev) => { if (prev === null || prev <= 1) { clearTimeouts(); onSkip?.(segment); handleHide('timeout'); return null; } return prev - 1; }); }, 1000); autoSkipTimeoutRef.current = setTimeout(() => { clearTimeouts(); onSkip?.(segment); handleHide('timeout'); }, delay * 1000); }; const handleSkip = () => { if (!segment) return; clearTimeouts(); onSkip?.(segment); handleHide('user-action'); }; const handleShow = () => { if (!segment) return; setIsVisible(true); onShow?.(segment); if (autoHideDelay > 0) { autoHideTimeoutRef.current = setTimeout(() => { handleHide('timeout'); }, autoHideDelay); } if (enableAutoSkip && segment.autoSkip && segment.autoSkipDelay) { startAutoSkip(segment, segment.autoSkipDelay); } }; const handleHide = (reason = 'manual') => { if (!segment) return; clearTimeouts(); setIsVisible(false); setIsAutoSkip(false); setCountdown(null); onHide?.(segment, reason); }; useEffect(() => { if (visible && segment && segment !== previousSegmentRef.current) { previousSegmentRef.current = segment; handleShow(); } else if (!visible || !segment) { if (previousSegmentRef.current) { handleHide('segment-end'); } previousSegmentRef.current = null; } }, [visible, segment]); useEffect(() => { return () => { clearTimeouts(); }; }, []); if (!segment || !isVisible) { return null; } const buttonText = skipLabel || segment.skipLabel || DEFAULT_SKIP_LABELS[segment.type]; const displayText = isAutoSkip && countdown !== null ? `${buttonText} (${countdown})` : buttonText; const positionClass = `uvf-skip-button-${position}`; const segmentClass = `uvf-skip-${segment.type}`; const autoSkipClass = isAutoSkip ? 'auto-skip' : ''; const countdownClass = isAutoSkip && countdown !== null ? 'countdown' : ''; const buttonClasses = [ 'uvf-skip-button', 'visible', positionClass, segmentClass, autoSkipClass, countdownClass, className ].filter(Boolean).join(' '); const defaultStyles = { position: 'absolute', zIndex: 1000, ...style }; switch (position) { case 'bottom-right': Object.assign(defaultStyles, { bottom: '100px', right: '30px' }); break; case 'bottom-left': Object.assign(defaultStyles, { bottom: '100px', left: '30px' }); break; case 'top-right': Object.assign(defaultStyles, { top: '30px', right: '30px' }); break; case 'top-left': Object.assign(defaultStyles, { top: '30px', left: '30px' }); break; } return (React.createElement("button", { type: "button", className: buttonClasses, style: defaultStyles, onClick: handleSkip, "aria-label": `${buttonText} - ${segment.title || segment.type}` }, displayText, isAutoSkip && countdown !== null && (React.createElement("div", { className: "uvf-skip-countdown-progress", style: { position: 'absolute', bottom: 0, left: 0, height: '3px', backgroundColor: 'currentColor', width: `${((autoSkipDelay - countdown) / autoSkipDelay) * 100}%`, transition: 'width 1s linear', borderRadius: '0 0 6px 6px' } })))); }; //# sourceMappingURL=SkipButton.js.map