diff --git a/.prettierrc b/.prettierrc index 0a72520..9c350b0 100644 --- a/.prettierrc +++ b/.prettierrc @@ -2,5 +2,6 @@ "trailingComma": "es5", "tabWidth": 2, "semi": true, - "singleQuote": true + "singleQuote": true, + "endOfLine": "lf" } diff --git a/CHANGELOG.md b/CHANGELOG.md index e69de29..fdf6ec0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -0,0 +1,37 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +## [0.0.2] - 2025-08-10 + +### Style + +- Configure prettier to use lf line endings + +### Chore + +- Support code lint and commit lint +- Add test lint +- Tsup config file confugured + +### Test + +- Fix test error + +### Docs + +- Add CONTRIBUTING.md guide +- Add DEVELOPER.md guide +- Update README.md with detailed project information +- Add horizontal rule to README + +### Features + +- Migrate tsup configuration to tsup.config.ts +- Add React wrapper and example +- Update package metadata and dependencies +- Setup project structure and CI workflows + +### Bug Fixes + +- Resolve race condition on initialization diff --git a/examples/index.tsx b/examples/index.tsx index 53a5c6f..2bba8dc 100644 --- a/examples/index.tsx +++ b/examples/index.tsx @@ -1,6 +1,6 @@ import React from 'react'; import ReactDOM from 'react-dom/client'; -import { InteractiveVideo } from '../dist/index'; +import { InteractiveVideo } from '@interactive-video-labs/react'; const App = () => { return ( @@ -13,6 +13,17 @@ const App = () => { onAnalyticsEvent={(event, payload) => { console.log('Analytics Event:', event, payload); }} + cues={[ + { + id: 'cue1', + time: 2, + payload: { + type: 'quiz', + question: 'What is the capital of France?', + answers: ['Paris', 'London', 'Berlin', 'Madrid'], + }, + }, + ]} /> diff --git a/src/index.tsx b/src/index.tsx index f0f0cce..8a82b35 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -59,55 +59,35 @@ export const InteractiveVideo: React.FC = ({ const uniqueIdRef = useRef(generateUniqueId()); useEffect(() => { - if (containerRef.current && !playerRef.current) { - const playerConfig: PlayerConfig = { - videoUrl, - ...restOptions, - }; + if (!containerRef.current) return; - try { - setTimeout(() => { - if (containerRef.current) { - const player = new IVLabsPlayer(uniqueIdRef.current, playerConfig); - playerRef.current = player; - - if (onAnalyticsEvent) { - player.on('PLAYER_LOADED', (payload?: AnalyticsPayload) => - onAnalyticsEvent('PLAYER_LOADED', payload) - ); - player.on('VIDEO_STARTED', (payload?: AnalyticsPayload) => - onAnalyticsEvent('VIDEO_STARTED', payload) - ); - player.on('VIDEO_PAUSED', (payload?: AnalyticsPayload) => - onAnalyticsEvent('VIDEO_PAUSED', payload) - ); - player.on('VIDEO_ENDED', (payload?: AnalyticsPayload) => - onAnalyticsEvent('VIDEO_ENDED', payload) - ); - player.on('CUE_TRIGGERED', (payload?: AnalyticsPayload) => - onAnalyticsEvent('CUE_TRIGGERED', payload) - ); - player.on('INTERACTION_COMPLETED', (payload?: AnalyticsPayload) => - onAnalyticsEvent('INTERACTION_COMPLETED', payload) - ); - player.on('ERROR', (payload?: AnalyticsPayload) => - onAnalyticsEvent('ERROR', payload) - ); - } + const playerConfig: PlayerConfig = { + videoUrl, + ...restOptions, + }; - if (cues) { - player.loadCues(cues); - } + try { + const player = new IVLabsPlayer(uniqueIdRef.current, playerConfig); + playerRef.current = player; - if (translations) { - const locale = restOptions.locale || 'en'; - player.loadTranslations(locale, translations); - } - } - }, 0); - } catch (error) { - console.error('Error initializing IVLabsPlayer:', error); + if (onAnalyticsEvent) { + const events: AnalyticsEvent[] = [ + 'PLAYER_LOADED', + 'VIDEO_STARTED', + 'VIDEO_PAUSED', + 'VIDEO_ENDED', + 'CUE_TRIGGERED', + 'INTERACTION_COMPLETED', + 'ERROR', + ]; + events.forEach((event) => { + player.on(event, (payload?: AnalyticsPayload) => + onAnalyticsEvent(event, payload) + ); + }); } + } catch (error) { + console.error('Error initializing IVLabsPlayer:', error); } return () => { @@ -116,7 +96,20 @@ export const InteractiveVideo: React.FC = ({ playerRef.current = null; } }; - }, [videoUrl, onAnalyticsEvent, cues, translations, restOptions]); + }, [videoUrl, onAnalyticsEvent, restOptions]); + + useEffect(() => { + if (playerRef.current && cues) { + playerRef.current.loadCues(cues); + } + }, [cues]); + + useEffect(() => { + if (playerRef.current && translations) { + const locale = restOptions.locale || 'en'; + playerRef.current.loadTranslations(locale, translations); + } + }, [translations, restOptions.locale]); return (
({ entry: ['src/index.tsx'], format: ['esm', 'cjs'], + outExtension({ format }) { + return { + js: `.${format === 'esm' ? 'mjs' : 'cjs'}`, + }; + }, dts: true, + watch: options.watch, clean: true, banner: { js: `/** * ${pkg.name} v${pkg.version} * Author: ${pkg.author} + * @license MIT */ - `, + `, }, -}); +}));