@devix-technologies/react-gjirafa-vp-player 1.0.31-beta.19 → 1.0.31-beta.21

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
@@ -53,20 +53,16 @@ import { VPPlayer } from "@devix-technologies/react-gjirafa-vp-player";
53
53
  <VPPlayer
54
54
  scriptId="ptkzurnx"
55
55
  videoId="vjsobqhe"
56
- onPlay={() => analytics.track('play')}
57
- onQuartile25={() => analytics.track('25% watched')}
58
- onProgress20s={() => analytics.track('20s milestone')}
56
+ onPlay={() => analytics.track("play")}
57
+ onQuartile25={() => analytics.track("25% watched")}
58
+ onProgress20s={() => analytics.track("20s milestone")}
59
59
  />
60
60
  ```
61
61
 
62
62
  ### Vertical Player
63
63
 
64
64
  ```tsx
65
- <VPPlayer
66
- scriptId="rbqcdwzlg"
67
- videoId="vjsobqhe"
68
- isVertical={true}
69
- />
65
+ <VPPlayer scriptId="rbqcdwzlg" videoId="vjsobqhe" isVertical={true} />
70
66
  ```
71
67
 
72
68
  ### Reels Mode (TikTok-style)
@@ -109,8 +105,8 @@ For vertical player with your own videos array (not using GTech admin playlists)
109
105
  ],
110
106
  startIndex: 0,
111
107
  }}
112
- onNext={() => console.log('Next video')}
113
- onVideoStarted={(data) => console.log('Playing:', data.title)}
108
+ onNext={() => console.log("Next video")}
109
+ onVideoStarted={(data) => console.log("Playing:", data.title)}
114
110
  />
115
111
  ```
116
112
 
@@ -132,59 +128,111 @@ The player fills its container (100% width/height). Control sizing with a wrappe
132
128
  </div>
133
129
  ```
134
130
 
131
+ ## Video Locking
132
+
133
+ Video locking lets you lock a portion of each video (e.g. require watching N seconds or N% before skipping). The SDK supports this via a `shouldLockVideo` callback and `removeVideoLock()`. The recommended approach is to set the callback inside `onVideoSwitch` so locking applies after each video switch.
134
+
135
+ ### Ref methods
136
+
137
+ - **`shouldLockVideo(callback)`** – Set the callback that returns lock config. Pass a function that returns `{ isEnabled, type, value }`, or `null` to clear. Matches SDK naming.
138
+ - **`removeVideoLock()`** – Clear any active lock.
139
+
140
+ ### Lock config shape
141
+
142
+ ```ts
143
+ { isEnabled: boolean; type: "seconds" | "percentage"; value: number }
144
+ ```
145
+
146
+ ### Recommended pattern: lock on video switch
147
+
148
+ Use `onVideoSwitch` to set or clear `shouldLockVideo` after each switch. In the callback you can decide whether to lock (e.g. from app state) and for how long.
149
+
150
+ ```tsx
151
+ const playerRef = useRef<VPPlayerRef>(null);
152
+
153
+ <VPPlayer
154
+ ref={playerRef}
155
+ scriptId="ptkzurnx"
156
+ videoId="vjsobqhe"
157
+ config={{ /* ... */ }}
158
+ onVideoSwitch={() => {
159
+ const shouldLock = true; // your logic, e.g. from state
160
+ if (shouldLock) {
161
+ playerRef.current?.shouldLockVideo(() => ({
162
+ isEnabled: true,
163
+ type: "seconds",
164
+ value: 20,
165
+ }));
166
+ } else {
167
+ playerRef.current?.removeVideoLock();
168
+ playerRef.current?.shouldLockVideo(() => ({
169
+ isEnabled: false,
170
+ type: "seconds",
171
+ value: 0,
172
+ }));
173
+ }
174
+ }}
175
+ />
176
+ ```
177
+
178
+ To only lock for a period after each switch, enable locking in `onVideoSwitch` with the desired `value` (e.g. 20 seconds). To disable locking for the next video, call `removeVideoLock()` and set `shouldLockVideo` to return `isEnabled: false`.
179
+
135
180
  ## Props Reference
136
181
 
137
182
  ### Identification (one required)
138
183
 
139
- | Prop | Type | Description |
140
- |------|------|-------------|
141
- | `scriptId` | `string` | GTech script ID (e.g., "ptkzurnx") |
142
- | `videoId` | `string` | GTech video ID (e.g., "vjsobqhe") |
143
- | `scriptUrl` | `string` | Full managed script URL |
184
+ | Prop | Type | Description |
185
+ | ----------- | -------- | ---------------------------------- |
186
+ | `scriptId` | `string` | GTech script ID (e.g., "ptkzurnx") |
187
+ | `videoId` | `string` | GTech video ID (e.g., "vjsobqhe") |
188
+ | `scriptUrl` | `string` | Full managed script URL |
144
189
 
145
190
  ### Optional
146
191
 
147
- | Prop | Type | Description |
148
- |------|------|-------------|
149
- | `projectId` | `string` | GTech project ID (required for manual playlist) |
150
- | `playlist` | `ManualPlaylistConfig` | Custom videos array for manual playlist mode |
151
- | `playerId` | `string` | Custom container ID (auto-generated if not provided) |
152
- | `isVertical` | `boolean` | Force vertical player mode |
153
- | `isReels` | `boolean` | Enable Reels overlay mode |
154
- | `thumbnailUrl` | `string` | Thumbnail for Reels mode |
155
- | `className` | `string` | CSS class for container |
156
- | `hiddenClasses` | `string[]` | SDK element classes to hide |
192
+ | Prop | Type | Description |
193
+ | --------------- | ---------------------- | ---------------------------------------------------- |
194
+ | `projectId` | `string` | GTech project ID (required for manual playlist) |
195
+ | `playlist` | `ManualPlaylistConfig` | Custom videos array for manual playlist mode |
196
+ | `playerId` | `string` | Custom container ID (auto-generated if not provided) |
197
+ | `isVertical` | `boolean` | Force vertical player mode |
198
+ | `isReels` | `boolean` | Enable Reels overlay mode |
199
+ | `thumbnailUrl` | `string` | Thumbnail for Reels mode |
200
+ | `className` | `string` | CSS class for container |
201
+ | `hiddenClasses` | `string[]` | SDK element classes to hide |
157
202
 
158
203
  ### Event Callbacks
159
204
 
160
- | Prop | Horizontal | Vertical | Description |
161
- |------|:----------:|:--------:|-------------|
162
- | `onReady` | | | Player initialized |
163
- | `onPlay` | | | Playback started (initial play) |
164
- | `onPause` | | | Playback paused (user-initiated) |
165
- | `onResume` | | | Playback resumed after pause (vertical only) |
166
- | `onComplete` | | | Video completed (horizontal only) |
167
- | `onError` | | | Error occurred |
168
- | `onVideoStarted` | | | Video metadata available (returns `CurrentVideoData`) |
169
- | `onTimeUpdate` | | | Continuous time updates (returns seconds) |
170
- | `onQuartile25` | | | 25% watched |
171
- | `onQuartile50` | | | 50% watched |
172
- | `onQuartile75` | | | 75% watched |
173
- | `onNext` | | | Next video in playlist |
174
- | `onPrevious` | | | Previous video (vertical only) |
175
- | `onProgress10s` | | | Every ~10 seconds (returns seconds) |
176
- | `onProgress20s` | | | 20 second milestone (returns seconds) |
177
- | `onClose` | - | - | Reels overlay closed |
205
+ | Prop | Horizontal | Vertical | Description |
206
+ | ---------------- | :--------: | :------: | ----------------------------------------------------- |
207
+ | `onReady` | | | Player initialized |
208
+ | `onPlay` | | | Playback started (initial play) |
209
+ | `onPause` | | | Playback paused (user-initiated) |
210
+ | `onResume` | | | Playback resumed after pause (vertical only) |
211
+ | `onComplete` | | | Video completed (horizontal only) |
212
+ | `onError` | | | Error occurred |
213
+ | `onVideoStarted` | | | Video metadata available (returns `CurrentVideoData`) |
214
+ | `onTimeUpdate` | | | Continuous time updates (returns seconds) |
215
+ | `onQuartile25` | | | 25% watched |
216
+ | `onQuartile50` | | | 50% watched |
217
+ | `onQuartile75` | | | 75% watched |
218
+ | `onNext` | | | Next video in playlist |
219
+ | `onPrevious` | | | Previous video (vertical only) |
220
+ | `onProgress10s` | | | Every ~10 seconds (returns seconds) |
221
+ | `onProgress20s` | | | 20 second milestone (returns seconds) |
222
+ | `onVideoSwitch` | ✓ | ✓ | SDK `vp-video-switch` (use for video locking) |
223
+ | `onClose` | - | - | Reels overlay closed |
178
224
 
179
225
  #### Event Implementation Notes
180
226
 
181
227
  **Horizontal Player** uses standard VP Player SDK events via `.on()` listener:
228
+
182
229
  - `ready`, `play`, `pause`, `complete`, `video-started`, `video-state`, `time`, `playlistItem`, `error`
183
230
  - Quartiles: `analytics-25%-completed`, `analytics-50%-completed`, `analytics-75%-completed`
184
231
 
185
232
  **Vertical Player** uses a combination of `.on()` listener and the global `vp-event` handler:
186
233
 
187
234
  Standard events via `.on()`:
235
+
188
236
  - `vp-first-frame`, `vp-video-started`, `vp-video-state`, `vp-time`, `vp-video-switch`, `error`
189
237
  - Quartiles: `analytics-25%-completed`, `analytics-50%-completed`, `analytics-75%-completed`
190
238
 
@@ -192,15 +240,16 @@ Standard events via `.on()`:
192
240
 
193
241
  The following events are intercepted from the global `vp-event` emission because the VP Vertical Player SDK doesn't expose them via the standard `.on()` listener:
194
242
 
195
- | Event | SDK Event | Special Logic |
196
- |-------|-----------|---------------|
197
- | `onPlay` | `vp-state-playing` | Fires on initial play (when not resuming from pause) |
198
- | `onPause` | `vp-state-paused` | Only fires on **user-initiated** pause (not on video loop/end) |
199
- | `onResume` | `vp-state-playing` | Fires when resuming after **user-initiated** pause |
243
+ | Event | SDK Event | Special Logic |
244
+ | ---------- | ------------------ | -------------------------------------------------------------- |
245
+ | `onPlay` | `vp-state-playing` | Fires on initial play (when not resuming from pause) |
246
+ | `onPause` | `vp-state-paused` | Only fires on **user-initiated** pause (not on video loop/end) |
247
+ | `onResume` | `vp-state-playing` | Fires when resuming after **user-initiated** pause |
200
248
 
201
249
  **User Interaction Tracking:**
202
250
 
203
251
  To distinguish between user actions and automatic playback events (like video loops), we track the `vp-user-interaction` event:
252
+
204
253
  - When `vp-user-interaction` fires before `vp-state-paused` → user clicked pause → `onPause` fires
205
254
  - When `vp-user-interaction` fires before `vp-state-playing` (after pause) → user clicked play → `onResume` fires
206
255
  - When `vp-state-paused` fires without prior user interaction → video ended/looped → no `onPause` (silent)
@@ -209,6 +258,7 @@ To distinguish between user actions and automatic playback events (like video lo
209
258
  This ensures analytics events like `player_pause` and `player_resume` only fire for actual user actions, not automatic video looping.
210
259
 
211
260
  **Key Differences:**
261
+
212
262
  - `onComplete` - Only available on horizontal player (vertical auto-advances to next video)
213
263
  - `onResume` - Only available on vertical player (horizontal has no pause/resume distinction)
214
264
  - `onPrevious` - Only available on vertical player (horizontal has no direction detection)
@@ -222,14 +272,14 @@ import {
222
272
  getFullyManagedPlayerScriptUrl,
223
273
  getVerticalPlayerScriptUrl,
224
274
  appendDivIdToUrl,
225
- } from '@devix-technologies/react-gjirafa-vp-player';
275
+ } from "@devix-technologies/react-gjirafa-vp-player";
226
276
 
227
277
  // Build managed script URL
228
- const url = getFullyManagedPlayerScriptUrl('ptkzurnx', 'vjsobqhe');
278
+ const url = getFullyManagedPlayerScriptUrl("ptkzurnx", "vjsobqhe");
229
279
  // => "https://host.vpplayer.tech/player/ptkzurnx/vjsobqhe.js"
230
280
 
231
281
  // Build vertical player URL
232
- const verticalUrl = getVerticalPlayerScriptUrl('rbqcdwzlg');
282
+ const verticalUrl = getVerticalPlayerScriptUrl("rbqcdwzlg");
233
283
  // => "https://host.vpplayer.tech/vertical-player/rbqcdwzlg.js"
234
284
  ```
235
285
 
@@ -238,13 +288,16 @@ const verticalUrl = getVerticalPlayerScriptUrl('rbqcdwzlg');
238
288
  For programmatic control, use the hook directly:
239
289
 
240
290
  ```tsx
241
- import { useVPPlayerLogic, PlayerContainer } from '@devix-technologies/react-gjirafa-vp-player';
291
+ import {
292
+ useVPPlayerLogic,
293
+ PlayerContainer,
294
+ } from "@devix-technologies/react-gjirafa-vp-player";
242
295
 
243
296
  function CustomPlayer() {
244
297
  const { playerRef, playerInstanceRef, isScriptLoaded, generatedPlayerId } =
245
298
  useVPPlayerLogic({
246
- scriptId: 'ptkzurnx',
247
- videoId: 'vjsobqhe',
299
+ scriptId: "ptkzurnx",
300
+ videoId: "vjsobqhe",
248
301
  });
249
302
 
250
303
  return (
@@ -257,7 +310,9 @@ function CustomPlayer() {
257
310
  $hiddenClasses={[]}
258
311
  />
259
312
  <button onClick={() => playerInstanceRef.current?.play?.()}>Play</button>
260
- <button onClick={() => playerInstanceRef.current?.pause?.()}>Pause</button>
313
+ <button onClick={() => playerInstanceRef.current?.pause?.()}>
314
+ Pause
315
+ </button>
261
316
  </div>
262
317
  );
263
318
  }
package/dist/index.d.ts CHANGED
@@ -6,7 +6,6 @@ import { RefAttributes } from 'react';
6
6
  import { RefObject } from 'react';
7
7
  import { StyledComponent } from '@emotion/styled';
8
8
  import { Theme } from '@emotion/react';
9
- import { VideoLockingConfig as VideoLockingConfig_2 } from '../../../../../../../src/interfaces';
10
9
  import { VPPlayerInstance as VPPlayerInstance_2 } from '../../../../../../../src/interfaces';
11
10
  import { VPPlayerProps as VPPlayerProps_2 } from '../../../../../../../src/interfaces';
12
11
  import { VPPlayerRef as VPPlayerRef_2 } from '../../../../../../../src/interfaces';
@@ -269,6 +268,7 @@ export declare interface EventCallbackRefs {
269
268
  onProgress10s?: (seconds: number) => void;
270
269
  onProgress20s?: (seconds: number) => void;
271
270
  onPlaylistItem?: (data: CurrentVideoData_2) => void;
271
+ onVideoSwitch?: (data: VideoSwitchData) => void;
272
272
  }
273
273
 
274
274
  /**
@@ -728,15 +728,13 @@ export declare interface TimesliderSkin {
728
728
  * 1. **Auto-init mode** (default): Load managed script that auto-initializes with GTech admin config
729
729
  * 2. **Config override mode**: Fetch config, merge user overrides, and call setup()
730
730
  */
731
- export declare const useVPPlayerLogic: ({ scriptId, videoId, scriptUrl, projectId, config, playerId, isVertical, isReels, onReady, onPlay, onPause, onResume, onComplete, onError, onVideoStarted, onTimeUpdate, onQuartile25, onQuartile50, onQuartile75, onNext, onPrevious, onProgress10s, onProgress20s, onPlaylistItem, }: VPPlayerProps_2) => {
731
+ export declare const useVPPlayerLogic: ({ scriptId, videoId, scriptUrl, projectId, config, playerId, isVertical, isReels, onReady, onPlay, onPause, onResume, onComplete, onError, onVideoStarted, onTimeUpdate, onQuartile25, onQuartile50, onQuartile75, onNext, onPrevious, onProgress10s, onProgress20s, onPlaylistItem, onVideoSwitch, }: VPPlayerProps_2) => {
732
732
  playerRef: RefObject<HTMLDivElement | null>;
733
733
  playerInstanceRef: RefObject<VPPlayerInstance_2 | null>;
734
734
  isScriptLoaded: boolean;
735
735
  isLoading: boolean;
736
736
  error: string | null;
737
737
  generatedPlayerId: string;
738
- isInPlaylistTransitionRef: RefObject<boolean>;
739
- pendingVideoLockingRef: RefObject<VideoLockingConfig_2 | null>;
740
738
  };
741
739
 
742
740
  /**
@@ -828,6 +826,11 @@ export declare interface VideoLockingConfig {
828
826
  value: number;
829
827
  }
830
828
 
829
+ export declare interface VideoSwitchData {
830
+ direction?: "next" | "prev";
831
+ currentTime?: number;
832
+ }
833
+
831
834
  /**
832
835
  * Volume skin configuration
833
836
  */
@@ -985,6 +988,8 @@ export declare interface VPPlayerInstance {
985
988
  setLevelToAuto?: () => void;
986
989
  setCuePoint?: (cue: number, callback: () => void) => void;
987
990
  setVideoLocking?: (config: VideoLockingConfig) => void;
991
+ removeVideoLock?: () => void;
992
+ shouldLockVideo?: () => VideoLockingConfig;
988
993
  on?: (event: string, callback: (data?: unknown) => void) => void;
989
994
  off?: (event: string, callback?: (data?: unknown) => void) => void;
990
995
  videoIndex?: number;
@@ -1168,6 +1173,11 @@ export declare interface VPPlayerProps {
1168
1173
  * @param data - Video metadata for the new playlist item
1169
1174
  */
1170
1175
  onPlaylistItem?: (data: CurrentVideoData_2) => void;
1176
+ /**
1177
+ * Called when the SDK emits vp-video-switch (e.g. user switched to next/prev video).
1178
+ * Use with ref.shouldLockVideo() for video locking; see README Video Locking section.
1179
+ */
1180
+ onVideoSwitch?: (data: VideoSwitchData) => void;
1171
1181
  }
1172
1182
 
1173
1183
  /**
@@ -1207,8 +1217,16 @@ export declare interface VPPlayerRef {
1207
1217
  isPaused: () => boolean;
1208
1218
  isFullscreen: () => boolean;
1209
1219
  /**
1210
- * Set video locking configuration dynamically.
1211
- * This is the correct way to enable/disable video locking after the player has started.
1220
+ * Set the shouldLockVideo callback on the player (SDK naming).
1221
+ * Pass a function that returns lock config, or null to clear.
1222
+ */
1223
+ shouldLockVideo: (callback: (() => VideoLockingConfig) | null) => void;
1224
+ /**
1225
+ * Remove/unlock the video.
1226
+ */
1227
+ removeVideoLock: () => void;
1228
+ /**
1229
+ * Imperatively set the video lock config. Use this to apply lock after video switch.
1212
1230
  */
1213
1231
  setVideoLocking: (config: VideoLockingConfig) => void;
1214
1232
  }