@flowplayer/spins 0.6.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,10 +2,12 @@
2
2
 
3
3
  A TypeScript library for creating Flowplayer playlist components optimized for short-form video content like Reels and Shorts.
4
4
 
5
+ ## Quick Start
6
+
5
7
  ```typescript
6
8
  import { createSpins } from "@flowplayer/spins";
7
9
 
8
- const spinsContainer = createSpins({
10
+ const spinsContainer = createSpins({
9
11
  playlist: "your-playlist-id",
10
12
  token: "your-token",
11
13
  lang: "en",
@@ -13,30 +15,6 @@ const spinsContainer = createSpins({
13
15
  document.body.appendChild(spinsContainer);
14
16
  ```
15
17
 
16
- ### React Usage
17
-
18
- ```tsx
19
- import { createSpins, type SpinsConfig } from "@flowplayer/spins";
20
- import { useEffect, useRef } from "react";
21
-
22
- function SpinsPlayer({ playlistId }: { playlistId: string }) {
23
- const containerRef = useRef<HTMLDivElement>(null);
24
-
25
- useEffect(() => {
26
- if (containerRef.current) {
27
- const spinsContainer = createSpins({
28
- playlist: playlistId,
29
- token: "your-token",
30
- lang: "en",
31
- });
32
- containerRef.current.appendChild(spinsContainer);
33
- }
34
- }, [playlistId]);
35
-
36
- return <div ref={containerRef} className="spins-container" />;
37
- }
38
- ```
39
-
40
18
  ## Features
41
19
 
42
20
  - 🎯 **Type-safe** - Built with TypeScript and Zod schema validation
@@ -56,20 +34,76 @@ bun add @flowplayer/spins
56
34
 
57
35
  ## Usage
58
36
 
37
+ ### Basic Usage
38
+
59
39
  ```typescript
60
- import { spins, type SpinsConfig } from "@flowplayer/spins";
40
+ import { createSpins, type SpinsConfig } from "@flowplayer/spins";
61
41
 
62
- // Create a playlist component for short-form content
63
42
  const config: SpinsConfig = {
64
43
  playlist: "your-playlist-id", // or array of SpinItem objects
65
44
  token: "your-flowplayer-token",
66
45
  lang: "en"
67
46
  };
68
47
 
69
- const spinsContainer = spins(config);
48
+ const spinsContainer = createSpins(config);
70
49
  document.body.appendChild(spinsContainer);
71
50
  ```
72
51
 
52
+ ### React Integration
53
+
54
+ ```tsx
55
+ import { createSpins, type SpinsConfig } from "@flowplayer/spins";
56
+ import { useEffect, useRef } from "react";
57
+
58
+ function SpinsPlayer({ playlistId }: { playlistId: string }) {
59
+ const containerRef = useRef<HTMLDivElement>(null);
60
+
61
+ useEffect(() => {
62
+ if (!containerRef.current) return;
63
+
64
+ const spinsContainer = createSpins({
65
+ playlist: playlistId,
66
+ token: "your-token",
67
+ lang: "en",
68
+ });
69
+
70
+ containerRef.current.appendChild(spinsContainer);
71
+
72
+ return () => {
73
+ spinsContainer.remove();
74
+ };
75
+ }, [playlistId]);
76
+
77
+ return <div ref={containerRef} className="spins-container" />;
78
+ }
79
+ ```
80
+
81
+ ### With Custom Playlist
82
+
83
+ ```typescript
84
+ import { createSpins, type SpinItem } from "@flowplayer/spins";
85
+
86
+ const customPlaylist: SpinItem[] = [
87
+ {
88
+ url: "https://example.com/video1.mp4",
89
+ title: "First Video",
90
+ poster: "https://example.com/poster1.jpg",
91
+ description: "Description of first video"
92
+ },
93
+ {
94
+ url: { src: "https://example.com/video2.mp4", type: "video/mp4" },
95
+ title: "Second Video",
96
+ poster: "https://example.com/poster2.jpg"
97
+ }
98
+ ];
99
+
100
+ const spinsContainer = createSpins({
101
+ playlist: customPlaylist,
102
+ token: "your-token",
103
+ lang: "en"
104
+ });
105
+ ```
106
+
73
107
  ## Short-Form Video Content
74
108
 
75
109
  This library is specifically designed to handle short-form video playlists, making it easy to create engaging vertical video experiences similar to:
@@ -86,78 +120,299 @@ The component automatically handles playlist loading and provides the structure
86
120
 
87
121
  Creates a Flowplayer playlist component container optimized for short-form video content.
88
122
 
89
- #### Parameters
123
+ #### Configuration Options
90
124
 
91
- - `config.playlist: string | Array<SpinItem>` - The playlist ID or array of spin configurations
92
- - `config.token: string` - Your Flowplayer token
93
- - `config.lang: string` - Language code (e.g., "en", "es")
125
+ ```typescript
126
+ interface SpinsConfig {
127
+ playlist: string | Array<SpinItem>; // Playlist ID or array of SpinItem
128
+ token?: string; // Your Flowplayer token
129
+ lang?: string; // Language code (e.g., "en", "es")
130
+ ui?: number; // UI configuration bitmask
131
+ ima?: PlayerIMAConfig; // IMA ads configuration
132
+ adsFrequency?: number; // Show ads every Nth spin (default: 10)
133
+ share?: ShareConfig; // Share plugin configuration
134
+ consent?: number; // Consent plugin configuration
135
+ plugins?: string[]; // List of plugins to enable
136
+ }
137
+ ```
94
138
 
95
139
  #### Returns
96
140
 
97
- Returns a `SpinsContainer` (extends `HTMLElement`) with event handling capabilities:
98
- - `on(event, handler)` - Subscribe to events
99
- - `off(event, handler)` - Unsubscribe from events
100
- - `addSpins(spins: SpinItem[])` - Adds more spins dynamically
141
+ A `SpinsContainer` instance (extends `HTMLElement`) with the following methods:
142
+
143
+ ##### Event Handling
144
+
145
+ ```typescript
146
+ // Listen to spin lifecycle events
147
+ spinsContainer.on(spinEvents.SPIN_CREATED, (e) => {
148
+ console.log('Spin created:', e.detail.config, e.detail.index);
149
+ });
150
+
151
+ spinsContainer.on(spinEvents.SPIN_IN_VIEWPORT, (e) => {
152
+ console.log('Spin in viewport:', e.detail.index);
153
+ });
154
+
155
+ // Listen to player events (media events)
156
+ spinsContainer.onPlayerEvent(mediaEvents.PLAY, (e) => {
157
+ console.log('Video playing:', e.detail.spinIndex, e.detail.currentTime);
158
+ });
159
+
160
+ spinsContainer.onPlayerEvent(mediaEvents.ENDED, (e) => {
161
+ console.log('Video ended:', e.detail.spinIndex);
162
+ });
163
+
164
+ // Listen to ad events
165
+ spinsContainer.onPlayerEvent(adEvents.AD_STARTED, (e) => {
166
+ console.log('Ad started:', e.detail.spinIndex);
167
+ });
168
+
169
+ // Remove event listeners
170
+ spinsContainer.off(spinEvents.SPIN_CREATED, handler);
171
+ spinsContainer.offPlayerEvent(mediaEvents.PLAY, handler);
172
+ ```
173
+
174
+ ##### Dynamic Content
101
175
 
102
- #### Events
176
+ ```typescript
177
+ // Add more spins dynamically
178
+ spinsContainer.addSpins([
179
+ {
180
+ url: "https://example.com/video3.mp4",
181
+ title: "New Video",
182
+ poster: "https://example.com/poster3.jpg"
183
+ }
184
+ ]);
185
+ ```
186
+
187
+ ### Events
188
+
189
+ #### Spin Events (`spinEvents`)
103
190
 
104
191
  - `SPIN_CREATED` - Fired when a new spin is created
192
+ - `detail.config`: SpinItem configuration
193
+ - `detail.spin`: The spin container HTMLElement
194
+ - `detail.index`: Spin index
195
+
105
196
  - `SPIN_IN_VIEWPORT` - Fired when a spin enters the viewport
197
+ - `detail.config`: SpinItem configuration
198
+ - `detail.spin`: The spin container HTMLElement
199
+ - `detail.index`: Spin index
200
+
201
+ #### Media Events (`mediaEvents`)
202
+
203
+ - `PLAY` - Playback started/resumed
204
+ - `PAUSE` - Playback paused
205
+ - `PLAYING` - Actively playing
206
+ - `WAITING` - Buffering
207
+ - `CAN_PLAY` - Ready to play
208
+ - `TIME_UPDATE` - Playback position changed
209
+ - `SEEKING` - User seeking
210
+ - `SEEKED` - Seeking completed
211
+ - `ENDED` - Playback ended
212
+
213
+ All media events include:
214
+ - `detail.spinIndex`: Index of the spin
215
+ - `detail.currentTime`: Current playback time in seconds
216
+ - `detail.duration`: Video duration in seconds
217
+ - `detail.mediaId`: Media ID (if available)
218
+ - `detail.url`: Full URL of the media
219
+
220
+ #### Ad Events (`adEvents`)
221
+
222
+ - `AD_STARTED` - Ad playback started
223
+ - `AD_COMPLETED` - Ad finished playing
224
+ - `AD_PROGRESS` - Ad playback progress
225
+ - `AD_PAUSED` - Ad paused
226
+ - `AD_RESUMED` - Ad resumed
227
+ - `AD_SKIPPED` - Ad skipped by user
228
+ - `AD_ERROR` - Ad error occurred
229
+ - `AD_REQUEST_ERROR` - Ad request failed
230
+ - `AD_PLAYBACK_ERROR` - Ad playback error
231
+ - `AD_BREAK_COMPLETED` - Ad break finished
232
+ - `AD_TEARDOWN` - Ad cleanup
233
+ - `AD_MUTED` - Ad muted
234
+ - `AD_VOLUME_CHANGED` - Ad volume changed
235
+ - `AD_PREROLL_FINSIHED` - Preroll ad finished
236
+
237
+ All ad events include:
238
+ - `detail.spinIndex`: Index of the spin where the ad is shown
106
239
 
107
240
  ## TypeScript Support
108
241
 
109
- The library exports TypeScript types for full type safety:
242
+ The library is fully typed with TypeScript. Import types for full type safety:
110
243
 
111
244
  ```typescript
112
- import { type SpinsConfig, type SpinItem, type SpinsContainer } from "@flowplayer/spins";
245
+ import {
246
+ createSpins,
247
+ createAdPlayer,
248
+ spinEvents,
249
+ mediaEvents,
250
+ adEvents,
251
+ type SpinsConfig,
252
+ type SpinItem,
253
+ type SpinsContainer,
254
+ type SpinsAdPlayer,
255
+ type SpinsAdPlayerConfig,
256
+ type SpinEvent,
257
+ type MediaEvent,
258
+ type AdEvent,
259
+ type PlayerEvent,
260
+ type SpinEventData,
261
+ type MediaEventData,
262
+ type AdEventData,
263
+ type PlayerEventsDetailMap,
264
+ type AdEventsDetailMap,
265
+ } from "@flowplayer/spins";
113
266
  ```
114
267
 
115
- ### `SpinsConfig`
268
+ ### Key Type Definitions
116
269
 
117
- The main configuration interface:
270
+ #### `SpinsConfig`
271
+
272
+ Main configuration for creating a spins container:
118
273
 
119
274
  ```typescript
120
275
  interface SpinsConfig {
121
276
  playlist: string | Array<SpinItem>;
122
- token: string;
123
- lang: string;
277
+ token?: string;
278
+ lang?: string;
279
+ ui?: number;
280
+ ima?: PlayerIMAConfig;
281
+ adsFrequency?: number;
282
+ share?: ShareConfig;
283
+ consent?: number;
284
+ plugins?: string[];
124
285
  }
125
286
  ```
126
287
 
127
- ### `SpinItem`
288
+ #### `SpinItem`
128
289
 
129
- Individual spin configuration:
290
+ Individual video configuration:
130
291
 
131
292
  ```typescript
132
293
  interface SpinItem {
133
- url: string | { src: string; type: string }
134
- title?: string
135
- poster?: string
136
- description?: string
294
+ url: string | { src: string; type: string };
295
+ title?: string;
296
+ poster?: string;
297
+ description?: string;
298
+ subtitles?: SubtitlesConfig;
137
299
  }
138
300
  ```
139
301
 
140
- ## CSS Styling
302
+ #### `SpinsContainer`
141
303
 
142
- The component includes default CSS styling optimized for short-form video content. Styles are imported from:
143
- You can override styles by targeting the spins container and its children:
304
+ The container element with event handling:
144
305
 
145
- ```css
146
- .fp-spins-container {
147
- /* Base spins container styles */
306
+ ```typescript
307
+ interface SpinsContainer extends HTMLElement {
308
+ on(event: SpinEvent, handler: (e: CustomEvent<SpinEventData>) => void): void;
309
+ off(event: SpinEvent, handler: (e: CustomEvent<SpinEventData>) => void): void;
310
+ onPlayerEvent<K extends PlayerEvent>(
311
+ event: K,
312
+ handler: (e: CustomEvent<PlayerEventsDetailMap[K]>) => void
313
+ ): void;
314
+ offPlayerEvent<K extends PlayerEvent>(
315
+ event: K,
316
+ handler: (e: CustomEvent<PlayerEventsDetailMap[K]>) => void
317
+ ): void;
318
+ addSpins(spins: SpinItem[]): void;
319
+ }
320
+ ```
321
+
322
+ #### Event Data Types
323
+
324
+ ```typescript
325
+ interface SpinEventData {
326
+ config: SpinItem;
327
+ spin: HTMLElement;
328
+ index: number;
148
329
  }
149
330
 
150
- flowplayer-spin {
151
- /* Individual spin container styles */
331
+ interface MediaEventData {
332
+ spinIndex: number;
333
+ duration?: number;
334
+ currentTime: number;
335
+ mediaId?: string;
336
+ url: string;
152
337
  }
338
+
339
+ type AdEventData<K extends AdEvent> = {
340
+ spinIndex: number;
341
+ } & AdEventsDetailMap[K];
153
342
  ```
154
343
 
155
- ## Development
344
+ ## Advanced Usage
156
345
 
157
- ### Prerequisites
346
+ ### Listening to All Events
158
347
 
159
- - [Bun](https://bun.sh/) runtime
160
- - TypeScript 5+
348
+ ```typescript
349
+ import {
350
+ createSpins,
351
+ spinEvents,
352
+ mediaEvents,
353
+ adEvents,
354
+ type SpinEventData,
355
+ type MediaEventData
356
+ } from "@flowplayer/spins";
357
+
358
+ const container = createSpins({
359
+ playlist: "your-playlist-id",
360
+ token: "your-token",
361
+ lang: "en",
362
+ adsFrequency: 5 // Show ads every 5th spin
363
+ });
364
+
365
+ // Spin lifecycle events
366
+ container.on(spinEvents.SPIN_CREATED, (e) => {
367
+ console.log(`Spin ${e.detail.index} created:`, e.detail.config);
368
+ });
369
+
370
+ container.on(spinEvents.SPIN_IN_VIEWPORT, (e) => {
371
+ console.log(`Spin ${e.detail.index} is now visible`);
372
+ });
373
+
374
+ // Media playback events
375
+ container.onPlayerEvent(mediaEvents.PLAY, (e) => {
376
+ console.log(`Playing spin ${e.detail.spinIndex}`);
377
+ });
378
+
379
+ container.onPlayerEvent(mediaEvents.TIME_UPDATE, (e) => {
380
+ console.log(`Progress: ${e.detail.currentTime}/${e.detail.duration}`);
381
+ });
382
+
383
+ container.onPlayerEvent(mediaEvents.ENDED, (e) => {
384
+ console.log(`Spin ${e.detail.spinIndex} finished`);
385
+ });
386
+
387
+ // Ad events
388
+ container.onPlayerEvent(adEvents.AD_STARTED, (e) => {
389
+ console.log(`Ad started at spin ${e.detail.spinIndex}`);
390
+ });
391
+
392
+ container.onPlayerEvent(adEvents.AD_COMPLETED, (e) => {
393
+ console.log(`Ad completed at spin ${e.detail.spinIndex}`);
394
+ });
395
+
396
+ document.body.appendChild(container);
397
+ ```
398
+
399
+ ### Advertising Configuration
400
+
401
+ ```typescript
402
+ import { createSpins } from "@flowplayer/spins";
403
+
404
+ const container = createSpins({
405
+ playlist: "your-playlist-id",
406
+ token: "your-token",
407
+ lang: "en",
408
+ adsFrequency: 3, // Show ads every 3rd spin
409
+ ima: {
410
+ ads: [{
411
+ adTag: "https://pubads.g.doubleclick.net/gampad/ads?...",
412
+ time: 0
413
+ }]}
414
+ });
415
+ ```
161
416
 
162
417
  ## Contributing
163
418
 
@@ -167,6 +422,7 @@ This project uses:
167
422
  - **Vitest** with **Playwright** for browser testing
168
423
  - **Storybook** for component development and documentation
169
424
  - **Lit** for custom web components
425
+ - **Zod** for runtime schema validation
170
426
 
171
427
  ## License
172
428