From 6b37d3b9eca31fd1cbfcf0da8f60e9711ae09568 Mon Sep 17 00:00:00 2001 From: Taj Date: Sat, 9 Aug 2025 00:23:18 +0530 Subject: [PATCH 1/2] feat: Add MIT license to build output and refactor component structure - Add MIT license declaration to the tsup build output banner. - Refactor `src/index.ts` to improve code structure and readability: - Move `InteractiveVideoProps` interface definition outside of `defineComponent`. - Reformat component `props` definition for better clarity. --- src/index.ts | 340 ++++++++++++++++++++++++------------------------- tsup.config.ts | 1 + 2 files changed, 171 insertions(+), 170 deletions(-) diff --git a/src/index.ts b/src/index.ts index 433f9ed..37d5cc7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,196 +1,196 @@ -import { defineComponent, onUnmounted, onMounted, ref, watch, h, PropType, nextTick } from 'vue'; -import { IVLabsPlayer, PlayerConfig, CuePoint, Translations, AnalyticsEvent, AnalyticsPayload } from '@interactive-video-labs/core'; + import { defineComponent, onUnmounted, onMounted, ref, watch, h, PropType, nextTick } from 'vue'; + import { IVLabsPlayer, PlayerConfig, CuePoint, Translations, AnalyticsEvent, AnalyticsPayload } from '@interactive-video-labs/core'; -/** - * Props for the InteractiveVideo component. - */ -export interface InteractiveVideoProps extends Omit { /** - * The URL of the video to be loaded. + * Props for the InteractiveVideo component. */ - videoUrl: string; - /** - * Callback function for analytics events. - * @param event The name of the event. - * @param payload The data associated with the event. - */ - onAnalyticsEvent?: (event: AnalyticsEvent, payload?: AnalyticsPayload) => void; - /** - * An array of cue points for interactive events. - */ - cues?: CuePoint[]; - /** - * An object containing translations for the player. - */ - translations?: Translations; -} - - -/** - * A Vue component that wraps the IVLabsPlayer to provide interactive video capabilities. - * It handles the lifecycle of the player, including initialization, updates, and destruction. - */ -export default defineComponent({ - name: 'InteractiveVideo', - props: { + export interface InteractiveVideoProps extends Omit { /** * The URL of the video to be loaded. */ - videoUrl: { type: String, required: true }, + videoUrl: string; /** * Callback function for analytics events. + * @param event The name of the event. + * @param payload The data associated with the event. */ - onAnalyticsEvent: { type: Function as PropType<(event: AnalyticsEvent, payload?: AnalyticsPayload) => void> }, + onAnalyticsEvent?: (event: AnalyticsEvent, payload?: AnalyticsPayload) => void; /** * An array of cue points for interactive events. */ - cues: { type: Array as PropType }, + cues?: CuePoint[]; /** * An object containing translations for the player. */ - translations: { type: Object as PropType }, - /** - * Whether the video should start playing automatically. - */ - autoplay: { type: Boolean, default: false }, - /** - * Whether the video should loop. - */ - loop: { type: Boolean, default: false }, - /** - * The locale to be used for the player. - */ - locale: { type: String, default: 'en' }, - /** - * The ID of the target HTML element where the player will be mounted. - */ - targetElementId: { type: String }, - }, + translations?: Translations; + } + + /** - * The setup function for the component. - * @param props The component's props. - * @param attrs The component's attributes. - * @param expose Function to expose properties to the parent component. - * @returns A render function that creates the component's DOM structure. + * A Vue component that wraps the IVLabsPlayer to provide interactive video capabilities. + * It handles the lifecycle of the player, including initialization, updates, and destruction. */ - setup(props, { attrs, expose }) { - const containerRef = ref(null); - const playerRef = ref(null); - - // Determine the ID to be used by the IVLabsPlayer. - // If targetElementId is provided, use it directly. - // Otherwise, generate a unique ID for the div rendered by this component. - const playerTargetId = props.targetElementId || `ivlabs-player-${Math.random().toString(36).substr(2, 9)}`; - - const initializePlayer = () => { - if (playerRef.value) { - return; // Player already initialized - } - - // Ensure the target element exists in the DOM before proceeding. - const targetElement = document.getElementById(playerTargetId); - if (!targetElement) { - console.error(`IVLabsPlayer target element with ID '${playerTargetId}' not found.`); - return; - } - - const playerConfig: PlayerConfig = { - ...attrs, - videoUrl: props.videoUrl, - autoplay: props.autoplay, - loop: props.loop, - locale: props.locale, - }; - - try { - // Pass the ID of the target element, not the element itself. - const player = new IVLabsPlayer(playerTargetId, playerConfig); - playerRef.value = player; - - if (props.onAnalyticsEvent) { - const analyticsHandler = props.onAnalyticsEvent; - const eventsToRegister: AnalyticsEvent[] = [ - 'PLAYER_LOADED', - 'VIDEO_STARTED', - 'VIDEO_PAUSED', - 'VIDEO_ENDED', - 'CUE_TRIGGERED', - 'INTERACTION_COMPLETED', - 'ERROR', - ]; - - eventsToRegister.forEach((event) => { - player.on(event, (payload?: AnalyticsPayload) => { - analyticsHandler(event, payload); - }); - }); + export default defineComponent({ + name: 'InteractiveVideo', + props: { + /** + * The URL of the video to be loaded. + */ + videoUrl: { type: String, required: true }, + /** + * Callback function for analytics events. + */ + onAnalyticsEvent: { type: Function as PropType<(event: AnalyticsEvent, payload?: AnalyticsPayload) => void> }, + /** + * An array of cue points for interactive events. + */ + cues: { type: Array as PropType }, + /** + * An object containing translations for the player. + */ + translations: { type: Object as PropType }, + /** + * Whether the video should start playing automatically. + */ + autoplay: { type: Boolean, default: false }, + /** + * Whether the video should loop. + */ + loop: { type: Boolean, default: false }, + /** + * The locale to be used for the player. + */ + locale: { type: String, default: 'en' }, + /** + * The ID of the target HTML element where the player will be mounted. + */ + targetElementId: { type: String }, + }, + /** + * The setup function for the component. + * @param props The component's props. + * @param attrs The component's attributes. + * @param expose Function to expose properties to the parent component. + * @returns A render function that creates the component's DOM structure. + */ + setup(props, { attrs, expose }) { + const containerRef = ref(null); + const playerRef = ref(null); + + // Determine the ID to be used by the IVLabsPlayer. + // If targetElementId is provided, use it directly. + // Otherwise, generate a unique ID for the div rendered by this component. + const playerTargetId = props.targetElementId || `ivlabs-player-${Math.random().toString(36).substr(2, 9)}`; + + const initializePlayer = () => { + if (playerRef.value) { + return; // Player already initialized } - if (props.cues) { - player.loadCues(props.cues); + // Ensure the target element exists in the DOM before proceeding. + const targetElement = document.getElementById(playerTargetId); + if (!targetElement) { + console.error(`IVLabsPlayer target element with ID '${playerTargetId}' not found.`); + return; } - if (props.translations) { - player.loadTranslations(props.locale, props.translations); - } - } catch (error) { - console.error('Error initializing IVLabsPlayer:', error); - } - }; - - onMounted(() => { - // Delay initialization to ensure the DOM is ready - nextTick(() => { - initializePlayer(); - }); - }); + const playerConfig: PlayerConfig = { + ...attrs, + videoUrl: props.videoUrl, + autoplay: props.autoplay, + loop: props.loop, + locale: props.locale, + }; + + try { + // Pass the ID of the target element, not the element itself. + const player = new IVLabsPlayer(playerTargetId, playerConfig); + playerRef.value = player; + + if (props.onAnalyticsEvent) { + const analyticsHandler = props.onAnalyticsEvent; + const eventsToRegister: AnalyticsEvent[] = [ + 'PLAYER_LOADED', + 'VIDEO_STARTED', + 'VIDEO_PAUSED', + 'VIDEO_ENDED', + 'CUE_TRIGGERED', + 'INTERACTION_COMPLETED', + 'ERROR', + ]; + + eventsToRegister.forEach((event) => { + player.on(event, (payload?: AnalyticsPayload) => { + analyticsHandler(event, payload); + }); + }); + } - onUnmounted(() => { - if (playerRef.value) { - playerRef.value.destroy(); - playerRef.value = null; - } - }); + if (props.cues) { + player.loadCues(props.cues); + } - /** - * Watches for changes in the cues prop and reloads them in the player. - */ - watch(() => props.cues, (newCues) => { - if (playerRef.value && newCues) { - playerRef.value.loadCues(newCues); - } - }, { deep: true }); + if (props.translations) { + player.loadTranslations(props.locale, props.translations); + } + } catch (error) { + console.error('Error initializing IVLabsPlayer:', error); + } + }; - /** - * Watches for changes in the translations prop and reloads them in the player. - */ - watch(() => props.translations, (newTranslations) => { - if (playerRef.value && newTranslations) { - playerRef.value.loadTranslations(props.locale, newTranslations); - } - }, { deep: true }); + onMounted(() => { + // Delay initialization to ensure the DOM is ready + nextTick(() => { + initializePlayer(); + }); + }); - // Expose the player instance to the parent component. - expose({ playerRef }); + onUnmounted(() => { + if (playerRef.value) { + playerRef.value.destroy(); + playerRef.value = null; + } + }); - /** - * The render function for the component. - * @returns A VNode representing the container div for the player. - */ - return () => { - if (props.targetElementId) { - // If targetElementId is provided, this component does not render a div. - // It expects the user to provide the div with that ID. - return null; - } else { - // If no targetElementId is provided, this component renders its own div. - return h('div', { - ref: containerRef, - id: playerTargetId, // Use the generated ID for this div - style: { width: '100%', height: 'auto' }, - 'data-testid': 'interactive-video-container', - }); - } - }; - }, -}); + /** + * Watches for changes in the cues prop and reloads them in the player. + */ + watch(() => props.cues, (newCues) => { + if (playerRef.value && newCues) { + playerRef.value.loadCues(newCues); + } + }, { deep: true }); + + /** + * Watches for changes in the translations prop and reloads them in the player. + */ + watch(() => props.translations, (newTranslations) => { + if (playerRef.value && newTranslations) { + playerRef.value.loadTranslations(props.locale, newTranslations); + } + }, { deep: true }); + + // Expose the player instance to the parent component. + expose({ playerRef }); + + /** + * The render function for the component. + * @returns A VNode representing the container div for the player. + */ + return () => { + if (props.targetElementId) { + // If targetElementId is provided, this component does not render a div. + // It expects the user to provide the div with that ID. + return null; + } else { + // If no targetElementId is provided, this component renders its own div. + return h('div', { + ref: containerRef, + id: playerTargetId, // Use the generated ID for this div + style: { width: '100%', height: 'auto' }, + 'data-testid': 'interactive-video-container', + }); + } + }; + }, + }); diff --git a/tsup.config.ts b/tsup.config.ts index d3a93f3..a4a9507 100644 --- a/tsup.config.ts +++ b/tsup.config.ts @@ -16,6 +16,7 @@ export default defineConfig((options) => ({ js: `/** * ${pkg.name} v${pkg.version} * Author: ${pkg.author} + * @license MIT */ `, }, From f6a38bf0b6dc6c439c55874018b24d226dc91bb0 Mon Sep 17 00:00:00 2001 From: Taj Date: Sat, 9 Aug 2025 00:27:36 +0530 Subject: [PATCH 2/2] docs: Update CHANGELOG.md for version 0.1.0 release Updated CHANGELOG.md to reflect the release of version 0.1.0, including new features and chore updates. --- CHANGELOG.md | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c13aa52..863f728 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,17 +8,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased -### Added - -### Changed +## 0.1.0 - 2025-08-09 -### Deprecated +### Features -### Removed +* `6b37d3b` feat: Add MIT license to build output and refactor component structure +* `d44a709` feat: Refine target element mounting and bump version +* `b89538d` feat: Allow specifying targetElementId for player mounting +* `d1888ea` feat: Improve player initialization and build output -### Fixed +### Chores -### Security +* `11e7138` chore: Bump package version to `0.1.0` to reflect the new feature and breaking change in rendering behavior. +* `e919430` chore: Update examples/ExampleInteractiveVideo.vue +* `47f4db5` chore: Update examples/package.json ## 0.0.2 - 2025-08-05