@xhub-reel/feed 0.1.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.
@@ -0,0 +1,652 @@
1
+ import * as react from 'react';
2
+ import { CSSProperties, ReactNode, HTMLAttributes, RefObject } from 'react';
3
+ import { Video, XHubReelConfig, VideoFetchParams } from '@xhub-reel/core';
4
+ import * as react_jsx_runtime from 'react/jsx-runtime';
5
+ import { useQueryClient } from '@tanstack/react-query';
6
+ export { UsePreloadOptions, UsePreloadReturn, usePreload } from '@xhub-reel/player';
7
+
8
+ interface VideoFeedProps {
9
+ /** Videos to display */
10
+ videos: Video[];
11
+ /** Initial video index */
12
+ initialIndex?: number;
13
+ /** Called when more videos should be loaded */
14
+ onLoadMore?: () => void | Promise<void>;
15
+ /** Called when the current video changes */
16
+ onVideoChange?: (video: Video, index: number) => void;
17
+ /** Called when a video is liked */
18
+ onLike?: (video: Video) => void;
19
+ /** Called when comments should be shown */
20
+ onComment?: (video: Video) => void;
21
+ /** Called when share sheet should be shown */
22
+ onShare?: (video: Video) => void;
23
+ /** Called when author profile should be shown */
24
+ onAuthorClick?: (video: Video) => void;
25
+ /** Loading state */
26
+ isLoading?: boolean;
27
+ /** Has more videos to load */
28
+ hasMore?: boolean;
29
+ /** Threshold to trigger load more (videos before end) */
30
+ loadMoreThreshold?: number;
31
+ /** Animation duration in ms */
32
+ transitionDuration?: number;
33
+ /** Swipe threshold in pixels */
34
+ swipeThreshold?: number;
35
+ /** Swipe velocity threshold in px/ms */
36
+ velocityThreshold?: number;
37
+ /** Disable swipe gestures */
38
+ gesturesDisabled?: boolean;
39
+ /** Enable haptic feedback on swipe */
40
+ hapticEnabled?: boolean;
41
+ /** Custom styles override */
42
+ style?: CSSProperties;
43
+ /** Custom className (for external CSS if needed) */
44
+ className?: string;
45
+ }
46
+ interface VideoFeedRef {
47
+ slideTo: (index: number, animated?: boolean) => void;
48
+ slideNext: (animated?: boolean) => void;
49
+ slidePrev: (animated?: boolean) => void;
50
+ activeIndex: number;
51
+ totalSlides: number;
52
+ isBeginning: boolean;
53
+ isEnd: boolean;
54
+ }
55
+ declare const VideoFeed: react.ForwardRefExoticComponent<VideoFeedProps & react.RefAttributes<VideoFeedRef>>;
56
+
57
+ /**
58
+ * usePreloader - Feed-specific video preloading layer
59
+ *
60
+ * ARCHITECTURE:
61
+ * This module re-exports core preload functionality from @xhub-reel/player-core
62
+ * and adds FEED-SPECIFIC abstractions:
63
+ * - PreloadPriority type (high/medium/low/metadata/none)
64
+ * - Priority calculation helpers based on video index distance
65
+ *
66
+ * LAYERED DESIGN (Big Tech Pattern):
67
+ * ┌─────────────────────────────────────────┐
68
+ * │ @xhub-reel/feed (Domain Layer) │
69
+ * │ - Feed-specific priority enum │
70
+ * │ - Distance-based priority calculation │
71
+ * └──────────────┬──────────────────────────┘
72
+ * │ re-exports + extends
73
+ * ↓
74
+ * ┌─────────────────────────────────────────┐
75
+ * │ @xhub-reel/player (UI Layer) │
76
+ * │ - Re-exports core + UI components │
77
+ * └──────────────┬──────────────────────────┘
78
+ * │ re-exports
79
+ * ↓
80
+ * ┌─────────────────────────────────────────┐
81
+ * │ @xhub-reel/player-core (Core Layer) │
82
+ * │ - usePreload hook │
83
+ * │ - PreloadManager service │
84
+ * │ - Generic, reusable logic │
85
+ * └─────────────────────────────────────────┘
86
+ *
87
+ * FEED PRELOAD STRATEGY:
88
+ * - Current - 1: Keep in memory, paused
89
+ * - Current: Playing
90
+ * - Current + 1: Pre-load first 3 segments (high)
91
+ * - Current + 2: Pre-load first segment (medium)
92
+ * - Current + 3: Fetch metadata only (low)
93
+ * - Current ± 4+: Dispose (none)
94
+ */
95
+
96
+ /**
97
+ * Priority levels for feed preloading
98
+ */
99
+ type PreloadPriority = 'high' | 'medium' | 'low' | 'metadata' | 'none';
100
+ /**
101
+ * Calculate preload priority based on distance from current video
102
+ *
103
+ * @param index - Video index to check
104
+ * @param currentIndex - Current active video index
105
+ * @returns Numeric priority (1 = highest, 10 = none/dispose)
106
+ */
107
+ declare function getPreloadPriorityForFeed(index: number, currentIndex: number): number;
108
+ /**
109
+ * Map PreloadPriority enum to numeric priority
110
+ *
111
+ * @param priority - Priority enum
112
+ * @returns Numeric priority for PreloadManager
113
+ */
114
+ declare function mapPriorityToNumeric(priority: PreloadPriority): number;
115
+ /**
116
+ * Get PreloadPriority enum based on distance from current
117
+ *
118
+ * @param index - Video index to check
119
+ * @param currentIndex - Current active video index
120
+ * @returns PreloadPriority enum
121
+ */
122
+ declare function getPreloadPriority(index: number, currentIndex: number): PreloadPriority;
123
+
124
+ interface VideoFeedItemProps {
125
+ /** Video data */
126
+ video: Video;
127
+ /** Whether this is the currently active video */
128
+ isActive?: boolean;
129
+ /** Preload priority */
130
+ priority?: PreloadPriority;
131
+ /** Show timeline (default: true, only used with default children) */
132
+ showTimeline?: boolean;
133
+ /** Called when video is liked */
134
+ onLike?: () => void;
135
+ /** Called when comments button is pressed */
136
+ onComment?: () => void;
137
+ /** Called when share button is pressed */
138
+ onShare?: () => void;
139
+ /** Called when author is clicked */
140
+ onAuthorClick?: () => void;
141
+ /** Custom styles override */
142
+ style?: CSSProperties;
143
+ /** Custom className (for external CSS if needed) */
144
+ className?: string;
145
+ /** Custom children for compound component pattern */
146
+ children?: ReactNode;
147
+ }
148
+ /**
149
+ * VideoFeedItem - Root container for video feed items
150
+ *
151
+ * Provides context for all child components.
152
+ * Use with VideoFeedItemPlayer, VideoFeedItemActions, etc.
153
+ */
154
+ declare const VideoFeedItem: react.ForwardRefExoticComponent<VideoFeedItemProps & react.RefAttributes<HTMLDivElement>>;
155
+
156
+ interface VideoFeedItemPlayerProps extends HTMLAttributes<HTMLDivElement> {
157
+ /** Custom placeholder element */
158
+ placeholder?: React.ReactNode;
159
+ }
160
+ declare const VideoFeedItemPlayer: react.ForwardRefExoticComponent<VideoFeedItemPlayerProps & react.RefAttributes<HTMLVideoElement>>;
161
+
162
+ interface VideoFeedItemActionsProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onShare'> {
163
+ /** Override like callback from context */
164
+ onLike?: () => void;
165
+ /** Override comment callback from context */
166
+ onComment?: () => void;
167
+ /** Override share callback from context */
168
+ onShare?: () => void;
169
+ }
170
+ declare const VideoFeedItemActions: react.ForwardRefExoticComponent<VideoFeedItemActionsProps & react.RefAttributes<HTMLDivElement>>;
171
+
172
+ interface VideoFeedItemTimelineProps extends HTMLAttributes<HTMLDivElement> {
173
+ /** Override expanded state */
174
+ expanded?: boolean;
175
+ }
176
+ declare const VideoFeedItemTimeline: react.ForwardRefExoticComponent<VideoFeedItemTimelineProps & react.RefAttributes<HTMLDivElement>>;
177
+
178
+ interface VideoFeedItemOverlayProps extends HTMLAttributes<HTMLDivElement> {
179
+ /** Show play/pause overlay. Default: true */
180
+ showPlayPause?: boolean;
181
+ /** Show heart animation on double tap. Default: true */
182
+ showDoubleTapHeart?: boolean;
183
+ /** Show video info overlay (author, description). Default: true */
184
+ showVideoInfo?: boolean;
185
+ }
186
+ declare const VideoFeedItemOverlay: react.ForwardRefExoticComponent<VideoFeedItemOverlayProps & react.RefAttributes<HTMLDivElement>>;
187
+
188
+ interface VideoFeedItemContextValue {
189
+ video: Video;
190
+ isActive: boolean;
191
+ shouldRenderVideo: boolean;
192
+ preload: '' | 'none' | 'metadata' | 'auto';
193
+ /** Video has been preloaded and first frame is ready */
194
+ isPreloaded: boolean;
195
+ containerRef: RefObject<HTMLDivElement | null>;
196
+ videoRef: RefObject<HTMLVideoElement | null>;
197
+ isPlaying: boolean;
198
+ showPauseOverlay: boolean;
199
+ timelineExpanded: boolean;
200
+ play: () => Promise<void>;
201
+ pause: () => void;
202
+ seek: (time: number) => void;
203
+ setShowPauseOverlay: (show: boolean) => void;
204
+ setTimelineExpanded: (expanded: boolean) => void;
205
+ gestureBindings: () => Record<string, unknown>;
206
+ showHeart: boolean;
207
+ heartPosition: {
208
+ x: number;
209
+ y: number;
210
+ };
211
+ triggerHeart: (x: number, y: number) => void;
212
+ onLike?: () => void;
213
+ onComment?: () => void;
214
+ onShare?: () => void;
215
+ onAuthorClick?: () => void;
216
+ handleSeekStart: () => void;
217
+ handleSeekEnd: (time: number) => void;
218
+ }
219
+ declare function useVideoFeedItemContext(): VideoFeedItemContextValue;
220
+
221
+ interface VideoOverlayProps {
222
+ /** Video data */
223
+ video: Video;
224
+ /** Called when author is clicked */
225
+ onAuthorClick?: () => void;
226
+ /** Whether timeline is expanded (affects bottom padding) */
227
+ timelineExpanded?: boolean;
228
+ /** Custom styles override */
229
+ style?: CSSProperties;
230
+ /** Custom className */
231
+ className?: string;
232
+ }
233
+ declare function VideoOverlay({ video, timelineExpanded, style, className, }: VideoOverlayProps): react_jsx_runtime.JSX.Element;
234
+
235
+ interface ConnectedVideoFeedProps extends Omit<VideoFeedProps, 'videos' | 'isLoading' | 'hasMore' | 'onLoadMore'> {
236
+ /**
237
+ * XHubReelConfig for API connection
238
+ * Optional if wrapped in XHubReelProvider with config
239
+ */
240
+ config?: XHubReelConfig;
241
+ /**
242
+ * User ID for user-specific feed
243
+ */
244
+ userId?: string;
245
+ /**
246
+ * Tag/hashtag filter
247
+ */
248
+ tag?: string;
249
+ /**
250
+ * Search query
251
+ */
252
+ searchQuery?: string;
253
+ /**
254
+ * Number of videos per page
255
+ * @default 10
256
+ */
257
+ pageSize?: number;
258
+ /**
259
+ * Initial videos to show while loading (optional)
260
+ */
261
+ initialVideos?: Video[];
262
+ /**
263
+ * Called when videos are successfully fetched
264
+ */
265
+ onFetchSuccess?: (videos: Video[]) => void;
266
+ /**
267
+ * Called when fetch fails
268
+ */
269
+ onFetchError?: (error: Error) => void;
270
+ /**
271
+ * Render custom loading state
272
+ */
273
+ renderLoading?: () => React.ReactNode;
274
+ /**
275
+ * Render custom error state
276
+ */
277
+ renderError?: (error: Error, retry: () => void) => React.ReactNode;
278
+ /**
279
+ * Render custom empty state
280
+ */
281
+ renderEmpty?: () => React.ReactNode;
282
+ }
283
+ declare const ConnectedVideoFeed: react.ForwardRefExoticComponent<ConnectedVideoFeedProps & react.RefAttributes<VideoFeedRef>>;
284
+
285
+ /**
286
+ * useVideoVisibility - Track video visibility using IntersectionObserver
287
+ */
288
+
289
+ interface UseVideoVisibilityOptions {
290
+ /** Element to observe */
291
+ elementRef: RefObject<HTMLElement | null>;
292
+ /** Threshold to activate (default: 50%) */
293
+ activateThreshold?: number;
294
+ /** Threshold to deactivate (default: 30%) */
295
+ deactivateThreshold?: number;
296
+ /** Root margin */
297
+ rootMargin?: string;
298
+ /** Callback when visibility changes */
299
+ onVisibilityChange?: (isVisible: boolean, ratio: number) => void;
300
+ }
301
+ interface UseVideoVisibilityReturn {
302
+ isVisible: boolean;
303
+ isActive: boolean;
304
+ visibilityRatio: number;
305
+ }
306
+ declare function useVideoVisibility({ elementRef, activateThreshold, deactivateThreshold, rootMargin, onVisibilityChange, }: UseVideoVisibilityOptions): UseVideoVisibilityReturn;
307
+
308
+ /**
309
+ * useVideoActivation - Control video play/pause based on isCurrentVideo prop
310
+ *
311
+ * For carousel/swipe feeds: Uses index-based activation from VideoFeed (no IntersectionObserver)
312
+ * For scroll feeds: Enable `trackVisibility` to get viewport-based analytics
313
+ *
314
+ * Note: For infinite scroll loading, use `useInfiniteScroll` instead.
315
+ * For standalone visibility tracking, use `useVideoVisibility` directly.
316
+ */
317
+
318
+ interface UseVideoActivationOptions {
319
+ /** Video container element ref (required if trackVisibility is true) */
320
+ containerRef?: RefObject<HTMLElement | null>;
321
+ /** Video element ref */
322
+ videoRef: RefObject<HTMLVideoElement | null>;
323
+ /** Whether this video is the current active one (from parent feed) */
324
+ isCurrentVideo?: boolean;
325
+ /** Callback when video should activate */
326
+ onActivate?: () => void;
327
+ /** Callback when video should deactivate */
328
+ onDeactivate?: () => void;
329
+ /** Whether auto-activation is enabled */
330
+ autoActivate?: boolean;
331
+ /**
332
+ * Enable visibility tracking via IntersectionObserver
333
+ * Use this for:
334
+ * - Analytics (track how much of video is visible)
335
+ * - Scroll-based feeds (non-carousel)
336
+ * - Lazy loading based on viewport
337
+ * Default: false (carousel mode)
338
+ */
339
+ trackVisibility?: boolean;
340
+ /** Callback for visibility changes (requires trackVisibility: true) */
341
+ onVisibilityChange?: (isVisible: boolean, ratio: number) => void;
342
+ }
343
+ interface UseVideoActivationReturn {
344
+ /** Whether this video is currently active */
345
+ isActive: boolean;
346
+ /** Whether video is visible in viewport (only when trackVisibility: true) */
347
+ isVisible: boolean;
348
+ /** Visibility ratio 0-1 (only when trackVisibility: true) */
349
+ visibilityRatio: number;
350
+ /** Manually activate the video */
351
+ activate: () => void;
352
+ /** Manually deactivate the video */
353
+ deactivate: () => void;
354
+ }
355
+ declare function useVideoActivation({ containerRef, videoRef, isCurrentVideo, onActivate, onDeactivate, autoActivate, trackVisibility, onVisibilityChange, }: UseVideoActivationOptions): UseVideoActivationReturn;
356
+
357
+ /**
358
+ * Memory Manager - Control memory usage for video feed
359
+ *
360
+ * Limits:
361
+ * - Max 5 videos in DOM
362
+ * - Max 3 videos with decoded frames
363
+ * - Total memory cap 150MB
364
+ */
365
+ interface MemoryState {
366
+ videosInDom: number;
367
+ decodedVideos: number;
368
+ estimatedMemoryMB: number;
369
+ isLowMemory: boolean;
370
+ }
371
+ interface VideoMemoryEntry {
372
+ videoId: string;
373
+ inDom: boolean;
374
+ hasDecodedFrames: boolean;
375
+ estimatedSizeMB: number;
376
+ lastAccessed: number;
377
+ }
378
+ declare class MemoryManager {
379
+ private entries;
380
+ private listeners;
381
+ private memoryWarningThreshold;
382
+ constructor();
383
+ /**
384
+ * Register a video
385
+ */
386
+ register(videoId: string, estimatedSizeMB?: number): void;
387
+ /**
388
+ * Unregister a video
389
+ */
390
+ unregister(videoId: string): void;
391
+ /**
392
+ * Mark video as in DOM
393
+ */
394
+ setInDom(videoId: string, inDom: boolean): void;
395
+ /**
396
+ * Mark video as having decoded frames
397
+ */
398
+ setHasDecodedFrames(videoId: string, hasFrames: boolean): void;
399
+ /**
400
+ * Get current memory state
401
+ */
402
+ getState(): MemoryState;
403
+ /**
404
+ * Get videos that should be disposed (LRU)
405
+ */
406
+ getVideosToDispose(): string[];
407
+ /**
408
+ * Subscribe to memory state changes
409
+ */
410
+ subscribe(listener: (state: MemoryState) => void): () => void;
411
+ /**
412
+ * Force cleanup
413
+ */
414
+ forceCleanup(): string[];
415
+ private notifyListeners;
416
+ private setupMemoryPressureListener;
417
+ }
418
+ declare const memoryManager: MemoryManager;
419
+
420
+ /**
421
+ * useMemoryManager - Hook for memory management in feed
422
+ */
423
+
424
+ interface UseMemoryManagerOptions {
425
+ /** Video ID to track */
426
+ videoId: string;
427
+ /** Estimated video size in MB */
428
+ estimatedSizeMB?: number;
429
+ /** Callback when video should be disposed due to memory pressure */
430
+ onShouldDispose?: () => void;
431
+ }
432
+ interface UseMemoryManagerReturn {
433
+ memoryState: MemoryState;
434
+ setInDom: (inDom: boolean) => void;
435
+ setHasDecodedFrames: (hasFrames: boolean) => void;
436
+ shouldDispose: boolean;
437
+ }
438
+ declare function useMemoryManager({ videoId, estimatedSizeMB, onShouldDispose, }: UseMemoryManagerOptions): UseMemoryManagerReturn;
439
+ /**
440
+ * useGlobalMemoryState - Get global memory state without tracking a specific video
441
+ */
442
+ declare function useGlobalMemoryState(): MemoryState;
443
+
444
+ /**
445
+ * useFeedScroll - Scroll management hook with snap behavior
446
+ */
447
+
448
+ interface UseFeedScrollOptions {
449
+ /** Scroll container ref */
450
+ scrollRef: RefObject<HTMLElement | null>;
451
+ /** Total number of items */
452
+ itemCount: number;
453
+ /** Height of each item (default: viewport height) */
454
+ itemHeight?: number;
455
+ /** Callback when scroll position changes */
456
+ onScrollChange?: (scrollTop: number, velocity: number) => void;
457
+ /** Callback when current index changes */
458
+ onIndexChange?: (index: number) => void;
459
+ }
460
+ interface UseFeedScrollReturn {
461
+ currentIndex: number;
462
+ scrollVelocity: number;
463
+ isScrolling: boolean;
464
+ scrollToIndex: (index: number, smooth?: boolean) => void;
465
+ scrollToNext: () => void;
466
+ scrollToPrev: () => void;
467
+ }
468
+ declare function useFeedScroll({ scrollRef, itemCount, itemHeight, onScrollChange, onIndexChange, }: UseFeedScrollOptions): UseFeedScrollReturn;
469
+
470
+ /**
471
+ * useInfiniteScroll - Hook for infinite scroll loading
472
+ */
473
+ interface UseInfiniteScrollOptions {
474
+ /** Called when more content should be loaded */
475
+ onLoadMore?: () => void | Promise<void>;
476
+ /** Whether currently loading */
477
+ isLoading?: boolean;
478
+ /** Whether there's more content to load */
479
+ hasMore?: boolean;
480
+ /** Number of items from end to trigger load */
481
+ threshold?: number;
482
+ /** Root margin for intersection observer */
483
+ rootMargin?: string;
484
+ }
485
+ interface UseInfiniteScrollReturn {
486
+ /** Ref to attach to sentinel element */
487
+ sentinelRef: (element: HTMLElement | null) => void;
488
+ /** Whether currently in loading state */
489
+ isLoadingMore: boolean;
490
+ }
491
+ declare function useInfiniteScroll({ onLoadMore, isLoading, hasMore, threshold: _threshold, rootMargin, }: UseInfiniteScrollOptions): UseInfiniteScrollReturn;
492
+
493
+ /**
494
+ * useVideoFeed - Hook for fetching videos from API with infinite scroll support
495
+ *
496
+ * Uses XHubReelProvider config to fetch videos. Falls back to manual mode if no config.
497
+ *
498
+ * @example
499
+ * ```tsx
500
+ * // API Mode (requires XHubReelProvider with config)
501
+ * function FeedPage() {
502
+ * const {
503
+ * videos,
504
+ * isLoading,
505
+ * hasMore,
506
+ * fetchNextPage,
507
+ * error,
508
+ * } = useVideoFeed()
509
+ *
510
+ * return <VideoFeed videos={videos} onLoadMore={fetchNextPage} />
511
+ * }
512
+ *
513
+ * // Manual Mode (pass videos directly)
514
+ * function FeedPage() {
515
+ * const localVideos = [...]
516
+ * return <VideoFeed videos={localVideos} />
517
+ * }
518
+ * ```
519
+ */
520
+
521
+ interface UseVideoFeedOptions {
522
+ /**
523
+ * XHubReelConfig - required for API mode
524
+ * If not provided, the hook returns empty data (use manual mode)
525
+ */
526
+ config?: XHubReelConfig;
527
+ /**
528
+ * Enable/disable the query (default: true)
529
+ */
530
+ enabled?: boolean;
531
+ /**
532
+ * Initial videos to show while loading
533
+ */
534
+ initialVideos?: Video[];
535
+ /**
536
+ * Stale time in ms (default: 5 minutes)
537
+ */
538
+ staleTime?: number;
539
+ /**
540
+ * Refetch on window focus (default: false)
541
+ */
542
+ refetchOnWindowFocus?: boolean;
543
+ /**
544
+ * Callback when videos are fetched
545
+ */
546
+ onSuccess?: (videos: Video[]) => void;
547
+ /**
548
+ * Callback on error
549
+ */
550
+ onError?: (error: Error) => void;
551
+ /** User ID filter */
552
+ userId?: string;
553
+ /** Tag/hashtag filter */
554
+ tag?: string;
555
+ /** Search query */
556
+ searchQuery?: string;
557
+ /** Number of videos per page */
558
+ limit?: number;
559
+ /** Pagination cursor */
560
+ cursor?: string;
561
+ }
562
+ interface UseVideoFeedReturn {
563
+ /** Flattened array of all fetched videos */
564
+ videos: Video[];
565
+ /** Loading state for initial fetch */
566
+ isLoading: boolean;
567
+ /** Loading state for fetching more */
568
+ isFetchingMore: boolean;
569
+ /** Whether there are more videos to load */
570
+ hasMore: boolean;
571
+ /** Fetch next page of videos */
572
+ fetchNextPage: () => Promise<void>;
573
+ /** Refetch all videos */
574
+ refetch: () => Promise<void>;
575
+ /** Error if any */
576
+ error: Error | null;
577
+ /** Whether API mode is active */
578
+ isApiMode: boolean;
579
+ /** Total count of videos (if provided by API) */
580
+ totalCount?: number;
581
+ }
582
+ /**
583
+ * useVideoFeed - Fetch videos with infinite scroll support
584
+ */
585
+ declare function useVideoFeed(options?: UseVideoFeedOptions): UseVideoFeedReturn;
586
+ /**
587
+ * Prefetch videos for a feed type
588
+ * Call this in a Server Component or before navigation to pre-warm cache
589
+ *
590
+ * @example
591
+ * ```tsx
592
+ * // In a page component
593
+ * export async function generateStaticParams() {
594
+ * const queryClient = new QueryClient()
595
+ * await prefetchVideoFeed(queryClient, config)
596
+ * return { props: { dehydratedState: dehydrate(queryClient) } }
597
+ * }
598
+ * ```
599
+ */
600
+ declare function prefetchVideoFeed(queryClient: ReturnType<typeof useQueryClient>, config: XHubReelConfig, params?: VideoFetchParams): Promise<void>;
601
+
602
+ /**
603
+ * useSwipeAnimation - High-performance swipe animation hook
604
+ *
605
+ * Features:
606
+ * - Direct DOM manipulation (bypasses React re-renders)
607
+ * - RAF batching (max 1 update per frame)
608
+ * - Cached viewport height (no layout thrashing)
609
+ * - transitionend event (no setTimeout race conditions)
610
+ * - Design system easing curve
611
+ *
612
+ * @example
613
+ * ```tsx
614
+ * const { setTranslateY, animateTo, snapBack, viewportHeight } = useSwipeAnimation({
615
+ * trackRef,
616
+ * transitionDuration: 300,
617
+ * })
618
+ *
619
+ * // During swipe (hot path - no React re-render)
620
+ * setTranslateY(movement)
621
+ *
622
+ * // Complete swipe with animation
623
+ * await animateTo(-viewportHeight)
624
+ * ```
625
+ */
626
+ interface UseSwipeAnimationOptions {
627
+ /** Ref to the track element that will be animated */
628
+ trackRef: React.RefObject<HTMLDivElement | null>;
629
+ /** Transition duration in ms. Default: 300 */
630
+ transitionDuration?: number;
631
+ /** CSS easing function. Default: design system spring */
632
+ easing?: string;
633
+ /** Called when any transition completes */
634
+ onTransitionEnd?: () => void;
635
+ }
636
+ interface UseSwipeAnimationReturn {
637
+ /** Set translateY directly (no React, RAF batched) - use during swipe */
638
+ setTranslateY: (y: number) => void;
639
+ /** Animate to target Y with CSS transition - returns Promise */
640
+ animateTo: (y: number) => Promise<void>;
641
+ /** Snap back to 0 with transition */
642
+ snapBack: () => Promise<void>;
643
+ /** Get current translateY value (sync, no DOM read) */
644
+ getCurrentY: () => number;
645
+ /** Cached viewport height - use this instead of window.innerHeight */
646
+ viewportHeight: number;
647
+ /** Whether currently animating */
648
+ isAnimating: boolean;
649
+ }
650
+ declare function useSwipeAnimation({ trackRef, transitionDuration, easing, onTransitionEnd, }: UseSwipeAnimationOptions): UseSwipeAnimationReturn;
651
+
652
+ export { ConnectedVideoFeed, type ConnectedVideoFeedProps, type MemoryState, type PreloadPriority, type UseFeedScrollOptions, type UseFeedScrollReturn, type UseInfiniteScrollOptions, type UseInfiniteScrollReturn, type UseMemoryManagerOptions, type UseMemoryManagerReturn, type UseSwipeAnimationOptions, type UseSwipeAnimationReturn, type UseVideoActivationOptions, type UseVideoActivationReturn, type UseVideoFeedOptions, type UseVideoFeedReturn, type UseVideoVisibilityOptions, type UseVideoVisibilityReturn, VideoFeed, VideoFeedItem, VideoFeedItemActions, type VideoFeedItemActionsProps, type VideoFeedItemContextValue, VideoFeedItemOverlay, type VideoFeedItemOverlayProps, VideoFeedItemPlayer, type VideoFeedItemPlayerProps, type VideoFeedItemProps, VideoFeedItemTimeline, type VideoFeedItemTimelineProps, type VideoFeedProps, type VideoFeedRef, type VideoMemoryEntry, VideoOverlay, type VideoOverlayProps, getPreloadPriority, getPreloadPriorityForFeed, mapPriorityToNumeric, memoryManager, prefetchVideoFeed, useFeedScroll, useGlobalMemoryState, useInfiniteScroll, useMemoryManager, useSwipeAnimation, useVideoActivation, useVideoFeed, useVideoFeedItemContext, useVideoVisibility };