@shortkitsdk/react-native 0.2.6 → 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.
- package/ShortKitReactNative.podspec +1 -0
- package/android/build.gradle.kts +5 -1
- package/android/src/main/java/com/shortkit/reactnative/ReactCarouselOverlayHost.kt +319 -0
- package/android/src/main/java/com/shortkit/reactnative/ReactLoadingHost.kt +40 -0
- package/android/src/main/java/com/shortkit/reactnative/ReactOverlayHost.kt +559 -0
- package/android/src/main/java/com/shortkit/reactnative/ShortKitBridge.kt +984 -0
- package/android/src/main/java/com/shortkit/reactnative/ShortKitFeedView.kt +88 -220
- package/android/src/main/java/com/shortkit/reactnative/ShortKitFeedViewManager.kt +12 -3
- package/android/src/main/java/com/shortkit/reactnative/ShortKitModule.kt +123 -741
- package/android/src/main/java/com/shortkit/reactnative/ShortKitPlayerNativeView.kt +2 -2
- package/android/src/main/java/com/shortkit/reactnative/ShortKitWidgetNativeView.kt +2 -2
- package/ios/ReactCarouselOverlayHost.swift +177 -0
- package/ios/ReactLoadingHost.swift +38 -0
- package/ios/ReactOverlayHost.swift +458 -0
- package/ios/SKFabricSurfaceWrapper.h +18 -0
- package/ios/SKFabricSurfaceWrapper.mm +57 -0
- package/ios/ShortKitBridge.swift +186 -63
- package/ios/ShortKitFeedView.swift +62 -229
- package/ios/ShortKitFeedViewManager.mm +3 -2
- package/ios/ShortKitModule.mm +66 -37
- package/ios/ShortKitPlayerNativeView.swift +39 -8
- package/ios/ShortKitReactNative-Bridging-Header.h +2 -0
- package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Headers/ShortKitSDK-Swift.h +1 -1
- package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.abi.json +2380 -522
- package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.private.swiftinterface +39 -12
- package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.swiftdoc +0 -0
- package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.swiftinterface +39 -12
- package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/ShortKitSDK +0 -0
- package/ios/ShortKitSDK.xcframework/ios-arm64-simulator/ShortKitSDK.framework/Headers/ShortKitSDK-Swift.h +1 -1
- package/ios/ShortKitSDK.xcframework/ios-arm64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.abi.json +2380 -522
- package/ios/ShortKitSDK.xcframework/ios-arm64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface +39 -12
- package/ios/ShortKitSDK.xcframework/ios-arm64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.swiftdoc +0 -0
- package/ios/ShortKitSDK.xcframework/ios-arm64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.swiftinterface +39 -12
- package/ios/ShortKitSDK.xcframework/ios-arm64-simulator/ShortKitSDK.framework/ShortKitSDK +0 -0
- package/ios/ShortKitSDK.xcframework.bak/Info.plist +43 -0
- package/ios/ShortKitSDK.xcframework.bak/ios-arm64/ShortKitSDK.framework/Headers/ShortKitSDK-Swift.h +418 -0
- package/ios/ShortKitSDK.xcframework.bak/ios-arm64/ShortKitSDK.framework/Info.plist +16 -0
- package/ios/ShortKitSDK.xcframework.bak/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.abi.json +28917 -0
- package/ios/ShortKitSDK.xcframework.bak/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.private.swiftinterface +824 -0
- package/ios/ShortKitSDK.xcframework.bak/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.swiftdoc +0 -0
- package/ios/ShortKitSDK.xcframework.bak/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.swiftinterface +824 -0
- package/ios/ShortKitSDK.xcframework.bak/ios-arm64/ShortKitSDK.framework/Modules/module.modulemap +4 -0
- package/ios/ShortKitSDK.xcframework.bak/ios-arm64/ShortKitSDK.framework/ShortKitSDK +0 -0
- package/ios/ShortKitSDK.xcframework.bak/ios-arm64-simulator/ShortKitSDK.framework/Headers/ShortKitSDK-Swift.h +418 -0
- package/ios/ShortKitSDK.xcframework.bak/ios-arm64-simulator/ShortKitSDK.framework/Info.plist +16 -0
- package/ios/ShortKitSDK.xcframework.bak/ios-arm64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.abi.json +28917 -0
- package/ios/ShortKitSDK.xcframework.bak/ios-arm64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface +824 -0
- package/ios/ShortKitSDK.xcframework.bak/ios-arm64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.swiftdoc +0 -0
- package/ios/ShortKitSDK.xcframework.bak/ios-arm64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.swiftinterface +824 -0
- package/ios/ShortKitSDK.xcframework.bak/ios-arm64-simulator/ShortKitSDK.framework/Modules/module.modulemap +4 -0
- package/ios/ShortKitSDK.xcframework.bak/ios-arm64-simulator/ShortKitSDK.framework/ShortKitSDK +0 -0
- package/ios/ShortKitWidgetNativeView.swift +3 -3
- package/package.json +1 -1
- package/src/ShortKitCarouselOverlaySurface.tsx +55 -0
- package/src/ShortKitCommands.ts +31 -0
- package/src/ShortKitContext.ts +6 -25
- package/src/ShortKitFeed.tsx +110 -41
- package/src/ShortKitLoadingSurface.tsx +24 -0
- package/src/ShortKitOverlaySurface.tsx +205 -0
- package/src/ShortKitPlayer.tsx +6 -7
- package/src/ShortKitProvider.tsx +27 -286
- package/src/index.ts +5 -3
- package/src/serialization.ts +19 -39
- package/src/specs/NativeShortKitModule.ts +58 -46
- package/src/specs/ShortKitFeedViewNativeComponent.ts +3 -2
- package/src/types.ts +78 -16
- package/src/useShortKit.ts +1 -3
- package/src/useShortKitPlayer.ts +7 -7
- package/android/src/main/java/com/shortkit/reactnative/ShortKitCarouselOverlayBridge.kt +0 -48
- package/android/src/main/java/com/shortkit/reactnative/ShortKitOverlayBridge.kt +0 -128
- package/ios/ShortKitCarouselOverlayBridge.swift +0 -219
- package/ios/ShortKitOverlayBridge.swift +0 -111
- package/src/CarouselOverlayManager.tsx +0 -70
- package/src/OverlayManager.tsx +0 -87
- 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
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}>;
|
|
92
|
+
type DismissEvent = Readonly<{}>;
|
|
93
|
+
|
|
94
|
+
type RefreshRequestedEvent = Readonly<{}>;
|
|
94
95
|
|
|
95
|
-
type
|
|
96
|
-
|
|
96
|
+
type DidFetchContentItemsEvent = Readonly<{
|
|
97
|
+
items: string; // JSON-serialized ContentItem[]
|
|
97
98
|
}>;
|
|
98
99
|
|
|
99
100
|
type SurveyResponseEvent = Readonly<{
|
|
@@ -102,50 +103,60 @@ type SurveyResponseEvent = Readonly<{
|
|
|
102
103
|
optionText: string;
|
|
103
104
|
}>;
|
|
104
105
|
|
|
105
|
-
type
|
|
106
|
-
|
|
106
|
+
type ContentTappedEvent = Readonly<{
|
|
107
|
+
contentId: string;
|
|
108
|
+
index: Int32;
|
|
107
109
|
}>;
|
|
108
110
|
|
|
109
|
-
|
|
110
|
-
item: string; // JSON-serialized ContentItem
|
|
111
|
-
}>;
|
|
111
|
+
// --- Overlay per-surface event payload types ---
|
|
112
112
|
|
|
113
|
-
type
|
|
114
|
-
|
|
113
|
+
type OverlayActiveEvent = Readonly<{
|
|
114
|
+
surfaceId: string;
|
|
115
|
+
isActive: boolean;
|
|
115
116
|
}>;
|
|
116
117
|
|
|
117
|
-
type
|
|
118
|
-
|
|
119
|
-
|
|
118
|
+
type OverlayPlayerStateEvent = Readonly<{
|
|
119
|
+
surfaceId: string;
|
|
120
|
+
playerState: string;
|
|
120
121
|
}>;
|
|
121
122
|
|
|
122
|
-
type
|
|
123
|
-
|
|
123
|
+
type OverlayMutedEvent = Readonly<{
|
|
124
|
+
surfaceId: string;
|
|
125
|
+
isMuted: boolean;
|
|
124
126
|
}>;
|
|
125
127
|
|
|
126
|
-
type
|
|
127
|
-
|
|
128
|
+
type OverlayPlaybackRateEvent = Readonly<{
|
|
129
|
+
surfaceId: string;
|
|
130
|
+
playbackRate: Double;
|
|
128
131
|
}>;
|
|
129
132
|
|
|
130
|
-
type
|
|
133
|
+
type OverlayCaptionsEnabledEvent = Readonly<{
|
|
134
|
+
surfaceId: string;
|
|
135
|
+
captionsEnabled: boolean;
|
|
136
|
+
}>;
|
|
131
137
|
|
|
132
|
-
type
|
|
133
|
-
|
|
134
|
-
|
|
138
|
+
type OverlayActiveCueEvent = Readonly<{
|
|
139
|
+
surfaceId: string;
|
|
140
|
+
activeCue: string;
|
|
135
141
|
}>;
|
|
136
142
|
|
|
137
|
-
type
|
|
143
|
+
type OverlayFeedScrollPhaseEvent = Readonly<{
|
|
144
|
+
surfaceId: string;
|
|
145
|
+
feedScrollPhase: string;
|
|
146
|
+
}>;
|
|
138
147
|
|
|
139
|
-
type
|
|
140
|
-
|
|
141
|
-
|
|
148
|
+
type OverlayTimeUpdateEvent = Readonly<{
|
|
149
|
+
surfaceId: string;
|
|
150
|
+
current: Double;
|
|
151
|
+
duration: Double;
|
|
152
|
+
buffered: Double;
|
|
142
153
|
}>;
|
|
143
154
|
|
|
144
155
|
export interface Spec extends TurboModule {
|
|
145
156
|
// --- Lifecycle ---
|
|
146
157
|
initialize(
|
|
147
158
|
apiKey: string,
|
|
148
|
-
|
|
159
|
+
hasLoadingView: boolean,
|
|
149
160
|
clientAppName?: string,
|
|
150
161
|
clientAppVersion?: string,
|
|
151
162
|
customDimensions?: string, // JSON-serialized Record<string, string>
|
|
@@ -171,17 +182,16 @@ export interface Spec extends TurboModule {
|
|
|
171
182
|
setMaxBitrate(bitrate: Double): void;
|
|
172
183
|
|
|
173
184
|
// --- Custom feed ---
|
|
174
|
-
setFeedItems(items: string): void;
|
|
175
|
-
appendFeedItems(items: string): void;
|
|
176
|
-
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>;
|
|
177
190
|
|
|
178
191
|
// --- Storyboard / seek thumbnails ---
|
|
179
192
|
prefetchStoryboard(playbackId: string): void;
|
|
180
193
|
getStoryboardData(playbackId: string): Promise<string>;
|
|
181
194
|
|
|
182
|
-
// --- Overlay lifecycle ---
|
|
183
|
-
notifyOverlayReady(): void;
|
|
184
|
-
|
|
185
195
|
// --- Event emitters ---
|
|
186
196
|
readonly onPlayerStateChanged: EventEmitter<PlayerStateEvent>;
|
|
187
197
|
readonly onCurrentItemChanged: EventEmitter<CurrentItemEvent>;
|
|
@@ -197,19 +207,21 @@ export interface Spec extends TurboModule {
|
|
|
197
207
|
readonly onFormatChange: EventEmitter<FormatChangeEvent>;
|
|
198
208
|
readonly onPrefetchedAheadCountChanged: EventEmitter<PrefetchedAheadCountEvent>;
|
|
199
209
|
readonly onRemainingContentCountChanged: EventEmitter<RemainingContentCountEvent>;
|
|
200
|
-
readonly onError: EventEmitter<ErrorEvent>;
|
|
201
|
-
readonly onShareTapped: EventEmitter<ShareTappedEvent>;
|
|
202
210
|
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
211
|
readonly onContentTapped: EventEmitter<ContentTappedEvent>;
|
|
209
|
-
readonly
|
|
210
|
-
readonly
|
|
211
|
-
readonly
|
|
212
|
-
|
|
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>;
|
|
213
225
|
}
|
|
214
226
|
|
|
215
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
|
-
|
|
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;
|
|
@@ -66,7 +79,7 @@ export interface ImageCarouselItem {
|
|
|
66
79
|
}
|
|
67
80
|
|
|
68
81
|
export type FeedInput =
|
|
69
|
-
| { type: 'video'; playbackId: string }
|
|
82
|
+
| { type: 'video'; playbackId: string; fallbackUrl?: string }
|
|
70
83
|
| { type: 'imageCarousel'; item: ImageCarouselItem };
|
|
71
84
|
|
|
72
85
|
export type JSONValue =
|
|
@@ -97,7 +110,10 @@ export interface StoryboardData {
|
|
|
97
110
|
export interface CaptionTrack {
|
|
98
111
|
language: string;
|
|
99
112
|
label: string;
|
|
100
|
-
|
|
113
|
+
source?: CaptionSource;
|
|
114
|
+
url?: string;
|
|
115
|
+
/** @deprecated Use `url` instead. */
|
|
116
|
+
sourceUrl?: string;
|
|
101
117
|
}
|
|
102
118
|
|
|
103
119
|
export interface PlayerTime {
|
|
@@ -148,35 +164,86 @@ export interface SurveyOption {
|
|
|
148
164
|
text: string;
|
|
149
165
|
}
|
|
150
166
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
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;
|
|
154
195
|
}
|
|
155
196
|
|
|
156
197
|
// --- Provider Props ---
|
|
157
198
|
|
|
158
199
|
export interface ShortKitProviderProps {
|
|
159
200
|
apiKey: string;
|
|
160
|
-
config: FeedConfig;
|
|
161
201
|
userId?: string;
|
|
162
202
|
|
|
163
203
|
clientAppName?: string;
|
|
164
204
|
clientAppVersion?: string;
|
|
165
205
|
customDimensions?: Record<string, string>;
|
|
166
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<{}>;
|
|
167
210
|
}
|
|
168
211
|
|
|
169
212
|
// --- Feed Component Props ---
|
|
170
213
|
|
|
171
214
|
export interface ShortKitFeedProps {
|
|
215
|
+
config?: FeedConfig;
|
|
216
|
+
preloadId?: string;
|
|
172
217
|
style?: ViewStyle;
|
|
173
|
-
|
|
174
|
-
|
|
218
|
+
/** Item ID to scroll to on initial load. */
|
|
219
|
+
startAtItemId?: string;
|
|
175
220
|
onSurveyResponse?: (surveyId: string, option: SurveyOption) => void;
|
|
176
221
|
onLoop?: (event: LoopEvent) => void;
|
|
177
222
|
onFeedTransition?: (event: FeedTransitionEvent) => void;
|
|
178
223
|
onFormatChange?: (event: FormatChangeEvent) => void;
|
|
179
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;
|
|
180
247
|
}
|
|
181
248
|
|
|
182
249
|
// --- Single Player Config ---
|
|
@@ -232,8 +299,6 @@ export interface ShortKitWidgetProps {
|
|
|
232
299
|
export interface ShortKitPlayerState {
|
|
233
300
|
playerState: PlayerState;
|
|
234
301
|
currentItem: ContentItem | null;
|
|
235
|
-
nextItem: ContentItem | null;
|
|
236
|
-
activeCellType: 'video' | 'carousel' | null;
|
|
237
302
|
time: PlayerTime;
|
|
238
303
|
isMuted: boolean;
|
|
239
304
|
playbackRate: number;
|
|
@@ -241,11 +306,8 @@ export interface ShortKitPlayerState {
|
|
|
241
306
|
activeCaptionTrack: CaptionTrack | null;
|
|
242
307
|
activeCue: { text: string; startTime: number; endTime: number } | null;
|
|
243
308
|
prefetchedAheadCount: number;
|
|
244
|
-
remainingContentCount: number;
|
|
245
309
|
isActive: boolean;
|
|
246
310
|
feedScrollPhase: FeedScrollPhase | null;
|
|
247
|
-
lastOverlayTap: number;
|
|
248
|
-
lastOverlayDoubleTap: { x: number; y: number; id: number } | null;
|
|
249
311
|
|
|
250
312
|
play: () => void;
|
|
251
313
|
pause: () => void;
|
package/src/useShortKit.ts
CHANGED
|
@@ -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
|
-
|
|
20
|
+
preloadFeed: context.preloadFeed,
|
|
23
21
|
};
|
|
24
22
|
}
|
package/src/useShortKitPlayer.ts
CHANGED
|
@@ -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
|
-
}
|