UNPKG

parevo-interactive-video

Version:

Framework-agnostic interactive video library with quiz overlays for React, Vue, and vanilla JS

128 lines (123 loc) 5.56 kB
'use strict'; var jsxRuntime = require('react/jsx-runtime'); var react = require('react'); var videojs = require('video.js'); const QuizOverlay = ({ question, onAnswer, isVisible }) => { if (!isVisible) return null; return (jsxRuntime.jsx("div", { className: "interactive-video-quiz-overlay", children: jsxRuntime.jsxs("div", { className: "quiz-content", children: [jsxRuntime.jsx("h3", { className: "quiz-question", children: question.question }), jsxRuntime.jsx("div", { className: "quiz-options", children: question.options.map((option) => (jsxRuntime.jsx("button", { className: "quiz-option", onClick: () => onAnswer(option.id), children: option.text }, option.id))) })] }) })); }; const InteractiveVideo = ({ src, config, className = '', width = 640, height = 360, autoplay = false, muted = false, controls = true, onQuestionAnswered, onVideoEnd }) => { const videoRef = react.useRef(null); const playerRef = react.useRef(null); const containerRef = react.useRef(null); const [currentQuestion, setCurrentQuestion] = react.useState(null); const [showQuiz, setShowQuiz] = react.useState(false); const [answeredQuestions, setAnsweredQuestions] = react.useState(new Set()); const [isPlayerReady, setIsPlayerReady] = react.useState(false); const handleAnswer = react.useCallback((optionId) => { if (!currentQuestion) return; const selectedOption = currentQuestion.options.find(opt => opt.id === optionId); if (!selectedOption) return; const isCorrect = selectedOption.isCorrect; setAnsweredQuestions(prev => new Set(prev).add(currentQuestion.id)); setShowQuiz(false); setCurrentQuestion(null); onQuestionAnswered?.(currentQuestion.id, optionId, isCorrect); if (playerRef.current) { if (isCorrect) { playerRef.current.play(); } else { playerRef.current.currentTime(currentQuestion.rewindTime); playerRef.current.play(); } } }, [currentQuestion, onQuestionAnswered]); const checkForQuestions = react.useCallback((currentTime) => { if (showQuiz || !isPlayerReady) return; const triggerQuestion = config.questions.find(q => !answeredQuestions.has(q.id) && currentTime >= q.triggerTime && currentTime < q.triggerTime + 1); if (triggerQuestion) { setCurrentQuestion(triggerQuestion); setShowQuiz(true); playerRef.current?.pause(); } }, [config.questions, answeredQuestions, showQuiz, isPlayerReady]); // Video player'ı initialize et react.useEffect(() => { if (!videoRef.current) return; // Eğer player zaten varsa ve aynı src'yi kullanıyorsa, tekrar initialize etme if (playerRef.current) { const currentSrc = playerRef.current.src(); if (currentSrc === src) { return; } // Farklı src ise dispose et try { playerRef.current.dispose(); } catch (error) { console.warn('Error disposing existing player:', error); } playerRef.current = null; } const initPlayer = () => { if (!videoRef.current || playerRef.current) return; try { const player = videojs(videoRef.current, { width, height, autoplay, muted, controls, sources: [{ src, type: 'video/mp4' }] }); playerRef.current = player; player.ready(() => { setIsPlayerReady(true); }); player.on('timeupdate', () => { const currentTime = player.currentTime(); if (currentTime !== undefined) { checkForQuestions(currentTime); } }); player.on('ended', () => { onVideoEnd?.(); }); } catch (error) { console.error('Error initializing video player:', error); } }; // Bir frame bekle ki DOM kesinlikle hazır olsun const timeoutId = setTimeout(initPlayer, 0); return () => { clearTimeout(timeoutId); if (playerRef.current) { try { playerRef.current.dispose(); } catch (error) { // Sessizce handle et } playerRef.current = null; } setIsPlayerReady(false); }; }, [src, width, height, autoplay, muted, controls, checkForQuestions, onVideoEnd]); return (jsxRuntime.jsxs("div", { ref: containerRef, className: `interactive-video-container ${className}`, style: { position: 'relative' }, children: [jsxRuntime.jsx("video", { ref: videoRef, className: "video-js vjs-default-skin", "data-setup": "{}", style: { width, height }, preload: "auto" }), jsxRuntime.jsx(QuizOverlay, { question: currentQuestion, onAnswer: handleAnswer, isVisible: showQuiz })] })); }; exports.InteractiveVideo = InteractiveVideo; exports.QuizOverlay = QuizOverlay; //# sourceMappingURL=index.js.map