rampkit-expo-dev 0.0.76 → 0.0.77
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 +112 -108
- 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!
|
|
@@ -1203,7 +1208,20 @@ function Overlay(props) {
|
|
|
1203
1208
|
(_a = props.onRegisterClose) === null || _a === void 0 ? void 0 : _a.call(props, null);
|
|
1204
1209
|
};
|
|
1205
1210
|
}, [handleRequestClose, props.onRegisterClose]);
|
|
1211
|
+
// Helper to complete a screen transition - updates state and sends data
|
|
1212
|
+
const completeTransition = (nextIndex) => {
|
|
1213
|
+
setIndex(nextIndex);
|
|
1214
|
+
sendVarsToWebView(nextIndex);
|
|
1215
|
+
sendOnboardingStateToWebView(nextIndex);
|
|
1216
|
+
// Track screen change event
|
|
1217
|
+
if (props.onScreenChange && props.screens[nextIndex]) {
|
|
1218
|
+
props.onScreenChange(nextIndex, props.screens[nextIndex].id);
|
|
1219
|
+
}
|
|
1220
|
+
};
|
|
1206
1221
|
// Android hardware back goes to previous page, then closes
|
|
1222
|
+
// NOTE: This function no longer uses PagerView. Instead, all screens are rendered
|
|
1223
|
+
// in a stack and we animate individual screen opacity/transform values.
|
|
1224
|
+
// This ensures all WebViews complete their first paint before any navigation.
|
|
1207
1225
|
const navigateToIndex = (nextIndex, animation = "fade") => {
|
|
1208
1226
|
if (nextIndex === index ||
|
|
1209
1227
|
nextIndex < 0 ||
|
|
@@ -1211,108 +1229,103 @@ function Overlay(props) {
|
|
|
1211
1229
|
return;
|
|
1212
1230
|
if (isTransitioning)
|
|
1213
1231
|
return;
|
|
1232
|
+
// Update active screen index and activation time FIRST
|
|
1233
|
+
activeScreenIndexRef.current = nextIndex;
|
|
1234
|
+
screenActivationTimeRef.current[nextIndex] = Date.now();
|
|
1214
1235
|
// Parse animation type case-insensitively
|
|
1215
1236
|
const animationType = (animation === null || animation === void 0 ? void 0 : animation.toLowerCase()) || "fade";
|
|
1216
|
-
|
|
1217
|
-
|
|
1237
|
+
const currentScreenAnim = screenAnims[index];
|
|
1238
|
+
const nextScreenAnim = screenAnims[nextIndex];
|
|
1239
|
+
const isForward = nextIndex > index;
|
|
1240
|
+
const direction = isForward ? 1 : -1;
|
|
1241
|
+
// Slide animation: animate both screens simultaneously
|
|
1218
1242
|
if (animationType === "slide") {
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1243
|
+
setIsTransitioning(true);
|
|
1244
|
+
// Set up next screen starting position (offscreen in direction of navigation)
|
|
1245
|
+
nextScreenAnim.translateX.setValue(SLIDE_FADE_OFFSET * direction);
|
|
1246
|
+
nextScreenAnim.opacity.setValue(1);
|
|
1247
|
+
// Animate both screens
|
|
1248
|
+
react_native_1.Animated.parallel([
|
|
1249
|
+
// Current screen slides out
|
|
1250
|
+
react_native_1.Animated.timing(currentScreenAnim.translateX, {
|
|
1251
|
+
toValue: -SLIDE_FADE_OFFSET * direction,
|
|
1252
|
+
duration: SLIDE_FADE_DURATION,
|
|
1253
|
+
easing: react_native_1.Easing.out(react_native_1.Easing.ease),
|
|
1254
|
+
useNativeDriver: true,
|
|
1255
|
+
}),
|
|
1256
|
+
// Next screen slides in
|
|
1257
|
+
react_native_1.Animated.timing(nextScreenAnim.translateX, {
|
|
1258
|
+
toValue: 0,
|
|
1259
|
+
duration: SLIDE_FADE_DURATION,
|
|
1260
|
+
easing: react_native_1.Easing.out(react_native_1.Easing.ease),
|
|
1261
|
+
useNativeDriver: true,
|
|
1262
|
+
}),
|
|
1263
|
+
]).start(() => {
|
|
1264
|
+
// Hide old screen and reset its position
|
|
1265
|
+
currentScreenAnim.opacity.setValue(0);
|
|
1266
|
+
currentScreenAnim.translateX.setValue(0);
|
|
1267
|
+
completeTransition(nextIndex);
|
|
1268
|
+
setIsTransitioning(false);
|
|
1236
1269
|
});
|
|
1237
1270
|
return;
|
|
1238
1271
|
}
|
|
1239
|
-
// slideFade animation: smooth slide + fade transition
|
|
1240
|
-
// Animates the PagerView container out, switches page, then animates back in
|
|
1272
|
+
// slideFade animation: smooth slide + fade transition on both screens
|
|
1241
1273
|
if (animationType === "slidefade") {
|
|
1242
1274
|
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
1275
|
const halfDuration = SLIDE_FADE_DURATION / 2;
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
};
|
|
1255
|
-
// Phase 1: Fade out and slide the current page in exit direction
|
|
1276
|
+
// Set up next screen starting position
|
|
1277
|
+
nextScreenAnim.translateX.setValue(SLIDE_FADE_OFFSET * direction * 0.5);
|
|
1278
|
+
nextScreenAnim.opacity.setValue(0);
|
|
1279
|
+
// Animate both screens simultaneously with crossfade
|
|
1256
1280
|
react_native_1.Animated.parallel([
|
|
1257
|
-
|
|
1281
|
+
// Current screen fades out and slides away
|
|
1282
|
+
react_native_1.Animated.timing(currentScreenAnim.opacity, {
|
|
1258
1283
|
toValue: 0,
|
|
1259
|
-
|
|
1284
|
+
duration: halfDuration,
|
|
1285
|
+
easing: react_native_1.Easing.out(react_native_1.Easing.ease),
|
|
1286
|
+
useNativeDriver: true,
|
|
1260
1287
|
}),
|
|
1261
|
-
react_native_1.Animated.timing(
|
|
1262
|
-
toValue: -SLIDE_FADE_OFFSET * direction * 0.5,
|
|
1263
|
-
|
|
1288
|
+
react_native_1.Animated.timing(currentScreenAnim.translateX, {
|
|
1289
|
+
toValue: -SLIDE_FADE_OFFSET * direction * 0.5,
|
|
1290
|
+
duration: halfDuration,
|
|
1291
|
+
easing: react_native_1.Easing.out(react_native_1.Easing.ease),
|
|
1292
|
+
useNativeDriver: true,
|
|
1293
|
+
}),
|
|
1294
|
+
// Next screen fades in and slides to center
|
|
1295
|
+
react_native_1.Animated.timing(nextScreenAnim.opacity, {
|
|
1296
|
+
toValue: 1,
|
|
1297
|
+
duration: halfDuration,
|
|
1298
|
+
easing: react_native_1.Easing.out(react_native_1.Easing.ease),
|
|
1299
|
+
useNativeDriver: true,
|
|
1300
|
+
}),
|
|
1301
|
+
react_native_1.Animated.timing(nextScreenAnim.translateX, {
|
|
1302
|
+
toValue: 0,
|
|
1303
|
+
duration: halfDuration,
|
|
1304
|
+
easing: react_native_1.Easing.out(react_native_1.Easing.ease),
|
|
1305
|
+
useNativeDriver: true,
|
|
1264
1306
|
}),
|
|
1265
1307
|
]).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
|
-
});
|
|
1308
|
+
// Reset old screen position
|
|
1309
|
+
currentScreenAnim.translateX.setValue(0);
|
|
1310
|
+
completeTransition(nextIndex);
|
|
1311
|
+
setIsTransitioning(false);
|
|
1292
1312
|
});
|
|
1293
1313
|
return;
|
|
1294
1314
|
}
|
|
1295
1315
|
// Default fade animation: uses a white curtain overlay
|
|
1296
1316
|
setIsTransitioning(true);
|
|
1297
|
-
// Update active screen index and activation time FIRST
|
|
1298
|
-
activeScreenIndexRef.current = nextIndex;
|
|
1299
|
-
screenActivationTimeRef.current[nextIndex] = Date.now();
|
|
1300
1317
|
react_native_1.Animated.timing(fadeOpacity, {
|
|
1301
1318
|
toValue: 1,
|
|
1302
1319
|
duration: 160,
|
|
1303
1320
|
easing: react_native_1.Easing.out(react_native_1.Easing.quad),
|
|
1304
1321
|
useNativeDriver: true,
|
|
1305
1322
|
}).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);
|
|
1323
|
+
// Swap screens instantly while curtain is opaque
|
|
1324
|
+
currentScreenAnim.opacity.setValue(0);
|
|
1325
|
+
nextScreenAnim.opacity.setValue(1);
|
|
1310
1326
|
requestAnimationFrame(() => {
|
|
1311
|
-
|
|
1312
|
-
//
|
|
1313
|
-
// timing was off during the transition
|
|
1314
|
-
sendVarsToWebView(nextIndex);
|
|
1315
|
-
sendOnboardingStateToWebView(nextIndex);
|
|
1327
|
+
completeTransition(nextIndex);
|
|
1328
|
+
// Fade curtain out to reveal new screen
|
|
1316
1329
|
react_native_1.Animated.timing(fadeOpacity, {
|
|
1317
1330
|
toValue: 0,
|
|
1318
1331
|
duration: 160,
|
|
@@ -1447,7 +1460,7 @@ function Overlay(props) {
|
|
|
1447
1460
|
wv.injectJavaScript(buildDirectVarsScript(varsRef.current));
|
|
1448
1461
|
// NOTE: Do NOT call sendOnboardingStateToWebView here - it would cause infinite loops
|
|
1449
1462
|
// because the WebView echoes back variables which triggers another sendVarsToWebView.
|
|
1450
|
-
// Onboarding state is sent separately in onLoadEnd and
|
|
1463
|
+
// Onboarding state is sent separately in onLoadEnd and navigateToIndex.
|
|
1451
1464
|
}
|
|
1452
1465
|
react_1.default.useEffect(() => {
|
|
1453
1466
|
const sub = react_native_1.BackHandler.addEventListener("hardwareBackPress", () => {
|
|
@@ -1490,24 +1503,8 @@ function Overlay(props) {
|
|
|
1490
1503
|
}, 600);
|
|
1491
1504
|
return () => clearTimeout(tid);
|
|
1492
1505
|
}, [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
|
-
};
|
|
1506
|
+
// NOTE: onPageSelected callback removed - we no longer use PagerView.
|
|
1507
|
+
// Screen transitions are now handled directly in navigateToIndex via completeTransition().
|
|
1511
1508
|
const handleAdvance = (i, animation = "fade") => {
|
|
1512
1509
|
var _a;
|
|
1513
1510
|
const currentScreenId = (_a = props.screens[i]) === null || _a === void 0 ? void 0 : _a.id;
|
|
@@ -1623,13 +1620,19 @@ function Overlay(props) {
|
|
|
1623
1620
|
styles.root,
|
|
1624
1621
|
!visible && styles.invisible,
|
|
1625
1622
|
visible && { opacity: overlayOpacity },
|
|
1626
|
-
], pointerEvents: visible && !isClosing ? "auto" : "none", children: [(0, jsx_runtime_1.jsx)(react_native_1.
|
|
1627
|
-
|
|
1628
|
-
{
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1623
|
+
], 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) => {
|
|
1624
|
+
var _a, _b;
|
|
1625
|
+
return ((0, jsx_runtime_1.jsx)(react_native_1.Animated.View, { style: [
|
|
1626
|
+
react_native_1.StyleSheet.absoluteFill,
|
|
1627
|
+
{
|
|
1628
|
+
opacity: (_a = screenAnims[i]) === null || _a === void 0 ? void 0 : _a.opacity,
|
|
1629
|
+
transform: [{ translateX: ((_b = screenAnims[i]) === null || _b === void 0 ? void 0 : _b.translateX) || 0 }],
|
|
1630
|
+
// Active screen renders on top
|
|
1631
|
+
zIndex: i === index ? 1 : 0,
|
|
1632
|
+
},
|
|
1633
|
+
],
|
|
1634
|
+
// Only the active screen receives touch events
|
|
1635
|
+
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
1636
|
// Only initialize each screen ONCE to avoid repeated processing
|
|
1634
1637
|
if (initializedScreensRef.current.has(i)) {
|
|
1635
1638
|
if (__DEV__)
|
|
@@ -1930,7 +1933,8 @@ function Overlay(props) {
|
|
|
1930
1933
|
}, onError: (e) => {
|
|
1931
1934
|
// You can surface an inline error UI here if you want
|
|
1932
1935
|
console.warn("WebView error:", e.nativeEvent);
|
|
1933
|
-
} }) }, props.screens[i].id))
|
|
1936
|
+
} }) }, props.screens[i].id));
|
|
1937
|
+
}) }), (0, jsx_runtime_1.jsx)(react_native_1.Animated.View, { pointerEvents: isTransitioning ? "auto" : "none", style: [
|
|
1934
1938
|
react_native_1.StyleSheet.absoluteFillObject,
|
|
1935
1939
|
styles.curtain,
|
|
1936
1940
|
{ opacity: fadeOpacity },
|
package/package.json
CHANGED