@shortkitsdk/react-native 0.2.0 → 0.2.2

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.
Files changed (34) hide show
  1. package/android/src/main/java/com/shortkit/reactnative/ShortKitCarouselOverlayBridge.kt +48 -0
  2. package/android/src/main/java/com/shortkit/reactnative/ShortKitFeedView.kt +48 -6
  3. package/android/src/main/java/com/shortkit/reactnative/ShortKitModule.kt +180 -2
  4. package/android/src/main/java/com/shortkit/reactnative/ShortKitOverlayBridge.kt +28 -1
  5. package/android/src/main/java/com/shortkit/reactnative/ShortKitPackage.kt +5 -1
  6. package/android/src/main/java/com/shortkit/reactnative/ShortKitPlayerNativeView.kt +136 -0
  7. package/android/src/main/java/com/shortkit/reactnative/ShortKitPlayerViewManager.kt +35 -0
  8. package/android/src/main/java/com/shortkit/reactnative/ShortKitWidgetNativeView.kt +133 -0
  9. package/android/src/main/java/com/shortkit/reactnative/ShortKitWidgetViewManager.kt +30 -0
  10. package/ios/ShortKitBridge.swift +134 -2
  11. package/ios/ShortKitCarouselOverlayBridge.swift +54 -0
  12. package/ios/ShortKitFeedView.swift +46 -7
  13. package/ios/ShortKitModule.mm +42 -0
  14. package/ios/ShortKitOverlayBridge.swift +23 -1
  15. package/ios/ShortKitPlayerNativeView.swift +186 -0
  16. package/ios/ShortKitPlayerNativeViewManager.mm +28 -0
  17. package/ios/ShortKitWidgetNativeView.swift +168 -0
  18. package/ios/ShortKitWidgetNativeViewManager.mm +27 -0
  19. package/package.json +1 -1
  20. package/src/CarouselOverlayManager.tsx +71 -0
  21. package/src/ShortKitContext.ts +18 -0
  22. package/src/ShortKitFeed.tsx +13 -0
  23. package/src/ShortKitPlayer.tsx +61 -0
  24. package/src/ShortKitProvider.tsx +161 -2
  25. package/src/ShortKitWidget.tsx +63 -0
  26. package/src/index.ts +15 -1
  27. package/src/serialization.ts +16 -2
  28. package/src/specs/NativeShortKitModule.ts +37 -0
  29. package/src/specs/ShortKitPlayerViewNativeComponent.ts +13 -0
  30. package/src/specs/ShortKitWidgetViewNativeComponent.ts +12 -0
  31. package/src/types.ts +82 -3
  32. package/src/useShortKit.ts +5 -1
  33. package/src/useShortKitCarousel.ts +29 -0
  34. package/src/useShortKitPlayer.ts +10 -2
@@ -6,6 +6,8 @@ import type { ShortKitContextValue } from './ShortKitContext';
6
6
  import type {
7
7
  ShortKitProviderProps,
8
8
  ContentItem,
9
+ ImageCarouselItem,
10
+ CustomFeedItem,
9
11
  PlayerTime,
10
12
  PlayerState,
11
13
  CaptionTrack,
@@ -13,6 +15,7 @@ import type {
13
15
  } from './types';
14
16
  import {
15
17
  serializeFeedConfigForModule,
18
+ serializeCustomFeedItems,
16
19
  deserializePlayerState,
17
20
  deserializeContentItem,
18
21
  deserializePlayerTime,
@@ -34,10 +37,16 @@ interface State {
34
37
  activeCaptionTrack: CaptionTrack | null;
35
38
  activeCue: { text: string; startTime: number; endTime: number } | null;
36
39
  prefetchedAheadCount: number;
40
+ remainingContentCount: number;
37
41
  isActive: boolean;
38
42
  isTransitioning: boolean;
39
43
  lastOverlayTap: number;
40
44
  lastOverlayDoubleTap: { x: number; y: number; id: number } | null;
45
+ currentCarouselItem: ImageCarouselItem | null;
46
+ nextCarouselItem: ImageCarouselItem | null;
47
+ isCarouselActive: boolean;
48
+ isCarouselTransitioning: boolean;
49
+ activeCellType: 'video' | 'carousel' | null;
41
50
  }
42
51
 
43
52
  const initialState: State = {
@@ -51,10 +60,16 @@ const initialState: State = {
51
60
  activeCaptionTrack: null,
52
61
  activeCue: null,
53
62
  prefetchedAheadCount: 0,
63
+ remainingContentCount: 0,
54
64
  isActive: false,
55
65
  isTransitioning: false,
56
66
  lastOverlayTap: 0,
57
67
  lastOverlayDoubleTap: null,
68
+ currentCarouselItem: null,
69
+ nextCarouselItem: null,
70
+ isCarouselActive: false,
71
+ isCarouselTransitioning: false,
72
+ activeCellType: null,
58
73
  };
59
74
 
60
75
  type Action =
@@ -67,13 +82,20 @@ type Action =
67
82
  | { type: 'CAPTION_TRACK'; payload: CaptionTrack | null }
68
83
  | { type: 'CUE'; payload: { text: string; startTime: number; endTime: number } | null }
69
84
  | { type: 'PREFETCH_COUNT'; payload: number }
85
+ | { type: 'REMAINING_COUNT'; payload: number }
70
86
  | { type: 'OVERLAY_CONFIGURE'; payload: ContentItem }
71
87
  | { type: 'OVERLAY_ACTIVATE'; payload: ContentItem }
72
88
  | { type: 'OVERLAY_RESET' }
73
89
  | { type: 'OVERLAY_FADE_OUT' }
74
90
  | { type: 'OVERLAY_RESTORE' }
75
91
  | { type: 'OVERLAY_TAP' }
76
- | { type: 'OVERLAY_DOUBLE_TAP'; payload: { x: number; y: number } };
92
+ | { type: 'OVERLAY_DOUBLE_TAP'; payload: { x: number; y: number } }
93
+ | { type: 'ACTIVE_CELL_TYPE'; payload: 'video' | 'carousel' }
94
+ | { type: 'CAROUSEL_OVERLAY_CONFIGURE'; payload: ImageCarouselItem }
95
+ | { type: 'CAROUSEL_OVERLAY_ACTIVATE'; payload: ImageCarouselItem }
96
+ | { type: 'CAROUSEL_OVERLAY_RESET' }
97
+ | { type: 'CAROUSEL_OVERLAY_FADE_OUT' }
98
+ | { type: 'CAROUSEL_OVERLAY_RESTORE' };
77
99
 
78
100
  function reducer(state: State, action: Action): State {
79
101
  switch (action.type) {
@@ -86,10 +108,13 @@ function reducer(state: State, action: Action): State {
86
108
  action.payload === 'paused' ||
87
109
  action.payload === 'buffering' ||
88
110
  action.payload === 'seeking';
111
+ const becameActive = !state.isActive && isPlaybackActive;
89
112
  return {
90
113
  ...state,
91
114
  playerState: action.payload,
92
115
  isActive: state.isActive || isPlaybackActive,
116
+ // First playback means a video cell is active (initial load)
117
+ activeCellType: becameActive ? 'video' : state.activeCellType,
93
118
  };
94
119
  }
95
120
  case 'CURRENT_ITEM':
@@ -108,10 +133,25 @@ function reducer(state: State, action: Action): State {
108
133
  return { ...state, activeCue: action.payload };
109
134
  case 'PREFETCH_COUNT':
110
135
  return { ...state, prefetchedAheadCount: action.payload };
136
+ case 'REMAINING_COUNT':
137
+ return { ...state, remainingContentCount: action.payload };
111
138
  case 'OVERLAY_CONFIGURE':
112
139
  return { ...state, nextItem: action.payload };
113
140
  case 'OVERLAY_ACTIVATE':
114
- return { ...state, currentItem: action.payload, isActive: true };
141
+ // Reset time/cue/transition state to prevent stale playback data from
142
+ // the previous cell flashing on the new cell's overlay.
143
+ // Note: nextItem is NOT cleared here — the native-side deferred-configure
144
+ // (ShortKitOverlayBridge) already prevents handleSwipe from polluting it.
145
+ // Clearing it would cause overlay-next to unmount its content ~80ms before
146
+ // the page settle swaps overlays, creating a visible dim-layer gap.
147
+ return {
148
+ ...state,
149
+ currentItem: action.payload,
150
+ isActive: true,
151
+ time: { current: 0, duration: action.payload.duration, buffered: 0 },
152
+ activeCue: null,
153
+ isTransitioning: false,
154
+ };
115
155
  case 'OVERLAY_RESET':
116
156
  // Don't set isActive = false — the overlay stays mounted during
117
157
  // transitions. In the native SDK each cell has its own overlay
@@ -133,6 +173,18 @@ function reducer(state: State, action: Action): State {
133
173
  id: (state.lastOverlayDoubleTap?.id ?? 0) + 1,
134
174
  },
135
175
  };
176
+ case 'ACTIVE_CELL_TYPE':
177
+ return { ...state, activeCellType: action.payload };
178
+ case 'CAROUSEL_OVERLAY_CONFIGURE':
179
+ return { ...state, nextCarouselItem: action.payload };
180
+ case 'CAROUSEL_OVERLAY_ACTIVATE':
181
+ return { ...state, currentCarouselItem: action.payload, isCarouselActive: true };
182
+ case 'CAROUSEL_OVERLAY_RESET':
183
+ return { ...state, isCarouselTransitioning: false };
184
+ case 'CAROUSEL_OVERLAY_FADE_OUT':
185
+ return { ...state, isCarouselTransitioning: true };
186
+ case 'CAROUSEL_OVERLAY_RESTORE':
187
+ return { ...state, isCarouselTransitioning: false };
136
188
  default:
137
189
  return state;
138
190
  }
@@ -145,6 +197,7 @@ function reducer(state: State, action: Action): State {
145
197
  export function ShortKitProvider({
146
198
  apiKey,
147
199
  config,
200
+ embedId,
148
201
  userId,
149
202
  clientAppName,
150
203
  clientAppVersion,
@@ -168,6 +221,7 @@ export function ShortKitProvider({
168
221
  NativeShortKitModule.initialize(
169
222
  apiKey,
170
223
  serializedConfig,
224
+ embedId,
171
225
  clientAppName,
172
226
  clientAppVersion,
173
227
  serializedDimensions,
@@ -245,6 +299,7 @@ export function ShortKitProvider({
245
299
  NativeShortKitModule.onCurrentItemChanged((event) => {
246
300
  const item: ContentItem = {
247
301
  id: event.id,
302
+ playbackId: event.playbackId,
248
303
  title: event.title,
249
304
  description: event.description,
250
305
  duration: event.duration,
@@ -327,6 +382,13 @@ export function ShortKitProvider({
327
382
  }),
328
383
  );
329
384
 
385
+ // Remaining content count
386
+ subscriptions.push(
387
+ NativeShortKitModule.onRemainingContentCountChanged((event) => {
388
+ dispatch({ type: 'REMAINING_COUNT', payload: event.count });
389
+ }),
390
+ );
391
+
330
392
  // Overlay lifecycle events
331
393
  subscriptions.push(
332
394
  NativeShortKitModule.onOverlayConfigure((event) => {
@@ -380,6 +442,61 @@ export function ShortKitProvider({
380
442
  }),
381
443
  );
382
444
 
445
+ // Feed transition — track active cell type
446
+ subscriptions.push(
447
+ NativeShortKitModule.onFeedTransition((event) => {
448
+ if (event.phase === 'ended') {
449
+ // toItem is null when the destination cell is non-video (carousel, survey, ad)
450
+ const isVideo = event.toItem != null;
451
+ dispatch({
452
+ type: 'ACTIVE_CELL_TYPE',
453
+ payload: isVideo ? 'video' : 'carousel',
454
+ });
455
+ }
456
+ }),
457
+ );
458
+
459
+ // Carousel overlay lifecycle events
460
+ subscriptions.push(
461
+ NativeShortKitModule.onCarouselOverlayConfigure((event) => {
462
+ try {
463
+ const item = JSON.parse(event.item) as ImageCarouselItem;
464
+ dispatch({ type: 'CAROUSEL_OVERLAY_CONFIGURE', payload: item });
465
+ } catch {
466
+ // Ignore malformed JSON
467
+ }
468
+ }),
469
+ );
470
+
471
+ subscriptions.push(
472
+ NativeShortKitModule.onCarouselOverlayActivate((event) => {
473
+ try {
474
+ const item = JSON.parse(event.item) as ImageCarouselItem;
475
+ dispatch({ type: 'CAROUSEL_OVERLAY_ACTIVATE', payload: item });
476
+ } catch {
477
+ // Ignore malformed JSON
478
+ }
479
+ }),
480
+ );
481
+
482
+ subscriptions.push(
483
+ NativeShortKitModule.onCarouselOverlayReset((_event) => {
484
+ dispatch({ type: 'CAROUSEL_OVERLAY_RESET' });
485
+ }),
486
+ );
487
+
488
+ subscriptions.push(
489
+ NativeShortKitModule.onCarouselOverlayFadeOut((_event) => {
490
+ dispatch({ type: 'CAROUSEL_OVERLAY_FADE_OUT' });
491
+ }),
492
+ );
493
+
494
+ subscriptions.push(
495
+ NativeShortKitModule.onCarouselOverlayRestore((_event) => {
496
+ dispatch({ type: 'CAROUSEL_OVERLAY_RESTORE' });
497
+ }),
498
+ );
499
+
383
500
  // Note: Feed-level callback events (onDidLoop, onFeedTransition,
384
501
  // onShareTapped, etc.) are subscribed by the ShortKitFeed component
385
502
  // (Task 11), not here. The provider only manages state-driving events.
@@ -450,6 +567,24 @@ export function ShortKitProvider({
450
567
  NativeShortKitModule?.clearUserId();
451
568
  }, []);
452
569
 
570
+ const setFeedItemsCmd = useCallback((items: CustomFeedItem[]) => {
571
+ NativeShortKitModule?.setFeedItems(serializeCustomFeedItems(items));
572
+ }, []);
573
+
574
+ const appendFeedItemsCmd = useCallback((items: CustomFeedItem[]) => {
575
+ NativeShortKitModule?.appendFeedItems(serializeCustomFeedItems(items));
576
+ }, []);
577
+
578
+ const fetchContentCmd = useCallback(async (limit: number = 10): Promise<ContentItem[]> => {
579
+ if (!NativeShortKitModule) return [];
580
+ const json = await NativeShortKitModule.fetchContent(limit);
581
+ try {
582
+ return JSON.parse(json) as ContentItem[];
583
+ } catch {
584
+ return [];
585
+ }
586
+ }, []);
587
+
453
588
  // -----------------------------------------------------------------------
454
589
  // Context value (memoized to avoid unnecessary re-renders)
455
590
  // -----------------------------------------------------------------------
@@ -466,6 +601,7 @@ export function ShortKitProvider({
466
601
  activeCaptionTrack: state.activeCaptionTrack,
467
602
  activeCue: state.activeCue,
468
603
  prefetchedAheadCount: state.prefetchedAheadCount,
604
+ remainingContentCount: state.remainingContentCount,
469
605
  isActive: state.isActive,
470
606
  isTransitioning: state.isTransitioning,
471
607
  lastOverlayTap: state.lastOverlayTap,
@@ -486,9 +622,22 @@ export function ShortKitProvider({
486
622
  setMaxBitrate,
487
623
  setUserId: setUserIdCmd,
488
624
  clearUserId: clearUserIdCmd,
625
+ setFeedItems: setFeedItemsCmd,
626
+ appendFeedItems: appendFeedItemsCmd,
627
+ fetchContent: fetchContentCmd,
628
+
629
+ // Active cell type
630
+ activeCellType: state.activeCellType,
631
+
632
+ // Carousel overlay state
633
+ currentCarouselItem: state.currentCarouselItem,
634
+ nextCarouselItem: state.nextCarouselItem,
635
+ isCarouselActive: state.isCarouselActive,
636
+ isCarouselTransitioning: state.isCarouselTransitioning,
489
637
 
490
638
  // Internal — consumed by ShortKitFeed to pass to OverlayManager
491
639
  _overlayConfig: config.overlay ?? 'none',
640
+ _carouselOverlayConfig: config.carouselOverlay ?? 'none',
492
641
  }),
493
642
  [
494
643
  state.playerState,
@@ -501,10 +650,16 @@ export function ShortKitProvider({
501
650
  state.activeCaptionTrack,
502
651
  state.activeCue,
503
652
  state.prefetchedAheadCount,
653
+ state.remainingContentCount,
504
654
  state.isActive,
505
655
  state.isTransitioning,
506
656
  state.lastOverlayTap,
507
657
  state.lastOverlayDoubleTap,
658
+ state.activeCellType,
659
+ state.currentCarouselItem,
660
+ state.nextCarouselItem,
661
+ state.isCarouselActive,
662
+ state.isCarouselTransitioning,
508
663
  play,
509
664
  pause,
510
665
  seek,
@@ -519,7 +674,11 @@ export function ShortKitProvider({
519
674
  setMaxBitrate,
520
675
  setUserIdCmd,
521
676
  clearUserIdCmd,
677
+ setFeedItemsCmd,
678
+ appendFeedItemsCmd,
679
+ fetchContentCmd,
522
680
  config.overlay,
681
+ config.carouselOverlay,
523
682
  ],
524
683
  );
525
684
 
@@ -0,0 +1,63 @@
1
+ import React, { useContext, useMemo } from 'react';
2
+ import { View, StyleSheet } from 'react-native';
3
+ import type { ShortKitWidgetProps } from './types';
4
+ import ShortKitWidgetView from './specs/ShortKitWidgetViewNativeComponent';
5
+ import { ShortKitContext } from './ShortKitContext';
6
+
7
+ /**
8
+ * Horizontal carousel widget component. Displays a row of video cards
9
+ * with automatic rotation. Wraps a native Fabric view.
10
+ *
11
+ * Must be rendered inside a `<ShortKitProvider>`.
12
+ */
13
+ export function ShortKitWidget(props: ShortKitWidgetProps) {
14
+ const { config, items, style } = props;
15
+
16
+ const context = useContext(ShortKitContext);
17
+ if (!context) {
18
+ throw new Error('ShortKitWidget must be used within a ShortKitProvider');
19
+ }
20
+
21
+ const serializedConfig = useMemo(() => {
22
+ const cfg = config ?? {};
23
+ return JSON.stringify({
24
+ cardCount: cfg.cardCount ?? 3,
25
+ cardSpacing: cfg.cardSpacing ?? 8,
26
+ cornerRadius: cfg.cornerRadius ?? 12,
27
+ autoplay: cfg.autoplay ?? true,
28
+ muteOnStart: cfg.muteOnStart ?? true,
29
+ loop: cfg.loop ?? true,
30
+ rotationInterval: cfg.rotationInterval ?? 10000,
31
+ clickAction: cfg.clickAction ?? 'feed',
32
+ overlay: cfg.overlay
33
+ ? typeof cfg.overlay === 'string'
34
+ ? cfg.overlay
35
+ : { type: 'custom' }
36
+ : 'none',
37
+ });
38
+ }, [config]);
39
+
40
+ const serializedItems = useMemo(() => {
41
+ if (!items || items.length === 0) return undefined;
42
+ return JSON.stringify(items);
43
+ }, [items]);
44
+
45
+ return (
46
+ <View style={[styles.container, style]}>
47
+ <ShortKitWidgetView
48
+ style={styles.widget}
49
+ config={serializedConfig}
50
+ items={serializedItems}
51
+ />
52
+ </View>
53
+ );
54
+ }
55
+
56
+ const styles = StyleSheet.create({
57
+ container: {
58
+ overflow: 'hidden',
59
+ },
60
+ widget: {
61
+ flex: 1,
62
+ },
63
+ });
package/src/index.ts CHANGED
@@ -1,15 +1,26 @@
1
1
  export { ShortKitProvider } from './ShortKitProvider';
2
2
  export { ShortKitFeed } from './ShortKitFeed';
3
+ export { ShortKitPlayer } from './ShortKitPlayer';
4
+ export { ShortKitWidget } from './ShortKitWidget';
3
5
  export { useShortKitPlayer } from './useShortKitPlayer';
4
6
  export { useShortKit } from './useShortKit';
7
+ export { useShortKitCarousel } from './useShortKitCarousel';
5
8
  export type {
6
9
  FeedConfig,
7
10
  FeedHeight,
11
+ FeedSource,
8
12
  OverlayConfig,
9
- CarouselMode,
13
+ CarouselOverlayConfig,
10
14
  SurveyMode,
11
15
 
16
+ PlayerConfig,
17
+ PlayerClickAction,
18
+ WidgetConfig,
19
+
12
20
  ContentItem,
21
+ CarouselImage,
22
+ ImageCarouselItem,
23
+ CustomFeedItem,
13
24
  JSONValue,
14
25
  CaptionTrack,
15
26
  PlayerTime,
@@ -22,5 +33,8 @@ export type {
22
33
  ShortKitError,
23
34
  ShortKitProviderProps,
24
35
  ShortKitFeedProps,
36
+ ShortKitPlayerProps,
37
+ ShortKitWidgetProps,
25
38
  ShortKitPlayerState,
26
39
  } from './types';
40
+ export type { ShortKitCarouselState } from './useShortKitCarousel';
@@ -1,6 +1,7 @@
1
1
  import type {
2
2
  FeedConfig,
3
3
  ContentItem,
4
+ CustomFeedItem,
4
5
  PlayerState,
5
6
  PlayerTime,
6
7
  } from './types';
@@ -12,9 +13,10 @@ import type {
12
13
  export interface SerializedFeedConfig {
13
14
  feedHeight: string;
14
15
  overlay: string;
15
- carouselMode: string;
16
+ carouselOverlay: string;
16
17
  surveyMode: string;
17
18
  muteOnStart: boolean;
19
+ feedSource: string;
18
20
  }
19
21
 
20
22
  /**
@@ -35,9 +37,14 @@ export function serializeFeedConfig(config: FeedConfig): SerializedFeedConfig {
35
37
  return {
36
38
  feedHeight: JSON.stringify(config.feedHeight ?? { type: 'fullscreen' }),
37
39
  overlay,
38
- carouselMode: JSON.stringify(config.carouselMode ?? 'none'),
40
+ carouselOverlay: (() => {
41
+ const raw = config.carouselOverlay ?? 'none';
42
+ if (typeof raw === 'string') return JSON.stringify(raw);
43
+ return JSON.stringify({ type: 'custom' });
44
+ })(),
39
45
  surveyMode: JSON.stringify(config.surveyMode ?? 'none'),
40
46
  muteOnStart: config.muteOnStart ?? true,
47
+ feedSource: config.feedSource ?? 'algorithmic',
41
48
  };
42
49
  }
43
50
 
@@ -93,3 +100,10 @@ export function deserializePlayerTime(event: {
93
100
  buffered: event.buffered,
94
101
  };
95
102
  }
103
+
104
+ /**
105
+ * Serialize CustomFeedItem[] to a JSON string for the bridge.
106
+ */
107
+ export function serializeCustomFeedItems(items: CustomFeedItem[]): string {
108
+ return JSON.stringify(items);
109
+ }
@@ -11,6 +11,7 @@ type PlayerStateEvent = Readonly<{
11
11
 
12
12
  type CurrentItemEvent = Readonly<{
13
13
  id: string;
14
+ playbackId?: string;
14
15
  title: string;
15
16
  description?: string;
16
17
  duration: Double;
@@ -77,6 +78,10 @@ type PrefetchedAheadCountEvent = Readonly<{
77
78
  count: Int32;
78
79
  }>;
79
80
 
81
+ type RemainingContentCountEvent = Readonly<{
82
+ count: Int32;
83
+ }>;
84
+
80
85
  type ErrorEvent = Readonly<{
81
86
  code: string;
82
87
  message: string;
@@ -112,6 +117,25 @@ type OverlayRestoreEvent = Readonly<{
112
117
  item: string; // JSON-serialized ContentItem
113
118
  }>;
114
119
 
120
+ type ContentTappedEvent = Readonly<{
121
+ contentId: string;
122
+ index: Int32;
123
+ }>;
124
+
125
+ type CarouselOverlayConfigureEvent = Readonly<{
126
+ item: string; // JSON-serialized ImageCarouselItem
127
+ }>;
128
+
129
+ type CarouselOverlayActivateEvent = Readonly<{
130
+ item: string; // JSON-serialized ImageCarouselItem
131
+ }>;
132
+
133
+ type CarouselOverlayResetEvent = Readonly<{}>;
134
+
135
+ type CarouselOverlayFadeOutEvent = Readonly<{}>;
136
+
137
+ type CarouselOverlayRestoreEvent = Readonly<{}>;
138
+
115
139
  type OverlayTapEvent = Readonly<{}>;
116
140
 
117
141
  type OverlayDoubleTapEvent = Readonly<{
@@ -124,6 +148,7 @@ export interface Spec extends TurboModule {
124
148
  initialize(
125
149
  apiKey: string,
126
150
  config: string, // JSON-serialized FeedConfig
151
+ embedId?: string,
127
152
  clientAppName?: string,
128
153
  clientAppVersion?: string,
129
154
  customDimensions?: string, // JSON-serialized Record<string, string>
@@ -148,6 +173,11 @@ export interface Spec extends TurboModule {
148
173
  sendContentSignal(signal: string): void;
149
174
  setMaxBitrate(bitrate: Double): void;
150
175
 
176
+ // --- Custom feed ---
177
+ setFeedItems(items: string): void;
178
+ appendFeedItems(items: string): void;
179
+ fetchContent(limit: Int32): Promise<string>;
180
+
151
181
  // --- Event emitters ---
152
182
  readonly onPlayerStateChanged: EventEmitter<PlayerStateEvent>;
153
183
  readonly onCurrentItemChanged: EventEmitter<CurrentItemEvent>;
@@ -161,6 +191,7 @@ export interface Spec extends TurboModule {
161
191
  readonly onFeedTransition: EventEmitter<FeedTransitionEvent>;
162
192
  readonly onFormatChange: EventEmitter<FormatChangeEvent>;
163
193
  readonly onPrefetchedAheadCountChanged: EventEmitter<PrefetchedAheadCountEvent>;
194
+ readonly onRemainingContentCountChanged: EventEmitter<RemainingContentCountEvent>;
164
195
  readonly onError: EventEmitter<ErrorEvent>;
165
196
  readonly onShareTapped: EventEmitter<ShareTappedEvent>;
166
197
  readonly onSurveyResponse: EventEmitter<SurveyResponseEvent>;
@@ -171,6 +202,12 @@ export interface Spec extends TurboModule {
171
202
  readonly onOverlayRestore: EventEmitter<OverlayRestoreEvent>;
172
203
  readonly onOverlayTap: EventEmitter<OverlayTapEvent>;
173
204
  readonly onOverlayDoubleTap: EventEmitter<OverlayDoubleTapEvent>;
205
+ readonly onContentTapped: EventEmitter<ContentTappedEvent>;
206
+ readonly onCarouselOverlayConfigure: EventEmitter<CarouselOverlayConfigureEvent>;
207
+ readonly onCarouselOverlayActivate: EventEmitter<CarouselOverlayActivateEvent>;
208
+ readonly onCarouselOverlayReset: EventEmitter<CarouselOverlayResetEvent>;
209
+ readonly onCarouselOverlayFadeOut: EventEmitter<CarouselOverlayFadeOutEvent>;
210
+ readonly onCarouselOverlayRestore: EventEmitter<CarouselOverlayRestoreEvent>;
174
211
  }
175
212
 
176
213
  export default TurboModuleRegistry.getEnforcing<Spec>('ShortKitModule');
@@ -0,0 +1,13 @@
1
+ import type { HostComponent, ViewProps } from 'react-native';
2
+ import { codegenNativeComponent } from 'react-native';
3
+
4
+ export interface NativeProps extends ViewProps {
5
+ config: string;
6
+ contentItem?: string;
7
+ active?: boolean;
8
+ }
9
+
10
+ export default codegenNativeComponent<NativeProps>(
11
+ 'ShortKitPlayerView',
12
+ {},
13
+ ) as HostComponent<NativeProps>;
@@ -0,0 +1,12 @@
1
+ import type { HostComponent, ViewProps } from 'react-native';
2
+ import { codegenNativeComponent } from 'react-native';
3
+
4
+ export interface NativeProps extends ViewProps {
5
+ config: string;
6
+ items?: string;
7
+ }
8
+
9
+ export default codegenNativeComponent<NativeProps>(
10
+ 'ShortKitWidgetView',
11
+ {},
12
+ ) as HostComponent<NativeProps>;