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
JavaScript
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