@shortkitsdk/react-native 0.2.23 → 0.2.25
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/README.md +151 -0
- package/android/libs/shortkit-release.aar +0 -0
- package/android/src/main/java/com/shortkit/reactnative/ReactOverlayHost.kt +19 -1
- package/android/src/main/java/com/shortkit/reactnative/ShortKitBridge.kt +10 -7
- package/android/src/main/java/com/shortkit/reactnative/ShortKitModule.kt +43 -0
- package/ios/ReactCarouselOverlayHost.swift +51 -3
- package/ios/ReactOverlayHost.swift +67 -7
- package/ios/ReactVideoCarouselOverlayHost.swift +181 -19
- package/ios/SKFabricSurfaceWrapper.mm +7 -1
- package/ios/ShortKitBridge.swift +140 -3
- package/ios/ShortKitFeedView.swift +20 -0
- package/ios/ShortKitFeedViewManager.mm +1 -0
- package/ios/ShortKitModule.mm +56 -0
- package/ios/ShortKitSDK.xcframework/Info.plist +5 -5
- package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Info.plist +2 -2
- package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.abi.json +4745 -456
- package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.private.swiftinterface +127 -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 +127 -5
- package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/ShortKitSDK +0 -0
- package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/_CodeSignature/CodeResources +9 -9
- package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Info.plist +2 -2
- package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.abi.json +4745 -456
- package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface +127 -5
- package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.swiftdoc +0 -0
- package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.swiftinterface +127 -5
- package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.abi.json +4745 -456
- package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface +127 -5
- 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 +127 -5
- 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 +17 -17
- package/package.json +1 -1
- package/src/ShortKitCarouselOverlaySurface.tsx +38 -10
- package/src/ShortKitCommands.ts +7 -0
- package/src/ShortKitContext.ts +6 -0
- package/src/ShortKitFeed.tsx +23 -7
- package/src/ShortKitOverlaySurface.tsx +59 -23
- package/src/ShortKitProvider.tsx +45 -1
- package/src/ShortKitVideoCarouselOverlaySurface.tsx +51 -5
- package/src/index.ts +4 -0
- package/src/serialization.ts +37 -1
- package/src/specs/NativeShortKitModule.ts +80 -2
- package/src/specs/ShortKitFeedViewNativeComponent.ts +8 -0
- package/src/types.ts +71 -2
- package/src/useShortKitCarousel.ts +80 -0
|
@@ -109,6 +109,25 @@ type FeedReadyEvent = Readonly<{
|
|
|
109
109
|
feedId: string;
|
|
110
110
|
}>;
|
|
111
111
|
|
|
112
|
+
type DownloadStartedEvent = Readonly<{
|
|
113
|
+
itemId: string;
|
|
114
|
+
}>;
|
|
115
|
+
|
|
116
|
+
type DownloadProgressEvent = Readonly<{
|
|
117
|
+
itemId: string;
|
|
118
|
+
progress: number;
|
|
119
|
+
}>;
|
|
120
|
+
|
|
121
|
+
type DownloadCompletedEvent = Readonly<{
|
|
122
|
+
itemId: string;
|
|
123
|
+
fileUrl: string;
|
|
124
|
+
}>;
|
|
125
|
+
|
|
126
|
+
type DownloadFailedEvent = Readonly<{
|
|
127
|
+
itemId: string;
|
|
128
|
+
error: string;
|
|
129
|
+
}>;
|
|
130
|
+
|
|
112
131
|
// --- Overlay per-surface event payload types ---
|
|
113
132
|
|
|
114
133
|
type OverlayActiveEvent = Readonly<{
|
|
@@ -158,12 +177,38 @@ type CarouselActiveImageEvent = Readonly<{
|
|
|
158
177
|
activeImageIndex: Int32;
|
|
159
178
|
}>;
|
|
160
179
|
|
|
180
|
+
type CarouselItemChangedEvent = Readonly<{
|
|
181
|
+
surfaceId: string;
|
|
182
|
+
item: string; // JSON-serialized ImageCarouselItem (with local file:// URLs where cached)
|
|
183
|
+
isActive: boolean;
|
|
184
|
+
activeImageIndex: Int32;
|
|
185
|
+
}>;
|
|
186
|
+
|
|
161
187
|
type VideoCarouselActiveVideoEvent = Readonly<{
|
|
162
188
|
surfaceId: string;
|
|
163
189
|
activeVideo: string;
|
|
164
190
|
activeVideoIndex: Int32;
|
|
165
191
|
}>;
|
|
166
192
|
|
|
193
|
+
type VideoCarouselItemChangedEvent = Readonly<{
|
|
194
|
+
surfaceId: string;
|
|
195
|
+
carouselItem: string; // JSON-serialized VideoCarouselItem
|
|
196
|
+
activeVideo: string | null; // JSON-serialized ContentItem; null when item has no videos
|
|
197
|
+
activeVideoIndex: Int32;
|
|
198
|
+
isActive: boolean;
|
|
199
|
+
playerState: string;
|
|
200
|
+
isMuted: boolean;
|
|
201
|
+
}>;
|
|
202
|
+
|
|
203
|
+
type CarouselActiveVideoCompletedEvent = Readonly<{
|
|
204
|
+
surfaceId: string;
|
|
205
|
+
contentItem: string; // JSON-serialized ContentItem
|
|
206
|
+
indexInCarousel: Int32;
|
|
207
|
+
carouselItem: string; // JSON-serialized VideoCarouselItem
|
|
208
|
+
wasLast: boolean;
|
|
209
|
+
willAutoAdvance: boolean;
|
|
210
|
+
}>;
|
|
211
|
+
|
|
167
212
|
type OverlayFullStateEvent = Readonly<{
|
|
168
213
|
surfaceId: string;
|
|
169
214
|
isActive: boolean;
|
|
@@ -171,8 +216,20 @@ type OverlayFullStateEvent = Readonly<{
|
|
|
171
216
|
isMuted: boolean;
|
|
172
217
|
playbackRate: Double;
|
|
173
218
|
captionsEnabled: boolean;
|
|
174
|
-
activeCue: string;
|
|
175
|
-
feedScrollPhase: string;
|
|
219
|
+
activeCue: string | null;
|
|
220
|
+
feedScrollPhase: string | null;
|
|
221
|
+
}>;
|
|
222
|
+
|
|
223
|
+
type OverlayItemChangedEvent = Readonly<{
|
|
224
|
+
surfaceId: string;
|
|
225
|
+
item: string; // JSON-serialized ContentItem
|
|
226
|
+
isActive: boolean;
|
|
227
|
+
playerState: string;
|
|
228
|
+
isMuted: boolean;
|
|
229
|
+
playbackRate: Double;
|
|
230
|
+
captionsEnabled: boolean;
|
|
231
|
+
activeCue: string | null;
|
|
232
|
+
feedScrollPhase: string | null;
|
|
176
233
|
}>;
|
|
177
234
|
|
|
178
235
|
export interface Spec extends TurboModule {
|
|
@@ -198,6 +255,9 @@ export interface Spec extends TurboModule {
|
|
|
198
255
|
seekAndPlay(seconds: Double): void;
|
|
199
256
|
skipToNext(): void;
|
|
200
257
|
skipToPrevious(): void;
|
|
258
|
+
carouselNext(): boolean;
|
|
259
|
+
carouselPrevious(): boolean;
|
|
260
|
+
carouselSetActiveIndex(index: Int32): boolean;
|
|
201
261
|
setMuted(muted: boolean): void;
|
|
202
262
|
setPlaybackRate(rate: Double): void;
|
|
203
263
|
setCaptionsEnabled(enabled: boolean): void;
|
|
@@ -216,6 +276,14 @@ export interface Spec extends TurboModule {
|
|
|
216
276
|
prefetchStoryboard(playbackId: string): void;
|
|
217
277
|
getStoryboardData(playbackId: string): Promise<string>;
|
|
218
278
|
|
|
279
|
+
// --- Download ---
|
|
280
|
+
downloadVideo(itemId: string, mode: string): Promise<string>;
|
|
281
|
+
cancelDownload(): void;
|
|
282
|
+
|
|
283
|
+
// --- Carousel accessors ---
|
|
284
|
+
getCarouselActiveIndex(): Int32;
|
|
285
|
+
getCarouselVideoCount(): Int32;
|
|
286
|
+
|
|
219
287
|
// --- Event emitters ---
|
|
220
288
|
readonly onPlayerStateChanged: EventEmitter<PlayerStateEvent>;
|
|
221
289
|
readonly onCurrentItemChanged: EventEmitter<CurrentItemEvent>;
|
|
@@ -247,8 +315,18 @@ export interface Spec extends TurboModule {
|
|
|
247
315
|
readonly onOverlayFeedScrollPhaseChanged: EventEmitter<OverlayFeedScrollPhaseEvent>;
|
|
248
316
|
readonly onOverlayTimeUpdate: EventEmitter<OverlayTimeUpdateEvent>;
|
|
249
317
|
readonly onOverlayFullState: EventEmitter<OverlayFullStateEvent>;
|
|
318
|
+
readonly onOverlayItemChanged: EventEmitter<OverlayItemChangedEvent>;
|
|
250
319
|
readonly onCarouselActiveImageChanged: EventEmitter<CarouselActiveImageEvent>;
|
|
320
|
+
readonly onCarouselItemChanged: EventEmitter<CarouselItemChangedEvent>;
|
|
251
321
|
readonly onVideoCarouselActiveVideoChanged: EventEmitter<VideoCarouselActiveVideoEvent>;
|
|
322
|
+
readonly onVideoCarouselItemChanged: EventEmitter<VideoCarouselItemChangedEvent>;
|
|
323
|
+
readonly onCarouselActiveVideoCompleted: EventEmitter<CarouselActiveVideoCompletedEvent>;
|
|
324
|
+
|
|
325
|
+
// --- Download events ---
|
|
326
|
+
readonly onDownloadStarted: EventEmitter<DownloadStartedEvent>;
|
|
327
|
+
readonly onDownloadProgress: EventEmitter<DownloadProgressEvent>;
|
|
328
|
+
readonly onDownloadCompleted: EventEmitter<DownloadCompletedEvent>;
|
|
329
|
+
readonly onDownloadFailed: EventEmitter<DownloadFailedEvent>;
|
|
252
330
|
}
|
|
253
331
|
|
|
254
332
|
export default TurboModuleRegistry.getEnforcing<Spec>('ShortKitModule');
|
|
@@ -6,6 +6,14 @@ export interface NativeProps extends ViewProps {
|
|
|
6
6
|
feedId?: string;
|
|
7
7
|
startAtItemId?: string;
|
|
8
8
|
preloadId?: string;
|
|
9
|
+
/**
|
|
10
|
+
* URL of a thumbnail already rendered/cached on the host side (e.g. the
|
|
11
|
+
* grid tile the user tapped to open this feed). When expo-image or FastImage
|
|
12
|
+
* is used on iOS, SDK fetches the decoded UIImage from SDWebImage's memory
|
|
13
|
+
* cache and paints it onto the first cell with zero network and zero
|
|
14
|
+
* latency. Falls back to network fetch for non-SDWebImage clients.
|
|
15
|
+
*/
|
|
16
|
+
seedThumbnailUrl?: string;
|
|
9
17
|
}
|
|
10
18
|
|
|
11
19
|
export default codegenNativeComponent<NativeProps>(
|
package/src/types.ts
CHANGED
|
@@ -68,6 +68,21 @@ export interface ContentItem {
|
|
|
68
68
|
articleUrl?: string;
|
|
69
69
|
commentCount?: number;
|
|
70
70
|
fallbackUrl?: string;
|
|
71
|
+
downloadUrl?: string;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export type DownloadStatus = 'idle' | 'downloading' | 'completed' | 'failed';
|
|
75
|
+
|
|
76
|
+
export interface DownloadState {
|
|
77
|
+
status: DownloadStatus;
|
|
78
|
+
/** ID of the content item being downloaded, if any. */
|
|
79
|
+
itemId?: string;
|
|
80
|
+
/** 0.0 to 1.0 progress fraction. */
|
|
81
|
+
progress: number;
|
|
82
|
+
/** Local file URL after successful download. */
|
|
83
|
+
fileUrl?: string;
|
|
84
|
+
/** Error message if download failed. */
|
|
85
|
+
error?: string;
|
|
71
86
|
}
|
|
72
87
|
|
|
73
88
|
// --- Custom Feed Types ---
|
|
@@ -98,10 +113,41 @@ export interface VideoCarouselItem {
|
|
|
98
113
|
articleUrl?: string;
|
|
99
114
|
}
|
|
100
115
|
|
|
116
|
+
export type ContentOrigin = 'ios_upload' | 'other';
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Per-slide input for a VideoCarouselInput. Mirrors the `{ type: 'video' }`
|
|
120
|
+
* FeedInput variant — host apps pass a playback ID and the SDK constructs
|
|
121
|
+
* the streaming and thumbnail URLs internally.
|
|
122
|
+
*/
|
|
123
|
+
export interface VideoCarouselVideoInput {
|
|
124
|
+
playbackId: string;
|
|
125
|
+
origin?: ContentOrigin;
|
|
126
|
+
fallbackUrl?: string;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Compact input type for video carousels passed to
|
|
131
|
+
* `{ type: 'videoCarousel', item: VideoCarouselInput }`.
|
|
132
|
+
*
|
|
133
|
+
* The SDK hydrates each playback ID into a full ContentItem internally
|
|
134
|
+
* before rendering. Overlays continue to receive the fully-hydrated
|
|
135
|
+
* VideoCarouselItem shape via VideoCarouselOverlayProps.carouselItem.
|
|
136
|
+
*/
|
|
137
|
+
export interface VideoCarouselInput {
|
|
138
|
+
id: string;
|
|
139
|
+
videos: VideoCarouselVideoInput[];
|
|
140
|
+
title?: string;
|
|
141
|
+
description?: string;
|
|
142
|
+
author?: string;
|
|
143
|
+
section?: string;
|
|
144
|
+
articleUrl?: string;
|
|
145
|
+
}
|
|
146
|
+
|
|
101
147
|
export type FeedInput =
|
|
102
|
-
| { type: 'video'; playbackId: string; fallbackUrl?: string }
|
|
148
|
+
| { type: 'video'; playbackId: string; origin?: ContentOrigin; fallbackUrl?: string }
|
|
103
149
|
| { type: 'imageCarousel'; item: ImageCarouselItem }
|
|
104
|
-
| { type: 'videoCarousel'; item:
|
|
150
|
+
| { type: 'videoCarousel'; item: VideoCarouselInput };
|
|
105
151
|
|
|
106
152
|
export type JSONValue =
|
|
107
153
|
| string
|
|
@@ -257,6 +303,17 @@ export interface ShortKitFeedProps {
|
|
|
257
303
|
style?: ViewStyle;
|
|
258
304
|
/** Item ID to scroll to on initial load. */
|
|
259
305
|
startAtItemId?: string;
|
|
306
|
+
/**
|
|
307
|
+
* URL of the thumbnail already displayed in your UI (e.g. the grid tile
|
|
308
|
+
* the user just tapped). If your app uses expo-image or FastImage, the SDK
|
|
309
|
+
* will extract the already-decoded UIImage from SDWebImage's memory cache
|
|
310
|
+
* and paint it on the first feed cell with zero network overhead — closing
|
|
311
|
+
* the black-frame gap before video playback begins.
|
|
312
|
+
*
|
|
313
|
+
* Falls back silently (no extra network beyond the existing fallback) for
|
|
314
|
+
* apps on React Native's core <Image> or other image libraries.
|
|
315
|
+
*/
|
|
316
|
+
seedThumbnailUrl?: string;
|
|
260
317
|
onLoop?: (event: LoopEvent) => void;
|
|
261
318
|
onFeedTransition?: (event: FeedTransitionEvent) => void;
|
|
262
319
|
onFormatChange?: (event: FormatChangeEvent) => void;
|
|
@@ -273,6 +330,15 @@ export interface ShortKitFeedProps {
|
|
|
273
330
|
/** Called once when this feed has loaded content and assigned a player
|
|
274
331
|
* to the first cell. Use to dismiss a splash screen or loading overlay. */
|
|
275
332
|
onFeedReady?: () => void;
|
|
333
|
+
/** Called when the active video in a video carousel completes playback. */
|
|
334
|
+
onCarouselActiveVideoCompleted?: (event: {
|
|
335
|
+
surfaceId: string;
|
|
336
|
+
contentItem: ContentItem;
|
|
337
|
+
indexInCarousel: number;
|
|
338
|
+
carouselItem: VideoCarouselItem;
|
|
339
|
+
wasLast: boolean;
|
|
340
|
+
willAutoAdvance: boolean;
|
|
341
|
+
}) => void;
|
|
276
342
|
}
|
|
277
343
|
|
|
278
344
|
/**
|
|
@@ -339,6 +405,9 @@ export interface ShortKitWidgetProps {
|
|
|
339
405
|
|
|
340
406
|
// --- Hook Return Types ---
|
|
341
407
|
|
|
408
|
+
export type { ShortKitCarouselState } from './useShortKitCarousel';
|
|
409
|
+
|
|
410
|
+
|
|
342
411
|
export interface ShortKitPlayerState {
|
|
343
412
|
playerState: PlayerState;
|
|
344
413
|
currentItem: ContentItem | null;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
2
|
+
import NativeShortKitModule from './specs/NativeShortKitModule';
|
|
3
|
+
import { ShortKitCommands } from './ShortKitCommands';
|
|
4
|
+
import type { VideoCarouselItem } from './types';
|
|
5
|
+
|
|
6
|
+
export interface ShortKitCarouselState {
|
|
7
|
+
/** Index of the currently active video in the carousel, or null if no carousel is active. */
|
|
8
|
+
activeIndex: number | null;
|
|
9
|
+
/** Number of videos in the active carousel item, or 0 if none. */
|
|
10
|
+
videoCount: number;
|
|
11
|
+
/** The active carousel item, or null if no carousel is active. */
|
|
12
|
+
activeCarouselItem: VideoCarouselItem | null;
|
|
13
|
+
/** Advance to the next video in the carousel. Returns true if the command was dispatched. */
|
|
14
|
+
next: () => boolean;
|
|
15
|
+
/** Go back to the previous video in the carousel. Returns true if the command was dispatched. */
|
|
16
|
+
previous: () => boolean;
|
|
17
|
+
/** Jump to a specific index in the carousel. Returns true if the command was dispatched. */
|
|
18
|
+
setActiveIndex: (index: number) => boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Hook to access video carousel state and commands.
|
|
23
|
+
*
|
|
24
|
+
* Subscribes to `onVideoCarouselItemChanged` and
|
|
25
|
+
* `onVideoCarouselActiveVideoChanged` from the native TurboModule and surfaces
|
|
26
|
+
* carousel state as reactive values. The imperative commands (`next`,
|
|
27
|
+
* `previous`, `setActiveIndex`) delegate to `ShortKitCommands`.
|
|
28
|
+
*
|
|
29
|
+
* Does not require a `<ShortKitProvider>` — it subscribes directly to native
|
|
30
|
+
* events and is suitable for use inside overlay components.
|
|
31
|
+
*/
|
|
32
|
+
export function useShortKitCarousel(): ShortKitCarouselState {
|
|
33
|
+
const [activeIndex, setActiveIndexState] = useState<number | null>(() => {
|
|
34
|
+
const v = NativeShortKitModule?.getCarouselActiveIndex?.() ?? -1;
|
|
35
|
+
return v < 0 ? null : v;
|
|
36
|
+
});
|
|
37
|
+
const [activeCarouselItem, setActiveCarouselItem] = useState<VideoCarouselItem | null>(null);
|
|
38
|
+
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
if (!NativeShortKitModule) return;
|
|
41
|
+
const subItem = NativeShortKitModule.onVideoCarouselItemChanged((e: any) => {
|
|
42
|
+
try {
|
|
43
|
+
const item = e.carouselItem
|
|
44
|
+
? (JSON.parse(e.carouselItem) as VideoCarouselItem)
|
|
45
|
+
: null;
|
|
46
|
+
setActiveCarouselItem(item);
|
|
47
|
+
setActiveIndexState(
|
|
48
|
+
typeof e.activeVideoIndex === 'number' ? e.activeVideoIndex : null,
|
|
49
|
+
);
|
|
50
|
+
} catch {
|
|
51
|
+
// ignore parse errors
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
const subIdx = NativeShortKitModule.onVideoCarouselActiveVideoChanged((e: any) => {
|
|
55
|
+
setActiveIndexState(
|
|
56
|
+
typeof e.activeVideoIndex === 'number' ? e.activeVideoIndex : null,
|
|
57
|
+
);
|
|
58
|
+
});
|
|
59
|
+
return () => {
|
|
60
|
+
subItem?.remove?.();
|
|
61
|
+
subIdx?.remove?.();
|
|
62
|
+
};
|
|
63
|
+
}, []);
|
|
64
|
+
|
|
65
|
+
const next = useCallback(() => ShortKitCommands.carouselNext(), []);
|
|
66
|
+
const previous = useCallback(() => ShortKitCommands.carouselPrevious(), []);
|
|
67
|
+
const setActiveIndex = useCallback(
|
|
68
|
+
(i: number) => ShortKitCommands.carouselSetActiveIndex(i),
|
|
69
|
+
[],
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
activeIndex,
|
|
74
|
+
videoCount: activeCarouselItem?.videos?.length ?? 0,
|
|
75
|
+
activeCarouselItem,
|
|
76
|
+
next,
|
|
77
|
+
previous,
|
|
78
|
+
setActiveIndex,
|
|
79
|
+
};
|
|
80
|
+
}
|