rampkit-expo-dev 0.0.77 → 0.0.78

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.
@@ -1041,6 +1041,84 @@ function Overlay(props) {
1041
1041
  const screenActivationTimeRef = (0, react_1.useRef)({ 0: Date.now() });
1042
1042
  // Settling period - ignore variable updates from a screen for this long after activation
1043
1043
  const SCREEN_SETTLING_MS = 300;
1044
+ // Queue of pending actions per screen - actions are queued when screen is inactive
1045
+ // and executed when the screen becomes active (matches iOS SDK behavior)
1046
+ const pendingActionsRef = (0, react_1.useRef)({});
1047
+ // Check if a screen is currently active
1048
+ const isScreenActive = (screenIndex) => {
1049
+ return screenIndex === activeScreenIndexRef.current;
1050
+ };
1051
+ // Queue an action to be executed when screen becomes active
1052
+ const queueAction = (screenIndex, action) => {
1053
+ if (__DEV__) {
1054
+ console.log(`[Rampkit] 📥 Queuing action for screen ${screenIndex}`);
1055
+ }
1056
+ if (!pendingActionsRef.current[screenIndex]) {
1057
+ pendingActionsRef.current[screenIndex] = [];
1058
+ }
1059
+ pendingActionsRef.current[screenIndex].push(action);
1060
+ };
1061
+ // Process any pending actions for a screen
1062
+ const processPendingActions = (screenIndex) => {
1063
+ const actions = pendingActionsRef.current[screenIndex];
1064
+ if (!actions || actions.length === 0)
1065
+ return;
1066
+ if (__DEV__) {
1067
+ console.log(`[Rampkit] ⚡ Processing ${actions.length} pending action(s) for screen ${screenIndex}`);
1068
+ }
1069
+ for (const action of actions) {
1070
+ try {
1071
+ action();
1072
+ }
1073
+ catch (e) {
1074
+ console.warn('[Rampkit] Error executing pending action:', e);
1075
+ }
1076
+ }
1077
+ // Clear the queue
1078
+ pendingActionsRef.current[screenIndex] = [];
1079
+ };
1080
+ // Activate a screen (set visibility flag and dispatch event)
1081
+ const activateScreen = (screenIndex) => {
1082
+ var _a;
1083
+ const wv = webviewsRef.current[screenIndex];
1084
+ if (!wv)
1085
+ return;
1086
+ if (__DEV__) {
1087
+ console.log(`[Rampkit] 🔓 Activating screen ${screenIndex}`);
1088
+ }
1089
+ const screenId = ((_a = props.screens[screenIndex]) === null || _a === void 0 ? void 0 : _a.id) || '';
1090
+ const activateScript = `(function() {
1091
+ window.__rampkitScreenVisible = true;
1092
+ window.__rampkitScreenIndex = ${screenIndex};
1093
+ console.log('🔓 Screen ${screenIndex} ACTIVATED');
1094
+
1095
+ // Dispatch custom event that HTML can listen to
1096
+ try {
1097
+ document.dispatchEvent(new CustomEvent('rampkit:screen-visible', {
1098
+ detail: { screenIndex: ${screenIndex}, screenId: '${screenId}' }
1099
+ }));
1100
+ } catch(e) {}
1101
+ })();`;
1102
+ // @ts-ignore: injectJavaScript exists on WebView instance
1103
+ wv.injectJavaScript(activateScript);
1104
+ // Process any pending actions for this screen
1105
+ processPendingActions(screenIndex);
1106
+ };
1107
+ // Deactivate a screen (clear visibility flag)
1108
+ const deactivateScreen = (screenIndex) => {
1109
+ const wv = webviewsRef.current[screenIndex];
1110
+ if (!wv)
1111
+ return;
1112
+ if (__DEV__) {
1113
+ console.log(`[Rampkit] 🔒 Deactivating screen ${screenIndex}`);
1114
+ }
1115
+ const deactivateScript = `(function() {
1116
+ window.__rampkitScreenVisible = false;
1117
+ console.log('🔒 Screen ${screenIndex} DEACTIVATED');
1118
+ })();`;
1119
+ // @ts-ignore: injectJavaScript exists on WebView instance
1120
+ wv.injectJavaScript(deactivateScript);
1121
+ };
1044
1122
  // ============================================================================
1045
1123
  // Navigation Resolution Helpers (matches iOS SDK behavior)
1046
1124
  // ============================================================================
@@ -1208,8 +1286,14 @@ function Overlay(props) {
1208
1286
  (_a = props.onRegisterClose) === null || _a === void 0 ? void 0 : _a.call(props, null);
1209
1287
  };
1210
1288
  }, [handleRequestClose, props.onRegisterClose]);
1211
- // Helper to complete a screen transition - updates state and sends data
1212
- const completeTransition = (nextIndex) => {
1289
+ // Helper to complete a screen transition - updates state, activates/deactivates screens, and sends data
1290
+ const completeTransition = (nextIndex, prevIndex) => {
1291
+ // Deactivate previous screen and activate new screen (matches iOS SDK behavior)
1292
+ // This ensures actions like review/notification requests only fire on the active screen
1293
+ if (prevIndex !== nextIndex) {
1294
+ deactivateScreen(prevIndex);
1295
+ activateScreen(nextIndex);
1296
+ }
1213
1297
  setIndex(nextIndex);
1214
1298
  sendVarsToWebView(nextIndex);
1215
1299
  sendOnboardingStateToWebView(nextIndex);
@@ -1264,7 +1348,7 @@ function Overlay(props) {
1264
1348
  // Hide old screen and reset its position
1265
1349
  currentScreenAnim.opacity.setValue(0);
1266
1350
  currentScreenAnim.translateX.setValue(0);
1267
- completeTransition(nextIndex);
1351
+ completeTransition(nextIndex, index);
1268
1352
  setIsTransitioning(false);
1269
1353
  });
1270
1354
  return;
@@ -1307,7 +1391,7 @@ function Overlay(props) {
1307
1391
  ]).start(() => {
1308
1392
  // Reset old screen position
1309
1393
  currentScreenAnim.translateX.setValue(0);
1310
- completeTransition(nextIndex);
1394
+ completeTransition(nextIndex, index);
1311
1395
  setIsTransitioning(false);
1312
1396
  });
1313
1397
  return;
@@ -1324,7 +1408,7 @@ function Overlay(props) {
1324
1408
  currentScreenAnim.opacity.setValue(0);
1325
1409
  nextScreenAnim.opacity.setValue(1);
1326
1410
  requestAnimationFrame(() => {
1327
- completeTransition(nextIndex);
1411
+ completeTransition(nextIndex, index);
1328
1412
  // Fade curtain out to reveal new screen
1329
1413
  react_native_1.Animated.timing(fadeOpacity, {
1330
1414
  toValue: 0,
@@ -1661,6 +1745,25 @@ function Overlay(props) {
1661
1745
  // By sending state to all screens upfront, the DOM is already in its final state
1662
1746
  // before any navigation occurs.
1663
1747
  sendOnboardingStateToWebView(i);
1748
+ // Set initial visibility flag (matches iOS SDK behavior).
1749
+ // Only screen 0 starts as active - all others start inactive.
1750
+ // This prevents actions like review requests from firing on all screens at startup.
1751
+ if (i === 0) {
1752
+ // First screen is immediately active
1753
+ activateScreen(i);
1754
+ }
1755
+ else {
1756
+ // Other screens start inactive - inject the flag but don't dispatch event
1757
+ const wv = webviewsRef.current[i];
1758
+ if (wv) {
1759
+ // @ts-ignore: injectJavaScript exists on WebView instance
1760
+ wv.injectJavaScript(`(function() {
1761
+ window.__rampkitScreenVisible = false;
1762
+ window.__rampkitScreenIndex = ${i};
1763
+ console.log('🔒 Screen ${i} loaded but INACTIVE');
1764
+ })();`);
1765
+ }
1766
+ }
1664
1767
  }, onMessage: (ev) => {
1665
1768
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
1666
1769
  const raw = ev.nativeEvent.data;
@@ -1746,7 +1849,7 @@ function Overlay(props) {
1746
1849
  // 3) A page requested an in-app review prompt
1747
1850
  if ((data === null || data === void 0 ? void 0 : data.type) === "rampkit:request-review" ||
1748
1851
  (data === null || data === void 0 ? void 0 : data.type) === "rampkit:review") {
1749
- (async () => {
1852
+ const executeReview = async () => {
1750
1853
  try {
1751
1854
  const available = await RampKitNative_1.StoreReview.isAvailableAsync();
1752
1855
  if (available) {
@@ -1754,16 +1857,36 @@ function Overlay(props) {
1754
1857
  }
1755
1858
  }
1756
1859
  catch (_) { }
1757
- })();
1860
+ };
1861
+ // Only execute if screen is active, otherwise queue for later
1862
+ if (isScreenActive(i)) {
1863
+ executeReview();
1864
+ }
1865
+ else {
1866
+ if (__DEV__)
1867
+ console.log(`[Rampkit] Queuing review request from inactive screen ${i}`);
1868
+ queueAction(i, executeReview);
1869
+ }
1758
1870
  return;
1759
1871
  }
1760
1872
  // 4) A page requested notification permission
1761
1873
  if ((data === null || data === void 0 ? void 0 : data.type) === "rampkit:request-notification-permission") {
1762
- handleNotificationPermissionRequest({
1763
- ios: data === null || data === void 0 ? void 0 : data.ios,
1764
- android: data === null || data === void 0 ? void 0 : data.android,
1765
- behavior: data === null || data === void 0 ? void 0 : data.behavior,
1766
- });
1874
+ const executeNotification = () => {
1875
+ handleNotificationPermissionRequest({
1876
+ ios: data === null || data === void 0 ? void 0 : data.ios,
1877
+ android: data === null || data === void 0 ? void 0 : data.android,
1878
+ behavior: data === null || data === void 0 ? void 0 : data.behavior,
1879
+ });
1880
+ };
1881
+ // Only execute if screen is active, otherwise queue for later
1882
+ if (isScreenActive(i)) {
1883
+ executeNotification();
1884
+ }
1885
+ else {
1886
+ if (__DEV__)
1887
+ console.log(`[Rampkit] Queuing notification request from inactive screen ${i}`);
1888
+ queueAction(i, executeNotification);
1889
+ }
1767
1890
  return;
1768
1891
  }
1769
1892
  // 5) Onboarding finished event from page
@@ -1850,7 +1973,7 @@ function Overlay(props) {
1850
1973
  return;
1851
1974
  }
1852
1975
  if (raw === "rampkit:request-review" || raw === "rampkit:review") {
1853
- (async () => {
1976
+ const executeReview = async () => {
1854
1977
  try {
1855
1978
  const available = await RampKitNative_1.StoreReview.isAvailableAsync();
1856
1979
  if (available) {
@@ -1858,11 +1981,29 @@ function Overlay(props) {
1858
1981
  }
1859
1982
  }
1860
1983
  catch (_) { }
1861
- })();
1984
+ };
1985
+ // Only execute if screen is active, otherwise queue for later
1986
+ if (isScreenActive(i)) {
1987
+ executeReview();
1988
+ }
1989
+ else {
1990
+ if (__DEV__)
1991
+ console.log(`[Rampkit] Queuing review request (raw) from inactive screen ${i}`);
1992
+ queueAction(i, executeReview);
1993
+ }
1862
1994
  return;
1863
1995
  }
1864
1996
  if (raw === "rampkit:request-notification-permission") {
1865
- handleNotificationPermissionRequest(undefined);
1997
+ const executeNotification = () => handleNotificationPermissionRequest(undefined);
1998
+ // Only execute if screen is active, otherwise queue for later
1999
+ if (isScreenActive(i)) {
2000
+ executeNotification();
2001
+ }
2002
+ else {
2003
+ if (__DEV__)
2004
+ console.log(`[Rampkit] Queuing notification request (raw) from inactive screen ${i}`);
2005
+ queueAction(i, executeNotification);
2006
+ }
1866
2007
  return;
1867
2008
  }
1868
2009
  if (raw === "rampkit:onboarding-finished") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rampkit-expo-dev",
3
- "version": "0.0.77",
3
+ "version": "0.0.78",
4
4
  "description": "The Expo SDK for RampKit. Build, test, and personalize app onboardings with instant updates.",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",