@digia-engage/core 1.0.0 → 1.1.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 CHANGED
@@ -1,203 +1,113 @@
1
- # @digia/engage-react-native
1
+ # @digia-engage/core
2
2
 
3
- React Native bridge for the **Digia Engage SDK** – renders native Android
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 | 🚧 Stub (no-op – coming soon) |
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.
9
+ > | iOS | Full support |
64
10
 
65
11
  ---
66
12
 
67
13
  ## Installation
68
14
 
69
15
  ```sh
70
- # npm
71
- npm install @digia/engage-react-native
72
-
73
- # yarn
74
- yarn add @digia/engage-react-native
16
+ npm install @digia-engage/core
75
17
  ```
76
18
 
77
- React Native CLI auto-linking handles the rest. Rebuild the native app:
19
+ React Native CLI auto-linking handles the rest. Rebuild the native app after installing:
78
20
 
79
21
  ```sh
80
- npx react-native build-android
22
+ npx react-native run-android
81
23
  # or
82
24
  cd android && ./gradlew assembleDebug
83
25
  ```
84
26
 
85
- ### Android – host app dependencies
27
+ ### Android – host app dependency
86
28
 
87
- Your app's `android/app/build.gradle` must declare the Digia Engage AAR
88
- (or include it via your local Maven / private registry):
29
+ Add the Digia Engage Android SDK to `android/app/build.gradle.kts`:
89
30
 
90
- ```groovy
31
+ ```kotlin
91
32
  dependencies {
92
- implementation 'com.digia:digia-ui:1.0.0-beta-1'
33
+ implementation("tech.digia:engage:1.1.0")
93
34
  }
94
35
  ```
95
36
 
96
- If you are working inside the monorepo and building locally, add the `:digia-ui`
97
- project instead:
98
-
99
- ```groovy
100
- implementation(project(':digia-ui'))
101
- ```
102
-
103
- ### iOS
104
-
105
- iOS is a no-op stub. All methods resolve immediately without error.
106
-
107
37
  ---
108
38
 
109
39
  ## Usage
110
40
 
111
41
  ### 1 – Initialise the SDK
112
42
 
113
- Call `Digia.initialize()` once, as early as possible (e.g. the top of
114
- `App.tsx`):
43
+ Call `Digia.initialize()` once at app startup, before registering any CEP plugin:
115
44
 
116
45
  ```tsx
117
- import React, { useEffect } from 'react';
118
- import { NavigationContainer } from '@react-navigation/native';
119
- import { Digia } from '@digia/engage-react-native';
46
+ import { useEffect } from 'react';
47
+ import { Digia } from '@digia-engage/core';
120
48
 
121
- export default function App() {
49
+ export function RootApp() {
122
50
  useEffect(() => {
123
- Digia.initialize({
124
- apiKey: 'YOUR_DIGIA_API_KEY',
125
- environment: 'production', // or 'sandbox'
126
- logLevel: 'error',
127
- });
51
+ (async () => {
52
+ await Digia.initialize({ apiKey: 'YOUR_ACCESS_KEY' });
53
+ // Register your CEP plugin here (e.g. DigiaCleverTapPlugin)
54
+ })().catch(console.error);
128
55
  }, []);
129
56
 
130
- return <NavigationContainer>{/* … */}</NavigationContainer>;
57
+ return <AppNavigator />;
131
58
  }
132
59
  ```
133
60
 
134
- `initialize()` returns a `Promise<void>` and automatically attaches the Compose
135
- overlay host to the Activity. You do **not** need to add `<DigiaHostView>`
136
- unless you want an explicit component-based mount point.
61
+ ### 2 Mount the overlay host
137
62
 
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:
63
+ Place `<DigiaHostView>` at the app root so nudge campaigns (bottom sheets, dialogs, tooltips, spotlights) render above all content:
142
64
 
143
65
  ```tsx
144
- import { useNavigationContainerRef } from '@react-navigation/native';
145
- import { Digia } from '@digia/engage-react-native';
66
+ import { StyleSheet, View } from 'react-native';
67
+ import { DigiaHostView } from '@digia-engage/core';
68
+ import { Stack } from 'expo-router';
146
69
 
147
- // Inside your App component:
148
- const navRef = useNavigationContainerRef();
70
+ export default function RootLayout() {
71
+ return (
72
+ <View style={styles.root}>
73
+ <DigiaHostView style={StyleSheet.absoluteFill} />
74
+ <Stack />
75
+ </View>
76
+ );
77
+ }
149
78
 
150
- <NavigationContainer
151
- ref={navRef}
152
- onStateChange={() => {
153
- const currentRoute = navRef.getCurrentRoute();
154
- if (currentRoute) {
155
- Digia.setCurrentScreen(currentRoute.name);
156
- }
157
- }}
158
- >
79
+ const styles = StyleSheet.create({
80
+ root: { flex: 1 },
81
+ });
159
82
  ```
160
83
 
161
- ### 3 – Open the Digia UI navigation flow
84
+ ### 3 – Track screen changes
162
85
 
163
- Launch the full-screen native SDUI stack:
86
+ Wire `setCurrentScreen()` to your navigation library so the SDK can trigger screen-scoped campaigns:
164
87
 
165
88
  ```tsx
166
- import { Digia } from '@digia/engage-react-native';
89
+ import { Digia } from '@digia-engage/core';
167
90
 
168
- function MyScreen() {
169
- return (
170
- <Button
171
- title="Open Digia Experience"
172
- onPress={() => Digia.createInitialPage()}
173
- />
174
- );
175
- }
91
+ // React Navigation example:
92
+ <NavigationContainer
93
+ onStateChange={() => {
94
+ const route = navRef.getCurrentRoute();
95
+ if (route) Digia.setCurrentScreen(route.name);
96
+ }}
97
+ >
176
98
  ```
177
99
 
178
- ### 4 – (Optional) Declarative overlay mount via `<DigiaHostView>`
100
+ ### 4 – Add inline slots
179
101
 
180
- If you prefer an explicit React component instead of the auto-mount, skip the
181
- `initialize()` auto-mount and place `<DigiaHostView>` at the root of your
182
- component tree:
102
+ Place `<DigiaSlotView>` wherever you want inline campaign content (banners, cards):
183
103
 
184
104
  ```tsx
185
- import React from 'react';
186
- import { StyleSheet, View } from 'react-native';
187
- import { DigiaHostView } from '@digia/engage-react-native';
188
-
189
- export default function App() {
190
- return (
191
- <View style={styles.root}>
192
- {/* DigiaHostView must be above all other content in z-order */}
193
- <DigiaHostView style={StyleSheet.absoluteFill} />
105
+ import { DigiaSlotView } from '@digia-engage/core';
194
106
 
195
- {/* Your navigation / content here */}
196
- </View>
197
- );
198
- }
199
-
200
- const styles = StyleSheet.create({ root: { flex: 1 } });
107
+ <DigiaSlotView
108
+ placementKey="home_hero_banner"
109
+ style={{ width: '100%', height: 180 }}
110
+ />
201
111
  ```
202
112
 
203
113
  ---
@@ -208,9 +118,10 @@ const styles = StyleSheet.create({ root: { flex: 1 } });
208
118
 
209
119
  | Method | Signature | Description |
210
120
  |---|---|---|
211
- | `initialize` | `(config: DigiaConfig) => Promise<void>` | Initialise the SDK and mount the Compose overlay host. |
212
- | `setCurrentScreen` | `(name: string) => void` | Notify the SDK of the current screen. |
213
- | `createInitialPage` | `() => void` | Full-screen Digia SDUI (Android: `DigiaUINavigationActivity`; iOS: modal `DigiaNavigationView`). |
121
+ | `initialize` | `(config: DigiaConfig) => Promise<void>` | Initialise the SDK. Call once at app startup. |
122
+ | `register` | `(plugin: DigiaPlugin) => void` | Register a CEP plugin (e.g. `DigiaCleverTapPlugin`). |
123
+ | `unregister` | `(plugin: DigiaPlugin \| string) => void` | Unregister a plugin and call its `teardown()`. |
124
+ | `setCurrentScreen` | `(name: string) => void` | Notify the SDK of the current screen name. |
214
125
 
215
126
  ### `DigiaConfig`
216
127
 
@@ -220,46 +131,22 @@ const styles = StyleSheet.create({ root: { flex: 1 } });
220
131
  | `environment` | `'production' \| 'sandbox'` | `'production'` | Target environment. |
221
132
  | `logLevel` | `'none' \| 'error' \| 'verbose'` | `'error'` | Log verbosity. |
222
133
 
223
- ### `CreateInitialPageOptions`
224
-
225
- Empty interface — reserved for future optional arguments.
226
-
227
134
  ### `<DigiaHostView>`
228
135
 
229
- A transparent React Native view that hosts the Compose overlay anchor.
136
+ Transparent overlay that hosts Digia-rendered campaign UI (dialogs, bottom sheets, tooltips, spotlights) above app content. Mount once at the app root.
230
137
 
231
138
  | Prop | Type | Description |
232
139
  |---|---|---|
233
- | `style` | `ViewStyle?` | Custom style (defaults to `absoluteFill` behaviour). |
140
+ | `style` | `ViewStyle?` | Style for the overlay view. Typically `StyleSheet.absoluteFill`. |
234
141
 
235
- ---
142
+ ### `<DigiaSlotView>`
236
143
 
237
- ## Architecture overview
144
+ Renders inline campaign content (banners, cards) at a named placement. Collapses to zero height when no campaign is active for the slot.
238
145
 
239
- ```
240
- react-native/
241
- ├── src/
242
- │ ├── index.ts ← Public API exports
243
- │ ├── types.ts ← TypeScript interfaces
244
- │ ├── Digia.ts ← High-level JS SDK wrapper
245
- │ ├── NativeDigiaEngage.ts ← Low-level native module binding
246
- │ └── DigiaHostView.tsx ← <DigiaHostView> React component
247
-
248
- ├── android/
249
- │ ├── build.gradle ← Android library build config
250
- │ └── src/main/java/com/digia/engage/rn/
251
- │ ├── DigiaPackage.kt ← ReactPackage (registers module + view)
252
- │ ├── DigiaModule.kt ← NativeModule (initialize, setCurrentScreen, createInitialPage)
253
- │ ├── DigiaViewManager.kt ← ViewManager for <DigiaHostView>
254
- │ └── DigiaHostComposeView.kt ← AbstractComposeView hosting DigiaHost { }
255
-
256
- ├── ios/
257
- │ └── DigiaEngageModule.m ← iOS no-op stub
258
-
259
- ├── DigiaEngageReactNative.podspec
260
- ├── react-native.config.js ← Auto-linking config
261
- └── package.json
262
- ```
146
+ | Prop | Type | Description |
147
+ |---|---|---|
148
+ | `placementKey` | `string` | Must match the placement key in your CEP campaign. |
149
+ | `style` | `ViewStyle?` | An explicit height is required — the slot is not visible without one. |
263
150
 
264
151
  ---
265
152
 
@@ -70,8 +70,7 @@ android {
70
70
  }
71
71
 
72
72
  dependencies {
73
- // Digia Engage Android library
74
- implementation 'tech.digia:engage:1.0.0-beta.04'
73
+ implementation 'tech.digia:engage:1.1.0'
75
74
 
76
75
  // ── React Native ─────────────────────────────────────────────────────────
77
76
  // React Native is provided by the host app; mark as compileOnly so it is
@@ -1 +1 @@
1
- sdk.dir=/Users/ram/Library/Android/sdk
1
+ sdk.dir=/Users/adityachoubey/Library/Android/sdk
@@ -16,8 +16,9 @@ pluginManagement {
16
16
  dependencyResolutionManagement {
17
17
  repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
18
18
  repositories {
19
+ mavenLocal()
19
20
  google()
20
- mavenCentral()
21
+ mavenCentral()
21
22
  }
22
23
  }
23
24
 
@@ -0,0 +1,66 @@
1
+ package com.digia.engage.rn
2
+
3
+ import android.graphics.Color
4
+ import android.graphics.Outline
5
+ import android.view.View
6
+ import android.view.ViewOutlineProvider
7
+ import android.widget.FrameLayout
8
+ import androidx.lifecycle.LifecycleOwner
9
+ import androidx.lifecycle.ViewModelStoreOwner
10
+ import androidx.lifecycle.setViewTreeLifecycleOwner
11
+ import androidx.lifecycle.setViewTreeViewModelStoreOwner
12
+ import androidx.savedstate.SavedStateRegistryOwner
13
+ import androidx.savedstate.setViewTreeSavedStateRegistryOwner
14
+ import com.digia.engage.DigiaAnchorView
15
+ import com.facebook.react.uimanager.ThemedReactContext
16
+ import com.facebook.react.uimanager.ViewGroupManager
17
+ import com.facebook.react.uimanager.annotations.ReactProp
18
+
19
+ internal class DigiaAnchorViewManager : ViewGroupManager<DigiaAnchorView>() {
20
+
21
+ override fun getName(): String = VIEW_NAME
22
+
23
+ override fun createViewInstance(context: ThemedReactContext): DigiaAnchorView {
24
+ val activityContext = context.currentActivity ?: context
25
+ val view = DigiaAnchorView(activityContext)
26
+
27
+ val activity = context.currentActivity
28
+ if (activity is LifecycleOwner) view.setViewTreeLifecycleOwner(activity)
29
+ if (activity is ViewModelStoreOwner) view.setViewTreeViewModelStoreOwner(activity)
30
+ if (activity is SavedStateRegistryOwner) view.setViewTreeSavedStateRegistryOwner(activity)
31
+
32
+ view.layoutParams = FrameLayout.LayoutParams(
33
+ FrameLayout.LayoutParams.WRAP_CONTENT,
34
+ FrameLayout.LayoutParams.WRAP_CONTENT,
35
+ )
36
+ // Prevent the FrameLayout background from leaking white in spotlight corners.
37
+ view.setBackgroundColor(Color.TRANSPARENT)
38
+ return view
39
+ }
40
+
41
+ @ReactProp(name = "anchorKey")
42
+ fun setAnchorKey(view: DigiaAnchorView, anchorKey: String?) {
43
+ view.anchorKey = anchorKey.orEmpty()
44
+ }
45
+
46
+ @ReactProp(name = "cornerRadius", defaultFloat = 0f)
47
+ fun setCornerRadius(view: DigiaAnchorView, cornerRadius: Float) {
48
+ val px = cornerRadius * view.resources.displayMetrics.density
49
+ view.spotlightCornerRadius = px
50
+ if (px > 0f) {
51
+ view.outlineProvider = object : ViewOutlineProvider() {
52
+ override fun getOutline(v: View, outline: Outline) {
53
+ outline.setRoundRect(0, 0, v.width, v.height, px)
54
+ }
55
+ }
56
+ view.clipToOutline = true
57
+ } else {
58
+ view.clipToOutline = false
59
+ view.outlineProvider = ViewOutlineProvider.BOUNDS
60
+ }
61
+ }
62
+
63
+ companion object {
64
+ const val VIEW_NAME = "DigiaAnchorView"
65
+ }
66
+ }
@@ -65,5 +65,6 @@ class DigiaPackage : BaseReactPackage() {
65
65
  listOf(
66
66
  DigiaViewManager(),
67
67
  DigiaSlotViewManager(),
68
+ DigiaAnchorViewManager(),
68
69
  )
69
70
  }
@@ -0,0 +1,43 @@
1
+ import React
2
+ import UIKit
3
+ import DigiaEngage
4
+
5
+ @objc(DigiaAnchorView)
6
+ final class DigiaAnchorViewManager: RCTViewManager {
7
+
8
+ override static func requiresMainQueueSetup() -> Bool { true }
9
+
10
+ override func view() -> UIView! {
11
+ return DigiaAnchorUIView()
12
+ }
13
+
14
+ @objc func setAnchorKey(_ anchorKey: String, forView view: DigiaAnchorUIView) {
15
+ view.anchorKey = anchorKey
16
+ }
17
+ }
18
+
19
+ // MARK: - DigiaAnchorUIView
20
+
21
+ final class DigiaAnchorUIView: UIView {
22
+
23
+ var anchorKey: String = "" {
24
+ didSet {
25
+ guard anchorKey != oldValue else { return }
26
+ if !oldValue.isEmpty {
27
+ AnchorRegistry.shared.unregister(key: oldValue)
28
+ }
29
+ if !anchorKey.isEmpty, window != nil {
30
+ AnchorRegistry.shared.register(key: anchorKey, view: self)
31
+ }
32
+ }
33
+ }
34
+
35
+ override func didMoveToWindow() {
36
+ super.didMoveToWindow()
37
+ if window != nil, !anchorKey.isEmpty {
38
+ AnchorRegistry.shared.register(key: anchorKey, view: self)
39
+ } else if window == nil, !anchorKey.isEmpty {
40
+ AnchorRegistry.shared.unregister(key: anchorKey)
41
+ }
42
+ }
43
+ }
@@ -38,6 +38,14 @@ RCT_EXTERN_METHOD(triggerCampaign:(NSString *)id
38
38
 
39
39
  RCT_EXTERN_METHOD(invalidateCampaign:(NSString *)campaignId)
40
40
 
41
+ RCT_EXTERN_METHOD(showAnchoredOverlay:(NSString *)id
42
+ content:(NSDictionary *)content
43
+ cepContext:(NSDictionary *)cepContext
44
+ anchorX:(double)anchorX
45
+ anchorY:(double)anchorY
46
+ anchorWidth:(double)anchorWidth
47
+ anchorHeight:(double)anchorHeight)
48
+
41
49
  @end
42
50
 
43
51
 
@@ -50,3 +58,7 @@ RCT_EXTERN_METHOD(invalidateCampaign:(NSString *)campaignId)
50
58
  RCT_EXPORT_VIEW_PROPERTY(placementKey, NSString)
51
59
  RCT_EXPORT_VIEW_PROPERTY(onContentSizeChange, RCTDirectEventBlock)
52
60
  @end
61
+
62
+ @interface RCT_EXTERN_MODULE(DigiaAnchorView, RCTViewManager)
63
+ RCT_EXPORT_VIEW_PROPERTY(anchorKey, NSString)
64
+ @end
@@ -151,6 +151,41 @@ final class DigiaModule: RCTEventEmitter {
151
151
  }
152
152
  }
153
153
 
154
+ // ────────────────────────────────────────────────────────────────────────
155
+ // MARK: - showAnchoredOverlay
156
+
157
+ /// Shows SHOW_TOOLTIP or SHOW_SPOTLIGHT anchored to coordinates measured in JS.
158
+ /// anchorX/Y/Width/Height are screen-pixel values from measureInWindow().
159
+ @objc
160
+ func showAnchoredOverlay(
161
+ _ id: String,
162
+ content contentMap: NSDictionary,
163
+ cepContext cepContextMap: NSDictionary,
164
+ anchorX: Double,
165
+ anchorY: Double,
166
+ anchorWidth: Double,
167
+ anchorHeight: Double
168
+ ) {
169
+ let mutable = NSMutableDictionary(dictionary: contentMap)
170
+ // Pack anchor coords into the args sub-dict so buildInAppPayloadContent
171
+ // captures them as JSONValue entries in InAppPayloadContent.args.
172
+ var argsDict = (mutable["args"] as? [String: Any]) ?? [:]
173
+ argsDict["_anchorX"] = anchorX
174
+ argsDict["_anchorY"] = anchorY
175
+ argsDict["_anchorWidth"] = anchorWidth
176
+ argsDict["_anchorHeight"] = anchorHeight
177
+ mutable["args"] = argsDict
178
+
179
+ let content = buildInAppPayloadContent(from: mutable)
180
+ let cepContext = (cepContextMap as? [String: String]) ?? [:]
181
+ let payload = InAppPayload(id: id, content: content, cepContext: cepContext)
182
+
183
+ Task { @MainActor in
184
+ guard let delegate = self.rnPlugin.delegate else { return }
185
+ delegate.onCampaignTriggered(payload)
186
+ }
187
+ }
188
+
154
189
  // ────────────────────────────────────────────────────────────────────────
155
190
  // MARK: - Internal: mount the SwiftUI overlay host
156
191
 
@@ -170,22 +205,34 @@ final class DigiaModule: RCTEventEmitter {
170
205
  let mountTag = 0xD19140
171
206
  if rootVC.view.viewWithTag(mountTag) != nil { return }
172
207
 
208
+ // Container with passthrough hitTest — lets tooltip card taps reach SwiftUI
209
+ // while all other touches fall through to React Native content.
210
+ let container = DigiaPassthroughHostView()
211
+ container.tag = mountTag
212
+ container.translatesAutoresizingMaskIntoConstraints = false
213
+ container.backgroundColor = .clear
214
+
173
215
  let hc = UIHostingController(rootView: DigiaHostWrapperView())
174
- hc.view.tag = mountTag
175
216
  hc.view.translatesAutoresizingMaskIntoConstraints = false
176
217
  hc.view.backgroundColor = .clear
177
- // Pass touches through to React Native content below.
178
- hc.view.isUserInteractionEnabled = false
218
+
219
+ container.hostingView = hc.view
179
220
 
180
221
  rootVC.addChild(hc)
181
- rootVC.view.addSubview(hc.view)
222
+ container.addSubview(hc.view)
182
223
  hc.didMove(toParent: rootVC)
183
224
 
225
+ rootVC.view.addSubview(container)
226
+
184
227
  NSLayoutConstraint.activate([
185
- hc.view.leadingAnchor.constraint(equalTo: rootVC.view.leadingAnchor),
186
- hc.view.trailingAnchor.constraint(equalTo: rootVC.view.trailingAnchor),
187
- hc.view.topAnchor.constraint(equalTo: rootVC.view.topAnchor),
188
- hc.view.bottomAnchor.constraint(equalTo: rootVC.view.bottomAnchor),
228
+ container.leadingAnchor.constraint(equalTo: rootVC.view.leadingAnchor),
229
+ container.trailingAnchor.constraint(equalTo: rootVC.view.trailingAnchor),
230
+ container.topAnchor.constraint(equalTo: rootVC.view.topAnchor),
231
+ container.bottomAnchor.constraint(equalTo: rootVC.view.bottomAnchor),
232
+ hc.view.leadingAnchor.constraint(equalTo: container.leadingAnchor),
233
+ hc.view.trailingAnchor.constraint(equalTo: container.trailingAnchor),
234
+ hc.view.topAnchor.constraint(equalTo: container.topAnchor),
235
+ hc.view.bottomAnchor.constraint(equalTo: container.bottomAnchor),
189
236
  ])
190
237
  }
191
238
 
@@ -208,6 +255,8 @@ final class DigiaModule: RCTEventEmitter {
208
255
  return raw.compactMapValues { JSONValue(rawValue: $0) }
209
256
  }()
210
257
 
258
+ let anchorKey = map["anchorKey"] as? String
259
+
211
260
  return InAppPayloadContent(
212
261
  type: type,
213
262
  placementKey: pk,
@@ -216,11 +265,28 @@ final class DigiaModule: RCTEventEmitter {
216
265
  viewId: viewId,
217
266
  command: command,
218
267
  args: args,
219
- screenId: screenId
268
+ screenId: screenId,
269
+ anchorKey: anchorKey
220
270
  )
221
271
  }
222
272
  }
223
273
 
274
+ // MARK: - DigiaPassthroughHostView
275
+
276
+ /// Container that delegates hitTest to the SwiftUI hosting view.
277
+ /// When SwiftUI renders nothing interactive (no overlay), hitTest returns nil
278
+ /// so touches fall through to React Native. When an overlay is visible,
279
+ /// taps on it are consumed by SwiftUI.
280
+ private final class DigiaPassthroughHostView: UIView {
281
+ weak var hostingView: UIView?
282
+
283
+ override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
284
+ guard let hv = hostingView else { return nil }
285
+ let converted = convert(point, to: hv)
286
+ return hv.hitTest(converted, with: event)
287
+ }
288
+ }
289
+
224
290
  // MARK: - JSONValue convenience init from Any
225
291
  private extension JSONValue {
226
292
  init?(rawValue: Any) {
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.DigiaAnchorView = void 0;
7
+ var _reactNative = require("react-native");
8
+ /**
9
+ * DigiaAnchorView
10
+ *
11
+ * Registers a native Android DigiaAnchorView (FrameLayout) in AnchorRegistry by anchorKey.
12
+ * When a SHOW_TOOLTIP or SHOW_SPOTLIGHT campaign fires, the native SDK looks up this view
13
+ * via AnchorRegistry and uses getLocationOnScreen() for accurate pixel-perfect coordinates.
14
+ *
15
+ * Usage:
16
+ * <DigiaAnchorView anchorKey="pdp_add_to_cart" style={{ alignSelf: 'flex-start' }}>
17
+ * <TouchableOpacity ...>Add to Cart</TouchableOpacity>
18
+ * </DigiaAnchorView>
19
+ */
20
+
21
+ const DigiaAnchorView = exports.DigiaAnchorView = (0, _reactNative.requireNativeComponent)('DigiaAnchorView');
22
+ //# sourceMappingURL=DigiaAnchorView.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_reactNative","require","DigiaAnchorView","exports","requireNativeComponent"],"sourceRoot":"../../src","sources":["DigiaAnchorView.tsx"],"mappings":";;;;;;AAaA,IAAAA,YAAA,GAAAC,OAAA;AAbA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAUO,MAAMC,eAAe,GAAAC,OAAA,CAAAD,eAAA,GAAG,IAAAE,mCAAsB,EAAuB,iBAAiB,CAAC","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"names":["_reactNative","require","_resolved","getModule","TurboModuleRegistry","get","NativeModules","DigiaEngageModule","__DEV__","console","warn","nativeDigiaModule","exports","initialize","apiKey","environment","logLevel","Promise","resolve","registerBridge","setCurrentScreen","name","triggerCampaign","id","content","cepContext","invalidateCampaign","campaignId","getConstants"],"sourceRoot":"../../src","sources":["NativeDigiaEngage.ts"],"mappings":";;;;;;AAgBA,IAAAA,YAAA,GAAAC,OAAA;AAhBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AA8BA;AACA;AACA;AACA;AACA;AACA;AACA,IAAIC,SAAsB,GAAG,IAAI;AACjC,SAASC,SAASA,CAAA,EAAgB;EAC9B,IAAID,SAAS,KAAK,IAAI,EAAE,OAAOA,SAAS;EACxCA,SAAS,GACLE,gCAAmB,CAACC,GAAG,CAAO,mBAAmB,CAAC,IACjDC,0BAAa,CAACC,iBAAsC,IACrD,IAAI;EACR,IAAIC,OAAO,IAAI,CAACN,SAAS,EAAE;IACvBO,OAAO,CAACC,IAAI,CACR,wCAAwC,GACxC,iEACJ,CAAC;EACL;EACA,OAAOR,SAAS;AACpB;AAEO,MAAMS,iBAAuB,GAAAC,OAAA,CAAAD,iBAAA,GAAG;EACnCE,UAAU,EAAEA,CAACC,MAAM,EAAEC,WAAW,EAAEC,QAAQ,KACtCb,SAAS,CAAC,CAAC,EAAEU,UAAU,CAACC,MAAM,EAAEC,WAAW,EAAEC,QAAQ,CAAC,IAAIC,OAAO,CAACC,OAAO,CAAC,CAAC;EAC/EC,cAAc,EAAEA,CAAA,KAAMhB,SAAS,CAAC,CAAC,EAAEgB,cAAc,CAAC,CAAC;EACnDC,gBAAgB,EAAGC,IAAI,IAAKlB,SAAS,CAAC,CAAC,EAAEiB,gBAAgB,CAACC,IAAI,CAAC;EAC/DC,eAAe,EAAEA,CAACC,EAAE,EAAEC,OAAO,EAAEC,UAAU,KACrCtB,SAAS,CAAC,CAAC,EAAEmB,eAAe,CAACC,EAAE,EAAEC,OAAO,EAAEC,UAAU,CAAC;EACzDC,kBAAkB,EAAGC,UAAU,IAAKxB,SAAS,CAAC,CAAC,EAAEuB,kBAAkB,CAACC,UAAU,CAAC;EAC/EC,YAAY,EAAEA,CAAA,KAAMzB,SAAS,CAAC,CAAC,EAAEyB,YAAY,GAAG,CAAC,IAAI,CAAC;AAC1D,CAAC","ignoreList":[]}
1
+ {"version":3,"names":["_reactNative","require","_resolved","getModule","TurboModuleRegistry","get","NativeModules","DigiaEngageModule","__DEV__","console","warn","nativeDigiaModule","exports","initialize","apiKey","environment","logLevel","Promise","resolve","registerBridge","setCurrentScreen","name","triggerCampaign","id","content","cepContext","invalidateCampaign","campaignId","getConstants"],"sourceRoot":"../../src","sources":["NativeDigiaEngage.ts"],"mappings":";;;;;;AAgBA,IAAAA,YAAA,GAAAC,OAAA;AAhBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AA+BA;AACA;AACA;AACA;AACA;AACA;AACA,IAAIC,SAAsB,GAAG,IAAI;AACjC,SAASC,SAASA,CAAA,EAAgB;EAC9B,IAAID,SAAS,KAAK,IAAI,EAAE,OAAOA,SAAS;EACxCA,SAAS,GACLE,gCAAmB,CAACC,GAAG,CAAO,mBAAmB,CAAC,IACjDC,0BAAa,CAACC,iBAAsC,IACrD,IAAI;EACR,IAAIC,OAAO,IAAI,CAACN,SAAS,EAAE;IACvBO,OAAO,CAACC,IAAI,CACR,wCAAwC,GACxC,iEACJ,CAAC;EACL;EACA,OAAOR,SAAS;AACpB;AAEO,MAAMS,iBAAuB,GAAAC,OAAA,CAAAD,iBAAA,GAAG;EACnCE,UAAU,EAAEA,CAACC,MAAM,EAAEC,WAAW,EAAEC,QAAQ,KACtCb,SAAS,CAAC,CAAC,EAAEU,UAAU,CAACC,MAAM,EAAEC,WAAW,EAAEC,QAAQ,CAAC,IAAIC,OAAO,CAACC,OAAO,CAAC,CAAC;EAC/EC,cAAc,EAAEA,CAAA,KAAMhB,SAAS,CAAC,CAAC,EAAEgB,cAAc,CAAC,CAAC;EACnDC,gBAAgB,EAAGC,IAAI,IAAKlB,SAAS,CAAC,CAAC,EAAEiB,gBAAgB,CAACC,IAAI,CAAC;EAC/DC,eAAe,EAAEA,CAACC,EAAE,EAAEC,OAAO,EAAEC,UAAU,KACrCtB,SAAS,CAAC,CAAC,EAAEmB,eAAe,CAACC,EAAE,EAAEC,OAAO,EAAEC,UAAU,CAAC;EACzDC,kBAAkB,EAAGC,UAAU,IAAKxB,SAAS,CAAC,CAAC,EAAEuB,kBAAkB,CAACC,UAAU,CAAC;EAC/EC,YAAY,EAAEA,CAAA,KAAMzB,SAAS,CAAC,CAAC,EAAEyB,YAAY,GAAG,CAAC,IAAI,CAAC;AAC1D,CAAC","ignoreList":[]}
@@ -9,6 +9,12 @@ Object.defineProperty(exports, "Digia", {
9
9
  return _Digia.Digia;
10
10
  }
11
11
  });
12
+ Object.defineProperty(exports, "DigiaAnchorView", {
13
+ enumerable: true,
14
+ get: function () {
15
+ return _DigiaAnchorView.DigiaAnchorView;
16
+ }
17
+ });
12
18
  Object.defineProperty(exports, "DigiaHostView", {
13
19
  enumerable: true,
14
20
  get: function () {
@@ -24,4 +30,5 @@ Object.defineProperty(exports, "DigiaSlotView", {
24
30
  var _Digia = require("./Digia");
25
31
  var _DigiaHostView = require("./DigiaHostView");
26
32
  var _DigiaSlotView = require("./DigiaSlotView");
33
+ var _DigiaAnchorView = require("./DigiaAnchorView");
27
34
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["_Digia","require","_DigiaHostView","_DigiaSlotView"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAWA,IAAAA,MAAA,GAAAC,OAAA;AACA,IAAAC,cAAA,GAAAD,OAAA;AACA,IAAAE,cAAA,GAAAF,OAAA","ignoreList":[]}
1
+ {"version":3,"names":["_Digia","require","_DigiaHostView","_DigiaSlotView","_DigiaAnchorView"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAWA,IAAAA,MAAA,GAAAC,OAAA;AACA,IAAAC,cAAA,GAAAD,OAAA;AACA,IAAAE,cAAA,GAAAF,OAAA;AACA,IAAAG,gBAAA,GAAAH,OAAA","ignoreList":[]}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * DigiaAnchorView
3
+ *
4
+ * Registers a native Android DigiaAnchorView (FrameLayout) in AnchorRegistry by anchorKey.
5
+ * When a SHOW_TOOLTIP or SHOW_SPOTLIGHT campaign fires, the native SDK looks up this view
6
+ * via AnchorRegistry and uses getLocationOnScreen() for accurate pixel-perfect coordinates.
7
+ *
8
+ * Usage:
9
+ * <DigiaAnchorView anchorKey="pdp_add_to_cart" style={{ alignSelf: 'flex-start' }}>
10
+ * <TouchableOpacity ...>Add to Cart</TouchableOpacity>
11
+ * </DigiaAnchorView>
12
+ */
13
+
14
+ import { requireNativeComponent } from 'react-native';
15
+ export const DigiaAnchorView = requireNativeComponent('DigiaAnchorView');
16
+ //# sourceMappingURL=DigiaAnchorView.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["requireNativeComponent","DigiaAnchorView"],"sourceRoot":"../../src","sources":["DigiaAnchorView.tsx"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,SAASA,sBAAsB,QAAwB,cAAc;AAQrE,OAAO,MAAMC,eAAe,GAAGD,sBAAsB,CAAuB,iBAAiB,CAAC","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"names":["NativeModules","TurboModuleRegistry","_resolved","getModule","get","DigiaEngageModule","__DEV__","console","warn","nativeDigiaModule","initialize","apiKey","environment","logLevel","Promise","resolve","registerBridge","setCurrentScreen","name","triggerCampaign","id","content","cepContext","invalidateCampaign","campaignId","getConstants"],"sourceRoot":"../../src","sources":["NativeDigiaEngage.ts"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,SAASA,aAAa,EAAEC,mBAAmB,QAAQ,cAAc;;AAEjE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AA8BA;AACA;AACA;AACA;AACA;AACA;AACA,IAAIC,SAAsB,GAAG,IAAI;AACjC,SAASC,SAASA,CAAA,EAAgB;EAC9B,IAAID,SAAS,KAAK,IAAI,EAAE,OAAOA,SAAS;EACxCA,SAAS,GACLD,mBAAmB,CAACG,GAAG,CAAO,mBAAmB,CAAC,IACjDJ,aAAa,CAACK,iBAAsC,IACrD,IAAI;EACR,IAAIC,OAAO,IAAI,CAACJ,SAAS,EAAE;IACvBK,OAAO,CAACC,IAAI,CACR,wCAAwC,GACxC,iEACJ,CAAC;EACL;EACA,OAAON,SAAS;AACpB;AAEA,OAAO,MAAMO,iBAAuB,GAAG;EACnCC,UAAU,EAAEA,CAACC,MAAM,EAAEC,WAAW,EAAEC,QAAQ,KACtCV,SAAS,CAAC,CAAC,EAAEO,UAAU,CAACC,MAAM,EAAEC,WAAW,EAAEC,QAAQ,CAAC,IAAIC,OAAO,CAACC,OAAO,CAAC,CAAC;EAC/EC,cAAc,EAAEA,CAAA,KAAMb,SAAS,CAAC,CAAC,EAAEa,cAAc,CAAC,CAAC;EACnDC,gBAAgB,EAAGC,IAAI,IAAKf,SAAS,CAAC,CAAC,EAAEc,gBAAgB,CAACC,IAAI,CAAC;EAC/DC,eAAe,EAAEA,CAACC,EAAE,EAAEC,OAAO,EAAEC,UAAU,KACrCnB,SAAS,CAAC,CAAC,EAAEgB,eAAe,CAACC,EAAE,EAAEC,OAAO,EAAEC,UAAU,CAAC;EACzDC,kBAAkB,EAAGC,UAAU,IAAKrB,SAAS,CAAC,CAAC,EAAEoB,kBAAkB,CAACC,UAAU,CAAC;EAC/EC,YAAY,EAAEA,CAAA,KAAMtB,SAAS,CAAC,CAAC,EAAEsB,YAAY,GAAG,CAAC,IAAI,CAAC;AAC1D,CAAC","ignoreList":[]}
1
+ {"version":3,"names":["NativeModules","TurboModuleRegistry","_resolved","getModule","get","DigiaEngageModule","__DEV__","console","warn","nativeDigiaModule","initialize","apiKey","environment","logLevel","Promise","resolve","registerBridge","setCurrentScreen","name","triggerCampaign","id","content","cepContext","invalidateCampaign","campaignId","getConstants"],"sourceRoot":"../../src","sources":["NativeDigiaEngage.ts"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,SAASA,aAAa,EAAEC,mBAAmB,QAAQ,cAAc;;AAEjE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AA+BA;AACA;AACA;AACA;AACA;AACA;AACA,IAAIC,SAAsB,GAAG,IAAI;AACjC,SAASC,SAASA,CAAA,EAAgB;EAC9B,IAAID,SAAS,KAAK,IAAI,EAAE,OAAOA,SAAS;EACxCA,SAAS,GACLD,mBAAmB,CAACG,GAAG,CAAO,mBAAmB,CAAC,IACjDJ,aAAa,CAACK,iBAAsC,IACrD,IAAI;EACR,IAAIC,OAAO,IAAI,CAACJ,SAAS,EAAE;IACvBK,OAAO,CAACC,IAAI,CACR,wCAAwC,GACxC,iEACJ,CAAC;EACL;EACA,OAAON,SAAS;AACpB;AAEA,OAAO,MAAMO,iBAAuB,GAAG;EACnCC,UAAU,EAAEA,CAACC,MAAM,EAAEC,WAAW,EAAEC,QAAQ,KACtCV,SAAS,CAAC,CAAC,EAAEO,UAAU,CAACC,MAAM,EAAEC,WAAW,EAAEC,QAAQ,CAAC,IAAIC,OAAO,CAACC,OAAO,CAAC,CAAC;EAC/EC,cAAc,EAAEA,CAAA,KAAMb,SAAS,CAAC,CAAC,EAAEa,cAAc,CAAC,CAAC;EACnDC,gBAAgB,EAAGC,IAAI,IAAKf,SAAS,CAAC,CAAC,EAAEc,gBAAgB,CAACC,IAAI,CAAC;EAC/DC,eAAe,EAAEA,CAACC,EAAE,EAAEC,OAAO,EAAEC,UAAU,KACrCnB,SAAS,CAAC,CAAC,EAAEgB,eAAe,CAACC,EAAE,EAAEC,OAAO,EAAEC,UAAU,CAAC;EACzDC,kBAAkB,EAAGC,UAAU,IAAKrB,SAAS,CAAC,CAAC,EAAEoB,kBAAkB,CAACC,UAAU,CAAC;EAC/EC,YAAY,EAAEA,CAAA,KAAMtB,SAAS,CAAC,CAAC,EAAEsB,YAAY,GAAG,CAAC,IAAI,CAAC;AAC1D,CAAC","ignoreList":[]}
@@ -12,4 +12,5 @@
12
12
  export { Digia } from './Digia';
13
13
  export { DigiaHostView } from './DigiaHostView';
14
14
  export { DigiaSlotView } from './DigiaSlotView';
15
+ export { DigiaAnchorView } from './DigiaAnchorView';
15
16
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["Digia","DigiaHostView","DigiaSlotView"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,SAASA,KAAK,QAAQ,SAAS;AAC/B,SAASC,aAAa,QAAQ,iBAAiB;AAC/C,SAASC,aAAa,QAAQ,iBAAiB","ignoreList":[]}
1
+ {"version":3,"names":["Digia","DigiaHostView","DigiaSlotView","DigiaAnchorView"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,SAASA,KAAK,QAAQ,SAAS;AAC/B,SAASC,aAAa,QAAQ,iBAAiB;AAC/C,SAASC,aAAa,QAAQ,iBAAiB;AAC/C,SAASC,eAAe,QAAQ,mBAAmB","ignoreList":[]}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * DigiaAnchorView
3
+ *
4
+ * Registers a native Android DigiaAnchorView (FrameLayout) in AnchorRegistry by anchorKey.
5
+ * When a SHOW_TOOLTIP or SHOW_SPOTLIGHT campaign fires, the native SDK looks up this view
6
+ * via AnchorRegistry and uses getLocationOnScreen() for accurate pixel-perfect coordinates.
7
+ *
8
+ * Usage:
9
+ * <DigiaAnchorView anchorKey="pdp_add_to_cart" style={{ alignSelf: 'flex-start' }}>
10
+ * <TouchableOpacity ...>Add to Cart</TouchableOpacity>
11
+ * </DigiaAnchorView>
12
+ */
13
+ import { type ViewProps } from 'react-native';
14
+ interface DigiaAnchorViewProps extends ViewProps {
15
+ anchorKey: string;
16
+ /** Corner radius in dp — used to round the spotlight cutout to match the wrapped button. */
17
+ cornerRadius?: number;
18
+ }
19
+ export declare const DigiaAnchorView: import("react-native").HostComponent<DigiaAnchorViewProps>;
20
+ export {};
21
+ //# sourceMappingURL=DigiaAnchorView.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DigiaAnchorView.d.ts","sourceRoot":"","sources":["../../src/DigiaAnchorView.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAA0B,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAEtE,UAAU,oBAAqB,SAAQ,SAAS;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,4FAA4F;IAC5F,YAAY,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,eAAO,MAAM,eAAe,4DAAkE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"NativeDigiaEngage.d.ts","sourceRoot":"","sources":["../../src/NativeDigiaEngage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD;;;;;;;GAOG;AACH,MAAM,WAAW,IAAK,SAAQ,WAAW;IACrC,0DAA0D;IAC1D,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjF;;;;OAIG;IACH,cAAc,IAAI,IAAI,CAAC;IAEvB,sDAAsD;IACtD,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAErC;;;OAGG;IACH,eAAe,CACX,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,GACnB,IAAI,CAAC;IAER,iDAAiD;IACjD,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAEhD;AAwBD,eAAO,MAAM,iBAAiB,EAAE,IAS/B,CAAC"}
1
+ {"version":3,"file":"NativeDigiaEngage.d.ts","sourceRoot":"","sources":["../../src/NativeDigiaEngage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD;;;;;;;GAOG;AACH,MAAM,WAAW,IAAK,SAAQ,WAAW;IACrC,0DAA0D;IAC1D,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjF;;;;OAIG;IACH,cAAc,IAAI,IAAI,CAAC;IAEvB,sDAAsD;IACtD,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAErC;;;OAGG;IACH,eAAe,CACX,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,GACnB,IAAI,CAAC;IAER,iDAAiD;IACjD,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAEhD;AAyBD,eAAO,MAAM,iBAAiB,EAAE,IAS/B,CAAC"}
@@ -11,5 +11,6 @@
11
11
  export { Digia } from './Digia';
12
12
  export { DigiaHostView } from './DigiaHostView';
13
13
  export { DigiaSlotView } from './DigiaSlotView';
14
+ export { DigiaAnchorView } from './DigiaAnchorView';
14
15
  export type { DigiaConfig, DigiaDelegate, DigiaExperienceEvent, DigiaPlugin, InAppPayload } from './types';
15
16
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,oBAAoB,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,oBAAoB,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@digia-engage/core",
3
- "version": "1.0.0",
3
+ "version": "1.1.1",
4
4
  "description": "React Native bridge for Digia Engage – renders native Android Compose UI inside React Native apps",
5
5
  "main": "src/index.ts",
6
6
  "module": "src/index.ts",
@@ -13,6 +13,7 @@
13
13
  "android",
14
14
  "ios",
15
15
  "*.podspec",
16
+ "react-native.config.js",
16
17
  "!lib/typescript/example",
17
18
  "!android/.gradle",
18
19
  "!android/build",
@@ -0,0 +1,23 @@
1
+ /**
2
+ * react-native.config.js
3
+ *
4
+ * Configures React Native CLI auto-linking for @digia/engage-react-native.
5
+ * This tells the RN CLI where to find the Android library module and the
6
+ * iOS podspec so that `npx react-native link` / auto-linking works without
7
+ * any manual steps in host app project files.
8
+ */
9
+ module.exports = {
10
+ dependency: {
11
+ platforms: {
12
+ android: {
13
+ // Path to the Android library module (relative to this package root)
14
+ sourceDir: './android',
15
+ packageImportPath: 'import com.digia.engage.rn.DigiaPackage;',
16
+ packageInstance: 'new DigiaPackage()',
17
+ },
18
+ ios: {
19
+ podspecPath: './DigiaEngageReactNative.podspec',
20
+ },
21
+ },
22
+ },
23
+ };
@@ -0,0 +1,22 @@
1
+ /**
2
+ * DigiaAnchorView
3
+ *
4
+ * Registers a native Android DigiaAnchorView (FrameLayout) in AnchorRegistry by anchorKey.
5
+ * When a SHOW_TOOLTIP or SHOW_SPOTLIGHT campaign fires, the native SDK looks up this view
6
+ * via AnchorRegistry and uses getLocationOnScreen() for accurate pixel-perfect coordinates.
7
+ *
8
+ * Usage:
9
+ * <DigiaAnchorView anchorKey="pdp_add_to_cart" style={{ alignSelf: 'flex-start' }}>
10
+ * <TouchableOpacity ...>Add to Cart</TouchableOpacity>
11
+ * </DigiaAnchorView>
12
+ */
13
+
14
+ import { requireNativeComponent, type ViewProps } from 'react-native';
15
+
16
+ interface DigiaAnchorViewProps extends ViewProps {
17
+ anchorKey: string;
18
+ /** Corner radius in dp — used to round the spotlight cutout to match the wrapped button. */
19
+ cornerRadius?: number;
20
+ }
21
+
22
+ export const DigiaAnchorView = requireNativeComponent<DigiaAnchorViewProps>('DigiaAnchorView');
@@ -53,6 +53,7 @@ export interface Spec extends TurboModule {
53
53
 
54
54
  }
55
55
 
56
+
56
57
  // Try TurboModuleRegistry first (New Architecture / JSI).
57
58
  // Fall back to NativeModules (bridge interop layer — enabled by default in
58
59
  // RN 0.73+ New Architecture when the module is registered with
package/src/index.ts CHANGED
@@ -12,4 +12,5 @@
12
12
  export { Digia } from './Digia';
13
13
  export { DigiaHostView } from './DigiaHostView';
14
14
  export { DigiaSlotView } from './DigiaSlotView';
15
+ export { DigiaAnchorView } from './DigiaAnchorView';
15
16
  export type { DigiaConfig, DigiaDelegate, DigiaExperienceEvent, DigiaPlugin, InAppPayload } from './types';
package/android/.project DELETED
@@ -1,28 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <projectDescription>
3
- <name>digia-engage_core</name>
4
- <comment>Project digia-engage_core created by Buildship.</comment>
5
- <projects>
6
- </projects>
7
- <buildSpec>
8
- <buildCommand>
9
- <name>org.eclipse.buildship.core.gradleprojectbuilder</name>
10
- <arguments>
11
- </arguments>
12
- </buildCommand>
13
- </buildSpec>
14
- <natures>
15
- <nature>org.eclipse.buildship.core.gradleprojectnature</nature>
16
- </natures>
17
- <filteredResources>
18
- <filter>
19
- <id>1775559486270</id>
20
- <name></name>
21
- <type>30</type>
22
- <matcher>
23
- <id>org.eclipse.core.resources.regexFilterMatcher</id>
24
- <arguments>node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__</arguments>
25
- </matcher>
26
- </filter>
27
- </filteredResources>
28
- </projectDescription>