@shortkitsdk/react-native 0.2.45 → 0.2.47
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/android/libs/shortkit-release.aar +0 -0
- package/android/src/main/java/com/shortkit/reactnative/ReactOverlayHost.kt +17 -2
- package/android/src/main/java/com/shortkit/reactnative/ShortKitBridge.kt +2 -4
- package/ios/ShortKitBridge.swift +74 -1
- package/ios/ShortKitModule.mm +10 -0
- package/ios/ShortKitPushHostViewController.swift +59 -0
- package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Info.plist +2 -2
- package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.abi.json +1296 -107
- package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.private.swiftinterface +30 -9
- 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 +30 -9
- package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/ShortKitSDK +0 -0
- package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/_CodeSignature/CodeResources +9 -9
- package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Info.plist +2 -2
- package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.abi.json +1296 -107
- package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface +30 -9
- package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.swiftdoc +0 -0
- package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.swiftinterface +30 -9
- package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.abi.json +1296 -107
- package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface +30 -9
- package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.swiftdoc +0 -0
- package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.swiftinterface +30 -9
- package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/ShortKitSDK +0 -0
- package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/_CodeSignature/CodeResources +17 -17
- package/package.json +1 -1
- package/src/ShortKitCommands.ts +39 -0
- package/src/index.ts +5 -0
- package/src/specs/NativeShortKitModule.ts +4 -0
|
Binary file
|
|
@@ -69,6 +69,10 @@ class ReactOverlayHost(context: Context) : FrameLayout(context), FeedOverlay {
|
|
|
69
69
|
layout(left, top, right, bottom)
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
/** Tracks the deferred measureAndLayoutSurfaceView post from configure() so it can be
|
|
73
|
+
* cancelled in onDetachedFromWindow before the stale dimensions are applied. */
|
|
74
|
+
private var configureLayoutRunnable: Runnable? = null
|
|
75
|
+
|
|
72
76
|
/**
|
|
73
77
|
* Fabric may suppress layout propagation to native child views inside
|
|
74
78
|
* the SDK's RecyclerView cells. Override to force a manual layout pass.
|
|
@@ -238,7 +242,13 @@ class ReactOverlayHost(context: Context) : FrameLayout(context), FeedOverlay {
|
|
|
238
242
|
}
|
|
239
243
|
ShortKitBridge.shared?.emitEvent("onOverlayItemChanged", params)
|
|
240
244
|
}
|
|
241
|
-
// Pre-size the surface view
|
|
245
|
+
// Pre-size the surface view. Deferred to avoid calling sv.measure() synchronously
|
|
246
|
+
// during RecyclerView.onBindViewHolder — which can trigger Fabric to dispatch pending
|
|
247
|
+
// mount items (e.g. react-native-screens activityState updates) that commit fragment
|
|
248
|
+
// transactions re-entrantly, detaching the RecyclerView mid-layout and crashing with
|
|
249
|
+
// "Tmp detached view should be removed from RecyclerView before it can be recycled".
|
|
250
|
+
// Safe to defer: createSurfaceIfNeeded() already pre-sizes new surfaces, and onLayout
|
|
251
|
+
// re-pushes correct dimensions during the same layout pass for recycled ones.
|
|
242
252
|
val parentView = parent as? android.view.View
|
|
243
253
|
val w = if (width > 0) width
|
|
244
254
|
else if (parentView != null && parentView.width > 0) parentView.width
|
|
@@ -246,7 +256,10 @@ class ReactOverlayHost(context: Context) : FrameLayout(context), FeedOverlay {
|
|
|
246
256
|
val h = if (height > 0) height
|
|
247
257
|
else if (parentView != null && parentView.height > 0) parentView.height
|
|
248
258
|
else context.resources.displayMetrics.heightPixels
|
|
249
|
-
|
|
259
|
+
configureLayoutRunnable?.let { layoutHandler.removeCallbacks(it) }
|
|
260
|
+
val r = Runnable { measureAndLayoutSurfaceView(w, h) }
|
|
261
|
+
configureLayoutRunnable = r
|
|
262
|
+
layoutHandler.post(r)
|
|
250
263
|
}
|
|
251
264
|
|
|
252
265
|
override fun activatePlayback() {
|
|
@@ -300,6 +313,8 @@ class ReactOverlayHost(context: Context) : FrameLayout(context), FeedOverlay {
|
|
|
300
313
|
|
|
301
314
|
override fun onDetachedFromWindow() {
|
|
302
315
|
super.onDetachedFromWindow()
|
|
316
|
+
configureLayoutRunnable?.let { layoutHandler.removeCallbacks(it) }
|
|
317
|
+
configureLayoutRunnable = null
|
|
303
318
|
layoutHandler.removeCallbacks(layoutRunnable)
|
|
304
319
|
// Cancel flow subscriptions to avoid emitting events for off-screen cells.
|
|
305
320
|
// Do NOT stop the surface — keep JS alive so subscriptions persist across
|
|
@@ -428,10 +428,8 @@ class ShortKitBridge(
|
|
|
428
428
|
"video" -> {
|
|
429
429
|
val playbackId = obj.optString("playbackId", null) ?: continue
|
|
430
430
|
val fallbackUrl = obj.optString("fallbackUrl", null)
|
|
431
|
-
val
|
|
432
|
-
|
|
433
|
-
if (!itemId.isNullOrBlank() && !fallbackUrl.isNullOrBlank()) itemId else playbackId
|
|
434
|
-
result.add(FeedInput.Video(nativePlaybackId, fallbackUrl))
|
|
431
|
+
val contentId = obj.optString("id", null).takeIf { !it.isNullOrBlank() }
|
|
432
|
+
result.add(FeedInput.Video(playbackId, fallbackUrl, contentId))
|
|
435
433
|
}
|
|
436
434
|
"imageCarousel" -> {
|
|
437
435
|
val itemObj = obj.optJSONObject("item") ?: continue
|
package/ios/ShortKitBridge.swift
CHANGED
|
@@ -1111,7 +1111,8 @@ import ShortKitSDK
|
|
|
1111
1111
|
guard let playbackId = obj["playbackId"] as? String else { continue }
|
|
1112
1112
|
let origin = (obj["origin"] as? String).flatMap { ContentOrigin(rawValue: $0) } ?? .other
|
|
1113
1113
|
let fallbackUrl = obj["fallbackUrl"] as? String
|
|
1114
|
-
|
|
1114
|
+
let contentId = obj["id"] as? String
|
|
1115
|
+
result.append(.video(playbackId: playbackId, origin: origin, fallbackUrl: fallbackUrl, contentId: contentId))
|
|
1115
1116
|
case "imageCarousel":
|
|
1116
1117
|
guard let itemData = obj["item"],
|
|
1117
1118
|
let itemJSON = try? JSONSerialization.data(withJSONObject: itemData),
|
|
@@ -1210,6 +1211,78 @@ extension ShortKitBridge {
|
|
|
1210
1211
|
}
|
|
1211
1212
|
}
|
|
1212
1213
|
|
|
1214
|
+
// MARK: - Push Navigation
|
|
1215
|
+
|
|
1216
|
+
extension ShortKitBridge {
|
|
1217
|
+
/// Push a host-registered RN component onto the feed modal's
|
|
1218
|
+
/// UINavigationController with a native parallax animation. Finds the
|
|
1219
|
+
/// topmost presented UINavigationController via the UIKit presentation
|
|
1220
|
+
/// chain — works for both mask and standard feed expansions. Silently
|
|
1221
|
+
/// no-ops if no nav controller is currently presented (e.g. called when
|
|
1222
|
+
/// no feed modal is on screen).
|
|
1223
|
+
@objc public func pushFeedScreen(_ componentName: String, propsJSON: String) {
|
|
1224
|
+
DispatchQueue.main.async { [weak self] in
|
|
1225
|
+
guard let self,
|
|
1226
|
+
let navController = Self.topmostNavigationController(),
|
|
1227
|
+
let presenter = self.surfacePresenter else { return }
|
|
1228
|
+
|
|
1229
|
+
let props: [String: Any]
|
|
1230
|
+
if let data = propsJSON.data(using: .utf8),
|
|
1231
|
+
let obj = try? JSONSerialization.jsonObject(with: data) as? [String: Any] {
|
|
1232
|
+
props = obj
|
|
1233
|
+
} else {
|
|
1234
|
+
props = [:]
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
let pushVC = ShortKitPushHostViewController(
|
|
1238
|
+
moduleName: componentName,
|
|
1239
|
+
initialProps: props,
|
|
1240
|
+
surfacePresenter: presenter
|
|
1241
|
+
)
|
|
1242
|
+
navController.pushViewController(pushVC, animated: true)
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
/// Pop the topmost pushed screen from its navigation stack.
|
|
1247
|
+
///
|
|
1248
|
+
/// Drills to the topmost *view controller* (not the nav controller itself)
|
|
1249
|
+
/// and calls popViewController on its navigationController. This is more
|
|
1250
|
+
/// robust than calling popViewController on the topmost nav controller
|
|
1251
|
+
/// directly: if a system sheet or other modal is presented on top of the
|
|
1252
|
+
/// pushed screen, that sheet's nav controller (nil) is used instead of
|
|
1253
|
+
/// the push host's nav controller, making the pop a safe no-op rather
|
|
1254
|
+
/// than popping from the wrong stack.
|
|
1255
|
+
@objc public func popFeedScreen() {
|
|
1256
|
+
DispatchQueue.main.async {
|
|
1257
|
+
Self.topmostViewController()?.navigationController?.popViewController(animated: true)
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
/// Walk the UIViewController presentation chain to find the topmost
|
|
1262
|
+
/// UINavigationController. Used by pushFeedScreen. Called on the main queue.
|
|
1263
|
+
private static func topmostNavigationController() -> UINavigationController? {
|
|
1264
|
+
guard let vc = topmostViewController() else { return nil }
|
|
1265
|
+
if let nav = vc as? UINavigationController { return nav }
|
|
1266
|
+
return vc.navigationController
|
|
1267
|
+
}
|
|
1268
|
+
|
|
1269
|
+
/// Walk the UIViewController presentation chain to its end, then drill
|
|
1270
|
+
/// into a UINavigationController's topViewController if present.
|
|
1271
|
+
private static func topmostViewController() -> UIViewController? {
|
|
1272
|
+
guard let windowScene = UIApplication.shared.connectedScenes
|
|
1273
|
+
.first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene,
|
|
1274
|
+
let window = windowScene.windows.first(where: { $0.isKeyWindow }) else {
|
|
1275
|
+
return nil
|
|
1276
|
+
}
|
|
1277
|
+
var vc: UIViewController? = window.rootViewController
|
|
1278
|
+
while let presented = vc?.presentedViewController {
|
|
1279
|
+
vc = presented
|
|
1280
|
+
}
|
|
1281
|
+
if let nav = vc as? UINavigationController { return nav.topViewController }
|
|
1282
|
+
return vc
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1213
1286
|
// MARK: - ShortKitDownloadDelegate
|
|
1214
1287
|
|
|
1215
1288
|
extension ShortKitBridge: ShortKitDownloadDelegate {
|
package/ios/ShortKitModule.mm
CHANGED
|
@@ -387,6 +387,16 @@ RCT_EXPORT_METHOD(cancelDownload) {
|
|
|
387
387
|
[_shortKitBridge cancelDownload];
|
|
388
388
|
}
|
|
389
389
|
|
|
390
|
+
// MARK: - Push Navigation
|
|
391
|
+
|
|
392
|
+
RCT_EXPORT_METHOD(pushFeedScreen:(NSString *)componentName propsJSON:(NSString *)propsJSON) {
|
|
393
|
+
[_shortKitBridge pushFeedScreen:componentName propsJSON:propsJSON];
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
RCT_EXPORT_METHOD(popFeedScreen) {
|
|
397
|
+
[_shortKitBridge popFeedScreen];
|
|
398
|
+
}
|
|
399
|
+
|
|
390
400
|
// MARK: - New Architecture (TurboModule)
|
|
391
401
|
|
|
392
402
|
#ifdef RCT_NEW_ARCH_ENABLED
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import UIKit
|
|
2
|
+
|
|
3
|
+
/// Full-screen UIViewController that hosts an RCTFabricSurface rendering a
|
|
4
|
+
/// host-registered RN component. Pushed onto the feed modal's
|
|
5
|
+
/// UINavigationController by `ShortKitBridge.pushFeedScreen(componentName:propsJSON:)`
|
|
6
|
+
/// to give a native parallax-push animation from within the expanded feed.
|
|
7
|
+
final class ShortKitPushHostViewController: UIViewController {
|
|
8
|
+
|
|
9
|
+
private let moduleName: String
|
|
10
|
+
private let initialProps: [String: Any]
|
|
11
|
+
private let surfacePresenter: AnyObject
|
|
12
|
+
private var surface: SKFabricSurfaceWrapper?
|
|
13
|
+
private var lastLayoutSize: CGSize = .zero
|
|
14
|
+
|
|
15
|
+
init(moduleName: String, initialProps: [String: Any], surfacePresenter: AnyObject) {
|
|
16
|
+
self.moduleName = moduleName
|
|
17
|
+
self.initialProps = initialProps
|
|
18
|
+
self.surfacePresenter = surfacePresenter
|
|
19
|
+
super.init(nibName: nil, bundle: nil)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
@available(*, unavailable)
|
|
23
|
+
required init?(coder: NSCoder) { fatalError() }
|
|
24
|
+
|
|
25
|
+
override func viewDidLoad() {
|
|
26
|
+
super.viewDidLoad()
|
|
27
|
+
view.backgroundColor = .black
|
|
28
|
+
|
|
29
|
+
guard let surf = SKFabricSurfaceWrapper(
|
|
30
|
+
presenter: surfacePresenter,
|
|
31
|
+
moduleName: moduleName,
|
|
32
|
+
initialProperties: initialProps
|
|
33
|
+
) else { return }
|
|
34
|
+
surf.start()
|
|
35
|
+
|
|
36
|
+
let surfaceView = surf.view
|
|
37
|
+
surfaceView.translatesAutoresizingMaskIntoConstraints = false
|
|
38
|
+
view.addSubview(surfaceView)
|
|
39
|
+
NSLayoutConstraint.activate([
|
|
40
|
+
surfaceView.topAnchor.constraint(equalTo: view.topAnchor),
|
|
41
|
+
surfaceView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
|
42
|
+
surfaceView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
|
43
|
+
surfaceView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
|
|
44
|
+
])
|
|
45
|
+
self.surface = surf
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
override func viewDidLayoutSubviews() {
|
|
49
|
+
super.viewDidLayoutSubviews()
|
|
50
|
+
let size = view.bounds.size
|
|
51
|
+
guard size.width > 0, size.height > 0, size != lastLayoutSize else { return }
|
|
52
|
+
lastLayoutSize = size
|
|
53
|
+
surface?.setMinimumSize(size)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
deinit {
|
|
57
|
+
surface?.stop()
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
<key>CFBundlePackageType</key>
|
|
12
12
|
<string>FMWK</string>
|
|
13
13
|
<key>CFBundleVersion</key>
|
|
14
|
-
<string>0.2.
|
|
14
|
+
<string>0.2.47</string>
|
|
15
15
|
<key>CFBundleShortVersionString</key>
|
|
16
|
-
<string>0.2.
|
|
16
|
+
<string>0.2.47</string>
|
|
17
17
|
<key>MinimumOSVersion</key>
|
|
18
18
|
<string>16.0</string>
|
|
19
19
|
</dict>
|