@shortkitsdk/react-native 0.2.0 → 0.2.1
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/ShortKitModule.kt +117 -1
- package/android/src/main/java/com/shortkit/reactnative/ShortKitPackage.kt +5 -1
- package/android/src/main/java/com/shortkit/reactnative/ShortKitPlayerNativeView.kt +136 -0
- package/android/src/main/java/com/shortkit/reactnative/ShortKitPlayerViewManager.kt +35 -0
- package/android/src/main/java/com/shortkit/reactnative/ShortKitWidgetNativeView.kt +133 -0
- package/android/src/main/java/com/shortkit/reactnative/ShortKitWidgetViewManager.kt +30 -0
- package/ios/ShortKitBridge.swift +88 -1
- package/ios/ShortKitModule.mm +22 -0
- package/ios/ShortKitPlayerNativeView.swift +186 -0
- package/ios/ShortKitPlayerNativeViewManager.mm +28 -0
- package/ios/ShortKitWidgetNativeView.swift +168 -0
- package/ios/ShortKitWidgetNativeViewManager.mm +27 -0
- package/package.json +1 -1
- package/src/ShortKitContext.ts +5 -0
- package/src/ShortKitFeed.tsx +10 -0
- package/src/ShortKitPlayer.tsx +61 -0
- package/src/ShortKitProvider.tsx +43 -0
- package/src/ShortKitWidget.tsx +63 -0
- package/src/index.ts +12 -0
- package/src/serialization.ts +10 -0
- package/src/specs/NativeShortKitModule.ts +18 -0
- package/src/specs/ShortKitPlayerViewNativeComponent.ts +13 -0
- package/src/specs/ShortKitWidgetViewNativeComponent.ts +12 -0
- package/src/types.ts +78 -0
- package/src/useShortKit.ts +5 -1
package/src/ShortKitProvider.tsx
CHANGED
|
@@ -6,6 +6,7 @@ import type { ShortKitContextValue } from './ShortKitContext';
|
|
|
6
6
|
import type {
|
|
7
7
|
ShortKitProviderProps,
|
|
8
8
|
ContentItem,
|
|
9
|
+
CustomFeedItem,
|
|
9
10
|
PlayerTime,
|
|
10
11
|
PlayerState,
|
|
11
12
|
CaptionTrack,
|
|
@@ -13,6 +14,7 @@ import type {
|
|
|
13
14
|
} from './types';
|
|
14
15
|
import {
|
|
15
16
|
serializeFeedConfigForModule,
|
|
17
|
+
serializeCustomFeedItems,
|
|
16
18
|
deserializePlayerState,
|
|
17
19
|
deserializeContentItem,
|
|
18
20
|
deserializePlayerTime,
|
|
@@ -34,6 +36,7 @@ interface State {
|
|
|
34
36
|
activeCaptionTrack: CaptionTrack | null;
|
|
35
37
|
activeCue: { text: string; startTime: number; endTime: number } | null;
|
|
36
38
|
prefetchedAheadCount: number;
|
|
39
|
+
remainingContentCount: number;
|
|
37
40
|
isActive: boolean;
|
|
38
41
|
isTransitioning: boolean;
|
|
39
42
|
lastOverlayTap: number;
|
|
@@ -51,6 +54,7 @@ const initialState: State = {
|
|
|
51
54
|
activeCaptionTrack: null,
|
|
52
55
|
activeCue: null,
|
|
53
56
|
prefetchedAheadCount: 0,
|
|
57
|
+
remainingContentCount: 0,
|
|
54
58
|
isActive: false,
|
|
55
59
|
isTransitioning: false,
|
|
56
60
|
lastOverlayTap: 0,
|
|
@@ -67,6 +71,7 @@ type Action =
|
|
|
67
71
|
| { type: 'CAPTION_TRACK'; payload: CaptionTrack | null }
|
|
68
72
|
| { type: 'CUE'; payload: { text: string; startTime: number; endTime: number } | null }
|
|
69
73
|
| { type: 'PREFETCH_COUNT'; payload: number }
|
|
74
|
+
| { type: 'REMAINING_COUNT'; payload: number }
|
|
70
75
|
| { type: 'OVERLAY_CONFIGURE'; payload: ContentItem }
|
|
71
76
|
| { type: 'OVERLAY_ACTIVATE'; payload: ContentItem }
|
|
72
77
|
| { type: 'OVERLAY_RESET' }
|
|
@@ -108,6 +113,8 @@ function reducer(state: State, action: Action): State {
|
|
|
108
113
|
return { ...state, activeCue: action.payload };
|
|
109
114
|
case 'PREFETCH_COUNT':
|
|
110
115
|
return { ...state, prefetchedAheadCount: action.payload };
|
|
116
|
+
case 'REMAINING_COUNT':
|
|
117
|
+
return { ...state, remainingContentCount: action.payload };
|
|
111
118
|
case 'OVERLAY_CONFIGURE':
|
|
112
119
|
return { ...state, nextItem: action.payload };
|
|
113
120
|
case 'OVERLAY_ACTIVATE':
|
|
@@ -145,6 +152,7 @@ function reducer(state: State, action: Action): State {
|
|
|
145
152
|
export function ShortKitProvider({
|
|
146
153
|
apiKey,
|
|
147
154
|
config,
|
|
155
|
+
embedId,
|
|
148
156
|
userId,
|
|
149
157
|
clientAppName,
|
|
150
158
|
clientAppVersion,
|
|
@@ -168,6 +176,7 @@ export function ShortKitProvider({
|
|
|
168
176
|
NativeShortKitModule.initialize(
|
|
169
177
|
apiKey,
|
|
170
178
|
serializedConfig,
|
|
179
|
+
embedId,
|
|
171
180
|
clientAppName,
|
|
172
181
|
clientAppVersion,
|
|
173
182
|
serializedDimensions,
|
|
@@ -245,6 +254,7 @@ export function ShortKitProvider({
|
|
|
245
254
|
NativeShortKitModule.onCurrentItemChanged((event) => {
|
|
246
255
|
const item: ContentItem = {
|
|
247
256
|
id: event.id,
|
|
257
|
+
playbackId: event.playbackId,
|
|
248
258
|
title: event.title,
|
|
249
259
|
description: event.description,
|
|
250
260
|
duration: event.duration,
|
|
@@ -327,6 +337,13 @@ export function ShortKitProvider({
|
|
|
327
337
|
}),
|
|
328
338
|
);
|
|
329
339
|
|
|
340
|
+
// Remaining content count
|
|
341
|
+
subscriptions.push(
|
|
342
|
+
NativeShortKitModule.onRemainingContentCountChanged((event) => {
|
|
343
|
+
dispatch({ type: 'REMAINING_COUNT', payload: event.count });
|
|
344
|
+
}),
|
|
345
|
+
);
|
|
346
|
+
|
|
330
347
|
// Overlay lifecycle events
|
|
331
348
|
subscriptions.push(
|
|
332
349
|
NativeShortKitModule.onOverlayConfigure((event) => {
|
|
@@ -450,6 +467,24 @@ export function ShortKitProvider({
|
|
|
450
467
|
NativeShortKitModule?.clearUserId();
|
|
451
468
|
}, []);
|
|
452
469
|
|
|
470
|
+
const setFeedItemsCmd = useCallback((items: CustomFeedItem[]) => {
|
|
471
|
+
NativeShortKitModule?.setFeedItems(serializeCustomFeedItems(items));
|
|
472
|
+
}, []);
|
|
473
|
+
|
|
474
|
+
const appendFeedItemsCmd = useCallback((items: CustomFeedItem[]) => {
|
|
475
|
+
NativeShortKitModule?.appendFeedItems(serializeCustomFeedItems(items));
|
|
476
|
+
}, []);
|
|
477
|
+
|
|
478
|
+
const fetchContentCmd = useCallback(async (limit: number = 10): Promise<ContentItem[]> => {
|
|
479
|
+
if (!NativeShortKitModule) return [];
|
|
480
|
+
const json = await NativeShortKitModule.fetchContent(limit);
|
|
481
|
+
try {
|
|
482
|
+
return JSON.parse(json) as ContentItem[];
|
|
483
|
+
} catch {
|
|
484
|
+
return [];
|
|
485
|
+
}
|
|
486
|
+
}, []);
|
|
487
|
+
|
|
453
488
|
// -----------------------------------------------------------------------
|
|
454
489
|
// Context value (memoized to avoid unnecessary re-renders)
|
|
455
490
|
// -----------------------------------------------------------------------
|
|
@@ -466,6 +501,7 @@ export function ShortKitProvider({
|
|
|
466
501
|
activeCaptionTrack: state.activeCaptionTrack,
|
|
467
502
|
activeCue: state.activeCue,
|
|
468
503
|
prefetchedAheadCount: state.prefetchedAheadCount,
|
|
504
|
+
remainingContentCount: state.remainingContentCount,
|
|
469
505
|
isActive: state.isActive,
|
|
470
506
|
isTransitioning: state.isTransitioning,
|
|
471
507
|
lastOverlayTap: state.lastOverlayTap,
|
|
@@ -486,6 +522,9 @@ export function ShortKitProvider({
|
|
|
486
522
|
setMaxBitrate,
|
|
487
523
|
setUserId: setUserIdCmd,
|
|
488
524
|
clearUserId: clearUserIdCmd,
|
|
525
|
+
setFeedItems: setFeedItemsCmd,
|
|
526
|
+
appendFeedItems: appendFeedItemsCmd,
|
|
527
|
+
fetchContent: fetchContentCmd,
|
|
489
528
|
|
|
490
529
|
// Internal — consumed by ShortKitFeed to pass to OverlayManager
|
|
491
530
|
_overlayConfig: config.overlay ?? 'none',
|
|
@@ -501,6 +540,7 @@ export function ShortKitProvider({
|
|
|
501
540
|
state.activeCaptionTrack,
|
|
502
541
|
state.activeCue,
|
|
503
542
|
state.prefetchedAheadCount,
|
|
543
|
+
state.remainingContentCount,
|
|
504
544
|
state.isActive,
|
|
505
545
|
state.isTransitioning,
|
|
506
546
|
state.lastOverlayTap,
|
|
@@ -519,6 +559,9 @@ export function ShortKitProvider({
|
|
|
519
559
|
setMaxBitrate,
|
|
520
560
|
setUserIdCmd,
|
|
521
561
|
clearUserIdCmd,
|
|
562
|
+
setFeedItemsCmd,
|
|
563
|
+
appendFeedItemsCmd,
|
|
564
|
+
fetchContentCmd,
|
|
522
565
|
config.overlay,
|
|
523
566
|
],
|
|
524
567
|
);
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import React, { useContext, useMemo } from 'react';
|
|
2
|
+
import { View, StyleSheet } from 'react-native';
|
|
3
|
+
import type { ShortKitWidgetProps } from './types';
|
|
4
|
+
import ShortKitWidgetView from './specs/ShortKitWidgetViewNativeComponent';
|
|
5
|
+
import { ShortKitContext } from './ShortKitContext';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Horizontal carousel widget component. Displays a row of video cards
|
|
9
|
+
* with automatic rotation. Wraps a native Fabric view.
|
|
10
|
+
*
|
|
11
|
+
* Must be rendered inside a `<ShortKitProvider>`.
|
|
12
|
+
*/
|
|
13
|
+
export function ShortKitWidget(props: ShortKitWidgetProps) {
|
|
14
|
+
const { config, items, style } = props;
|
|
15
|
+
|
|
16
|
+
const context = useContext(ShortKitContext);
|
|
17
|
+
if (!context) {
|
|
18
|
+
throw new Error('ShortKitWidget must be used within a ShortKitProvider');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const serializedConfig = useMemo(() => {
|
|
22
|
+
const cfg = config ?? {};
|
|
23
|
+
return JSON.stringify({
|
|
24
|
+
cardCount: cfg.cardCount ?? 3,
|
|
25
|
+
cardSpacing: cfg.cardSpacing ?? 8,
|
|
26
|
+
cornerRadius: cfg.cornerRadius ?? 12,
|
|
27
|
+
autoplay: cfg.autoplay ?? true,
|
|
28
|
+
muteOnStart: cfg.muteOnStart ?? true,
|
|
29
|
+
loop: cfg.loop ?? true,
|
|
30
|
+
rotationInterval: cfg.rotationInterval ?? 10000,
|
|
31
|
+
clickAction: cfg.clickAction ?? 'feed',
|
|
32
|
+
overlay: cfg.overlay
|
|
33
|
+
? typeof cfg.overlay === 'string'
|
|
34
|
+
? cfg.overlay
|
|
35
|
+
: { type: 'custom' }
|
|
36
|
+
: 'none',
|
|
37
|
+
});
|
|
38
|
+
}, [config]);
|
|
39
|
+
|
|
40
|
+
const serializedItems = useMemo(() => {
|
|
41
|
+
if (!items || items.length === 0) return undefined;
|
|
42
|
+
return JSON.stringify(items);
|
|
43
|
+
}, [items]);
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<View style={[styles.container, style]}>
|
|
47
|
+
<ShortKitWidgetView
|
|
48
|
+
style={styles.widget}
|
|
49
|
+
config={serializedConfig}
|
|
50
|
+
items={serializedItems}
|
|
51
|
+
/>
|
|
52
|
+
</View>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const styles = StyleSheet.create({
|
|
57
|
+
container: {
|
|
58
|
+
overflow: 'hidden',
|
|
59
|
+
},
|
|
60
|
+
widget: {
|
|
61
|
+
flex: 1,
|
|
62
|
+
},
|
|
63
|
+
});
|
package/src/index.ts
CHANGED
|
@@ -1,15 +1,25 @@
|
|
|
1
1
|
export { ShortKitProvider } from './ShortKitProvider';
|
|
2
2
|
export { ShortKitFeed } from './ShortKitFeed';
|
|
3
|
+
export { ShortKitPlayer } from './ShortKitPlayer';
|
|
4
|
+
export { ShortKitWidget } from './ShortKitWidget';
|
|
3
5
|
export { useShortKitPlayer } from './useShortKitPlayer';
|
|
4
6
|
export { useShortKit } from './useShortKit';
|
|
5
7
|
export type {
|
|
6
8
|
FeedConfig,
|
|
7
9
|
FeedHeight,
|
|
10
|
+
FeedSource,
|
|
8
11
|
OverlayConfig,
|
|
9
12
|
CarouselMode,
|
|
10
13
|
SurveyMode,
|
|
11
14
|
|
|
15
|
+
PlayerConfig,
|
|
16
|
+
PlayerClickAction,
|
|
17
|
+
WidgetConfig,
|
|
18
|
+
|
|
12
19
|
ContentItem,
|
|
20
|
+
CarouselImage,
|
|
21
|
+
ImageCarouselItem,
|
|
22
|
+
CustomFeedItem,
|
|
13
23
|
JSONValue,
|
|
14
24
|
CaptionTrack,
|
|
15
25
|
PlayerTime,
|
|
@@ -22,5 +32,7 @@ export type {
|
|
|
22
32
|
ShortKitError,
|
|
23
33
|
ShortKitProviderProps,
|
|
24
34
|
ShortKitFeedProps,
|
|
35
|
+
ShortKitPlayerProps,
|
|
36
|
+
ShortKitWidgetProps,
|
|
25
37
|
ShortKitPlayerState,
|
|
26
38
|
} from './types';
|
package/src/serialization.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
FeedConfig,
|
|
3
3
|
ContentItem,
|
|
4
|
+
CustomFeedItem,
|
|
4
5
|
PlayerState,
|
|
5
6
|
PlayerTime,
|
|
6
7
|
} from './types';
|
|
@@ -15,6 +16,7 @@ export interface SerializedFeedConfig {
|
|
|
15
16
|
carouselMode: string;
|
|
16
17
|
surveyMode: string;
|
|
17
18
|
muteOnStart: boolean;
|
|
19
|
+
feedSource: string;
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
/**
|
|
@@ -38,6 +40,7 @@ export function serializeFeedConfig(config: FeedConfig): SerializedFeedConfig {
|
|
|
38
40
|
carouselMode: JSON.stringify(config.carouselMode ?? 'none'),
|
|
39
41
|
surveyMode: JSON.stringify(config.surveyMode ?? 'none'),
|
|
40
42
|
muteOnStart: config.muteOnStart ?? true,
|
|
43
|
+
feedSource: config.feedSource ?? 'algorithmic',
|
|
41
44
|
};
|
|
42
45
|
}
|
|
43
46
|
|
|
@@ -93,3 +96,10 @@ export function deserializePlayerTime(event: {
|
|
|
93
96
|
buffered: event.buffered,
|
|
94
97
|
};
|
|
95
98
|
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Serialize CustomFeedItem[] to a JSON string for the bridge.
|
|
102
|
+
*/
|
|
103
|
+
export function serializeCustomFeedItems(items: CustomFeedItem[]): string {
|
|
104
|
+
return JSON.stringify(items);
|
|
105
|
+
}
|
|
@@ -11,6 +11,7 @@ type PlayerStateEvent = Readonly<{
|
|
|
11
11
|
|
|
12
12
|
type CurrentItemEvent = Readonly<{
|
|
13
13
|
id: string;
|
|
14
|
+
playbackId?: string;
|
|
14
15
|
title: string;
|
|
15
16
|
description?: string;
|
|
16
17
|
duration: Double;
|
|
@@ -77,6 +78,10 @@ type PrefetchedAheadCountEvent = Readonly<{
|
|
|
77
78
|
count: Int32;
|
|
78
79
|
}>;
|
|
79
80
|
|
|
81
|
+
type RemainingContentCountEvent = Readonly<{
|
|
82
|
+
count: Int32;
|
|
83
|
+
}>;
|
|
84
|
+
|
|
80
85
|
type ErrorEvent = Readonly<{
|
|
81
86
|
code: string;
|
|
82
87
|
message: string;
|
|
@@ -112,6 +117,11 @@ type OverlayRestoreEvent = Readonly<{
|
|
|
112
117
|
item: string; // JSON-serialized ContentItem
|
|
113
118
|
}>;
|
|
114
119
|
|
|
120
|
+
type ContentTappedEvent = Readonly<{
|
|
121
|
+
contentId: string;
|
|
122
|
+
index: Int32;
|
|
123
|
+
}>;
|
|
124
|
+
|
|
115
125
|
type OverlayTapEvent = Readonly<{}>;
|
|
116
126
|
|
|
117
127
|
type OverlayDoubleTapEvent = Readonly<{
|
|
@@ -124,6 +134,7 @@ export interface Spec extends TurboModule {
|
|
|
124
134
|
initialize(
|
|
125
135
|
apiKey: string,
|
|
126
136
|
config: string, // JSON-serialized FeedConfig
|
|
137
|
+
embedId?: string,
|
|
127
138
|
clientAppName?: string,
|
|
128
139
|
clientAppVersion?: string,
|
|
129
140
|
customDimensions?: string, // JSON-serialized Record<string, string>
|
|
@@ -148,6 +159,11 @@ export interface Spec extends TurboModule {
|
|
|
148
159
|
sendContentSignal(signal: string): void;
|
|
149
160
|
setMaxBitrate(bitrate: Double): void;
|
|
150
161
|
|
|
162
|
+
// --- Custom feed ---
|
|
163
|
+
setFeedItems(items: string): void;
|
|
164
|
+
appendFeedItems(items: string): void;
|
|
165
|
+
fetchContent(limit: Int32): Promise<string>;
|
|
166
|
+
|
|
151
167
|
// --- Event emitters ---
|
|
152
168
|
readonly onPlayerStateChanged: EventEmitter<PlayerStateEvent>;
|
|
153
169
|
readonly onCurrentItemChanged: EventEmitter<CurrentItemEvent>;
|
|
@@ -161,6 +177,7 @@ export interface Spec extends TurboModule {
|
|
|
161
177
|
readonly onFeedTransition: EventEmitter<FeedTransitionEvent>;
|
|
162
178
|
readonly onFormatChange: EventEmitter<FormatChangeEvent>;
|
|
163
179
|
readonly onPrefetchedAheadCountChanged: EventEmitter<PrefetchedAheadCountEvent>;
|
|
180
|
+
readonly onRemainingContentCountChanged: EventEmitter<RemainingContentCountEvent>;
|
|
164
181
|
readonly onError: EventEmitter<ErrorEvent>;
|
|
165
182
|
readonly onShareTapped: EventEmitter<ShareTappedEvent>;
|
|
166
183
|
readonly onSurveyResponse: EventEmitter<SurveyResponseEvent>;
|
|
@@ -171,6 +188,7 @@ export interface Spec extends TurboModule {
|
|
|
171
188
|
readonly onOverlayRestore: EventEmitter<OverlayRestoreEvent>;
|
|
172
189
|
readonly onOverlayTap: EventEmitter<OverlayTapEvent>;
|
|
173
190
|
readonly onOverlayDoubleTap: EventEmitter<OverlayDoubleTapEvent>;
|
|
191
|
+
readonly onContentTapped: EventEmitter<ContentTappedEvent>;
|
|
174
192
|
}
|
|
175
193
|
|
|
176
194
|
export default TurboModuleRegistry.getEnforcing<Spec>('ShortKitModule');
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { HostComponent, ViewProps } from 'react-native';
|
|
2
|
+
import { codegenNativeComponent } from 'react-native';
|
|
3
|
+
|
|
4
|
+
export interface NativeProps extends ViewProps {
|
|
5
|
+
config: string;
|
|
6
|
+
contentItem?: string;
|
|
7
|
+
active?: boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export default codegenNativeComponent<NativeProps>(
|
|
11
|
+
'ShortKitPlayerView',
|
|
12
|
+
{},
|
|
13
|
+
) as HostComponent<NativeProps>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { HostComponent, ViewProps } from 'react-native';
|
|
2
|
+
import { codegenNativeComponent } from 'react-native';
|
|
3
|
+
|
|
4
|
+
export interface NativeProps extends ViewProps {
|
|
5
|
+
config: string;
|
|
6
|
+
items?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export default codegenNativeComponent<NativeProps>(
|
|
10
|
+
'ShortKitWidgetView',
|
|
11
|
+
{},
|
|
12
|
+
) as HostComponent<NativeProps>;
|
package/src/types.ts
CHANGED
|
@@ -2,12 +2,15 @@ import type { ViewStyle } from 'react-native';
|
|
|
2
2
|
|
|
3
3
|
// --- Configuration ---
|
|
4
4
|
|
|
5
|
+
export type FeedSource = 'algorithmic' | 'custom';
|
|
6
|
+
|
|
5
7
|
export interface FeedConfig {
|
|
6
8
|
feedHeight?: FeedHeight;
|
|
7
9
|
overlay?: OverlayConfig;
|
|
8
10
|
carouselMode?: CarouselMode;
|
|
9
11
|
surveyMode?: SurveyMode;
|
|
10
12
|
muteOnStart?: boolean;
|
|
13
|
+
feedSource?: FeedSource;
|
|
11
14
|
}
|
|
12
15
|
|
|
13
16
|
export type FeedHeight =
|
|
@@ -30,6 +33,7 @@ export type SurveyMode =
|
|
|
30
33
|
|
|
31
34
|
export interface ContentItem {
|
|
32
35
|
id: string;
|
|
36
|
+
playbackId?: string;
|
|
33
37
|
title: string;
|
|
34
38
|
description?: string;
|
|
35
39
|
duration: number;
|
|
@@ -42,6 +46,29 @@ export interface ContentItem {
|
|
|
42
46
|
commentCount?: number;
|
|
43
47
|
}
|
|
44
48
|
|
|
49
|
+
// --- Custom Feed Types ---
|
|
50
|
+
|
|
51
|
+
export interface CarouselImage {
|
|
52
|
+
url: string;
|
|
53
|
+
alt?: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface ImageCarouselItem {
|
|
57
|
+
id: string;
|
|
58
|
+
images: CarouselImage[];
|
|
59
|
+
autoScrollInterval?: number;
|
|
60
|
+
caption?: string;
|
|
61
|
+
title?: string;
|
|
62
|
+
description?: string;
|
|
63
|
+
author?: string;
|
|
64
|
+
section?: string;
|
|
65
|
+
articleUrl?: string;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export type CustomFeedItem =
|
|
69
|
+
| { type: 'video'; playbackId: string }
|
|
70
|
+
| { type: 'imageCarousel'; item: ImageCarouselItem };
|
|
71
|
+
|
|
45
72
|
export type JSONValue =
|
|
46
73
|
| string
|
|
47
74
|
| number
|
|
@@ -109,6 +136,7 @@ export interface ShortKitError {
|
|
|
109
136
|
export interface ShortKitProviderProps {
|
|
110
137
|
apiKey: string;
|
|
111
138
|
config: FeedConfig;
|
|
139
|
+
embedId?: string;
|
|
112
140
|
userId?: string;
|
|
113
141
|
|
|
114
142
|
clientAppName?: string;
|
|
@@ -127,6 +155,55 @@ export interface ShortKitFeedProps {
|
|
|
127
155
|
onLoop?: (event: LoopEvent) => void;
|
|
128
156
|
onFeedTransition?: (event: FeedTransitionEvent) => void;
|
|
129
157
|
onFormatChange?: (event: FormatChangeEvent) => void;
|
|
158
|
+
onContentTapped?: (contentId: string, index: number) => void;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// --- Single Player Config ---
|
|
162
|
+
|
|
163
|
+
export type PlayerClickAction = 'feed' | 'mute' | 'none';
|
|
164
|
+
|
|
165
|
+
export interface PlayerConfig {
|
|
166
|
+
cornerRadius?: number;
|
|
167
|
+
clickAction?: PlayerClickAction;
|
|
168
|
+
autoplay?: boolean;
|
|
169
|
+
loop?: boolean;
|
|
170
|
+
muteOnStart?: boolean;
|
|
171
|
+
overlay?: OverlayConfig;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// --- Widget Config ---
|
|
175
|
+
|
|
176
|
+
export interface WidgetConfig {
|
|
177
|
+
cardCount?: number;
|
|
178
|
+
cardSpacing?: number;
|
|
179
|
+
cornerRadius?: number;
|
|
180
|
+
autoplay?: boolean;
|
|
181
|
+
muteOnStart?: boolean;
|
|
182
|
+
loop?: boolean;
|
|
183
|
+
rotationInterval?: number;
|
|
184
|
+
clickAction?: PlayerClickAction;
|
|
185
|
+
overlay?: OverlayConfig;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// --- Single Player Props ---
|
|
189
|
+
|
|
190
|
+
export interface ShortKitPlayerProps {
|
|
191
|
+
config?: PlayerConfig;
|
|
192
|
+
contentItem?: ContentItem;
|
|
193
|
+
/** Controls whether the player is actively playing. When `false` the player
|
|
194
|
+
* returns to thumbnail-only mode without tearing down the view. Defaults to
|
|
195
|
+
* the value of `config.autoplay` (which itself defaults to `true`). */
|
|
196
|
+
active?: boolean;
|
|
197
|
+
style?: ViewStyle;
|
|
198
|
+
onTap?: () => void;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// --- Widget Props ---
|
|
202
|
+
|
|
203
|
+
export interface ShortKitWidgetProps {
|
|
204
|
+
config?: WidgetConfig;
|
|
205
|
+
items?: ContentItem[];
|
|
206
|
+
style?: ViewStyle;
|
|
130
207
|
}
|
|
131
208
|
|
|
132
209
|
// --- Hook Return Types ---
|
|
@@ -142,6 +219,7 @@ export interface ShortKitPlayerState {
|
|
|
142
219
|
activeCaptionTrack: CaptionTrack | null;
|
|
143
220
|
activeCue: { text: string; startTime: number; endTime: number } | null;
|
|
144
221
|
prefetchedAheadCount: number;
|
|
222
|
+
remainingContentCount: number;
|
|
145
223
|
isActive: boolean;
|
|
146
224
|
isTransitioning: boolean;
|
|
147
225
|
lastOverlayTap: number;
|
package/src/useShortKit.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { ShortKitContext } from './ShortKitContext';
|
|
|
6
6
|
*
|
|
7
7
|
* Must be used within a `<ShortKitProvider>`.
|
|
8
8
|
*
|
|
9
|
-
* @returns SDK operations
|
|
9
|
+
* @returns SDK operations and state.
|
|
10
10
|
*/
|
|
11
11
|
export function useShortKit() {
|
|
12
12
|
const context = useContext(ShortKitContext);
|
|
@@ -16,5 +16,9 @@ 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
|
+
fetchContent: context.fetchContent,
|
|
22
|
+
remainingContentCount: context.remainingContentCount,
|
|
19
23
|
};
|
|
20
24
|
}
|