rampkit-expo-dev 0.0.84 → 0.0.87

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.
@@ -3,7 +3,7 @@ export declare const injectedHardening = "\n(function(){\n try {\n var meta
3
3
  export declare const injectedNoSelect = "\n(function(){\n try {\n if (window.__rkNoSelectApplied) return true;\n window.__rkNoSelectApplied = true;\n var style = document.getElementById('rk-no-select-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'rk-no-select-style';\n style.innerHTML = \"\n * {\n user-select: none !important;\n -webkit-user-select: none !important;\n -webkit-touch-callout: none !important;\n }\n ::selection {\n background: transparent !important;\n }\n \";\n document.head.appendChild(style);\n }\n var prevent = function(e){ if(e && e.preventDefault) e.preventDefault(); return false; };\n document.addEventListener('contextmenu', prevent, { passive: false, capture: true });\n document.addEventListener('selectstart', prevent, { passive: false, capture: true });\n } catch (_) {}\n true;\n})();\n";
4
4
  export declare const injectedVarsHandler = "\n(function(){\n try {\n if (window.__rkVarsHandlerApplied) return true;\n window.__rkVarsHandlerApplied = true;\n \n // Handler function that updates variables and notifies the page\n window.__rkHandleVarsUpdate = function(vars) {\n if (!vars || typeof vars !== 'object') return;\n // Update the global variables object\n window.__rampkitVariables = vars;\n // Dispatch a custom event that the page's JS can listen to for re-rendering\n try {\n document.dispatchEvent(new CustomEvent('rampkit:vars-updated', { detail: vars }));\n } catch(e) {}\n // Also try calling a global handler if the page defined one\n try {\n if (typeof window.onRampkitVarsUpdate === 'function') {\n window.onRampkitVarsUpdate(vars);\n }\n } catch(e) {}\n };\n \n // Listen for message events from React Native\n document.addEventListener('message', function(event) {\n try {\n var data = event.data;\n if (data && data.type === 'rampkit:variables' && data.vars) {\n window.__rkHandleVarsUpdate(data.vars);\n }\n } catch(e) {}\n }, false);\n \n // Also listen on window for compatibility\n window.addEventListener('message', function(event) {\n try {\n var data = event.data;\n if (data && data.type === 'rampkit:variables' && data.vars) {\n window.__rkHandleVarsUpdate(data.vars);\n }\n } catch(e) {}\n }, false);\n } catch (_) {}\n true;\n})();\n";
5
5
  export declare const injectedDynamicTapHandler = "\n(function() {\n if (window.__rampkitClickInterceptorInstalled) return;\n window.__rampkitClickInterceptorInstalled = true;\n\n // Decode HTML entities\n function decodeHtml(str) {\n if (!str) return str;\n return str.replace(/&quot;/g, '\"').replace(/&#34;/g, '\"').replace(/&#x22;/g, '\"')\n .replace(/&apos;/g, \"'\").replace(/&#39;/g, \"'\").replace(/&#x27;/g, \"'\")\n .replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&amp;/g, '&');\n }\n\n // Find dynamic tap config on element or ancestors\n function findDynamicTap(el) {\n var current = el;\n var depth = 0;\n var attrNames = ['data-tap-dynamic', 'data-tapdynamic', 'tapDynamic', 'data-dynamic-tap'];\n while (current && current !== document.body && current !== document.documentElement && depth < 20) {\n if (current.getAttribute) {\n for (var i = 0; i < attrNames.length; i++) {\n var attr = current.getAttribute(attrNames[i]);\n if (attr && attr.length > 2) {\n return { element: current, config: attr };\n }\n }\n if (current.dataset && current.dataset.tapDynamic) {\n return { element: current, config: current.dataset.tapDynamic };\n }\n }\n current = current.parentElement;\n depth++;\n }\n return null;\n }\n \n // Get variables for condition evaluation - check ALL possible sources\n function getVars() {\n var vars = {};\n if (window.__rampkitVariables) {\n Object.keys(window.__rampkitVariables).forEach(function(k) {\n vars[k] = window.__rampkitVariables[k];\n });\n }\n if (window.__rampkitVars) {\n Object.keys(window.__rampkitVars).forEach(function(k) {\n vars[k] = window.__rampkitVars[k];\n });\n }\n if (window.RK_VARS) {\n Object.keys(window.RK_VARS).forEach(function(k) {\n vars[k] = window.RK_VARS[k];\n });\n }\n return vars;\n }\n \n // Evaluate a single rule\n function evalRule(rule, vars) {\n if (!rule || !rule.key) return false;\n var left = vars[rule.key];\n var right = rule.value;\n var op = rule.op || '=';\n if (left === undefined || left === null) left = '';\n if (right === undefined || right === null) right = '';\n var leftStr = String(left);\n var rightStr = String(right);\n var result = false;\n switch (op) {\n case '=': case '==': result = leftStr === rightStr; break;\n case '!=': case '<>': result = leftStr !== rightStr; break;\n case '>': result = parseFloat(left) > parseFloat(right); break;\n case '<': result = parseFloat(left) < parseFloat(right); break;\n case '>=': result = parseFloat(left) >= parseFloat(right); break;\n case '<=': result = parseFloat(left) <= parseFloat(right); break;\n default: result = false;\n }\n return result;\n }\n \n // Evaluate all rules (AND logic)\n function evalRules(rules, vars) {\n if (!rules || !rules.length) return true;\n for (var i = 0; i < rules.length; i++) {\n if (!evalRule(rules[i], vars)) return false;\n }\n return true;\n }\n \n // Execute an action\n function execAction(action) {\n if (!action || !action.type) return;\n var msg = null;\n var actionType = action.type.toLowerCase();\n \n switch (actionType) {\n case 'navigate':\n msg = { type: 'rampkit:navigate', targetScreenId: action.targetScreenId || '__continue__', animation: action.animation || 'fade' };\n break;\n case 'continue':\n msg = { type: 'rampkit:navigate', targetScreenId: '__continue__', animation: action.animation || 'fade' };\n break;\n case 'goback':\n msg = { type: 'rampkit:goBack', animation: action.animation || 'fade' };\n break;\n case 'close':\n msg = { type: 'rampkit:close' };\n break;\n case 'haptic':\n msg = { type: 'rampkit:haptic', hapticType: action.hapticType || 'impact', impactStyle: action.impactStyle || 'Medium', notificationType: action.notificationType };\n break;\n case 'showpaywall':\n msg = { type: 'rampkit:show-paywall', payload: action.payload || { paywallId: action.paywallId } };\n break;\n case 'requestreview':\n msg = { type: 'rampkit:request-review' };\n break;\n case 'requestnotificationpermission':\n msg = { type: 'rampkit:request-notification-permission' };\n break;\n case 'onboardingfinished':\n msg = { type: 'rampkit:onboarding-finished', payload: action.payload };\n break;\n case 'setvariable':\n case 'setstate':\n case 'updatevariable':\n case 'set':\n case 'assign':\n var varKey = action.key || action.variableName || action.name || action.variable;\n var varValue = action.variableValue !== undefined ? action.variableValue :\n action.value !== undefined ? action.value :\n action.newValue !== undefined ? action.newValue : undefined;\n if (varKey && varValue !== undefined) {\n if (window.__rampkitVariables) window.__rampkitVariables[varKey] = varValue;\n if (window.__rampkitVars) window.__rampkitVars[varKey] = varValue;\n var updateVars = {};\n updateVars[varKey] = varValue;\n msg = { type: 'rampkit:variables', vars: updateVars };\n }\n break;\n }\n if (msg) {\n try {\n if (window.ReactNativeWebView && window.ReactNativeWebView.postMessage) {\n window.ReactNativeWebView.postMessage(JSON.stringify(msg));\n }\n } catch(e) {}\n }\n }\n \n // Evaluate dynamic tap config\n function evalDynamicTap(config) {\n if (!config || !config.values) return false;\n var vars = getVars();\n var conditions = config.values;\n for (var i = 0; i < conditions.length; i++) {\n var cond = conditions[i];\n var condType = cond.conditionType || 'if';\n var rules = cond.rules || [];\n var actions = cond.actions || [];\n if (condType === 'else' || evalRules(rules, vars)) {\n for (var j = 0; j < actions.length; j++) {\n execAction(actions[j]);\n }\n return true;\n }\n }\n return false;\n }\n \n // Click interceptor - capture phase, runs BEFORE onclick handlers\n function interceptClick(event) {\n var result = findDynamicTap(event.target);\n if (!result) return;\n\n try {\n var configStr = decodeHtml(result.config);\n var config = JSON.parse(configStr);\n var handled = evalDynamicTap(config);\n if (handled) {\n event.stopImmediatePropagation();\n event.preventDefault();\n return false;\n }\n } catch (e) {\n console.log('[RampKit] Dynamic tap error:', e);\n }\n }\n\n // Install interceptor on window in capture phase\n window.addEventListener('click', interceptClick, true);\n})();\n";
6
- export declare const injectedButtonAnimations = "\n(function(){\n try {\n if (window.__rkButtonAnimApplied) return true;\n window.__rkButtonAnimApplied = true;\n\n var pressed = null;\n var pressedOriginalTransform = '';\n var pressedOriginalOpacity = '';\n var pressedOriginalTransition = '';\n var releaseTimer = null;\n\n // Find interactive element - looks for clickable-looking elements\n function findInteractive(el) {\n var current = el;\n for (var i = 0; i < 20 && current && current !== document.body && current !== document.documentElement; i++) {\n if (!current || !current.tagName) { current = current.parentElement; continue; }\n var tag = current.tagName.toLowerCase();\n\n // Skip tiny elements (likely icons inside buttons)\n var rect = current.getBoundingClientRect();\n if (rect.width < 20 || rect.height < 20) { current = current.parentElement; continue; }\n\n // Match standard interactive elements\n if (tag === 'button' || tag === 'a' || tag === 'input' || tag === 'select') return current;\n\n // Match elements with tap/click-related data attributes\n // Exclude lifecycle attributes like data-on-open-actions, data-on-close-actions\n var attrs = current.attributes;\n if (attrs) {\n for (var j = 0; j < attrs.length; j++) {\n var attrName = attrs[j].name.toLowerCase();\n // Skip lifecycle attributes (on-open, on-close, on-load, on-appear, etc.)\n if (attrName.indexOf('on-open') !== -1 || attrName.indexOf('on-close') !== -1 ||\n attrName.indexOf('on-load') !== -1 || attrName.indexOf('on-appear') !== -1 ||\n attrName.indexOf('onopen') !== -1 || attrName.indexOf('onclose') !== -1 ||\n attrName.indexOf('onload') !== -1 || attrName.indexOf('onappear') !== -1) {\n continue;\n }\n // Match tap/click interaction attributes\n if (attrName.indexOf('click') !== -1 || attrName.indexOf('tap') !== -1 ||\n attrName.indexOf('action') !== -1 || attrName.indexOf('navigate') !== -1 ||\n attrName.indexOf('press') !== -1) {\n return current;\n }\n }\n }\n\n // Match elements with onclick\n if (current.onclick || current.hasAttribute('onclick')) return current;\n\n // Match elements with role=\"button\"\n if (current.getAttribute('role') === 'button') return current;\n\n // Match any element with an ID containing button/btn/cta\n var id = current.id || '';\n if (id && (id.toLowerCase().indexOf('button') !== -1 || id.toLowerCase().indexOf('btn') !== -1 || id.toLowerCase().indexOf('cta') !== -1)) return current;\n\n // Match elements with button-like classes\n var className = current.className;\n if (className && typeof className === 'string') {\n var cls = className.toLowerCase();\n if (cls.indexOf('btn') !== -1 || cls.indexOf('button') !== -1 || cls.indexOf('cta') !== -1 ||\n cls.indexOf('clickable') !== -1 || cls.indexOf('tappable') !== -1 || cls.indexOf('pressable') !== -1) {\n return current;\n }\n }\n\n // Match elements with cursor pointer\n try {\n var computed = window.getComputedStyle(current);\n if (computed && computed.cursor === 'pointer') return current;\n } catch(e) {}\n\n current = current.parentElement;\n }\n return null;\n }\n\n function applyPressedStyle(el) {\n if (!el || !el.style) return;\n // Save original styles\n pressedOriginalTransform = el.style.transform || '';\n pressedOriginalOpacity = el.style.opacity || '';\n pressedOriginalTransition = el.style.transition || '';\n // Apply pressed style with inline styles for maximum specificity\n el.style.transition = 'transform 80ms cubic-bezier(0.25, 0.1, 0.25, 1), opacity 80ms cubic-bezier(0.25, 0.1, 0.25, 1)';\n el.style.transform = 'scale(0.97)';\n el.style.opacity = '0.8';\n }\n\n function applyReleasedStyle(el) {\n if (!el || !el.style) return;\n // Apply spring-back animation\n el.style.transition = 'transform 280ms cubic-bezier(0.34, 1.56, 0.64, 1), opacity 280ms cubic-bezier(0.34, 1.56, 0.64, 1)';\n el.style.transform = pressedOriginalTransform || 'scale(1)';\n el.style.opacity = pressedOriginalOpacity || '1';\n }\n\n function resetStyle(el) {\n if (!el || !el.style) return;\n el.style.transform = pressedOriginalTransform;\n el.style.opacity = pressedOriginalOpacity;\n el.style.transition = pressedOriginalTransition;\n }\n\n function onTouchStart(e) {\n try {\n var target = findInteractive(e.target);\n if (!target) return;\n if (releaseTimer) { clearTimeout(releaseTimer); releaseTimer = null; }\n if (pressed && pressed !== target) { resetStyle(pressed); }\n applyPressedStyle(target);\n pressed = target;\n } catch(err) {}\n }\n \n function onTouchEnd(e) {\n try {\n if (!pressed) return;\n var t = pressed;\n applyReleasedStyle(t);\n releaseTimer = setTimeout(function() {\n resetStyle(t);\n releaseTimer = null;\n }, 300);\n pressed = null;\n } catch(err) {}\n }\n \n function onTouchCancel(e) {\n try {\n if (!pressed) return;\n resetStyle(pressed);\n pressed = null;\n if (releaseTimer) { clearTimeout(releaseTimer); releaseTimer = null; }\n } catch(err) {}\n }\n \n // Use capture phase for immediate response before any other handlers\n document.addEventListener('touchstart', onTouchStart, { passive: true, capture: true });\n document.addEventListener('touchend', onTouchEnd, { passive: true, capture: true });\n document.addEventListener('touchcancel', onTouchCancel, { passive: true, capture: true });\n // Mouse events for testing\n document.addEventListener('mousedown', onTouchStart, { passive: true, capture: true });\n document.addEventListener('mouseup', onTouchEnd, { passive: true, capture: true });\n \n } catch (err) {}\n true;\n})();\n";
6
+ export declare const injectedButtonAnimations = "\n(function(){\n try {\n if (window.__rkButtonAnimApplied) return true;\n window.__rkButtonAnimApplied = true;\n\n var pressed = null;\n var pressedOriginalTransform = '';\n var pressedOriginalOpacity = '';\n var pressedOriginalTransition = '';\n var releaseTimer = null;\n\n // Find interactive element - looks for clickable-looking elements\n function findInteractive(el) {\n var current = el;\n for (var i = 0; i < 20 && current && current !== document.body && current !== document.documentElement; i++) {\n if (!current || !current.tagName) { current = current.parentElement; continue; }\n var tag = current.tagName.toLowerCase();\n\n // Skip tiny elements (likely icons inside buttons)\n var rect = current.getBoundingClientRect();\n if (rect.width < 20 || rect.height < 20) { current = current.parentElement; continue; }\n\n // Match standard interactive elements\n if (tag === 'button' || tag === 'a' || tag === 'input' || tag === 'select') return current;\n\n // Match elements with tap/click-related data attributes\n // Exclude lifecycle attributes like data-on-open-actions, data-on-close-actions\n var attrs = current.attributes;\n if (attrs) {\n for (var j = 0; j < attrs.length; j++) {\n var attrName = attrs[j].name.toLowerCase();\n // Skip lifecycle attributes (on-open, on-close, on-load, on-appear, etc.)\n // These are for screen lifecycle events, not user tap interactions\n var isLifecycleAttr = (attrName.indexOf('on-open') !== -1 || attrName.indexOf('on-close') !== -1 ||\n attrName.indexOf('on-load') !== -1 || attrName.indexOf('on-appear') !== -1 ||\n attrName.indexOf('onopen') !== -1 || attrName.indexOf('onclose') !== -1 ||\n attrName.indexOf('onload') !== -1 || attrName.indexOf('onappear') !== -1);\n if (isLifecycleAttr) {\n continue;\n }\n // Match tap/click interaction attributes\n if (attrName.indexOf('click') !== -1 || attrName.indexOf('tap') !== -1 ||\n attrName.indexOf('action') !== -1 || attrName.indexOf('navigate') !== -1 ||\n attrName.indexOf('press') !== -1) {\n return current;\n }\n }\n }\n\n // Match elements with onclick\n if (current.onclick || current.hasAttribute('onclick')) return current;\n\n // Match elements with role=\"button\"\n if (current.getAttribute('role') === 'button') return current;\n\n // Match any element with an ID containing button/btn/cta\n var id = current.id || '';\n if (id && (id.toLowerCase().indexOf('button') !== -1 || id.toLowerCase().indexOf('btn') !== -1 || id.toLowerCase().indexOf('cta') !== -1)) return current;\n\n // Match elements with button-like classes\n var className = current.className;\n if (className && typeof className === 'string') {\n var cls = className.toLowerCase();\n if (cls.indexOf('btn') !== -1 || cls.indexOf('button') !== -1 || cls.indexOf('cta') !== -1 ||\n cls.indexOf('clickable') !== -1 || cls.indexOf('tappable') !== -1 || cls.indexOf('pressable') !== -1) {\n return current;\n }\n }\n\n // Match elements with cursor pointer\n try {\n var computed = window.getComputedStyle(current);\n if (computed && computed.cursor === 'pointer') return current;\n } catch(e) {}\n\n current = current.parentElement;\n }\n return null;\n }\n\n function applyPressedStyle(el) {\n if (!el || !el.style) return;\n // Save original styles\n pressedOriginalTransform = el.style.transform || '';\n pressedOriginalOpacity = el.style.opacity || '';\n pressedOriginalTransition = el.style.transition || '';\n // Apply pressed style with inline styles for maximum specificity\n el.style.transition = 'transform 80ms cubic-bezier(0.25, 0.1, 0.25, 1), opacity 80ms cubic-bezier(0.25, 0.1, 0.25, 1)';\n el.style.transform = 'scale(0.97)';\n el.style.opacity = '0.8';\n }\n\n function applyReleasedStyle(el) {\n if (!el || !el.style) return;\n // Apply spring-back animation\n el.style.transition = 'transform 280ms cubic-bezier(0.34, 1.56, 0.64, 1), opacity 280ms cubic-bezier(0.34, 1.56, 0.64, 1)';\n el.style.transform = pressedOriginalTransform || 'scale(1)';\n el.style.opacity = pressedOriginalOpacity || '1';\n }\n\n function resetStyle(el) {\n if (!el || !el.style) return;\n el.style.transform = pressedOriginalTransform;\n el.style.opacity = pressedOriginalOpacity;\n el.style.transition = pressedOriginalTransition;\n }\n\n function onTouchStart(e) {\n try {\n var target = findInteractive(e.target);\n if (!target) return;\n if (releaseTimer) { clearTimeout(releaseTimer); releaseTimer = null; }\n if (pressed && pressed !== target) { resetStyle(pressed); }\n applyPressedStyle(target);\n pressed = target;\n } catch(err) {}\n }\n \n function onTouchEnd(e) {\n try {\n if (!pressed) return;\n var t = pressed;\n applyReleasedStyle(t);\n releaseTimer = setTimeout(function() {\n resetStyle(t);\n releaseTimer = null;\n }, 300);\n pressed = null;\n } catch(err) {}\n }\n \n function onTouchCancel(e) {\n try {\n if (!pressed) return;\n resetStyle(pressed);\n pressed = null;\n if (releaseTimer) { clearTimeout(releaseTimer); releaseTimer = null; }\n } catch(err) {}\n }\n \n // Use capture phase for immediate response before any other handlers\n document.addEventListener('touchstart', onTouchStart, { passive: true, capture: true });\n document.addEventListener('touchend', onTouchEnd, { passive: true, capture: true });\n document.addEventListener('touchcancel', onTouchCancel, { passive: true, capture: true });\n // Mouse events for testing\n document.addEventListener('mousedown', onTouchStart, { passive: true, capture: true });\n document.addEventListener('mouseup', onTouchEnd, { passive: true, capture: true });\n \n } catch (err) {}\n true;\n})();\n";
7
7
  export type ScreenPayload = {
8
8
  id: string;
9
9
  html: string;
@@ -406,10 +406,12 @@ exports.injectedButtonAnimations = `
406
406
  for (var j = 0; j < attrs.length; j++) {
407
407
  var attrName = attrs[j].name.toLowerCase();
408
408
  // Skip lifecycle attributes (on-open, on-close, on-load, on-appear, etc.)
409
- if (attrName.indexOf('on-open') !== -1 || attrName.indexOf('on-close') !== -1 ||
409
+ // These are for screen lifecycle events, not user tap interactions
410
+ var isLifecycleAttr = (attrName.indexOf('on-open') !== -1 || attrName.indexOf('on-close') !== -1 ||
410
411
  attrName.indexOf('on-load') !== -1 || attrName.indexOf('on-appear') !== -1 ||
411
412
  attrName.indexOf('onopen') !== -1 || attrName.indexOf('onclose') !== -1 ||
412
- attrName.indexOf('onload') !== -1 || attrName.indexOf('onappear') !== -1) {
413
+ attrName.indexOf('onload') !== -1 || attrName.indexOf('onappear') !== -1);
414
+ if (isLifecycleAttr) {
413
415
  continue;
414
416
  }
415
417
  // Match tap/click interaction attributes
@@ -1125,6 +1127,124 @@ function Overlay(props) {
1125
1127
  detail: { screenIndex: ${screenIndex}, screenId: '${screenId}' }
1126
1128
  }));
1127
1129
  } catch(e) {}
1130
+
1131
+ // Process on-open actions (SDK-side handling)
1132
+ // This ensures actions run when screen becomes VISIBLE, not when loaded
1133
+ try {
1134
+ if (window.__rampkitOnOpenActionsProcessed) return; // Only run once per screen visibility
1135
+ window.__rampkitOnOpenActionsProcessed = true;
1136
+
1137
+ var elements = document.querySelectorAll('[data-on-open-actions]');
1138
+ elements.forEach(function(el) {
1139
+ try {
1140
+ var actionsStr = el.getAttribute('data-on-open-actions');
1141
+ if (!actionsStr) return;
1142
+
1143
+ // Decode HTML entities
1144
+ actionsStr = actionsStr.replace(/&quot;/g, '"').replace(/&#34;/g, '"')
1145
+ .replace(/&apos;/g, "'").replace(/&#39;/g, "'")
1146
+ .replace(/&lt;/g, '<').replace(/&gt;/g, '>')
1147
+ .replace(/&amp;/g, '&');
1148
+
1149
+ var actions = JSON.parse(actionsStr);
1150
+ if (!Array.isArray(actions)) return;
1151
+
1152
+ console.log('[RampKit] Processing on-open actions:', actions.length);
1153
+
1154
+ // Execute actions in sequence with delays
1155
+ var executeActions = function(actionList, index) {
1156
+ if (index >= actionList.length) return;
1157
+ if (!window.__rampkitScreenVisible) return; // Stop if screen became inactive
1158
+
1159
+ var action = actionList[index];
1160
+ var actionType = action.type || action.actionType;
1161
+
1162
+ console.log('[RampKit] Executing on-open action:', actionType);
1163
+
1164
+ if (actionType === 'wait') {
1165
+ var waitMs = action.waitMs || action.duration || 1000;
1166
+ setTimeout(function() {
1167
+ executeActions(actionList, index + 1);
1168
+ }, waitMs);
1169
+ return;
1170
+ }
1171
+
1172
+ if (actionType === 'navigate' || actionType === 'continue') {
1173
+ var target = action.targetScreenId || action.target || '__continue__';
1174
+ var animation = action.animation || 'fade';
1175
+ window.ReactNativeWebView.postMessage(JSON.stringify({
1176
+ type: 'rampkit:navigate',
1177
+ targetScreenId: target,
1178
+ animation: animation,
1179
+ fromOnOpen: true
1180
+ }));
1181
+ // Don't continue to next action after navigate
1182
+ return;
1183
+ }
1184
+
1185
+ if (actionType === 'goBack') {
1186
+ window.ReactNativeWebView.postMessage(JSON.stringify({
1187
+ type: 'rampkit:goBack',
1188
+ animation: action.animation || 'fade',
1189
+ fromOnOpen: true
1190
+ }));
1191
+ return;
1192
+ }
1193
+
1194
+ if (actionType === 'requestReview' || actionType === 'request-review') {
1195
+ window.ReactNativeWebView.postMessage(JSON.stringify({
1196
+ type: 'rampkit:request-review',
1197
+ fromOnOpen: true
1198
+ }));
1199
+ executeActions(actionList, index + 1);
1200
+ return;
1201
+ }
1202
+
1203
+ if (actionType === 'requestNotificationPermission' || actionType === 'request-notification-permission') {
1204
+ window.ReactNativeWebView.postMessage(JSON.stringify({
1205
+ type: 'rampkit:request-notification-permission',
1206
+ ios: action.ios,
1207
+ android: action.android,
1208
+ behavior: action.behavior,
1209
+ fromOnOpen: true
1210
+ }));
1211
+ executeActions(actionList, index + 1);
1212
+ return;
1213
+ }
1214
+
1215
+ if (actionType === 'haptic') {
1216
+ window.ReactNativeWebView.postMessage(JSON.stringify({
1217
+ type: 'rampkit:haptic',
1218
+ hapticType: action.hapticType || 'impact',
1219
+ impactStyle: action.impactStyle || 'Medium',
1220
+ fromOnOpen: true
1221
+ }));
1222
+ executeActions(actionList, index + 1);
1223
+ return;
1224
+ }
1225
+
1226
+ if (actionType === 'close') {
1227
+ window.ReactNativeWebView.postMessage(JSON.stringify({
1228
+ type: 'rampkit:close',
1229
+ fromOnOpen: true
1230
+ }));
1231
+ return;
1232
+ }
1233
+
1234
+ // Unknown action, continue to next
1235
+ executeActions(actionList, index + 1);
1236
+ };
1237
+
1238
+ // Start executing actions
1239
+ executeActions(actions, 0);
1240
+
1241
+ } catch(e) {
1242
+ console.log('[RampKit] Error processing on-open actions:', e);
1243
+ }
1244
+ });
1245
+ } catch(e) {
1246
+ console.log('[RampKit] Error finding on-open actions:', e);
1247
+ }
1128
1248
  })();`;
1129
1249
  // @ts-ignore: injectJavaScript exists on WebView instance
1130
1250
  wv.injectJavaScript(activateScript);
@@ -1141,6 +1261,7 @@ function Overlay(props) {
1141
1261
  }
1142
1262
  const deactivateScript = `(function() {
1143
1263
  window.__rampkitScreenVisible = false;
1264
+ window.__rampkitOnOpenActionsProcessed = false; // Reset so on-open can run again if user returns
1144
1265
  console.log('🔒 Screen ${screenIndex} DEACTIVATED');
1145
1266
 
1146
1267
  // Pause all Lottie animations
@@ -1986,20 +2107,20 @@ function Overlay(props) {
1986
2107
  }
1987
2108
  if ((data === null || data === void 0 ? void 0 : data.type) === "rampkit:continue" ||
1988
2109
  (data === null || data === void 0 ? void 0 : data.type) === "continue") {
1989
- // Only process continue from the active screen
2110
+ // Only process from active screen (on-open actions are handled by SDK in activateScreen)
1990
2111
  if (!isScreenActive(i)) {
1991
2112
  if (__DEV__)
1992
- console.log(`[RampKit] Ignoring continue from inactive screen ${i}`);
2113
+ console.log(`[Rampkit] Ignoring continue from inactive screen ${i} (SDK handles on-open)`);
1993
2114
  return;
1994
2115
  }
1995
2116
  handleAdvance(i, (data === null || data === void 0 ? void 0 : data.animation) || "fade");
1996
2117
  return;
1997
2118
  }
1998
2119
  if ((data === null || data === void 0 ? void 0 : data.type) === "rampkit:navigate") {
1999
- // Only process navigate from the active screen
2120
+ // Only process from active screen (on-open actions are handled by SDK in activateScreen)
2000
2121
  if (!isScreenActive(i)) {
2001
2122
  if (__DEV__)
2002
- console.log(`[RampKit] Ignoring navigate from inactive screen ${i}`);
2123
+ console.log(`[Rampkit] Ignoring navigate from inactive screen ${i} (SDK handles on-open)`);
2003
2124
  return;
2004
2125
  }
2005
2126
  const target = data === null || data === void 0 ? void 0 : data.targetScreenId;
@@ -2021,10 +2142,10 @@ function Overlay(props) {
2021
2142
  return;
2022
2143
  }
2023
2144
  if ((data === null || data === void 0 ? void 0 : data.type) === "rampkit:goBack") {
2024
- // Only process goBack from the active screen
2145
+ // Only process from active screen (on-open actions are handled by SDK in activateScreen)
2025
2146
  if (!isScreenActive(i)) {
2026
2147
  if (__DEV__)
2027
- console.log(`[RampKit] Ignoring goBack from inactive screen ${i}`);
2148
+ console.log(`[Rampkit] Ignoring goBack from inactive screen ${i} (SDK handles on-open)`);
2028
2149
  return;
2029
2150
  }
2030
2151
  handleGoBack(i, (data === null || data === void 0 ? void 0 : data.animation) || "fade");
@@ -2049,10 +2170,10 @@ function Overlay(props) {
2049
2170
  if (raw === "rampkit:tap" ||
2050
2171
  raw === "next" ||
2051
2172
  raw === "continue") {
2052
- // Only process from the active screen
2173
+ // Only process from active screen (on-open actions are handled by SDK in activateScreen)
2053
2174
  if (!isScreenActive(i)) {
2054
2175
  if (__DEV__)
2055
- console.log(`[RampKit] Ignoring ${raw} from inactive screen ${i}`);
2176
+ console.log(`[Rampkit] Ignoring ${raw} from inactive screen ${i} (SDK handles on-open)`);
2056
2177
  return;
2057
2178
  }
2058
2179
  handleAdvance(i);
@@ -2109,20 +2230,20 @@ function Overlay(props) {
2109
2230
  return;
2110
2231
  }
2111
2232
  if (raw === "rampkit:goBack") {
2112
- // Only process from the active screen
2233
+ // Only process from active screen (on-open actions are handled by SDK in activateScreen)
2113
2234
  if (!isScreenActive(i)) {
2114
2235
  if (__DEV__)
2115
- console.log(`[RampKit] Ignoring goBack (raw) from inactive screen ${i}`);
2236
+ console.log(`[Rampkit] Ignoring goBack (raw) from inactive screen ${i} (SDK handles on-open)`);
2116
2237
  return;
2117
2238
  }
2118
2239
  handleGoBack(i);
2119
2240
  return;
2120
2241
  }
2121
2242
  if (raw.startsWith("rampkit:navigate:")) {
2122
- // Only process from the active screen
2243
+ // Only process from active screen (on-open actions are handled by SDK in activateScreen)
2123
2244
  if (!isScreenActive(i)) {
2124
2245
  if (__DEV__)
2125
- console.log(`[RampKit] Ignoring navigate (raw) from inactive screen ${i}`);
2246
+ console.log(`[Rampkit] Ignoring navigate (raw) from inactive screen ${i} (SDK handles on-open)`);
2126
2247
  return;
2127
2248
  }
2128
2249
  const target = raw.slice("rampkit:navigate:".length);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rampkit-expo-dev",
3
- "version": "0.0.84",
3
+ "version": "0.0.87",
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",