@thewhateverapp/tile-sdk 0.11.1 → 0.12.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.
@@ -33,6 +33,12 @@ export interface KeyboardState {
33
33
  visible: boolean;
34
34
  height: number;
35
35
  }
36
+ /**
37
+ * Visibility state from parent (for TikTok-style feeds where tiles are preloaded)
38
+ */
39
+ export interface VisibilityState {
40
+ visible: boolean;
41
+ }
36
42
  type NextRouter = {
37
43
  push: (href: string) => void;
38
44
  replace: (href: string) => void;
@@ -49,6 +55,7 @@ export declare class TileBridge {
49
55
  private currentToken;
50
56
  private tokenExpiresAt;
51
57
  private keyboardState;
58
+ private visibilityState;
52
59
  private baselineViewportHeight;
53
60
  private keyboardDetectionEnabled;
54
61
  private lastReportedKeyboardState;
@@ -93,6 +100,11 @@ export declare class TileBridge {
93
100
  * Handle keyboard state message from parent (mobile app)
94
101
  */
95
102
  private handleKeyboard;
103
+ /**
104
+ * Handle visibility state message from parent (mobile app)
105
+ * Used for TikTok-style feeds where tiles are preloaded but not visible
106
+ */
107
+ private handleVisibility;
96
108
  private sendToParent;
97
109
  /**
98
110
  * Request to navigate to full page view
@@ -281,6 +293,24 @@ export declare class TileBridge {
281
293
  * @returns Unsubscribe function
282
294
  */
283
295
  onKeyboardChange(handler: (state: KeyboardState) => void): () => void;
296
+ /**
297
+ * Get the current visibility state from parent
298
+ * For TikTok-style feeds where tiles may be preloaded but not visible
299
+ * Returns { visible: true } by default (for web/non-mobile platforms)
300
+ */
301
+ getVisibilityState(): VisibilityState;
302
+ /**
303
+ * Check if the tile is currently visible
304
+ * Returns true by default (for standalone tiles not in a feed)
305
+ */
306
+ isVisible(): boolean;
307
+ /**
308
+ * Subscribe to visibility state changes
309
+ * Called when parent sends visibility show/hide events (e.g., TikTok-style feed)
310
+ * @param handler Callback receiving { visible: boolean }
311
+ * @returns Unsubscribe function
312
+ */
313
+ onVisibilityChange(handler: (state: VisibilityState) => void): () => void;
284
314
  /**
285
315
  * Wait for ready state
286
316
  *
@@ -1 +1 @@
1
- {"version":3,"file":"TileBridge.d.ts","sourceRoot":"","sources":["../../src/bridge/TileBridge.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"TileBridge.d.ts","sourceRoot":"","sources":["../../src/bridge/TileBridge.ts"],"names":[],"mappings":"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"}
@@ -15,6 +15,8 @@ export class TileBridge {
15
15
  this.tokenExpiresAt = null;
16
16
  // Keyboard state from parent (mobile app)
17
17
  this.keyboardState = { visible: false, height: 0 };
18
+ // Visibility state from parent (for TikTok-style feeds)
19
+ this.visibilityState = { visible: true };
18
20
  // VisualViewport tracking for keyboard detection (Plan A)
19
21
  this.baselineViewportHeight = 0;
20
22
  this.keyboardDetectionEnabled = false;
@@ -287,6 +289,9 @@ export class TileBridge {
287
289
  case 'parent:keyboard':
288
290
  this.handleKeyboard(message.payload);
289
291
  break;
292
+ case 'parent:visibility':
293
+ this.handleVisibility(message.payload);
294
+ break;
290
295
  case 'parent:navigateToPage':
291
296
  this.handleParentNavigate({ target: 'page' });
292
297
  break;
@@ -381,6 +386,27 @@ export class TileBridge {
381
386
  // Emit keyboard update event for listeners
382
387
  this.emitEvent('keyboard:update', this.keyboardState);
383
388
  }
389
+ /**
390
+ * Handle visibility state message from parent (mobile app)
391
+ * Used for TikTok-style feeds where tiles are preloaded but not visible
392
+ */
393
+ handleVisibility(payload) {
394
+ if (payload?.visible === undefined) {
395
+ console.warn('[TileBridge] Invalid visibility payload received');
396
+ return;
397
+ }
398
+ const wasVisible = this.visibilityState.visible;
399
+ this.visibilityState = {
400
+ visible: !!payload.visible,
401
+ };
402
+ if (this.isDevelopment() || this.isPreview()) {
403
+ console.log('[TileBridge] 👁️ Received visibility state', this.visibilityState);
404
+ }
405
+ // Only emit if visibility actually changed
406
+ if (wasVisible !== this.visibilityState.visible) {
407
+ this.emitEvent('visibility:update', this.visibilityState);
408
+ }
409
+ }
384
410
  sendToParent(message) {
385
411
  if (typeof window === 'undefined' || !window.parent)
386
412
  return;
@@ -1060,6 +1086,31 @@ export class TileBridge {
1060
1086
  onKeyboardChange(handler) {
1061
1087
  return this.on('keyboard:update', handler);
1062
1088
  }
1089
+ // ============= VISIBILITY API =============
1090
+ /**
1091
+ * Get the current visibility state from parent
1092
+ * For TikTok-style feeds where tiles may be preloaded but not visible
1093
+ * Returns { visible: true } by default (for web/non-mobile platforms)
1094
+ */
1095
+ getVisibilityState() {
1096
+ return { ...this.visibilityState };
1097
+ }
1098
+ /**
1099
+ * Check if the tile is currently visible
1100
+ * Returns true by default (for standalone tiles not in a feed)
1101
+ */
1102
+ isVisible() {
1103
+ return this.visibilityState.visible;
1104
+ }
1105
+ /**
1106
+ * Subscribe to visibility state changes
1107
+ * Called when parent sends visibility show/hide events (e.g., TikTok-style feed)
1108
+ * @param handler Callback receiving { visible: boolean }
1109
+ * @returns Unsubscribe function
1110
+ */
1111
+ onVisibilityChange(handler) {
1112
+ return this.on('visibility:update', handler);
1113
+ }
1063
1114
  /**
1064
1115
  * Wait for ready state
1065
1116
  *
package/dist/index.d.ts CHANGED
@@ -7,7 +7,7 @@ export { withTile } from './react/withTile';
7
7
  export { VideoPlayer, useVideoState, Slideshow, useSlideshowState, OverlaySlot, FullOverlay, GradientOverlay, } from './react/overlay';
8
8
  export type { VideoState, VideoControls, VideoContextValue, VideoPlayerProps, SlideImage, SlideshowState, SlideshowControls, SlideshowContextValue, SlideshowProps, SlotPosition, OverlaySlotProps, FullOverlayProps, GradientOverlayProps, } from './react/overlay';
9
9
  export { getTileBridge, TileBridge } from './bridge/TileBridge';
10
- export type { TileMessage, TileConfig, TileTokenData, KeyboardState } from './bridge/TileBridge';
10
+ export type { TileMessage, TileConfig, TileTokenData, KeyboardState, VisibilityState } from './bridge/TileBridge';
11
11
  export { StateClient } from './state/StateClient';
12
12
  export type { TileStats, ViewResponse } from './state/StateClient';
13
13
  export * from './tools';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAG5C,OAAO,EAEL,WAAW,EACX,aAAa,EAEb,SAAS,EACT,iBAAiB,EAEjB,WAAW,EACX,WAAW,EACX,eAAe,GAChB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAEV,UAAU,EACV,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAEhB,UAAU,EACV,cAAc,EACd,iBAAiB,EACjB,qBAAqB,EACrB,cAAc,EAEd,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAChE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGjG,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGnE,cAAc,SAAS,CAAC;AAGxB,cAAc,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAG5C,OAAO,EAEL,WAAW,EACX,aAAa,EAEb,SAAS,EACT,iBAAiB,EAEjB,WAAW,EACX,WAAW,EACX,eAAe,GAChB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAEV,UAAU,EACV,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAEhB,UAAU,EACV,cAAc,EACd,iBAAiB,EACjB,qBAAqB,EACrB,cAAc,EAEd,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAChE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,aAAa,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAGlH,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGnE,cAAc,SAAS,CAAC;AAGxB,cAAc,SAAS,CAAC"}
@@ -50,12 +50,20 @@ export interface VideoContextValue {
50
50
  controls: VideoControls;
51
51
  videoRef: React.RefObject<HTMLVideoElement>;
52
52
  }
53
+ export interface CuePoint {
54
+ /** Time in seconds when the cue should trigger */
55
+ time: number;
56
+ /** Unique identifier for the cue point */
57
+ id: string;
58
+ /** Optional data to pass to the callback */
59
+ data?: unknown;
60
+ }
53
61
  export interface VideoPlayerProps {
54
62
  /** HLS playlist URL (m3u8) */
55
63
  src: string;
56
64
  /** Auto-start playback (default: true) */
57
65
  autoplay?: boolean;
58
- /** Loop video (default: false) */
66
+ /** Loop video (default: false, but true in preview mode) */
59
67
  loop?: boolean;
60
68
  /** Start muted (default: true for autoplay compliance) */
61
69
  muted?: boolean;
@@ -69,15 +77,103 @@ export interface VideoPlayerProps {
69
77
  className?: string;
70
78
  /** Video wrapper class names */
71
79
  videoClassName?: string;
80
+ /** Cue points for time-based triggers */
81
+ cuePoints?: CuePoint[];
82
+ /** Callback when a cue point is reached */
83
+ onCuePoint?: (cuePoint: CuePoint) => void;
84
+ /** Callback on time update (fires ~4 times per second) */
85
+ onTimeUpdate?: (currentTime: number, duration: number) => void;
72
86
  }
73
87
  /**
74
88
  * VideoPlayer component with HLS streaming support.
75
89
  * Provides video state and controls to child overlays via context.
90
+ *
91
+ * Features:
92
+ * - HLS streaming with automatic quality adaptation
93
+ * - Time-based cue points for triggering overlays
94
+ * - Visibility-aware playback (plays when visible, pauses when hidden)
95
+ * - Auto-loops in preview mode for testing
76
96
  */
77
- export declare function VideoPlayer({ src, autoplay, loop, muted, poster, controls, children, className, videoClassName, }: VideoPlayerProps): React.JSX.Element;
97
+ export declare function VideoPlayer({ src, autoplay, loop: loopProp, muted, poster, controls, children, className, videoClassName, cuePoints, onCuePoint, onTimeUpdate, }: VideoPlayerProps): React.JSX.Element;
78
98
  /**
79
99
  * Hook to access video state and controls from within VideoPlayer children.
80
100
  */
81
101
  export declare function useVideoState(): VideoContextValue;
102
+ /**
103
+ * Hook to trigger an action when a specific time is reached.
104
+ * Returns true when the video has reached or passed the specified time.
105
+ *
106
+ * @param triggerTime - Time in seconds when to trigger
107
+ * @param options - Configuration options
108
+ * @returns boolean indicating if the trigger time has been reached
109
+ *
110
+ * @example
111
+ * ```tsx
112
+ * function PollOverlay() {
113
+ * const showPoll = useCuePoint(5); // Show after 5 seconds
114
+ * return showPoll ? <Poll /> : null;
115
+ * }
116
+ * ```
117
+ */
118
+ export declare function useCuePoint(triggerTime: number, options?: {
119
+ /** Reset trigger when video loops (default: true) */
120
+ resetOnLoop?: boolean;
121
+ /** Trigger once or every time the time is crossed (default: 'once') */
122
+ mode?: 'once' | 'every-loop';
123
+ }): boolean;
124
+ /**
125
+ * Hook to manage multiple cue points with callbacks.
126
+ * More flexible than useCuePoint for complex time-based interactions.
127
+ *
128
+ * @param cuePoints - Array of cue points with times and callbacks
129
+ * @param options - Configuration options
130
+ *
131
+ * @example
132
+ * ```tsx
133
+ * function InteractiveOverlay() {
134
+ * const [showPoll, setShowPoll] = useState(false);
135
+ * const [showCTA, setShowCTA] = useState(false);
136
+ *
137
+ * useCuePoints([
138
+ * { time: 5, onTrigger: () => setShowPoll(true) },
139
+ * { time: 10, onTrigger: () => setShowCTA(true) },
140
+ * { time: 15, onTrigger: () => { setShowPoll(false); setShowCTA(false); } },
141
+ * ]);
142
+ *
143
+ * return (
144
+ * <>
145
+ * {showPoll && <Poll />}
146
+ * {showCTA && <CTAButton />}
147
+ * </>
148
+ * );
149
+ * }
150
+ * ```
151
+ */
152
+ export declare function useCuePoints(cuePoints: Array<{
153
+ /** Time in seconds when to trigger */
154
+ time: number;
155
+ /** Callback to execute when time is reached */
156
+ onTrigger: () => void;
157
+ /** Optional unique ID (defaults to index) */
158
+ id?: string;
159
+ }>, options?: {
160
+ /** Reset triggers when video loops (default: true) */
161
+ resetOnLoop?: boolean;
162
+ }): void;
163
+ /**
164
+ * Hook to get the current video progress as a percentage (0-100).
165
+ * Useful for progress bars or time-based animations.
166
+ *
167
+ * @returns Progress percentage (0-100)
168
+ *
169
+ * @example
170
+ * ```tsx
171
+ * function ProgressBar() {
172
+ * const progress = useVideoProgress();
173
+ * return <div style={{ width: `${progress}%` }} className="h-1 bg-white" />;
174
+ * }
175
+ * ```
176
+ */
177
+ export declare function useVideoProgress(): number;
82
178
  export {};
83
179
  //# sourceMappingURL=VideoPlayer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"VideoPlayer.d.ts","sourceRoot":"","sources":["../../../src/react/overlay/VideoPlayer.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"VideoPlayer.d.ts","sourceRoot":"","sources":["../../../src/react/overlay/VideoPlayer.tsx"],"names":[],"mappings":"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"}
@@ -1,13 +1,30 @@
1
1
  'use client';
2
2
  import React, { createContext, useContext, useEffect, useRef, useState, useCallback, } from 'react';
3
+ import { getTileBridge } from '../../bridge/TileBridge';
3
4
  const VideoContext = createContext(null);
5
+ // Detect if we're in preview mode (tile-preview sets this global)
6
+ function isPreviewMode() {
7
+ if (typeof window === 'undefined')
8
+ return false;
9
+ return !!window.__PREVIEW_SESSION_ID__;
10
+ }
4
11
  /**
5
12
  * VideoPlayer component with HLS streaming support.
6
13
  * Provides video state and controls to child overlays via context.
14
+ *
15
+ * Features:
16
+ * - HLS streaming with automatic quality adaptation
17
+ * - Time-based cue points for triggering overlays
18
+ * - Visibility-aware playback (plays when visible, pauses when hidden)
19
+ * - Auto-loops in preview mode for testing
7
20
  */
8
- export function VideoPlayer({ src, autoplay = true, loop = false, muted = true, poster, controls = false, children, className = '', videoClassName = '', }) {
21
+ export function VideoPlayer({ src, autoplay = true, loop: loopProp, muted = true, poster, controls = false, children, className = '', videoClassName = '', cuePoints = [], onCuePoint, onTimeUpdate, }) {
9
22
  const videoRef = useRef(null);
10
23
  const hlsRef = useRef(null);
24
+ const triggeredCuePointsRef = useRef(new Set());
25
+ const lastTimeRef = useRef(0);
26
+ // Auto-enable loop in preview mode unless explicitly set to false
27
+ const loop = loopProp ?? isPreviewMode();
11
28
  const [state, setState] = useState({
12
29
  isPlaying: false,
13
30
  currentTime: 0,
@@ -126,7 +143,35 @@ export function VideoPlayer({ src, autoplay = true, loop = false, muted = true,
126
143
  return;
127
144
  const handlePlay = () => setState(s => ({ ...s, isPlaying: true }));
128
145
  const handlePause = () => setState(s => ({ ...s, isPlaying: false }));
129
- const handleTimeUpdate = () => setState(s => ({ ...s, currentTime: video.currentTime }));
146
+ const handleTimeUpdate = () => {
147
+ const currentTime = video.currentTime;
148
+ const duration = video.duration;
149
+ setState(s => ({ ...s, currentTime }));
150
+ // Call onTimeUpdate callback
151
+ if (onTimeUpdate && !isNaN(duration)) {
152
+ onTimeUpdate(currentTime, duration);
153
+ }
154
+ // Check cue points - trigger if we crossed the cue time since last update
155
+ if (onCuePoint && cuePoints.length > 0) {
156
+ const lastTime = lastTimeRef.current;
157
+ for (const cuePoint of cuePoints) {
158
+ const cueKey = `${cuePoint.id}-${Math.floor(currentTime / (duration || 1))}`;
159
+ // Trigger if we crossed the cue point time (handles both forward and loop)
160
+ // For looping: reset triggered cues when video loops back
161
+ if (currentTime < lastTime && lastTime > duration * 0.9) {
162
+ // Video looped - clear triggered cues
163
+ triggeredCuePointsRef.current.clear();
164
+ }
165
+ const alreadyTriggered = triggeredCuePointsRef.current.has(cueKey);
166
+ const crossedCuePoint = lastTime < cuePoint.time && currentTime >= cuePoint.time;
167
+ if (!alreadyTriggered && crossedCuePoint) {
168
+ triggeredCuePointsRef.current.add(cueKey);
169
+ onCuePoint(cuePoint);
170
+ }
171
+ }
172
+ }
173
+ lastTimeRef.current = currentTime;
174
+ };
130
175
  const handleDurationChange = () => setState(s => ({ ...s, duration: video.duration }));
131
176
  const handleVolumeChange = () => setState(s => ({ ...s, volume: video.volume, muted: video.muted }));
132
177
  const handleProgress = () => {
@@ -154,7 +199,40 @@ export function VideoPlayer({ src, autoplay = true, loop = false, muted = true,
154
199
  video.removeEventListener('progress', handleProgress);
155
200
  video.removeEventListener('error', handleError);
156
201
  };
157
- }, []);
202
+ }, [onTimeUpdate, onCuePoint, cuePoints]);
203
+ // Visibility handling - play/pause based on tile visibility
204
+ // Enables TikTok-style preloaded video tiles that only play when visible
205
+ useEffect(() => {
206
+ const video = videoRef.current;
207
+ if (!video || !autoplay)
208
+ return;
209
+ try {
210
+ const bridge = getTileBridge();
211
+ // Handle visibility changes from parent (mobile app)
212
+ const unsubscribe = bridge.onVisibilityChange((visibilityState) => {
213
+ if (visibilityState.visible) {
214
+ // Tile became visible - play the video
215
+ video.play().catch(() => { });
216
+ }
217
+ else {
218
+ // Tile became hidden - pause the video
219
+ video.pause();
220
+ }
221
+ });
222
+ // Check initial visibility state
223
+ if (!bridge.isVisible()) {
224
+ // If not visible on mount, pause any autoplay
225
+ video.pause();
226
+ }
227
+ return () => {
228
+ unsubscribe();
229
+ };
230
+ }
231
+ catch {
232
+ // Bridge not available (e.g., in SSR or outside TileProvider)
233
+ // Video will just use autoplay behavior
234
+ }
235
+ }, [autoplay]);
158
236
  const contextValue = {
159
237
  state,
160
238
  controls: { play, pause, toggle, seek, setVolume, setMuted },
@@ -179,3 +257,116 @@ export function useVideoState() {
179
257
  }
180
258
  return context;
181
259
  }
260
+ /**
261
+ * Hook to trigger an action when a specific time is reached.
262
+ * Returns true when the video has reached or passed the specified time.
263
+ *
264
+ * @param triggerTime - Time in seconds when to trigger
265
+ * @param options - Configuration options
266
+ * @returns boolean indicating if the trigger time has been reached
267
+ *
268
+ * @example
269
+ * ```tsx
270
+ * function PollOverlay() {
271
+ * const showPoll = useCuePoint(5); // Show after 5 seconds
272
+ * return showPoll ? <Poll /> : null;
273
+ * }
274
+ * ```
275
+ */
276
+ export function useCuePoint(triggerTime, options = {}) {
277
+ const { resetOnLoop = true, mode = 'once' } = options;
278
+ const { state } = useVideoState();
279
+ const [triggered, setTriggered] = useState(false);
280
+ const lastTimeRef = useRef(0);
281
+ useEffect(() => {
282
+ const { currentTime, duration } = state;
283
+ // Detect video loop (time jumped backwards significantly)
284
+ if (currentTime < lastTimeRef.current && lastTimeRef.current > duration * 0.9) {
285
+ if (resetOnLoop && mode === 'every-loop') {
286
+ setTriggered(false);
287
+ }
288
+ }
289
+ // Check if we crossed the trigger time
290
+ if (!triggered && currentTime >= triggerTime) {
291
+ setTriggered(true);
292
+ }
293
+ lastTimeRef.current = currentTime;
294
+ }, [state.currentTime, state.duration, triggerTime, triggered, resetOnLoop, mode]);
295
+ return triggered;
296
+ }
297
+ /**
298
+ * Hook to manage multiple cue points with callbacks.
299
+ * More flexible than useCuePoint for complex time-based interactions.
300
+ *
301
+ * @param cuePoints - Array of cue points with times and callbacks
302
+ * @param options - Configuration options
303
+ *
304
+ * @example
305
+ * ```tsx
306
+ * function InteractiveOverlay() {
307
+ * const [showPoll, setShowPoll] = useState(false);
308
+ * const [showCTA, setShowCTA] = useState(false);
309
+ *
310
+ * useCuePoints([
311
+ * { time: 5, onTrigger: () => setShowPoll(true) },
312
+ * { time: 10, onTrigger: () => setShowCTA(true) },
313
+ * { time: 15, onTrigger: () => { setShowPoll(false); setShowCTA(false); } },
314
+ * ]);
315
+ *
316
+ * return (
317
+ * <>
318
+ * {showPoll && <Poll />}
319
+ * {showCTA && <CTAButton />}
320
+ * </>
321
+ * );
322
+ * }
323
+ * ```
324
+ */
325
+ export function useCuePoints(cuePoints, options = {}) {
326
+ const { resetOnLoop = true } = options;
327
+ const { state } = useVideoState();
328
+ const triggeredRef = useRef(new Set());
329
+ const lastTimeRef = useRef(0);
330
+ useEffect(() => {
331
+ const { currentTime, duration } = state;
332
+ // Detect video loop
333
+ if (currentTime < lastTimeRef.current && lastTimeRef.current > duration * 0.9) {
334
+ if (resetOnLoop) {
335
+ triggeredRef.current.clear();
336
+ }
337
+ }
338
+ // Check each cue point
339
+ for (let i = 0; i < cuePoints.length; i++) {
340
+ const cue = cuePoints[i];
341
+ const cueId = cue.id ?? `cue-${i}`;
342
+ const alreadyTriggered = triggeredRef.current.has(cueId);
343
+ const crossedTime = lastTimeRef.current < cue.time && currentTime >= cue.time;
344
+ if (!alreadyTriggered && crossedTime) {
345
+ triggeredRef.current.add(cueId);
346
+ cue.onTrigger();
347
+ }
348
+ }
349
+ lastTimeRef.current = currentTime;
350
+ }, [state.currentTime, state.duration, cuePoints, resetOnLoop]);
351
+ }
352
+ /**
353
+ * Hook to get the current video progress as a percentage (0-100).
354
+ * Useful for progress bars or time-based animations.
355
+ *
356
+ * @returns Progress percentage (0-100)
357
+ *
358
+ * @example
359
+ * ```tsx
360
+ * function ProgressBar() {
361
+ * const progress = useVideoProgress();
362
+ * return <div style={{ width: `${progress}%` }} className="h-1 bg-white" />;
363
+ * }
364
+ * ```
365
+ */
366
+ export function useVideoProgress() {
367
+ const { state } = useVideoState();
368
+ const { currentTime, duration } = state;
369
+ if (!duration || duration === 0)
370
+ return 0;
371
+ return Math.min(100, (currentTime / duration) * 100);
372
+ }
@@ -1,5 +1,5 @@
1
- export { VideoPlayer, useVideoState, } from './VideoPlayer';
2
- export type { VideoState, VideoControls, VideoContextValue, VideoPlayerProps, } from './VideoPlayer';
1
+ export { VideoPlayer, useVideoState, useCuePoint, useCuePoints, useVideoProgress, } from './VideoPlayer';
2
+ export type { VideoState, VideoControls, VideoContextValue, VideoPlayerProps, CuePoint, } from './VideoPlayer';
3
3
  export { Slideshow, useSlideshowState, } from './Slideshow';
4
4
  export type { SlideImage, SlideshowState, SlideshowControls, SlideshowContextValue, SlideshowProps, } from './Slideshow';
5
5
  export { OverlaySlot, FullOverlay, GradientOverlay, } from './OverlaySlot';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/react/overlay/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,WAAW,EACX,aAAa,GACd,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,UAAU,EACV,aAAa,EACb,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,SAAS,EACT,iBAAiB,GAClB,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,UAAU,EACV,cAAc,EACd,iBAAiB,EACjB,qBAAqB,EACrB,cAAc,GACf,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,WAAW,EACX,WAAW,EACX,eAAe,GAChB,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/react/overlay/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,WAAW,EACX,aAAa,EACb,WAAW,EACX,YAAY,EACZ,gBAAgB,GACjB,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,UAAU,EACV,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAChB,QAAQ,GACT,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,SAAS,EACT,iBAAiB,GAClB,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,UAAU,EACV,cAAc,EACd,iBAAiB,EACjB,qBAAqB,EACrB,cAAc,GACf,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,WAAW,EACX,WAAW,EACX,eAAe,GAChB,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,eAAe,CAAC"}
@@ -1,5 +1,5 @@
1
1
  // Video player with HLS streaming support
2
- export { VideoPlayer, useVideoState, } from './VideoPlayer';
2
+ export { VideoPlayer, useVideoState, useCuePoint, useCuePoints, useVideoProgress, } from './VideoPlayer';
3
3
  // Image slideshow component
4
4
  export { Slideshow, useSlideshowState, } from './Slideshow';
5
5
  // Overlay positioning components
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thewhateverapp/tile-sdk",
3
- "version": "0.11.1",
3
+ "version": "0.12.0",
4
4
  "description": "SDK for building interactive tiles on The Whatever App platform",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",