@shortkitsdk/react-native 0.2.27 → 0.2.29

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 (38) hide show
  1. package/android/libs/shortkit-release.aar +0 -0
  2. package/android/src/main/java/com/shortkit/reactnative/ShortKitBridge.kt +8 -0
  3. package/android/src/main/java/com/shortkit/reactnative/ShortKitModule.kt +10 -0
  4. package/android/src/main/java/com/shortkit/reactnative/ShortKitPlayerNativeView.kt +4 -0
  5. package/android/src/main/java/com/shortkit/reactnative/ShortKitWidgetNativeView.kt +45 -33
  6. package/ios/ReactVideoCarouselOverlayHost.swift +6 -0
  7. package/ios/ShortKitBridge.swift +142 -35
  8. package/ios/ShortKitFeedView.swift +43 -44
  9. package/ios/ShortKitModule.mm +11 -0
  10. package/ios/ShortKitPlayerNativeView.swift +7 -1
  11. package/ios/ShortKitSDK.xcframework/Info.plist +5 -5
  12. package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Info.plist +2 -2
  13. package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.abi.json +950 -126
  14. package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.private.swiftinterface +26 -3
  15. package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.swiftdoc +0 -0
  16. package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.swiftinterface +26 -3
  17. package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/ShortKitSDK +0 -0
  18. package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/_CodeSignature/CodeResources +9 -9
  19. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Info.plist +2 -2
  20. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.abi.json +950 -126
  21. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface +26 -3
  22. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.swiftdoc +0 -0
  23. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.swiftinterface +26 -3
  24. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.abi.json +950 -126
  25. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface +26 -3
  26. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.swiftdoc +0 -0
  27. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.swiftinterface +26 -3
  28. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/ShortKitSDK +0 -0
  29. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/_CodeSignature/CodeResources +17 -17
  30. package/ios/ShortKitWidgetNativeView.swift +33 -12
  31. package/package.json +1 -1
  32. package/src/ShortKitFeed.tsx +34 -0
  33. package/src/ShortKitPlayer.tsx +25 -15
  34. package/src/ShortKitWidget.tsx +24 -18
  35. package/src/index.ts +1 -0
  36. package/src/serialization.ts +38 -0
  37. package/src/specs/NativeShortKitModule.ts +7 -0
  38. package/src/types.ts +19 -1
@@ -442,6 +442,15 @@ public enum ShortKitDownloadError : Swift.Error {
442
442
  public typealias Body = Swift.Never
443
443
  public typealias UIViewControllerType = ShortKitSDK.ShortKitFeedViewController
444
444
  }
445
+ public enum ShortKitFeedLifecycle {
446
+ case automatic
447
+ case manual
448
+ public static func == (a: ShortKitSDK.ShortKitFeedLifecycle, b: ShortKitSDK.ShortKitFeedLifecycle) -> Swift.Bool
449
+ public func hash(into hasher: inout Swift.Hasher)
450
+ public var hashValue: Swift.Int {
451
+ get
452
+ }
453
+ }
445
454
  @objc @_hasMissingDesignatedInitializers @_Concurrency.MainActor @preconcurrency public class ShortKitFeedViewController : UIKit.UIViewController {
446
455
  @_Concurrency.MainActor @preconcurrency public var debugPanelFactory: ((_ active: Combine.CurrentValueSubject<ShortKitSDK.DebugMetrics, Swift.Never>, _ prev: Combine.CurrentValueSubject<ShortKitSDK.DebugMetrics, Swift.Never>, _ next: Combine.CurrentValueSubject<ShortKitSDK.DebugMetrics, Swift.Never>) -> UIKit.UIView)?
447
456
  @_Concurrency.MainActor @preconcurrency public var onDismiss: (() -> Swift.Void)?
@@ -454,8 +463,12 @@ public enum ShortKitDownloadError : Swift.Error {
454
463
  }
455
464
  @_Concurrency.MainActor @preconcurrency public var onVideoCarouselCellTap: ((ShortKitSDK.ShortKitFeedViewController.VideoCarouselCellTapPayload) -> Swift.Void)?
456
465
  @_Concurrency.MainActor @preconcurrency public var onRefreshStateChanged: ((ShortKitSDK.ShortKitRefreshState) -> Swift.Void)?
466
+ @_Concurrency.MainActor @preconcurrency public var onFeedTransition: ((ShortKitSDK.FeedTransitionEvent) -> Swift.Void)?
467
+ @_Concurrency.MainActor @preconcurrency public var isActiveSurface: Swift.Bool {
468
+ get
469
+ }
457
470
  @_Concurrency.MainActor @preconcurrency public var seedThumbnail: UIKit.UIImage?
458
- @_Concurrency.MainActor @preconcurrency public init(shortKit: ShortKitSDK.ShortKit, config: ShortKitSDK.FeedConfig, startAtItemId: Swift.String? = nil)
471
+ @_Concurrency.MainActor @preconcurrency public init(shortKit: ShortKitSDK.ShortKit, config: ShortKitSDK.FeedConfig, startAtItemId: Swift.String? = nil, lifecycle: ShortKitSDK.ShortKitFeedLifecycle = .automatic)
459
472
  @_Concurrency.MainActor public func setFeedItems(_ items: [ShortKitSDK.FeedInput], startAtId: Swift.String? = nil)
460
473
  @_Concurrency.MainActor public func scrollToItem(id: Swift.String, animated: Swift.Bool)
461
474
  @_Concurrency.MainActor public func appendFeedItems(_ items: [ShortKitSDK.FeedInput])
@@ -465,6 +478,7 @@ public enum ShortKitDownloadError : Swift.Error {
465
478
  @_Concurrency.MainActor @preconcurrency @objc override dynamic public func viewWillAppear(_ animated: Swift.Bool)
466
479
  @_Concurrency.MainActor @preconcurrency @objc override dynamic public func viewDidAppear(_ animated: Swift.Bool)
467
480
  @_Concurrency.MainActor @preconcurrency @objc override dynamic public func viewWillDisappear(_ animated: Swift.Bool)
481
+ @available(*, deprecated, message: "Pass lifecycle: .manual to ShortKitFeedViewController's initializer instead.")
468
482
  @_Concurrency.MainActor @preconcurrency public func setBridgeManaged()
469
483
  @_Concurrency.MainActor @preconcurrency public func activate()
470
484
  @_Concurrency.MainActor @preconcurrency public func deactivate()
@@ -472,6 +486,7 @@ public enum ShortKitDownloadError : Swift.Error {
472
486
  @_Concurrency.MainActor @preconcurrency @objc override dynamic public var supportedInterfaceOrientations: UIKit.UIInterfaceOrientationMask {
473
487
  @objc get
474
488
  }
489
+ @_Concurrency.MainActor public func refresh()
475
490
  @objc deinit
476
491
  @_Concurrency.MainActor @preconcurrency @objc override dynamic public var canBecomeFirstResponder: Swift.Bool {
477
492
  @objc get
@@ -939,6 +954,9 @@ public struct FeedTransitionEvent : Swift.Equatable, Swift.Sendable {
939
954
  public let from: ShortKitSDK.ContentItem?
940
955
  public let to: ShortKitSDK.ContentItem?
941
956
  public let direction: ShortKitSDK.FeedTransitionEvent.Direction
957
+ public let fromFeedItem: ShortKitSDK.FeedItem?
958
+ public let toFeedItem: ShortKitSDK.FeedItem?
959
+ public init(phase: ShortKitSDK.FeedTransitionEvent.Phase, from: ShortKitSDK.ContentItem?, to: ShortKitSDK.ContentItem?, direction: ShortKitSDK.FeedTransitionEvent.Direction, fromFeedItem: ShortKitSDK.FeedItem? = nil, toFeedItem: ShortKitSDK.FeedItem? = nil)
942
960
  public static func == (a: ShortKitSDK.FeedTransitionEvent, b: ShortKitSDK.FeedTransitionEvent) -> Swift.Bool
943
961
  }
944
962
  public struct FormatChangeEvent : Swift.Equatable, Swift.Sendable {
@@ -1141,8 +1159,8 @@ extension ShortKitSDK.ShortKitPlayerViewController : UIKit.UIViewControllerTrans
1141
1159
  }
1142
1160
  @objc @_hasMissingDesignatedInitializers @_Concurrency.MainActor @preconcurrency final public class ShortKitWidgetViewController : UIKit.UIViewController {
1143
1161
  @_Concurrency.MainActor @preconcurrency final public var feedMask: ShortKitSDK.FeedMaskMode
1144
- @_Concurrency.MainActor @preconcurrency public init(shortKit: ShortKitSDK.ShortKit, config: ShortKitSDK.WidgetConfig)
1145
- @_Concurrency.MainActor @preconcurrency final public func configure(with items: [ShortKitSDK.ContentItem])
1162
+ @_Concurrency.MainActor @preconcurrency public init(shortKit: ShortKitSDK.ShortKit, config: ShortKitSDK.WidgetConfig, items: [ShortKitSDK.WidgetInput] = [])
1163
+ @_Concurrency.MainActor @preconcurrency final public func configure(with inputs: [ShortKitSDK.WidgetInput])
1146
1164
  @_Concurrency.MainActor @preconcurrency @objc override final public func viewDidLoad()
1147
1165
  @_Concurrency.MainActor @preconcurrency @objc override final public func viewDidAppear(_ animated: Swift.Bool)
1148
1166
  @_Concurrency.MainActor @preconcurrency @objc override final public func viewWillDisappear(_ animated: Swift.Bool)
@@ -1175,6 +1193,9 @@ public struct WidgetConfig {
1175
1193
  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)
1176
1194
  public func resolvedFeedConfig() -> ShortKitSDK.FeedConfig
1177
1195
  }
1196
+ public enum WidgetInput : Swift.Sendable {
1197
+ case video(playbackId: Swift.String, origin: ShortKitSDK.ContentOrigin = .other, fallbackUrl: Swift.String? = nil)
1198
+ }
1178
1199
  extension ShortKitSDK.AdQuartile : Swift.Equatable {}
1179
1200
  extension ShortKitSDK.AdQuartile : Swift.Hashable {}
1180
1201
  extension ShortKitSDK.ScrollAxis : Swift.Hashable {}
@@ -1187,6 +1208,8 @@ extension ShortKitSDK.SwipeCurve : Swift.RawRepresentable {}
1187
1208
  extension ShortKitSDK.DownloadMode : Swift.Equatable {}
1188
1209
  extension ShortKitSDK.DownloadMode : Swift.Hashable {}
1189
1210
  extension ShortKitSDK.ShortKitFeedView : Swift.Sendable {}
1211
+ extension ShortKitSDK.ShortKitFeedLifecycle : Swift.Equatable {}
1212
+ extension ShortKitSDK.ShortKitFeedLifecycle : Swift.Hashable {}
1190
1213
  extension ShortKitSDK.CaptionSource : Swift.Equatable {}
1191
1214
  extension ShortKitSDK.CaptionSource : Swift.Hashable {}
1192
1215
  extension ShortKitSDK.CaptionSource : Swift.RawRepresentable {}
@@ -442,6 +442,15 @@ public enum ShortKitDownloadError : Swift.Error {
442
442
  public typealias Body = Swift.Never
443
443
  public typealias UIViewControllerType = ShortKitSDK.ShortKitFeedViewController
444
444
  }
445
+ public enum ShortKitFeedLifecycle {
446
+ case automatic
447
+ case manual
448
+ public static func == (a: ShortKitSDK.ShortKitFeedLifecycle, b: ShortKitSDK.ShortKitFeedLifecycle) -> Swift.Bool
449
+ public func hash(into hasher: inout Swift.Hasher)
450
+ public var hashValue: Swift.Int {
451
+ get
452
+ }
453
+ }
445
454
  @objc @_hasMissingDesignatedInitializers @_Concurrency.MainActor @preconcurrency public class ShortKitFeedViewController : UIKit.UIViewController {
446
455
  @_Concurrency.MainActor @preconcurrency public var debugPanelFactory: ((_ active: Combine.CurrentValueSubject<ShortKitSDK.DebugMetrics, Swift.Never>, _ prev: Combine.CurrentValueSubject<ShortKitSDK.DebugMetrics, Swift.Never>, _ next: Combine.CurrentValueSubject<ShortKitSDK.DebugMetrics, Swift.Never>) -> UIKit.UIView)?
447
456
  @_Concurrency.MainActor @preconcurrency public var onDismiss: (() -> Swift.Void)?
@@ -454,8 +463,12 @@ public enum ShortKitDownloadError : Swift.Error {
454
463
  }
455
464
  @_Concurrency.MainActor @preconcurrency public var onVideoCarouselCellTap: ((ShortKitSDK.ShortKitFeedViewController.VideoCarouselCellTapPayload) -> Swift.Void)?
456
465
  @_Concurrency.MainActor @preconcurrency public var onRefreshStateChanged: ((ShortKitSDK.ShortKitRefreshState) -> Swift.Void)?
466
+ @_Concurrency.MainActor @preconcurrency public var onFeedTransition: ((ShortKitSDK.FeedTransitionEvent) -> Swift.Void)?
467
+ @_Concurrency.MainActor @preconcurrency public var isActiveSurface: Swift.Bool {
468
+ get
469
+ }
457
470
  @_Concurrency.MainActor @preconcurrency public var seedThumbnail: UIKit.UIImage?
458
- @_Concurrency.MainActor @preconcurrency public init(shortKit: ShortKitSDK.ShortKit, config: ShortKitSDK.FeedConfig, startAtItemId: Swift.String? = nil)
471
+ @_Concurrency.MainActor @preconcurrency public init(shortKit: ShortKitSDK.ShortKit, config: ShortKitSDK.FeedConfig, startAtItemId: Swift.String? = nil, lifecycle: ShortKitSDK.ShortKitFeedLifecycle = .automatic)
459
472
  @_Concurrency.MainActor public func setFeedItems(_ items: [ShortKitSDK.FeedInput], startAtId: Swift.String? = nil)
460
473
  @_Concurrency.MainActor public func scrollToItem(id: Swift.String, animated: Swift.Bool)
461
474
  @_Concurrency.MainActor public func appendFeedItems(_ items: [ShortKitSDK.FeedInput])
@@ -465,6 +478,7 @@ public enum ShortKitDownloadError : Swift.Error {
465
478
  @_Concurrency.MainActor @preconcurrency @objc override dynamic public func viewWillAppear(_ animated: Swift.Bool)
466
479
  @_Concurrency.MainActor @preconcurrency @objc override dynamic public func viewDidAppear(_ animated: Swift.Bool)
467
480
  @_Concurrency.MainActor @preconcurrency @objc override dynamic public func viewWillDisappear(_ animated: Swift.Bool)
481
+ @available(*, deprecated, message: "Pass lifecycle: .manual to ShortKitFeedViewController's initializer instead.")
468
482
  @_Concurrency.MainActor @preconcurrency public func setBridgeManaged()
469
483
  @_Concurrency.MainActor @preconcurrency public func activate()
470
484
  @_Concurrency.MainActor @preconcurrency public func deactivate()
@@ -472,6 +486,7 @@ public enum ShortKitDownloadError : Swift.Error {
472
486
  @_Concurrency.MainActor @preconcurrency @objc override dynamic public var supportedInterfaceOrientations: UIKit.UIInterfaceOrientationMask {
473
487
  @objc get
474
488
  }
489
+ @_Concurrency.MainActor public func refresh()
475
490
  @objc deinit
476
491
  @_Concurrency.MainActor @preconcurrency @objc override dynamic public var canBecomeFirstResponder: Swift.Bool {
477
492
  @objc get
@@ -939,6 +954,9 @@ public struct FeedTransitionEvent : Swift.Equatable, Swift.Sendable {
939
954
  public let from: ShortKitSDK.ContentItem?
940
955
  public let to: ShortKitSDK.ContentItem?
941
956
  public let direction: ShortKitSDK.FeedTransitionEvent.Direction
957
+ public let fromFeedItem: ShortKitSDK.FeedItem?
958
+ public let toFeedItem: ShortKitSDK.FeedItem?
959
+ public init(phase: ShortKitSDK.FeedTransitionEvent.Phase, from: ShortKitSDK.ContentItem?, to: ShortKitSDK.ContentItem?, direction: ShortKitSDK.FeedTransitionEvent.Direction, fromFeedItem: ShortKitSDK.FeedItem? = nil, toFeedItem: ShortKitSDK.FeedItem? = nil)
942
960
  public static func == (a: ShortKitSDK.FeedTransitionEvent, b: ShortKitSDK.FeedTransitionEvent) -> Swift.Bool
943
961
  }
944
962
  public struct FormatChangeEvent : Swift.Equatable, Swift.Sendable {
@@ -1141,8 +1159,8 @@ extension ShortKitSDK.ShortKitPlayerViewController : UIKit.UIViewControllerTrans
1141
1159
  }
1142
1160
  @objc @_hasMissingDesignatedInitializers @_Concurrency.MainActor @preconcurrency final public class ShortKitWidgetViewController : UIKit.UIViewController {
1143
1161
  @_Concurrency.MainActor @preconcurrency final public var feedMask: ShortKitSDK.FeedMaskMode
1144
- @_Concurrency.MainActor @preconcurrency public init(shortKit: ShortKitSDK.ShortKit, config: ShortKitSDK.WidgetConfig)
1145
- @_Concurrency.MainActor @preconcurrency final public func configure(with items: [ShortKitSDK.ContentItem])
1162
+ @_Concurrency.MainActor @preconcurrency public init(shortKit: ShortKitSDK.ShortKit, config: ShortKitSDK.WidgetConfig, items: [ShortKitSDK.WidgetInput] = [])
1163
+ @_Concurrency.MainActor @preconcurrency final public func configure(with inputs: [ShortKitSDK.WidgetInput])
1146
1164
  @_Concurrency.MainActor @preconcurrency @objc override final public func viewDidLoad()
1147
1165
  @_Concurrency.MainActor @preconcurrency @objc override final public func viewDidAppear(_ animated: Swift.Bool)
1148
1166
  @_Concurrency.MainActor @preconcurrency @objc override final public func viewWillDisappear(_ animated: Swift.Bool)
@@ -1175,6 +1193,9 @@ public struct WidgetConfig {
1175
1193
  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)
1176
1194
  public func resolvedFeedConfig() -> ShortKitSDK.FeedConfig
1177
1195
  }
1196
+ public enum WidgetInput : Swift.Sendable {
1197
+ case video(playbackId: Swift.String, origin: ShortKitSDK.ContentOrigin = .other, fallbackUrl: Swift.String? = nil)
1198
+ }
1178
1199
  extension ShortKitSDK.AdQuartile : Swift.Equatable {}
1179
1200
  extension ShortKitSDK.AdQuartile : Swift.Hashable {}
1180
1201
  extension ShortKitSDK.ScrollAxis : Swift.Hashable {}
@@ -1187,6 +1208,8 @@ extension ShortKitSDK.SwipeCurve : Swift.RawRepresentable {}
1187
1208
  extension ShortKitSDK.DownloadMode : Swift.Equatable {}
1188
1209
  extension ShortKitSDK.DownloadMode : Swift.Hashable {}
1189
1210
  extension ShortKitSDK.ShortKitFeedView : Swift.Sendable {}
1211
+ extension ShortKitSDK.ShortKitFeedLifecycle : Swift.Equatable {}
1212
+ extension ShortKitSDK.ShortKitFeedLifecycle : Swift.Hashable {}
1190
1213
  extension ShortKitSDK.CaptionSource : Swift.Equatable {}
1191
1214
  extension ShortKitSDK.CaptionSource : Swift.Hashable {}
1192
1215
  extension ShortKitSDK.CaptionSource : Swift.RawRepresentable {}
@@ -10,39 +10,39 @@
10
10
  </data>
11
11
  <key>Info.plist</key>
12
12
  <data>
13
- vTgqqfDJyF8GYp6hOl5ygsKZXpc=
13
+ SGnC4k70E9DgpOqahVfG8CzDvZA=
14
14
  </data>
15
15
  <key>Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.abi.json</key>
16
16
  <data>
17
- 1CWbP83M4niqwACjutv+h5bAQI8=
17
+ BO1VUECw+jNellCun0jhxv3t30k=
18
18
  </data>
19
19
  <key>Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface</key>
20
20
  <data>
21
- SY4J8Ap5bvNmlGr2eHB/mIEc9/4=
21
+ CBxkj0soc11JQFMNAKh03fEskOQ=
22
22
  </data>
23
23
  <key>Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.swiftdoc</key>
24
24
  <data>
25
- Jifa8RGekCm+oLvj1vexV+qHBxg=
25
+ Egfd+TPgbG9XhezyyhpOkJ9bZWs=
26
26
  </data>
27
27
  <key>Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.swiftinterface</key>
28
28
  <data>
29
- SY4J8Ap5bvNmlGr2eHB/mIEc9/4=
29
+ CBxkj0soc11JQFMNAKh03fEskOQ=
30
30
  </data>
31
31
  <key>Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.abi.json</key>
32
32
  <data>
33
- 1CWbP83M4niqwACjutv+h5bAQI8=
33
+ BO1VUECw+jNellCun0jhxv3t30k=
34
34
  </data>
35
35
  <key>Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface</key>
36
36
  <data>
37
- RSB+lYIOsHV+EHcf6nw6updgwoE=
37
+ KDzWlPhZbTYIibjJVtICWSKv9cs=
38
38
  </data>
39
39
  <key>Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.swiftdoc</key>
40
40
  <data>
41
- 4SaiyfqnnCuP3NHBedJ86U5WUvk=
41
+ CbLKbJe6jCpRFjhJ5MJ7F7Um93M=
42
42
  </data>
43
43
  <key>Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.swiftinterface</key>
44
44
  <data>
45
- RSB+lYIOsHV+EHcf6nw6updgwoE=
45
+ KDzWlPhZbTYIibjJVtICWSKv9cs=
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
- 6osxQFoWx1z1shKfM1SJVKzrEMvwpavL4nz8CXhPCf0=
69
+ fHbFQio59u+N64dapbLRpLdCd4VatCDVkbn5qTzHCxc=
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
- 1/jxH+/lRA97UGj3ZA78cxyVLWeDthh0KFAHyutYAGs=
76
+ Ct1MN9BrXD/Rkc+lJb6iANMaf9f+RwWB4+pYW/i+3Ek=
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
- 1ZNQBox7b3AwcLy9/eOdX9J9kLPO6aiDoKklf4b+uDw=
83
+ aLVo05BXMvhibMAdWTtKpK4Ezm91V9IJz/GAm9WDhLw=
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
- 1/jxH+/lRA97UGj3ZA78cxyVLWeDthh0KFAHyutYAGs=
90
+ Ct1MN9BrXD/Rkc+lJb6iANMaf9f+RwWB4+pYW/i+3Ek=
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
- 6osxQFoWx1z1shKfM1SJVKzrEMvwpavL4nz8CXhPCf0=
97
+ fHbFQio59u+N64dapbLRpLdCd4VatCDVkbn5qTzHCxc=
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
- LcZQmnn2zALd1t49D1Ky9DkTE/qLtiA/Y8X7G8X0tpA=
104
+ 4rQvWmFNy7cluozJQCGW3y7OdbgvVQco8KNNJ5gFrhc=
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
- rFL1rnzbA6I/ynZT99TT87vcqERbX/oj+lvvjIITisM=
111
+ mVc5JWN6Fy34JoJsotmdTST52bcYpwdaOl1WZGL42xs=
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
- LcZQmnn2zALd1t49D1Ky9DkTE/qLtiA/Y8X7G8X0tpA=
118
+ 4rQvWmFNy7cluozJQCGW3y7OdbgvVQco8KNNJ5gFrhc=
119
119
  </data>
120
120
  </dict>
121
121
  <key>Modules/module.modulemap</key>
@@ -6,7 +6,7 @@ import ShortKitSDK
6
6
  ///
7
7
  /// Props (set by RCTViewManager):
8
8
  /// - `config`: JSON string with WidgetConfig values
9
- /// - `items`: JSON string with ContentItem array
9
+ /// - `items`: JSON string with WidgetInput array (compact playback-ID form)
10
10
  @objc public class ShortKitWidgetNativeView: UIView {
11
11
 
12
12
  // MARK: - Props
@@ -29,6 +29,7 @@ import ShortKitSDK
29
29
 
30
30
  private var widgetVC: ShortKitWidgetViewController?
31
31
  private var parsedConfig: WidgetConfig?
32
+ private var parsedItems: [WidgetInput] = []
32
33
 
33
34
  // MARK: - Lifecycle
34
35
 
@@ -60,7 +61,9 @@ import ShortKitSDK
60
61
 
61
62
  let widgetConfig = parsedConfig ?? WidgetConfig()
62
63
 
63
- let vc = ShortKitWidgetViewController(shortKit: sdk, config: widgetConfig)
64
+ // Pass items at construction so the VC never races the server fetch —
65
+ // analogous to the feed's `feedItems` prop wiring.
66
+ let vc = ShortKitWidgetViewController(shortKit: sdk, config: widgetConfig, items: parsedItems)
64
67
  self.widgetVC = vc
65
68
 
66
69
  parentVC.addChild(vc)
@@ -68,11 +71,6 @@ import ShortKitSDK
68
71
  vc.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
69
72
  addSubview(vc.view)
70
73
  vc.didMove(toParent: parentVC)
71
-
72
- // If items were already set, apply them
73
- if let json = items, let contentItems = Self.parseContentItems(json) {
74
- vc.configure(with: contentItems)
75
- }
76
74
  }
77
75
 
78
76
  private func removeWidgetVC() {
@@ -95,8 +93,11 @@ import ShortKitSDK
95
93
  }
96
94
 
97
95
  private func applyItems() {
98
- guard let json = items, let contentItems = Self.parseContentItems(json) else { return }
99
- widgetVC?.configure(with: contentItems)
96
+ parsedItems = items.flatMap { Self.parseWidgetInputs($0) } ?? []
97
+ // Post-mount updates: push items through the public API.
98
+ if let vc = widgetVC {
99
+ vc.configure(with: parsedItems)
100
+ }
100
101
  }
101
102
 
102
103
  // MARK: - Parsing
@@ -140,6 +141,11 @@ import ShortKitSDK
140
141
  return ShortKitBridge.parseFeedFilter(filterStr)
141
142
  }()
142
143
 
144
+ let feedConfig: FeedConfig = {
145
+ guard let feedConfigStr = obj["feedConfig"] as? String else { return FeedConfig() }
146
+ return ShortKitBridge.parseFeedConfig(feedConfigStr)
147
+ }()
148
+
143
149
  return WidgetConfig(
144
150
  cardCount: cardCount,
145
151
  cardSpacing: cardSpacing,
@@ -150,13 +156,28 @@ import ShortKitSDK
150
156
  rotationInterval: rotationInterval / 1000.0, // JS sends ms, iOS expects seconds
151
157
  clickAction: clickAction,
152
158
  cardOverlay: overlayMode,
159
+ feedConfig: feedConfig,
153
160
  filter: filter
154
161
  )
155
162
  }
156
163
 
157
- private static func parseContentItems(_ json: String) -> [ContentItem]? {
158
- guard let data = json.data(using: .utf8) else { return nil }
159
- return try? JSONDecoder().decode([ContentItem].self, from: data)
164
+ /// Parse a JSON array of `WidgetInput` values (compact playback-ID form).
165
+ /// Mirrors the JS `WidgetInput` type: `{ type: 'video'; playbackId: string; origin?: string; fallbackUrl?: string }`.
166
+ private static func parseWidgetInputs(_ json: String) -> [WidgetInput]? {
167
+ guard let data = json.data(using: .utf8),
168
+ let arr = try? JSONSerialization.jsonObject(with: data) as? [[String: Any]] else {
169
+ return nil
170
+ }
171
+ return arr.compactMap { obj -> WidgetInput? in
172
+ guard let type = obj["type"] as? String, type == "video",
173
+ let playbackId = obj["playbackId"] as? String else { return nil }
174
+ let origin: ContentOrigin = {
175
+ guard let s = obj["origin"] as? String else { return .other }
176
+ return s == "ios_upload" ? .iosUpload : .other
177
+ }()
178
+ let fallbackUrl = obj["fallbackUrl"] as? String
179
+ return .video(playbackId: playbackId, origin: origin, fallbackUrl: fallbackUrl)
180
+ }
160
181
  }
161
182
 
162
183
  // MARK: - Helpers
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shortkitsdk/react-native",
3
- "version": "0.2.27",
3
+ "version": "0.2.29",
4
4
  "description": "ShortKit React Native SDK — short-form video feed",
5
5
  "react-native": "src/index",
6
6
  "source": "src/index",
@@ -76,6 +76,9 @@ export const ShortKitFeed = forwardRef<ShortKitFeedHandle, ShortKitFeedProps>(
76
76
  applyFilter: (filter: FeedFilter | null) => {
77
77
  NativeShortKitModule?.applyFilter(feedId, filter ? JSON.stringify(filter) : null);
78
78
  },
79
+ refresh: () => {
80
+ NativeShortKitModule?.refresh(feedId);
81
+ },
79
82
  }), [feedId]);
80
83
 
81
84
  // Subscribe to per-feed remaining content count events
@@ -160,6 +163,11 @@ export const ShortKitFeed = forwardRef<ShortKitFeedHandle, ShortKitFeedProps>(
160
163
  if (onLoop) {
161
164
  subscriptions.push(
162
165
  NativeShortKitModule.onDidLoop((event) => {
166
+ // Filter to this feed instance — onDidLoop is fired from the
167
+ // shared player's global Combine publisher. The native bridge
168
+ // tags the emit with the active surface's feedId; reject events
169
+ // that don't match. Accept empty feedId for forward-compat.
170
+ if (event.feedId !== feedId && event.feedId !== '') return;
163
171
  onLoop({ contentId: event.contentId, loopCount: event.loopCount });
164
172
  }),
165
173
  );
@@ -168,6 +176,16 @@ export const ShortKitFeed = forwardRef<ShortKitFeedHandle, ShortKitFeedProps>(
168
176
  if (onFeedTransition) {
169
177
  subscriptions.push(
170
178
  NativeShortKitModule.onFeedTransition((event) => {
179
+ // Filter to this feed instance — `player.feedTransition` is a
180
+ // singleton publisher on the shared player; the native bridge now
181
+ // tags the emit with the active surface's feedId. Without this
182
+ // filter, every <ShortKitFeed> consumer receives every transition,
183
+ // which caused cross-tab state pollution (e.g., sibling tabs'
184
+ // onCurrentItemIdChange handlers firing on the active tab's
185
+ // scroll, leaking that item ID into their own startAtItemId).
186
+ // Accept empty feedId as a fallback for older native builds that
187
+ // don't tag the emit yet — same pattern as other callbacks here.
188
+ if (event.feedId !== feedId && event.feedId !== '') return;
171
189
  onFeedTransition({
172
190
  phase: event.phase as 'began' | 'ended',
173
191
  from: deserializeContentItem(event.fromItem ?? null),
@@ -181,6 +199,10 @@ export const ShortKitFeed = forwardRef<ShortKitFeedHandle, ShortKitFeedProps>(
181
199
  if (onFormatChange) {
182
200
  subscriptions.push(
183
201
  NativeShortKitModule.onFormatChange((event) => {
202
+ // Filter to this feed instance — onFormatChange fires from the
203
+ // shared player's global publisher; bridge tags with active
204
+ // surface's feedId. Reject events addressed to other feeds.
205
+ if (event.feedId !== feedId && event.feedId !== '') return;
184
206
  onFormatChange({
185
207
  contentId: event.contentId,
186
208
  fromBitrate: event.fromBitrate,
@@ -195,6 +217,9 @@ export const ShortKitFeed = forwardRef<ShortKitFeedHandle, ShortKitFeedProps>(
195
217
  if (onContentTapped) {
196
218
  subscriptions.push(
197
219
  NativeShortKitModule.onContentTapped((event) => {
220
+ // Filter to this feed instance — ShortKitDelegate is a singleton
221
+ // (bridge); native side tags with active surface's feedId.
222
+ if (event.feedId !== feedId && event.feedId !== '') return;
198
223
  onContentTapped(event.contentId, event.index);
199
224
  }),
200
225
  );
@@ -226,6 +251,10 @@ export const ShortKitFeed = forwardRef<ShortKitFeedHandle, ShortKitFeedProps>(
226
251
  if (onDidFetchContentItems) {
227
252
  subscriptions.push(
228
253
  NativeShortKitModule.onDidFetchContentItems((event) => {
254
+ // Filter to this feed instance — ShortKitDelegate is a singleton
255
+ // (bridge); native side tags with active surface's feedId (at
256
+ // delegate call time, before any Task/await suspension).
257
+ if (event.feedId !== feedId && event.feedId !== '') return;
229
258
  try {
230
259
  const items = JSON.parse(event.items);
231
260
  onDidFetchContentItems(items);
@@ -239,6 +268,11 @@ export const ShortKitFeed = forwardRef<ShortKitFeedHandle, ShortKitFeedProps>(
239
268
  if (onCarouselActiveVideoCompleted) {
240
269
  subscriptions.push(
241
270
  NativeShortKitModule.onCarouselActiveVideoCompleted((event) => {
271
+ // Filter to this feed instance — overlay events were previously
272
+ // unscoped per-feed; native side now tags with active surface's
273
+ // feedId. surfaceId continues to identify the React overlay host
274
+ // (separate concern from feedId).
275
+ if (event.feedId !== feedId && event.feedId !== '') return;
242
276
  try {
243
277
  onCarouselActiveVideoCompleted({
244
278
  surfaceId: event.surfaceId,
@@ -1,7 +1,11 @@
1
- import React, { useMemo } from 'react';
1
+ import React, { useLayoutEffect, useMemo } from 'react';
2
2
  import { View, StyleSheet } from 'react-native';
3
3
  import type { ShortKitPlayerProps } from './types';
4
4
  import ShortKitPlayerView from './specs/ShortKitPlayerViewNativeComponent';
5
+ import { serializePlayerConfig } from './serialization';
6
+ import { registerOverlayComponent } from './ShortKitOverlaySurface';
7
+ import { registerCarouselOverlayComponent } from './ShortKitCarouselOverlaySurface';
8
+ import { registerVideoCarouselOverlayComponent } from './ShortKitVideoCarouselOverlaySurface';
5
9
 
6
10
  /**
7
11
  * Single-video player component. Displays one video with thumbnail fallback
@@ -19,21 +23,27 @@ export function ShortKitPlayer(props: ShortKitPlayerProps) {
19
23
 
20
24
  const clickAction = config?.clickAction ?? 'feed';
21
25
 
26
+ useLayoutEffect(() => {
27
+ if (config?.overlay && config.overlay !== 'none') {
28
+ registerOverlayComponent(config.overlay.name, config.overlay.component);
29
+ }
30
+ if (config?.feedConfig) {
31
+ const fc = config.feedConfig;
32
+ if (fc.overlay && fc.overlay !== 'none') {
33
+ registerOverlayComponent(fc.overlay.name, fc.overlay.component);
34
+ }
35
+ if (fc.carouselOverlay && fc.carouselOverlay !== 'none') {
36
+ registerCarouselOverlayComponent(fc.carouselOverlay.name, fc.carouselOverlay.component);
37
+ }
38
+ if (fc.videoCarouselOverlay && fc.videoCarouselOverlay !== 'none') {
39
+ registerVideoCarouselOverlayComponent(fc.videoCarouselOverlay.name, fc.videoCarouselOverlay.component);
40
+ }
41
+ }
42
+ }, [config?.overlay, config?.feedConfig]);
43
+
22
44
  const serializedConfig = useMemo(() => {
23
- const cfg = config ?? {};
24
- return JSON.stringify({
25
- cornerRadius: cfg.cornerRadius ?? 12,
26
- clickAction: clickAction,
27
- autoplay: cfg.autoplay ?? true,
28
- loop: cfg.loop ?? true,
29
- muteOnStart: cfg.muteOnStart ?? true,
30
- overlay: cfg.overlay
31
- ? typeof cfg.overlay === 'string'
32
- ? cfg.overlay
33
- : { type: 'custom' }
34
- : 'none',
35
- });
36
- }, [config, clickAction]);
45
+ return serializePlayerConfig(config ?? {});
46
+ }, [config]);
37
47
 
38
48
  const serializedItem = useMemo(() => {
39
49
  if (!contentItem) return undefined;
@@ -1,8 +1,12 @@
1
- import React, { useContext, useMemo } from 'react';
1
+ import React, { useContext, useLayoutEffect, useMemo } from 'react';
2
2
  import { View, StyleSheet } from 'react-native';
3
3
  import type { ShortKitWidgetProps } from './types';
4
4
  import ShortKitWidgetView from './specs/ShortKitWidgetViewNativeComponent';
5
5
  import { ShortKitInitContext } from './ShortKitContext';
6
+ import { serializeWidgetConfig } from './serialization';
7
+ import { registerOverlayComponent } from './ShortKitOverlaySurface';
8
+ import { registerCarouselOverlayComponent } from './ShortKitCarouselOverlaySurface';
9
+ import { registerVideoCarouselOverlayComponent } from './ShortKitVideoCarouselOverlaySurface';
6
10
 
7
11
  /**
8
12
  * Horizontal carousel widget component. Displays a row of video cards
@@ -18,24 +22,26 @@ export function ShortKitWidget(props: ShortKitWidgetProps) {
18
22
  throw new Error('ShortKitWidget must be used within a ShortKitProvider');
19
23
  }
20
24
 
25
+ useLayoutEffect(() => {
26
+ if (config?.overlay && config.overlay !== 'none') {
27
+ registerOverlayComponent(config.overlay.name, config.overlay.component);
28
+ }
29
+ if (config?.feedConfig) {
30
+ const fc = config.feedConfig;
31
+ if (fc.overlay && fc.overlay !== 'none') {
32
+ registerOverlayComponent(fc.overlay.name, fc.overlay.component);
33
+ }
34
+ if (fc.carouselOverlay && fc.carouselOverlay !== 'none') {
35
+ registerCarouselOverlayComponent(fc.carouselOverlay.name, fc.carouselOverlay.component);
36
+ }
37
+ if (fc.videoCarouselOverlay && fc.videoCarouselOverlay !== 'none') {
38
+ registerVideoCarouselOverlayComponent(fc.videoCarouselOverlay.name, fc.videoCarouselOverlay.component);
39
+ }
40
+ }
41
+ }, [config?.overlay, config?.feedConfig]);
42
+
21
43
  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
- filter: cfg.filter ? JSON.stringify(cfg.filter) : undefined,
38
- });
44
+ return serializeWidgetConfig(config ?? {});
39
45
  }, [config]);
40
46
 
41
47
  const serializedItems = useMemo(() => {
package/src/index.ts CHANGED
@@ -16,6 +16,7 @@ export type {
16
16
  PlayerConfig,
17
17
  PlayerClickAction,
18
18
  WidgetConfig,
19
+ WidgetInput,
19
20
 
20
21
  ContentItem,
21
22
  CarouselImage,
@@ -4,6 +4,9 @@ import type {
4
4
  FeedInput,
5
5
  PlayerState,
6
6
  PlayerTime,
7
+ WidgetConfig,
8
+ PlayerConfig,
9
+ OverlayConfig,
7
10
  VideoCarouselVideoInput,
8
11
  } from './types';
9
12
 
@@ -130,3 +133,38 @@ export function serializeFeedInputs(items: FeedInput[]): string {
130
133
  });
131
134
  return JSON.stringify(serialized);
132
135
  }
136
+
137
+ function serializeOverlay(overlay: OverlayConfig | undefined): string | { type: 'custom'; name: string } {
138
+ if (!overlay || overlay === 'none') return 'none';
139
+ return { type: 'custom', name: overlay.name };
140
+ }
141
+
142
+ export function serializeWidgetConfig(config: WidgetConfig): string {
143
+ const cfg = config ?? {};
144
+ return JSON.stringify({
145
+ cardCount: cfg.cardCount ?? 3,
146
+ cardSpacing: cfg.cardSpacing ?? 8,
147
+ cornerRadius: cfg.cornerRadius ?? 12,
148
+ autoplay: cfg.autoplay ?? true,
149
+ muteOnStart: cfg.muteOnStart ?? true,
150
+ loop: cfg.loop ?? true,
151
+ rotationInterval: cfg.rotationInterval ?? 10000,
152
+ clickAction: cfg.clickAction ?? 'feed',
153
+ overlay: serializeOverlay(cfg.overlay),
154
+ filter: cfg.filter ? JSON.stringify(cfg.filter) : undefined,
155
+ feedConfig: cfg.feedConfig ? serializeFeedConfig(cfg.feedConfig) : undefined,
156
+ });
157
+ }
158
+
159
+ export function serializePlayerConfig(config: PlayerConfig): string {
160
+ const cfg = config ?? {};
161
+ return JSON.stringify({
162
+ cornerRadius: cfg.cornerRadius ?? 12,
163
+ clickAction: cfg.clickAction ?? 'feed',
164
+ autoplay: cfg.autoplay ?? true,
165
+ loop: cfg.loop ?? true,
166
+ muteOnStart: cfg.muteOnStart ?? true,
167
+ overlay: serializeOverlay(cfg.overlay),
168
+ feedConfig: cfg.feedConfig ? serializeFeedConfig(cfg.feedConfig) : undefined,
169
+ });
170
+ }