@shortkitsdk/react-native 0.2.5 → 0.2.11

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 +5 -1
  3. package/android/src/main/java/com/shortkit/reactnative/ReactCarouselOverlayHost.kt +319 -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 +559 -0
  6. package/android/src/main/java/com/shortkit/reactnative/ShortKitBridge.kt +984 -0
  7. package/android/src/main/java/com/shortkit/reactnative/ShortKitFeedView.kt +88 -220
  8. package/android/src/main/java/com/shortkit/reactnative/ShortKitFeedViewManager.kt +12 -3
  9. package/android/src/main/java/com/shortkit/reactnative/ShortKitModule.kt +126 -706
  10. package/android/src/main/java/com/shortkit/reactnative/ShortKitPlayerNativeView.kt +2 -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 +458 -0
  15. package/ios/SKFabricSurfaceWrapper.h +18 -0
  16. package/ios/SKFabricSurfaceWrapper.mm +57 -0
  17. package/ios/ShortKitBridge.swift +266 -65
  18. package/ios/ShortKitFeedView.swift +63 -207
  19. package/ios/ShortKitFeedViewManager.mm +3 -2
  20. package/ios/ShortKitModule.mm +86 -32
  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 +2 -1
  24. package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.abi.json +3998 -962
  25. package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.private.swiftinterface +85 -24
  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 +85 -24
  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 +2 -1
  30. package/ios/ShortKitSDK.xcframework/ios-arm64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.abi.json +3998 -962
  31. package/ios/ShortKitSDK.xcframework/ios-arm64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface +85 -24
  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 +85 -24
  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 +11 -25
  57. package/src/ShortKitFeed.tsx +110 -41
  58. package/src/ShortKitLoadingSurface.tsx +24 -0
  59. package/src/ShortKitOverlaySurface.tsx +205 -0
  60. package/src/ShortKitPlayer.tsx +6 -7
  61. package/src/ShortKitProvider.tsx +65 -250
  62. package/src/index.ts +9 -4
  63. package/src/serialization.ts +22 -42
  64. package/src/specs/NativeShortKitModule.ts +67 -53
  65. package/src/specs/ShortKitFeedViewNativeComponent.ts +3 -2
  66. package/src/types.ts +104 -19
  67. package/src/useShortKit.ts +1 -3
  68. package/src/useShortKitPlayer.ts +7 -8
  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 -54
  72. package/ios/ShortKitOverlayBridge.swift +0 -113
  73. package/src/CarouselOverlayManager.tsx +0 -71
  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<{
@@ -66,6 +67,11 @@ type FeedTransitionEvent = Readonly<{
66
67
  direction: string;
67
68
  }>;
68
69
 
70
+ type FeedScrollPhaseEvent = Readonly<{
71
+ phase: string;
72
+ fromId?: string;
73
+ }>;
74
+
69
75
  type FormatChangeEvent = Readonly<{
70
76
  contentId: string;
71
77
  fromBitrate: Double;
@@ -79,16 +85,16 @@ type PrefetchedAheadCountEvent = Readonly<{
79
85
  }>;
80
86
 
81
87
  type RemainingContentCountEvent = Readonly<{
88
+ feedId: string;
82
89
  count: Int32;
83
90
  }>;
84
91
 
85
- type ErrorEvent = Readonly<{
86
- code: string;
87
- message: string;
88
- }>;
92
+ type DismissEvent = Readonly<{}>;
93
+
94
+ type RefreshRequestedEvent = Readonly<{}>;
89
95
 
90
- type ShareTappedEvent = Readonly<{
91
- item: string; // JSON-serialized ContentItem
96
+ type DidFetchContentItemsEvent = Readonly<{
97
+ items: string; // JSON-serialized ContentItem[]
92
98
  }>;
93
99
 
94
100
  type SurveyResponseEvent = Readonly<{
@@ -97,58 +103,60 @@ type SurveyResponseEvent = Readonly<{
97
103
  optionText: string;
98
104
  }>;
99
105
 
100
- type OverlayConfigureEvent = Readonly<{
101
- item: string; // JSON-serialized ContentItem
106
+ type ContentTappedEvent = Readonly<{
107
+ contentId: string;
108
+ index: Int32;
102
109
  }>;
103
110
 
104
- type OverlayActivateEvent = Readonly<{
105
- item: string; // JSON-serialized ContentItem
106
- }>;
111
+ // --- Overlay per-surface event payload types ---
107
112
 
108
- type OverlayResetEvent = Readonly<{
109
- item: string; // JSON-serialized ContentItem
113
+ type OverlayActiveEvent = Readonly<{
114
+ surfaceId: string;
115
+ isActive: boolean;
110
116
  }>;
111
117
 
112
- type OverlayFadeOutEvent = Readonly<{
113
- item: string; // JSON-serialized ContentItem
118
+ type OverlayPlayerStateEvent = Readonly<{
119
+ surfaceId: string;
120
+ playerState: string;
114
121
  }>;
115
122
 
116
- type OverlayRestoreEvent = Readonly<{
117
- item: string; // JSON-serialized ContentItem
123
+ type OverlayMutedEvent = Readonly<{
124
+ surfaceId: string;
125
+ isMuted: boolean;
118
126
  }>;
119
127
 
120
- type ContentTappedEvent = Readonly<{
121
- contentId: string;
122
- index: Int32;
128
+ type OverlayPlaybackRateEvent = Readonly<{
129
+ surfaceId: string;
130
+ playbackRate: Double;
123
131
  }>;
124
132
 
125
- type CarouselOverlayConfigureEvent = Readonly<{
126
- item: string; // JSON-serialized ImageCarouselItem
133
+ type OverlayCaptionsEnabledEvent = Readonly<{
134
+ surfaceId: string;
135
+ captionsEnabled: boolean;
127
136
  }>;
128
137
 
129
- type CarouselOverlayActivateEvent = Readonly<{
130
- item: string; // JSON-serialized ImageCarouselItem
138
+ type OverlayActiveCueEvent = Readonly<{
139
+ surfaceId: string;
140
+ activeCue: string;
131
141
  }>;
132
142
 
133
- type CarouselOverlayResetEvent = Readonly<{}>;
134
-
135
- type CarouselOverlayFadeOutEvent = Readonly<{}>;
136
-
137
- type CarouselOverlayRestoreEvent = Readonly<{}>;
138
-
139
- type OverlayTapEvent = Readonly<{}>;
143
+ type OverlayFeedScrollPhaseEvent = Readonly<{
144
+ surfaceId: string;
145
+ feedScrollPhase: string;
146
+ }>;
140
147
 
141
- type OverlayDoubleTapEvent = Readonly<{
142
- x: Double;
143
- y: Double;
148
+ type OverlayTimeUpdateEvent = Readonly<{
149
+ surfaceId: string;
150
+ current: Double;
151
+ duration: Double;
152
+ buffered: Double;
144
153
  }>;
145
154
 
146
155
  export interface Spec extends TurboModule {
147
156
  // --- Lifecycle ---
148
157
  initialize(
149
158
  apiKey: string,
150
- config: string, // JSON-serialized FeedConfig
151
- embedId?: string,
159
+ hasLoadingView: boolean,
152
160
  clientAppName?: string,
153
161
  clientAppVersion?: string,
154
162
  customDimensions?: string, // JSON-serialized Record<string, string>
@@ -174,9 +182,15 @@ export interface Spec extends TurboModule {
174
182
  setMaxBitrate(bitrate: Double): void;
175
183
 
176
184
  // --- Custom feed ---
177
- setFeedItems(items: string): void;
178
- appendFeedItems(items: string): void;
179
- fetchContent(limit: Int32): Promise<string>;
185
+ setFeedItems(feedId: string, items: string): void;
186
+ appendFeedItems(feedId: string, items: string): void;
187
+ fetchContent(limit: Int32, filterJSON: string | null): Promise<string>;
188
+ applyFilter(feedId: string, filterJSON: string | null): void;
189
+ preloadFeed(configJSON: string): Promise<string>;
190
+
191
+ // --- Storyboard / seek thumbnails ---
192
+ prefetchStoryboard(playbackId: string): void;
193
+ getStoryboardData(playbackId: string): Promise<string>;
180
194
 
181
195
  // --- Event emitters ---
182
196
  readonly onPlayerStateChanged: EventEmitter<PlayerStateEvent>;
@@ -189,25 +203,25 @@ export interface Spec extends TurboModule {
189
203
  readonly onActiveCueChanged: EventEmitter<CueEvent>;
190
204
  readonly onDidLoop: EventEmitter<LoopEvent>;
191
205
  readonly onFeedTransition: EventEmitter<FeedTransitionEvent>;
206
+ readonly onFeedScrollPhase: EventEmitter<FeedScrollPhaseEvent>;
192
207
  readonly onFormatChange: EventEmitter<FormatChangeEvent>;
193
208
  readonly onPrefetchedAheadCountChanged: EventEmitter<PrefetchedAheadCountEvent>;
194
209
  readonly onRemainingContentCountChanged: EventEmitter<RemainingContentCountEvent>;
195
- readonly onError: EventEmitter<ErrorEvent>;
196
- readonly onShareTapped: EventEmitter<ShareTappedEvent>;
197
210
  readonly onSurveyResponse: EventEmitter<SurveyResponseEvent>;
198
- readonly onOverlayConfigure: EventEmitter<OverlayConfigureEvent>;
199
- readonly onOverlayActivate: EventEmitter<OverlayActivateEvent>;
200
- readonly onOverlayReset: EventEmitter<OverlayResetEvent>;
201
- readonly onOverlayFadeOut: EventEmitter<OverlayFadeOutEvent>;
202
- readonly onOverlayRestore: EventEmitter<OverlayRestoreEvent>;
203
- readonly onOverlayTap: EventEmitter<OverlayTapEvent>;
204
- readonly onOverlayDoubleTap: EventEmitter<OverlayDoubleTapEvent>;
205
211
  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>;
212
+ readonly onDismiss: EventEmitter<DismissEvent>;
213
+ readonly onRefreshRequested: EventEmitter<RefreshRequestedEvent>;
214
+ readonly onDidFetchContentItems: EventEmitter<DidFetchContentItemsEvent>;
215
+
216
+ // --- Overlay per-surface events ---
217
+ readonly onOverlayActiveChanged: EventEmitter<OverlayActiveEvent>;
218
+ readonly onOverlayPlayerStateChanged: EventEmitter<OverlayPlayerStateEvent>;
219
+ readonly onOverlayMutedChanged: EventEmitter<OverlayMutedEvent>;
220
+ readonly onOverlayPlaybackRateChanged: EventEmitter<OverlayPlaybackRateEvent>;
221
+ readonly onOverlayCaptionsEnabledChanged: EventEmitter<OverlayCaptionsEnabledEvent>;
222
+ readonly onOverlayActiveCueChanged: EventEmitter<OverlayActiveCueEvent>;
223
+ readonly onOverlayFeedScrollPhaseChanged: EventEmitter<OverlayFeedScrollPhaseEvent>;
224
+ readonly onOverlayTimeUpdate: EventEmitter<OverlayTimeUpdateEvent>;
211
225
  }
212
226
 
213
227
  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,9 +1,20 @@
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;
9
20
  overlay?: OverlayConfig;
@@ -11,6 +22,8 @@ export interface FeedConfig {
11
22
  surveyMode?: SurveyMode;
12
23
  muteOnStart?: boolean;
13
24
  feedSource?: FeedSource;
25
+ autoplay?: boolean;
26
+ filter?: FeedFilter;
14
27
  }
15
28
 
16
29
  export type FeedHeight =
@@ -19,11 +32,11 @@ export type FeedHeight =
19
32
 
20
33
  export type OverlayConfig =
21
34
  | 'none'
22
- | { type: 'custom'; component: React.ComponentType };
35
+ | { type: 'custom'; name: string; component: React.ComponentType<OverlayProps> };
23
36
 
24
37
  export type CarouselOverlayConfig =
25
38
  | 'none'
26
- | { type: 'custom'; component: React.ComponentType };
39
+ | { type: 'custom'; name: string; component: React.ComponentType<CarouselOverlayProps> };
27
40
 
28
41
  export type SurveyMode =
29
42
  | 'none'
@@ -44,6 +57,7 @@ export interface ContentItem {
44
57
  author?: string;
45
58
  articleUrl?: string;
46
59
  commentCount?: number;
60
+ fallbackUrl?: string;
47
61
  }
48
62
 
49
63
  // --- Custom Feed Types ---
@@ -56,7 +70,6 @@ export interface CarouselImage {
56
70
  export interface ImageCarouselItem {
57
71
  id: string;
58
72
  images: CarouselImage[];
59
- autoScrollInterval?: number;
60
73
  caption?: string;
61
74
  title?: string;
62
75
  description?: string;
@@ -65,8 +78,8 @@ export interface ImageCarouselItem {
65
78
  articleUrl?: string;
66
79
  }
67
80
 
68
- export type CustomFeedItem =
69
- | { type: 'video'; playbackId: string }
81
+ export type FeedInput =
82
+ | { type: 'video'; playbackId: string; fallbackUrl?: string }
70
83
  | { type: 'imageCarousel'; item: ImageCarouselItem };
71
84
 
72
85
  export type JSONValue =
@@ -76,10 +89,31 @@ export type JSONValue =
76
89
  | null
77
90
  | { [key: string]: JSONValue };
78
91
 
92
+ // --- Storyboard / Seek Thumbnails ---
93
+
94
+ export interface StoryboardTile {
95
+ start: number;
96
+ x: number;
97
+ y: number;
98
+ }
99
+
100
+ export interface StoryboardData {
101
+ url: string;
102
+ tileWidth: number;
103
+ tileHeight: number;
104
+ duration: number;
105
+ imageWidth: number;
106
+ imageHeight: number;
107
+ tiles: StoryboardTile[];
108
+ }
109
+
79
110
  export interface CaptionTrack {
80
111
  language: string;
81
112
  label: string;
82
- sourceUrl: string;
113
+ source?: CaptionSource;
114
+ url?: string;
115
+ /** @deprecated Use `url` instead. */
116
+ sourceUrl?: string;
83
117
  }
84
118
 
85
119
  export interface PlayerTime {
@@ -111,6 +145,10 @@ export interface FeedTransitionEvent {
111
145
  direction: 'forward' | 'backward';
112
146
  }
113
147
 
148
+ export type FeedScrollPhase =
149
+ | { phase: 'dragging'; fromId: string }
150
+ | { phase: 'settled' };
151
+
114
152
  export interface FormatChangeEvent {
115
153
  contentId: string;
116
154
  fromBitrate: number;
@@ -126,36 +164,86 @@ export interface SurveyOption {
126
164
  text: string;
127
165
  }
128
166
 
129
- export interface ShortKitError {
130
- code: string;
131
- message: string;
167
+ // --- Overlay Props ---
168
+
169
+ /** Props passed to video overlay components rendered inside feed cells. */
170
+ export interface OverlayProps {
171
+ /** The content item for this cell. */
172
+ item: ContentItem;
173
+ /** Whether this cell is the active playback cell. */
174
+ isActive: boolean;
175
+ /** Current player state. */
176
+ playerState: PlayerState;
177
+ /** Current playback time. Only updates when isActive is true. */
178
+ time: PlayerTime;
179
+ /** Whether audio is muted. */
180
+ isMuted: boolean;
181
+ /** Current playback speed. */
182
+ playbackRate: number;
183
+ /** Whether captions are enabled. */
184
+ captionsEnabled: boolean;
185
+ /** The currently active caption cue, or null. */
186
+ activeCue: { text: string; startTime: number; endTime: number } | null;
187
+ /** Current feed scroll phase — use to fade overlay during swipes. */
188
+ feedScrollPhase: FeedScrollPhase | null;
189
+ }
190
+
191
+ /** Props passed to carousel overlay components rendered inside feed cells. */
192
+ export interface CarouselOverlayProps {
193
+ /** The carousel item for this cell. */
194
+ item: ImageCarouselItem;
132
195
  }
133
196
 
134
197
  // --- Provider Props ---
135
198
 
136
199
  export interface ShortKitProviderProps {
137
200
  apiKey: string;
138
- config: FeedConfig;
139
- embedId?: string;
140
201
  userId?: string;
141
202
 
142
203
  clientAppName?: string;
143
204
  clientAppVersion?: string;
144
205
  customDimensions?: Record<string, string>;
145
206
  children: React.ReactNode;
207
+ /** Custom loading view rendered while the feed loads or during filter changes.
208
+ * When omitted, the SDK uses a default spinner. */
209
+ loadingViewComponent?: React.ComponentType<{}>;
146
210
  }
147
211
 
148
212
  // --- Feed Component Props ---
149
213
 
150
214
  export interface ShortKitFeedProps {
215
+ config?: FeedConfig;
216
+ preloadId?: string;
151
217
  style?: ViewStyle;
152
- onError?: (error: ShortKitError) => void;
153
- onShareTapped?: (item: ContentItem) => void;
218
+ /** Item ID to scroll to on initial load. */
219
+ startAtItemId?: string;
154
220
  onSurveyResponse?: (surveyId: string, option: SurveyOption) => void;
155
221
  onLoop?: (event: LoopEvent) => void;
156
222
  onFeedTransition?: (event: FeedTransitionEvent) => void;
157
223
  onFormatChange?: (event: FormatChangeEvent) => void;
158
224
  onContentTapped?: (contentId: string, index: number) => void;
225
+ /** Called when the user dismisses the feed (swipe-down or back gesture). */
226
+ onDismiss?: () => void;
227
+ /** Called when the user pulls to refresh in custom feed mode. */
228
+ onRefreshRequested?: () => void;
229
+ /** Called when the SDK fetches content items from the algorithmic feed.
230
+ * Use to pre-fetch your own metadata for the given items. */
231
+ onDidFetchContentItems?: (items: ContentItem[]) => void;
232
+ /** Called when the number of remaining items in this feed changes. */
233
+ onRemainingContentCountChange?: (count: number) => void;
234
+ }
235
+
236
+ /**
237
+ * Imperative handle for per-feed-instance operations.
238
+ * Obtained via `ref` on `<ShortKitFeed>`.
239
+ */
240
+ export interface ShortKitFeedHandle {
241
+ /** Replace all items in this feed instance. */
242
+ setFeedItems: (items: FeedInput[]) => void;
243
+ /** Append items to this feed instance. */
244
+ appendFeedItems: (items: FeedInput[]) => void;
245
+ /** Apply a content filter to this feed instance. Pass null to clear. */
246
+ applyFilter: (filter: FeedFilter | null) => void;
159
247
  }
160
248
 
161
249
  // --- Single Player Config ---
@@ -211,8 +299,6 @@ export interface ShortKitWidgetProps {
211
299
  export interface ShortKitPlayerState {
212
300
  playerState: PlayerState;
213
301
  currentItem: ContentItem | null;
214
- nextItem: ContentItem | null;
215
- activeCellType: 'video' | 'carousel' | null;
216
302
  time: PlayerTime;
217
303
  isMuted: boolean;
218
304
  playbackRate: number;
@@ -220,11 +306,8 @@ export interface ShortKitPlayerState {
220
306
  activeCaptionTrack: CaptionTrack | null;
221
307
  activeCue: { text: string; startTime: number; endTime: number } | null;
222
308
  prefetchedAheadCount: number;
223
- remainingContentCount: number;
224
309
  isActive: boolean;
225
- isTransitioning: boolean;
226
- lastOverlayTap: number;
227
- lastOverlayDoubleTap: { x: number; y: number; id: number } | null;
310
+ feedScrollPhase: FeedScrollPhase | null;
228
311
 
229
312
  play: () => void;
230
313
  pause: () => void;
@@ -238,4 +321,6 @@ export interface ShortKitPlayerState {
238
321
  selectCaptionTrack: (language: string) => void;
239
322
  sendContentSignal: (signal: ContentSignal) => void;
240
323
  setMaxBitrate: (bitrate: number) => void;
324
+ prefetchStoryboard: (playbackId: string) => void;
325
+ getStoryboardData: (playbackId: string) => Promise<StoryboardData | null>;
241
326
  }
@@ -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,20 +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
- isCarouselTransitioning: _isCarouselTransitioning,
31
- _overlayConfig: _overlay,
32
- _carouselOverlayConfig: _carouselOverlay,
33
32
  ...playerState
34
33
  } = context;
35
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
- }