@digia-engage/core 1.0.0-beta.4 → 1.0.0-beta.5
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/DigiaEngageReactNative.podspec +24 -5
- package/android/settings.gradle +1 -2
- package/ios/DigiaEngageModule.m +24 -44
- package/ios/DigiaHostViewManager.swift +104 -0
- package/ios/DigiaModule.swift +192 -0
- package/ios/DigiaSlotViewManager.swift +107 -0
- package/ios/RNEventBridgePlugin.swift +72 -0
- package/lib/commonjs/DigiaHostView.js +10 -8
- package/lib/commonjs/DigiaHostView.js.map +1 -1
- package/lib/commonjs/DigiaSlotView.js +6 -5
- package/lib/commonjs/DigiaSlotView.js.map +1 -1
- package/lib/module/DigiaHostView.js +10 -8
- package/lib/module/DigiaHostView.js.map +1 -1
- package/lib/module/DigiaSlotView.js +6 -5
- package/lib/module/DigiaSlotView.js.map +1 -1
- package/lib/typescript/DigiaHostView.d.ts +2 -1
- package/lib/typescript/DigiaHostView.d.ts.map +1 -1
- package/lib/typescript/DigiaSlotView.d.ts +2 -1
- package/lib/typescript/DigiaSlotView.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/DigiaHostView.tsx +10 -8
- package/src/DigiaSlotView.tsx +6 -5
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
Pod::Spec.new do |s|
|
|
2
2
|
s.name = 'DigiaEngageReactNative'
|
|
3
3
|
s.version = '0.1.0'
|
|
4
|
-
s.summary = 'React Native bridge for the Digia Engage SDK (
|
|
4
|
+
s.summary = 'React Native bridge for the Digia Engage SDK (iOS & Android).'
|
|
5
5
|
s.description = <<-DESC
|
|
6
|
-
Provides a React Native bridge that surfaces the Digia Engage
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
Provides a React Native bridge that surfaces the Digia Engage SDK inside
|
|
7
|
+
React Native applications. Supports both iOS (SwiftUI) and Android
|
|
8
|
+
(Jetpack Compose) using the New Architecture (TurboModules / Fabric).
|
|
9
9
|
DESC
|
|
10
10
|
|
|
11
11
|
s.homepage = 'https://github.com/Digia-Technology-Private-Limited/digia_engage'
|
|
@@ -13,9 +13,28 @@ Pod::Spec.new do |s|
|
|
|
13
13
|
s.author = { 'Digia Technology Private Limited' => '' }
|
|
14
14
|
s.source = { :git => 'https://github.com/Digia-Technology-Private-Limited/digia_engage.git', :tag => s.version.to_s }
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
# DigiaEngage iOS SDK requires iOS 16+ (SwiftUI features used internally).
|
|
17
|
+
s.ios.deployment_target = '16.0'
|
|
17
18
|
|
|
18
19
|
s.source_files = 'ios/**/*.{h,m,mm,swift}'
|
|
19
20
|
|
|
21
|
+
# Swift version must match the Digia iOS SDK.
|
|
22
|
+
s.swift_version = '5.9'
|
|
23
|
+
|
|
20
24
|
s.dependency 'React-Core'
|
|
25
|
+
|
|
26
|
+
# ── Digia Engage iOS SDK ──────────────────────────────────────────────────
|
|
27
|
+
# Published Swift Package: https://swiftpackageindex.com/Digia-Technology-Private-Limited/digia_engage_iOS
|
|
28
|
+
# Source: https://github.com/Digia-Technology-Private-Limited/digia_engage_iOS.git
|
|
29
|
+
#
|
|
30
|
+
# When integrating via CocoaPods, add the git source to your Podfile:
|
|
31
|
+
# pod 'DigiaEngage', :git => 'https://github.com/Digia-Technology-Private-Limited/digia_engage_iOS.git',
|
|
32
|
+
# :tag => '1.0.0-beta.1'
|
|
33
|
+
s.dependency 'DigiaEngage', '1.0.0-beta.1'
|
|
34
|
+
|
|
35
|
+
# ── New Architecture (Fabric / TurboModules) support ─────────────────────
|
|
36
|
+
# install_modules_dependencies wires the pod into both Old Architecture
|
|
37
|
+
# (bridge) and New Architecture (JSI / Fabric) automatically when the host
|
|
38
|
+
# app has `use_frameworks!` / `use_react_native!` with :fabric_enabled.
|
|
39
|
+
install_modules_dependencies(s)
|
|
21
40
|
end
|
package/android/settings.gradle
CHANGED
|
@@ -17,8 +17,7 @@ dependencyResolutionManagement {
|
|
|
17
17
|
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
|
18
18
|
repositories {
|
|
19
19
|
google()
|
|
20
|
-
mavenCentral()
|
|
21
|
-
mavenLocal()
|
|
20
|
+
mavenCentral() // tech.digia:engage published at https://central.sonatype.com/artifact/tech.digia/engage
|
|
22
21
|
maven { url 'https://jitpack.io' }
|
|
23
22
|
}
|
|
24
23
|
}
|
package/ios/DigiaEngageModule.m
CHANGED
|
@@ -1,71 +1,51 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* DigiaEngageModule
|
|
2
|
+
* DigiaEngageModule.m
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* ObjC bridge file that exports Swift implementations to the React Native
|
|
5
|
+
* runtime (both Old Architecture bridge and New Architecture TurboModules).
|
|
6
|
+
*
|
|
7
|
+
* All real logic lives in the Swift files alongside this one:
|
|
8
|
+
* DigiaModule.swift — NativeModule (RCTEventEmitter subclass)
|
|
9
|
+
* RNEventBridgePlugin.swift — DigiaCEPPlugin bridge
|
|
10
|
+
* DigiaHostViewManager.swift — ViewManager for <DigiaHostView>
|
|
11
|
+
* DigiaSlotViewManager.swift — ViewManager for <DigiaSlotView>
|
|
6
12
|
*/
|
|
13
|
+
|
|
7
14
|
#import <React/RCTBridgeModule.h>
|
|
15
|
+
#import <React/RCTEventEmitter.h>
|
|
8
16
|
#import <React/RCTViewManager.h>
|
|
9
17
|
|
|
10
|
-
// ── NativeModule
|
|
11
|
-
|
|
12
|
-
@interface DigiaEngageModule : NSObject <RCTBridgeModule>
|
|
13
|
-
@end
|
|
18
|
+
// ── NativeModule ──────────────────────────────────────────────────────────────
|
|
14
19
|
|
|
15
|
-
|
|
20
|
+
// RCT_EXTERN_MODULE wires the Swift class DigiaModule (which inherits
|
|
21
|
+
// RCTEventEmitter) to the React Native bridge under the name "DigiaEngageModule".
|
|
16
22
|
|
|
17
|
-
|
|
23
|
+
@interface RCT_EXTERN_MODULE(DigiaEngageModule, RCTEventEmitter)
|
|
18
24
|
|
|
19
|
-
|
|
25
|
+
RCT_EXTERN_METHOD(initialize:(NSString *)apiKey
|
|
20
26
|
environment:(NSString *)environment
|
|
21
27
|
logLevel:(NSString *)logLevel
|
|
22
28
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
23
29
|
reject:(RCTPromiseRejectBlock)reject)
|
|
24
|
-
{
|
|
25
|
-
// iOS not yet implemented – resolve immediately so JS doesn't hang.
|
|
26
|
-
resolve(nil);
|
|
27
|
-
}
|
|
28
30
|
|
|
29
|
-
|
|
30
|
-
{
|
|
31
|
-
// no-op
|
|
32
|
-
}
|
|
31
|
+
RCT_EXTERN_METHOD(registerBridge)
|
|
33
32
|
|
|
34
|
-
|
|
35
|
-
pageArgs:(NSDictionary *)pageArgs)
|
|
36
|
-
{
|
|
37
|
-
// no-op
|
|
38
|
-
}
|
|
33
|
+
RCT_EXTERN_METHOD(setCurrentScreen:(NSString *)name)
|
|
39
34
|
|
|
40
|
-
|
|
35
|
+
RCT_EXTERN_METHOD(triggerCampaign:(NSString *)id
|
|
41
36
|
content:(NSDictionary *)content
|
|
42
37
|
cepContext:(NSDictionary *)cepContext)
|
|
43
|
-
{
|
|
44
|
-
// no-op — iOS Digia SDK not yet available
|
|
45
|
-
}
|
|
46
38
|
|
|
47
|
-
|
|
48
|
-
{
|
|
49
|
-
// no-op
|
|
50
|
-
}
|
|
39
|
+
RCT_EXTERN_METHOD(invalidateCampaign:(NSString *)campaignId)
|
|
51
40
|
|
|
52
41
|
@end
|
|
53
42
|
|
|
54
43
|
|
|
55
|
-
// ──
|
|
44
|
+
// ── ViewManagers ──────────────────────────────────────────────────────────────
|
|
56
45
|
|
|
57
|
-
@interface
|
|
46
|
+
@interface RCT_EXTERN_MODULE(DigiaHostView, RCTViewManager)
|
|
58
47
|
@end
|
|
59
48
|
|
|
60
|
-
@
|
|
61
|
-
|
|
62
|
-
RCT_EXPORT_MODULE(DigiaHostView)
|
|
63
|
-
|
|
64
|
-
- (UIView *)view {
|
|
65
|
-
// Return a transparent placeholder view
|
|
66
|
-
UIView *v = [[UIView alloc] init];
|
|
67
|
-
v.userInteractionEnabled = NO;
|
|
68
|
-
return v;
|
|
69
|
-
}
|
|
70
|
-
|
|
49
|
+
@interface RCT_EXTERN_MODULE(DigiaSlotView, RCTViewManager)
|
|
50
|
+
RCT_EXPORT_VIEW_PROPERTY(placementKey, NSString)
|
|
71
51
|
@end
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DigiaHostViewManager
|
|
3
|
+
*
|
|
4
|
+
* React Native ViewManager that exposes a UIView wrapping DigiaHost (from the
|
|
5
|
+
* Digia iOS SDK) as the native view behind the JS <DigiaHostView> component.
|
|
6
|
+
*
|
|
7
|
+
* DigiaHost is a SwiftUI view, so we bridge it into UIKit using a
|
|
8
|
+
* UIHostingController embedded as a child view controller. The host view
|
|
9
|
+
* manages dialog and bottom-sheet overlays driven by Digia CEP plugins.
|
|
10
|
+
*
|
|
11
|
+
* Place <DigiaHostView> once at the root of your RN component tree.
|
|
12
|
+
*/
|
|
13
|
+
import SwiftUI
|
|
14
|
+
import React
|
|
15
|
+
import DigiaEngage
|
|
16
|
+
|
|
17
|
+
@objc(DigiaHostView)
|
|
18
|
+
final class DigiaHostViewManager: RCTViewManager {
|
|
19
|
+
|
|
20
|
+
override static func requiresMainQueueSetup() -> Bool { true }
|
|
21
|
+
|
|
22
|
+
override func view() -> UIView! {
|
|
23
|
+
return DigiaHostUIView()
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// MARK: - DigiaHostUIView
|
|
28
|
+
|
|
29
|
+
/// Lightweight UIView container that embeds a UIHostingController<DigiaHost>
|
|
30
|
+
/// as a child so SwiftUI's DigiaHost composable renders overlays above all
|
|
31
|
+
/// React Native content.
|
|
32
|
+
final class DigiaHostUIView: UIView {
|
|
33
|
+
|
|
34
|
+
private var hostingController: UIHostingController<DigiaHostWrapperView>?
|
|
35
|
+
|
|
36
|
+
override func didMoveToWindow() {
|
|
37
|
+
super.didMoveToWindow()
|
|
38
|
+
guard window != nil else {
|
|
39
|
+
// View removed from hierarchy — tear down the hosting controller.
|
|
40
|
+
hostingController?.willMove(toParent: nil)
|
|
41
|
+
hostingController?.view.removeFromSuperview()
|
|
42
|
+
hostingController?.removeFromParent()
|
|
43
|
+
hostingController = nil
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
guard hostingController == nil else { return }
|
|
47
|
+
mountHostingController()
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
private func mountHostingController() {
|
|
51
|
+
guard let parentVC = parentViewController() else { return }
|
|
52
|
+
|
|
53
|
+
let swiftUIView = DigiaHostWrapperView()
|
|
54
|
+
let hc = UIHostingController(rootView: swiftUIView)
|
|
55
|
+
hc.view.translatesAutoresizingMaskIntoConstraints = false
|
|
56
|
+
hc.view.backgroundColor = .clear
|
|
57
|
+
// Disable touch interception so all taps pass through to React Native
|
|
58
|
+
// content below. The dialog/bottom-sheet overlays are presented as
|
|
59
|
+
// separate UIViewControllers (via ViewControllerUtil.present) so they
|
|
60
|
+
// independently capture touches when visible.
|
|
61
|
+
hc.view.isUserInteractionEnabled = false
|
|
62
|
+
|
|
63
|
+
parentVC.addChild(hc)
|
|
64
|
+
addSubview(hc.view)
|
|
65
|
+
hc.didMove(toParent: parentVC)
|
|
66
|
+
|
|
67
|
+
NSLayoutConstraint.activate([
|
|
68
|
+
hc.view.leadingAnchor.constraint(equalTo: leadingAnchor),
|
|
69
|
+
hc.view.trailingAnchor.constraint(equalTo: trailingAnchor),
|
|
70
|
+
hc.view.topAnchor.constraint(equalTo: topAnchor),
|
|
71
|
+
hc.view.bottomAnchor.constraint(equalTo: bottomAnchor),
|
|
72
|
+
])
|
|
73
|
+
|
|
74
|
+
hostingController = hc
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Walk the responder chain to find the nearest UIViewController.
|
|
78
|
+
private func parentViewController() -> UIViewController? {
|
|
79
|
+
var responder: UIResponder? = self
|
|
80
|
+
while let r = responder {
|
|
81
|
+
if let vc = r as? UIViewController { return vc }
|
|
82
|
+
responder = r.next
|
|
83
|
+
}
|
|
84
|
+
return nil
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// MARK: - SwiftUI wrapper
|
|
89
|
+
|
|
90
|
+
/// A SwiftUI view that acts as the DigiaHost root. An EmptyView is used as
|
|
91
|
+
/// content because React Native's own navigation already manages the app's
|
|
92
|
+
/// view hierarchy — DigiaHost only needs to be mounted to activate the overlay
|
|
93
|
+
/// layer.
|
|
94
|
+
private struct DigiaHostWrapperView: View {
|
|
95
|
+
var body: some View {
|
|
96
|
+
DigiaHost {
|
|
97
|
+
EmptyView()
|
|
98
|
+
}
|
|
99
|
+
// No frame constraint here — the view fills its parent (absoluteFill
|
|
100
|
+
// from JS). A non-zero frame is required so UIKit calls viewDidAppear
|
|
101
|
+
// on the UIHostingController, which in turn triggers SwiftUI onAppear
|
|
102
|
+
// and establishes the onChange(activePayload) subscription.
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DigiaModule
|
|
3
|
+
*
|
|
4
|
+
* React Native NativeModule that bridges the Digia Engage iOS SDK.
|
|
5
|
+
*
|
|
6
|
+
* Exposed methods (callable from JS via NativeModules.DigiaEngageModule):
|
|
7
|
+
* initialize(apiKey, environment, logLevel): Promise<void>
|
|
8
|
+
* registerBridge(): void
|
|
9
|
+
* setCurrentScreen(name): void
|
|
10
|
+
* triggerCampaign(id, content, cepContext): void
|
|
11
|
+
* invalidateCampaign(campaignId): void
|
|
12
|
+
*
|
|
13
|
+
* Architecture
|
|
14
|
+
* ────────────
|
|
15
|
+
* The RN bridge mirrors the native Digia.initialize / Digia.register /
|
|
16
|
+
* Digia.setCurrentScreen flow exactly. An internal RNEventBridgePlugin is
|
|
17
|
+
* the single native DigiaCEPPlugin registered via Digia.register().
|
|
18
|
+
*
|
|
19
|
+
* When the SDK calls plugin.setup(delegate:), the bridge stores that
|
|
20
|
+
* delegate reference. JS plugins that deliver campaigns call triggerCampaign /
|
|
21
|
+
* invalidateCampaign which forward to delegate.onCampaignTriggered /
|
|
22
|
+
* delegate.onCampaignInvalidated.
|
|
23
|
+
*
|
|
24
|
+
* Overlay lifecycle events (impressed / clicked / dismissed) are forwarded from
|
|
25
|
+
* the native plugin.notifyEvent() to JS via RCTEventEmitter so that pure-JS
|
|
26
|
+
* CEP plugins (e.g. DigiaMoEngagePlugin) can report analytics.
|
|
27
|
+
*/
|
|
28
|
+
import Foundation
|
|
29
|
+
import React
|
|
30
|
+
import DigiaEngage
|
|
31
|
+
|
|
32
|
+
@objc(DigiaEngageModule)
|
|
33
|
+
final class DigiaModule: RCTEventEmitter {
|
|
34
|
+
|
|
35
|
+
private lazy var rnPlugin: RNEventBridgePlugin = MainActor.assumeIsolated {
|
|
36
|
+
RNEventBridgePlugin(eventEmitter: self)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// ────────────────────────────────────────────────────────────────────────
|
|
40
|
+
// MARK: - RCTEventEmitter
|
|
41
|
+
|
|
42
|
+
override static func requiresMainQueueSetup() -> Bool { true }
|
|
43
|
+
|
|
44
|
+
override func supportedEvents() -> [String]! {
|
|
45
|
+
return [
|
|
46
|
+
"digia_experience_impressed",
|
|
47
|
+
"digia_experience_clicked",
|
|
48
|
+
"digia_experience_dismissed",
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ────────────────────────────────────────────────────────────────────────
|
|
53
|
+
// MARK: - initialize
|
|
54
|
+
|
|
55
|
+
@objc
|
|
56
|
+
func initialize(
|
|
57
|
+
_ apiKey: String,
|
|
58
|
+
environment: String,
|
|
59
|
+
logLevel: String,
|
|
60
|
+
resolve: @escaping RCTPromiseResolveBlock,
|
|
61
|
+
reject: @escaping RCTPromiseRejectBlock
|
|
62
|
+
) {
|
|
63
|
+
let envValue: DigiaEnvironment = environment.lowercased() == "sandbox" ? .sandbox : .production
|
|
64
|
+
let logLevelValue: DigiaLogLevel
|
|
65
|
+
switch logLevel.lowercased() {
|
|
66
|
+
case "verbose": logLevelValue = .verbose
|
|
67
|
+
case "none": logLevelValue = .none
|
|
68
|
+
default: logLevelValue = .error
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
let config = DigiaConfig(
|
|
72
|
+
apiKey: apiKey,
|
|
73
|
+
logLevel: logLevelValue,
|
|
74
|
+
environment: envValue
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
Task { @MainActor in
|
|
78
|
+
do {
|
|
79
|
+
try await Digia.initialize(config)
|
|
80
|
+
resolve(nil)
|
|
81
|
+
} catch {
|
|
82
|
+
reject("DIGIA_INIT_ERROR", error.localizedDescription, error)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// ────────────────────────────────────────────────────────────────────────
|
|
88
|
+
// MARK: - registerBridge
|
|
89
|
+
|
|
90
|
+
/// Registers RNEventBridgePlugin with the native Digia SDK.
|
|
91
|
+
/// Called automatically by the JS Digia.register() wrapper on first plugin
|
|
92
|
+
/// registration so that the delegate is populated before any
|
|
93
|
+
/// triggerCampaign / invalidateCampaign calls arrive from JS.
|
|
94
|
+
@objc
|
|
95
|
+
func registerBridge() {
|
|
96
|
+
Task { @MainActor in
|
|
97
|
+
Digia.register(self.rnPlugin)
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// ────────────────────────────────────────────────────────────────────────
|
|
102
|
+
// MARK: - setCurrentScreen
|
|
103
|
+
|
|
104
|
+
@objc
|
|
105
|
+
func setCurrentScreen(_ name: String) {
|
|
106
|
+
// Digia.setCurrentScreen is not yet part of the public iOS API; this is
|
|
107
|
+
// a no-op placeholder that can be activated once it is added.
|
|
108
|
+
// Digia.setCurrentScreen(name)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// ────────────────────────────────────────────────────────────────────────
|
|
112
|
+
// MARK: - triggerCampaign
|
|
113
|
+
|
|
114
|
+
/// Forwards a campaign payload to the native DigiaCEPDelegate.
|
|
115
|
+
///
|
|
116
|
+
/// Called by the JS DigiaDelegate.onCampaignTriggered() when a JS CEP
|
|
117
|
+
/// plugin (e.g. DigiaMoEngagePlugin) delivers a campaign. The delegate
|
|
118
|
+
/// routes it into the SwiftUI overlay for rendering.
|
|
119
|
+
@objc
|
|
120
|
+
func triggerCampaign(
|
|
121
|
+
_ id: String,
|
|
122
|
+
content contentMap: NSDictionary,
|
|
123
|
+
cepContext cepContextMap: NSDictionary
|
|
124
|
+
) {
|
|
125
|
+
let content = buildInAppPayloadContent(from: contentMap)
|
|
126
|
+
let cepContext = (cepContextMap as? [String: String]) ?? [:]
|
|
127
|
+
let payload = InAppPayload(id: id, content: content, cepContext: cepContext)
|
|
128
|
+
|
|
129
|
+
Task { @MainActor in
|
|
130
|
+
guard let delegate = self.rnPlugin.delegate else { return }
|
|
131
|
+
delegate.onCampaignTriggered(payload)
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// ────────────────────────────────────────────────────────────────────────
|
|
136
|
+
// MARK: - invalidateCampaign
|
|
137
|
+
|
|
138
|
+
@objc
|
|
139
|
+
func invalidateCampaign(_ campaignId: String) {
|
|
140
|
+
Task { @MainActor in
|
|
141
|
+
guard let delegate = self.rnPlugin.delegate else { return }
|
|
142
|
+
delegate.onCampaignInvalidated(campaignId)
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// ────────────────────────────────────────────────────────────────────────
|
|
147
|
+
// MARK: - Private helpers
|
|
148
|
+
|
|
149
|
+
private func buildInAppPayloadContent(from map: NSDictionary) -> InAppPayloadContent {
|
|
150
|
+
let type = (map["type"] as? String) ?? "dialog"
|
|
151
|
+
let pk = map["placementKey"] as? String
|
|
152
|
+
let title = map["title"] as? String
|
|
153
|
+
let text = map["text"] as? String
|
|
154
|
+
let viewId = map["viewId"] as? String
|
|
155
|
+
let command = map["command"] as? String
|
|
156
|
+
let screenId = map["screenId"] as? String
|
|
157
|
+
let args: [String: JSONValue] = {
|
|
158
|
+
guard let raw = map["args"] as? [String: Any] else { return [:] }
|
|
159
|
+
return raw.compactMapValues { JSONValue(rawValue: $0) }
|
|
160
|
+
}()
|
|
161
|
+
|
|
162
|
+
return InAppPayloadContent(
|
|
163
|
+
type: type,
|
|
164
|
+
placementKey: pk,
|
|
165
|
+
title: title,
|
|
166
|
+
text: text,
|
|
167
|
+
viewId: viewId,
|
|
168
|
+
command: command,
|
|
169
|
+
args: args,
|
|
170
|
+
screenId: screenId
|
|
171
|
+
)
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// MARK: - JSONValue convenience init from Any
|
|
176
|
+
private extension JSONValue {
|
|
177
|
+
init?(rawValue: Any) {
|
|
178
|
+
switch rawValue {
|
|
179
|
+
case let s as String: self = .string(s)
|
|
180
|
+
case let b as Bool: self = .bool(b)
|
|
181
|
+
case let i as Int: self = .int(i)
|
|
182
|
+
case let d as Double: self = .double(d)
|
|
183
|
+
case let arr as [Any]:
|
|
184
|
+
self = .array(arr.compactMap { JSONValue(rawValue: $0) })
|
|
185
|
+
case let dict as [String: Any]:
|
|
186
|
+
let mapped = dict.compactMapValues { JSONValue(rawValue: $0) }
|
|
187
|
+
self = .object(mapped)
|
|
188
|
+
default:
|
|
189
|
+
return nil
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DigiaSlotViewManager
|
|
3
|
+
*
|
|
4
|
+
* React Native ViewManager that exposes a UIView wrapping DigiaSlot (from the
|
|
5
|
+
* Digia iOS SDK) as the native view behind the JS <DigiaSlotView> component.
|
|
6
|
+
*
|
|
7
|
+
* DigiaSlot is a SwiftUI view, so it is bridged into UIKit via a
|
|
8
|
+
* UIHostingController. The placementKey prop is forwarded to the SwiftUI
|
|
9
|
+
* view via a StateObject/ObservableObject binding.
|
|
10
|
+
*
|
|
11
|
+
* Supported JS props:
|
|
12
|
+
* - `placementKey` (String) — matches the placement key set in the Digia dashboard.
|
|
13
|
+
*/
|
|
14
|
+
import SwiftUI
|
|
15
|
+
import React
|
|
16
|
+
import DigiaEngage
|
|
17
|
+
|
|
18
|
+
@objc(DigiaSlotView)
|
|
19
|
+
final class DigiaSlotViewManager: RCTViewManager {
|
|
20
|
+
|
|
21
|
+
override static func requiresMainQueueSetup() -> Bool { true }
|
|
22
|
+
|
|
23
|
+
override func view() -> UIView! {
|
|
24
|
+
return DigiaSlotUIView()
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// ── prop setter wired by ObjC runtime via RCT_EXPORT_VIEW_PROPERTY ────────
|
|
28
|
+
// The @objc name must match the RCT_EXPORT_VIEW_PROPERTY in the .m file.
|
|
29
|
+
@objc func setPlacementKey(_ placementKey: String, forView view: DigiaSlotUIView) {
|
|
30
|
+
view.placementKey = placementKey
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// MARK: - DigiaSlotUIView
|
|
35
|
+
|
|
36
|
+
/// UIView container that embeds DigiaSlot<EmptyView> in a UIHostingController.
|
|
37
|
+
/// Re-creates the SwiftUI view when placementKey changes.
|
|
38
|
+
final class DigiaSlotUIView: UIView {
|
|
39
|
+
|
|
40
|
+
@objc var placementKey: String = "" {
|
|
41
|
+
didSet {
|
|
42
|
+
guard placementKey != oldValue else { return }
|
|
43
|
+
remount()
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
private var hostingController: UIHostingController<DigiaSlotWrapperView>?
|
|
48
|
+
|
|
49
|
+
override func didMoveToWindow() {
|
|
50
|
+
super.didMoveToWindow()
|
|
51
|
+
if window != nil {
|
|
52
|
+
if hostingController == nil { remount() }
|
|
53
|
+
} else {
|
|
54
|
+
teardown()
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
private func remount() {
|
|
59
|
+
teardown()
|
|
60
|
+
guard window != nil, !placementKey.isEmpty else { return }
|
|
61
|
+
guard let parentVC = parentViewController() else { return }
|
|
62
|
+
|
|
63
|
+
let swiftUIView = DigiaSlotWrapperView(placementKey: placementKey)
|
|
64
|
+
let hc = UIHostingController(rootView: swiftUIView)
|
|
65
|
+
hc.view.translatesAutoresizingMaskIntoConstraints = false
|
|
66
|
+
hc.view.backgroundColor = .clear
|
|
67
|
+
|
|
68
|
+
parentVC.addChild(hc)
|
|
69
|
+
addSubview(hc.view)
|
|
70
|
+
hc.didMove(toParent: parentVC)
|
|
71
|
+
|
|
72
|
+
NSLayoutConstraint.activate([
|
|
73
|
+
hc.view.leadingAnchor.constraint(equalTo: leadingAnchor),
|
|
74
|
+
hc.view.trailingAnchor.constraint(equalTo: trailingAnchor),
|
|
75
|
+
hc.view.topAnchor.constraint(equalTo: topAnchor),
|
|
76
|
+
hc.view.bottomAnchor.constraint(equalTo: bottomAnchor),
|
|
77
|
+
])
|
|
78
|
+
|
|
79
|
+
hostingController = hc
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
private func teardown() {
|
|
83
|
+
hostingController?.willMove(toParent: nil)
|
|
84
|
+
hostingController?.view.removeFromSuperview()
|
|
85
|
+
hostingController?.removeFromParent()
|
|
86
|
+
hostingController = nil
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
private func parentViewController() -> UIViewController? {
|
|
90
|
+
var responder: UIResponder? = self
|
|
91
|
+
while let r = responder {
|
|
92
|
+
if let vc = r as? UIViewController { return vc }
|
|
93
|
+
responder = r.next
|
|
94
|
+
}
|
|
95
|
+
return nil
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// MARK: - SwiftUI wrapper
|
|
100
|
+
|
|
101
|
+
private struct DigiaSlotWrapperView: View {
|
|
102
|
+
let placementKey: String
|
|
103
|
+
|
|
104
|
+
var body: some View {
|
|
105
|
+
DigiaSlot(placementKey)
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RNEventBridgePlugin
|
|
3
|
+
*
|
|
4
|
+
* Implements DigiaCEPPlugin so it can be registered with the native iOS Digia
|
|
5
|
+
* SDK via Digia.register(). It acts as the bridge between the native SDK's
|
|
6
|
+
* DigiaCEPDelegate and the JS layer.
|
|
7
|
+
*
|
|
8
|
+
* Lifecycle
|
|
9
|
+
* ─────────
|
|
10
|
+
* 1. JS calls Digia.register() → native registerBridge() → this plugin is
|
|
11
|
+
* registered with the native SDK via Digia.register(rnPlugin).
|
|
12
|
+
* 2. The SDK calls setup(delegate:) storing the delegate reference.
|
|
13
|
+
* 3. When a JS CEP plugin delivers a campaign via onCampaignTriggered(),
|
|
14
|
+
* the JS side calls triggerCampaign() which forwards here via DigiaModule.
|
|
15
|
+
* 4. Overlay lifecycle events (impressed / clicked / dismissed) travel back to
|
|
16
|
+
* JS as DeviceEventEmitter events.
|
|
17
|
+
*/
|
|
18
|
+
import Foundation
|
|
19
|
+
import React
|
|
20
|
+
import DigiaEngage
|
|
21
|
+
|
|
22
|
+
@objc
|
|
23
|
+
internal final class RNEventBridgePlugin: NSObject, DigiaCEPPlugin {
|
|
24
|
+
|
|
25
|
+
let identifier = "com.digia.rn.bridge"
|
|
26
|
+
|
|
27
|
+
/// Populated by the SDK when registered. Used to forward JS-side campaigns
|
|
28
|
+
/// into the native overlay rendering pipeline.
|
|
29
|
+
private(set) weak var delegate: DigiaCEPDelegate?
|
|
30
|
+
|
|
31
|
+
private weak var eventEmitter: RCTEventEmitter?
|
|
32
|
+
|
|
33
|
+
init(eventEmitter: RCTEventEmitter?) {
|
|
34
|
+
self.eventEmitter = eventEmitter
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// MARK: - DigiaCEPPlugin
|
|
38
|
+
|
|
39
|
+
func setup(delegate: DigiaCEPDelegate) {
|
|
40
|
+
self.delegate = delegate
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
func notifyEvent(_ event: DigiaExperienceEvent, payload: InAppPayload) {
|
|
44
|
+
let eventName: String
|
|
45
|
+
switch event {
|
|
46
|
+
case .impressed:
|
|
47
|
+
eventName = "digia_experience_impressed"
|
|
48
|
+
case .clicked:
|
|
49
|
+
eventName = "digia_experience_clicked"
|
|
50
|
+
case .dismissed:
|
|
51
|
+
eventName = "digia_experience_dismissed"
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
let body: [String: Any] = [
|
|
55
|
+
"id": payload.id,
|
|
56
|
+
"type": payload.content.type,
|
|
57
|
+
]
|
|
58
|
+
eventEmitter?.sendEvent(withName: eventName, body: body)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
func healthCheck() -> DiagnosticReport {
|
|
62
|
+
return DiagnosticReport(
|
|
63
|
+
isHealthy: delegate != nil,
|
|
64
|
+
issue: delegate == nil ? "No delegate set" : nil,
|
|
65
|
+
resolution: delegate == nil ? "Call registerBridge() before triggerCampaign()" : nil
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
func teardown() {
|
|
70
|
+
delegate = nil
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -36,31 +36,33 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
|
|
|
36
36
|
*
|
|
37
37
|
* On Android this mounts a Jetpack Compose `DigiaHost` composable that
|
|
38
38
|
* manages dialog + bottom-sheet presentation triggered by CEP plugins.
|
|
39
|
-
* On iOS
|
|
39
|
+
* On iOS this mounts a SwiftUI `DigiaHost` via UIHostingController that
|
|
40
|
+
* manages the same overlay layer above React Native content.
|
|
40
41
|
* ─────────────────────────────────────────────────────────────────────────────
|
|
41
42
|
*/
|
|
42
43
|
|
|
43
44
|
// requireNativeComponent expects a plain ViewStyle, not StyleProp.
|
|
44
45
|
|
|
45
46
|
// Fabric (New Architecture) resolves view configs lazily — no UIManager
|
|
46
|
-
// guard needed. requireNativeComponent is called unconditionally on Android.
|
|
47
|
-
const NativeDigiaHostView = _reactNative.Platform.OS === 'android' ? (0, _reactNative.requireNativeComponent)('DigiaHostView') : null;
|
|
47
|
+
// guard needed. requireNativeComponent is called unconditionally on iOS and Android.
|
|
48
|
+
const NativeDigiaHostView = _reactNative.Platform.OS === 'android' || _reactNative.Platform.OS === 'ios' ? (0, _reactNative.requireNativeComponent)('DigiaHostView') : null;
|
|
48
49
|
|
|
49
50
|
// ── DigiaHostView ─────────────────────────────────────────────────────────────
|
|
50
51
|
|
|
51
52
|
function DigiaHostView({
|
|
52
53
|
style
|
|
53
54
|
}) {
|
|
54
|
-
if (_reactNative.Platform.OS === 'android' && NativeDigiaHostView) {
|
|
55
|
-
// The native Compose
|
|
56
|
-
// float above the view hierarchy on their
|
|
57
|
-
// needs to be mounted in the tree, not take up
|
|
55
|
+
if ((_reactNative.Platform.OS === 'android' || _reactNative.Platform.OS === 'ios') && NativeDigiaHostView) {
|
|
56
|
+
// The native DigiaHost (Compose on Android, SwiftUI on iOS) renders
|
|
57
|
+
// dialogs / bottom sheets that float above the view hierarchy on their
|
|
58
|
+
// own — the host view only needs to be mounted in the tree, not take up
|
|
59
|
+
// any screen space.
|
|
58
60
|
return /*#__PURE__*/_react.default.createElement(NativeDigiaHostView, {
|
|
59
61
|
style: _reactNative.StyleSheet.flatten([styles.host, style])
|
|
60
62
|
});
|
|
61
63
|
}
|
|
62
64
|
|
|
63
|
-
//
|
|
65
|
+
// Other platforms: no-op.
|
|
64
66
|
return null;
|
|
65
67
|
}
|
|
66
68
|
const styles = _reactNative.StyleSheet.create({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_react","_interopRequireDefault","require","_reactNative","e","__esModule","default","NativeDigiaHostView","Platform","OS","requireNativeComponent","DigiaHostView","style","createElement","StyleSheet","flatten","styles","host","create","width","height","overflow"],"sourceRoot":"../../src","sources":["DigiaHostView.tsx"],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"names":["_react","_interopRequireDefault","require","_reactNative","e","__esModule","default","NativeDigiaHostView","Platform","OS","requireNativeComponent","DigiaHostView","style","createElement","StyleSheet","flatten","styles","host","create","width","height","overflow"],"sourceRoot":"../../src","sources":["DigiaHostView.tsx"],"mappings":";;;;;;AAkCA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,YAAA,GAAAD,OAAA;AAMsB,SAAAD,uBAAAG,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAzCtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAeA;;AAKA;AACA;AACA,MAAMG,mBAAmB,GACrBC,qBAAQ,CAACC,EAAE,KAAK,SAAS,IAAID,qBAAQ,CAACC,EAAE,KAAK,KAAK,GAC5C,IAAAC,mCAAsB,EAA2B,eAAe,CAAC,GACjE,IAAI;;AAEd;;AAEO,SAASC,aAAaA,CAAC;EAAEC;AAA0B,CAAC,EAAE;EACzD,IAAI,CAACJ,qBAAQ,CAACC,EAAE,KAAK,SAAS,IAAID,qBAAQ,CAACC,EAAE,KAAK,KAAK,KAAKF,mBAAmB,EAAE;IAC7E;IACA;IACA;IACA;IACA,oBACIP,MAAA,CAAAM,OAAA,CAAAO,aAAA,CAACN,mBAAmB;MAChBK,KAAK,EAAEE,uBAAU,CAACC,OAAO,CAAC,CAACC,MAAM,CAACC,IAAI,EAAEL,KAAK,CAAC;IAAE,CACnD,CAAC;EAEV;;EAEA;EACA,OAAO,IAAI;AACf;AAEA,MAAMI,MAAM,GAAGF,uBAAU,CAACI,MAAM,CAAC;EAC7BD,IAAI,EAAE;IACFE,KAAK,EAAE,CAAC;IACRC,MAAM,EAAE,CAAC;IACTC,QAAQ,EAAE;EACd;AACJ,CAAC,CAAC","ignoreList":[]}
|
|
@@ -15,7 +15,8 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
|
|
|
15
15
|
*
|
|
16
16
|
* On Android this mounts a Jetpack Compose `DigiaSlot` composable that
|
|
17
17
|
* observes the slot payload for the given placement key and renders the
|
|
18
|
-
* matching campaign component. On iOS
|
|
18
|
+
* matching campaign component. On iOS this mounts the equivalent SwiftUI
|
|
19
|
+
* `DigiaSlot` view via UIHostingController.
|
|
19
20
|
*
|
|
20
21
|
* ─── Usage ───────────────────────────────────────────────────────────────────
|
|
21
22
|
* ```tsx
|
|
@@ -51,8 +52,8 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
|
|
|
51
52
|
*/
|
|
52
53
|
|
|
53
54
|
// Fabric (New Architecture) resolves view configs lazily — no UIManager
|
|
54
|
-
// guard needed. requireNativeComponent is called unconditionally on Android.
|
|
55
|
-
const NativeDigiaSlotView = _reactNative.Platform.OS === 'android' ? (0, _reactNative.requireNativeComponent)('DigiaSlotView') : null;
|
|
55
|
+
// guard needed. requireNativeComponent is called unconditionally on iOS and Android.
|
|
56
|
+
const NativeDigiaSlotView = _reactNative.Platform.OS === 'android' || _reactNative.Platform.OS === 'ios' ? (0, _reactNative.requireNativeComponent)('DigiaSlotView') : null;
|
|
56
57
|
|
|
57
58
|
// ── DigiaSlotView ─────────────────────────────────────────────────────────────
|
|
58
59
|
|
|
@@ -60,14 +61,14 @@ function DigiaSlotView({
|
|
|
60
61
|
placementKey,
|
|
61
62
|
style
|
|
62
63
|
}) {
|
|
63
|
-
if (_reactNative.Platform.OS === 'android' && NativeDigiaSlotView) {
|
|
64
|
+
if ((_reactNative.Platform.OS === 'android' || _reactNative.Platform.OS === 'ios') && NativeDigiaSlotView) {
|
|
64
65
|
return /*#__PURE__*/_react.default.createElement(NativeDigiaSlotView, {
|
|
65
66
|
placementKey: placementKey,
|
|
66
67
|
style: style
|
|
67
68
|
});
|
|
68
69
|
}
|
|
69
70
|
|
|
70
|
-
//
|
|
71
|
+
// Other platforms: not yet implemented — render nothing.
|
|
71
72
|
return null;
|
|
72
73
|
}
|
|
73
74
|
//# sourceMappingURL=DigiaSlotView.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_react","_interopRequireDefault","require","_reactNative","e","__esModule","default","NativeDigiaSlotView","Platform","OS","requireNativeComponent","DigiaSlotView","placementKey","style","createElement"],"sourceRoot":"../../src","sources":["DigiaSlotView.tsx"],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"names":["_react","_interopRequireDefault","require","_reactNative","e","__esModule","default","NativeDigiaSlotView","Platform","OS","requireNativeComponent","DigiaSlotView","placementKey","style","createElement"],"sourceRoot":"../../src","sources":["DigiaSlotView.tsx"],"mappings":";;;;;;AA4CA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,YAAA,GAAAD,OAAA;AAKsB,SAAAD,uBAAAG,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAlDtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAgBA;AACA;AACA,MAAMG,mBAAmB,GACrBC,qBAAQ,CAACC,EAAE,KAAK,SAAS,IAAID,qBAAQ,CAACC,EAAE,KAAK,KAAK,GAC5C,IAAAC,mCAAsB,EAAqB,eAAe,CAAC,GAC3D,IAAI;;AAEd;;AAEO,SAASC,aAAaA,CAAC;EAAEC,YAAY;EAAEC;AAA0B,CAAC,EAAE;EACvE,IAAI,CAACL,qBAAQ,CAACC,EAAE,KAAK,SAAS,IAAID,qBAAQ,CAACC,EAAE,KAAK,KAAK,KAAKF,mBAAmB,EAAE;IAC7E,oBACIP,MAAA,CAAAM,OAAA,CAAAQ,aAAA,CAACP,mBAAmB;MAChBK,YAAY,EAAEA,YAAa;MAC3BC,KAAK,EAAEA;IAAM,CAChB,CAAC;EAEV;;EAEA;EACA,OAAO,IAAI;AACf","ignoreList":[]}
|
|
@@ -27,7 +27,8 @@
|
|
|
27
27
|
*
|
|
28
28
|
* On Android this mounts a Jetpack Compose `DigiaHost` composable that
|
|
29
29
|
* manages dialog + bottom-sheet presentation triggered by CEP plugins.
|
|
30
|
-
* On iOS
|
|
30
|
+
* On iOS this mounts a SwiftUI `DigiaHost` via UIHostingController that
|
|
31
|
+
* manages the same overlay layer above React Native content.
|
|
31
32
|
* ─────────────────────────────────────────────────────────────────────────────
|
|
32
33
|
*/
|
|
33
34
|
|
|
@@ -37,24 +38,25 @@ import { Platform, StyleSheet, requireNativeComponent } from 'react-native';
|
|
|
37
38
|
// requireNativeComponent expects a plain ViewStyle, not StyleProp.
|
|
38
39
|
|
|
39
40
|
// Fabric (New Architecture) resolves view configs lazily — no UIManager
|
|
40
|
-
// guard needed. requireNativeComponent is called unconditionally on Android.
|
|
41
|
-
const NativeDigiaHostView = Platform.OS === 'android' ? requireNativeComponent('DigiaHostView') : null;
|
|
41
|
+
// guard needed. requireNativeComponent is called unconditionally on iOS and Android.
|
|
42
|
+
const NativeDigiaHostView = Platform.OS === 'android' || Platform.OS === 'ios' ? requireNativeComponent('DigiaHostView') : null;
|
|
42
43
|
|
|
43
44
|
// ── DigiaHostView ─────────────────────────────────────────────────────────────
|
|
44
45
|
|
|
45
46
|
export function DigiaHostView({
|
|
46
47
|
style
|
|
47
48
|
}) {
|
|
48
|
-
if (Platform.OS === 'android' && NativeDigiaHostView) {
|
|
49
|
-
// The native Compose
|
|
50
|
-
// float above the view hierarchy on their
|
|
51
|
-
// needs to be mounted in the tree, not take up
|
|
49
|
+
if ((Platform.OS === 'android' || Platform.OS === 'ios') && NativeDigiaHostView) {
|
|
50
|
+
// The native DigiaHost (Compose on Android, SwiftUI on iOS) renders
|
|
51
|
+
// dialogs / bottom sheets that float above the view hierarchy on their
|
|
52
|
+
// own — the host view only needs to be mounted in the tree, not take up
|
|
53
|
+
// any screen space.
|
|
52
54
|
return /*#__PURE__*/React.createElement(NativeDigiaHostView, {
|
|
53
55
|
style: StyleSheet.flatten([styles.host, style])
|
|
54
56
|
});
|
|
55
57
|
}
|
|
56
58
|
|
|
57
|
-
//
|
|
59
|
+
// Other platforms: no-op.
|
|
58
60
|
return null;
|
|
59
61
|
}
|
|
60
62
|
const styles = StyleSheet.create({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["React","Platform","StyleSheet","requireNativeComponent","NativeDigiaHostView","OS","DigiaHostView","style","createElement","flatten","styles","host","create","width","height","overflow"],"sourceRoot":"../../src","sources":["DigiaHostView.tsx"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,OAAOA,KAAK,MAAM,OAAO;AACzB,SACIC,QAAQ,EACRC,UAAU,EACVC,sBAAsB,QAGnB,cAAc;;AAMrB;;AAKA;AACA;AACA,MAAMC,mBAAmB,GACrBH,QAAQ,CAACI,EAAE,KAAK,SAAS,
|
|
1
|
+
{"version":3,"names":["React","Platform","StyleSheet","requireNativeComponent","NativeDigiaHostView","OS","DigiaHostView","style","createElement","flatten","styles","host","create","width","height","overflow"],"sourceRoot":"../../src","sources":["DigiaHostView.tsx"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,OAAOA,KAAK,MAAM,OAAO;AACzB,SACIC,QAAQ,EACRC,UAAU,EACVC,sBAAsB,QAGnB,cAAc;;AAMrB;;AAKA;AACA;AACA,MAAMC,mBAAmB,GACrBH,QAAQ,CAACI,EAAE,KAAK,SAAS,IAAIJ,QAAQ,CAACI,EAAE,KAAK,KAAK,GAC5CF,sBAAsB,CAA2B,eAAe,CAAC,GACjE,IAAI;;AAEd;;AAEA,OAAO,SAASG,aAAaA,CAAC;EAAEC;AAA0B,CAAC,EAAE;EACzD,IAAI,CAACN,QAAQ,CAACI,EAAE,KAAK,SAAS,IAAIJ,QAAQ,CAACI,EAAE,KAAK,KAAK,KAAKD,mBAAmB,EAAE;IAC7E;IACA;IACA;IACA;IACA,oBACIJ,KAAA,CAAAQ,aAAA,CAACJ,mBAAmB;MAChBG,KAAK,EAAEL,UAAU,CAACO,OAAO,CAAC,CAACC,MAAM,CAACC,IAAI,EAAEJ,KAAK,CAAC;IAAE,CACnD,CAAC;EAEV;;EAEA;EACA,OAAO,IAAI;AACf;AAEA,MAAMG,MAAM,GAAGR,UAAU,CAACU,MAAM,CAAC;EAC7BD,IAAI,EAAE;IACFE,KAAK,EAAE,CAAC;IACRC,MAAM,EAAE,CAAC;IACTC,QAAQ,EAAE;EACd;AACJ,CAAC,CAAC","ignoreList":[]}
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
*
|
|
7
7
|
* On Android this mounts a Jetpack Compose `DigiaSlot` composable that
|
|
8
8
|
* observes the slot payload for the given placement key and renders the
|
|
9
|
-
* matching campaign component. On iOS
|
|
9
|
+
* matching campaign component. On iOS this mounts the equivalent SwiftUI
|
|
10
|
+
* `DigiaSlot` view via UIHostingController.
|
|
10
11
|
*
|
|
11
12
|
* ─── Usage ───────────────────────────────────────────────────────────────────
|
|
12
13
|
* ```tsx
|
|
@@ -44,8 +45,8 @@
|
|
|
44
45
|
import React from 'react';
|
|
45
46
|
import { Platform, requireNativeComponent } from 'react-native';
|
|
46
47
|
// Fabric (New Architecture) resolves view configs lazily — no UIManager
|
|
47
|
-
// guard needed. requireNativeComponent is called unconditionally on Android.
|
|
48
|
-
const NativeDigiaSlotView = Platform.OS === 'android' ? requireNativeComponent('DigiaSlotView') : null;
|
|
48
|
+
// guard needed. requireNativeComponent is called unconditionally on iOS and Android.
|
|
49
|
+
const NativeDigiaSlotView = Platform.OS === 'android' || Platform.OS === 'ios' ? requireNativeComponent('DigiaSlotView') : null;
|
|
49
50
|
|
|
50
51
|
// ── DigiaSlotView ─────────────────────────────────────────────────────────────
|
|
51
52
|
|
|
@@ -53,14 +54,14 @@ export function DigiaSlotView({
|
|
|
53
54
|
placementKey,
|
|
54
55
|
style
|
|
55
56
|
}) {
|
|
56
|
-
if (Platform.OS === 'android' && NativeDigiaSlotView) {
|
|
57
|
+
if ((Platform.OS === 'android' || Platform.OS === 'ios') && NativeDigiaSlotView) {
|
|
57
58
|
return /*#__PURE__*/React.createElement(NativeDigiaSlotView, {
|
|
58
59
|
placementKey: placementKey,
|
|
59
60
|
style: style
|
|
60
61
|
});
|
|
61
62
|
}
|
|
62
63
|
|
|
63
|
-
//
|
|
64
|
+
// Other platforms: not yet implemented — render nothing.
|
|
64
65
|
return null;
|
|
65
66
|
}
|
|
66
67
|
//# sourceMappingURL=DigiaSlotView.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["React","Platform","requireNativeComponent","NativeDigiaSlotView","OS","DigiaSlotView","placementKey","style","createElement"],"sourceRoot":"../../src","sources":["DigiaSlotView.tsx"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,OAAOA,KAAK,MAAM,OAAO;AACzB,SACIC,QAAQ,EACRC,sBAAsB,QAGnB,cAAc;AAQrB;AACA;AACA,MAAMC,mBAAmB,GACrBF,QAAQ,CAACG,EAAE,KAAK,SAAS,
|
|
1
|
+
{"version":3,"names":["React","Platform","requireNativeComponent","NativeDigiaSlotView","OS","DigiaSlotView","placementKey","style","createElement"],"sourceRoot":"../../src","sources":["DigiaSlotView.tsx"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,OAAOA,KAAK,MAAM,OAAO;AACzB,SACIC,QAAQ,EACRC,sBAAsB,QAGnB,cAAc;AAQrB;AACA;AACA,MAAMC,mBAAmB,GACrBF,QAAQ,CAACG,EAAE,KAAK,SAAS,IAAIH,QAAQ,CAACG,EAAE,KAAK,KAAK,GAC5CF,sBAAsB,CAAqB,eAAe,CAAC,GAC3D,IAAI;;AAEd;;AAEA,OAAO,SAASG,aAAaA,CAAC;EAAEC,YAAY;EAAEC;AAA0B,CAAC,EAAE;EACvE,IAAI,CAACN,QAAQ,CAACG,EAAE,KAAK,SAAS,IAAIH,QAAQ,CAACG,EAAE,KAAK,KAAK,KAAKD,mBAAmB,EAAE;IAC7E,oBACIH,KAAA,CAAAQ,aAAA,CAACL,mBAAmB;MAChBG,YAAY,EAAEA,YAAa;MAC3BC,KAAK,EAAEA;IAAM,CAChB,CAAC;EAEV;;EAEA;EACA,OAAO,IAAI;AACf","ignoreList":[]}
|
|
@@ -27,7 +27,8 @@
|
|
|
27
27
|
*
|
|
28
28
|
* On Android this mounts a Jetpack Compose `DigiaHost` composable that
|
|
29
29
|
* manages dialog + bottom-sheet presentation triggered by CEP plugins.
|
|
30
|
-
* On iOS
|
|
30
|
+
* On iOS this mounts a SwiftUI `DigiaHost` via UIHostingController that
|
|
31
|
+
* manages the same overlay layer above React Native content.
|
|
31
32
|
* ─────────────────────────────────────────────────────────────────────────────
|
|
32
33
|
*/
|
|
33
34
|
import React from 'react';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DigiaHostView.d.ts","sourceRoot":"","sources":["../../src/DigiaHostView.tsx"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"DigiaHostView.d.ts","sourceRoot":"","sources":["../../src/DigiaHostView.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAIH,KAAK,SAAS,EACd,KAAK,SAAS,EACjB,MAAM,cAAc,CAAC;AAEtB,UAAU,kBAAkB;IACxB,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAChC;AAgBD,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,EAAE,kBAAkB,4BAe1D"}
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
*
|
|
7
7
|
* On Android this mounts a Jetpack Compose `DigiaSlot` composable that
|
|
8
8
|
* observes the slot payload for the given placement key and renders the
|
|
9
|
-
* matching campaign component. On iOS
|
|
9
|
+
* matching campaign component. On iOS this mounts the equivalent SwiftUI
|
|
10
|
+
* `DigiaSlot` view via UIHostingController.
|
|
10
11
|
*
|
|
11
12
|
* ─── Usage ───────────────────────────────────────────────────────────────────
|
|
12
13
|
* ```tsx
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DigiaSlotView.d.ts","sourceRoot":"","sources":["../../src/DigiaSlotView.tsx"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"DigiaSlotView.d.ts","sourceRoot":"","sources":["../../src/DigiaSlotView.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAGH,KAAK,SAAS,EACd,KAAK,SAAS,EACjB,MAAM,cAAc,CAAC;AAEtB,UAAU,kBAAkB;IACxB,oEAAoE;IACpE,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAChC;AAWD,wBAAgB,aAAa,CAAC,EAAE,YAAY,EAAE,KAAK,EAAE,EAAE,kBAAkB,4BAYxE"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@digia-engage/core",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.5",
|
|
4
4
|
"description": "React Native bridge for Digia Engage – renders native Android Compose UI inside React Native apps",
|
|
5
5
|
"main": "lib/commonjs/index",
|
|
6
6
|
"module": "lib/module/index",
|
package/src/DigiaHostView.tsx
CHANGED
|
@@ -27,7 +27,8 @@
|
|
|
27
27
|
*
|
|
28
28
|
* On Android this mounts a Jetpack Compose `DigiaHost` composable that
|
|
29
29
|
* manages dialog + bottom-sheet presentation triggered by CEP plugins.
|
|
30
|
-
* On iOS
|
|
30
|
+
* On iOS this mounts a SwiftUI `DigiaHost` via UIHostingController that
|
|
31
|
+
* manages the same overlay layer above React Native content.
|
|
31
32
|
* ─────────────────────────────────────────────────────────────────────────────
|
|
32
33
|
*/
|
|
33
34
|
|
|
@@ -50,19 +51,20 @@ interface NativeDigiaHostViewProps {
|
|
|
50
51
|
}
|
|
51
52
|
|
|
52
53
|
// Fabric (New Architecture) resolves view configs lazily — no UIManager
|
|
53
|
-
// guard needed. requireNativeComponent is called unconditionally on Android.
|
|
54
|
+
// guard needed. requireNativeComponent is called unconditionally on iOS and Android.
|
|
54
55
|
const NativeDigiaHostView =
|
|
55
|
-
Platform.OS === 'android'
|
|
56
|
+
Platform.OS === 'android' || Platform.OS === 'ios'
|
|
56
57
|
? requireNativeComponent<NativeDigiaHostViewProps>('DigiaHostView')
|
|
57
58
|
: null;
|
|
58
59
|
|
|
59
60
|
// ── DigiaHostView ─────────────────────────────────────────────────────────────
|
|
60
61
|
|
|
61
62
|
export function DigiaHostView({ style }: DigiaHostViewProps) {
|
|
62
|
-
if (Platform.OS === 'android' && NativeDigiaHostView) {
|
|
63
|
-
// The native Compose
|
|
64
|
-
// float above the view hierarchy on their
|
|
65
|
-
// needs to be mounted in the tree, not take up
|
|
63
|
+
if ((Platform.OS === 'android' || Platform.OS === 'ios') && NativeDigiaHostView) {
|
|
64
|
+
// The native DigiaHost (Compose on Android, SwiftUI on iOS) renders
|
|
65
|
+
// dialogs / bottom sheets that float above the view hierarchy on their
|
|
66
|
+
// own — the host view only needs to be mounted in the tree, not take up
|
|
67
|
+
// any screen space.
|
|
66
68
|
return (
|
|
67
69
|
<NativeDigiaHostView
|
|
68
70
|
style={StyleSheet.flatten([styles.host, style])}
|
|
@@ -70,7 +72,7 @@ export function DigiaHostView({ style }: DigiaHostViewProps) {
|
|
|
70
72
|
);
|
|
71
73
|
}
|
|
72
74
|
|
|
73
|
-
//
|
|
75
|
+
// Other platforms: no-op.
|
|
74
76
|
return null;
|
|
75
77
|
}
|
|
76
78
|
|
package/src/DigiaSlotView.tsx
CHANGED
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
*
|
|
7
7
|
* On Android this mounts a Jetpack Compose `DigiaSlot` composable that
|
|
8
8
|
* observes the slot payload for the given placement key and renders the
|
|
9
|
-
* matching campaign component. On iOS
|
|
9
|
+
* matching campaign component. On iOS this mounts the equivalent SwiftUI
|
|
10
|
+
* `DigiaSlot` view via UIHostingController.
|
|
10
11
|
*
|
|
11
12
|
* ─── Usage ───────────────────────────────────────────────────────────────────
|
|
12
13
|
* ```tsx
|
|
@@ -56,16 +57,16 @@ interface DigiaSlotViewProps {
|
|
|
56
57
|
}
|
|
57
58
|
|
|
58
59
|
// Fabric (New Architecture) resolves view configs lazily — no UIManager
|
|
59
|
-
// guard needed. requireNativeComponent is called unconditionally on Android.
|
|
60
|
+
// guard needed. requireNativeComponent is called unconditionally on iOS and Android.
|
|
60
61
|
const NativeDigiaSlotView =
|
|
61
|
-
Platform.OS === 'android'
|
|
62
|
+
Platform.OS === 'android' || Platform.OS === 'ios'
|
|
62
63
|
? requireNativeComponent<DigiaSlotViewProps>('DigiaSlotView')
|
|
63
64
|
: null;
|
|
64
65
|
|
|
65
66
|
// ── DigiaSlotView ─────────────────────────────────────────────────────────────
|
|
66
67
|
|
|
67
68
|
export function DigiaSlotView({ placementKey, style }: DigiaSlotViewProps) {
|
|
68
|
-
if (Platform.OS === 'android' && NativeDigiaSlotView) {
|
|
69
|
+
if ((Platform.OS === 'android' || Platform.OS === 'ios') && NativeDigiaSlotView) {
|
|
69
70
|
return (
|
|
70
71
|
<NativeDigiaSlotView
|
|
71
72
|
placementKey={placementKey}
|
|
@@ -74,6 +75,6 @@ export function DigiaSlotView({ placementKey, style }: DigiaSlotViewProps) {
|
|
|
74
75
|
);
|
|
75
76
|
}
|
|
76
77
|
|
|
77
|
-
//
|
|
78
|
+
// Other platforms: not yet implemented — render nothing.
|
|
78
79
|
return null;
|
|
79
80
|
}
|