@shortkitsdk/react-native 0.2.6 → 0.2.12

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 (75) hide show
  1. package/ShortKitReactNative.podspec +1 -0
  2. package/android/build.gradle.kts +17 -1
  3. package/android/src/main/java/com/shortkit/reactnative/ReactCarouselOverlayHost.kt +379 -0
  4. package/android/src/main/java/com/shortkit/reactnative/ReactLoadingHost.kt +40 -0
  5. package/android/src/main/java/com/shortkit/reactnative/ReactOverlayHost.kt +570 -0
  6. package/android/src/main/java/com/shortkit/reactnative/ShortKitBridge.kt +1029 -0
  7. package/android/src/main/java/com/shortkit/reactnative/ShortKitFeedView.kt +212 -219
  8. package/android/src/main/java/com/shortkit/reactnative/ShortKitFeedViewManager.kt +17 -3
  9. package/android/src/main/java/com/shortkit/reactnative/ShortKitModule.kt +157 -742
  10. package/android/src/main/java/com/shortkit/reactnative/ShortKitPlayerNativeView.kt +11 -2
  11. package/android/src/main/java/com/shortkit/reactnative/ShortKitWidgetNativeView.kt +2 -2
  12. package/ios/ReactCarouselOverlayHost.swift +177 -0
  13. package/ios/ReactLoadingHost.swift +38 -0
  14. package/ios/ReactOverlayHost.swift +444 -0
  15. package/ios/SKFabricSurfaceWrapper.h +18 -0
  16. package/ios/SKFabricSurfaceWrapper.mm +57 -0
  17. package/ios/ShortKitBridge.swift +220 -63
  18. package/ios/ShortKitFeedView.swift +82 -228
  19. package/ios/ShortKitFeedViewManager.mm +3 -2
  20. package/ios/ShortKitModule.mm +69 -37
  21. package/ios/ShortKitPlayerNativeView.swift +39 -8
  22. package/ios/ShortKitReactNative-Bridging-Header.h +2 -0
  23. package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Headers/ShortKitSDK-Swift.h +1 -1
  24. package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.abi.json +3683 -1249
  25. package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.private.swiftinterface +56 -15
  26. package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.swiftdoc +0 -0
  27. package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.swiftinterface +56 -15
  28. package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/ShortKitSDK +0 -0
  29. package/ios/ShortKitSDK.xcframework/ios-arm64-simulator/ShortKitSDK.framework/Headers/ShortKitSDK-Swift.h +1 -1
  30. package/ios/ShortKitSDK.xcframework/ios-arm64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.abi.json +3683 -1249
  31. package/ios/ShortKitSDK.xcframework/ios-arm64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface +56 -15
  32. package/ios/ShortKitSDK.xcframework/ios-arm64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.swiftdoc +0 -0
  33. package/ios/ShortKitSDK.xcframework/ios-arm64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.swiftinterface +56 -15
  34. package/ios/ShortKitSDK.xcframework/ios-arm64-simulator/ShortKitSDK.framework/ShortKitSDK +0 -0
  35. package/ios/ShortKitSDK.xcframework.bak/Info.plist +43 -0
  36. package/ios/ShortKitSDK.xcframework.bak/ios-arm64/ShortKitSDK.framework/Headers/ShortKitSDK-Swift.h +418 -0
  37. package/ios/ShortKitSDK.xcframework.bak/ios-arm64/ShortKitSDK.framework/Info.plist +16 -0
  38. package/ios/ShortKitSDK.xcframework.bak/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.abi.json +28917 -0
  39. package/ios/ShortKitSDK.xcframework.bak/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.private.swiftinterface +824 -0
  40. package/ios/ShortKitSDK.xcframework.bak/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.swiftdoc +0 -0
  41. package/ios/ShortKitSDK.xcframework.bak/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.swiftinterface +824 -0
  42. package/ios/ShortKitSDK.xcframework.bak/ios-arm64/ShortKitSDK.framework/Modules/module.modulemap +4 -0
  43. package/ios/ShortKitSDK.xcframework.bak/ios-arm64/ShortKitSDK.framework/ShortKitSDK +0 -0
  44. package/ios/ShortKitSDK.xcframework.bak/ios-arm64-simulator/ShortKitSDK.framework/Headers/ShortKitSDK-Swift.h +418 -0
  45. package/ios/ShortKitSDK.xcframework.bak/ios-arm64-simulator/ShortKitSDK.framework/Info.plist +16 -0
  46. package/ios/ShortKitSDK.xcframework.bak/ios-arm64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.abi.json +28917 -0
  47. package/ios/ShortKitSDK.xcframework.bak/ios-arm64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface +824 -0
  48. package/ios/ShortKitSDK.xcframework.bak/ios-arm64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.swiftdoc +0 -0
  49. package/ios/ShortKitSDK.xcframework.bak/ios-arm64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.swiftinterface +824 -0
  50. package/ios/ShortKitSDK.xcframework.bak/ios-arm64-simulator/ShortKitSDK.framework/Modules/module.modulemap +4 -0
  51. package/ios/ShortKitSDK.xcframework.bak/ios-arm64-simulator/ShortKitSDK.framework/ShortKitSDK +0 -0
  52. package/ios/ShortKitWidgetNativeView.swift +3 -3
  53. package/package.json +1 -1
  54. package/src/ShortKitCarouselOverlaySurface.tsx +55 -0
  55. package/src/ShortKitCommands.ts +31 -0
  56. package/src/ShortKitContext.ts +6 -24
  57. package/src/ShortKitFeed.tsx +124 -41
  58. package/src/ShortKitLoadingSurface.tsx +24 -0
  59. package/src/ShortKitOverlaySurface.tsx +313 -0
  60. package/src/ShortKitPlayer.tsx +30 -9
  61. package/src/ShortKitProvider.tsx +28 -285
  62. package/src/index.ts +9 -3
  63. package/src/serialization.ts +20 -39
  64. package/src/specs/NativeShortKitModule.ts +74 -45
  65. package/src/specs/ShortKitFeedViewNativeComponent.ts +3 -2
  66. package/src/types.ts +84 -16
  67. package/src/useShortKit.ts +1 -3
  68. package/src/useShortKitPlayer.ts +7 -7
  69. package/android/src/main/java/com/shortkit/reactnative/ShortKitCarouselOverlayBridge.kt +0 -48
  70. package/android/src/main/java/com/shortkit/reactnative/ShortKitOverlayBridge.kt +0 -128
  71. package/ios/ShortKitCarouselOverlayBridge.swift +0 -219
  72. package/ios/ShortKitOverlayBridge.swift +0 -111
  73. package/src/CarouselOverlayManager.tsx +0 -70
  74. package/src/OverlayManager.tsx +0 -87
  75. package/src/useShortKitCarousel.ts +0 -29
@@ -22,6 +22,7 @@ type CurrentItemEvent = Readonly<{
22
22
  author?: string;
23
23
  articleUrl?: string;
24
24
  commentCount?: Int32;
25
+ fallbackUrl?: string;
25
26
  }>;
26
27
 
27
28
  type TimeUpdateEvent = Readonly<{
@@ -84,16 +85,16 @@ type PrefetchedAheadCountEvent = Readonly<{
84
85
  }>;
85
86
 
86
87
  type RemainingContentCountEvent = Readonly<{
88
+ feedId: string;
87
89
  count: Int32;
88
90
  }>;
89
91
 
90
- type ErrorEvent = Readonly<{
91
- code: string;
92
- message: string;
93
- }>;
92
+ type DismissEvent = Readonly<{}>;
93
+
94
+ type RefreshRequestedEvent = Readonly<{}>;
94
95
 
95
- type ShareTappedEvent = Readonly<{
96
- item: string; // JSON-serialized ContentItem
96
+ type DidFetchContentItemsEvent = Readonly<{
97
+ items: string; // JSON-serialized ContentItem[]
97
98
  }>;
98
99
 
99
100
  type SurveyResponseEvent = Readonly<{
@@ -102,50 +103,75 @@ type SurveyResponseEvent = Readonly<{
102
103
  optionText: string;
103
104
  }>;
104
105
 
105
- type OverlayConfigureEvent = Readonly<{
106
- item: string; // JSON-serialized ContentItem
106
+ type ContentTappedEvent = Readonly<{
107
+ contentId: string;
108
+ index: Int32;
107
109
  }>;
108
110
 
109
- type OverlayActivateEvent = Readonly<{
110
- item: string; // JSON-serialized ContentItem
111
+ type FeedReadyEvent = Readonly<{
112
+ feedId: string;
111
113
  }>;
112
114
 
113
- type OverlayResetEvent = Readonly<{
114
- item: string; // JSON-serialized ContentItem
115
+ // --- Overlay per-surface event payload types ---
116
+
117
+ type OverlayActiveEvent = Readonly<{
118
+ surfaceId: string;
119
+ isActive: boolean;
115
120
  }>;
116
121
 
117
- type ContentTappedEvent = Readonly<{
118
- contentId: string;
119
- index: Int32;
122
+ type OverlayPlayerStateEvent = Readonly<{
123
+ surfaceId: string;
124
+ playerState: string;
120
125
  }>;
121
126
 
122
- type CarouselOverlayConfigureEvent = Readonly<{
123
- item: string; // JSON-serialized ImageCarouselItem
127
+ type OverlayMutedEvent = Readonly<{
128
+ surfaceId: string;
129
+ isMuted: boolean;
124
130
  }>;
125
131
 
126
- type CarouselOverlayActivateEvent = Readonly<{
127
- item: string; // JSON-serialized ImageCarouselItem
132
+ type OverlayPlaybackRateEvent = Readonly<{
133
+ surfaceId: string;
134
+ playbackRate: Double;
128
135
  }>;
129
136
 
130
- type CarouselOverlayResetEvent = Readonly<{}>;
137
+ type OverlayCaptionsEnabledEvent = Readonly<{
138
+ surfaceId: string;
139
+ captionsEnabled: boolean;
140
+ }>;
131
141
 
132
- type CarouselPageChangedEvent = Readonly<{
133
- page: Int32;
134
- pageCount: Int32;
142
+ type OverlayActiveCueEvent = Readonly<{
143
+ surfaceId: string;
144
+ activeCue: string;
135
145
  }>;
136
146
 
137
- type OverlayTapEvent = Readonly<{}>;
147
+ type OverlayFeedScrollPhaseEvent = Readonly<{
148
+ surfaceId: string;
149
+ feedScrollPhase: string;
150
+ }>;
138
151
 
139
- type OverlayDoubleTapEvent = Readonly<{
140
- x: Double;
141
- y: Double;
152
+ type OverlayTimeUpdateEvent = Readonly<{
153
+ surfaceId: string;
154
+ current: Double;
155
+ duration: Double;
156
+ buffered: Double;
157
+ }>;
158
+
159
+ type OverlayFullStateEvent = Readonly<{
160
+ surfaceId: string;
161
+ isActive: boolean;
162
+ playerState: string;
163
+ isMuted: boolean;
164
+ playbackRate: Double;
165
+ captionsEnabled: boolean;
166
+ activeCue: string;
167
+ feedScrollPhase: string;
142
168
  }>;
143
169
 
144
170
  export interface Spec extends TurboModule {
145
171
  // --- Lifecycle ---
146
172
  initialize(
147
173
  apiKey: string,
148
- config: string, // JSON-serialized FeedConfig
174
+ hasLoadingView: boolean,
149
175
  clientAppName?: string,
150
176
  clientAppVersion?: string,
151
177
  customDimensions?: string, // JSON-serialized Record<string, string>
@@ -171,17 +197,16 @@ export interface Spec extends TurboModule {
171
197
  setMaxBitrate(bitrate: Double): void;
172
198
 
173
199
  // --- Custom feed ---
174
- setFeedItems(items: string): void;
175
- appendFeedItems(items: string): void;
176
- fetchContent(limit: Int32): Promise<string>;
200
+ setFeedItems(feedId: string, items: string): void;
201
+ appendFeedItems(feedId: string, items: string): void;
202
+ fetchContent(limit: Int32, filterJSON: string | null): Promise<string>;
203
+ applyFilter(feedId: string, filterJSON: string | null): void;
204
+ preloadFeed(configJSON: string, itemsJSON: string | null): Promise<string>;
177
205
 
178
206
  // --- Storyboard / seek thumbnails ---
179
207
  prefetchStoryboard(playbackId: string): void;
180
208
  getStoryboardData(playbackId: string): Promise<string>;
181
209
 
182
- // --- Overlay lifecycle ---
183
- notifyOverlayReady(): void;
184
-
185
210
  // --- Event emitters ---
186
211
  readonly onPlayerStateChanged: EventEmitter<PlayerStateEvent>;
187
212
  readonly onCurrentItemChanged: EventEmitter<CurrentItemEvent>;
@@ -197,19 +222,23 @@ export interface Spec extends TurboModule {
197
222
  readonly onFormatChange: EventEmitter<FormatChangeEvent>;
198
223
  readonly onPrefetchedAheadCountChanged: EventEmitter<PrefetchedAheadCountEvent>;
199
224
  readonly onRemainingContentCountChanged: EventEmitter<RemainingContentCountEvent>;
200
- readonly onError: EventEmitter<ErrorEvent>;
201
- readonly onShareTapped: EventEmitter<ShareTappedEvent>;
202
225
  readonly onSurveyResponse: EventEmitter<SurveyResponseEvent>;
203
- readonly onOverlayConfigure: EventEmitter<OverlayConfigureEvent>;
204
- readonly onOverlayActivate: EventEmitter<OverlayActivateEvent>;
205
- readonly onOverlayReset: EventEmitter<OverlayResetEvent>;
206
- readonly onOverlayTap: EventEmitter<OverlayTapEvent>;
207
- readonly onOverlayDoubleTap: EventEmitter<OverlayDoubleTapEvent>;
208
226
  readonly onContentTapped: EventEmitter<ContentTappedEvent>;
209
- readonly onCarouselOverlayConfigure: EventEmitter<CarouselOverlayConfigureEvent>;
210
- readonly onCarouselOverlayActivate: EventEmitter<CarouselOverlayActivateEvent>;
211
- readonly onCarouselOverlayReset: EventEmitter<CarouselOverlayResetEvent>;
212
- readonly onCarouselPageChanged: EventEmitter<CarouselPageChangedEvent>;
227
+ readonly onDismiss: EventEmitter<DismissEvent>;
228
+ readonly onRefreshRequested: EventEmitter<RefreshRequestedEvent>;
229
+ readonly onDidFetchContentItems: EventEmitter<DidFetchContentItemsEvent>;
230
+ readonly onFeedReady: EventEmitter<FeedReadyEvent>;
231
+
232
+ // --- Overlay per-surface events ---
233
+ readonly onOverlayActiveChanged: EventEmitter<OverlayActiveEvent>;
234
+ readonly onOverlayPlayerStateChanged: EventEmitter<OverlayPlayerStateEvent>;
235
+ readonly onOverlayMutedChanged: EventEmitter<OverlayMutedEvent>;
236
+ readonly onOverlayPlaybackRateChanged: EventEmitter<OverlayPlaybackRateEvent>;
237
+ readonly onOverlayCaptionsEnabledChanged: EventEmitter<OverlayCaptionsEnabledEvent>;
238
+ readonly onOverlayActiveCueChanged: EventEmitter<OverlayActiveCueEvent>;
239
+ readonly onOverlayFeedScrollPhaseChanged: EventEmitter<OverlayFeedScrollPhaseEvent>;
240
+ readonly onOverlayTimeUpdate: EventEmitter<OverlayTimeUpdateEvent>;
241
+ readonly onOverlayFullState: EventEmitter<OverlayFullStateEvent>;
213
242
  }
214
243
 
215
244
  export default TurboModuleRegistry.getEnforcing<Spec>('ShortKitModule');
@@ -1,10 +1,11 @@
1
1
  import type { HostComponent, ViewProps } from 'react-native';
2
2
  import { codegenNativeComponent } from 'react-native';
3
- import type { WithDefault } from 'react-native/Libraries/Types/CodegenTypes';
4
3
 
5
4
  export interface NativeProps extends ViewProps {
6
5
  config: string;
7
- overlayType?: WithDefault<'none' | 'custom', 'none'>;
6
+ feedId?: string;
7
+ startAtItemId?: string;
8
+ preloadId?: string;
8
9
  }
9
10
 
10
11
  export default codegenNativeComponent<NativeProps>(
package/src/types.ts CHANGED
@@ -1,29 +1,45 @@
1
+ import type React from 'react';
1
2
  import type { ViewStyle } from 'react-native';
2
3
 
3
4
  // --- Configuration ---
4
5
 
5
6
  export type FeedSource = 'algorithmic' | 'custom';
6
7
 
8
+ export interface FeedFilter {
9
+ tags?: string[];
10
+ section?: string;
11
+ author?: string;
12
+ contentType?: string;
13
+ metadata?: Record<string, string>;
14
+ }
15
+
16
+ export type CaptionSource = 'embedded' | 'external' | 'generated';
17
+
7
18
  export interface FeedConfig {
8
19
  feedHeight?: FeedHeight;
20
+ scrollAxis?: ScrollAxis;
9
21
  overlay?: OverlayConfig;
10
22
  carouselOverlay?: CarouselOverlayConfig;
11
23
  surveyMode?: SurveyMode;
12
24
  muteOnStart?: boolean;
13
25
  feedSource?: FeedSource;
26
+ autoplay?: boolean;
27
+ filter?: FeedFilter;
14
28
  }
15
29
 
16
30
  export type FeedHeight =
17
31
  | { type: 'fullscreen' }
18
32
  | { type: 'percentage'; value: number };
19
33
 
34
+ export type ScrollAxis = 'vertical' | 'horizontal';
35
+
20
36
  export type OverlayConfig =
21
37
  | 'none'
22
- | { type: 'custom'; component: React.ComponentType };
38
+ | { type: 'custom'; name: string; component: React.ComponentType<OverlayProps> };
23
39
 
24
40
  export type CarouselOverlayConfig =
25
41
  | 'none'
26
- | { type: 'custom'; component: React.ComponentType };
42
+ | { type: 'custom'; name: string; component: React.ComponentType<CarouselOverlayProps> };
27
43
 
28
44
  export type SurveyMode =
29
45
  | 'none'
@@ -44,6 +60,7 @@ export interface ContentItem {
44
60
  author?: string;
45
61
  articleUrl?: string;
46
62
  commentCount?: number;
63
+ fallbackUrl?: string;
47
64
  }
48
65
 
49
66
  // --- Custom Feed Types ---
@@ -56,7 +73,6 @@ export interface CarouselImage {
56
73
  export interface ImageCarouselItem {
57
74
  id: string;
58
75
  images: CarouselImage[];
59
- autoScrollInterval?: number;
60
76
  caption?: string;
61
77
  title?: string;
62
78
  description?: string;
@@ -66,7 +82,7 @@ export interface ImageCarouselItem {
66
82
  }
67
83
 
68
84
  export type FeedInput =
69
- | { type: 'video'; playbackId: string }
85
+ | { type: 'video'; playbackId: string; fallbackUrl?: string }
70
86
  | { type: 'imageCarousel'; item: ImageCarouselItem };
71
87
 
72
88
  export type JSONValue =
@@ -97,7 +113,10 @@ export interface StoryboardData {
97
113
  export interface CaptionTrack {
98
114
  language: string;
99
115
  label: string;
100
- sourceUrl: string;
116
+ source?: CaptionSource;
117
+ url?: string;
118
+ /** @deprecated Use `url` instead. */
119
+ sourceUrl?: string;
101
120
  }
102
121
 
103
122
  export interface PlayerTime {
@@ -148,35 +167,89 @@ export interface SurveyOption {
148
167
  text: string;
149
168
  }
150
169
 
151
- export interface ShortKitError {
152
- code: string;
153
- message: string;
170
+ // --- Overlay Props ---
171
+
172
+ /** Props passed to video overlay components rendered inside feed cells. */
173
+ export interface OverlayProps {
174
+ /** The content item for this cell. */
175
+ item: ContentItem;
176
+ /** Whether this cell is the active playback cell. */
177
+ isActive: boolean;
178
+ /** Current player state. */
179
+ playerState: PlayerState;
180
+ /** Current playback time. Only updates when isActive is true. */
181
+ time: PlayerTime;
182
+ /** Whether audio is muted. */
183
+ isMuted: boolean;
184
+ /** Current playback speed. */
185
+ playbackRate: number;
186
+ /** Whether captions are enabled. */
187
+ captionsEnabled: boolean;
188
+ /** The currently active caption cue, or null. */
189
+ activeCue: { text: string; startTime: number; endTime: number } | null;
190
+ /** Current feed scroll phase — use to fade overlay during swipes. */
191
+ feedScrollPhase: FeedScrollPhase | null;
192
+ }
193
+
194
+ /** Props passed to carousel overlay components rendered inside feed cells. */
195
+ export interface CarouselOverlayProps {
196
+ /** The carousel item for this cell. */
197
+ item: ImageCarouselItem;
154
198
  }
155
199
 
156
200
  // --- Provider Props ---
157
201
 
158
202
  export interface ShortKitProviderProps {
159
203
  apiKey: string;
160
- config: FeedConfig;
161
204
  userId?: string;
162
205
 
163
206
  clientAppName?: string;
164
207
  clientAppVersion?: string;
165
208
  customDimensions?: Record<string, string>;
166
209
  children: React.ReactNode;
210
+ /** Custom loading view rendered while the feed loads or during filter changes.
211
+ * When omitted, the SDK uses a default spinner. */
212
+ loadingViewComponent?: React.ComponentType<{}>;
167
213
  }
168
214
 
169
215
  // --- Feed Component Props ---
170
216
 
171
217
  export interface ShortKitFeedProps {
218
+ config?: FeedConfig;
219
+ preloadId?: string;
172
220
  style?: ViewStyle;
173
- onError?: (error: ShortKitError) => void;
174
- onShareTapped?: (item: ContentItem) => void;
221
+ /** Item ID to scroll to on initial load. */
222
+ startAtItemId?: string;
175
223
  onSurveyResponse?: (surveyId: string, option: SurveyOption) => void;
176
224
  onLoop?: (event: LoopEvent) => void;
177
225
  onFeedTransition?: (event: FeedTransitionEvent) => void;
178
226
  onFormatChange?: (event: FormatChangeEvent) => void;
179
227
  onContentTapped?: (contentId: string, index: number) => void;
228
+ /** Called when the user dismisses the feed (swipe-down or back gesture). */
229
+ onDismiss?: () => void;
230
+ /** Called when the user pulls to refresh in custom feed mode. */
231
+ onRefreshRequested?: () => void;
232
+ /** Called when the SDK fetches content items from the algorithmic feed.
233
+ * Use to pre-fetch your own metadata for the given items. */
234
+ onDidFetchContentItems?: (items: ContentItem[]) => void;
235
+ /** Called when the number of remaining items in this feed changes. */
236
+ onRemainingContentCountChange?: (count: number) => void;
237
+ /** Called once when this feed has loaded content and assigned a player
238
+ * to the first cell. Use to dismiss a splash screen or loading overlay. */
239
+ onFeedReady?: () => void;
240
+ }
241
+
242
+ /**
243
+ * Imperative handle for per-feed-instance operations.
244
+ * Obtained via `ref` on `<ShortKitFeed>`.
245
+ */
246
+ export interface ShortKitFeedHandle {
247
+ /** Replace all items in this feed instance. */
248
+ setFeedItems: (items: FeedInput[]) => void;
249
+ /** Append items to this feed instance. */
250
+ appendFeedItems: (items: FeedInput[]) => void;
251
+ /** Apply a content filter to this feed instance. Pass null to clear. */
252
+ applyFilter: (filter: FeedFilter | null) => void;
180
253
  }
181
254
 
182
255
  // --- Single Player Config ---
@@ -232,8 +305,6 @@ export interface ShortKitWidgetProps {
232
305
  export interface ShortKitPlayerState {
233
306
  playerState: PlayerState;
234
307
  currentItem: ContentItem | null;
235
- nextItem: ContentItem | null;
236
- activeCellType: 'video' | 'carousel' | null;
237
308
  time: PlayerTime;
238
309
  isMuted: boolean;
239
310
  playbackRate: number;
@@ -241,11 +312,8 @@ export interface ShortKitPlayerState {
241
312
  activeCaptionTrack: CaptionTrack | null;
242
313
  activeCue: { text: string; startTime: number; endTime: number } | null;
243
314
  prefetchedAheadCount: number;
244
- remainingContentCount: number;
245
315
  isActive: boolean;
246
316
  feedScrollPhase: FeedScrollPhase | null;
247
- lastOverlayTap: number;
248
- lastOverlayDoubleTap: { x: number; y: number; id: number } | null;
249
317
 
250
318
  play: () => void;
251
319
  pause: () => void;
@@ -16,9 +16,7 @@ export function useShortKit() {
16
16
  return {
17
17
  setUserId: context.setUserId,
18
18
  clearUserId: context.clearUserId,
19
- setFeedItems: context.setFeedItems,
20
- appendFeedItems: context.appendFeedItems,
21
19
  fetchContent: context.fetchContent,
22
- remainingContentCount: context.remainingContentCount,
20
+ preloadFeed: context.preloadFeed,
23
21
  };
24
22
  }
@@ -7,6 +7,12 @@ import type { ShortKitPlayerState } from './types';
7
7
  *
8
8
  * Must be used within a `<ShortKitProvider>`.
9
9
  *
10
+ * **Note:** This hook is NOT available inside overlay components registered via
11
+ * `config.overlay.component` / `config.carouselOverlay.component`. Overlays run
12
+ * in isolated React surfaces and receive data via props (OverlayProps /
13
+ * CarouselOverlayProps). Use `ShortKitCommands` for imperative player control
14
+ * from overlays.
15
+ *
10
16
  * @returns Player state (playerState, currentItem, time, etc.) and
11
17
  * command functions (play, pause, seek, etc.).
12
18
  */
@@ -16,19 +22,13 @@ export function useShortKitPlayer(): ShortKitPlayerState {
16
22
  throw new Error('useShortKitPlayer must be used within a ShortKitProvider');
17
23
  }
18
24
 
19
- // Return only player-related state and commands (exclude SDK operations,
20
- // carousel state, and internal fields)
25
+ // Return only player-related state and commands (exclude SDK operations)
21
26
  const {
22
27
  setUserId: _setUserId,
23
28
  clearUserId: _clearUserId,
24
29
  setFeedItems: _setFeedItems,
25
30
  appendFeedItems: _appendFeedItems,
26
31
  fetchContent: _fetchContent,
27
- currentCarouselItem: _currentCarouselItem,
28
- nextCarouselItem: _nextCarouselItem,
29
- isCarouselActive: _isCarouselActive,
30
- _overlayConfig: _overlay,
31
- _carouselOverlayConfig: _carouselOverlay,
32
32
  ...playerState
33
33
  } = context;
34
34
 
@@ -1,48 +0,0 @@
1
- package com.shortkit.reactnative
2
-
3
- import android.content.Context
4
- import android.graphics.Color
5
- import android.widget.FrameLayout
6
- import com.facebook.react.bridge.Arguments
7
- import com.shortkit.sdk.model.ImageCarouselItem
8
- import com.shortkit.sdk.overlay.CarouselOverlay
9
- import kotlinx.serialization.encodeToString
10
- import kotlinx.serialization.json.Json
11
-
12
- /**
13
- * A transparent [FrameLayout] that implements [CarouselOverlay] and bridges
14
- * carousel overlay lifecycle calls to JS events via [ShortKitModule].
15
- *
16
- * The actual carousel overlay UI is rendered by React Native on the JS side
17
- * through the `CarouselOverlayManager` component. This view simply relays
18
- * the SDK lifecycle events so the JS carousel overlay knows when to
19
- * configure, activate, reset, etc.
20
- *
21
- * Android equivalent of iOS `ShortKitCarouselOverlayBridge.swift`.
22
- */
23
- class ShortKitCarouselOverlayBridge(context: Context) : FrameLayout(context), CarouselOverlay {
24
-
25
- init {
26
- setBackgroundColor(Color.TRANSPARENT)
27
- }
28
-
29
- override fun configure(item: ImageCarouselItem) {
30
- val json = Json.encodeToString(item)
31
- val params = Arguments.createMap().apply {
32
- putString("item", json)
33
- }
34
- ShortKitModule.shared?.emitCarouselOverlayEvent("onCarouselOverlayConfigure", params)
35
- }
36
-
37
- override fun resetState() {
38
- ShortKitModule.shared?.emitCarouselOverlayEvent("onCarouselOverlayReset", Arguments.createMap())
39
- }
40
-
41
- override fun fadeOutForTransition() {
42
- ShortKitModule.shared?.emitCarouselOverlayEvent("onCarouselOverlayFadeOut", Arguments.createMap())
43
- }
44
-
45
- override fun restoreFromTransition() {
46
- ShortKitModule.shared?.emitCarouselOverlayEvent("onCarouselOverlayRestore", Arguments.createMap())
47
- }
48
- }
@@ -1,128 +0,0 @@
1
- package com.shortkit.reactnative
2
-
3
- import android.content.Context
4
- import android.graphics.Color
5
- import android.os.Handler
6
- import android.os.Looper
7
- import android.view.GestureDetector
8
- import android.view.MotionEvent
9
- import android.widget.FrameLayout
10
- import com.facebook.react.bridge.Arguments
11
- import com.shortkit.ContentItem
12
- import com.shortkit.FeedOverlay
13
- import com.shortkit.ShortKitPlayer
14
-
15
- /**
16
- * A transparent [FrameLayout] that implements [FeedOverlay] and bridges
17
- * overlay lifecycle calls to JS events via [ShortKitModule].
18
- *
19
- * The actual overlay UI is rendered by React Native on the JS side through
20
- * the `OverlayManager` component. This view simply relays the SDK lifecycle
21
- * events so the JS overlay knows when to configure, activate, reset, etc.
22
- *
23
- * Android equivalent of iOS `ShortKitOverlayBridge.swift`.
24
- */
25
- class ShortKitOverlayBridge(context: Context) : FrameLayout(context), FeedOverlay {
26
-
27
- // -----------------------------------------------------------------------
28
- // State
29
- // -----------------------------------------------------------------------
30
-
31
- /**
32
- * Stores the last configured [ContentItem] so we can pass it with
33
- * lifecycle events that don't receive the item as a parameter.
34
- */
35
- private var currentItem: ContentItem? = null
36
-
37
- /**
38
- * Deferred configure emission — cancelled if [activatePlayback] fires
39
- * on the same message-queue iteration (handleSwipe re-configure of the
40
- * active cell, not a prefetch for the next cell).
41
- */
42
- private var pendingConfigureRunnable: Runnable? = null
43
-
44
- private val handler = Handler(Looper.getMainLooper())
45
-
46
- // -----------------------------------------------------------------------
47
- // Gestures
48
- // -----------------------------------------------------------------------
49
-
50
- private val gestureDetector = GestureDetector(context, object : GestureDetector.SimpleOnGestureListener() {
51
- override fun onSingleTapConfirmed(e: MotionEvent): Boolean {
52
- ShortKitModule.shared?.emitOverlayEvent("onOverlayTap", Arguments.createMap())
53
- return true
54
- }
55
-
56
- override fun onDoubleTap(e: MotionEvent): Boolean {
57
- val params = Arguments.createMap().apply {
58
- putDouble("x", e.x.toDouble())
59
- putDouble("y", e.y.toDouble())
60
- }
61
- ShortKitModule.shared?.emitOverlayEvent("onOverlayDoubleTap", params)
62
- return true
63
- }
64
- })
65
-
66
- // -----------------------------------------------------------------------
67
- // Init
68
- // -----------------------------------------------------------------------
69
-
70
- init {
71
- setBackgroundColor(Color.TRANSPARENT)
72
- isClickable = true
73
- }
74
-
75
- override fun onTouchEvent(event: MotionEvent): Boolean {
76
- return gestureDetector.onTouchEvent(event) || super.onTouchEvent(event)
77
- }
78
-
79
- // -----------------------------------------------------------------------
80
- // FeedOverlay
81
- // -----------------------------------------------------------------------
82
-
83
- override fun attach(player: ShortKitPlayer) {
84
- // No-op on the native side. The JS overlay subscribes to player
85
- // state via the TurboModule's flow publishers.
86
- }
87
-
88
- override fun configure(item: ContentItem) {
89
- currentItem = item
90
-
91
- // Defer the configure event by one message-queue tick. If activatePlayback()
92
- // fires before then (handleSwipe sequence: configure → reset → activate),
93
- // the event is cancelled — preventing nextItem from being overwritten
94
- // with the current cell's data.
95
- pendingConfigureRunnable?.let { handler.removeCallbacks(it) }
96
- val runnable = Runnable {
97
- currentItem?.let { ShortKitModule.shared?.emitOverlayEvent("onOverlayConfigure", it) }
98
- pendingConfigureRunnable = null
99
- }
100
- pendingConfigureRunnable = runnable
101
- handler.post(runnable)
102
- }
103
-
104
- override fun resetPlaybackProgress() {
105
- val item = currentItem ?: return
106
- ShortKitModule.shared?.emitOverlayEvent("onOverlayReset", item)
107
- }
108
-
109
- override fun activatePlayback() {
110
- // Cancel the pending configure — it was for the current cell (part of
111
- // handleSwipe), not a prefetch for the next cell.
112
- pendingConfigureRunnable?.let { handler.removeCallbacks(it) }
113
- pendingConfigureRunnable = null
114
-
115
- val item = currentItem ?: return
116
- ShortKitModule.shared?.emitOverlayEvent("onOverlayActivate", item)
117
- }
118
-
119
- override fun fadeOutForTransition() {
120
- val item = currentItem ?: return
121
- ShortKitModule.shared?.emitOverlayEvent("onOverlayFadeOut", item)
122
- }
123
-
124
- override fun restoreFromTransition() {
125
- val item = currentItem ?: return
126
- ShortKitModule.shared?.emitOverlayEvent("onOverlayRestore", item)
127
- }
128
- }