@shortkitsdk/react-native 0.2.34 → 0.2.36

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 (52) hide show
  1. package/android/build.gradle.kts +8 -0
  2. package/android/libs/shortkit-release.aar +0 -0
  3. package/android/src/main/java/com/shortkit/reactnative/ReactCarouselOverlayHost.kt +100 -47
  4. package/android/src/main/java/com/shortkit/reactnative/ReactOverlayHost.kt +54 -8
  5. package/android/src/main/java/com/shortkit/reactnative/ReactVideoCarouselOverlayHost.kt +240 -27
  6. package/android/src/main/java/com/shortkit/reactnative/ShortKitBridge.kt +151 -1
  7. package/android/src/main/java/com/shortkit/reactnative/ShortKitFeedView.kt +135 -6
  8. package/android/src/main/java/com/shortkit/reactnative/ShortKitFeedViewManager.kt +15 -0
  9. package/android/src/main/java/com/shortkit/reactnative/ShortKitModule.kt +21 -11
  10. package/android/src/main/java/com/shortkit/reactnative/ShortKitPackage.kt +0 -2
  11. package/android/src/test/java/com/shortkit/reactnative/ReactCarouselOverlayHostEmitTest.kt +134 -0
  12. package/android/src/test/java/com/shortkit/reactnative/ReactOverlayHostDragTest.kt +45 -0
  13. package/android/src/test/java/com/shortkit/reactnative/ReactVideoCarouselOverlayHostDragTest.kt +69 -0
  14. package/android/src/test/java/com/shortkit/reactnative/ReactVideoCarouselOverlayHostEmitTest.kt +144 -0
  15. package/android/src/test/java/com/shortkit/reactnative/ShortKitFeedViewActivePropTest.kt +57 -0
  16. package/ios/ReactOverlayHost.swift +10 -8
  17. package/ios/ReactVideoCarouselOverlayHost.swift +6 -5
  18. package/ios/ShortKitBridge.swift +18 -0
  19. package/ios/ShortKitModule.mm +5 -0
  20. package/ios/ShortKitPlayerNativeView.swift +36 -0
  21. package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Info.plist +2 -2
  22. package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.abi.json +1252 -82
  23. package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.private.swiftinterface +28 -2
  24. package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.swiftdoc +0 -0
  25. package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.swiftinterface +28 -2
  26. package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/ShortKitSDK +0 -0
  27. package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/_CodeSignature/CodeResources +9 -9
  28. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Info.plist +2 -2
  29. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.abi.json +1252 -82
  30. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface +28 -2
  31. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.swiftdoc +0 -0
  32. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.swiftinterface +28 -2
  33. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.abi.json +1252 -82
  34. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface +28 -2
  35. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.swiftdoc +0 -0
  36. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.swiftinterface +28 -2
  37. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/ShortKitSDK +0 -0
  38. package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/_CodeSignature/CodeResources +17 -17
  39. package/ios/ShortKitWidgetNativeView.swift +30 -3
  40. package/ios/ShortKitWidgetNativeViewManager.mm +1 -0
  41. package/package.json +1 -1
  42. package/src/ShortKitCommands.ts +20 -0
  43. package/src/ShortKitFeed.tsx +21 -0
  44. package/src/ShortKitPlayer.tsx +20 -1
  45. package/src/ShortKitWidget.tsx +63 -15
  46. package/src/specs/NativeShortKitModule.ts +10 -0
  47. package/src/specs/ShortKitWidgetViewNativeComponent.ts +15 -3
  48. package/src/types.ts +40 -0
  49. package/android/src/main/java/com/shortkit/reactnative/ShortKitPlayerNativeView.kt +0 -149
  50. package/android/src/main/java/com/shortkit/reactnative/ShortKitPlayerViewManager.kt +0 -35
  51. package/android/src/main/java/com/shortkit/reactnative/ShortKitWidgetNativeView.kt +0 -149
  52. package/android/src/main/java/com/shortkit/reactnative/ShortKitWidgetViewManager.kt +0 -30
@@ -556,6 +556,14 @@ public enum ShortKitFeedLifecycle {
556
556
  get
557
557
  }
558
558
  }
559
+ public enum VideoCarouselCellLongPressState : Swift.String {
560
+ case began, ended, cancelled
561
+ public init?(rawValue: Swift.String)
562
+ public typealias RawValue = Swift.String
563
+ public var rawValue: Swift.String {
564
+ get
565
+ }
566
+ }
559
567
  @objc @_hasMissingDesignatedInitializers @_Concurrency.MainActor @preconcurrency public class ShortKitFeedViewController : UIKit.UIViewController {
560
568
  @_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)?
561
569
  @_Concurrency.MainActor @preconcurrency public var onDismiss: (() -> Swift.Void)?
@@ -567,6 +575,13 @@ public enum ShortKitFeedLifecycle {
567
575
  public let pageIndex: Swift.Int
568
576
  }
569
577
  @_Concurrency.MainActor @preconcurrency public var onVideoCarouselCellTap: ((ShortKitSDK.ShortKitFeedViewController.VideoCarouselCellTapPayload) -> Swift.Void)?
578
+ public struct VideoCarouselCellLongPressPayload {
579
+ public let id: Swift.String
580
+ public let index: Swift.Int
581
+ public let pageIndex: Swift.Int
582
+ public let state: ShortKitSDK.VideoCarouselCellLongPressState
583
+ }
584
+ @_Concurrency.MainActor @preconcurrency public var onVideoCarouselCellLongPress: ((ShortKitSDK.ShortKitFeedViewController.VideoCarouselCellLongPressPayload) -> Swift.Void)?
570
585
  @_Concurrency.MainActor @preconcurrency public var onRefreshStateChanged: ((ShortKitSDK.ShortKitRefreshState) -> Swift.Void)?
571
586
  @_Concurrency.MainActor @preconcurrency public var onFeedTransition: ((ShortKitSDK.FeedTransitionEvent) -> Swift.Void)?
572
587
  @_Concurrency.MainActor @preconcurrency public var isActiveSurface: Swift.Bool {
@@ -893,12 +908,13 @@ public struct VTTCue : Swift.Equatable, Swift.Sendable {
893
908
  public struct VideoCarouselInput : Swift.Codable, Swift.Equatable, Swift.Sendable {
894
909
  public let id: Swift.String
895
910
  public let videos: [ShortKitSDK.VideoCarouselVideoInput]
911
+ public let initialPageIndex: Swift.Int?
896
912
  public let title: Swift.String?
897
913
  public let description: Swift.String?
898
914
  public let author: Swift.String?
899
915
  public let section: Swift.String?
900
916
  public let articleUrl: Swift.String?
901
- public init(id: Swift.String, videos: [ShortKitSDK.VideoCarouselVideoInput], title: Swift.String? = nil, description: Swift.String? = nil, author: Swift.String? = nil, section: Swift.String? = nil, articleUrl: Swift.String? = nil)
917
+ public init(id: Swift.String, videos: [ShortKitSDK.VideoCarouselVideoInput], initialPageIndex: Swift.Int? = nil, title: Swift.String? = nil, description: Swift.String? = nil, author: Swift.String? = nil, section: Swift.String? = nil, articleUrl: Swift.String? = nil)
902
918
  public static func == (a: ShortKitSDK.VideoCarouselInput, b: ShortKitSDK.VideoCarouselInput) -> Swift.Bool
903
919
  public func encode(to encoder: any Swift.Encoder) throws
904
920
  public init(from decoder: any Swift.Decoder) throws
@@ -906,12 +922,16 @@ public struct VideoCarouselInput : Swift.Codable, Swift.Equatable, Swift.Sendabl
906
922
  public struct VideoCarouselItem : Swift.Codable, Swift.Equatable, Swift.Sendable {
907
923
  public let id: Swift.String
908
924
  public let videos: [ShortKitSDK.ContentItem]
925
+ public let initialPageIndex: Swift.Int?
909
926
  public let title: Swift.String?
910
927
  public let description: Swift.String?
911
928
  public let author: Swift.String?
912
929
  public let section: Swift.String?
913
930
  public let articleUrl: Swift.String?
914
- public init(id: Swift.String, videos: [ShortKitSDK.ContentItem], title: Swift.String? = nil, description: Swift.String? = nil, author: Swift.String? = nil, section: Swift.String? = nil, articleUrl: Swift.String? = nil)
931
+ public init(id: Swift.String, videos: [ShortKitSDK.ContentItem], initialPageIndex: Swift.Int? = nil, title: Swift.String? = nil, description: Swift.String? = nil, author: Swift.String? = nil, section: Swift.String? = nil, articleUrl: Swift.String? = nil)
932
+ public var clampedInitialPageIndex: Swift.Int {
933
+ get
934
+ }
915
935
  public static func == (a: ShortKitSDK.VideoCarouselItem, b: ShortKitSDK.VideoCarouselItem) -> Swift.Bool
916
936
  public func encode(to encoder: any Swift.Encoder) throws
917
937
  public init(from decoder: any Swift.Decoder) throws
@@ -1165,6 +1185,7 @@ public enum ContentSignal : Swift.Equatable, Swift.Sendable {
1165
1185
  final public func setMaxBitrate(_ bps: Swift.Int)
1166
1186
  final public func setCaptionsEnabled(_ enabled: Swift.Bool)
1167
1187
  final public func selectCaptionTrack(language: Swift.String)
1188
+ final public func setFeedScrollEnabled(_ enabled: Swift.Bool)
1168
1189
  final public func dismissLiveRoom()
1169
1190
  final public func seekThumbnail(at time: Swift.Double) -> UIKit.UIImage?
1170
1191
  @objc deinit
@@ -1279,6 +1300,8 @@ extension ShortKitSDK.ShortKitPlayerViewController : UIKit.UIViewControllerTrans
1279
1300
  @objc @_hasMissingDesignatedInitializers @_Concurrency.MainActor @preconcurrency final public class ShortKitWidgetViewController : UIKit.UIViewController {
1280
1301
  @_Concurrency.MainActor @preconcurrency final public var feedMask: ShortKitSDK.FeedMaskMode
1281
1302
  @_Concurrency.MainActor @preconcurrency final public var onCardTap: ((Swift.String, Swift.Int) -> Swift.Void)?
1303
+ @_Concurrency.MainActor @preconcurrency final public var onModalFeedPresented: ((ShortKitSDK.ShortKitFeedViewController) -> Swift.Void)?
1304
+ @_Concurrency.MainActor @preconcurrency final public var onModalFeedDismissed: (() -> Swift.Void)?
1282
1305
  @_Concurrency.MainActor @preconcurrency final public var active: Swift.Bool {
1283
1306
  get
1284
1307
  set
@@ -1355,6 +1378,9 @@ extension ShortKitSDK.DownloadMode : Swift.Hashable {}
1355
1378
  extension ShortKitSDK.ShortKitFeedView : Swift.Sendable {}
1356
1379
  extension ShortKitSDK.ShortKitFeedLifecycle : Swift.Equatable {}
1357
1380
  extension ShortKitSDK.ShortKitFeedLifecycle : Swift.Hashable {}
1381
+ extension ShortKitSDK.VideoCarouselCellLongPressState : Swift.Equatable {}
1382
+ extension ShortKitSDK.VideoCarouselCellLongPressState : Swift.Hashable {}
1383
+ extension ShortKitSDK.VideoCarouselCellLongPressState : Swift.RawRepresentable {}
1358
1384
  extension ShortKitSDK.CaptionSource : Swift.Equatable {}
1359
1385
  extension ShortKitSDK.CaptionSource : Swift.Hashable {}
1360
1386
  extension ShortKitSDK.CaptionSource : Swift.RawRepresentable {}
@@ -556,6 +556,14 @@ public enum ShortKitFeedLifecycle {
556
556
  get
557
557
  }
558
558
  }
559
+ public enum VideoCarouselCellLongPressState : Swift.String {
560
+ case began, ended, cancelled
561
+ public init?(rawValue: Swift.String)
562
+ public typealias RawValue = Swift.String
563
+ public var rawValue: Swift.String {
564
+ get
565
+ }
566
+ }
559
567
  @objc @_hasMissingDesignatedInitializers @_Concurrency.MainActor @preconcurrency public class ShortKitFeedViewController : UIKit.UIViewController {
560
568
  @_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)?
561
569
  @_Concurrency.MainActor @preconcurrency public var onDismiss: (() -> Swift.Void)?
@@ -567,6 +575,13 @@ public enum ShortKitFeedLifecycle {
567
575
  public let pageIndex: Swift.Int
568
576
  }
569
577
  @_Concurrency.MainActor @preconcurrency public var onVideoCarouselCellTap: ((ShortKitSDK.ShortKitFeedViewController.VideoCarouselCellTapPayload) -> Swift.Void)?
578
+ public struct VideoCarouselCellLongPressPayload {
579
+ public let id: Swift.String
580
+ public let index: Swift.Int
581
+ public let pageIndex: Swift.Int
582
+ public let state: ShortKitSDK.VideoCarouselCellLongPressState
583
+ }
584
+ @_Concurrency.MainActor @preconcurrency public var onVideoCarouselCellLongPress: ((ShortKitSDK.ShortKitFeedViewController.VideoCarouselCellLongPressPayload) -> Swift.Void)?
570
585
  @_Concurrency.MainActor @preconcurrency public var onRefreshStateChanged: ((ShortKitSDK.ShortKitRefreshState) -> Swift.Void)?
571
586
  @_Concurrency.MainActor @preconcurrency public var onFeedTransition: ((ShortKitSDK.FeedTransitionEvent) -> Swift.Void)?
572
587
  @_Concurrency.MainActor @preconcurrency public var isActiveSurface: Swift.Bool {
@@ -893,12 +908,13 @@ public struct VTTCue : Swift.Equatable, Swift.Sendable {
893
908
  public struct VideoCarouselInput : Swift.Codable, Swift.Equatable, Swift.Sendable {
894
909
  public let id: Swift.String
895
910
  public let videos: [ShortKitSDK.VideoCarouselVideoInput]
911
+ public let initialPageIndex: Swift.Int?
896
912
  public let title: Swift.String?
897
913
  public let description: Swift.String?
898
914
  public let author: Swift.String?
899
915
  public let section: Swift.String?
900
916
  public let articleUrl: Swift.String?
901
- public init(id: Swift.String, videos: [ShortKitSDK.VideoCarouselVideoInput], title: Swift.String? = nil, description: Swift.String? = nil, author: Swift.String? = nil, section: Swift.String? = nil, articleUrl: Swift.String? = nil)
917
+ public init(id: Swift.String, videos: [ShortKitSDK.VideoCarouselVideoInput], initialPageIndex: Swift.Int? = nil, title: Swift.String? = nil, description: Swift.String? = nil, author: Swift.String? = nil, section: Swift.String? = nil, articleUrl: Swift.String? = nil)
902
918
  public static func == (a: ShortKitSDK.VideoCarouselInput, b: ShortKitSDK.VideoCarouselInput) -> Swift.Bool
903
919
  public func encode(to encoder: any Swift.Encoder) throws
904
920
  public init(from decoder: any Swift.Decoder) throws
@@ -906,12 +922,16 @@ public struct VideoCarouselInput : Swift.Codable, Swift.Equatable, Swift.Sendabl
906
922
  public struct VideoCarouselItem : Swift.Codable, Swift.Equatable, Swift.Sendable {
907
923
  public let id: Swift.String
908
924
  public let videos: [ShortKitSDK.ContentItem]
925
+ public let initialPageIndex: Swift.Int?
909
926
  public let title: Swift.String?
910
927
  public let description: Swift.String?
911
928
  public let author: Swift.String?
912
929
  public let section: Swift.String?
913
930
  public let articleUrl: Swift.String?
914
- public init(id: Swift.String, videos: [ShortKitSDK.ContentItem], title: Swift.String? = nil, description: Swift.String? = nil, author: Swift.String? = nil, section: Swift.String? = nil, articleUrl: Swift.String? = nil)
931
+ public init(id: Swift.String, videos: [ShortKitSDK.ContentItem], initialPageIndex: Swift.Int? = nil, title: Swift.String? = nil, description: Swift.String? = nil, author: Swift.String? = nil, section: Swift.String? = nil, articleUrl: Swift.String? = nil)
932
+ public var clampedInitialPageIndex: Swift.Int {
933
+ get
934
+ }
915
935
  public static func == (a: ShortKitSDK.VideoCarouselItem, b: ShortKitSDK.VideoCarouselItem) -> Swift.Bool
916
936
  public func encode(to encoder: any Swift.Encoder) throws
917
937
  public init(from decoder: any Swift.Decoder) throws
@@ -1165,6 +1185,7 @@ public enum ContentSignal : Swift.Equatable, Swift.Sendable {
1165
1185
  final public func setMaxBitrate(_ bps: Swift.Int)
1166
1186
  final public func setCaptionsEnabled(_ enabled: Swift.Bool)
1167
1187
  final public func selectCaptionTrack(language: Swift.String)
1188
+ final public func setFeedScrollEnabled(_ enabled: Swift.Bool)
1168
1189
  final public func dismissLiveRoom()
1169
1190
  final public func seekThumbnail(at time: Swift.Double) -> UIKit.UIImage?
1170
1191
  @objc deinit
@@ -1279,6 +1300,8 @@ extension ShortKitSDK.ShortKitPlayerViewController : UIKit.UIViewControllerTrans
1279
1300
  @objc @_hasMissingDesignatedInitializers @_Concurrency.MainActor @preconcurrency final public class ShortKitWidgetViewController : UIKit.UIViewController {
1280
1301
  @_Concurrency.MainActor @preconcurrency final public var feedMask: ShortKitSDK.FeedMaskMode
1281
1302
  @_Concurrency.MainActor @preconcurrency final public var onCardTap: ((Swift.String, Swift.Int) -> Swift.Void)?
1303
+ @_Concurrency.MainActor @preconcurrency final public var onModalFeedPresented: ((ShortKitSDK.ShortKitFeedViewController) -> Swift.Void)?
1304
+ @_Concurrency.MainActor @preconcurrency final public var onModalFeedDismissed: (() -> Swift.Void)?
1282
1305
  @_Concurrency.MainActor @preconcurrency final public var active: Swift.Bool {
1283
1306
  get
1284
1307
  set
@@ -1355,6 +1378,9 @@ extension ShortKitSDK.DownloadMode : Swift.Hashable {}
1355
1378
  extension ShortKitSDK.ShortKitFeedView : Swift.Sendable {}
1356
1379
  extension ShortKitSDK.ShortKitFeedLifecycle : Swift.Equatable {}
1357
1380
  extension ShortKitSDK.ShortKitFeedLifecycle : Swift.Hashable {}
1381
+ extension ShortKitSDK.VideoCarouselCellLongPressState : Swift.Equatable {}
1382
+ extension ShortKitSDK.VideoCarouselCellLongPressState : Swift.Hashable {}
1383
+ extension ShortKitSDK.VideoCarouselCellLongPressState : Swift.RawRepresentable {}
1358
1384
  extension ShortKitSDK.CaptionSource : Swift.Equatable {}
1359
1385
  extension ShortKitSDK.CaptionSource : Swift.Hashable {}
1360
1386
  extension ShortKitSDK.CaptionSource : Swift.RawRepresentable {}
@@ -10,39 +10,39 @@
10
10
  </data>
11
11
  <key>Info.plist</key>
12
12
  <data>
13
- kXOjURx+Z1d6/6VN46mtXJY4tGs=
13
+ WQrFujyFbopBKGGWbEKoC1woXeM=
14
14
  </data>
15
15
  <key>Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.abi.json</key>
16
16
  <data>
17
- IFMuyXGMCXuNezRhYjKHLUu9xA4=
17
+ mwN55YBG0lFbYyqh8rFLlhydUhg=
18
18
  </data>
19
19
  <key>Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface</key>
20
20
  <data>
21
- v3GW9Gub1dJiosTgJ/z5NwmgWnY=
21
+ VtQKD6iU2DxNLUgN8Nm9hVEd+LA=
22
22
  </data>
23
23
  <key>Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.swiftdoc</key>
24
24
  <data>
25
- 0oQnp4oNo+Ztwgww53FIZhz0zfM=
25
+ RYBSyi3j5xH2WhtxZngr8vlpDDM=
26
26
  </data>
27
27
  <key>Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.swiftinterface</key>
28
28
  <data>
29
- v3GW9Gub1dJiosTgJ/z5NwmgWnY=
29
+ VtQKD6iU2DxNLUgN8Nm9hVEd+LA=
30
30
  </data>
31
31
  <key>Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.abi.json</key>
32
32
  <data>
33
- IFMuyXGMCXuNezRhYjKHLUu9xA4=
33
+ mwN55YBG0lFbYyqh8rFLlhydUhg=
34
34
  </data>
35
35
  <key>Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface</key>
36
36
  <data>
37
- Duv2bgxehsG2ZV4wnlh7s8/WzFk=
37
+ l/8aNIdTZYrYfdGjeCunQev+z2s=
38
38
  </data>
39
39
  <key>Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.swiftdoc</key>
40
40
  <data>
41
- Cu/J3KUQmcbxz8bCf9NQZ5aVBTM=
41
+ dK384fZQxXLFp6AahpyFqGJOfnY=
42
42
  </data>
43
43
  <key>Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.swiftinterface</key>
44
44
  <data>
45
- Duv2bgxehsG2ZV4wnlh7s8/WzFk=
45
+ l/8aNIdTZYrYfdGjeCunQev+z2s=
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
- N/7VIAsF7mG+qU52BV03Pbvk+uQA/UoDg7z3aLRvEm4=
69
+ lPV80dTyQRi3R5Al7WxpvZYLMH1fLtDMRPj8kH++RCs=
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
- HHpbkQ91Av7qOwHoz6asjSQ4d9TzPj7Lg+sxPVOhA30=
76
+ rf7zOX3BNWSgC2Lvt4rs/pTvzoqY4r2easqa7IcD/BY=
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
- pbR9S11lEANUEhT1e5NkK796Tecps3q6SosOoeuApuQ=
83
+ U33t59L18Q9DqIsgOyi6pcHV+IuHxLRdntw2IQW1DLo=
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
- HHpbkQ91Av7qOwHoz6asjSQ4d9TzPj7Lg+sxPVOhA30=
90
+ rf7zOX3BNWSgC2Lvt4rs/pTvzoqY4r2easqa7IcD/BY=
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
- N/7VIAsF7mG+qU52BV03Pbvk+uQA/UoDg7z3aLRvEm4=
97
+ lPV80dTyQRi3R5Al7WxpvZYLMH1fLtDMRPj8kH++RCs=
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
- 6nFBIiTjaP5xmdLc7I/x9j4ASiT2UjNnxKmRYUGmLXw=
104
+ c3dj4IBlPLhIqbUCIQDEpGHL5WE7f1b16++z2hPOOTU=
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
- Yx9LmEqOq+aeF+mSiKZyfw0FW/BySAPRrQMVzDyEiUU=
111
+ kFhyC63KxDPM8/iRTzRd5M1FO7ojEQzF0migxa4EIpU=
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
- 6nFBIiTjaP5xmdLc7I/x9j4ASiT2UjNnxKmRYUGmLXw=
118
+ c3dj4IBlPLhIqbUCIQDEpGHL5WE7f1b16++z2hPOOTU=
119
119
  </data>
120
120
  </dict>
121
121
  <key>Modules/module.modulemap</key>
@@ -25,12 +25,24 @@ import ShortKitSDK
25
25
  }
26
26
  }
27
27
 
28
- /// Stable per-instance widget identifier set by the JS wrapper. Echoed
28
+ /// Stable per-instance widget identifier set by the JS wrapper when the
29
+ /// host has wired `onCardTap` and wants to handle taps itself. Echoed
29
30
  /// back on `onWidgetCardTap` events so the JS wrapper can route the
30
- /// global emit to the correct `<ShortKitWidget>` instance when more than
31
- /// one is mounted simultaneously.
31
+ /// global emit to the correct `<ShortKitWidget>` instance when more
32
+ /// than one is mounted simultaneously. Presence of this id signals
33
+ /// "host takes over taps" — the native side wires `vc.onCardTap`
34
+ /// which makes the SDK skip its built-in modal-present path.
32
35
  @objc public var widgetId: String?
33
36
 
37
+ /// Stable per-instance modal-feed identifier set by the JS wrapper when
38
+ /// the host has wired per-feed callbacks (e.g.
39
+ /// `feedConfig.onDidFetchContentItems`) and wants to receive scoped
40
+ /// events from the SDK's built-in modal feed. Independent from
41
+ /// `widgetId` — the host can wire modal callbacks WITHOUT taking over
42
+ /// taps. Used as the `feedId` under which the modal feed VC is
43
+ /// registered with the bridge on present.
44
+ @objc public var modalFeedId: String?
45
+
34
46
  /// Mirrors `ShortKitWidgetViewController.active`. Hosts use this to
35
47
  /// release the widget's pool tile when it shouldn't be playing
36
48
  /// (e.g. inactive tab, scrolled off-screen). Defaults to `true` so
@@ -172,6 +184,21 @@ import ShortKitSDK
172
184
  }
173
185
  }
174
186
 
187
+ // Register the SDK's built-in modal feed VC with the bridge under
188
+ // the JS-supplied `modalFeedId` so per-feed callbacks wired on the
189
+ // widget's `feedConfig` (e.g. `onDidFetchContentItems`) get scoped
190
+ // attribution. The JS wrapper supplies this id only when at least
191
+ // one such callback is set; absent it, the modal still presents
192
+ // and runs normally — events just emit with empty feedId.
193
+ if let id = modalFeedId {
194
+ vc.onModalFeedPresented = { feedVC in
195
+ ShortKitBridge.shared?.registerFeed(id: id, viewController: feedVC)
196
+ }
197
+ vc.onModalFeedDismissed = {
198
+ ShortKitBridge.shared?.unregisterFeed(id: id)
199
+ }
200
+ }
201
+
175
202
  parentVC.addChild(vc)
176
203
  vc.view.frame = bounds
177
204
  vc.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
@@ -24,6 +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(modalFeedId, NSString)
27
28
  RCT_EXPORT_VIEW_PROPERTY(active, BOOL)
28
29
  RCT_EXPORT_VIEW_PROPERTY(feedItems, NSString)
29
30
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shortkitsdk/react-native",
3
- "version": "0.2.34",
3
+ "version": "0.2.36",
4
4
  "description": "ShortKit React Native SDK — short-form video feed",
5
5
  "react-native": "src/index",
6
6
  "source": "src/index",
@@ -28,6 +28,26 @@ export const ShortKitCommands = {
28
28
  NativeShortKitModule?.sendContentSignal(signal),
29
29
  setMaxBitrate: (bitrate: number) =>
30
30
  NativeShortKitModule?.setMaxBitrate(bitrate),
31
+ /**
32
+ * Toggle feed scroll while an overlay-owned gesture is in flight.
33
+ *
34
+ * Hosts use this to grant exclusive priority to an in-flight gesture in
35
+ * an overlay (e.g. a horizontal scrubber drag) so the feed's pan
36
+ * recognizer can't steal the touch mid-drag. Pair the call: pass
37
+ * `false` when the host gesture starts (RN PanResponder grant), `true`
38
+ * when it ends or is cancelled (release / terminate).
39
+ *
40
+ * iOS: toggles the active feed view controller's
41
+ * `collectionView.panGestureRecognizer.isEnabled`. No-op when no feed
42
+ * VC is currently active.
43
+ *
44
+ * Android: fans out across every registered feed (including any masked
45
+ * underlay), toggling each `ViewPager2.isUserInputEnabled`. Intentional
46
+ * divergence from iOS — broader fan-out is simpler and has the same
47
+ * user-visible effect since only the active feed is interactable.
48
+ */
49
+ setFeedScrollEnabled: (enabled: boolean) =>
50
+ NativeShortKitModule?.setFeedScrollEnabled(enabled),
31
51
  prefetchStoryboard: (playbackId: string) =>
32
52
  NativeShortKitModule?.prefetchStoryboard(playbackId),
33
53
  getStoryboardData: (playbackId: string): Promise<string | null> =>
@@ -47,6 +47,7 @@ export const ShortKitFeed = forwardRef<ShortKitFeedHandle, ShortKitFeedProps>(
47
47
  onFeedReady,
48
48
  onCarouselActiveVideoCompleted,
49
49
  onVideoCarouselCellTap,
50
+ onVideoCarouselCellLongPress,
50
51
  debugPanel,
51
52
  } = props;
52
53
 
@@ -126,6 +127,26 @@ export const ShortKitFeed = forwardRef<ShortKitFeedHandle, ShortKitFeedProps>(
126
127
  return () => subscription.remove();
127
128
  }, [feedId, onVideoCarouselCellTap]);
128
129
 
130
+ // Subscribe to per-feed video-carousel cell long-press events
131
+ useEffect(() => {
132
+ if (!NativeShortKitModule || !onVideoCarouselCellLongPress) return;
133
+
134
+ const subscription = NativeShortKitModule.onVideoCarouselCellLongPress((event) => {
135
+ if (event.feedId === feedId) {
136
+ // Bridge emits `state` as plain `string` (codegen constraint);
137
+ // the native side only ever emits these three values.
138
+ onVideoCarouselCellLongPress({
139
+ id: event.id,
140
+ index: event.index,
141
+ pageIndex: event.pageIndex,
142
+ state: event.state as 'began' | 'ended' | 'cancelled',
143
+ });
144
+ }
145
+ });
146
+
147
+ return () => subscription.remove();
148
+ }, [feedId, onVideoCarouselCellLongPress]);
149
+
129
150
  // Register overlay components before native view mounts.
130
151
  // useLayoutEffect fires after commit but before paint — before
131
152
  // didMoveToWindow/onAttachedToWindow on the native view.
@@ -1,5 +1,5 @@
1
1
  import React, { useLayoutEffect, useMemo } from 'react';
2
- import { View, StyleSheet } from 'react-native';
2
+ import { Platform, View, StyleSheet } from 'react-native';
3
3
  import type { ShortKitPlayerProps } from './types';
4
4
  import ShortKitPlayerView from './specs/ShortKitPlayerViewNativeComponent';
5
5
  import { serializePlayerConfig } from './serialization';
@@ -8,6 +8,11 @@ import { registerCarouselOverlayComponent } from './ShortKitCarouselOverlaySurfa
8
8
  import { registerVideoCarouselOverlayComponent } from './ShortKitVideoCarouselOverlaySurface';
9
9
  import { registerFeedMaskComponent } from './ShortKitFeedMaskSurface';
10
10
 
11
+ // One-time dev warning when ShortKitPlayer is rendered on Android. The
12
+ // Android SDK was scoped down to feed-only in #246; the JS surface stays
13
+ // for iOS but renders an empty container on Android.
14
+ let didWarnAndroidPlayerUnavailable = false;
15
+
11
16
  /**
12
17
  * Single-video player component. Displays one video with thumbnail fallback
13
18
  * and optional overlay. Wraps a native Fabric view.
@@ -75,6 +80,20 @@ export function ShortKitPlayer(props: ShortKitPlayerProps) {
75
80
  // is fully invisible to hit testing.
76
81
  const nativeTouchPassthrough = clickAction === 'none';
77
82
 
83
+ // Android: the native ViewManager backing ShortKitPlayer was removed in
84
+ // #246 (feed-only scope-down). The JS surface stays so cross-platform
85
+ // host code compiles, but renders an empty container.
86
+ if (Platform.OS === 'android') {
87
+ if (__DEV__ && !didWarnAndroidPlayerUnavailable) {
88
+ didWarnAndroidPlayerUnavailable = true;
89
+ // eslint-disable-next-line no-console
90
+ console.warn(
91
+ '[ShortKit] <ShortKitPlayer> is not supported on Android — rendering an empty container.',
92
+ );
93
+ }
94
+ return <View style={[styles.container, style]} />;
95
+ }
96
+
78
97
  return (
79
98
  <View
80
99
  style={[styles.container, style]}
@@ -1,5 +1,5 @@
1
1
  import React, { useContext, useEffect, useLayoutEffect, useMemo, useRef } from 'react';
2
- import { View, StyleSheet } from 'react-native';
2
+ import { Platform, View, StyleSheet } from 'react-native';
3
3
  import type { ShortKitWidgetProps } from './types';
4
4
  import ShortKitWidgetView from './specs/ShortKitWidgetViewNativeComponent';
5
5
  import NativeShortKitModule from './specs/NativeShortKitModule';
@@ -10,6 +10,11 @@ import { registerCarouselOverlayComponent } from './ShortKitCarouselOverlaySurfa
10
10
  import { registerVideoCarouselOverlayComponent } from './ShortKitVideoCarouselOverlaySurface';
11
11
  import { registerFeedMaskComponent } from './ShortKitFeedMaskSurface';
12
12
 
13
+ // One-time dev warning when ShortKitWidget is rendered on Android. The
14
+ // Android SDK was scoped down to feed-only in #246; the JS surface stays
15
+ // for iOS but renders an empty container on Android.
16
+ let didWarnAndroidWidgetUnavailable = false;
17
+
13
18
  // Local UUID generator. We don't pull in a runtime dep just for this; a
14
19
  // timestamp + random suffix is more than unique enough to disambiguate
15
20
  // concurrently-mounted widgets within a single app session.
@@ -31,28 +36,36 @@ export function ShortKitWidget(props: ShortKitWidgetProps) {
31
36
  throw new Error('ShortKitWidget must be used within a ShortKitProvider');
32
37
  }
33
38
 
34
- // Stable widget ID for the lifetime of this component, ONLY when the host
35
- // wires `onCardTap`. Skipping it when unset means the native side leaves
36
- // `widgetVC.onCardTap` nil, which means the SDK's existing
37
- // `clickAction: 'feed'` modal-presentation path stays intact for hosts
38
- // that don't opt in. Backwards compatible.
39
+ // Stable widget ID, generated only when the host wires `onCardTap`.
40
+ // Presence on the native side signals "host handles taps" and the SDK
41
+ // skips its built-in modal-presentation path. Backwards compatible —
42
+ // hosts who don't wire `onCardTap` see no behavior change.
39
43
  const widgetId = useMemo(
40
44
  () => (onCardTap ? generateWidgetId() : undefined),
41
- // We deliberately compute this once per "host wired callback" lifetime,
42
- // not per render. The boolean test on first render is what matters; if
43
- // the host swaps onCardTap from set → unset later we keep the same
44
- // widgetId (harmless — no events will fire because the JS subscription
45
- // below tears down). Going the other way (unset → set), we generate a
46
- // fresh id then.
47
45
  // eslint-disable-next-line react-hooks/exhaustive-deps
48
46
  [Boolean(onCardTap)],
49
47
  );
50
48
 
51
- // Keep a stable ref to the latest onCardTap so the subscription doesn't
52
- // need to tear down + rebuild every time the host re-renders with a new
53
- // closure identity.
49
+ // Stable modal-feed ID, generated only when the host wires per-feed
50
+ // callbacks on the expanded modal feed (currently
51
+ // `feedConfig.onDidFetchContentItems`). Independent from `widgetId` —
52
+ // hosts can subscribe to modal events without taking over taps. The
53
+ // native side registers the modal feed VC under this id so emits get
54
+ // scoped back to this widget's callbacks.
55
+ const onDidFetchContentItems = config?.feedConfig?.onDidFetchContentItems;
56
+ const modalFeedId = useMemo(
57
+ () => (onDidFetchContentItems ? generateWidgetId() : undefined),
58
+ // eslint-disable-next-line react-hooks/exhaustive-deps
59
+ [Boolean(onDidFetchContentItems)],
60
+ );
61
+
62
+ // Keep stable refs to the latest callbacks so subscriptions don't need to
63
+ // tear down + rebuild every time the host re-renders with a new closure
64
+ // identity.
54
65
  const onCardTapRef = useRef(onCardTap);
55
66
  onCardTapRef.current = onCardTap;
67
+ const onDidFetchContentItemsRef = useRef(onDidFetchContentItems);
68
+ onDidFetchContentItemsRef.current = onDidFetchContentItems;
56
69
 
57
70
  useLayoutEffect(() => {
58
71
  if (config?.overlay && config.overlay !== 'none') {
@@ -88,6 +101,26 @@ export function ShortKitWidget(props: ShortKitWidgetProps) {
88
101
  return () => subscription.remove();
89
102
  }, [widgetId, onCardTap]);
90
103
 
104
+ // Subscribe to `onDidFetchContentItems` scoped to this widget's modal
105
+ // feed. Native side registers the modal feed VC under `modalFeedId` on
106
+ // present and emits with that feedId; filter to it and route to the
107
+ // host callback wired on `feedConfig.onDidFetchContentItems`.
108
+ useEffect(() => {
109
+ if (!NativeShortKitModule || !modalFeedId || !onDidFetchContentItems) return;
110
+
111
+ const subscription = NativeShortKitModule.onDidFetchContentItems((event) => {
112
+ if (event.feedId !== modalFeedId) return;
113
+ try {
114
+ const items = JSON.parse(event.items);
115
+ onDidFetchContentItemsRef.current?.(items);
116
+ } catch {
117
+ // ignore malformed JSON
118
+ }
119
+ });
120
+
121
+ return () => subscription.remove();
122
+ }, [modalFeedId, onDidFetchContentItems]);
123
+
91
124
  const serializedConfig = useMemo(() => {
92
125
  return serializeWidgetConfig(config ?? {});
93
126
  }, [config]);
@@ -105,6 +138,20 @@ export function ShortKitWidget(props: ShortKitWidgetProps) {
105
138
  return JSON.stringify(feedItems);
106
139
  }, [feedItems]);
107
140
 
141
+ // Android: the native ViewManager backing ShortKitWidget was removed in
142
+ // #246 (feed-only scope-down). The JS surface stays so cross-platform
143
+ // host code compiles, but renders an empty container.
144
+ if (Platform.OS === 'android') {
145
+ if (__DEV__ && !didWarnAndroidWidgetUnavailable) {
146
+ didWarnAndroidWidgetUnavailable = true;
147
+ // eslint-disable-next-line no-console
148
+ console.warn(
149
+ '[ShortKit] <ShortKitWidget> is not supported on Android — rendering an empty container.',
150
+ );
151
+ }
152
+ return <View style={[styles.container, style]} />;
153
+ }
154
+
108
155
  return (
109
156
  <View style={[styles.container, style]}>
110
157
  <ShortKitWidgetView
@@ -112,6 +159,7 @@ export function ShortKitWidget(props: ShortKitWidgetProps) {
112
159
  config={serializedConfig}
113
160
  items={serializedItems}
114
161
  widgetId={widgetId}
162
+ modalFeedId={modalFeedId}
115
163
  active={active}
116
164
  feedItems={serializedFeedItems}
117
165
  />
@@ -127,6 +127,14 @@ type VideoCarouselCellTapEvent = Readonly<{
127
127
  pageIndex: Int32;
128
128
  }>;
129
129
 
130
+ type VideoCarouselCellLongPressEvent = Readonly<{
131
+ feedId: string;
132
+ id: string;
133
+ index: Int32;
134
+ pageIndex: Int32;
135
+ state: string; // "began" | "ended" | "cancelled" — string for codegen compat
136
+ }>;
137
+
130
138
  type WidgetCardTapEvent = Readonly<{
131
139
  widgetId: string;
132
140
  playbackId: string;
@@ -292,6 +300,7 @@ export interface Spec extends TurboModule {
292
300
  selectCaptionTrack(language: string): void;
293
301
  sendContentSignal(signal: string): void;
294
302
  setMaxBitrate(bitrate: Double): void;
303
+ setFeedScrollEnabled(enabled: boolean): void;
295
304
 
296
305
  // --- Custom feed ---
297
306
  setFeedItems(feedId: string, items: string, startAtId: string | null): void;
@@ -336,6 +345,7 @@ export interface Spec extends TurboModule {
336
345
  readonly onDidFetchContentItems: EventEmitter<DidFetchContentItemsEvent>;
337
346
  readonly onFeedReady: EventEmitter<FeedReadyEvent>;
338
347
  readonly onVideoCarouselCellTap: EventEmitter<VideoCarouselCellTapEvent>;
348
+ readonly onVideoCarouselCellLongPress: EventEmitter<VideoCarouselCellLongPressEvent>;
339
349
  readonly onWidgetCardTap: EventEmitter<WidgetCardTapEvent>;
340
350
 
341
351
  // --- Overlay per-surface events ---
@@ -5,11 +5,23 @@ export interface NativeProps extends ViewProps {
5
5
  config: string;
6
6
  items?: string;
7
7
  /**
8
- * Stable per-instance widget identifier. Used to route the global
9
- * `NativeShortKitModule.onWidgetCardTap` event back to the originating
10
- * `<ShortKitWidget>` when multiple widgets are mounted.
8
+ * Stable per-instance widget identifier. Set only when the host has
9
+ * wired `onCardTap` its presence signals "host handles taps" to the
10
+ * native side. Echoed back on `onWidgetCardTap` events so the JS
11
+ * wrapper can route the global emit to the correct `<ShortKitWidget>`
12
+ * instance when more than one is mounted.
11
13
  */
12
14
  widgetId?: string;
15
+ /**
16
+ * Stable per-instance modal-feed identifier. Set only when the host
17
+ * has wired per-feed callbacks (e.g.
18
+ * `feedConfig.onDidFetchContentItems`). The native side registers the
19
+ * SDK's built-in modal feed VC with the bridge under this id so events
20
+ * fired by the modal can be scoped back to the correct widget's
21
+ * callbacks. Independent from `widgetId` — a host can wire modal
22
+ * callbacks without taking over taps.
23
+ */
24
+ modalFeedId?: string;
13
25
  /**
14
26
  * Whether the widget is currently allowed to play. Defaults to true on
15
27
  * the native side. Hosts use this to release the widget's pool tile