@shortkitsdk/react-native 0.2.32 → 0.2.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/android/libs/shortkit-release.aar +0 -0
  2. package/android/src/main/java/com/shortkit/reactnative/ShortKitBridge.kt +26 -5
  3. package/android/src/main/java/com/shortkit/reactnative/ShortKitModule.kt +19 -5
  4. package/ios/FeedMaskHostView.swift +190 -0
  5. package/ios/ShortKitBridge.swift +34 -0
  6. package/ios/ShortKitPlayerNativeView.swift +31 -0
  7. package/ios/ShortKitPlayerNativeViewManager.mm +1 -0
  8. package/ios/ShortKitSDK.xcframework/Info.plist +5 -5
  9. package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Info.plist +2 -2
  10. package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.abi.json +1919 -106
  11. package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.private.swiftinterface +49 -5
  12. package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.swiftdoc +0 -0
  13. package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.swiftinterface +49 -5
  14. package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/ShortKitSDK +0 -0
  15. package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/_CodeSignature/CodeResources +9 -9
  16. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Info.plist +2 -2
  17. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.abi.json +1919 -106
  18. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface +49 -5
  19. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.swiftdoc +0 -0
  20. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.swiftinterface +49 -5
  21. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.abi.json +1919 -106
  22. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface +49 -5
  23. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.swiftdoc +0 -0
  24. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.swiftinterface +49 -5
  25. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/ShortKitSDK +0 -0
  26. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/_CodeSignature/CodeResources +17 -17
  27. package/ios/ShortKitWidgetNativeView.swift +153 -6
  28. package/ios/ShortKitWidgetNativeViewManager.mm +2 -0
  29. package/package.json +1 -1
  30. package/src/ShortKitFeedMaskSurface.tsx +132 -0
  31. package/src/ShortKitPlayer.tsx +15 -2
  32. package/src/ShortKitWidget.tsx +16 -2
  33. package/src/index.ts +8 -1
  34. package/src/serialization.ts +15 -0
  35. package/src/specs/ShortKitPlayerViewNativeComponent.ts +7 -0
  36. package/src/specs/ShortKitWidgetViewNativeComponent.ts +15 -0
  37. package/src/types.ts +95 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shortkitsdk/react-native",
3
- "version": "0.2.32",
3
+ "version": "0.2.33",
4
4
  "description": "ShortKit React Native SDK — short-form video feed",
5
5
  "react-native": "src/index",
6
6
  "source": "src/index",
@@ -0,0 +1,132 @@
1
+ import React from 'react';
2
+ import { AppRegistry, View, Text } from 'react-native';
3
+ import type { FeedMaskProps, ContentItem } from './types';
4
+ import { deserializeContentItem } from './serialization';
5
+
6
+ const SK_MASK_TAG = '[ShortKit:FeedMaskSurface]';
7
+
8
+ // Named registry — supports different mask components per host site.
9
+ const _maskRegistry = new Map<string, React.ComponentType<FeedMaskProps>>();
10
+
11
+ /**
12
+ * Register a named feed-mask component for rendering around the
13
+ * expanded feed. Called by `<ShortKitPlayer>` / `<ShortKitWidget>` on
14
+ * mount via `useLayoutEffect` whenever `config.feedMask` is set with
15
+ * `type: 'custom'`. Idempotent — registering the same name twice is
16
+ * a no-op.
17
+ */
18
+ export function registerFeedMaskComponent(
19
+ name: string,
20
+ component: React.ComponentType<FeedMaskProps>,
21
+ ) {
22
+ if (_maskRegistry.has(name)) {
23
+ return;
24
+ }
25
+ _maskRegistry.set(name, component);
26
+
27
+ const moduleName = `ShortKitFeedMask_${name}`;
28
+ AppRegistry.registerComponent(moduleName, () => {
29
+ return function NamedFeedMaskSurface(props: RawFeedMaskSurfaceProps) {
30
+ return <ShortKitFeedMaskSurfaceInner {...props} maskName={name} />;
31
+ };
32
+ });
33
+ }
34
+
35
+ /**
36
+ * Error boundary mirrors the overlay-surface boundary so a crash in
37
+ * the mask component doesn't bring down the SDK's modal presentation.
38
+ */
39
+ class FeedMaskErrorBoundary extends React.Component<
40
+ { maskName: string; children: React.ReactNode },
41
+ { error: Error | null }
42
+ > {
43
+ state: { error: Error | null } = { error: null };
44
+
45
+ static getDerivedStateFromError(error: Error) {
46
+ return { error };
47
+ }
48
+
49
+ componentDidCatch(error: Error, info: React.ErrorInfo) {
50
+ console.error(
51
+ `${SK_MASK_TAG} CRASH in mask '${this.props.maskName}':`,
52
+ error.message,
53
+ '\nComponent stack:',
54
+ info.componentStack,
55
+ );
56
+ }
57
+
58
+ render() {
59
+ if (this.state.error) {
60
+ if (__DEV__) {
61
+ return (
62
+ <View style={{ flex: 1, backgroundColor: 'rgba(255,0,0,0.3)', justifyContent: 'center', alignItems: 'center', padding: 20 }}>
63
+ <Text style={{ color: 'white', fontSize: 14, textAlign: 'center' }}>
64
+ {`Mask '${this.props.maskName}' crashed:\n${this.state.error.message}`}
65
+ </Text>
66
+ </View>
67
+ );
68
+ }
69
+ // Production fallback: render an empty view so the SDK still
70
+ // has a usable feedRegion via the embed slot the host inserts
71
+ // (which they no longer do, since the mask crashed). The SDK's
72
+ // placeholder UIView keeps the feed visible.
73
+ return null;
74
+ }
75
+ return this.props.children;
76
+ }
77
+ }
78
+
79
+ /**
80
+ * Raw props pushed in by the native bridge (`FeedMaskHostView`)
81
+ * via `SKFabricSurfaceWrapper.setProperties`. Item arrives serialized
82
+ * as a JSON string; everything else is a primitive.
83
+ */
84
+ interface RawFeedMaskSurfaceProps {
85
+ /** Serialized `ContentItem`. JSON-stringified by the bridge. */
86
+ item?: string;
87
+ /** Active item's index in the feed, when known. */
88
+ activeIndex?: number;
89
+ /** Total feed length, when known. */
90
+ totalCount?: number;
91
+ }
92
+
93
+ interface InnerProps extends RawFeedMaskSurfaceProps {
94
+ maskName: string;
95
+ }
96
+
97
+ function ShortKitFeedMaskSurfaceInner(props: InnerProps) {
98
+ const Component = _maskRegistry.get(props.maskName);
99
+ if (!Component) {
100
+ if (__DEV__) {
101
+ console.warn(
102
+ `${SK_MASK_TAG} mask '${props.maskName}' is not registered — did you set config.feedMask?`,
103
+ );
104
+ }
105
+ return null;
106
+ }
107
+
108
+ let item: ContentItem | null = null;
109
+ if (props.item) {
110
+ try {
111
+ item = deserializeContentItem(props.item);
112
+ } catch (e) {
113
+ console.warn(`${SK_MASK_TAG} failed to deserialize item:`, e);
114
+ }
115
+ }
116
+
117
+ // No item to render around → render nothing yet. The SDK will push
118
+ // a configure() with the active item shortly after expansion.
119
+ if (!item) {
120
+ return null;
121
+ }
122
+
123
+ return (
124
+ <FeedMaskErrorBoundary maskName={props.maskName}>
125
+ <Component
126
+ item={item}
127
+ activeIndex={props.activeIndex}
128
+ totalCount={props.totalCount}
129
+ />
130
+ </FeedMaskErrorBoundary>
131
+ );
132
+ }
@@ -6,6 +6,7 @@ import { serializePlayerConfig } from './serialization';
6
6
  import { registerOverlayComponent } from './ShortKitOverlaySurface';
7
7
  import { registerCarouselOverlayComponent } from './ShortKitCarouselOverlaySurface';
8
8
  import { registerVideoCarouselOverlayComponent } from './ShortKitVideoCarouselOverlaySurface';
9
+ import { registerFeedMaskComponent } from './ShortKitFeedMaskSurface';
9
10
 
10
11
  /**
11
12
  * Single-video player component. Displays one video with thumbnail fallback
@@ -19,7 +20,7 @@ import { registerVideoCarouselOverlayComponent } from './ShortKitVideoCarouselOv
19
20
  * app's responsibility.
20
21
  */
21
22
  export function ShortKitPlayer(props: ShortKitPlayerProps) {
22
- const { config, contentItem, active, style } = props;
23
+ const { config, contentItem, active, feedItems, style } = props;
23
24
 
24
25
  const clickAction = config?.clickAction ?? 'feed';
25
26
 
@@ -39,7 +40,10 @@ export function ShortKitPlayer(props: ShortKitPlayerProps) {
39
40
  registerVideoCarouselOverlayComponent(fc.videoCarouselOverlay.name, fc.videoCarouselOverlay.component);
40
41
  }
41
42
  }
42
- }, [config?.overlay, config?.feedConfig]);
43
+ if (config?.feedMask && config.feedMask !== 'none') {
44
+ registerFeedMaskComponent(config.feedMask.name, config.feedMask.component);
45
+ }
46
+ }, [config?.overlay, config?.feedConfig, config?.feedMask]);
43
47
 
44
48
  const serializedConfig = useMemo(() => {
45
49
  return serializePlayerConfig(config ?? {});
@@ -50,6 +54,14 @@ export function ShortKitPlayer(props: ShortKitPlayerProps) {
50
54
  return JSON.stringify(contentItem);
51
55
  }, [contentItem]);
52
56
 
57
+ // Serialize the optional expanded-feed seed list. Empty/undefined ⇒
58
+ // pass `undefined` so the native side falls through to the legacy
59
+ // single-item behavior (preload built from `self.items`).
60
+ const serializedFeedItems = useMemo(() => {
61
+ if (!feedItems || feedItems.length === 0) return undefined;
62
+ return JSON.stringify(feedItems);
63
+ }, [feedItems]);
64
+
53
65
  // When clickAction is "none", the native view should not participate in
54
66
  // Fabric's JS-side hit testing. Without this, Fabric on Android sees the
55
67
  // native component as the touch target and never routes the touch to a
@@ -76,6 +88,7 @@ export function ShortKitPlayer(props: ShortKitPlayerProps) {
76
88
  config={serializedConfig}
77
89
  contentItem={serializedItem}
78
90
  active={active}
91
+ feedItems={serializedFeedItems}
79
92
  pointerEvents={nativeTouchPassthrough ? 'none' : 'auto'}
80
93
  />
81
94
  </View>
@@ -8,6 +8,7 @@ import { serializeWidgetConfig } from './serialization';
8
8
  import { registerOverlayComponent } from './ShortKitOverlaySurface';
9
9
  import { registerCarouselOverlayComponent } from './ShortKitCarouselOverlaySurface';
10
10
  import { registerVideoCarouselOverlayComponent } from './ShortKitVideoCarouselOverlaySurface';
11
+ import { registerFeedMaskComponent } from './ShortKitFeedMaskSurface';
11
12
 
12
13
  // Local UUID generator. We don't pull in a runtime dep just for this; a
13
14
  // timestamp + random suffix is more than unique enough to disambiguate
@@ -23,7 +24,7 @@ function generateWidgetId(): string {
23
24
  * Must be rendered inside a `<ShortKitProvider>`.
24
25
  */
25
26
  export function ShortKitWidget(props: ShortKitWidgetProps) {
26
- const { config, items, onCardTap, style } = props;
27
+ const { config, items, onCardTap, active, feedItems, style } = props;
27
28
 
28
29
  const isInitialized = useContext(ShortKitInitContext);
29
30
  if (!isInitialized) {
@@ -69,7 +70,10 @@ export function ShortKitWidget(props: ShortKitWidgetProps) {
69
70
  registerVideoCarouselOverlayComponent(fc.videoCarouselOverlay.name, fc.videoCarouselOverlay.component);
70
71
  }
71
72
  }
72
- }, [config?.overlay, config?.feedConfig]);
73
+ if (config?.feedMask && config.feedMask !== 'none') {
74
+ registerFeedMaskComponent(config.feedMask.name, config.feedMask.component);
75
+ }
76
+ }, [config?.overlay, config?.feedConfig, config?.feedMask]);
73
77
 
74
78
  // Subscribe to the global widget-card-tap event, filtered to this
75
79
  // instance's widgetId.
@@ -93,6 +97,14 @@ export function ShortKitWidget(props: ShortKitWidgetProps) {
93
97
  return JSON.stringify(items);
94
98
  }, [items]);
95
99
 
100
+ // Serialize the optional expanded-feed seed list. Empty/undefined ⇒
101
+ // pass `undefined` so the native side falls through to the legacy
102
+ // behavior (preload built from `self.items` — the carousel cards).
103
+ const serializedFeedItems = useMemo(() => {
104
+ if (!feedItems || feedItems.length === 0) return undefined;
105
+ return JSON.stringify(feedItems);
106
+ }, [feedItems]);
107
+
96
108
  return (
97
109
  <View style={[styles.container, style]}>
98
110
  <ShortKitWidgetView
@@ -100,6 +112,8 @@ export function ShortKitWidget(props: ShortKitWidgetProps) {
100
112
  config={serializedConfig}
101
113
  items={serializedItems}
102
114
  widgetId={widgetId}
115
+ active={active}
116
+ feedItems={serializedFeedItems}
103
117
  />
104
118
  </View>
105
119
  );
package/src/index.ts CHANGED
@@ -52,4 +52,11 @@ export { default as NativeShortKitModule } from './specs/NativeShortKitModule';
52
52
  export { registerOverlayComponent } from './ShortKitOverlaySurface';
53
53
  export { registerCarouselOverlayComponent } from './ShortKitCarouselOverlaySurface';
54
54
  export { registerVideoCarouselOverlayComponent } from './ShortKitVideoCarouselOverlaySurface';
55
- export type { OverlayProps, CarouselOverlayProps, VideoCarouselOverlayProps } from './types';
55
+ export { registerFeedMaskComponent } from './ShortKitFeedMaskSurface';
56
+ export type {
57
+ OverlayProps,
58
+ CarouselOverlayProps,
59
+ VideoCarouselOverlayProps,
60
+ FeedMaskProps,
61
+ FeedMaskConfig,
62
+ } from './types';
@@ -2,6 +2,7 @@ import type {
2
2
  FeedConfig,
3
3
  ContentItem,
4
4
  FeedInput,
5
+ FeedMaskConfig,
5
6
  PlayerState,
6
7
  PlayerTime,
7
8
  WidgetConfig,
@@ -139,6 +140,16 @@ function serializeOverlay(overlay: OverlayConfig | undefined): string | { type:
139
140
  return { type: 'custom', name: overlay.name };
140
141
  }
141
142
 
143
+ /**
144
+ * FeedMask serialization mirrors the overlay path: only the name
145
+ * crosses the bridge — the JS-side registry maps the name back to
146
+ * the React component at mount time inside `FeedMaskHostView`.
147
+ */
148
+ function serializeFeedMask(mask: FeedMaskConfig | undefined): string | { type: 'custom'; name: string } {
149
+ if (!mask || mask === 'none') return 'none';
150
+ return { type: 'custom', name: mask.name };
151
+ }
152
+
142
153
  export function serializeWidgetConfig(config: WidgetConfig): string {
143
154
  const cfg = config ?? {};
144
155
  return JSON.stringify({
@@ -153,6 +164,9 @@ export function serializeWidgetConfig(config: WidgetConfig): string {
153
164
  overlay: serializeOverlay(cfg.overlay),
154
165
  filter: cfg.filter ? JSON.stringify(cfg.filter) : undefined,
155
166
  feedConfig: cfg.feedConfig ? serializeFeedConfig(cfg.feedConfig) : undefined,
167
+ feedMask: serializeFeedMask(cfg.feedMask),
168
+ playbackMode: cfg.playbackMode ?? 'singleVisibleRotating',
169
+ previewDuration: cfg.previewDuration ?? 5,
156
170
  });
157
171
  }
158
172
 
@@ -166,5 +180,6 @@ export function serializePlayerConfig(config: PlayerConfig): string {
166
180
  muteOnStart: cfg.muteOnStart ?? true,
167
181
  overlay: serializeOverlay(cfg.overlay),
168
182
  feedConfig: cfg.feedConfig ? serializeFeedConfig(cfg.feedConfig) : undefined,
183
+ feedMask: serializeFeedMask(cfg.feedMask),
169
184
  });
170
185
  }
@@ -5,6 +5,13 @@ export interface NativeProps extends ViewProps {
5
5
  config: string;
6
6
  contentItem?: string;
7
7
  active?: boolean;
8
+ /**
9
+ * Serialized JSON of the host-provided expanded-feed seed list.
10
+ * See `ShortKitPlayerProps.feedItems` for semantics. Sent as a
11
+ * string to keep the prop primitive (Codegen-friendly) — the
12
+ * native bridge parses + hydrates into `[ContentItem]`.
13
+ */
14
+ feedItems?: string;
8
15
  }
9
16
 
10
17
  export default codegenNativeComponent<NativeProps>(
@@ -10,6 +10,21 @@ export interface NativeProps extends ViewProps {
10
10
  * `<ShortKitWidget>` when multiple widgets are mounted.
11
11
  */
12
12
  widgetId?: string;
13
+ /**
14
+ * Whether the widget is currently allowed to play. Defaults to true on
15
+ * the native side. Hosts use this to release the widget's pool tile
16
+ * when it shouldn't be playing (inactive tab, scrolled off-screen,
17
+ * etc.) so other surfaces can claim the tile cleanly. Mirrors
18
+ * `<ShortKitFeed>`'s `active` prop.
19
+ */
20
+ active?: boolean;
21
+ /**
22
+ * Serialized JSON of the host-provided expanded-feed seed list.
23
+ * See `ShortKitWidgetProps.feedItems` for semantics. Sent as a
24
+ * string to keep the prop primitive (Codegen-friendly) — the
25
+ * native bridge parses + hydrates into `[FeedInput]`.
26
+ */
27
+ feedItems?: string;
13
28
  }
14
29
 
15
30
  export default codegenNativeComponent<NativeProps>(
package/src/types.ts CHANGED
@@ -52,6 +52,35 @@ export type VideoCarouselOverlayConfig =
52
52
  | 'none'
53
53
  | { type: 'custom'; name: string; component: React.ComponentType<VideoCarouselOverlayProps> };
54
54
 
55
+ /**
56
+ * Custom feed mask config for `<ShortKitPlayer>` / `<ShortKitWidget>`.
57
+ *
58
+ * When set to `{type: 'custom', name, component}`, the SDK presents the
59
+ * expanded feed embedded inside the host-supplied React component rather
60
+ * than full-screen. The mask renders chrome (e.g. a footer pill) AROUND
61
+ * the feed; the feed itself occupies the `<ShortKitFeedRegion>` placeholder
62
+ * the host puts somewhere in the mask's tree.
63
+ *
64
+ * iOS only. On Android the prop is currently a no-op.
65
+ */
66
+ export type FeedMaskConfig =
67
+ | 'none'
68
+ | { type: 'custom'; name: string; component: React.ComponentType<FeedMaskProps> };
69
+
70
+ /**
71
+ * Props passed to the host-supplied feed mask component as the user pages
72
+ * through the expanded feed. Mirrors a subset of `OverlayProps` —
73
+ * additional fields (playback state, time, etc.) can be added later.
74
+ */
75
+ export interface FeedMaskProps {
76
+ /** The currently-active feed item. Re-renders the mask when paging. */
77
+ item: ContentItem;
78
+ /** Active item's index in the feed, when known. */
79
+ activeIndex?: number;
80
+ /** Total feed length, when known (paginated feeds may grow). */
81
+ totalCount?: number;
82
+ }
83
+
55
84
  // --- Data Models ---
56
85
 
57
86
  export interface ContentItem {
@@ -438,6 +467,12 @@ export interface PlayerConfig {
438
467
  muteOnStart?: boolean;
439
468
  overlay?: OverlayConfig;
440
469
  feedConfig?: FeedConfig;
470
+ /**
471
+ * Optional feed mask. When `{type: 'custom', ...}`, the SDK embeds the
472
+ * expanded feed inside the host's React component instead of presenting
473
+ * full-screen. iOS only. See `FeedMaskConfig` for full semantics.
474
+ */
475
+ feedMask?: FeedMaskConfig;
441
476
  }
442
477
 
443
478
  // --- Widget Config ---
@@ -454,6 +489,24 @@ export interface WidgetConfig {
454
489
  overlay?: OverlayConfig;
455
490
  filter?: FeedFilter;
456
491
  feedConfig?: FeedConfig;
492
+ /**
493
+ * Optional feed mask, same shape as `PlayerConfig.feedMask`. iOS only.
494
+ */
495
+ feedMask?: FeedMaskConfig;
496
+ /**
497
+ * How the widget schedules preview playback across cells.
498
+ * - `'singleVisibleRotating'` (default): one visible card plays at a
499
+ * time using an HLS Instant Clip; advances to the next visible card
500
+ * on natural EOS, wrapping at the end. Off-screen cards never play.
501
+ * - `'allVisibleSimultaneous'`: every visible card plays simultaneously,
502
+ * hard-capped at 3. Each card loops its own preview in place.
503
+ */
504
+ playbackMode?: 'singleVisibleRotating' | 'allVisibleSimultaneous';
505
+ /**
506
+ * Length of the looping preview window in seconds. Used to construct the
507
+ * Mux Instant Clip URL for each card. Defaults to 5.
508
+ */
509
+ previewDuration?: number;
457
510
  }
458
511
 
459
512
  /**
@@ -473,6 +526,22 @@ export interface ShortKitPlayerProps {
473
526
  * returns to thumbnail-only mode without tearing down the view. Defaults to
474
527
  * the value of `config.autoplay` (which itself defaults to `true`). */
475
528
  active?: boolean;
529
+ /**
530
+ * Optional list of items used to seed the expanded feed when the user
531
+ * taps the player and `config.clickAction === 'feed'`. The inline
532
+ * player's own `contentItem` is automatically prepended (deduped by
533
+ * playback ID), so the modal-zoom transition lands on the inline
534
+ * clip and the host's items follow.
535
+ *
536
+ * Combine with `config.feedConfig.feedSource`:
537
+ * - `'algorithmic'` (default) → expanded feed plays the seeded
538
+ * items, then continues paginating via `/v1/feed`.
539
+ * - `'custom'` → expanded feed plays only the seeded items and
540
+ * stops at the end (closed list).
541
+ *
542
+ * Has no effect when `clickAction !== 'feed'`.
543
+ */
544
+ feedItems?: FeedInput[];
476
545
  style?: ViewStyle;
477
546
  onTap?: () => void;
478
547
  }
@@ -499,6 +568,32 @@ export interface ShortKitWidgetProps {
499
568
  * regardless (per-cell mute toggle runs alongside `onCardTap`).
500
569
  */
501
570
  onCardTap?: (playbackId: string, index: number) => void;
571
+ /**
572
+ * Whether the widget is currently allowed to play. Defaults to `true`.
573
+ * When `false`, the widget stops its rotation timer and deactivates
574
+ * whichever card was active — releasing its tile back to the SDK
575
+ * player pool. Use this for viewport-aware playback orchestration
576
+ * (e.g. tab-focus gating: `active={isFocused}`). Mirrors
577
+ * `<ShortKitFeed>`'s same-named prop.
578
+ */
579
+ active?: boolean;
580
+ /**
581
+ * Optional list of items used to seed the expanded feed when the user
582
+ * taps a card and `config.clickAction === 'feed'`. The widget's own
583
+ * `items` (the carousel cards) are automatically prepended (deduped
584
+ * by playback ID), so the modal-zoom transition lands on the tapped
585
+ * clip and the host's items follow.
586
+ *
587
+ * Combine with `config.feedConfig.feedSource`:
588
+ * - `'algorithmic'` (default) → expanded feed plays the seeded
589
+ * items, then continues paginating via `/v1/feed`.
590
+ * - `'custom'` → expanded feed plays only the seeded items and
591
+ * stops at the end (closed list).
592
+ *
593
+ * Has no effect when `clickAction !== 'feed'`. Mirrors the
594
+ * `feedItems` prop on `<ShortKitPlayer>`.
595
+ */
596
+ feedItems?: FeedInput[];
502
597
  style?: ViewStyle;
503
598
  }
504
599