@shortkitsdk/react-native 0.2.12 → 0.2.15
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/android/src/main/java/com/shortkit/reactnative/ReactCarouselOverlayHost.kt +47 -4
- package/android/src/main/java/com/shortkit/reactnative/ReactVideoCarouselOverlayHost.kt +431 -0
- package/android/src/main/java/com/shortkit/reactnative/ShortKitBridge.kt +117 -2
- package/android/src/main/java/com/shortkit/reactnative/ShortKitModule.kt +7 -5
- package/ios/ReactCarouselOverlayHost.swift +67 -35
- package/ios/ReactOverlayHost.swift +85 -75
- package/ios/ReactVideoCarouselOverlayHost.swift +283 -0
- package/ios/ShortKitBridge.swift +122 -20
- package/ios/ShortKitModule.mm +15 -5
- package/ios/ShortKitSDK.xcframework/Info.plist +5 -4
- package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Headers/ShortKitSDK-Swift.h +1 -0
- package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Info.plist +5 -1
- package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.abi.json +2488 -281
- package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.private.swiftinterface +65 -5
- 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 +65 -5
- package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/ShortKitSDK +0 -0
- package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/_CodeSignature/CodeResources +168 -0
- package/ios/{ShortKitSDK.xcframework.bak/ios-arm64-simulator → ShortKitSDK.xcframework/ios-arm64_x86_64-simulator}/ShortKitSDK.framework/Headers/ShortKitSDK-Swift.h +2 -1
- package/ios/ShortKitSDK.xcframework/{ios-arm64-simulator → ios-arm64_x86_64-simulator}/ShortKitSDK.framework/Info.plist +5 -1
- package/ios/{ShortKitSDK.xcframework.bak/ios-arm64-simulator → ShortKitSDK.xcframework/ios-arm64_x86_64-simulator}/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.abi.json +8233 -3592
- package/ios/{ShortKitSDK.xcframework.bak/ios-arm64-simulator → ShortKitSDK.xcframework/ios-arm64_x86_64-simulator}/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface +120 -19
- package/ios/{ShortKitSDK.xcframework.bak/ios-arm64-simulator → ShortKitSDK.xcframework/ios-arm64_x86_64-simulator}/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.swiftdoc +0 -0
- package/ios/{ShortKitSDK.xcframework.bak/ios-arm64-simulator → ShortKitSDK.xcframework/ios-arm64_x86_64-simulator}/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.swiftinterface +120 -19
- package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.abi.json +33558 -0
- package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface +925 -0
- package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.swiftdoc +0 -0
- package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.swiftinterface +925 -0
- package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/ShortKitSDK +0 -0
- package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/_CodeSignature/CodeResources +212 -0
- package/ios/{ShortKitSDK.xcframework.bak → ShortKitSDK.xcframework.dev-backup}/ios-arm64/ShortKitSDK.framework/Headers/ShortKitSDK-Swift.h +1 -1
- package/ios/{ShortKitSDK.xcframework.bak → ShortKitSDK.xcframework.dev-backup}/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.abi.json +7338 -3272
- package/ios/{ShortKitSDK.xcframework.bak → ShortKitSDK.xcframework.dev-backup}/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.private.swiftinterface +106 -15
- package/ios/{ShortKitSDK.xcframework.bak → ShortKitSDK.xcframework.dev-backup}/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.swiftdoc +0 -0
- package/ios/{ShortKitSDK.xcframework.bak → ShortKitSDK.xcframework.dev-backup}/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.swiftinterface +106 -15
- package/ios/ShortKitSDK.xcframework.dev-backup/ios-arm64/ShortKitSDK.framework/ShortKitSDK +0 -0
- package/ios/ShortKitSDK.xcframework.dev-backup/ios-arm64/ShortKitSDK.framework/_CodeSignature/CodeResources +168 -0
- package/ios/{ShortKitSDK.xcframework → ShortKitSDK.xcframework.dev-backup}/ios-arm64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.abi.json +1838 -206
- package/ios/{ShortKitSDK.xcframework → ShortKitSDK.xcframework.dev-backup}/ios-arm64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface +51 -1
- package/ios/{ShortKitSDK.xcframework → ShortKitSDK.xcframework.dev-backup}/ios-arm64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.swiftdoc +0 -0
- package/ios/{ShortKitSDK.xcframework → ShortKitSDK.xcframework.dev-backup}/ios-arm64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.swiftinterface +51 -1
- package/ios/ShortKitSDK.xcframework.dev-backup/ios-arm64-simulator/ShortKitSDK.framework/ShortKitSDK +0 -0
- package/ios/ShortKitSDK.xcframework.dev-backup/ios-arm64-simulator/ShortKitSDK.framework/_CodeSignature/CodeResources +168 -0
- package/package.json +1 -1
- package/src/ShortKitCarouselOverlaySurface.tsx +57 -2
- package/src/ShortKitContext.ts +11 -0
- package/src/ShortKitFeed.tsx +25 -10
- package/src/ShortKitOverlaySurface.tsx +24 -11
- package/src/ShortKitProvider.tsx +4 -2
- package/src/ShortKitVideoCarouselOverlaySurface.tsx +156 -0
- package/src/ShortKitWidget.tsx +3 -3
- package/src/index.ts +5 -1
- package/src/serialization.ts +7 -0
- package/src/specs/NativeShortKitModule.ts +18 -2
- package/src/types.ts +48 -3
- package/ios/ShortKitSDK.xcframework/ios-arm64-simulator/ShortKitSDK.framework/ShortKitSDK +0 -0
- package/ios/ShortKitSDK.xcframework.bak/ios-arm64/ShortKitSDK.framework/ShortKitSDK +0 -0
- package/ios/ShortKitSDK.xcframework.bak/ios-arm64-simulator/ShortKitSDK.framework/ShortKitSDK +0 -0
- package/ios/ShortKitSDK.xcframework/{ios-arm64-simulator → ios-arm64_x86_64-simulator}/ShortKitSDK.framework/Modules/module.modulemap +0 -0
- package/ios/{ShortKitSDK.xcframework.bak → ShortKitSDK.xcframework.dev-backup}/Info.plist +4 -4
- /package/ios/{ShortKitSDK.xcframework.bak → ShortKitSDK.xcframework.dev-backup}/ios-arm64/ShortKitSDK.framework/Info.plist +0 -0
- /package/ios/{ShortKitSDK.xcframework.bak → ShortKitSDK.xcframework.dev-backup}/ios-arm64/ShortKitSDK.framework/Modules/module.modulemap +0 -0
- /package/ios/{ShortKitSDK.xcframework → ShortKitSDK.xcframework.dev-backup}/ios-arm64-simulator/ShortKitSDK.framework/Headers/ShortKitSDK-Swift.h +0 -0
- /package/ios/{ShortKitSDK.xcframework.bak → ShortKitSDK.xcframework.dev-backup}/ios-arm64-simulator/ShortKitSDK.framework/Info.plist +0 -0
- /package/ios/{ShortKitSDK.xcframework.bak → ShortKitSDK.xcframework.dev-backup}/ios-arm64-simulator/ShortKitSDK.framework/Modules/module.modulemap +0 -0
|
@@ -161,6 +161,8 @@ function ShortKitOverlaySurfaceInner(props: InnerProps) {
|
|
|
161
161
|
const [activeCue, setActiveCue] = useState<OverlayProps['activeCue']>(
|
|
162
162
|
props.activeCue ? JSON.parse(props.activeCue) : null,
|
|
163
163
|
);
|
|
164
|
+
// Track raw JSON string to avoid re-parsing unchanged cues
|
|
165
|
+
const lastActiveCueJsonRef = React.useRef<string | null>(props.activeCue ?? null);
|
|
164
166
|
const [feedScrollPhase, setFeedScrollPhase] =
|
|
165
167
|
useState<FeedScrollPhase | null>(
|
|
166
168
|
props.feedScrollPhase ? JSON.parse(props.feedScrollPhase) : null,
|
|
@@ -176,7 +178,9 @@ function ShortKitOverlaySurfaceInner(props: InnerProps) {
|
|
|
176
178
|
setIsMuted(props.isMuted ?? true);
|
|
177
179
|
setPlaybackRate(props.playbackRate ?? 1);
|
|
178
180
|
setCaptionsEnabled(props.captionsEnabled ?? false);
|
|
179
|
-
|
|
181
|
+
const rawCue = props.activeCue ?? null;
|
|
182
|
+
lastActiveCueJsonRef.current = rawCue;
|
|
183
|
+
setActiveCue(rawCue ? JSON.parse(rawCue) : null);
|
|
180
184
|
setFeedScrollPhase(
|
|
181
185
|
props.feedScrollPhase ? JSON.parse(props.feedScrollPhase) : null,
|
|
182
186
|
);
|
|
@@ -229,7 +233,12 @@ function ShortKitOverlaySurfaceInner(props: InnerProps) {
|
|
|
229
233
|
|
|
230
234
|
useOverlayEvent<{ surfaceId: string; activeCue: string | null }>(
|
|
231
235
|
'onOverlayActiveCueChanged', sid,
|
|
232
|
-
(e) =>
|
|
236
|
+
(e) => {
|
|
237
|
+
const raw = e.activeCue ?? null;
|
|
238
|
+
if (raw === lastActiveCueJsonRef.current) return;
|
|
239
|
+
lastActiveCueJsonRef.current = raw;
|
|
240
|
+
setActiveCue(raw ? JSON.parse(raw) : null);
|
|
241
|
+
},
|
|
233
242
|
);
|
|
234
243
|
|
|
235
244
|
useOverlayEvent<{ surfaceId: string; feedScrollPhase: string | null }>(
|
|
@@ -252,11 +261,10 @@ function ShortKitOverlaySurfaceInner(props: InnerProps) {
|
|
|
252
261
|
},
|
|
253
262
|
);
|
|
254
263
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
// );
|
|
264
|
+
useOverlayEvent<{ surfaceId: string; current: number; duration: number; buffered: number }>(
|
|
265
|
+
'onOverlayTimeUpdate', sid,
|
|
266
|
+
(e) => setTime({ current: e.current, duration: e.duration, buffered: e.buffered }),
|
|
267
|
+
);
|
|
260
268
|
|
|
261
269
|
// Batched full-state sync — replaces 7 individual events on swipe settle.
|
|
262
270
|
// All setState calls within one handler = one React render (auto-batched).
|
|
@@ -275,10 +283,15 @@ function ShortKitOverlaySurfaceInner(props: InnerProps) {
|
|
|
275
283
|
setIsMuted(e.isMuted);
|
|
276
284
|
setPlaybackRate(e.playbackRate);
|
|
277
285
|
setCaptionsEnabled(e.captionsEnabled);
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
286
|
+
// Only re-parse activeCue if the raw JSON string actually changed
|
|
287
|
+
const rawCue = e.activeCue ?? null;
|
|
288
|
+
if (rawCue !== lastActiveCueJsonRef.current) {
|
|
289
|
+
lastActiveCueJsonRef.current = rawCue;
|
|
290
|
+
try {
|
|
291
|
+
setActiveCue(rawCue ? JSON.parse(rawCue) : null);
|
|
292
|
+
} catch {
|
|
293
|
+
setActiveCue(null);
|
|
294
|
+
}
|
|
282
295
|
}
|
|
283
296
|
try {
|
|
284
297
|
const next = e.feedScrollPhase ? JSON.parse(e.feedScrollPhase) : null;
|
package/src/ShortKitProvider.tsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useMemo, useReducer, useRef } from 'react';
|
|
2
2
|
import { AppState } from 'react-native';
|
|
3
3
|
import type { AppStateStatus } from 'react-native';
|
|
4
|
-
import { ShortKitContext } from './ShortKitContext';
|
|
4
|
+
import { ShortKitContext, ShortKitInitContext } from './ShortKitContext';
|
|
5
5
|
import type { ShortKitContextValue } from './ShortKitContext';
|
|
6
6
|
import type {
|
|
7
7
|
ShortKitProviderProps,
|
|
@@ -500,6 +500,8 @@ export function ShortKitProvider({
|
|
|
500
500
|
);
|
|
501
501
|
|
|
502
502
|
return (
|
|
503
|
-
<
|
|
503
|
+
<ShortKitInitContext.Provider value={true}>
|
|
504
|
+
<ShortKitContext.Provider value={value}>{children}</ShortKitContext.Provider>
|
|
505
|
+
</ShortKitInitContext.Provider>
|
|
504
506
|
);
|
|
505
507
|
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import React, { useState, useEffect, useMemo } from 'react';
|
|
2
|
+
import { AppRegistry } from 'react-native';
|
|
3
|
+
import type { VideoCarouselOverlayProps, VideoCarouselItem, ContentItem, PlayerTime, PlayerState } from './types';
|
|
4
|
+
import NativeShortKitModule from './specs/NativeShortKitModule';
|
|
5
|
+
|
|
6
|
+
const _videoCarouselRegistry = new Map<string, React.ComponentType<VideoCarouselOverlayProps>>();
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Register a named video carousel overlay component for rendering inside feed cells.
|
|
10
|
+
* Called by ShortKitFeed on mount via useLayoutEffect.
|
|
11
|
+
* Idempotent — registering the same name twice is a no-op.
|
|
12
|
+
*/
|
|
13
|
+
export function registerVideoCarouselOverlayComponent(
|
|
14
|
+
name: string,
|
|
15
|
+
component: React.ComponentType<VideoCarouselOverlayProps>,
|
|
16
|
+
) {
|
|
17
|
+
if (_videoCarouselRegistry.has(name)) return;
|
|
18
|
+
_videoCarouselRegistry.set(name, component);
|
|
19
|
+
|
|
20
|
+
const moduleName = `ShortKitVideoCarouselOverlay_${name}`;
|
|
21
|
+
AppRegistry.registerComponent(moduleName, () => {
|
|
22
|
+
return function NamedVideoCarouselSurface(props: RawProps) {
|
|
23
|
+
return <VideoCarouselSurfaceInner {...props} overlayName={name} />;
|
|
24
|
+
};
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Subscribe to a named native event, filtered by surfaceId. */
|
|
29
|
+
function useOverlayEvent<T extends { surfaceId: string }>(
|
|
30
|
+
eventName: string,
|
|
31
|
+
surfaceId: string | undefined,
|
|
32
|
+
handler: (event: T) => void,
|
|
33
|
+
) {
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
if (!surfaceId) return;
|
|
36
|
+
|
|
37
|
+
let sub: { remove: () => void } | undefined;
|
|
38
|
+
const emitter = NativeShortKitModule?.[eventName as keyof typeof NativeShortKitModule];
|
|
39
|
+
if (typeof emitter === 'function') {
|
|
40
|
+
sub = (emitter as (cb: (e: T) => void) => { remove: () => void })((e: T) => {
|
|
41
|
+
if (e.surfaceId !== surfaceId) return;
|
|
42
|
+
handler(e);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return () => sub?.remove();
|
|
47
|
+
}, [surfaceId]);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
interface RawProps {
|
|
51
|
+
surfaceId?: string;
|
|
52
|
+
carouselItem?: string;
|
|
53
|
+
activeVideo?: string;
|
|
54
|
+
activeVideoIndex?: number;
|
|
55
|
+
isActive?: boolean;
|
|
56
|
+
playerState?: string;
|
|
57
|
+
isMuted?: boolean;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
interface InnerProps extends RawProps {
|
|
61
|
+
overlayName: string;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function VideoCarouselSurfaceInner(props: InnerProps) {
|
|
65
|
+
const Component = _videoCarouselRegistry.get(props.overlayName);
|
|
66
|
+
if (!Component) return null;
|
|
67
|
+
|
|
68
|
+
const sid = props.surfaceId;
|
|
69
|
+
|
|
70
|
+
// Playback state — initialized from surface props, updated via events
|
|
71
|
+
const [isActive, setIsActive] = useState(props.isActive ?? false);
|
|
72
|
+
const [playerState, setPlayerState] = useState<PlayerState>((props.playerState as PlayerState) ?? 'idle');
|
|
73
|
+
const [isMuted, setIsMuted] = useState(props.isMuted ?? true);
|
|
74
|
+
const [time, setTime] = useState<PlayerTime>({ current: 0, duration: 0, buffered: 0 });
|
|
75
|
+
|
|
76
|
+
// Batched full-state sync
|
|
77
|
+
useOverlayEvent<{
|
|
78
|
+
surfaceId: string;
|
|
79
|
+
isActive: boolean;
|
|
80
|
+
playerState: string;
|
|
81
|
+
isMuted: boolean;
|
|
82
|
+
playbackRate: number;
|
|
83
|
+
captionsEnabled: boolean;
|
|
84
|
+
activeCue: string | null;
|
|
85
|
+
feedScrollPhase: string | null;
|
|
86
|
+
}>('onOverlayFullState', sid, (e) => {
|
|
87
|
+
setIsActive(e.isActive);
|
|
88
|
+
setPlayerState(e.playerState as PlayerState);
|
|
89
|
+
setIsMuted(e.isMuted);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// Individual state updates
|
|
93
|
+
useOverlayEvent<{ surfaceId: string; playerState: string }>(
|
|
94
|
+
'onOverlayPlayerStateChanged', sid,
|
|
95
|
+
(e) => setPlayerState(e.playerState as PlayerState),
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
useOverlayEvent<{ surfaceId: string; isMuted: boolean }>(
|
|
99
|
+
'onOverlayMutedChanged', sid,
|
|
100
|
+
(e) => setIsMuted(e.isMuted),
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
// Time updates (250ms coalesced)
|
|
104
|
+
useOverlayEvent<{ surfaceId: string; current: number; duration: number; buffered: number }>(
|
|
105
|
+
'onOverlayTimeUpdate', sid,
|
|
106
|
+
(e) => setTime({ current: e.current, duration: e.duration, buffered: e.buffered }),
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
// Carousel item — from surface props (set once in configure())
|
|
110
|
+
const carouselItem: VideoCarouselItem | null = useMemo(() => {
|
|
111
|
+
if (!props.carouselItem) return null;
|
|
112
|
+
try { return JSON.parse(props.carouselItem); } catch { return null; }
|
|
113
|
+
}, [props.carouselItem]);
|
|
114
|
+
|
|
115
|
+
// Active video — initialized from surface props, updated via events on swipe
|
|
116
|
+
const initialActiveVideo: ContentItem | null = useMemo(() => {
|
|
117
|
+
if (!props.activeVideo) return null;
|
|
118
|
+
try { return JSON.parse(props.activeVideo); } catch { return null; }
|
|
119
|
+
}, [props.activeVideo]);
|
|
120
|
+
|
|
121
|
+
const [activeVideo, setActiveVideo] = useState<ContentItem | null>(initialActiveVideo);
|
|
122
|
+
const [activeVideoIndex, setActiveVideoIndex] = useState(props.activeVideoIndex ?? 0);
|
|
123
|
+
|
|
124
|
+
// Sync from props when surface is reconfigured (new carousel item)
|
|
125
|
+
useEffect(() => {
|
|
126
|
+
setActiveVideo(initialActiveVideo);
|
|
127
|
+
setActiveVideoIndex(props.activeVideoIndex ?? 0);
|
|
128
|
+
}, [initialActiveVideo]);
|
|
129
|
+
|
|
130
|
+
// Active video changes via event (no Fabric remount)
|
|
131
|
+
useOverlayEvent<{ surfaceId: string; activeVideo: string; activeVideoIndex: number }>(
|
|
132
|
+
'onVideoCarouselActiveVideoChanged', sid,
|
|
133
|
+
(e) => {
|
|
134
|
+
try {
|
|
135
|
+
setActiveVideo(JSON.parse(e.activeVideo));
|
|
136
|
+
} catch {
|
|
137
|
+
// ignore parse errors
|
|
138
|
+
}
|
|
139
|
+
setActiveVideoIndex(e.activeVideoIndex);
|
|
140
|
+
},
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
if (!carouselItem || !activeVideo) return null;
|
|
144
|
+
|
|
145
|
+
return (
|
|
146
|
+
<Component
|
|
147
|
+
carouselItem={carouselItem}
|
|
148
|
+
activeVideo={activeVideo}
|
|
149
|
+
activeVideoIndex={activeVideoIndex}
|
|
150
|
+
isActive={isActive}
|
|
151
|
+
time={time}
|
|
152
|
+
playerState={playerState}
|
|
153
|
+
isMuted={isMuted}
|
|
154
|
+
/>
|
|
155
|
+
);
|
|
156
|
+
}
|
package/src/ShortKitWidget.tsx
CHANGED
|
@@ -2,7 +2,7 @@ import React, { useContext, useMemo } from 'react';
|
|
|
2
2
|
import { View, StyleSheet } from 'react-native';
|
|
3
3
|
import type { ShortKitWidgetProps } from './types';
|
|
4
4
|
import ShortKitWidgetView from './specs/ShortKitWidgetViewNativeComponent';
|
|
5
|
-
import {
|
|
5
|
+
import { ShortKitInitContext } from './ShortKitContext';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Horizontal carousel widget component. Displays a row of video cards
|
|
@@ -13,8 +13,8 @@ import { ShortKitContext } from './ShortKitContext';
|
|
|
13
13
|
export function ShortKitWidget(props: ShortKitWidgetProps) {
|
|
14
14
|
const { config, items, style } = props;
|
|
15
15
|
|
|
16
|
-
const
|
|
17
|
-
if (!
|
|
16
|
+
const isInitialized = useContext(ShortKitInitContext);
|
|
17
|
+
if (!isInitialized) {
|
|
18
18
|
throw new Error('ShortKitWidget must be used within a ShortKitProvider');
|
|
19
19
|
}
|
|
20
20
|
|
package/src/index.ts
CHANGED
|
@@ -11,6 +11,7 @@ export type {
|
|
|
11
11
|
FeedSource,
|
|
12
12
|
OverlayConfig,
|
|
13
13
|
CarouselOverlayConfig,
|
|
14
|
+
VideoCarouselOverlayConfig,
|
|
14
15
|
SurveyMode,
|
|
15
16
|
|
|
16
17
|
PlayerConfig,
|
|
@@ -20,6 +21,7 @@ export type {
|
|
|
20
21
|
ContentItem,
|
|
21
22
|
CarouselImage,
|
|
22
23
|
ImageCarouselItem,
|
|
24
|
+
VideoCarouselItem,
|
|
23
25
|
FeedInput,
|
|
24
26
|
JSONValue,
|
|
25
27
|
CaptionTrack,
|
|
@@ -39,6 +41,7 @@ export type {
|
|
|
39
41
|
ShortKitPlayerProps,
|
|
40
42
|
ShortKitWidgetProps,
|
|
41
43
|
ShortKitPlayerState,
|
|
44
|
+
ShortKitRefreshState,
|
|
42
45
|
StoryboardData,
|
|
43
46
|
StoryboardTile,
|
|
44
47
|
} from './types';
|
|
@@ -46,4 +49,5 @@ export { ShortKitCommands } from './ShortKitCommands';
|
|
|
46
49
|
export { default as NativeShortKitModule } from './specs/NativeShortKitModule';
|
|
47
50
|
export { registerOverlayComponent } from './ShortKitOverlaySurface';
|
|
48
51
|
export { registerCarouselOverlayComponent } from './ShortKitCarouselOverlaySurface';
|
|
49
|
-
export
|
|
52
|
+
export { registerVideoCarouselOverlayComponent } from './ShortKitVideoCarouselOverlaySurface';
|
|
53
|
+
export type { OverlayProps, CarouselOverlayProps, VideoCarouselOverlayProps } from './types';
|
package/src/serialization.ts
CHANGED
|
@@ -25,11 +25,18 @@ export function serializeFeedConfig(config: FeedConfig): string {
|
|
|
25
25
|
return JSON.stringify({ type: 'custom', name: raw.name });
|
|
26
26
|
})();
|
|
27
27
|
|
|
28
|
+
const videoCarouselOverlay = (() => {
|
|
29
|
+
const raw = config.videoCarouselOverlay ?? 'none';
|
|
30
|
+
if (typeof raw === 'string') return JSON.stringify(raw);
|
|
31
|
+
return JSON.stringify({ type: 'custom', name: raw.name });
|
|
32
|
+
})();
|
|
33
|
+
|
|
28
34
|
return JSON.stringify({
|
|
29
35
|
feedHeight: JSON.stringify(config.feedHeight ?? { type: 'fullscreen' }),
|
|
30
36
|
scrollAxis: config.scrollAxis ?? 'vertical',
|
|
31
37
|
overlay,
|
|
32
38
|
carouselOverlay,
|
|
39
|
+
videoCarouselOverlay,
|
|
33
40
|
surveyMode: JSON.stringify(config.surveyMode ?? 'none'),
|
|
34
41
|
muteOnStart: config.muteOnStart ?? true,
|
|
35
42
|
feedSource: config.feedSource ?? 'algorithmic',
|
|
@@ -91,7 +91,10 @@ type RemainingContentCountEvent = Readonly<{
|
|
|
91
91
|
|
|
92
92
|
type DismissEvent = Readonly<{}>;
|
|
93
93
|
|
|
94
|
-
type
|
|
94
|
+
type RefreshStateChangedEvent = Readonly<{
|
|
95
|
+
status: string;
|
|
96
|
+
progress: Double;
|
|
97
|
+
}>;
|
|
95
98
|
|
|
96
99
|
type DidFetchContentItemsEvent = Readonly<{
|
|
97
100
|
items: string; // JSON-serialized ContentItem[]
|
|
@@ -156,6 +159,17 @@ type OverlayTimeUpdateEvent = Readonly<{
|
|
|
156
159
|
buffered: Double;
|
|
157
160
|
}>;
|
|
158
161
|
|
|
162
|
+
type CarouselActiveImageEvent = Readonly<{
|
|
163
|
+
surfaceId: string;
|
|
164
|
+
activeImageIndex: Int32;
|
|
165
|
+
}>;
|
|
166
|
+
|
|
167
|
+
type VideoCarouselActiveVideoEvent = Readonly<{
|
|
168
|
+
surfaceId: string;
|
|
169
|
+
activeVideo: string;
|
|
170
|
+
activeVideoIndex: Int32;
|
|
171
|
+
}>;
|
|
172
|
+
|
|
159
173
|
type OverlayFullStateEvent = Readonly<{
|
|
160
174
|
surfaceId: string;
|
|
161
175
|
isActive: boolean;
|
|
@@ -225,7 +239,7 @@ export interface Spec extends TurboModule {
|
|
|
225
239
|
readonly onSurveyResponse: EventEmitter<SurveyResponseEvent>;
|
|
226
240
|
readonly onContentTapped: EventEmitter<ContentTappedEvent>;
|
|
227
241
|
readonly onDismiss: EventEmitter<DismissEvent>;
|
|
228
|
-
readonly
|
|
242
|
+
readonly onRefreshStateChanged: EventEmitter<RefreshStateChangedEvent>;
|
|
229
243
|
readonly onDidFetchContentItems: EventEmitter<DidFetchContentItemsEvent>;
|
|
230
244
|
readonly onFeedReady: EventEmitter<FeedReadyEvent>;
|
|
231
245
|
|
|
@@ -239,6 +253,8 @@ export interface Spec extends TurboModule {
|
|
|
239
253
|
readonly onOverlayFeedScrollPhaseChanged: EventEmitter<OverlayFeedScrollPhaseEvent>;
|
|
240
254
|
readonly onOverlayTimeUpdate: EventEmitter<OverlayTimeUpdateEvent>;
|
|
241
255
|
readonly onOverlayFullState: EventEmitter<OverlayFullStateEvent>;
|
|
256
|
+
readonly onCarouselActiveImageChanged: EventEmitter<CarouselActiveImageEvent>;
|
|
257
|
+
readonly onVideoCarouselActiveVideoChanged: EventEmitter<VideoCarouselActiveVideoEvent>;
|
|
242
258
|
}
|
|
243
259
|
|
|
244
260
|
export default TurboModuleRegistry.getEnforcing<Spec>('ShortKitModule');
|
package/src/types.ts
CHANGED
|
@@ -15,16 +15,24 @@ export interface FeedFilter {
|
|
|
15
15
|
|
|
16
16
|
export type CaptionSource = 'embedded' | 'external' | 'generated';
|
|
17
17
|
|
|
18
|
+
export type ShortKitRefreshState =
|
|
19
|
+
| { status: 'idle' }
|
|
20
|
+
| { status: 'pulling'; progress: number }
|
|
21
|
+
| { status: 'triggered' }
|
|
22
|
+
| { status: 'refreshing' };
|
|
23
|
+
|
|
18
24
|
export interface FeedConfig {
|
|
19
25
|
feedHeight?: FeedHeight;
|
|
20
26
|
scrollAxis?: ScrollAxis;
|
|
21
27
|
overlay?: OverlayConfig;
|
|
22
28
|
carouselOverlay?: CarouselOverlayConfig;
|
|
29
|
+
videoCarouselOverlay?: VideoCarouselOverlayConfig;
|
|
23
30
|
surveyMode?: SurveyMode;
|
|
24
31
|
muteOnStart?: boolean;
|
|
25
32
|
feedSource?: FeedSource;
|
|
26
33
|
autoplay?: boolean;
|
|
27
34
|
filter?: FeedFilter;
|
|
35
|
+
pullToRefreshEnabled?: boolean;
|
|
28
36
|
}
|
|
29
37
|
|
|
30
38
|
export type FeedHeight =
|
|
@@ -41,6 +49,10 @@ export type CarouselOverlayConfig =
|
|
|
41
49
|
| 'none'
|
|
42
50
|
| { type: 'custom'; name: string; component: React.ComponentType<CarouselOverlayProps> };
|
|
43
51
|
|
|
52
|
+
export type VideoCarouselOverlayConfig =
|
|
53
|
+
| 'none'
|
|
54
|
+
| { type: 'custom'; name: string; component: React.ComponentType<VideoCarouselOverlayProps> };
|
|
55
|
+
|
|
44
56
|
export type SurveyMode =
|
|
45
57
|
| 'none'
|
|
46
58
|
| { type: 'template'; name: 'default' };
|
|
@@ -81,9 +93,20 @@ export interface ImageCarouselItem {
|
|
|
81
93
|
articleUrl?: string;
|
|
82
94
|
}
|
|
83
95
|
|
|
96
|
+
export interface VideoCarouselItem {
|
|
97
|
+
id: string;
|
|
98
|
+
videos: ContentItem[];
|
|
99
|
+
title?: string;
|
|
100
|
+
description?: string;
|
|
101
|
+
author?: string;
|
|
102
|
+
section?: string;
|
|
103
|
+
articleUrl?: string;
|
|
104
|
+
}
|
|
105
|
+
|
|
84
106
|
export type FeedInput =
|
|
85
107
|
| { type: 'video'; playbackId: string; fallbackUrl?: string }
|
|
86
|
-
| { type: 'imageCarousel'; item: ImageCarouselItem }
|
|
108
|
+
| { type: 'imageCarousel'; item: ImageCarouselItem }
|
|
109
|
+
| { type: 'videoCarousel'; item: VideoCarouselItem };
|
|
87
110
|
|
|
88
111
|
export type JSONValue =
|
|
89
112
|
| string
|
|
@@ -195,6 +218,28 @@ export interface OverlayProps {
|
|
|
195
218
|
export interface CarouselOverlayProps {
|
|
196
219
|
/** The carousel item for this cell. */
|
|
197
220
|
item: ImageCarouselItem;
|
|
221
|
+
/** Whether this carousel cell is the active (on-screen) cell. */
|
|
222
|
+
isActive: boolean;
|
|
223
|
+
/** Index of the currently visible image within the carousel. */
|
|
224
|
+
activeImageIndex: number;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/** Props passed to video carousel overlay components rendered inside feed cells. */
|
|
228
|
+
export interface VideoCarouselOverlayProps {
|
|
229
|
+
/** The video carousel item for this cell. */
|
|
230
|
+
carouselItem: VideoCarouselItem;
|
|
231
|
+
/** The currently active video within the carousel. */
|
|
232
|
+
activeVideo: ContentItem;
|
|
233
|
+
/** Index of the currently active video within the carousel. */
|
|
234
|
+
activeVideoIndex: number;
|
|
235
|
+
/** Whether this carousel cell is the active (on-screen) cell. */
|
|
236
|
+
isActive: boolean;
|
|
237
|
+
/** Current playback time for the active video. */
|
|
238
|
+
time: PlayerTime;
|
|
239
|
+
/** Current player state for the active video. */
|
|
240
|
+
playerState: PlayerState;
|
|
241
|
+
/** Whether audio is muted. */
|
|
242
|
+
isMuted: boolean;
|
|
198
243
|
}
|
|
199
244
|
|
|
200
245
|
// --- Provider Props ---
|
|
@@ -227,8 +272,8 @@ export interface ShortKitFeedProps {
|
|
|
227
272
|
onContentTapped?: (contentId: string, index: number) => void;
|
|
228
273
|
/** Called when the user dismisses the feed (swipe-down or back gesture). */
|
|
229
274
|
onDismiss?: () => void;
|
|
230
|
-
/** Called when the
|
|
231
|
-
|
|
275
|
+
/** Called when the pull-to-refresh state changes. */
|
|
276
|
+
onRefreshStateChanged?: (state: ShortKitRefreshState) => void;
|
|
232
277
|
/** Called when the SDK fetches content items from the algorithmic feed.
|
|
233
278
|
* Use to pre-fetch your own metadata for the given items. */
|
|
234
279
|
onDidFetchContentItems?: (items: ContentItem[]) => void;
|
|
Binary file
|
|
Binary file
|
package/ios/ShortKitSDK.xcframework.bak/ios-arm64-simulator/ShortKitSDK.framework/ShortKitSDK
DELETED
|
Binary file
|
|
File without changes
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<key>BinaryPath</key>
|
|
9
9
|
<string>ShortKitSDK.framework/ShortKitSDK</string>
|
|
10
10
|
<key>LibraryIdentifier</key>
|
|
11
|
-
<string>ios-arm64
|
|
11
|
+
<string>ios-arm64</string>
|
|
12
12
|
<key>LibraryPath</key>
|
|
13
13
|
<string>ShortKitSDK.framework</string>
|
|
14
14
|
<key>SupportedArchitectures</key>
|
|
@@ -17,14 +17,12 @@
|
|
|
17
17
|
</array>
|
|
18
18
|
<key>SupportedPlatform</key>
|
|
19
19
|
<string>ios</string>
|
|
20
|
-
<key>SupportedPlatformVariant</key>
|
|
21
|
-
<string>simulator</string>
|
|
22
20
|
</dict>
|
|
23
21
|
<dict>
|
|
24
22
|
<key>BinaryPath</key>
|
|
25
23
|
<string>ShortKitSDK.framework/ShortKitSDK</string>
|
|
26
24
|
<key>LibraryIdentifier</key>
|
|
27
|
-
<string>ios-arm64</string>
|
|
25
|
+
<string>ios-arm64-simulator</string>
|
|
28
26
|
<key>LibraryPath</key>
|
|
29
27
|
<string>ShortKitSDK.framework</string>
|
|
30
28
|
<key>SupportedArchitectures</key>
|
|
@@ -33,6 +31,8 @@
|
|
|
33
31
|
</array>
|
|
34
32
|
<key>SupportedPlatform</key>
|
|
35
33
|
<string>ios</string>
|
|
34
|
+
<key>SupportedPlatformVariant</key>
|
|
35
|
+
<string>simulator</string>
|
|
36
36
|
</dict>
|
|
37
37
|
</array>
|
|
38
38
|
<key>CFBundlePackageType</key>
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|