rampkit-expo-dev 0.0.76 → 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.
- package/build/RampkitOverlay.js +263 -118
- package/package.json +1 -1
package/build/RampkitOverlay.js
CHANGED
|
@@ -45,7 +45,8 @@ const jsx_runtime_1 = require("react/jsx-runtime");
|
|
|
45
45
|
const react_1 = __importStar(require("react"));
|
|
46
46
|
const react_native_1 = require("react-native");
|
|
47
47
|
const react_native_root_siblings_1 = __importDefault(require("react-native-root-siblings"));
|
|
48
|
-
|
|
48
|
+
// PagerView removed - we now render all screens in a stack to ensure first paint completes
|
|
49
|
+
// before any navigation. This fixes the "glitch on first open" bug.
|
|
49
50
|
const react_native_webview_1 = require("react-native-webview");
|
|
50
51
|
const RampKitNative_1 = require("./RampKitNative");
|
|
51
52
|
const OnboardingResponseStorage_1 = require("./OnboardingResponseStorage");
|
|
@@ -1004,7 +1005,6 @@ const SLIDE_FADE_DURATION = 320;
|
|
|
1004
1005
|
function Overlay(props) {
|
|
1005
1006
|
// Get explicit window dimensions to prevent flex-based layout recalculations during transitions
|
|
1006
1007
|
const { width: windowWidth, height: windowHeight } = (0, react_native_1.useWindowDimensions)();
|
|
1007
|
-
const pagerRef = (0, react_1.useRef)(null);
|
|
1008
1008
|
const [index, setIndex] = (0, react_1.useState)(0);
|
|
1009
1009
|
const [loadedCount, setLoadedCount] = (0, react_1.useState)(0);
|
|
1010
1010
|
const [firstPageLoaded, setFirstPageLoaded] = (0, react_1.useState)(false);
|
|
@@ -1014,9 +1014,14 @@ function Overlay(props) {
|
|
|
1014
1014
|
const [onboardingCompleted, setOnboardingCompleted] = (0, react_1.useState)(false);
|
|
1015
1015
|
const overlayOpacity = (0, react_1.useRef)(new react_native_1.Animated.Value(0)).current;
|
|
1016
1016
|
const fadeOpacity = (0, react_1.useRef)(new react_native_1.Animated.Value(0)).current;
|
|
1017
|
-
//
|
|
1018
|
-
|
|
1019
|
-
|
|
1017
|
+
// Per-screen animation values - each screen has its own opacity and translateX
|
|
1018
|
+
// This replaces PagerView and ensures ALL screens are rendered (forcing first paint)
|
|
1019
|
+
// First screen starts visible (opacity: 1), others start hidden (opacity: 0)
|
|
1020
|
+
const screenAnimsRef = (0, react_1.useRef)(props.screens.map((_, i) => ({
|
|
1021
|
+
opacity: new react_native_1.Animated.Value(i === 0 ? 1 : 0),
|
|
1022
|
+
translateX: new react_native_1.Animated.Value(0),
|
|
1023
|
+
})));
|
|
1024
|
+
const screenAnims = screenAnimsRef.current;
|
|
1020
1025
|
const allLoaded = loadedCount >= props.screens.length;
|
|
1021
1026
|
const hasTrackedInitialScreen = (0, react_1.useRef)(false);
|
|
1022
1027
|
// shared vars across all webviews - INITIALIZE from props.variables!
|
|
@@ -1036,6 +1041,84 @@ function Overlay(props) {
|
|
|
1036
1041
|
const screenActivationTimeRef = (0, react_1.useRef)({ 0: Date.now() });
|
|
1037
1042
|
// Settling period - ignore variable updates from a screen for this long after activation
|
|
1038
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
|
+
};
|
|
1039
1122
|
// ============================================================================
|
|
1040
1123
|
// Navigation Resolution Helpers (matches iOS SDK behavior)
|
|
1041
1124
|
// ============================================================================
|
|
@@ -1203,7 +1286,26 @@ function Overlay(props) {
|
|
|
1203
1286
|
(_a = props.onRegisterClose) === null || _a === void 0 ? void 0 : _a.call(props, null);
|
|
1204
1287
|
};
|
|
1205
1288
|
}, [handleRequestClose, props.onRegisterClose]);
|
|
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
|
+
}
|
|
1297
|
+
setIndex(nextIndex);
|
|
1298
|
+
sendVarsToWebView(nextIndex);
|
|
1299
|
+
sendOnboardingStateToWebView(nextIndex);
|
|
1300
|
+
// Track screen change event
|
|
1301
|
+
if (props.onScreenChange && props.screens[nextIndex]) {
|
|
1302
|
+
props.onScreenChange(nextIndex, props.screens[nextIndex].id);
|
|
1303
|
+
}
|
|
1304
|
+
};
|
|
1206
1305
|
// Android hardware back goes to previous page, then closes
|
|
1306
|
+
// NOTE: This function no longer uses PagerView. Instead, all screens are rendered
|
|
1307
|
+
// in a stack and we animate individual screen opacity/transform values.
|
|
1308
|
+
// This ensures all WebViews complete their first paint before any navigation.
|
|
1207
1309
|
const navigateToIndex = (nextIndex, animation = "fade") => {
|
|
1208
1310
|
if (nextIndex === index ||
|
|
1209
1311
|
nextIndex < 0 ||
|
|
@@ -1211,108 +1313,103 @@ function Overlay(props) {
|
|
|
1211
1313
|
return;
|
|
1212
1314
|
if (isTransitioning)
|
|
1213
1315
|
return;
|
|
1316
|
+
// Update active screen index and activation time FIRST
|
|
1317
|
+
activeScreenIndexRef.current = nextIndex;
|
|
1318
|
+
screenActivationTimeRef.current[nextIndex] = Date.now();
|
|
1214
1319
|
// Parse animation type case-insensitively
|
|
1215
1320
|
const animationType = (animation === null || animation === void 0 ? void 0 : animation.toLowerCase()) || "fade";
|
|
1216
|
-
|
|
1217
|
-
|
|
1321
|
+
const currentScreenAnim = screenAnims[index];
|
|
1322
|
+
const nextScreenAnim = screenAnims[nextIndex];
|
|
1323
|
+
const isForward = nextIndex > index;
|
|
1324
|
+
const direction = isForward ? 1 : -1;
|
|
1325
|
+
// Slide animation: animate both screens simultaneously
|
|
1218
1326
|
if (animationType === "slide") {
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1327
|
+
setIsTransitioning(true);
|
|
1328
|
+
// Set up next screen starting position (offscreen in direction of navigation)
|
|
1329
|
+
nextScreenAnim.translateX.setValue(SLIDE_FADE_OFFSET * direction);
|
|
1330
|
+
nextScreenAnim.opacity.setValue(1);
|
|
1331
|
+
// Animate both screens
|
|
1332
|
+
react_native_1.Animated.parallel([
|
|
1333
|
+
// Current screen slides out
|
|
1334
|
+
react_native_1.Animated.timing(currentScreenAnim.translateX, {
|
|
1335
|
+
toValue: -SLIDE_FADE_OFFSET * direction,
|
|
1336
|
+
duration: SLIDE_FADE_DURATION,
|
|
1337
|
+
easing: react_native_1.Easing.out(react_native_1.Easing.ease),
|
|
1338
|
+
useNativeDriver: true,
|
|
1339
|
+
}),
|
|
1340
|
+
// Next screen slides in
|
|
1341
|
+
react_native_1.Animated.timing(nextScreenAnim.translateX, {
|
|
1342
|
+
toValue: 0,
|
|
1343
|
+
duration: SLIDE_FADE_DURATION,
|
|
1344
|
+
easing: react_native_1.Easing.out(react_native_1.Easing.ease),
|
|
1345
|
+
useNativeDriver: true,
|
|
1346
|
+
}),
|
|
1347
|
+
]).start(() => {
|
|
1348
|
+
// Hide old screen and reset its position
|
|
1349
|
+
currentScreenAnim.opacity.setValue(0);
|
|
1350
|
+
currentScreenAnim.translateX.setValue(0);
|
|
1351
|
+
completeTransition(nextIndex, index);
|
|
1352
|
+
setIsTransitioning(false);
|
|
1236
1353
|
});
|
|
1237
1354
|
return;
|
|
1238
1355
|
}
|
|
1239
|
-
// slideFade animation: smooth slide + fade transition
|
|
1240
|
-
// Animates the PagerView container out, switches page, then animates back in
|
|
1356
|
+
// slideFade animation: smooth slide + fade transition on both screens
|
|
1241
1357
|
if (animationType === "slidefade") {
|
|
1242
1358
|
setIsTransitioning(true);
|
|
1243
|
-
// Update active screen index and activation time FIRST
|
|
1244
|
-
activeScreenIndexRef.current = nextIndex;
|
|
1245
|
-
screenActivationTimeRef.current[nextIndex] = Date.now();
|
|
1246
|
-
// Determine direction: forward (nextIndex > index) or backward
|
|
1247
|
-
const isForward = nextIndex > index;
|
|
1248
|
-
const direction = isForward ? 1 : -1;
|
|
1249
1359
|
const halfDuration = SLIDE_FADE_DURATION / 2;
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
};
|
|
1255
|
-
// Phase 1: Fade out and slide the current page in exit direction
|
|
1360
|
+
// Set up next screen starting position
|
|
1361
|
+
nextScreenAnim.translateX.setValue(SLIDE_FADE_OFFSET * direction * 0.5);
|
|
1362
|
+
nextScreenAnim.opacity.setValue(0);
|
|
1363
|
+
// Animate both screens simultaneously with crossfade
|
|
1256
1364
|
react_native_1.Animated.parallel([
|
|
1257
|
-
|
|
1365
|
+
// Current screen fades out and slides away
|
|
1366
|
+
react_native_1.Animated.timing(currentScreenAnim.opacity, {
|
|
1258
1367
|
toValue: 0,
|
|
1259
|
-
|
|
1368
|
+
duration: halfDuration,
|
|
1369
|
+
easing: react_native_1.Easing.out(react_native_1.Easing.ease),
|
|
1370
|
+
useNativeDriver: true,
|
|
1371
|
+
}),
|
|
1372
|
+
react_native_1.Animated.timing(currentScreenAnim.translateX, {
|
|
1373
|
+
toValue: -SLIDE_FADE_OFFSET * direction * 0.5,
|
|
1374
|
+
duration: halfDuration,
|
|
1375
|
+
easing: react_native_1.Easing.out(react_native_1.Easing.ease),
|
|
1376
|
+
useNativeDriver: true,
|
|
1260
1377
|
}),
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1378
|
+
// Next screen fades in and slides to center
|
|
1379
|
+
react_native_1.Animated.timing(nextScreenAnim.opacity, {
|
|
1380
|
+
toValue: 1,
|
|
1381
|
+
duration: halfDuration,
|
|
1382
|
+
easing: react_native_1.Easing.out(react_native_1.Easing.ease),
|
|
1383
|
+
useNativeDriver: true,
|
|
1384
|
+
}),
|
|
1385
|
+
react_native_1.Animated.timing(nextScreenAnim.translateX, {
|
|
1386
|
+
toValue: 0,
|
|
1387
|
+
duration: halfDuration,
|
|
1388
|
+
easing: react_native_1.Easing.out(react_native_1.Easing.ease),
|
|
1389
|
+
useNativeDriver: true,
|
|
1264
1390
|
}),
|
|
1265
1391
|
]).start(() => {
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
(
|
|
1270
|
-
// Set up for incoming animation - start from the direction we're navigating from
|
|
1271
|
-
pagerTranslateX.setValue(SLIDE_FADE_OFFSET * direction * 0.5);
|
|
1272
|
-
// Phase 2: Fade in and slide the new page to center
|
|
1273
|
-
react_native_1.Animated.parallel([
|
|
1274
|
-
react_native_1.Animated.timing(pagerOpacity, {
|
|
1275
|
-
toValue: 1,
|
|
1276
|
-
duration: halfDuration,
|
|
1277
|
-
easing: react_native_1.Easing.out(react_native_1.Easing.ease),
|
|
1278
|
-
useNativeDriver: true,
|
|
1279
|
-
}),
|
|
1280
|
-
react_native_1.Animated.timing(pagerTranslateX, {
|
|
1281
|
-
toValue: 0,
|
|
1282
|
-
duration: halfDuration,
|
|
1283
|
-
easing: react_native_1.Easing.out(react_native_1.Easing.ease),
|
|
1284
|
-
useNativeDriver: true,
|
|
1285
|
-
}),
|
|
1286
|
-
]).start(() => {
|
|
1287
|
-
// Send vars and onboarding state to the new page
|
|
1288
|
-
sendVarsToWebView(nextIndex);
|
|
1289
|
-
sendOnboardingStateToWebView(nextIndex);
|
|
1290
|
-
setIsTransitioning(false);
|
|
1291
|
-
});
|
|
1392
|
+
// Reset old screen position
|
|
1393
|
+
currentScreenAnim.translateX.setValue(0);
|
|
1394
|
+
completeTransition(nextIndex, index);
|
|
1395
|
+
setIsTransitioning(false);
|
|
1292
1396
|
});
|
|
1293
1397
|
return;
|
|
1294
1398
|
}
|
|
1295
1399
|
// Default fade animation: uses a white curtain overlay
|
|
1296
1400
|
setIsTransitioning(true);
|
|
1297
|
-
// Update active screen index and activation time FIRST
|
|
1298
|
-
activeScreenIndexRef.current = nextIndex;
|
|
1299
|
-
screenActivationTimeRef.current[nextIndex] = Date.now();
|
|
1300
1401
|
react_native_1.Animated.timing(fadeOpacity, {
|
|
1301
1402
|
toValue: 1,
|
|
1302
1403
|
duration: 160,
|
|
1303
1404
|
easing: react_native_1.Easing.out(react_native_1.Easing.quad),
|
|
1304
1405
|
useNativeDriver: true,
|
|
1305
1406
|
}).start(() => {
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
(_c = (_b = (_a = pagerRef.current) === null || _a === void 0 ? void 0 : _a.setPageWithoutAnimation) === null || _b === void 0 ? void 0 : _b.call(_a, nextIndex)) !== null && _c !== void 0 ? _c : (_d = pagerRef.current) === null || _d === void 0 ? void 0 : _d.setPage(nextIndex);
|
|
1407
|
+
// Swap screens instantly while curtain is opaque
|
|
1408
|
+
currentScreenAnim.opacity.setValue(0);
|
|
1409
|
+
nextScreenAnim.opacity.setValue(1);
|
|
1310
1410
|
requestAnimationFrame(() => {
|
|
1311
|
-
|
|
1312
|
-
//
|
|
1313
|
-
// timing was off during the transition
|
|
1314
|
-
sendVarsToWebView(nextIndex);
|
|
1315
|
-
sendOnboardingStateToWebView(nextIndex);
|
|
1411
|
+
completeTransition(nextIndex, index);
|
|
1412
|
+
// Fade curtain out to reveal new screen
|
|
1316
1413
|
react_native_1.Animated.timing(fadeOpacity, {
|
|
1317
1414
|
toValue: 0,
|
|
1318
1415
|
duration: 160,
|
|
@@ -1447,7 +1544,7 @@ function Overlay(props) {
|
|
|
1447
1544
|
wv.injectJavaScript(buildDirectVarsScript(varsRef.current));
|
|
1448
1545
|
// NOTE: Do NOT call sendOnboardingStateToWebView here - it would cause infinite loops
|
|
1449
1546
|
// because the WebView echoes back variables which triggers another sendVarsToWebView.
|
|
1450
|
-
// Onboarding state is sent separately in onLoadEnd and
|
|
1547
|
+
// Onboarding state is sent separately in onLoadEnd and navigateToIndex.
|
|
1451
1548
|
}
|
|
1452
1549
|
react_1.default.useEffect(() => {
|
|
1453
1550
|
const sub = react_native_1.BackHandler.addEventListener("hardwareBackPress", () => {
|
|
@@ -1490,24 +1587,8 @@ function Overlay(props) {
|
|
|
1490
1587
|
}, 600);
|
|
1491
1588
|
return () => clearTimeout(tid);
|
|
1492
1589
|
}, [docs.length, firstPageLoaded]);
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
setIndex(pos);
|
|
1496
|
-
// Update active screen index and activation time FIRST
|
|
1497
|
-
activeScreenIndexRef.current = pos;
|
|
1498
|
-
screenActivationTimeRef.current[pos] = Date.now();
|
|
1499
|
-
if (__DEV__)
|
|
1500
|
-
console.log("[Rampkit] onPageSelected - activating screen", pos);
|
|
1501
|
-
// Send vars and onboarding state to the newly active screen
|
|
1502
|
-
requestAnimationFrame(() => {
|
|
1503
|
-
sendVarsToWebView(pos);
|
|
1504
|
-
sendOnboardingStateToWebView(pos);
|
|
1505
|
-
});
|
|
1506
|
-
// Track screen change event
|
|
1507
|
-
if (props.onScreenChange && props.screens[pos]) {
|
|
1508
|
-
props.onScreenChange(pos, props.screens[pos].id);
|
|
1509
|
-
}
|
|
1510
|
-
};
|
|
1590
|
+
// NOTE: onPageSelected callback removed - we no longer use PagerView.
|
|
1591
|
+
// Screen transitions are now handled directly in navigateToIndex via completeTransition().
|
|
1511
1592
|
const handleAdvance = (i, animation = "fade") => {
|
|
1512
1593
|
var _a;
|
|
1513
1594
|
const currentScreenId = (_a = props.screens[i]) === null || _a === void 0 ? void 0 : _a.id;
|
|
@@ -1623,13 +1704,19 @@ function Overlay(props) {
|
|
|
1623
1704
|
styles.root,
|
|
1624
1705
|
!visible && styles.invisible,
|
|
1625
1706
|
visible && { opacity: overlayOpacity },
|
|
1626
|
-
], pointerEvents: visible && !isClosing ? "auto" : "none", children: [(0, jsx_runtime_1.jsx)(react_native_1.
|
|
1627
|
-
|
|
1628
|
-
{
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1707
|
+
], pointerEvents: visible && !isClosing ? "auto" : "none", children: [(0, jsx_runtime_1.jsx)(react_native_1.View, { style: react_native_1.StyleSheet.absoluteFill, children: docs.map((doc, i) => {
|
|
1708
|
+
var _a, _b;
|
|
1709
|
+
return ((0, jsx_runtime_1.jsx)(react_native_1.Animated.View, { style: [
|
|
1710
|
+
react_native_1.StyleSheet.absoluteFill,
|
|
1711
|
+
{
|
|
1712
|
+
opacity: (_a = screenAnims[i]) === null || _a === void 0 ? void 0 : _a.opacity,
|
|
1713
|
+
transform: [{ translateX: ((_b = screenAnims[i]) === null || _b === void 0 ? void 0 : _b.translateX) || 0 }],
|
|
1714
|
+
// Active screen renders on top
|
|
1715
|
+
zIndex: i === index ? 1 : 0,
|
|
1716
|
+
},
|
|
1717
|
+
],
|
|
1718
|
+
// Only the active screen receives touch events
|
|
1719
|
+
pointerEvents: i === index ? 'auto' : 'none', children: (0, jsx_runtime_1.jsx)(react_native_webview_1.WebView, { ref: (r) => (webviewsRef.current[i] = r), style: { width: windowWidth, height: windowHeight }, originWhitelist: ["*"], source: { html: doc }, injectedJavaScriptBeforeContentLoaded: exports.injectedHardening + exports.injectedDynamicTapHandler + exports.injectedButtonAnimations, injectedJavaScript: exports.injectedNoSelect + exports.injectedVarsHandler + exports.injectedButtonAnimations, automaticallyAdjustContentInsets: false, contentInsetAdjustmentBehavior: "never", bounces: false, scrollEnabled: false, overScrollMode: "never", scalesPageToFit: false, showsHorizontalScrollIndicator: false, dataDetectorTypes: "none", allowsLinkPreview: false, allowsInlineMediaPlayback: true, mediaPlaybackRequiresUserAction: false, cacheEnabled: true, javaScriptEnabled: true, domStorageEnabled: true, hideKeyboardAccessoryView: true, onLoadEnd: () => {
|
|
1633
1720
|
// Only initialize each screen ONCE to avoid repeated processing
|
|
1634
1721
|
if (initializedScreensRef.current.has(i)) {
|
|
1635
1722
|
if (__DEV__)
|
|
@@ -1658,6 +1745,25 @@ function Overlay(props) {
|
|
|
1658
1745
|
// By sending state to all screens upfront, the DOM is already in its final state
|
|
1659
1746
|
// before any navigation occurs.
|
|
1660
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
|
+
}
|
|
1661
1767
|
}, onMessage: (ev) => {
|
|
1662
1768
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
1663
1769
|
const raw = ev.nativeEvent.data;
|
|
@@ -1743,7 +1849,7 @@ function Overlay(props) {
|
|
|
1743
1849
|
// 3) A page requested an in-app review prompt
|
|
1744
1850
|
if ((data === null || data === void 0 ? void 0 : data.type) === "rampkit:request-review" ||
|
|
1745
1851
|
(data === null || data === void 0 ? void 0 : data.type) === "rampkit:review") {
|
|
1746
|
-
|
|
1852
|
+
const executeReview = async () => {
|
|
1747
1853
|
try {
|
|
1748
1854
|
const available = await RampKitNative_1.StoreReview.isAvailableAsync();
|
|
1749
1855
|
if (available) {
|
|
@@ -1751,16 +1857,36 @@ function Overlay(props) {
|
|
|
1751
1857
|
}
|
|
1752
1858
|
}
|
|
1753
1859
|
catch (_) { }
|
|
1754
|
-
}
|
|
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
|
+
}
|
|
1755
1870
|
return;
|
|
1756
1871
|
}
|
|
1757
1872
|
// 4) A page requested notification permission
|
|
1758
1873
|
if ((data === null || data === void 0 ? void 0 : data.type) === "rampkit:request-notification-permission") {
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
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
|
+
}
|
|
1764
1890
|
return;
|
|
1765
1891
|
}
|
|
1766
1892
|
// 5) Onboarding finished event from page
|
|
@@ -1847,7 +1973,7 @@ function Overlay(props) {
|
|
|
1847
1973
|
return;
|
|
1848
1974
|
}
|
|
1849
1975
|
if (raw === "rampkit:request-review" || raw === "rampkit:review") {
|
|
1850
|
-
|
|
1976
|
+
const executeReview = async () => {
|
|
1851
1977
|
try {
|
|
1852
1978
|
const available = await RampKitNative_1.StoreReview.isAvailableAsync();
|
|
1853
1979
|
if (available) {
|
|
@@ -1855,11 +1981,29 @@ function Overlay(props) {
|
|
|
1855
1981
|
}
|
|
1856
1982
|
}
|
|
1857
1983
|
catch (_) { }
|
|
1858
|
-
}
|
|
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
|
+
}
|
|
1859
1994
|
return;
|
|
1860
1995
|
}
|
|
1861
1996
|
if (raw === "rampkit:request-notification-permission") {
|
|
1862
|
-
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
|
+
}
|
|
1863
2007
|
return;
|
|
1864
2008
|
}
|
|
1865
2009
|
if (raw === "rampkit:onboarding-finished") {
|
|
@@ -1930,7 +2074,8 @@ function Overlay(props) {
|
|
|
1930
2074
|
}, onError: (e) => {
|
|
1931
2075
|
// You can surface an inline error UI here if you want
|
|
1932
2076
|
console.warn("WebView error:", e.nativeEvent);
|
|
1933
|
-
} }) }, props.screens[i].id))
|
|
2077
|
+
} }) }, props.screens[i].id));
|
|
2078
|
+
}) }), (0, jsx_runtime_1.jsx)(react_native_1.Animated.View, { pointerEvents: isTransitioning ? "auto" : "none", style: [
|
|
1934
2079
|
react_native_1.StyleSheet.absoluteFillObject,
|
|
1935
2080
|
styles.curtain,
|
|
1936
2081
|
{ opacity: fadeOpacity },
|
package/package.json
CHANGED