Skip to content

Commit 69b68da

Browse files
authored
Merge pull request #16 from taj54/main
docs: Update CHANGELOG.md for version 0.1.0 release
2 parents 9a08483 + f6a38bf commit 69b68da

File tree

3 files changed

+181
-177
lines changed

3 files changed

+181
-177
lines changed

CHANGELOG.md

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88

99
## Unreleased
1010

11-
### Added
12-
13-
### Changed
11+
## 0.1.0 - 2025-08-09
1412

15-
### Deprecated
13+
### Features
1614

17-
### Removed
15+
* `6b37d3b` feat: Add MIT license to build output and refactor component structure
16+
* `d44a709` feat: Refine target element mounting and bump version
17+
* `b89538d` feat: Allow specifying targetElementId for player mounting
18+
* `d1888ea` feat: Improve player initialization and build output
1819

19-
### Fixed
20+
### Chores
2021

21-
### Security
22+
* `11e7138` chore: Bump package version to `0.1.0` to reflect the new feature and breaking change in rendering behavior.
23+
* `e919430` chore: Update examples/ExampleInteractiveVideo.vue
24+
* `47f4db5` chore: Update examples/package.json
2225

2326
## 0.0.2 - 2025-08-05
2427

src/index.ts

Lines changed: 170 additions & 170 deletions
Original file line numberDiff line numberDiff line change
@@ -1,196 +1,196 @@
1-
import { defineComponent, onUnmounted, onMounted, ref, watch, h, PropType, nextTick } from 'vue';
2-
import { IVLabsPlayer, PlayerConfig, CuePoint, Translations, AnalyticsEvent, AnalyticsPayload } from '@interactive-video-labs/core';
1+
import { defineComponent, onUnmounted, onMounted, ref, watch, h, PropType, nextTick } from 'vue';
2+
import { IVLabsPlayer, PlayerConfig, CuePoint, Translations, AnalyticsEvent, AnalyticsPayload } from '@interactive-video-labs/core';
33

4-
/**
5-
* Props for the InteractiveVideo component.
6-
*/
7-
export interface InteractiveVideoProps extends Omit<PlayerConfig, 'videoUrl' | 'cues' | 'translations' | 'targetElementId'> {
84
/**
9-
* The URL of the video to be loaded.
5+
* Props for the InteractiveVideo component.
106
*/
11-
videoUrl: string;
12-
/**
13-
* Callback function for analytics events.
14-
* @param event The name of the event.
15-
* @param payload The data associated with the event.
16-
*/
17-
onAnalyticsEvent?: (event: AnalyticsEvent, payload?: AnalyticsPayload) => void;
18-
/**
19-
* An array of cue points for interactive events.
20-
*/
21-
cues?: CuePoint[];
22-
/**
23-
* An object containing translations for the player.
24-
*/
25-
translations?: Translations;
26-
}
27-
28-
29-
/**
30-
* A Vue component that wraps the IVLabsPlayer to provide interactive video capabilities.
31-
* It handles the lifecycle of the player, including initialization, updates, and destruction.
32-
*/
33-
export default defineComponent({
34-
name: 'InteractiveVideo',
35-
props: {
7+
export interface InteractiveVideoProps extends Omit<PlayerConfig, 'videoUrl' | 'cues' | 'translations' | 'targetElementId'> {
368
/**
379
* The URL of the video to be loaded.
3810
*/
39-
videoUrl: { type: String, required: true },
11+
videoUrl: string;
4012
/**
4113
* Callback function for analytics events.
14+
* @param event The name of the event.
15+
* @param payload The data associated with the event.
4216
*/
43-
onAnalyticsEvent: { type: Function as PropType<(event: AnalyticsEvent, payload?: AnalyticsPayload) => void> },
17+
onAnalyticsEvent?: (event: AnalyticsEvent, payload?: AnalyticsPayload) => void;
4418
/**
4519
* An array of cue points for interactive events.
4620
*/
47-
cues: { type: Array as PropType<CuePoint[]> },
21+
cues?: CuePoint[];
4822
/**
4923
* An object containing translations for the player.
5024
*/
51-
translations: { type: Object as PropType<Translations> },
52-
/**
53-
* Whether the video should start playing automatically.
54-
*/
55-
autoplay: { type: Boolean, default: false },
56-
/**
57-
* Whether the video should loop.
58-
*/
59-
loop: { type: Boolean, default: false },
60-
/**
61-
* The locale to be used for the player.
62-
*/
63-
locale: { type: String, default: 'en' },
64-
/**
65-
* The ID of the target HTML element where the player will be mounted.
66-
*/
67-
targetElementId: { type: String },
68-
},
25+
translations?: Translations;
26+
}
27+
28+
6929
/**
70-
* The setup function for the component.
71-
* @param props The component's props.
72-
* @param attrs The component's attributes.
73-
* @param expose Function to expose properties to the parent component.
74-
* @returns A render function that creates the component's DOM structure.
30+
* A Vue component that wraps the IVLabsPlayer to provide interactive video capabilities.
31+
* It handles the lifecycle of the player, including initialization, updates, and destruction.
7532
*/
76-
setup(props, { attrs, expose }) {
77-
const containerRef = ref<HTMLDivElement | null>(null);
78-
const playerRef = ref<IVLabsPlayer | null>(null);
79-
80-
// Determine the ID to be used by the IVLabsPlayer.
81-
// If targetElementId is provided, use it directly.
82-
// Otherwise, generate a unique ID for the div rendered by this component.
83-
const playerTargetId = props.targetElementId || `ivlabs-player-${Math.random().toString(36).substr(2, 9)}`;
84-
85-
const initializePlayer = () => {
86-
if (playerRef.value) {
87-
return; // Player already initialized
88-
}
89-
90-
// Ensure the target element exists in the DOM before proceeding.
91-
const targetElement = document.getElementById(playerTargetId);
92-
if (!targetElement) {
93-
console.error(`IVLabsPlayer target element with ID '${playerTargetId}' not found.`);
94-
return;
95-
}
96-
97-
const playerConfig: PlayerConfig = {
98-
...attrs,
99-
videoUrl: props.videoUrl,
100-
autoplay: props.autoplay,
101-
loop: props.loop,
102-
locale: props.locale,
103-
};
104-
105-
try {
106-
// Pass the ID of the target element, not the element itself.
107-
const player = new IVLabsPlayer(playerTargetId, playerConfig);
108-
playerRef.value = player;
109-
110-
if (props.onAnalyticsEvent) {
111-
const analyticsHandler = props.onAnalyticsEvent;
112-
const eventsToRegister: AnalyticsEvent[] = [
113-
'PLAYER_LOADED',
114-
'VIDEO_STARTED',
115-
'VIDEO_PAUSED',
116-
'VIDEO_ENDED',
117-
'CUE_TRIGGERED',
118-
'INTERACTION_COMPLETED',
119-
'ERROR',
120-
];
121-
122-
eventsToRegister.forEach((event) => {
123-
player.on(event, (payload?: AnalyticsPayload) => {
124-
analyticsHandler(event, payload);
125-
});
126-
});
33+
export default defineComponent({
34+
name: 'InteractiveVideo',
35+
props: {
36+
/**
37+
* The URL of the video to be loaded.
38+
*/
39+
videoUrl: { type: String, required: true },
40+
/**
41+
* Callback function for analytics events.
42+
*/
43+
onAnalyticsEvent: { type: Function as PropType<(event: AnalyticsEvent, payload?: AnalyticsPayload) => void> },
44+
/**
45+
* An array of cue points for interactive events.
46+
*/
47+
cues: { type: Array as PropType<CuePoint[]> },
48+
/**
49+
* An object containing translations for the player.
50+
*/
51+
translations: { type: Object as PropType<Translations> },
52+
/**
53+
* Whether the video should start playing automatically.
54+
*/
55+
autoplay: { type: Boolean, default: false },
56+
/**
57+
* Whether the video should loop.
58+
*/
59+
loop: { type: Boolean, default: false },
60+
/**
61+
* The locale to be used for the player.
62+
*/
63+
locale: { type: String, default: 'en' },
64+
/**
65+
* The ID of the target HTML element where the player will be mounted.
66+
*/
67+
targetElementId: { type: String },
68+
},
69+
/**
70+
* The setup function for the component.
71+
* @param props The component's props.
72+
* @param attrs The component's attributes.
73+
* @param expose Function to expose properties to the parent component.
74+
* @returns A render function that creates the component's DOM structure.
75+
*/
76+
setup(props, { attrs, expose }) {
77+
const containerRef = ref<HTMLDivElement | null>(null);
78+
const playerRef = ref<IVLabsPlayer | null>(null);
79+
80+
// Determine the ID to be used by the IVLabsPlayer.
81+
// If targetElementId is provided, use it directly.
82+
// Otherwise, generate a unique ID for the div rendered by this component.
83+
const playerTargetId = props.targetElementId || `ivlabs-player-${Math.random().toString(36).substr(2, 9)}`;
84+
85+
const initializePlayer = () => {
86+
if (playerRef.value) {
87+
return; // Player already initialized
12788
}
12889

129-
if (props.cues) {
130-
player.loadCues(props.cues);
90+
// Ensure the target element exists in the DOM before proceeding.
91+
const targetElement = document.getElementById(playerTargetId);
92+
if (!targetElement) {
93+
console.error(`IVLabsPlayer target element with ID '${playerTargetId}' not found.`);
94+
return;
13195
}
13296

133-
if (props.translations) {
134-
player.loadTranslations(props.locale, props.translations);
135-
}
136-
} catch (error) {
137-
console.error('Error initializing IVLabsPlayer:', error);
138-
}
139-
};
140-
141-
onMounted(() => {
142-
// Delay initialization to ensure the DOM is ready
143-
nextTick(() => {
144-
initializePlayer();
145-
});
146-
});
97+
const playerConfig: PlayerConfig = {
98+
...attrs,
99+
videoUrl: props.videoUrl,
100+
autoplay: props.autoplay,
101+
loop: props.loop,
102+
locale: props.locale,
103+
};
104+
105+
try {
106+
// Pass the ID of the target element, not the element itself.
107+
const player = new IVLabsPlayer(playerTargetId, playerConfig);
108+
playerRef.value = player;
109+
110+
if (props.onAnalyticsEvent) {
111+
const analyticsHandler = props.onAnalyticsEvent;
112+
const eventsToRegister: AnalyticsEvent[] = [
113+
'PLAYER_LOADED',
114+
'VIDEO_STARTED',
115+
'VIDEO_PAUSED',
116+
'VIDEO_ENDED',
117+
'CUE_TRIGGERED',
118+
'INTERACTION_COMPLETED',
119+
'ERROR',
120+
];
121+
122+
eventsToRegister.forEach((event) => {
123+
player.on(event, (payload?: AnalyticsPayload) => {
124+
analyticsHandler(event, payload);
125+
});
126+
});
127+
}
147128

148-
onUnmounted(() => {
149-
if (playerRef.value) {
150-
playerRef.value.destroy();
151-
playerRef.value = null;
152-
}
153-
});
129+
if (props.cues) {
130+
player.loadCues(props.cues);
131+
}
154132

155-
/**
156-
* Watches for changes in the cues prop and reloads them in the player.
157-
*/
158-
watch(() => props.cues, (newCues) => {
159-
if (playerRef.value && newCues) {
160-
playerRef.value.loadCues(newCues);
161-
}
162-
}, { deep: true });
133+
if (props.translations) {
134+
player.loadTranslations(props.locale, props.translations);
135+
}
136+
} catch (error) {
137+
console.error('Error initializing IVLabsPlayer:', error);
138+
}
139+
};
163140

164-
/**
165-
* Watches for changes in the translations prop and reloads them in the player.
166-
*/
167-
watch(() => props.translations, (newTranslations) => {
168-
if (playerRef.value && newTranslations) {
169-
playerRef.value.loadTranslations(props.locale, newTranslations);
170-
}
171-
}, { deep: true });
141+
onMounted(() => {
142+
// Delay initialization to ensure the DOM is ready
143+
nextTick(() => {
144+
initializePlayer();
145+
});
146+
});
172147

173-
// Expose the player instance to the parent component.
174-
expose({ playerRef });
148+
onUnmounted(() => {
149+
if (playerRef.value) {
150+
playerRef.value.destroy();
151+
playerRef.value = null;
152+
}
153+
});
175154

176-
/**
177-
* The render function for the component.
178-
* @returns A VNode representing the container div for the player.
179-
*/
180-
return () => {
181-
if (props.targetElementId) {
182-
// If targetElementId is provided, this component does not render a div.
183-
// It expects the user to provide the div with that ID.
184-
return null;
185-
} else {
186-
// If no targetElementId is provided, this component renders its own div.
187-
return h('div', {
188-
ref: containerRef,
189-
id: playerTargetId, // Use the generated ID for this div
190-
style: { width: '100%', height: 'auto' },
191-
'data-testid': 'interactive-video-container',
192-
});
193-
}
194-
};
195-
},
196-
});
155+
/**
156+
* Watches for changes in the cues prop and reloads them in the player.
157+
*/
158+
watch(() => props.cues, (newCues) => {
159+
if (playerRef.value && newCues) {
160+
playerRef.value.loadCues(newCues);
161+
}
162+
}, { deep: true });
163+
164+
/**
165+
* Watches for changes in the translations prop and reloads them in the player.
166+
*/
167+
watch(() => props.translations, (newTranslations) => {
168+
if (playerRef.value && newTranslations) {
169+
playerRef.value.loadTranslations(props.locale, newTranslations);
170+
}
171+
}, { deep: true });
172+
173+
// Expose the player instance to the parent component.
174+
expose({ playerRef });
175+
176+
/**
177+
* The render function for the component.
178+
* @returns A VNode representing the container div for the player.
179+
*/
180+
return () => {
181+
if (props.targetElementId) {
182+
// If targetElementId is provided, this component does not render a div.
183+
// It expects the user to provide the div with that ID.
184+
return null;
185+
} else {
186+
// If no targetElementId is provided, this component renders its own div.
187+
return h('div', {
188+
ref: containerRef,
189+
id: playerTargetId, // Use the generated ID for this div
190+
style: { width: '100%', height: 'auto' },
191+
'data-testid': 'interactive-video-container',
192+
});
193+
}
194+
};
195+
},
196+
});

0 commit comments

Comments
 (0)