@shortkitsdk/react-native 0.2.6 → 0.2.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ShortKitReactNative.podspec +1 -0
- package/android/build.gradle.kts +17 -1
- package/android/src/main/java/com/shortkit/reactnative/ReactCarouselOverlayHost.kt +379 -0
- package/android/src/main/java/com/shortkit/reactnative/ReactLoadingHost.kt +40 -0
- package/android/src/main/java/com/shortkit/reactnative/ReactOverlayHost.kt +570 -0
- package/android/src/main/java/com/shortkit/reactnative/ShortKitBridge.kt +1029 -0
- package/android/src/main/java/com/shortkit/reactnative/ShortKitFeedView.kt +212 -219
- package/android/src/main/java/com/shortkit/reactnative/ShortKitFeedViewManager.kt +17 -3
- package/android/src/main/java/com/shortkit/reactnative/ShortKitModule.kt +157 -742
- package/android/src/main/java/com/shortkit/reactnative/ShortKitPlayerNativeView.kt +11 -2
- package/android/src/main/java/com/shortkit/reactnative/ShortKitWidgetNativeView.kt +2 -2
- package/ios/ReactCarouselOverlayHost.swift +177 -0
- package/ios/ReactLoadingHost.swift +38 -0
- package/ios/ReactOverlayHost.swift +444 -0
- package/ios/SKFabricSurfaceWrapper.h +18 -0
- package/ios/SKFabricSurfaceWrapper.mm +57 -0
- package/ios/ShortKitBridge.swift +220 -63
- package/ios/ShortKitFeedView.swift +82 -228
- package/ios/ShortKitFeedViewManager.mm +3 -2
- package/ios/ShortKitModule.mm +69 -37
- package/ios/ShortKitPlayerNativeView.swift +39 -8
- package/ios/ShortKitReactNative-Bridging-Header.h +2 -0
- package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Headers/ShortKitSDK-Swift.h +1 -1
- package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.abi.json +3683 -1249
- package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.private.swiftinterface +56 -15
- package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.swiftdoc +0 -0
- package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.swiftinterface +56 -15
- package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/ShortKitSDK +0 -0
- package/ios/ShortKitSDK.xcframework/ios-arm64-simulator/ShortKitSDK.framework/Headers/ShortKitSDK-Swift.h +1 -1
- package/ios/ShortKitSDK.xcframework/ios-arm64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.abi.json +3683 -1249
- package/ios/ShortKitSDK.xcframework/ios-arm64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface +56 -15
- package/ios/ShortKitSDK.xcframework/ios-arm64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.swiftdoc +0 -0
- package/ios/ShortKitSDK.xcframework/ios-arm64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.swiftinterface +56 -15
- package/ios/ShortKitSDK.xcframework/ios-arm64-simulator/ShortKitSDK.framework/ShortKitSDK +0 -0
- package/ios/ShortKitSDK.xcframework.bak/Info.plist +43 -0
- package/ios/ShortKitSDK.xcframework.bak/ios-arm64/ShortKitSDK.framework/Headers/ShortKitSDK-Swift.h +418 -0
- package/ios/ShortKitSDK.xcframework.bak/ios-arm64/ShortKitSDK.framework/Info.plist +16 -0
- package/ios/ShortKitSDK.xcframework.bak/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.abi.json +28917 -0
- package/ios/ShortKitSDK.xcframework.bak/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.private.swiftinterface +824 -0
- package/ios/ShortKitSDK.xcframework.bak/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.swiftdoc +0 -0
- package/ios/ShortKitSDK.xcframework.bak/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.swiftinterface +824 -0
- package/ios/ShortKitSDK.xcframework.bak/ios-arm64/ShortKitSDK.framework/Modules/module.modulemap +4 -0
- package/ios/ShortKitSDK.xcframework.bak/ios-arm64/ShortKitSDK.framework/ShortKitSDK +0 -0
- package/ios/ShortKitSDK.xcframework.bak/ios-arm64-simulator/ShortKitSDK.framework/Headers/ShortKitSDK-Swift.h +418 -0
- package/ios/ShortKitSDK.xcframework.bak/ios-arm64-simulator/ShortKitSDK.framework/Info.plist +16 -0
- package/ios/ShortKitSDK.xcframework.bak/ios-arm64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.abi.json +28917 -0
- package/ios/ShortKitSDK.xcframework.bak/ios-arm64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface +824 -0
- package/ios/ShortKitSDK.xcframework.bak/ios-arm64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.swiftdoc +0 -0
- package/ios/ShortKitSDK.xcframework.bak/ios-arm64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.swiftinterface +824 -0
- package/ios/ShortKitSDK.xcframework.bak/ios-arm64-simulator/ShortKitSDK.framework/Modules/module.modulemap +4 -0
- package/ios/ShortKitSDK.xcframework.bak/ios-arm64-simulator/ShortKitSDK.framework/ShortKitSDK +0 -0
- package/ios/ShortKitWidgetNativeView.swift +3 -3
- package/package.json +1 -1
- package/src/ShortKitCarouselOverlaySurface.tsx +55 -0
- package/src/ShortKitCommands.ts +31 -0
- package/src/ShortKitContext.ts +6 -24
- package/src/ShortKitFeed.tsx +124 -41
- package/src/ShortKitLoadingSurface.tsx +24 -0
- package/src/ShortKitOverlaySurface.tsx +313 -0
- package/src/ShortKitPlayer.tsx +30 -9
- package/src/ShortKitProvider.tsx +28 -285
- package/src/index.ts +9 -3
- package/src/serialization.ts +20 -39
- package/src/specs/NativeShortKitModule.ts +74 -45
- package/src/specs/ShortKitFeedViewNativeComponent.ts +3 -2
- package/src/types.ts +84 -16
- package/src/useShortKit.ts +1 -3
- package/src/useShortKitPlayer.ts +7 -7
- package/android/src/main/java/com/shortkit/reactnative/ShortKitCarouselOverlayBridge.kt +0 -48
- package/android/src/main/java/com/shortkit/reactnative/ShortKitOverlayBridge.kt +0 -128
- package/ios/ShortKitCarouselOverlayBridge.swift +0 -219
- package/ios/ShortKitOverlayBridge.swift +0 -111
- package/src/CarouselOverlayManager.tsx +0 -70
- package/src/OverlayManager.tsx +0 -87
- package/src/useShortKitCarousel.ts +0 -29
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
package com.shortkit.reactnative
|
|
2
2
|
|
|
3
3
|
import android.content.Context
|
|
4
|
+
import android.view.MotionEvent
|
|
4
5
|
import android.widget.FrameLayout
|
|
5
6
|
import com.shortkit.sdk.config.PlayerClickAction
|
|
6
7
|
import com.shortkit.sdk.config.PlayerConfig
|
|
@@ -42,6 +43,14 @@ class ShortKitPlayerNativeView(context: Context) : FrameLayout(context) {
|
|
|
42
43
|
applyActive()
|
|
43
44
|
}
|
|
44
45
|
|
|
46
|
+
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
|
|
47
|
+
return super.onInterceptTouchEvent(ev)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
|
|
51
|
+
return super.dispatchTouchEvent(ev)
|
|
52
|
+
}
|
|
53
|
+
|
|
45
54
|
override fun onAttachedToWindow() {
|
|
46
55
|
super.onAttachedToWindow()
|
|
47
56
|
rebuildIfNeeded()
|
|
@@ -55,7 +64,7 @@ class ShortKitPlayerNativeView(context: Context) : FrameLayout(context) {
|
|
|
55
64
|
private fun rebuildIfNeeded() {
|
|
56
65
|
if (playerView != null) return
|
|
57
66
|
|
|
58
|
-
val sdk =
|
|
67
|
+
val sdk = ShortKitBridge.shared?.sdk ?: return
|
|
59
68
|
val playerConfig = parsePlayerConfig(configJson)
|
|
60
69
|
|
|
61
70
|
val view = ShortKitPlayerView(context).apply {
|
|
@@ -107,7 +116,7 @@ class ShortKitPlayerNativeView(context: Context) : FrameLayout(context) {
|
|
|
107
116
|
val overlay = obj.opt("overlay") ?: return VideoOverlayMode.None
|
|
108
117
|
if (overlay is JSONObject && overlay.optString("type") == "custom") {
|
|
109
118
|
return VideoOverlayMode.Custom {
|
|
110
|
-
|
|
119
|
+
ReactOverlayHost(context)
|
|
111
120
|
}
|
|
112
121
|
}
|
|
113
122
|
return VideoOverlayMode.None
|
|
@@ -48,7 +48,7 @@ class ShortKitWidgetNativeView(context: Context) : FrameLayout(context) {
|
|
|
48
48
|
private fun rebuildIfNeeded() {
|
|
49
49
|
if (widgetView != null) return
|
|
50
50
|
|
|
51
|
-
val sdk =
|
|
51
|
+
val sdk = ShortKitBridge.shared?.sdk ?: return
|
|
52
52
|
val widgetConfig = parseWidgetConfig(configJson)
|
|
53
53
|
|
|
54
54
|
val view = ShortKitWidgetView(context).apply {
|
|
@@ -97,7 +97,7 @@ class ShortKitWidgetNativeView(context: Context) : FrameLayout(context) {
|
|
|
97
97
|
val overlay = obj.opt("overlay") ?: return VideoOverlayMode.None
|
|
98
98
|
if (overlay is JSONObject && overlay.optString("type") == "custom") {
|
|
99
99
|
return VideoOverlayMode.Custom {
|
|
100
|
-
|
|
100
|
+
ReactOverlayHost(context)
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
103
|
return VideoOverlayMode.None
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import UIKit
|
|
2
|
+
import ShortKitSDK
|
|
3
|
+
|
|
4
|
+
/// A UIView that conforms to `CarouselOverlay` and hosts an `RCTFabricSurface`
|
|
5
|
+
/// for rendering the developer's React carousel overlay component inside a feed cell.
|
|
6
|
+
///
|
|
7
|
+
/// Unlike ReactOverlayHost, this does not subscribe to player state (carousels
|
|
8
|
+
/// are image-based). It emits image URLs to JS for Image.prefetch() and pushes
|
|
9
|
+
/// ImageCarouselItem data as appProperties.
|
|
10
|
+
@objc public class ReactCarouselOverlayHost: UIView, @unchecked Sendable, CarouselOverlay {
|
|
11
|
+
|
|
12
|
+
// MARK: - Configuration
|
|
13
|
+
|
|
14
|
+
var surfacePresenter: AnyObject?
|
|
15
|
+
weak var bridge: ShortKitBridge?
|
|
16
|
+
|
|
17
|
+
/// Module name for the RCTFabricSurface. Set by the overlay factory
|
|
18
|
+
/// based on the feed config's carousel overlay name.
|
|
19
|
+
var carouselOverlayModuleName: String = "ShortKitCarouselOverlay"
|
|
20
|
+
|
|
21
|
+
// MARK: - Eager Surface Creation
|
|
22
|
+
|
|
23
|
+
/// Eagerly create the RN surface so it's ready before the first configure().
|
|
24
|
+
/// Called by the overlay factory right after setting surfacePresenter and moduleName.
|
|
25
|
+
/// Mirrors ReactOverlayHost.attach(player:) which does the same for video overlays.
|
|
26
|
+
func prepareSurface() {
|
|
27
|
+
createSurfaceIfNeeded()
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// MARK: - CarouselOverlay
|
|
31
|
+
|
|
32
|
+
public var cachedImage: ((String) -> UIImage?)?
|
|
33
|
+
public var wantsNativeImagePrefetch: Bool { true }
|
|
34
|
+
|
|
35
|
+
// MARK: - State
|
|
36
|
+
|
|
37
|
+
private var surface: SKFabricSurfaceWrapper?
|
|
38
|
+
private var surfaceView: UIView?
|
|
39
|
+
private var pendingProps: [String: Any]?
|
|
40
|
+
|
|
41
|
+
// MARK: - Init
|
|
42
|
+
|
|
43
|
+
override init(frame: CGRect) {
|
|
44
|
+
super.init(frame: frame)
|
|
45
|
+
backgroundColor = .clear
|
|
46
|
+
isUserInteractionEnabled = true
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
required init?(coder: NSCoder) {
|
|
50
|
+
fatalError("init(coder:) is not supported")
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
deinit {
|
|
54
|
+
surface?.stop()
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// MARK: - CarouselOverlay
|
|
58
|
+
|
|
59
|
+
public func configure(with item: ImageCarouselItem) {
|
|
60
|
+
createSurfaceIfNeeded()
|
|
61
|
+
|
|
62
|
+
// Replace remote URLs with local file URLs for any natively-cached images.
|
|
63
|
+
// The SDK's PrefetchManager downloads images into NSCache<NSString, UIImage>
|
|
64
|
+
// which RN can't access. Writing to temp files lets RN load instantly from disk.
|
|
65
|
+
var modifiedItem = item
|
|
66
|
+
if let cachedImage {
|
|
67
|
+
var localImages: [CarouselImage] = []
|
|
68
|
+
for image in item.images {
|
|
69
|
+
if let uiImage = cachedImage(image.url),
|
|
70
|
+
let localURL = writeTempImage(uiImage, for: image.url) {
|
|
71
|
+
localImages.append(CarouselImage(url: localURL, alt: image.alt))
|
|
72
|
+
} else {
|
|
73
|
+
localImages.append(image)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
modifiedItem = ImageCarouselItem(
|
|
77
|
+
id: item.id,
|
|
78
|
+
images: localImages,
|
|
79
|
+
caption: item.caption,
|
|
80
|
+
title: item.title,
|
|
81
|
+
description: item.description,
|
|
82
|
+
author: item.author,
|
|
83
|
+
section: item.section,
|
|
84
|
+
articleUrl: item.articleUrl
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Build props — push now if surface exists, otherwise store for later
|
|
89
|
+
if let data = try? JSONEncoder().encode(modifiedItem),
|
|
90
|
+
let json = String(data: data, encoding: .utf8) {
|
|
91
|
+
let props: [String: Any] = ["item": json]
|
|
92
|
+
if let surface {
|
|
93
|
+
surface.setProperties(props)
|
|
94
|
+
} else {
|
|
95
|
+
pendingProps = props
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/// Write a UIImage to the temp directory, returning a file:// URL string.
|
|
101
|
+
/// Uses a hash of the remote URL as the filename to avoid duplicates.
|
|
102
|
+
private func writeTempImage(_ image: UIImage, for remoteURL: String) -> String? {
|
|
103
|
+
let hash = remoteURL.hash
|
|
104
|
+
let fileName = "sk-carousel-\(abs(hash)).jpg"
|
|
105
|
+
let fileURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(fileName)
|
|
106
|
+
|
|
107
|
+
// Skip if already written
|
|
108
|
+
if FileManager.default.fileExists(atPath: fileURL.path) {
|
|
109
|
+
return fileURL.absoluteString
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
guard let data = image.jpegData(compressionQuality: 0.9) else { return nil }
|
|
113
|
+
do {
|
|
114
|
+
try data.write(to: fileURL, options: .atomic)
|
|
115
|
+
return fileURL.absoluteString
|
|
116
|
+
} catch {
|
|
117
|
+
return nil
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
public func resetState() {
|
|
122
|
+
// Don't clear surface props — matches video overlay (ReactOverlayHost) pattern.
|
|
123
|
+
// configure() will overwrite with new props directly, letting React do an
|
|
124
|
+
// in-place re-render (old→new) instead of an unmount+remount (old→empty→new).
|
|
125
|
+
// The overlay's synchronous reset pattern handles state transitions.
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// MARK: - Surface Creation
|
|
129
|
+
|
|
130
|
+
private func createSurfaceIfNeeded() {
|
|
131
|
+
guard surface == nil, let presenter = surfacePresenter else { return }
|
|
132
|
+
|
|
133
|
+
// Must always dispatch to main queue — see ReactOverlayHost for details.
|
|
134
|
+
DispatchQueue.main.async { [weak self] in
|
|
135
|
+
guard let self, self.surface == nil else { return }
|
|
136
|
+
self.installSurface(presenter: presenter)
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
private func installSurface(presenter: AnyObject) {
|
|
141
|
+
guard let surf = SKFabricSurfaceWrapper(
|
|
142
|
+
presenter: presenter,
|
|
143
|
+
moduleName: carouselOverlayModuleName,
|
|
144
|
+
initialProperties: [:]
|
|
145
|
+
) else { return }
|
|
146
|
+
surf.start()
|
|
147
|
+
|
|
148
|
+
let view = surf.view
|
|
149
|
+
view.translatesAutoresizingMaskIntoConstraints = false
|
|
150
|
+
addSubview(view)
|
|
151
|
+
NSLayoutConstraint.activate([
|
|
152
|
+
view.topAnchor.constraint(equalTo: topAnchor),
|
|
153
|
+
view.leadingAnchor.constraint(equalTo: leadingAnchor),
|
|
154
|
+
view.trailingAnchor.constraint(equalTo: trailingAnchor),
|
|
155
|
+
view.bottomAnchor.constraint(equalTo: bottomAnchor),
|
|
156
|
+
])
|
|
157
|
+
surfaceView = view
|
|
158
|
+
surface = surf
|
|
159
|
+
|
|
160
|
+
// Flush any props that arrived before surface was ready
|
|
161
|
+
if let pending = pendingProps {
|
|
162
|
+
surf.setProperties(pending)
|
|
163
|
+
pendingProps = nil
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// MARK: - Layout
|
|
168
|
+
|
|
169
|
+
public override func layoutSubviews() {
|
|
170
|
+
super.layoutSubviews()
|
|
171
|
+
guard let surface else { return }
|
|
172
|
+
let size = bounds.size
|
|
173
|
+
guard size.width > 0, size.height > 0 else { return }
|
|
174
|
+
surface.setMinimumSize(size)
|
|
175
|
+
surface.setMaximumSize(size)
|
|
176
|
+
}
|
|
177
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import UIKit
|
|
2
|
+
|
|
3
|
+
/// UIView that hosts a React Fabric surface for the custom loading component.
|
|
4
|
+
/// Used as the `loadingViewProvider` for the ShortKit SDK.
|
|
5
|
+
@objc public class ReactLoadingHost: UIView {
|
|
6
|
+
|
|
7
|
+
public var surfacePresenter: AnyObject?
|
|
8
|
+
|
|
9
|
+
private var surface: SKFabricSurfaceWrapper?
|
|
10
|
+
|
|
11
|
+
public override func didMoveToWindow() {
|
|
12
|
+
super.didMoveToWindow()
|
|
13
|
+
if window != nil && surface == nil {
|
|
14
|
+
guard let presenter = surfacePresenter ?? ShortKitBridge.shared?.surfacePresenter else { return }
|
|
15
|
+
let wrapper = SKFabricSurfaceWrapper(presenter: presenter, moduleName: "ShortKitLoading", initialProperties: [:])
|
|
16
|
+
wrapper?.start()
|
|
17
|
+
if let surfaceView = wrapper?.view {
|
|
18
|
+
surfaceView.frame = bounds
|
|
19
|
+
surfaceView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
|
20
|
+
addSubview(surfaceView)
|
|
21
|
+
}
|
|
22
|
+
surface = wrapper
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public override func willMove(toWindow newWindow: UIWindow?) {
|
|
27
|
+
super.willMove(toWindow: newWindow)
|
|
28
|
+
if newWindow == nil {
|
|
29
|
+
surface?.stop()
|
|
30
|
+
surface = nil
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
public override func layoutSubviews() {
|
|
35
|
+
super.layoutSubviews()
|
|
36
|
+
surface?.view.frame = bounds
|
|
37
|
+
}
|
|
38
|
+
}
|