@digia-engage/core 1.1.1 → 2.0.0-rc.1
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/README.md +134 -51
- package/android/build.gradle +2 -2
- package/android/src/main/java/com/digia/engage/rn/DigiaModule.kt +52 -8
- package/android/src/main/java/com/digia/engage/rn/DigiaSlotViewManager.kt +6 -2
- package/android/src/main/java/com/digia/engage/rn/DigiaViewManager.kt +1 -0
- package/ios/DigiaEngageModule.m +7 -1
- package/ios/DigiaHostViewManager.swift +20 -20
- package/ios/DigiaModule.swift +8 -4
- package/lib/commonjs/Digia.js +301 -3
- package/lib/commonjs/Digia.js.map +1 -1
- package/lib/commonjs/DigiaGuideController.js +59 -0
- package/lib/commonjs/DigiaGuideController.js.map +1 -0
- package/lib/commonjs/DigiaHealthReporter.js +45 -0
- package/lib/commonjs/DigiaHealthReporter.js.map +1 -0
- package/lib/commonjs/DigiaProvider.js +1079 -0
- package/lib/commonjs/DigiaProvider.js.map +1 -0
- package/lib/commonjs/DigiaSlotView.js +18 -3
- package/lib/commonjs/DigiaSlotView.js.map +1 -1
- package/lib/commonjs/NativeDigiaEngage.js +14 -8
- package/lib/commonjs/NativeDigiaEngage.js.map +1 -1
- package/lib/commonjs/actionHandler.js +316 -0
- package/lib/commonjs/actionHandler.js.map +1 -0
- package/lib/commonjs/defaultInAppBrowser.js +31 -0
- package/lib/commonjs/defaultInAppBrowser.js.map +1 -0
- package/lib/commonjs/digiaAnchorRegistry.js +32 -0
- package/lib/commonjs/digiaAnchorRegistry.js.map +1 -0
- package/lib/commonjs/index.js +7 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/templateTypes.js +2 -0
- package/lib/commonjs/templateTypes.js.map +1 -0
- package/lib/module/Digia.js +301 -3
- package/lib/module/Digia.js.map +1 -1
- package/lib/module/DigiaGuideController.js +53 -0
- package/lib/module/DigiaGuideController.js.map +1 -0
- package/lib/module/DigiaHealthReporter.js +38 -0
- package/lib/module/DigiaHealthReporter.js.map +1 -0
- package/lib/module/DigiaProvider.js +1072 -0
- package/lib/module/DigiaProvider.js.map +1 -0
- package/lib/module/DigiaSlotView.js +20 -5
- package/lib/module/DigiaSlotView.js.map +1 -1
- package/lib/module/NativeDigiaEngage.js +14 -8
- package/lib/module/NativeDigiaEngage.js.map +1 -1
- package/lib/module/actionHandler.js +311 -0
- package/lib/module/actionHandler.js.map +1 -0
- package/lib/module/defaultInAppBrowser.js +25 -0
- package/lib/module/defaultInAppBrowser.js.map +1 -0
- package/lib/module/digiaAnchorRegistry.js +26 -0
- package/lib/module/digiaAnchorRegistry.js.map +1 -0
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/templateTypes.js +2 -0
- package/lib/module/templateTypes.js.map +1 -0
- package/lib/typescript/Digia.d.ts +29 -2
- package/lib/typescript/Digia.d.ts.map +1 -1
- package/lib/typescript/DigiaGuideController.d.ts +30 -0
- package/lib/typescript/DigiaGuideController.d.ts.map +1 -0
- package/lib/typescript/DigiaHealthReporter.d.ts +24 -0
- package/lib/typescript/DigiaHealthReporter.d.ts.map +1 -0
- package/lib/typescript/DigiaProvider.d.ts +3 -0
- package/lib/typescript/DigiaProvider.d.ts.map +1 -0
- package/lib/typescript/DigiaSlotView.d.ts.map +1 -1
- package/lib/typescript/NativeDigiaEngage.d.ts +10 -6
- package/lib/typescript/NativeDigiaEngage.d.ts.map +1 -1
- package/lib/typescript/actionHandler.d.ts +20 -0
- package/lib/typescript/actionHandler.d.ts.map +1 -0
- package/lib/typescript/defaultInAppBrowser.d.ts +3 -0
- package/lib/typescript/defaultInAppBrowser.d.ts.map +1 -0
- package/lib/typescript/digiaAnchorRegistry.d.ts +15 -0
- package/lib/typescript/digiaAnchorRegistry.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +1 -0
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/templateTypes.d.ts +140 -0
- package/lib/typescript/templateTypes.d.ts.map +1 -0
- package/lib/typescript/types.d.ts +140 -3
- package/lib/typescript/types.d.ts.map +1 -1
- package/package.json +11 -3
- package/src/Digia.ts +340 -3
- package/src/DigiaGuideController.ts +61 -0
- package/src/DigiaHealthReporter.ts +43 -0
- package/src/DigiaProvider.tsx +776 -0
- package/src/DigiaSlotView.tsx +26 -6
- package/src/NativeDigiaEngage.ts +28 -13
- package/src/actionHandler.ts +311 -0
- package/src/defaultInAppBrowser.ts +31 -0
- package/src/digiaAnchorRegistry.ts +27 -0
- package/src/index.ts +1 -0
- package/src/templateTypes.ts +121 -0
- package/src/types.ts +102 -5
package/README.md
CHANGED
|
@@ -6,11 +6,7 @@ React Native SDK for **Digia Engage** – renders native Android (Jetpack Compos
|
|
|
6
6
|
> | Platform | Status |
|
|
7
7
|
> |---|---|
|
|
8
8
|
> | Android | ✅ Full support |
|
|
9
|
-
> | iOS | ✅
|
|
10
|
-
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## Installation
|
|
9
|
+
> | iOS | ✅ Guide overlays (JS renderer); native bridge (surveys, inline) |
|
|
14
10
|
|
|
15
11
|
```sh
|
|
16
12
|
npm install @digia-engage/core
|
|
@@ -30,7 +26,7 @@ Add the Digia Engage Android SDK to `android/app/build.gradle.kts`:
|
|
|
30
26
|
|
|
31
27
|
```kotlin
|
|
32
28
|
dependencies {
|
|
33
|
-
implementation("tech.digia:engage:
|
|
29
|
+
implementation("tech.digia:engage:2.0.0-rc.1")
|
|
34
30
|
}
|
|
35
31
|
```
|
|
36
32
|
|
|
@@ -38,57 +34,43 @@ dependencies {
|
|
|
38
34
|
|
|
39
35
|
## Usage
|
|
40
36
|
|
|
41
|
-
### 1
|
|
37
|
+
### 1 — Initialize the SDK
|
|
42
38
|
|
|
43
|
-
Call `Digia.initialize()` once
|
|
39
|
+
Call `Digia.initialize()` once, as early as possible (top of `App.tsx`):
|
|
44
40
|
|
|
45
41
|
```tsx
|
|
46
|
-
import { useEffect } from 'react';
|
|
47
42
|
import { Digia } from '@digia-engage/core';
|
|
48
43
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
})().catch(console.error);
|
|
55
|
-
}, []);
|
|
56
|
-
|
|
57
|
-
return <AppNavigator />;
|
|
58
|
-
}
|
|
44
|
+
await Digia.initialize({
|
|
45
|
+
projectId: 'digia_YOUR_PROJECT_ID',
|
|
46
|
+
environment: 'production', // or 'sandbox'
|
|
47
|
+
logLevel: 'error',
|
|
48
|
+
});
|
|
59
49
|
```
|
|
60
50
|
|
|
61
|
-
### 2
|
|
51
|
+
### 2 — Mount `<DigiaHost />`
|
|
62
52
|
|
|
63
|
-
Place `<
|
|
53
|
+
Place `<DigiaHost />` at the root of your component tree. It renders the JS-side guide/tooltip/spotlight overlays via a `Modal`.
|
|
64
54
|
|
|
65
55
|
```tsx
|
|
66
|
-
|
|
67
|
-
import {
|
|
68
|
-
import { Stack } from 'expo-router';
|
|
56
|
+
// app/_layout.tsx (Expo Router) or App.tsx
|
|
57
|
+
import { DigiaHost } from '@digia-engage/core';
|
|
69
58
|
|
|
70
59
|
export default function RootLayout() {
|
|
71
60
|
return (
|
|
72
|
-
|
|
73
|
-
<DigiaHostView style={StyleSheet.absoluteFill} />
|
|
61
|
+
<>
|
|
74
62
|
<Stack />
|
|
75
|
-
|
|
63
|
+
<DigiaHost />
|
|
64
|
+
</>
|
|
76
65
|
);
|
|
77
66
|
}
|
|
78
|
-
|
|
79
|
-
const styles = StyleSheet.create({
|
|
80
|
-
root: { flex: 1 },
|
|
81
|
-
});
|
|
82
67
|
```
|
|
83
68
|
|
|
84
|
-
### 3
|
|
85
|
-
|
|
86
|
-
Wire `setCurrentScreen()` to your navigation library so the SDK can trigger screen-scoped campaigns:
|
|
69
|
+
### 3 — Track screen changes
|
|
87
70
|
|
|
88
71
|
```tsx
|
|
89
72
|
import { Digia } from '@digia-engage/core';
|
|
90
73
|
|
|
91
|
-
// React Navigation example:
|
|
92
74
|
<NavigationContainer
|
|
93
75
|
onStateChange={() => {
|
|
94
76
|
const route = navRef.getCurrentRoute();
|
|
@@ -97,17 +79,55 @@ import { Digia } from '@digia-engage/core';
|
|
|
97
79
|
>
|
|
98
80
|
```
|
|
99
81
|
|
|
100
|
-
### 4
|
|
82
|
+
### 4 — Register anchors for guide campaigns
|
|
101
83
|
|
|
102
|
-
|
|
84
|
+
Wrap any UI element you want a tooltip or spotlight to point at:
|
|
85
|
+
|
|
86
|
+
```tsx
|
|
87
|
+
import { DigiaAnchorView } from '@digia-engage/core';
|
|
88
|
+
|
|
89
|
+
<DigiaAnchorView anchorKey="home_banner_btn">
|
|
90
|
+
<Button title="Banner" />
|
|
91
|
+
</DigiaAnchorView>
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### 5 — Add slots for inline campaigns
|
|
103
95
|
|
|
104
96
|
```tsx
|
|
105
97
|
import { DigiaSlotView } from '@digia-engage/core';
|
|
106
98
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
99
|
+
// Auto-sizes to native content height
|
|
100
|
+
<DigiaSlotView placementKey="home_banner" />
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### 6 — Register a CEP plugin
|
|
104
|
+
|
|
105
|
+
```tsx
|
|
106
|
+
import { DigiaCleverTapPlugin, createCleverTapClient } from '@digia-engage/clevertap';
|
|
107
|
+
import CleverTap from 'clevertap-react-native';
|
|
108
|
+
|
|
109
|
+
Digia.register(new DigiaCleverTapPlugin({
|
|
110
|
+
cleverTap: createCleverTapClient(CleverTap),
|
|
111
|
+
}));
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### 7 — (Optional) Handle actions
|
|
115
|
+
|
|
116
|
+
Override or observe every action the SDK fires:
|
|
117
|
+
|
|
118
|
+
```tsx
|
|
119
|
+
await Digia.initialize({
|
|
120
|
+
projectId: '...',
|
|
121
|
+
onAction: (action, context) => {
|
|
122
|
+
if (action.type === 'deep_link') {
|
|
123
|
+
// return true to suppress SDK default; false/void to let SDK handle it
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
linking: {
|
|
127
|
+
routeViaSystemLinking: true,
|
|
128
|
+
inAppBrowser: defaultInAppBrowser, // requires react-native-inappbrowser-reborn
|
|
129
|
+
},
|
|
130
|
+
});
|
|
111
131
|
```
|
|
112
132
|
|
|
113
133
|
---
|
|
@@ -118,26 +138,36 @@ import { DigiaSlotView } from '@digia-engage/core';
|
|
|
118
138
|
|
|
119
139
|
| Method | Signature | Description |
|
|
120
140
|
|---|---|---|
|
|
121
|
-
| `initialize` | `(config: DigiaConfig) => Promise<void>` |
|
|
122
|
-
| `register` | `(plugin: DigiaPlugin) => void` | Register a CEP plugin (
|
|
123
|
-
| `unregister` | `(plugin: DigiaPlugin \| string) => void` |
|
|
124
|
-
| `setCurrentScreen` | `(name: string) => void` | Notify the SDK of the
|
|
141
|
+
| `initialize` | `(config: DigiaConfig) => Promise<void>` | Initialize the SDK. Call once before anything else. |
|
|
142
|
+
| `register` | `(plugin: DigiaPlugin) => void` | Register a CEP plugin (CleverTap, MoEngage, etc.). |
|
|
143
|
+
| `unregister` | `(plugin: DigiaPlugin \| string) => void` | Remove a previously registered plugin. |
|
|
144
|
+
| `setCurrentScreen` | `(name: string) => void` | Notify the SDK of the active screen. |
|
|
145
|
+
| `registerAnchor` | `(key: string, screen?: string) => void` | Manually register an anchor key. |
|
|
146
|
+
| `unregisterAnchor` | `(key: string) => void` | Remove an anchor registration. |
|
|
125
147
|
|
|
126
148
|
### `DigiaConfig`
|
|
127
149
|
|
|
128
150
|
| Prop | Type | Default | Description |
|
|
129
151
|
|---|---|---|---|
|
|
130
|
-
| `
|
|
152
|
+
| `projectId` | `string` | — | **Required.** Your Digia project ID (format: `digia_…`). Sent as `x-digia-project-id` on all SDK requests. |
|
|
131
153
|
| `environment` | `'production' \| 'sandbox'` | `'production'` | Target environment. |
|
|
132
154
|
| `logLevel` | `'none' \| 'error' \| 'verbose'` | `'error'` | Log verbosity. |
|
|
155
|
+
| `onAction` | `OnAction` | — | Override hook for all actions. Return `true` to suppress SDK default. |
|
|
156
|
+
| `linking.routeViaSystemLinking` | `boolean` | `true` | Use `Linking.openURL` for URL actions. |
|
|
157
|
+
| `linking.inAppBrowser` | `InAppBrowserAdapter` | — | Required for `open_url` with `presentation: 'in_app'`. |
|
|
158
|
+
| `baseUrl` | `string` | — | Override the Digia API base URL. |
|
|
133
159
|
|
|
134
|
-
### `<
|
|
160
|
+
### `<DigiaHost />`
|
|
135
161
|
|
|
136
|
-
|
|
162
|
+
No props. Renders the JS guide overlay runtime (`TooltipOverlay`, `SpotlightOverlay`).
|
|
163
|
+
Place it once, anywhere in the root view — `Modal` handles z-ordering.
|
|
164
|
+
|
|
165
|
+
### `<DigiaAnchorView>`
|
|
137
166
|
|
|
138
167
|
| Prop | Type | Description |
|
|
139
168
|
|---|---|---|
|
|
140
|
-
| `
|
|
169
|
+
| `anchorKey` | `string` | **Required.** Must match the step's `anchorKey` in the campaign config. |
|
|
170
|
+
| `...ViewProps` | — | All standard React Native `View` props are forwarded. |
|
|
141
171
|
|
|
142
172
|
### `<DigiaSlotView>`
|
|
143
173
|
|
|
@@ -145,8 +175,61 @@ Renders inline campaign content (banners, cards) at a named placement. Collapses
|
|
|
145
175
|
|
|
146
176
|
| Prop | Type | Description |
|
|
147
177
|
|---|---|---|
|
|
148
|
-
| `placementKey` | `string` | Must match the
|
|
149
|
-
| `style` | `ViewStyle?` |
|
|
178
|
+
| `placementKey` | `string` | **Required.** Must match the campaign's `slotKey`. |
|
|
179
|
+
| `style` | `ViewStyle?` | Pass an explicit `height` to fix size; otherwise auto-sizes. |
|
|
180
|
+
|
|
181
|
+
### `<DigiaHostView>`
|
|
182
|
+
|
|
183
|
+
Low-level transparent native overlay view (Android/iOS). Use `<DigiaHost />` instead
|
|
184
|
+
unless you need the native Compose/SwiftUI overlay host explicitly.
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## Campaign types
|
|
189
|
+
|
|
190
|
+
| Type | Trigger | JS or Native |
|
|
191
|
+
|---|---|---|
|
|
192
|
+
| `guide` (tooltip) | `DigiaGuideController` → `DigiaHost` | **JS** — `TooltipOverlay` via `Modal` |
|
|
193
|
+
| `guide` (spotlight) | `DigiaGuideController` → `DigiaHost` | **JS** — `SpotlightOverlay` via `Modal` |
|
|
194
|
+
| `inline` | `nativeDigiaModule.triggerCampaign()` | **Native** — Android Compose `VWCarousel` |
|
|
195
|
+
| `survey` | `nativeDigiaModule.triggerCampaign()` | **Native** — Android Compose `SurveyRenderer` |
|
|
196
|
+
| `nudge` | `nativeDigiaModule.triggerCampaign()` | **Native** — Android Compose dialog / bottom-sheet |
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## Architecture
|
|
201
|
+
|
|
202
|
+
```
|
|
203
|
+
react-native/src/
|
|
204
|
+
index.ts Public API exports
|
|
205
|
+
Digia.ts SDK singleton — initialize, register, setCurrentScreen,
|
|
206
|
+
campaign routing, campaign store (fetched from backend)
|
|
207
|
+
DigiaProvider.tsx JS guide renderer — TooltipOverlay + SpotlightOverlay + DigiaHost
|
|
208
|
+
DigiaGuideController.ts Event bus for guide start/cancel; queues if DigiaHost not mounted
|
|
209
|
+
digiaAnchorRegistry.ts In-memory anchor position store with subscriber pattern
|
|
210
|
+
DigiaAnchorView.tsx Wraps UI elements; measures position via ref.measure
|
|
211
|
+
DigiaSlotView.tsx Native slot view wrapper; auto-sizes to content height
|
|
212
|
+
DigiaHostView.tsx Low-level native overlay host (transparent, pointer-events none)
|
|
213
|
+
NativeDigiaEngage.ts Codegen native module spec (TurboModule)
|
|
214
|
+
actionHandler.ts Action execution — deep link, open URL, next/prev/dismiss;
|
|
215
|
+
onAction override; cold-start queue
|
|
216
|
+
defaultInAppBrowser.ts Lazily loads react-native-inappbrowser-reborn
|
|
217
|
+
templateTypes.ts TypeScript types for TooltipConfig, SpotlightConfig,
|
|
218
|
+
CarouselConfig, SurveyTemplateConfig
|
|
219
|
+
types.ts DigiaConfig, DigiaPlugin, DigiaDelegate, InAppPayload,
|
|
220
|
+
DigiaAction, ActionContext, DigiaExperienceEvent
|
|
221
|
+
|
|
222
|
+
react-native/android/ Android bridge
|
|
223
|
+
DigiaModule.kt initialize, registerBridge, triggerCampaign, registerAnchor, …
|
|
224
|
+
DigiaSlotViewManager.kt DigiaSlotView native view manager
|
|
225
|
+
DigiaAnchorViewManager.kt DigiaAnchorView native view manager
|
|
226
|
+
DigiaViewManager.kt DigiaHostView native view manager
|
|
227
|
+
|
|
228
|
+
react-native/ios/ iOS bridge
|
|
229
|
+
DigiaModule.swift initialize, registerBridge, triggerCampaign, …
|
|
230
|
+
DigiaHostViewManager.swift
|
|
231
|
+
DigiaAnchorViewManager.swift
|
|
232
|
+
```
|
|
150
233
|
|
|
151
234
|
---
|
|
152
235
|
|
package/android/build.gradle
CHANGED
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
* Android Gradle build file for the @digia/engage-react-native library module.
|
|
3
3
|
*
|
|
4
4
|
* This module is a thin bridge layer that:
|
|
5
|
-
* • Depends on the Digia Engage Android AAR
|
|
5
|
+
* • Depends on the Digia Engage Android AAR
|
|
6
6
|
* • Depends on the React Native SDK
|
|
7
7
|
* • Exposes a ReactPackage (DigiaPackage) that registers the native module
|
|
8
8
|
* and native view to React Native's bridge
|
|
9
9
|
*
|
|
10
10
|
* The Compose runtime/tooling dependencies are inherited transitively from
|
|
11
|
-
* the
|
|
11
|
+
* the Digia Engage AAR via `api` declarations; we only add what is needed for
|
|
12
12
|
* the bridge code itself.
|
|
13
13
|
*/
|
|
14
14
|
|
|
@@ -22,7 +22,6 @@
|
|
|
22
22
|
*/
|
|
23
23
|
package com.digia.engage.rn
|
|
24
24
|
|
|
25
|
-
import android.widget.FrameLayout
|
|
26
25
|
import androidx.lifecycle.LifecycleOwner
|
|
27
26
|
import androidx.lifecycle.ViewModelStoreOwner
|
|
28
27
|
import androidx.lifecycle.setViewTreeLifecycleOwner
|
|
@@ -59,7 +58,14 @@ internal class DigiaModule(
|
|
|
59
58
|
// ─── initialize ───────────────────────────────────────────────────────────
|
|
60
59
|
|
|
61
60
|
@ReactMethod
|
|
62
|
-
fun initialize(
|
|
61
|
+
fun initialize(
|
|
62
|
+
apiKey: String,
|
|
63
|
+
environment: String,
|
|
64
|
+
logLevel: String,
|
|
65
|
+
baseUrl: String?,
|
|
66
|
+
fontFamily: String?,
|
|
67
|
+
promise: Promise
|
|
68
|
+
) {
|
|
63
69
|
try {
|
|
64
70
|
val config =
|
|
65
71
|
DigiaConfig(
|
|
@@ -75,10 +81,18 @@ internal class DigiaModule(
|
|
|
75
81
|
"none" -> DigiaLogLevel.NONE
|
|
76
82
|
else -> DigiaLogLevel.ERROR
|
|
77
83
|
},
|
|
84
|
+
baseUrl = baseUrl?.takeIf { it.isNotBlank() },
|
|
85
|
+
fontFamily = fontFamily?.takeIf { it.isNotBlank() },
|
|
78
86
|
)
|
|
79
87
|
Digia.initialize(reactContext.applicationContext, config)
|
|
80
88
|
|
|
81
89
|
UiThreadUtil.runOnUiThread {
|
|
90
|
+
// Mount the Compose overlay ABOVE the ReactRootView via addContentView().
|
|
91
|
+
// This keeps it outside Fabric's shadow tree entirely so Fabric hit-testing
|
|
92
|
+
// never sees it. Touch pass-through is handled by DigiaHostView.dispatchTouchEvent
|
|
93
|
+
// returning false at the native Android level — which works correctly at this
|
|
94
|
+
// level of the hierarchy, unlike inside Fabric where pointerEvents="none" on
|
|
95
|
+
// non-ReactViewGroup views is not respected during shadow-tree hit-testing.
|
|
82
96
|
mountDigiaHost()
|
|
83
97
|
promise.resolve(null)
|
|
84
98
|
}
|
|
@@ -138,13 +152,42 @@ internal class DigiaModule(
|
|
|
138
152
|
rnPlugin.delegate?.onCampaignInvalidated(campaignId)
|
|
139
153
|
}
|
|
140
154
|
|
|
155
|
+
// ─── Anchor registration ──────────────────────────────────────────────────
|
|
156
|
+
|
|
157
|
+
@ReactMethod
|
|
158
|
+
fun registerAnchor(key: String, x: Int, y: Int, width: Int, height: Int) {
|
|
159
|
+
Digia.registerAnchor(key, x, y, width, height)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
@ReactMethod
|
|
163
|
+
fun unregisterAnchor(key: String) {
|
|
164
|
+
Digia.unregisterAnchor(key)
|
|
165
|
+
}
|
|
166
|
+
|
|
141
167
|
// ─── Internal: mount the Compose overlay host ─────────────────────────────
|
|
142
168
|
|
|
143
169
|
private fun mountDigiaHost() {
|
|
144
|
-
val activity = reactContext.currentActivity ?:
|
|
170
|
+
val activity = reactContext.currentActivity ?: run {
|
|
171
|
+
android.util.Log.w("DigiaHost", "[mountDigiaHost] no current activity — skipping")
|
|
172
|
+
return
|
|
173
|
+
}
|
|
145
174
|
|
|
146
175
|
val contentRoot = activity.window.decorView.findViewWithTag<DigiaHostView>(DIGIA_HOST_TAG)
|
|
147
|
-
if (contentRoot != null)
|
|
176
|
+
if (contentRoot != null) {
|
|
177
|
+
android.util.Log.d("DigiaHost", "[mountDigiaHost] already mounted (tag found) — skipping")
|
|
178
|
+
return
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
android.util.Log.d("DigiaHost", "[mountDigiaHost] mounting native overlay on DecorView")
|
|
182
|
+
|
|
183
|
+
// Mount on the DecorView (not content area) so the overlay covers the full screen
|
|
184
|
+
// including status bar and navigation bar. This also ensures the Compose Popup's
|
|
185
|
+
// canvas y=0 aligns with the absolute screen y=0, matching getLocationOnScreen()
|
|
186
|
+
// coordinates used by DigiaAnchorView.
|
|
187
|
+
val decorView = activity.window.decorView as? android.view.ViewGroup ?: run {
|
|
188
|
+
android.util.Log.w("DigiaHost", "[mountDigiaHost] decorView not a ViewGroup — skipping")
|
|
189
|
+
return
|
|
190
|
+
}
|
|
148
191
|
|
|
149
192
|
val composeView =
|
|
150
193
|
DigiaHostView(activity).apply {
|
|
@@ -155,13 +198,14 @@ internal class DigiaModule(
|
|
|
155
198
|
setViewTreeSavedStateRegistryOwner(activity)
|
|
156
199
|
}
|
|
157
200
|
|
|
158
|
-
|
|
201
|
+
decorView.addView(
|
|
159
202
|
composeView,
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
203
|
+
android.view.ViewGroup.LayoutParams(
|
|
204
|
+
android.view.ViewGroup.LayoutParams.MATCH_PARENT,
|
|
205
|
+
android.view.ViewGroup.LayoutParams.MATCH_PARENT,
|
|
163
206
|
),
|
|
164
207
|
)
|
|
208
|
+
android.util.Log.d("DigiaHost", "[mountDigiaHost] done — DecorView child count: ${decorView.childCount}")
|
|
165
209
|
}
|
|
166
210
|
|
|
167
211
|
companion object {
|
|
@@ -26,10 +26,14 @@ private class ContentSizeChangeEvent(
|
|
|
26
26
|
surfaceId: Int,
|
|
27
27
|
viewTag: Int,
|
|
28
28
|
private val heightDp: Double,
|
|
29
|
+
private val widthDp: Double,
|
|
29
30
|
) : Event<ContentSizeChangeEvent>(surfaceId, viewTag) {
|
|
30
31
|
override fun getEventName(): String = "onContentSizeChange"
|
|
31
32
|
override fun getEventData(): WritableMap =
|
|
32
|
-
Arguments.createMap().apply {
|
|
33
|
+
Arguments.createMap().apply {
|
|
34
|
+
putDouble("height", heightDp)
|
|
35
|
+
putDouble("width", widthDp)
|
|
36
|
+
}
|
|
33
37
|
}
|
|
34
38
|
|
|
35
39
|
// ── DigiaSlotContainerView ────────────────────────────────────────────────────
|
|
@@ -141,7 +145,7 @@ internal class DigiaSlotContainerView(context: Context) : FrameLayout(context) {
|
|
|
141
145
|
|
|
142
146
|
val dispatcher = UIManagerHelper.getEventDispatcherForReactTag(ctx, id) ?: return
|
|
143
147
|
val surfaceId = UIManagerHelper.getSurfaceId(this)
|
|
144
|
-
dispatcher.dispatchEvent(ContentSizeChangeEvent(surfaceId, id, heightDp.toDouble()))
|
|
148
|
+
dispatcher.dispatchEvent(ContentSizeChangeEvent(surfaceId, id, heightDp.toDouble(), 0.0))
|
|
145
149
|
}
|
|
146
150
|
|
|
147
151
|
companion object {
|
package/ios/DigiaEngageModule.m
CHANGED
|
@@ -22,9 +22,11 @@
|
|
|
22
22
|
|
|
23
23
|
@interface RCT_EXTERN_MODULE(DigiaEngageModule, RCTEventEmitter)
|
|
24
24
|
|
|
25
|
-
RCT_EXTERN_METHOD(initialize:(NSString *)
|
|
25
|
+
RCT_EXTERN_METHOD(initialize:(NSString *)projectId
|
|
26
26
|
environment:(NSString *)environment
|
|
27
27
|
logLevel:(NSString *)logLevel
|
|
28
|
+
baseUrl:(NSString *)baseUrl
|
|
29
|
+
fontFamily:(NSString *)fontFamily
|
|
28
30
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
29
31
|
reject:(RCTPromiseRejectBlock)reject)
|
|
30
32
|
|
|
@@ -62,3 +64,7 @@ RCT_EXPORT_VIEW_PROPERTY(onContentSizeChange, RCTDirectEventBlock)
|
|
|
62
64
|
@interface RCT_EXTERN_MODULE(DigiaAnchorView, RCTViewManager)
|
|
63
65
|
RCT_EXPORT_VIEW_PROPERTY(anchorKey, NSString)
|
|
64
66
|
@end
|
|
67
|
+
|
|
68
|
+
@interface RCT_EXTERN_MODULE(DigiaAnchorView, RCTViewManager)
|
|
69
|
+
RCT_EXPORT_VIEW_PROPERTY(anchorKey, NSString)
|
|
70
|
+
@end
|
|
@@ -48,30 +48,27 @@ final class DigiaHostUIView: UIView {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
private func mountHostingController() {
|
|
51
|
-
|
|
51
|
+
let parentVC = parentViewController()
|
|
52
52
|
|
|
53
53
|
let swiftUIView = DigiaHostWrapperView()
|
|
54
54
|
let hc = UIHostingController(rootView: swiftUIView)
|
|
55
55
|
hc.view.translatesAutoresizingMaskIntoConstraints = false
|
|
56
56
|
hc.view.backgroundColor = .clear
|
|
57
57
|
|
|
58
|
-
parentVC.addChild(hc)
|
|
59
|
-
// Mount onto parentVC.view
|
|
60
|
-
//
|
|
61
|
-
//
|
|
62
|
-
//
|
|
63
|
-
//
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
// rendering loop runs and reacts to SDK state changes.
|
|
67
|
-
parentVC.view.addSubview(hc.view)
|
|
68
|
-
hc.didMove(toParent: parentVC)
|
|
58
|
+
if let parentVC { parentVC.addChild(hc) }
|
|
59
|
+
// Mount onto self rather than parentVC.view. DigiaHostView is given
|
|
60
|
+
// absoluteFillObject style from JS so self IS full-screen, and SwiftUI
|
|
61
|
+
// will render normally. Mounting here means hitTest below is the single
|
|
62
|
+
// control point for touch dispatch — parentVC.view never has a rogue
|
|
63
|
+
// full-screen sibling that intercepts all RN touches.
|
|
64
|
+
addSubview(hc.view)
|
|
65
|
+
if let parentVC { hc.didMove(toParent: parentVC) }
|
|
69
66
|
|
|
70
67
|
NSLayoutConstraint.activate([
|
|
71
|
-
hc.view.leadingAnchor.constraint(equalTo:
|
|
72
|
-
hc.view.trailingAnchor.constraint(equalTo:
|
|
73
|
-
hc.view.topAnchor.constraint(equalTo:
|
|
74
|
-
hc.view.bottomAnchor.constraint(equalTo:
|
|
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),
|
|
75
72
|
])
|
|
76
73
|
|
|
77
74
|
hostingController = hc
|
|
@@ -79,11 +76,14 @@ final class DigiaHostUIView: UIView {
|
|
|
79
76
|
|
|
80
77
|
// Pass touches through to RN when no overlay is active.
|
|
81
78
|
// When an overlay renders in-host (bottom sheet / dialog inside DigiaHost's ZStack),
|
|
82
|
-
// SwiftUI's hit test returns the overlay view
|
|
83
|
-
//
|
|
84
|
-
//
|
|
79
|
+
// SwiftUI's hit test returns the overlay view — making the overlay interactive.
|
|
80
|
+
// When nothing is rendered, _UIHostingView.hitTest returns nil or itself; either
|
|
81
|
+
// way we return nil so UIKit falls through to RN content below.
|
|
85
82
|
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
|
86
|
-
|
|
83
|
+
guard let hcView = hostingController?.view else { return nil }
|
|
84
|
+
let hit = hcView.hitTest(point, with: event)
|
|
85
|
+
if hit == nil || hit === hcView { return nil }
|
|
86
|
+
return hit
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
/// Prefer React Native’s `UIView.reactViewController`, then walk `next` from each view’s `.next`.
|
package/ios/DigiaModule.swift
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* React Native NativeModule that bridges the Digia Engage iOS SDK.
|
|
5
5
|
*
|
|
6
6
|
* Exposed methods (callable from JS via NativeModules.DigiaEngageModule):
|
|
7
|
-
* initialize(
|
|
7
|
+
* initialize(projectId, environment, logLevel): Promise<void>
|
|
8
8
|
* registerBridge(): void
|
|
9
9
|
* setCurrentScreen(name): void
|
|
10
10
|
* triggerCampaign(id, content, cepContext): void
|
|
@@ -61,9 +61,11 @@ final class DigiaModule: RCTEventEmitter {
|
|
|
61
61
|
|
|
62
62
|
@objc
|
|
63
63
|
func initialize(
|
|
64
|
-
_
|
|
64
|
+
_ projectId: String,
|
|
65
65
|
environment: String,
|
|
66
66
|
logLevel: String,
|
|
67
|
+
baseUrl: String?,
|
|
68
|
+
fontFamily: String?,
|
|
67
69
|
resolve: @escaping RCTPromiseResolveBlock,
|
|
68
70
|
reject: @escaping RCTPromiseRejectBlock
|
|
69
71
|
) {
|
|
@@ -76,9 +78,11 @@ final class DigiaModule: RCTEventEmitter {
|
|
|
76
78
|
}
|
|
77
79
|
|
|
78
80
|
let config = DigiaConfig(
|
|
79
|
-
apiKey:
|
|
81
|
+
apiKey: projectId,
|
|
80
82
|
logLevel: logLevelValue,
|
|
81
|
-
environment: envValue
|
|
83
|
+
environment: envValue,
|
|
84
|
+
developerConfig: baseUrl.flatMap { $0.isEmpty ? nil : DigiaDeveloperConfig(baseURL: $0) },
|
|
85
|
+
fontFamily: fontFamily.flatMap { $0.isEmpty ? nil : $0 }
|
|
82
86
|
)
|
|
83
87
|
|
|
84
88
|
Task { @MainActor in
|