@digia-engage/core 1.1.0 → 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 +147 -177
- 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 +12 -3
- package/react-native.config.js +23 -0
- 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
|
@@ -1,203 +1,133 @@
|
|
|
1
|
-
# @digia/
|
|
1
|
+
# @digia-engage/core
|
|
2
2
|
|
|
3
|
-
React Native
|
|
4
|
-
Jetpack Compose UI (dialogs, bottom-sheets) inside React Native applications.
|
|
3
|
+
React Native SDK for **Digia Engage** – renders native Android (Jetpack Compose) and iOS campaign UI (bottom sheets, dialogs, inline banners, tooltips, spotlights) inside React Native applications.
|
|
5
4
|
|
|
6
5
|
> **Platform support**
|
|
7
6
|
> | Platform | Status |
|
|
8
7
|
> |---|---|
|
|
9
8
|
> | Android | ✅ Full support |
|
|
10
|
-
> | iOS |
|
|
11
|
-
|
|
12
|
-
---
|
|
13
|
-
|
|
14
|
-
## How it works
|
|
15
|
-
|
|
16
|
-
The Digia Engage Android SDK is built entirely with Jetpack Compose. In a
|
|
17
|
-
pure-Android app you wrap your content with the `DigiaHost { }` composable; it
|
|
18
|
-
then manages campaign-driven overlays (dialogs, bottom sheets) on top of your
|
|
19
|
-
content.
|
|
20
|
-
|
|
21
|
-
In a React Native app we cannot embed a Composable directly in the JS tree, so
|
|
22
|
-
the bridge uses two complementary mechanisms:
|
|
23
|
-
|
|
24
|
-
```
|
|
25
|
-
┌─────────────────────────────────────────┐
|
|
26
|
-
│ Android Activity (ReactActivity) │
|
|
27
|
-
│ │
|
|
28
|
-
│ ┌─────────────────────────────────┐ │
|
|
29
|
-
│ │ Android content FrameLayout │ │
|
|
30
|
-
│ │ │ │
|
|
31
|
-
│ │ ┌─────────────────────────┐ │ │
|
|
32
|
-
│ │ │ React Native RootView │ │ │
|
|
33
|
-
│ │ │ (your JS UI) │ │ │
|
|
34
|
-
│ │ └─────────────────────────┘ │ │
|
|
35
|
-
│ │ │ │
|
|
36
|
-
│ │ ┌─────────────────────────┐ │ │
|
|
37
|
-
│ │ │ DigiaHostComposeView │ │ │
|
|
38
|
-
│ │ │ (AbstractComposeView) │ │ │
|
|
39
|
-
│ │ │ hosts DigiaHost { } │ │ │
|
|
40
|
-
│ │ │ ← transparent, no │ │ │
|
|
41
|
-
│ │ │ touch interception │ │ │
|
|
42
|
-
│ │ └─────────────────────────┘ │ │
|
|
43
|
-
│ └─────────────────────────────────┘ │
|
|
44
|
-
│ │
|
|
45
|
-
│ ┌──────────────────────────────────┐ │
|
|
46
|
-
│ │ Compose Dialog window (overlay) │ │
|
|
47
|
-
│ │ Triggered by CEP campaign │ │
|
|
48
|
-
│ └──────────────────────────────────┘ │
|
|
49
|
-
└─────────────────────────────────────────┘
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
1. **`Digia.initialize()`** initialises the SDK and calls `addContentView()`
|
|
53
|
-
to attach a transparent `DigiaHostComposeView` on top of the React Native
|
|
54
|
-
view hierarchy. This is the anchor for the Compose composition.
|
|
55
|
-
|
|
56
|
-
2. **`DigiaHost { }`** inside the `ComposeView` manages `DialogManager` and
|
|
57
|
-
`BottomSheetManager`. When a CEP plugin triggers a campaign, Compose
|
|
58
|
-
renders a `Dialog` or `ModalBottomSheet` – these are **separate Android
|
|
59
|
-
windows** that appear on top of everything, including React Native content.
|
|
60
|
-
|
|
61
|
-
3. **`<DigiaHostView>`** is an optional React Native component you can place in
|
|
62
|
-
your component tree (e.g. as `StyleSheet.absoluteFill`) if you prefer a
|
|
63
|
-
declarative, component-based mount point instead of the auto-mount.
|
|
64
|
-
|
|
65
|
-
---
|
|
66
|
-
|
|
67
|
-
## Installation
|
|
9
|
+
> | iOS | ✅ Guide overlays (JS renderer); native bridge (surveys, inline) |
|
|
68
10
|
|
|
69
11
|
```sh
|
|
70
|
-
|
|
71
|
-
npm install @digia/engage-react-native
|
|
72
|
-
|
|
73
|
-
# yarn
|
|
74
|
-
yarn add @digia/engage-react-native
|
|
12
|
+
npm install @digia-engage/core
|
|
75
13
|
```
|
|
76
14
|
|
|
77
|
-
React Native CLI auto-linking handles the rest.
|
|
15
|
+
React Native CLI auto-linking handles the rest. Rebuild the native app after installing:
|
|
78
16
|
|
|
79
17
|
```sh
|
|
80
|
-
npx react-native
|
|
18
|
+
npx react-native run-android
|
|
81
19
|
# or
|
|
82
20
|
cd android && ./gradlew assembleDebug
|
|
83
21
|
```
|
|
84
22
|
|
|
85
|
-
### Android – host app
|
|
23
|
+
### Android – host app dependency
|
|
86
24
|
|
|
87
|
-
|
|
88
|
-
(or include it via your local Maven / private registry):
|
|
25
|
+
Add the Digia Engage Android SDK to `android/app/build.gradle.kts`:
|
|
89
26
|
|
|
90
|
-
```
|
|
27
|
+
```kotlin
|
|
91
28
|
dependencies {
|
|
92
|
-
implementation
|
|
29
|
+
implementation("tech.digia:engage:2.0.0-rc.1")
|
|
93
30
|
}
|
|
94
31
|
```
|
|
95
32
|
|
|
96
|
-
|
|
97
|
-
project instead:
|
|
33
|
+
---
|
|
98
34
|
|
|
99
|
-
|
|
100
|
-
implementation(project(':digia-ui'))
|
|
101
|
-
```
|
|
35
|
+
## Usage
|
|
102
36
|
|
|
103
|
-
###
|
|
37
|
+
### 1 — Initialize the SDK
|
|
104
38
|
|
|
105
|
-
|
|
39
|
+
Call `Digia.initialize()` once, as early as possible (top of `App.tsx`):
|
|
106
40
|
|
|
107
|
-
|
|
41
|
+
```tsx
|
|
42
|
+
import { Digia } from '@digia-engage/core';
|
|
108
43
|
|
|
109
|
-
|
|
44
|
+
await Digia.initialize({
|
|
45
|
+
projectId: 'digia_YOUR_PROJECT_ID',
|
|
46
|
+
environment: 'production', // or 'sandbox'
|
|
47
|
+
logLevel: 'error',
|
|
48
|
+
});
|
|
49
|
+
```
|
|
110
50
|
|
|
111
|
-
###
|
|
51
|
+
### 2 — Mount `<DigiaHost />`
|
|
112
52
|
|
|
113
|
-
|
|
114
|
-
`App.tsx`):
|
|
53
|
+
Place `<DigiaHost />` at the root of your component tree. It renders the JS-side guide/tooltip/spotlight overlays via a `Modal`.
|
|
115
54
|
|
|
116
55
|
```tsx
|
|
117
|
-
|
|
118
|
-
import {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
});
|
|
128
|
-
}, []);
|
|
129
|
-
|
|
130
|
-
return <NavigationContainer>{/* … */}</NavigationContainer>;
|
|
56
|
+
// app/_layout.tsx (Expo Router) or App.tsx
|
|
57
|
+
import { DigiaHost } from '@digia-engage/core';
|
|
58
|
+
|
|
59
|
+
export default function RootLayout() {
|
|
60
|
+
return (
|
|
61
|
+
<>
|
|
62
|
+
<Stack />
|
|
63
|
+
<DigiaHost />
|
|
64
|
+
</>
|
|
65
|
+
);
|
|
131
66
|
}
|
|
132
67
|
```
|
|
133
68
|
|
|
134
|
-
|
|
135
|
-
overlay host to the Activity. You do **not** need to add `<DigiaHostView>`
|
|
136
|
-
unless you want an explicit component-based mount point.
|
|
137
|
-
|
|
138
|
-
### 2 – Track screen changes
|
|
139
|
-
|
|
140
|
-
Wire `setCurrentScreen()` to your navigation state so the SDK can trigger
|
|
141
|
-
campaigns based on the active screen:
|
|
69
|
+
### 3 — Track screen changes
|
|
142
70
|
|
|
143
71
|
```tsx
|
|
144
|
-
import {
|
|
145
|
-
import { Digia } from '@digia/engage-react-native';
|
|
146
|
-
|
|
147
|
-
// Inside your App component:
|
|
148
|
-
const navRef = useNavigationContainerRef();
|
|
72
|
+
import { Digia } from '@digia-engage/core';
|
|
149
73
|
|
|
150
74
|
<NavigationContainer
|
|
151
|
-
ref={navRef}
|
|
152
75
|
onStateChange={() => {
|
|
153
|
-
const
|
|
154
|
-
if (
|
|
155
|
-
Digia.setCurrentScreen(currentRoute.name);
|
|
156
|
-
}
|
|
76
|
+
const route = navRef.getCurrentRoute();
|
|
77
|
+
if (route) Digia.setCurrentScreen(route.name);
|
|
157
78
|
}}
|
|
158
79
|
>
|
|
159
80
|
```
|
|
160
81
|
|
|
161
|
-
###
|
|
82
|
+
### 4 — Register anchors for guide campaigns
|
|
162
83
|
|
|
163
|
-
|
|
84
|
+
Wrap any UI element you want a tooltip or spotlight to point at:
|
|
164
85
|
|
|
165
86
|
```tsx
|
|
166
|
-
import {
|
|
87
|
+
import { DigiaAnchorView } from '@digia-engage/core';
|
|
167
88
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
title="Open Digia Experience"
|
|
172
|
-
onPress={() => Digia.createInitialPage()}
|
|
173
|
-
/>
|
|
174
|
-
);
|
|
175
|
-
}
|
|
89
|
+
<DigiaAnchorView anchorKey="home_banner_btn">
|
|
90
|
+
<Button title="Banner" />
|
|
91
|
+
</DigiaAnchorView>
|
|
176
92
|
```
|
|
177
93
|
|
|
178
|
-
###
|
|
94
|
+
### 5 — Add slots for inline campaigns
|
|
95
|
+
|
|
96
|
+
```tsx
|
|
97
|
+
import { DigiaSlotView } from '@digia-engage/core';
|
|
98
|
+
|
|
99
|
+
// Auto-sizes to native content height
|
|
100
|
+
<DigiaSlotView placementKey="home_banner" />
|
|
101
|
+
```
|
|
179
102
|
|
|
180
|
-
|
|
181
|
-
`initialize()` auto-mount and place `<DigiaHostView>` at the root of your
|
|
182
|
-
component tree:
|
|
103
|
+
### 6 — Register a CEP plugin
|
|
183
104
|
|
|
184
105
|
```tsx
|
|
185
|
-
import
|
|
186
|
-
import
|
|
187
|
-
import { DigiaHostView } from '@digia/engage-react-native';
|
|
106
|
+
import { DigiaCleverTapPlugin, createCleverTapClient } from '@digia-engage/clevertap';
|
|
107
|
+
import CleverTap from 'clevertap-react-native';
|
|
188
108
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
<DigiaHostView style={StyleSheet.absoluteFill} />
|
|
109
|
+
Digia.register(new DigiaCleverTapPlugin({
|
|
110
|
+
cleverTap: createCleverTapClient(CleverTap),
|
|
111
|
+
}));
|
|
112
|
+
```
|
|
194
113
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
}
|
|
114
|
+
### 7 — (Optional) Handle actions
|
|
115
|
+
|
|
116
|
+
Override or observe every action the SDK fires:
|
|
199
117
|
|
|
200
|
-
|
|
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
|
+
});
|
|
201
131
|
```
|
|
202
132
|
|
|
203
133
|
---
|
|
@@ -208,57 +138,97 @@ const styles = StyleSheet.create({ root: { flex: 1 } });
|
|
|
208
138
|
|
|
209
139
|
| Method | Signature | Description |
|
|
210
140
|
|---|---|---|
|
|
211
|
-
| `initialize` | `(config: DigiaConfig) => Promise<void>` |
|
|
212
|
-
| `
|
|
213
|
-
| `
|
|
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. |
|
|
214
147
|
|
|
215
148
|
### `DigiaConfig`
|
|
216
149
|
|
|
217
150
|
| Prop | Type | Default | Description |
|
|
218
151
|
|---|---|---|---|
|
|
219
|
-
| `
|
|
152
|
+
| `projectId` | `string` | — | **Required.** Your Digia project ID (format: `digia_…`). Sent as `x-digia-project-id` on all SDK requests. |
|
|
220
153
|
| `environment` | `'production' \| 'sandbox'` | `'production'` | Target environment. |
|
|
221
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. |
|
|
222
159
|
|
|
223
|
-
###
|
|
160
|
+
### `<DigiaHost />`
|
|
224
161
|
|
|
225
|
-
|
|
162
|
+
No props. Renders the JS guide overlay runtime (`TooltipOverlay`, `SpotlightOverlay`).
|
|
163
|
+
Place it once, anywhere in the root view — `Modal` handles z-ordering.
|
|
226
164
|
|
|
227
|
-
### `<
|
|
165
|
+
### `<DigiaAnchorView>`
|
|
228
166
|
|
|
229
|
-
|
|
167
|
+
| Prop | Type | Description |
|
|
168
|
+
|---|---|---|
|
|
169
|
+
| `anchorKey` | `string` | **Required.** Must match the step's `anchorKey` in the campaign config. |
|
|
170
|
+
| `...ViewProps` | — | All standard React Native `View` props are forwarded. |
|
|
171
|
+
|
|
172
|
+
### `<DigiaSlotView>`
|
|
173
|
+
|
|
174
|
+
Renders inline campaign content (banners, cards) at a named placement. Collapses to zero height when no campaign is active for the slot.
|
|
230
175
|
|
|
231
176
|
| Prop | Type | Description |
|
|
232
177
|
|---|---|---|
|
|
233
|
-
| `
|
|
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 |
|
|
234
197
|
|
|
235
198
|
---
|
|
236
199
|
|
|
237
|
-
## Architecture
|
|
200
|
+
## Architecture
|
|
238
201
|
|
|
239
202
|
```
|
|
240
|
-
react-native/
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
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
|
|
262
232
|
```
|
|
263
233
|
|
|
264
234
|
---
|
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`.
|