@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
@@ -243,6 +243,7 @@ public struct FeedConfig : Swift.Codable {
243
243
  public var surveyOverlay: ShortKitSDK.SurveyOverlayMode
244
244
  public var adOverlay: ShortKitSDK.AdOverlayMode
245
245
  public var liveOverlay: ShortKitSDK.LiveOverlayMode
246
+ public var liveEndedOverlay: ShortKitSDK.LiveEndedOverlayMode
246
247
  public var liveRoomMask: ShortKitSDK.LiveRoomMaskMode
247
248
  public var muteOnStart: Swift.Bool
248
249
  public var autoplay: Swift.Bool
@@ -251,7 +252,7 @@ public struct FeedConfig : Swift.Codable {
251
252
  public var pullToRefreshEnabled: Swift.Bool
252
253
  public var filter: ShortKitSDK.FeedFilter?
253
254
  public var preload: ShortKitSDK.FeedPreload?
254
- public init(feedHeight: ShortKitSDK.FeedHeight = .fullscreen, scrollAxis: ShortKitSDK.ScrollAxis = .vertical, videoOverlay: ShortKitSDK.VideoOverlayMode = .none, carouselOverlay: ShortKitSDK.CarouselOverlayMode = .none, videoCarouselOverlay: ShortKitSDK.VideoCarouselOverlayMode = .none, surveyOverlay: ShortKitSDK.SurveyOverlayMode = .none, adOverlay: ShortKitSDK.AdOverlayMode = .none, liveOverlay: ShortKitSDK.LiveOverlayMode = .default, liveRoomMask: ShortKitSDK.LiveRoomMaskMode = .none, muteOnStart: Swift.Bool = true, autoplay: Swift.Bool = true, feedSource: ShortKitSDK.FeedSource = .algorithmic, coldStartEnabled: Swift.Bool = false, pullToRefreshEnabled: Swift.Bool = true, filter: ShortKitSDK.FeedFilter? = nil, preload: ShortKitSDK.FeedPreload? = nil)
255
+ public init(feedHeight: ShortKitSDK.FeedHeight = .fullscreen, scrollAxis: ShortKitSDK.ScrollAxis = .vertical, videoOverlay: ShortKitSDK.VideoOverlayMode = .none, carouselOverlay: ShortKitSDK.CarouselOverlayMode = .none, videoCarouselOverlay: ShortKitSDK.VideoCarouselOverlayMode = .none, surveyOverlay: ShortKitSDK.SurveyOverlayMode = .none, adOverlay: ShortKitSDK.AdOverlayMode = .none, liveOverlay: ShortKitSDK.LiveOverlayMode = .default, liveEndedOverlay: ShortKitSDK.LiveEndedOverlayMode = .default, liveRoomMask: ShortKitSDK.LiveRoomMaskMode = .none, muteOnStart: Swift.Bool = true, autoplay: Swift.Bool = true, feedSource: ShortKitSDK.FeedSource = .algorithmic, coldStartEnabled: Swift.Bool = false, pullToRefreshEnabled: Swift.Bool = true, filter: ShortKitSDK.FeedFilter? = nil, preload: ShortKitSDK.FeedPreload? = nil)
255
256
  public init(from decoder: any Swift.Decoder) throws
256
257
  public func encode(to encoder: any Swift.Encoder) throws
257
258
  }
@@ -342,6 +343,20 @@ extension ShortKitSDK.LiveOverlayMode : Swift.Codable {
342
343
  public init(from decoder: any Swift.Decoder) throws
343
344
  public func encode(to encoder: any Swift.Encoder) throws
344
345
  }
346
+ public enum LiveEndedOverlayMode {
347
+ case `default`
348
+ case custom(@Sendable () -> any UIKit.UIView & ShortKitSDK.LiveEndedOverlay)
349
+ }
350
+ extension ShortKitSDK.LiveEndedOverlayMode {
351
+ public static func swiftUI<Content>(@SwiftUICore.ViewBuilder content: @escaping @Sendable (ShortKitSDK.ContentItem) -> Content) -> ShortKitSDK.LiveEndedOverlayMode where Content : SwiftUICore.View
352
+ }
353
+ extension ShortKitSDK.LiveEndedOverlayMode : Swift.Equatable {
354
+ public static func == (lhs: ShortKitSDK.LiveEndedOverlayMode, rhs: ShortKitSDK.LiveEndedOverlayMode) -> Swift.Bool
355
+ }
356
+ extension ShortKitSDK.LiveEndedOverlayMode : Swift.Codable {
357
+ public init(from decoder: any Swift.Decoder) throws
358
+ public func encode(to encoder: any Swift.Encoder) throws
359
+ }
345
360
  public struct DebugAlert {
346
361
  public enum Level {
347
362
  case warning
@@ -604,6 +619,9 @@ extension ShortKitSDK.ShortKitFeedViewController : ShortKitSDK.ShortKitAdDelegat
604
619
  @_Concurrency.MainActor @preconcurrency public func adDidFail(_ ad: ShortKitSDK.PreparedAd, error: ShortKitSDK.AdError)
605
620
  @_Concurrency.MainActor @preconcurrency public func adDidReceiveClick(_ ad: ShortKitSDK.PreparedAd)
606
621
  }
622
+ public protocol LiveEndedOverlay : AnyObject {
623
+ func configure(with item: ShortKitSDK.ContentItem)
624
+ }
607
625
  public enum SeedThumbnailResolver {
608
626
  public static func resolveFromMemory(url: Swift.String) -> UIKit.UIImage?
609
627
  }
@@ -702,8 +720,9 @@ public struct ContentItem : Swift.Codable, Swift.Equatable, @unchecked Swift.Sen
702
720
  public var liveStreamId: Swift.String?
703
721
  public var liveStreamStatus: ShortKitSDK.LiveStreamStatus?
704
722
  public var startedAt: Swift.String?
723
+ public var endedAt: Swift.String?
705
724
  public var currentViewers: Swift.Int
706
- public init(id: Swift.String, playbackId: Swift.String? = nil, title: Swift.String, description: Swift.String? = nil, duration: Swift.Double, streamingUrl: Swift.String, thumbnailUrl: Swift.String, captionTracks: [ShortKitSDK.CaptionTrack] = [], customMetadata: [Swift.String : ShortKitSDK.JSONValue]? = nil, author: Swift.String? = nil, articleUrl: Swift.String? = nil, commentCount: Swift.Int? = nil, fallbackUrl: Swift.String? = nil, downloadUrl: Swift.String? = nil, isLive: Swift.Bool = false, liveStreamId: Swift.String? = nil, liveStreamStatus: ShortKitSDK.LiveStreamStatus? = nil, startedAt: Swift.String? = nil, currentViewers: Swift.Int = 0)
725
+ public init(id: Swift.String, playbackId: Swift.String? = nil, title: Swift.String, description: Swift.String? = nil, duration: Swift.Double, streamingUrl: Swift.String, thumbnailUrl: Swift.String, captionTracks: [ShortKitSDK.CaptionTrack] = [], customMetadata: [Swift.String : ShortKitSDK.JSONValue]? = nil, author: Swift.String? = nil, articleUrl: Swift.String? = nil, commentCount: Swift.Int? = nil, fallbackUrl: Swift.String? = nil, downloadUrl: Swift.String? = nil, isLive: Swift.Bool = false, liveStreamId: Swift.String? = nil, liveStreamStatus: ShortKitSDK.LiveStreamStatus? = nil, startedAt: Swift.String? = nil, endedAt: Swift.String? = nil, currentViewers: Swift.Int = 0)
707
726
  public init(from decoder: any Swift.Decoder) throws
708
727
  public static func == (a: ShortKitSDK.ContentItem, b: ShortKitSDK.ContentItem) -> Swift.Bool
709
728
  public func encode(to encoder: any Swift.Encoder) throws
@@ -1193,7 +1212,7 @@ final public class ShortKit {
1193
1212
  weak final public var delegate: (any ShortKitSDK.ShortKitDelegate)?
1194
1213
  weak final public var downloadDelegate: (any ShortKitSDK.ShortKitDownloadDelegate)?
1195
1214
  final public var loadingViewProvider: (() -> UIKit.UIView)?
1196
- public init(apiKey: Swift.String, userId: Swift.String? = nil, adProvider: (any ShortKitSDK.ShortKitAdProvider)? = nil, clientAppName: Swift.String? = nil, clientAppVersion: Swift.String? = nil, customDimensions: [Swift.String : Swift.String]? = nil, loadingViewProvider: (() -> UIKit.UIView)? = nil, debugPanelEnabled: Swift.Bool = false, serverTracingEnabled: Swift.Bool = false, consoleTracingEnabled: Swift.Bool = false)
1215
+ public init(apiKey: Swift.String, userId: Swift.String? = nil, adProvider: (any ShortKitSDK.ShortKitAdProvider)? = nil, clientAppName: Swift.String? = nil, clientAppVersion: Swift.String? = nil, customDimensions: [Swift.String : Swift.String]? = nil, loadingViewProvider: (() -> UIKit.UIView)? = nil, debugPanelEnabled: Swift.Bool = false, serverTracingEnabled: Swift.Bool = false, consoleTracingEnabled: Swift.Bool = false, poolDebugEnabled: Swift.Bool = false)
1197
1216
  final public func preloadFeed(filter: ShortKitSDK.FeedFilter? = nil, limit: Swift.Int = 10) -> ShortKitSDK.FeedPreload
1198
1217
  final public func preloadFeed(items: [ShortKitSDK.FeedInput]) -> ShortKitSDK.FeedPreload
1199
1218
  final public func fetchContent(limit: Swift.Int = 10, filter: ShortKitSDK.FeedFilter? = nil) async throws -> [ShortKitSDK.ContentItem]
@@ -1223,7 +1242,13 @@ public struct PlayerConfig {
1223
1242
  public var muteOnStart: Swift.Bool
1224
1243
  public var videoOverlay: ShortKitSDK.VideoOverlayMode
1225
1244
  public var feedConfig: ShortKitSDK.FeedConfig
1226
- public init(cornerRadius: CoreFoundation.CGFloat = 12, clickAction: ShortKitSDK.PlayerClickAction = .feed, autoplay: Swift.Bool = true, loop: Swift.Bool = true, muteOnStart: Swift.Bool = true, videoOverlay: ShortKitSDK.VideoOverlayMode = .none, feedConfig: ShortKitSDK.FeedConfig = FeedConfig())
1245
+ public var previewMode: ShortKitSDK.PlayerConfig.PreviewMode
1246
+ public enum PreviewMode : Swift.Equatable, Swift.Sendable {
1247
+ case full
1248
+ case instantClip(seconds: Foundation.TimeInterval)
1249
+ public static func == (a: ShortKitSDK.PlayerConfig.PreviewMode, b: ShortKitSDK.PlayerConfig.PreviewMode) -> Swift.Bool
1250
+ }
1251
+ public init(cornerRadius: CoreFoundation.CGFloat = 12, clickAction: ShortKitSDK.PlayerClickAction = .feed, autoplay: Swift.Bool = true, loop: Swift.Bool = true, muteOnStart: Swift.Bool = true, videoOverlay: ShortKitSDK.VideoOverlayMode = .none, feedConfig: ShortKitSDK.FeedConfig = FeedConfig(), previewMode: ShortKitSDK.PlayerConfig.PreviewMode = .full)
1227
1252
  }
1228
1253
  @_Concurrency.MainActor @preconcurrency public struct ShortKitPlayerView : SwiftUI.UIViewControllerRepresentable {
1229
1254
  @_Concurrency.MainActor @preconcurrency public init(shortKit: ShortKitSDK.ShortKit, config: ShortKitSDK.PlayerConfig = PlayerConfig())
@@ -1235,11 +1260,13 @@ public struct PlayerConfig {
1235
1260
  }
1236
1261
  @objc @_hasMissingDesignatedInitializers @_Concurrency.MainActor @preconcurrency final public class ShortKitPlayerViewController : UIKit.UIViewController {
1237
1262
  @_Concurrency.MainActor @preconcurrency final public var feedMask: ShortKitSDK.FeedMaskMode
1263
+ @_Concurrency.MainActor @preconcurrency final public var onPreviewCompleted: (() -> Swift.Void)?
1238
1264
  @_Concurrency.MainActor @preconcurrency public init(shortKit: ShortKitSDK.ShortKit, config: ShortKitSDK.PlayerConfig)
1239
1265
  @_Concurrency.MainActor @preconcurrency @objc override final public func viewDidLoad()
1240
1266
  @_Concurrency.MainActor @preconcurrency @objc override final public func viewWillDisappear(_ animated: Swift.Bool)
1241
1267
  @_Concurrency.MainActor @preconcurrency @objc override final public func viewDidLayoutSubviews()
1242
1268
  @_Concurrency.MainActor @preconcurrency final public func configure(with contentItem: ShortKitSDK.ContentItem)
1269
+ @_Concurrency.MainActor @preconcurrency final public func setFeedItems(_ inputs: [ShortKitSDK.FeedInput])
1243
1270
  @_Concurrency.MainActor @preconcurrency final public func activate()
1244
1271
  @_Concurrency.MainActor @preconcurrency final public func deactivate()
1245
1272
  @objc deinit
@@ -1252,8 +1279,13 @@ extension ShortKitSDK.ShortKitPlayerViewController : UIKit.UIViewControllerTrans
1252
1279
  @objc @_hasMissingDesignatedInitializers @_Concurrency.MainActor @preconcurrency final public class ShortKitWidgetViewController : UIKit.UIViewController {
1253
1280
  @_Concurrency.MainActor @preconcurrency final public var feedMask: ShortKitSDK.FeedMaskMode
1254
1281
  @_Concurrency.MainActor @preconcurrency final public var onCardTap: ((Swift.String, Swift.Int) -> Swift.Void)?
1282
+ @_Concurrency.MainActor @preconcurrency final public var active: Swift.Bool {
1283
+ get
1284
+ set
1285
+ }
1255
1286
  @_Concurrency.MainActor @preconcurrency public init(shortKit: ShortKitSDK.ShortKit, config: ShortKitSDK.WidgetConfig, items: [ShortKitSDK.WidgetInput] = [])
1256
1287
  @_Concurrency.MainActor @preconcurrency final public func configure(with inputs: [ShortKitSDK.WidgetInput])
1288
+ @_Concurrency.MainActor @preconcurrency final public func setFeedItems(_ inputs: [ShortKitSDK.FeedInput])
1257
1289
  @_Concurrency.MainActor @preconcurrency @objc override final public func viewDidLoad()
1258
1290
  @_Concurrency.MainActor @preconcurrency @objc override final public func viewDidAppear(_ animated: Swift.Bool)
1259
1291
  @_Concurrency.MainActor @preconcurrency @objc override final public func viewWillDisappear(_ animated: Swift.Bool)
@@ -1271,6 +1303,15 @@ extension ShortKitSDK.ShortKitWidgetViewController : UIKit.UIViewControllerTrans
1271
1303
  @_Concurrency.MainActor @preconcurrency @objc final public func animationController(forDismissed dismissed: UIKit.UIViewController) -> (any UIKit.UIViewControllerAnimatedTransitioning)?
1272
1304
  @_Concurrency.MainActor @preconcurrency @objc final public func interactionControllerForDismissal(using animator: any UIKit.UIViewControllerAnimatedTransitioning) -> (any UIKit.UIViewControllerInteractiveTransitioning)?
1273
1305
  }
1306
+ public enum WidgetPlaybackMode : Swift.Equatable, Swift.Sendable {
1307
+ case singleVisibleRotating
1308
+ case allVisibleSimultaneous
1309
+ public static func == (a: ShortKitSDK.WidgetPlaybackMode, b: ShortKitSDK.WidgetPlaybackMode) -> Swift.Bool
1310
+ public func hash(into hasher: inout Swift.Hasher)
1311
+ public var hashValue: Swift.Int {
1312
+ get
1313
+ }
1314
+ }
1274
1315
  public struct WidgetConfig {
1275
1316
  public var cardCount: Swift.Int
1276
1317
  public var cardSpacing: CoreFoundation.CGFloat
@@ -1283,7 +1324,9 @@ public struct WidgetConfig {
1283
1324
  public var cardOverlay: ShortKitSDK.VideoOverlayMode
1284
1325
  public var feedConfig: ShortKitSDK.FeedConfig
1285
1326
  public var filter: ShortKitSDK.FeedFilter?
1286
- public init(cardCount: Swift.Int = 3, cardSpacing: CoreFoundation.CGFloat = 8, cornerRadius: CoreFoundation.CGFloat = 12, autoplay: Swift.Bool = true, muteOnStart: Swift.Bool = true, loop: Swift.Bool = true, rotationInterval: Foundation.TimeInterval = 10, clickAction: ShortKitSDK.PlayerClickAction = .feed, cardOverlay: ShortKitSDK.VideoOverlayMode = .none, feedConfig: ShortKitSDK.FeedConfig = FeedConfig(), filter: ShortKitSDK.FeedFilter? = nil)
1327
+ public var playbackMode: ShortKitSDK.WidgetPlaybackMode
1328
+ public var previewDuration: Foundation.TimeInterval
1329
+ public init(cardCount: Swift.Int = 3, cardSpacing: CoreFoundation.CGFloat = 8, cornerRadius: CoreFoundation.CGFloat = 12, autoplay: Swift.Bool = true, muteOnStart: Swift.Bool = true, loop: Swift.Bool = true, rotationInterval: Foundation.TimeInterval = 10, clickAction: ShortKitSDK.PlayerClickAction = .feed, cardOverlay: ShortKitSDK.VideoOverlayMode = .none, feedConfig: ShortKitSDK.FeedConfig = FeedConfig(), filter: ShortKitSDK.FeedFilter? = nil, playbackMode: ShortKitSDK.WidgetPlaybackMode = .singleVisibleRotating, previewDuration: Foundation.TimeInterval = 5.0)
1287
1330
  public func resolvedFeedConfig() -> ShortKitSDK.FeedConfig
1288
1331
  }
1289
1332
  public enum WidgetInput : Swift.Sendable {
@@ -1328,3 +1371,4 @@ extension ShortKitSDK.ContentSignal : Swift.Hashable {}
1328
1371
  extension ShortKitSDK.PlayerClickAction : Swift.Equatable {}
1329
1372
  extension ShortKitSDK.PlayerClickAction : Swift.Hashable {}
1330
1373
  extension ShortKitSDK.ShortKitPlayerView : Swift.Sendable {}
1374
+ extension ShortKitSDK.WidgetPlaybackMode : Swift.Hashable {}
@@ -243,6 +243,7 @@ public struct FeedConfig : Swift.Codable {
243
243
  public var surveyOverlay: ShortKitSDK.SurveyOverlayMode
244
244
  public var adOverlay: ShortKitSDK.AdOverlayMode
245
245
  public var liveOverlay: ShortKitSDK.LiveOverlayMode
246
+ public var liveEndedOverlay: ShortKitSDK.LiveEndedOverlayMode
246
247
  public var liveRoomMask: ShortKitSDK.LiveRoomMaskMode
247
248
  public var muteOnStart: Swift.Bool
248
249
  public var autoplay: Swift.Bool
@@ -251,7 +252,7 @@ public struct FeedConfig : Swift.Codable {
251
252
  public var pullToRefreshEnabled: Swift.Bool
252
253
  public var filter: ShortKitSDK.FeedFilter?
253
254
  public var preload: ShortKitSDK.FeedPreload?
254
- public init(feedHeight: ShortKitSDK.FeedHeight = .fullscreen, scrollAxis: ShortKitSDK.ScrollAxis = .vertical, videoOverlay: ShortKitSDK.VideoOverlayMode = .none, carouselOverlay: ShortKitSDK.CarouselOverlayMode = .none, videoCarouselOverlay: ShortKitSDK.VideoCarouselOverlayMode = .none, surveyOverlay: ShortKitSDK.SurveyOverlayMode = .none, adOverlay: ShortKitSDK.AdOverlayMode = .none, liveOverlay: ShortKitSDK.LiveOverlayMode = .default, liveRoomMask: ShortKitSDK.LiveRoomMaskMode = .none, muteOnStart: Swift.Bool = true, autoplay: Swift.Bool = true, feedSource: ShortKitSDK.FeedSource = .algorithmic, coldStartEnabled: Swift.Bool = false, pullToRefreshEnabled: Swift.Bool = true, filter: ShortKitSDK.FeedFilter? = nil, preload: ShortKitSDK.FeedPreload? = nil)
255
+ public init(feedHeight: ShortKitSDK.FeedHeight = .fullscreen, scrollAxis: ShortKitSDK.ScrollAxis = .vertical, videoOverlay: ShortKitSDK.VideoOverlayMode = .none, carouselOverlay: ShortKitSDK.CarouselOverlayMode = .none, videoCarouselOverlay: ShortKitSDK.VideoCarouselOverlayMode = .none, surveyOverlay: ShortKitSDK.SurveyOverlayMode = .none, adOverlay: ShortKitSDK.AdOverlayMode = .none, liveOverlay: ShortKitSDK.LiveOverlayMode = .default, liveEndedOverlay: ShortKitSDK.LiveEndedOverlayMode = .default, liveRoomMask: ShortKitSDK.LiveRoomMaskMode = .none, muteOnStart: Swift.Bool = true, autoplay: Swift.Bool = true, feedSource: ShortKitSDK.FeedSource = .algorithmic, coldStartEnabled: Swift.Bool = false, pullToRefreshEnabled: Swift.Bool = true, filter: ShortKitSDK.FeedFilter? = nil, preload: ShortKitSDK.FeedPreload? = nil)
255
256
  public init(from decoder: any Swift.Decoder) throws
256
257
  public func encode(to encoder: any Swift.Encoder) throws
257
258
  }
@@ -342,6 +343,20 @@ extension ShortKitSDK.LiveOverlayMode : Swift.Codable {
342
343
  public init(from decoder: any Swift.Decoder) throws
343
344
  public func encode(to encoder: any Swift.Encoder) throws
344
345
  }
346
+ public enum LiveEndedOverlayMode {
347
+ case `default`
348
+ case custom(@Sendable () -> any UIKit.UIView & ShortKitSDK.LiveEndedOverlay)
349
+ }
350
+ extension ShortKitSDK.LiveEndedOverlayMode {
351
+ public static func swiftUI<Content>(@SwiftUICore.ViewBuilder content: @escaping @Sendable (ShortKitSDK.ContentItem) -> Content) -> ShortKitSDK.LiveEndedOverlayMode where Content : SwiftUICore.View
352
+ }
353
+ extension ShortKitSDK.LiveEndedOverlayMode : Swift.Equatable {
354
+ public static func == (lhs: ShortKitSDK.LiveEndedOverlayMode, rhs: ShortKitSDK.LiveEndedOverlayMode) -> Swift.Bool
355
+ }
356
+ extension ShortKitSDK.LiveEndedOverlayMode : Swift.Codable {
357
+ public init(from decoder: any Swift.Decoder) throws
358
+ public func encode(to encoder: any Swift.Encoder) throws
359
+ }
345
360
  public struct DebugAlert {
346
361
  public enum Level {
347
362
  case warning
@@ -604,6 +619,9 @@ extension ShortKitSDK.ShortKitFeedViewController : ShortKitSDK.ShortKitAdDelegat
604
619
  @_Concurrency.MainActor @preconcurrency public func adDidFail(_ ad: ShortKitSDK.PreparedAd, error: ShortKitSDK.AdError)
605
620
  @_Concurrency.MainActor @preconcurrency public func adDidReceiveClick(_ ad: ShortKitSDK.PreparedAd)
606
621
  }
622
+ public protocol LiveEndedOverlay : AnyObject {
623
+ func configure(with item: ShortKitSDK.ContentItem)
624
+ }
607
625
  public enum SeedThumbnailResolver {
608
626
  public static func resolveFromMemory(url: Swift.String) -> UIKit.UIImage?
609
627
  }
@@ -702,8 +720,9 @@ public struct ContentItem : Swift.Codable, Swift.Equatable, @unchecked Swift.Sen
702
720
  public var liveStreamId: Swift.String?
703
721
  public var liveStreamStatus: ShortKitSDK.LiveStreamStatus?
704
722
  public var startedAt: Swift.String?
723
+ public var endedAt: Swift.String?
705
724
  public var currentViewers: Swift.Int
706
- public init(id: Swift.String, playbackId: Swift.String? = nil, title: Swift.String, description: Swift.String? = nil, duration: Swift.Double, streamingUrl: Swift.String, thumbnailUrl: Swift.String, captionTracks: [ShortKitSDK.CaptionTrack] = [], customMetadata: [Swift.String : ShortKitSDK.JSONValue]? = nil, author: Swift.String? = nil, articleUrl: Swift.String? = nil, commentCount: Swift.Int? = nil, fallbackUrl: Swift.String? = nil, downloadUrl: Swift.String? = nil, isLive: Swift.Bool = false, liveStreamId: Swift.String? = nil, liveStreamStatus: ShortKitSDK.LiveStreamStatus? = nil, startedAt: Swift.String? = nil, currentViewers: Swift.Int = 0)
725
+ public init(id: Swift.String, playbackId: Swift.String? = nil, title: Swift.String, description: Swift.String? = nil, duration: Swift.Double, streamingUrl: Swift.String, thumbnailUrl: Swift.String, captionTracks: [ShortKitSDK.CaptionTrack] = [], customMetadata: [Swift.String : ShortKitSDK.JSONValue]? = nil, author: Swift.String? = nil, articleUrl: Swift.String? = nil, commentCount: Swift.Int? = nil, fallbackUrl: Swift.String? = nil, downloadUrl: Swift.String? = nil, isLive: Swift.Bool = false, liveStreamId: Swift.String? = nil, liveStreamStatus: ShortKitSDK.LiveStreamStatus? = nil, startedAt: Swift.String? = nil, endedAt: Swift.String? = nil, currentViewers: Swift.Int = 0)
707
726
  public init(from decoder: any Swift.Decoder) throws
708
727
  public static func == (a: ShortKitSDK.ContentItem, b: ShortKitSDK.ContentItem) -> Swift.Bool
709
728
  public func encode(to encoder: any Swift.Encoder) throws
@@ -1193,7 +1212,7 @@ final public class ShortKit {
1193
1212
  weak final public var delegate: (any ShortKitSDK.ShortKitDelegate)?
1194
1213
  weak final public var downloadDelegate: (any ShortKitSDK.ShortKitDownloadDelegate)?
1195
1214
  final public var loadingViewProvider: (() -> UIKit.UIView)?
1196
- public init(apiKey: Swift.String, userId: Swift.String? = nil, adProvider: (any ShortKitSDK.ShortKitAdProvider)? = nil, clientAppName: Swift.String? = nil, clientAppVersion: Swift.String? = nil, customDimensions: [Swift.String : Swift.String]? = nil, loadingViewProvider: (() -> UIKit.UIView)? = nil, debugPanelEnabled: Swift.Bool = false, serverTracingEnabled: Swift.Bool = false, consoleTracingEnabled: Swift.Bool = false)
1215
+ public init(apiKey: Swift.String, userId: Swift.String? = nil, adProvider: (any ShortKitSDK.ShortKitAdProvider)? = nil, clientAppName: Swift.String? = nil, clientAppVersion: Swift.String? = nil, customDimensions: [Swift.String : Swift.String]? = nil, loadingViewProvider: (() -> UIKit.UIView)? = nil, debugPanelEnabled: Swift.Bool = false, serverTracingEnabled: Swift.Bool = false, consoleTracingEnabled: Swift.Bool = false, poolDebugEnabled: Swift.Bool = false)
1197
1216
  final public func preloadFeed(filter: ShortKitSDK.FeedFilter? = nil, limit: Swift.Int = 10) -> ShortKitSDK.FeedPreload
1198
1217
  final public func preloadFeed(items: [ShortKitSDK.FeedInput]) -> ShortKitSDK.FeedPreload
1199
1218
  final public func fetchContent(limit: Swift.Int = 10, filter: ShortKitSDK.FeedFilter? = nil) async throws -> [ShortKitSDK.ContentItem]
@@ -1223,7 +1242,13 @@ public struct PlayerConfig {
1223
1242
  public var muteOnStart: Swift.Bool
1224
1243
  public var videoOverlay: ShortKitSDK.VideoOverlayMode
1225
1244
  public var feedConfig: ShortKitSDK.FeedConfig
1226
- public init(cornerRadius: CoreFoundation.CGFloat = 12, clickAction: ShortKitSDK.PlayerClickAction = .feed, autoplay: Swift.Bool = true, loop: Swift.Bool = true, muteOnStart: Swift.Bool = true, videoOverlay: ShortKitSDK.VideoOverlayMode = .none, feedConfig: ShortKitSDK.FeedConfig = FeedConfig())
1245
+ public var previewMode: ShortKitSDK.PlayerConfig.PreviewMode
1246
+ public enum PreviewMode : Swift.Equatable, Swift.Sendable {
1247
+ case full
1248
+ case instantClip(seconds: Foundation.TimeInterval)
1249
+ public static func == (a: ShortKitSDK.PlayerConfig.PreviewMode, b: ShortKitSDK.PlayerConfig.PreviewMode) -> Swift.Bool
1250
+ }
1251
+ public init(cornerRadius: CoreFoundation.CGFloat = 12, clickAction: ShortKitSDK.PlayerClickAction = .feed, autoplay: Swift.Bool = true, loop: Swift.Bool = true, muteOnStart: Swift.Bool = true, videoOverlay: ShortKitSDK.VideoOverlayMode = .none, feedConfig: ShortKitSDK.FeedConfig = FeedConfig(), previewMode: ShortKitSDK.PlayerConfig.PreviewMode = .full)
1227
1252
  }
1228
1253
  @_Concurrency.MainActor @preconcurrency public struct ShortKitPlayerView : SwiftUI.UIViewControllerRepresentable {
1229
1254
  @_Concurrency.MainActor @preconcurrency public init(shortKit: ShortKitSDK.ShortKit, config: ShortKitSDK.PlayerConfig = PlayerConfig())
@@ -1235,11 +1260,13 @@ public struct PlayerConfig {
1235
1260
  }
1236
1261
  @objc @_hasMissingDesignatedInitializers @_Concurrency.MainActor @preconcurrency final public class ShortKitPlayerViewController : UIKit.UIViewController {
1237
1262
  @_Concurrency.MainActor @preconcurrency final public var feedMask: ShortKitSDK.FeedMaskMode
1263
+ @_Concurrency.MainActor @preconcurrency final public var onPreviewCompleted: (() -> Swift.Void)?
1238
1264
  @_Concurrency.MainActor @preconcurrency public init(shortKit: ShortKitSDK.ShortKit, config: ShortKitSDK.PlayerConfig)
1239
1265
  @_Concurrency.MainActor @preconcurrency @objc override final public func viewDidLoad()
1240
1266
  @_Concurrency.MainActor @preconcurrency @objc override final public func viewWillDisappear(_ animated: Swift.Bool)
1241
1267
  @_Concurrency.MainActor @preconcurrency @objc override final public func viewDidLayoutSubviews()
1242
1268
  @_Concurrency.MainActor @preconcurrency final public func configure(with contentItem: ShortKitSDK.ContentItem)
1269
+ @_Concurrency.MainActor @preconcurrency final public func setFeedItems(_ inputs: [ShortKitSDK.FeedInput])
1243
1270
  @_Concurrency.MainActor @preconcurrency final public func activate()
1244
1271
  @_Concurrency.MainActor @preconcurrency final public func deactivate()
1245
1272
  @objc deinit
@@ -1252,8 +1279,13 @@ extension ShortKitSDK.ShortKitPlayerViewController : UIKit.UIViewControllerTrans
1252
1279
  @objc @_hasMissingDesignatedInitializers @_Concurrency.MainActor @preconcurrency final public class ShortKitWidgetViewController : UIKit.UIViewController {
1253
1280
  @_Concurrency.MainActor @preconcurrency final public var feedMask: ShortKitSDK.FeedMaskMode
1254
1281
  @_Concurrency.MainActor @preconcurrency final public var onCardTap: ((Swift.String, Swift.Int) -> Swift.Void)?
1282
+ @_Concurrency.MainActor @preconcurrency final public var active: Swift.Bool {
1283
+ get
1284
+ set
1285
+ }
1255
1286
  @_Concurrency.MainActor @preconcurrency public init(shortKit: ShortKitSDK.ShortKit, config: ShortKitSDK.WidgetConfig, items: [ShortKitSDK.WidgetInput] = [])
1256
1287
  @_Concurrency.MainActor @preconcurrency final public func configure(with inputs: [ShortKitSDK.WidgetInput])
1288
+ @_Concurrency.MainActor @preconcurrency final public func setFeedItems(_ inputs: [ShortKitSDK.FeedInput])
1257
1289
  @_Concurrency.MainActor @preconcurrency @objc override final public func viewDidLoad()
1258
1290
  @_Concurrency.MainActor @preconcurrency @objc override final public func viewDidAppear(_ animated: Swift.Bool)
1259
1291
  @_Concurrency.MainActor @preconcurrency @objc override final public func viewWillDisappear(_ animated: Swift.Bool)
@@ -1271,6 +1303,15 @@ extension ShortKitSDK.ShortKitWidgetViewController : UIKit.UIViewControllerTrans
1271
1303
  @_Concurrency.MainActor @preconcurrency @objc final public func animationController(forDismissed dismissed: UIKit.UIViewController) -> (any UIKit.UIViewControllerAnimatedTransitioning)?
1272
1304
  @_Concurrency.MainActor @preconcurrency @objc final public func interactionControllerForDismissal(using animator: any UIKit.UIViewControllerAnimatedTransitioning) -> (any UIKit.UIViewControllerInteractiveTransitioning)?
1273
1305
  }
1306
+ public enum WidgetPlaybackMode : Swift.Equatable, Swift.Sendable {
1307
+ case singleVisibleRotating
1308
+ case allVisibleSimultaneous
1309
+ public static func == (a: ShortKitSDK.WidgetPlaybackMode, b: ShortKitSDK.WidgetPlaybackMode) -> Swift.Bool
1310
+ public func hash(into hasher: inout Swift.Hasher)
1311
+ public var hashValue: Swift.Int {
1312
+ get
1313
+ }
1314
+ }
1274
1315
  public struct WidgetConfig {
1275
1316
  public var cardCount: Swift.Int
1276
1317
  public var cardSpacing: CoreFoundation.CGFloat
@@ -1283,7 +1324,9 @@ public struct WidgetConfig {
1283
1324
  public var cardOverlay: ShortKitSDK.VideoOverlayMode
1284
1325
  public var feedConfig: ShortKitSDK.FeedConfig
1285
1326
  public var filter: ShortKitSDK.FeedFilter?
1286
- public init(cardCount: Swift.Int = 3, cardSpacing: CoreFoundation.CGFloat = 8, cornerRadius: CoreFoundation.CGFloat = 12, autoplay: Swift.Bool = true, muteOnStart: Swift.Bool = true, loop: Swift.Bool = true, rotationInterval: Foundation.TimeInterval = 10, clickAction: ShortKitSDK.PlayerClickAction = .feed, cardOverlay: ShortKitSDK.VideoOverlayMode = .none, feedConfig: ShortKitSDK.FeedConfig = FeedConfig(), filter: ShortKitSDK.FeedFilter? = nil)
1327
+ public var playbackMode: ShortKitSDK.WidgetPlaybackMode
1328
+ public var previewDuration: Foundation.TimeInterval
1329
+ public init(cardCount: Swift.Int = 3, cardSpacing: CoreFoundation.CGFloat = 8, cornerRadius: CoreFoundation.CGFloat = 12, autoplay: Swift.Bool = true, muteOnStart: Swift.Bool = true, loop: Swift.Bool = true, rotationInterval: Foundation.TimeInterval = 10, clickAction: ShortKitSDK.PlayerClickAction = .feed, cardOverlay: ShortKitSDK.VideoOverlayMode = .none, feedConfig: ShortKitSDK.FeedConfig = FeedConfig(), filter: ShortKitSDK.FeedFilter? = nil, playbackMode: ShortKitSDK.WidgetPlaybackMode = .singleVisibleRotating, previewDuration: Foundation.TimeInterval = 5.0)
1287
1330
  public func resolvedFeedConfig() -> ShortKitSDK.FeedConfig
1288
1331
  }
1289
1332
  public enum WidgetInput : Swift.Sendable {
@@ -1328,3 +1371,4 @@ extension ShortKitSDK.ContentSignal : Swift.Hashable {}
1328
1371
  extension ShortKitSDK.PlayerClickAction : Swift.Equatable {}
1329
1372
  extension ShortKitSDK.PlayerClickAction : Swift.Hashable {}
1330
1373
  extension ShortKitSDK.ShortKitPlayerView : Swift.Sendable {}
1374
+ extension ShortKitSDK.WidgetPlaybackMode : Swift.Hashable {}
@@ -10,39 +10,39 @@
10
10
  </data>
11
11
  <key>Info.plist</key>
12
12
  <data>
13
- c83UUfp8vl8OKNZgemM5Ckeupdw=
13
+ n0YLuilzX/YSi0+YLLdVwkcv7iY=
14
14
  </data>
15
15
  <key>Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.abi.json</key>
16
16
  <data>
17
- YIhDAI7GfkS3Bw8cCovcAQ/5bkc=
17
+ bMjJDoSuuCRYFpWH3EhlvZ0CS50=
18
18
  </data>
19
19
  <key>Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface</key>
20
20
  <data>
21
- jVb2+supqwkO14hFF9JSxbmcFUI=
21
+ v3GW9Gub1dJiosTgJ/z5NwmgWnY=
22
22
  </data>
23
23
  <key>Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.swiftdoc</key>
24
24
  <data>
25
- FQPcCHhpOilSUl89AxPXIKCLN/E=
25
+ 0oQnp4oNo+Ztwgww53FIZhz0zfM=
26
26
  </data>
27
27
  <key>Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.swiftinterface</key>
28
28
  <data>
29
- jVb2+supqwkO14hFF9JSxbmcFUI=
29
+ v3GW9Gub1dJiosTgJ/z5NwmgWnY=
30
30
  </data>
31
31
  <key>Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.abi.json</key>
32
32
  <data>
33
- YIhDAI7GfkS3Bw8cCovcAQ/5bkc=
33
+ bMjJDoSuuCRYFpWH3EhlvZ0CS50=
34
34
  </data>
35
35
  <key>Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface</key>
36
36
  <data>
37
- lr+Br5j/UDEGV7GBxg48gH/rncc=
37
+ Duv2bgxehsG2ZV4wnlh7s8/WzFk=
38
38
  </data>
39
39
  <key>Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.swiftdoc</key>
40
40
  <data>
41
- rTbauAd6wfGmUohCAGP+wwgmsNc=
41
+ Cu/J3KUQmcbxz8bCf9NQZ5aVBTM=
42
42
  </data>
43
43
  <key>Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.swiftinterface</key>
44
44
  <data>
45
- lr+Br5j/UDEGV7GBxg48gH/rncc=
45
+ Duv2bgxehsG2ZV4wnlh7s8/WzFk=
46
46
  </data>
47
47
  <key>Modules/module.modulemap</key>
48
48
  <data>
@@ -66,56 +66,56 @@
66
66
  <dict>
67
67
  <key>hash2</key>
68
68
  <data>
69
- v/uw62M6gyB+9mO/YoZTKs+xDZr5p0ehAwX9vFBOrA0=
69
+ G1RQHMm3BbfBLq07m9FgoUDszw3xw2Qb1+b9K0VYrr4=
70
70
  </data>
71
71
  </dict>
72
72
  <key>Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface</key>
73
73
  <dict>
74
74
  <key>hash2</key>
75
75
  <data>
76
- rxdNx/TSUVd/Pd8Fok5Kgwj/fUtUaq0HgqKC4JVJUx0=
76
+ HHpbkQ91Av7qOwHoz6asjSQ4d9TzPj7Lg+sxPVOhA30=
77
77
  </data>
78
78
  </dict>
79
79
  <key>Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.swiftdoc</key>
80
80
  <dict>
81
81
  <key>hash2</key>
82
82
  <data>
83
- khqs3UMVZ5tpEkBvJa5S2d3uTs80aVX+io6b4/TDNPE=
83
+ pbR9S11lEANUEhT1e5NkK796Tecps3q6SosOoeuApuQ=
84
84
  </data>
85
85
  </dict>
86
86
  <key>Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.swiftinterface</key>
87
87
  <dict>
88
88
  <key>hash2</key>
89
89
  <data>
90
- rxdNx/TSUVd/Pd8Fok5Kgwj/fUtUaq0HgqKC4JVJUx0=
90
+ HHpbkQ91Av7qOwHoz6asjSQ4d9TzPj7Lg+sxPVOhA30=
91
91
  </data>
92
92
  </dict>
93
93
  <key>Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.abi.json</key>
94
94
  <dict>
95
95
  <key>hash2</key>
96
96
  <data>
97
- v/uw62M6gyB+9mO/YoZTKs+xDZr5p0ehAwX9vFBOrA0=
97
+ G1RQHMm3BbfBLq07m9FgoUDszw3xw2Qb1+b9K0VYrr4=
98
98
  </data>
99
99
  </dict>
100
100
  <key>Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface</key>
101
101
  <dict>
102
102
  <key>hash2</key>
103
103
  <data>
104
- o9sGqAin0CW2u4q6wc85avBuxWQyEOnzzDME35fQ3ZY=
104
+ 6nFBIiTjaP5xmdLc7I/x9j4ASiT2UjNnxKmRYUGmLXw=
105
105
  </data>
106
106
  </dict>
107
107
  <key>Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.swiftdoc</key>
108
108
  <dict>
109
109
  <key>hash2</key>
110
110
  <data>
111
- HACqT0qILr02nDrz4hMSwIx1+67UnBeq1ote6RrUXWs=
111
+ Yx9LmEqOq+aeF+mSiKZyfw0FW/BySAPRrQMVzDyEiUU=
112
112
  </data>
113
113
  </dict>
114
114
  <key>Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.swiftinterface</key>
115
115
  <dict>
116
116
  <key>hash2</key>
117
117
  <data>
118
- o9sGqAin0CW2u4q6wc85avBuxWQyEOnzzDME35fQ3ZY=
118
+ 6nFBIiTjaP5xmdLc7I/x9j4ASiT2UjNnxKmRYUGmLXw=
119
119
  </data>
120
120
  </dict>
121
121
  <key>Modules/module.modulemap</key>
@@ -31,11 +31,40 @@ import ShortKitSDK
31
31
  /// one is mounted simultaneously.
32
32
  @objc public var widgetId: String?
33
33
 
34
+ /// Mirrors `ShortKitWidgetViewController.active`. Hosts use this to
35
+ /// release the widget's pool tile when it shouldn't be playing
36
+ /// (e.g. inactive tab, scrolled off-screen). Defaults to `true` so
37
+ /// existing host integrations behave identically to before.
38
+ @objc public var active: Bool = true {
39
+ didSet {
40
+ guard active != oldValue else { return }
41
+ widgetVC?.active = active
42
+ }
43
+ }
44
+
45
+ /// JSON-serialized `FeedInput[]` used to seed the expanded feed when
46
+ /// a card is tapped and `clickAction == .feed`. See
47
+ /// `ShortKitWidgetProps.feedItems` in the JS layer for full
48
+ /// semantics. The parsed list is forwarded to the SDK via
49
+ /// `ShortKitWidgetViewController.setFeedItems(_:)`.
50
+ @objc public var feedItems: String? {
51
+ didSet {
52
+ guard feedItems != oldValue else { return }
53
+ applyFeedItems()
54
+ }
55
+ }
56
+
34
57
  // MARK: - Child VC
35
58
 
36
59
  private var widgetVC: ShortKitWidgetViewController?
37
60
  private var parsedConfig: WidgetConfig?
38
61
  private var parsedItems: [WidgetInput] = []
62
+ private var parsedFeedItems: [FeedInput] = []
63
+ /// Parsed feedMask mode pulled out of the serialized config JSON in
64
+ /// `applyConfig()`. Stored separately because the SDK's
65
+ /// `ShortKitWidgetViewController.feedMask` is a top-level property,
66
+ /// not part of `WidgetConfig`.
67
+ private var parsedFeedMask: FeedMaskMode = .none
39
68
 
40
69
  // MARK: - Lifecycle
41
70
 
@@ -49,7 +78,17 @@ import ShortKitSDK
49
78
  public override func willMove(toWindow newWindow: UIWindow?) {
50
79
  super.willMove(toWindow: newWindow)
51
80
  if newWindow == nil {
52
- removeWidgetVC()
81
+ // The host UIView is leaving the window — typically a
82
+ // transient detach driven by `react-native-screens` when
83
+ // a tab blurs or a screen is pushed on top. We must NOT
84
+ // destroy the widget VC here; doing so causes the user
85
+ // to see the host's background through the widget on
86
+ // return, plus a fresh full reload of cards / players /
87
+ // HLS streams. Suspend instead: detach from the parent
88
+ // VC hierarchy + pause playback, but keep the VC and
89
+ // all its loaded state alive so we can re-attach in
90
+ // `didMoveToWindow` instantly.
91
+ suspendWidgetVC()
53
92
  }
54
93
  }
55
94
 
@@ -58,18 +97,62 @@ import ShortKitSDK
58
97
  widgetVC?.view.frame = bounds
59
98
  }
60
99
 
100
+ deinit {
101
+ // Final teardown when React truly unmounts the bridge UIView.
102
+ // The instance is going away, so it's safe to release the
103
+ // child VC's parent-chain references here. Without this, a
104
+ // suspended widget VC would leak (its parent VC still holds
105
+ // it as a child until the parent itself is deallocated).
106
+ destroyWidgetVC()
107
+ }
108
+
61
109
  // MARK: - VC Containment
62
110
 
63
111
  private func embedWidgetVCIfNeeded() {
64
- guard widgetVC == nil else { return }
65
- guard let sdk = ShortKitBridge.shared?.sdk else { return }
66
112
  guard let parentVC = findParentViewController() else { return }
67
113
 
114
+ // Re-attach a suspended VC. All loaded state — items, player
115
+ // pool checkouts, collection-view layout, scroll position —
116
+ // is preserved across a suspend/resume cycle, so the user
117
+ // sees the same widget reappear in place rather than a fresh
118
+ // load. Mirrors `ShortKitPlayerNativeView`.
119
+ if let vc = widgetVC {
120
+ parentVC.addChild(vc)
121
+ vc.view.frame = bounds
122
+ addSubview(vc.view)
123
+ vc.didMove(toParent: parentVC)
124
+ // Re-sync the active prop. While suspended we forced the
125
+ // VC inactive; restore whatever the JS prop currently says.
126
+ vc.active = active
127
+ return
128
+ }
129
+
130
+ // First mount — create a fresh VC.
131
+ guard let sdk = ShortKitBridge.shared?.sdk else { return }
132
+
68
133
  let widgetConfig = parsedConfig ?? WidgetConfig()
69
134
 
70
135
  // Pass items at construction so the VC never races the server fetch —
71
136
  // analogous to the feed's `feedItems` prop wiring.
72
137
  let vc = ShortKitWidgetViewController(shortKit: sdk, config: widgetConfig, items: parsedItems)
138
+ // Sync the active prop to the freshly-created VC. Without this, a
139
+ // widget that mounts already with active=false (e.g. on an
140
+ // unfocused tab) would still go through its initial-load path and
141
+ // start rotating before the prop change reaches it.
142
+ vc.active = active
143
+ // Forward the optional expanded-feed seed list. Set before view
144
+ // load so it's available the first time `openFeed()` runs —
145
+ // same ordering rationale as the player's bridge.
146
+ if !parsedFeedItems.isEmpty {
147
+ vc.setFeedItems(parsedFeedItems)
148
+ }
149
+ // Forward the optional host-supplied feed mask. The SDK's
150
+ // `feedMask` lives as a top-level VC property (not in
151
+ // WidgetConfig), so it has to be set after construction. The
152
+ // factory closure inside the mode is invoked by the SDK each
153
+ // time `openFeed()` fires — so each expansion gets its own
154
+ // FeedMaskHostView instance.
155
+ vc.feedMask = parsedFeedMask
73
156
  self.widgetVC = vc
74
157
 
75
158
  // Wire host-handleable card-tap callback. When the JS wrapper has
@@ -96,7 +179,25 @@ import ShortKitSDK
96
179
  vc.didMove(toParent: parentVC)
97
180
  }
98
181
 
99
- private func removeWidgetVC() {
182
+ /// Detach the widget VC from the parent VC + view hierarchy
183
+ /// without destroying it. Called when the bridge UIView leaves
184
+ /// the window (typically a `react-native-screens` tab blur).
185
+ /// All of the widget's loaded state is preserved so the
186
+ /// re-attach in `embedWidgetVCIfNeeded` can be instant. Pause
187
+ /// playback so the SDK pool tiles aren't held while suspended.
188
+ private func suspendWidgetVC() {
189
+ guard let vc = widgetVC else { return }
190
+ vc.active = false
191
+ vc.willMove(toParent: nil)
192
+ vc.view.removeFromSuperview()
193
+ vc.removeFromParent()
194
+ // Keep widgetVC reference — re-attached in embedWidgetVCIfNeeded.
195
+ }
196
+
197
+ /// Full teardown — called from `deinit` when React unmounts the
198
+ /// native view, and from `applyConfig` when the config string
199
+ /// changes and we need to rebuild the VC from scratch.
200
+ private func destroyWidgetVC() {
100
201
  guard let vc = widgetVC else { return }
101
202
  vc.willMove(toParent: nil)
102
203
  vc.view.removeFromSuperview()
@@ -109,12 +210,37 @@ import ShortKitSDK
109
210
  private func applyConfig() {
110
211
  guard let json = config else { return }
111
212
  parsedConfig = Self.parseWidgetConfig(json)
213
+ // FeedMask is stored as a sibling field in the serialized
214
+ // config JSON; extract it here so it's available when the VC
215
+ // gets (re)constructed in embedWidgetVCIfNeeded.
216
+ parsedFeedMask = Self.extractFeedMask(json)
112
217
  if widgetVC != nil {
113
- removeWidgetVC()
218
+ destroyWidgetVC()
114
219
  embedWidgetVCIfNeeded()
115
220
  }
116
221
  }
117
222
 
223
+ /// Pulls the `feedMask` field out of the raw config JSON without
224
+ /// re-parsing the rest of `WidgetConfig`. Returns `.none` if the
225
+ /// JSON is malformed or omits `feedMask`. Mirrors how the
226
+ /// equivalent value is read on `ShortKitPlayerNativeView`.
227
+ private static func extractFeedMask(_ json: String) -> FeedMaskMode {
228
+ guard let data = json.data(using: .utf8),
229
+ let obj = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else {
230
+ return .none
231
+ }
232
+ // The serializer emits feedMask either as the string "none" or
233
+ // as a {type, name} object — both arrive nested as a sub-JSON
234
+ // value (not stringified again, unlike feedConfig).
235
+ if let mask = obj["feedMask"] {
236
+ if let data = try? JSONSerialization.data(withJSONObject: mask),
237
+ let json = String(data: data, encoding: .utf8) {
238
+ return ShortKitBridge.parseFeedMask(json)
239
+ }
240
+ }
241
+ return .none
242
+ }
243
+
118
244
  private func applyItems() {
119
245
  parsedItems = items.flatMap { Self.parseWidgetInputs($0) } ?? []
120
246
  // Post-mount updates: push items through the public API.
@@ -123,6 +249,18 @@ import ShortKitSDK
123
249
  }
124
250
  }
125
251
 
252
+ private func applyFeedItems() {
253
+ // Empty / nil JSON ⇒ clear the host seed.
254
+ guard let json = feedItems,
255
+ let items = ShortKitBridge.parseFeedInputs(json) else {
256
+ parsedFeedItems = []
257
+ widgetVC?.setFeedItems([])
258
+ return
259
+ }
260
+ parsedFeedItems = items
261
+ widgetVC?.setFeedItems(items)
262
+ }
263
+
126
264
  // MARK: - Parsing
127
265
 
128
266
  private static func parseWidgetConfig(_ json: String) -> WidgetConfig {
@@ -138,6 +276,13 @@ import ShortKitSDK
138
276
  let muteOnStart = obj["muteOnStart"] as? Bool ?? true
139
277
  let loop = obj["loop"] as? Bool ?? true
140
278
  let rotationInterval = obj["rotationInterval"] as? TimeInterval ?? 10000
279
+ let previewDuration = obj["previewDuration"] as? TimeInterval ?? 5
280
+ let playbackMode: WidgetPlaybackMode
281
+ switch obj["playbackMode"] as? String {
282
+ case "allVisibleSimultaneous": playbackMode = .allVisibleSimultaneous
283
+ case "singleVisibleRotating": playbackMode = .singleVisibleRotating
284
+ default: playbackMode = .singleVisibleRotating
285
+ }
141
286
 
142
287
  let clickAction: PlayerClickAction
143
288
  switch obj["clickAction"] as? String {
@@ -180,7 +325,9 @@ import ShortKitSDK
180
325
  clickAction: clickAction,
181
326
  cardOverlay: overlayMode,
182
327
  feedConfig: feedConfig,
183
- filter: filter
328
+ filter: filter,
329
+ playbackMode: playbackMode,
330
+ previewDuration: previewDuration
184
331
  )
185
332
  }
186
333
 
@@ -24,5 +24,7 @@ RCT_EXPORT_MODULE(ShortKitWidgetView)
24
24
  RCT_EXPORT_VIEW_PROPERTY(config, NSString)
25
25
  RCT_EXPORT_VIEW_PROPERTY(items, NSString)
26
26
  RCT_EXPORT_VIEW_PROPERTY(widgetId, NSString)
27
+ RCT_EXPORT_VIEW_PROPERTY(active, BOOL)
28
+ RCT_EXPORT_VIEW_PROPERTY(feedItems, NSString)
27
29
 
28
30
  @end