rampkit-expo-dev 0.0.80 → 0.0.82

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.
@@ -2,8 +2,8 @@ import { RampKitContext, NavigationData } from "./types";
2
2
  export declare const injectedHardening = "\n(function(){\n try {\n var meta = document.querySelector('meta[name=\"viewport\"]');\n if (!meta) { meta = document.createElement('meta'); meta.name = 'viewport'; document.head.appendChild(meta); }\n meta.setAttribute('content','width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover');\n var style = document.createElement('style');\n style.textContent='html,body{overflow-x:hidden!important;} html,body,*{-webkit-user-select:none!important;user-select:none!important;-webkit-touch-callout:none!important;-ms-user-select:none!important;touch-action: pan-y;} *{-webkit-tap-highlight-color: rgba(0,0,0,0)!important;} ::selection{background: transparent!important;} ::-moz-selection{background: transparent!important;} a,img{-webkit-user-drag:none!important;user-drag:none!important;-webkit-touch-callout:none!important} input,textarea{caret-color:transparent!important;-webkit-user-select:none!important;user-select:none!important}';\n document.head.appendChild(style);\n var prevent=function(e){e.preventDefault&&e.preventDefault();};\n document.addEventListener('gesturestart',prevent,{passive:false});\n document.addEventListener('gesturechange',prevent,{passive:false});\n document.addEventListener('gestureend',prevent,{passive:false});\n document.addEventListener('dblclick',prevent,{passive:false});\n document.addEventListener('wheel',function(e){ if(e.ctrlKey) e.preventDefault(); },{passive:false});\n document.addEventListener('touchmove',function(e){ if(e.scale && e.scale !== 1) e.preventDefault(); },{passive:false});\n document.addEventListener('selectstart',prevent,{passive:false,capture:true});\n document.addEventListener('contextmenu',prevent,{passive:false,capture:true});\n document.addEventListener('copy',prevent,{passive:false,capture:true});\n document.addEventListener('cut',prevent,{passive:false,capture:true});\n document.addEventListener('paste',prevent,{passive:false,capture:true});\n document.addEventListener('dragstart',prevent,{passive:false,capture:true});\n // Belt-and-suspenders: aggressively clear any attempted selection\n var clearSel=function(){\n try{var sel=window.getSelection&&window.getSelection(); if(sel&&sel.removeAllRanges) sel.removeAllRanges();}catch(_){} }\n document.addEventListener('selectionchange',clearSel,{passive:true,capture:true});\n document.onselectstart=function(){ clearSel(); return false; };\n try{ document.documentElement.style.webkitUserSelect='none'; document.documentElement.style.userSelect='none'; }catch(_){ }\n try{ document.body.style.webkitUserSelect='none'; document.body.style.userSelect='none'; }catch(_){ }\n var __selTimer = setInterval(clearSel, 160);\n window.addEventListener('pagehide',function(){ try{ clearInterval(__selTimer); }catch(_){} });\n // Continuously enforce no-select on all elements and new nodes\n var enforceNoSelect = function(el){\n try{\n el.style && (el.style.webkitUserSelect='none', el.style.userSelect='none', el.style.webkitTouchCallout='none');\n el.setAttribute && (el.setAttribute('unselectable','on'), el.setAttribute('contenteditable','false'));\n }catch(_){}\n }\n try{\n var all=document.getElementsByTagName('*');\n for(var i=0;i<all.length;i++){ enforceNoSelect(all[i]); }\n var obs = new MutationObserver(function(muts){\n for(var j=0;j<muts.length;j++){\n var m=muts[j];\n if(m.type==='childList'){\n m.addedNodes && m.addedNodes.forEach && m.addedNodes.forEach(function(n){ if(n && n.nodeType===1){ enforceNoSelect(n); var q=n.getElementsByTagName? n.getElementsByTagName('*'): []; for(var k=0;k<q.length;k++){ enforceNoSelect(q[k]); }}});\n } else if(m.type==='attributes'){\n enforceNoSelect(m.target);\n }\n }\n });\n obs.observe(document.documentElement,{ childList:true, subtree:true, attributes:true, attributeFilter:['contenteditable','style'] });\n }catch(_){ }\n } catch(_) {}\n})(); true;\n";
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
- 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 - very permissive, looks for any clickable-looking element\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 any data attribute containing action/navigate/tap/click\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 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\" or tabindex\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";
5
+ export declare const injectedDynamicTapHandler = "\n(function() {\n if (window.__rampkitClickInterceptorInstalled) return;\n window.__rampkitClickInterceptorInstalled = true;\n\n // ========== DEBUG: Screen 19 specific logging (REMOVE AFTER BUG FIX) ==========\n var isScreen19Dynamic = function() {\n var screenId = window.__rampkitScreenId || '';\n var screenIndex = window.__rampkitScreenIndex;\n return screenId.indexOf('19') !== -1 ||\n screenId.toLowerCase().indexOf('screen 19') !== -1 ||\n screenId.toLowerCase().indexOf('screen19') !== -1 ||\n screenIndex === 19 ||\n screenIndex === 18;\n };\n\n var debugScreen19Dynamic = function(msg, data) {\n if (isScreen19Dynamic()) {\n console.log('[SCREEN19-DEBUG][DynamicTap] ' + msg, JSON.stringify(data || {}));\n }\n };\n // ========== END DEBUG ==========\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 var searchTrail = []; // DEBUG: Track search path\n\n while (current && current !== document.body && current !== document.documentElement && depth < 20) {\n // DEBUG: Build search trail for Screen 19\n var trailInfo = {\n depth: depth,\n tag: current.tagName,\n id: current.id || '(none)',\n class: (current.className && typeof current.className === 'string') ? current.className.substring(0,50) : '(none)'\n };\n searchTrail.push(trailInfo);\n\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 var rect = current.getBoundingClientRect ? current.getBoundingClientRect() : {};\n debugScreen19Dynamic('FOUND data-tap-dynamic', {\n attrName: attrNames[i],\n depth: depth,\n element: trailInfo,\n size: rect.width + 'x' + rect.height,\n configPreview: attr.substring(0, 100) + '...',\n trail: searchTrail\n });\n return { element: current, config: attr };\n }\n }\n if (current.dataset && current.dataset.tapDynamic) {\n var rect2 = current.getBoundingClientRect ? current.getBoundingClientRect() : {};\n debugScreen19Dynamic('FOUND dataset.tapDynamic', {\n depth: depth,\n element: trailInfo,\n size: rect2.width + 'x' + rect2.height,\n trail: searchTrail\n });\n return { element: current, config: current.dataset.tapDynamic };\n }\n }\n current = current.parentElement;\n depth++;\n }\n debugScreen19Dynamic('NO data-tap-dynamic found', { trail: searchTrail });\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 // ========== DEBUG: Screen 19 click logging ==========\n if (isScreen19Dynamic()) {\n var clickX = event.clientX;\n var clickY = event.clientY;\n var originalTarget = event.target;\n var originalRect = originalTarget.getBoundingClientRect ? originalTarget.getBoundingClientRect() : {};\n console.log('[SCREEN19-DEBUG][Click] Click at (' + clickX + ',' + clickY + ')', JSON.stringify({\n originalTarget: {\n tag: originalTarget.tagName,\n id: originalTarget.id || '(none)',\n class: (originalTarget.className && typeof originalTarget.className === 'string') ? originalTarget.className.substring(0,100) : '(none)',\n size: originalRect.width + 'x' + originalRect.height\n }\n }));\n }\n // ========== END DEBUG ==========\n\n var result = findDynamicTap(event.target);\n if (!result) return;\n\n // ========== DEBUG: Screen 19 - log when dynamic tap is found ==========\n if (isScreen19Dynamic()) {\n var rect = result.element.getBoundingClientRect ? result.element.getBoundingClientRect() : {};\n var screenWidth = window.innerWidth;\n var screenHeight = window.innerHeight;\n var isFullScreen = (rect.width >= screenWidth * 0.9 && rect.height >= screenHeight * 0.9);\n console.log('[SCREEN19-DEBUG][Click] DYNAMIC TAP WILL BE HANDLED', JSON.stringify({\n element: {\n tag: result.element.tagName,\n id: result.element.id || '(none)',\n class: (result.element.className && typeof result.element.className === 'string') ? result.element.className.substring(0,100) : '(none)',\n size: rect.width + 'x' + rect.height\n },\n isFullScreen: isFullScreen,\n WARNING: isFullScreen ? 'FULL SCREEN ELEMENT WITH DYNAMIC TAP - THIS IS THE BUG!' : 'normal element'\n }));\n }\n // ========== END DEBUG ==========\n\n try {\n var configStr = decodeHtml(result.config);\n var config = JSON.parse(configStr);\n\n // ========== DEBUG: Screen 19 - log parsed config ==========\n if (isScreen19Dynamic()) {\n console.log('[SCREEN19-DEBUG][Click] Parsed config:', JSON.stringify({\n hasValues: !!(config && config.values),\n valuesCount: config && config.values ? config.values.length : 0,\n firstCondition: config && config.values && config.values[0] ? {\n conditionType: config.values[0].conditionType,\n rulesCount: config.values[0].rules ? config.values[0].rules.length : 0,\n actionsCount: config.values[0].actions ? config.values[0].actions.length : 0\n } : null\n }));\n }\n // ========== END DEBUG ==========\n\n var handled = evalDynamicTap(config);\n if (handled) {\n debugScreen19Dynamic('Click HANDLED by dynamic tap - event stopped', { handled: true });\n event.stopImmediatePropagation();\n event.preventDefault();\n return false;\n }\n } catch (e) {\n console.log('[RampKit] Dynamic tap error:', e);\n if (isScreen19Dynamic()) {\n console.log('[SCREEN19-DEBUG][Click] Dynamic tap parse error:', e.message);\n }\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 // ========== DEBUG: Screen 19 specific logging (REMOVE AFTER BUG FIX) ==========\n var isScreen19 = function() {\n // Check multiple ways to identify Screen 19\n var screenId = window.__rampkitScreenId || '';\n var screenIndex = window.__rampkitScreenIndex;\n return screenId.indexOf('19') !== -1 ||\n screenId.toLowerCase().indexOf('screen 19') !== -1 ||\n screenId.toLowerCase().indexOf('screen19') !== -1 ||\n screenIndex === 19 ||\n screenIndex === 18; // 0-indexed, so screen 19 would be index 18\n };\n\n var debugScreen19 = function(msg, data) {\n if (isScreen19()) {\n console.log('[SCREEN19-DEBUG][ButtonAnim] ' + msg, JSON.stringify(data || {}));\n }\n };\n // ========== END DEBUG ==========\n\n // Find interactive element - very permissive, looks for any clickable-looking element\n function findInteractive(el) {\n var current = el;\n var debugTrail = []; // DEBUG: Track search path for Screen 19\n\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 // DEBUG: Build trail for Screen 19\n var debugInfo = {\n depth: i,\n tag: tag,\n id: current.id || '(none)',\n class: (current.className && typeof current.className === 'string') ? current.className.substring(0, 100) : '(none)',\n size: rect.width + 'x' + rect.height\n };\n debugTrail.push(debugInfo);\n\n // Match standard interactive elements\n if (tag === 'button' || tag === 'a' || tag === 'input' || tag === 'select') {\n debugScreen19('MATCHED: standard tag', { reason: 'tag=' + tag, element: debugInfo, trail: debugTrail });\n return current;\n }\n\n // Match elements with any data attribute containing action/navigate/tap/click\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 if (attrName.indexOf('click') !== -1 || attrName.indexOf('tap') !== -1 ||\n attrName.indexOf('action') !== -1 || attrName.indexOf('navigate') !== -1 ||\n attrName.indexOf('press') !== -1) {\n debugScreen19('MATCHED: data-attr', { reason: 'attr=' + attrName, value: attrs[j].value.substring(0,50), element: debugInfo, trail: debugTrail });\n return current;\n }\n }\n }\n\n // Match elements with onclick\n if (current.onclick || current.hasAttribute('onclick')) {\n debugScreen19('MATCHED: onclick', { element: debugInfo, trail: debugTrail });\n return current;\n }\n\n // Match elements with role=\"button\" or tabindex\n if (current.getAttribute('role') === 'button') {\n debugScreen19('MATCHED: role=button', { element: debugInfo, trail: debugTrail });\n return current;\n }\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)) {\n debugScreen19('MATCHED: button-like ID', { reason: 'id=' + id, element: debugInfo, trail: debugTrail });\n return current;\n }\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 debugScreen19('MATCHED: button-like class', { reason: 'class=' + className, element: debugInfo, trail: debugTrail });\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') {\n debugScreen19('MATCHED: cursor:pointer', { element: debugInfo, trail: debugTrail });\n return current;\n }\n } catch(e) {}\n\n current = current.parentElement;\n }\n debugScreen19('NO MATCH found', { originalTag: el.tagName, trail: debugTrail });\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 // ========== DEBUG: Screen 19 touch logging ==========\n if (isScreen19()) {\n var touchX = e.touches ? e.touches[0].clientX : e.clientX;\n var touchY = e.touches ? e.touches[0].clientY : e.clientY;\n var originalTarget = e.target;\n var originalRect = originalTarget.getBoundingClientRect ? originalTarget.getBoundingClientRect() : {};\n console.log('[SCREEN19-DEBUG][TouchStart] Touch at (' + touchX + ',' + touchY + ')', JSON.stringify({\n originalTarget: {\n tag: originalTarget.tagName,\n id: originalTarget.id || '(none)',\n class: (originalTarget.className && typeof originalTarget.className === 'string') ? originalTarget.className.substring(0,100) : '(none)',\n size: originalRect.width + 'x' + originalRect.height\n }\n }));\n }\n // ========== END DEBUG ==========\n\n var target = findInteractive(e.target);\n if (!target) return;\n\n // ========== DEBUG: Screen 19 - log what element was found interactive ==========\n if (isScreen19() && target) {\n var targetRect = target.getBoundingClientRect();\n var screenWidth = window.innerWidth;\n var screenHeight = window.innerHeight;\n var isFullScreen = (targetRect.width >= screenWidth * 0.9 && targetRect.height >= screenHeight * 0.9);\n console.log('[SCREEN19-DEBUG][TouchStart] INTERACTIVE ELEMENT FOUND', JSON.stringify({\n tag: target.tagName,\n id: target.id || '(none)',\n class: (target.className && typeof target.className === 'string') ? target.className.substring(0,100) : '(none)',\n size: targetRect.width + 'x' + targetRect.height,\n isFullScreen: isFullScreen,\n WARNING: isFullScreen ? 'FULL SCREEN ELEMENT DETECTED - THIS IS THE BUG!' : 'normal element'\n }));\n }\n // ========== END DEBUG ==========\n\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;
@@ -181,7 +181,25 @@ exports.injectedDynamicTapHandler = `
181
181
  (function() {
182
182
  if (window.__rampkitClickInterceptorInstalled) return;
183
183
  window.__rampkitClickInterceptorInstalled = true;
184
-
184
+
185
+ // ========== DEBUG: Screen 19 specific logging (REMOVE AFTER BUG FIX) ==========
186
+ var isScreen19Dynamic = function() {
187
+ var screenId = window.__rampkitScreenId || '';
188
+ var screenIndex = window.__rampkitScreenIndex;
189
+ return screenId.indexOf('19') !== -1 ||
190
+ screenId.toLowerCase().indexOf('screen 19') !== -1 ||
191
+ screenId.toLowerCase().indexOf('screen19') !== -1 ||
192
+ screenIndex === 19 ||
193
+ screenIndex === 18;
194
+ };
195
+
196
+ var debugScreen19Dynamic = function(msg, data) {
197
+ if (isScreen19Dynamic()) {
198
+ console.log('[SCREEN19-DEBUG][DynamicTap] ' + msg, JSON.stringify(data || {}));
199
+ }
200
+ };
201
+ // ========== END DEBUG ==========
202
+
185
203
  // Decode HTML entities
186
204
  function decodeHtml(str) {
187
205
  if (!str) return str;
@@ -189,27 +207,55 @@ exports.injectedDynamicTapHandler = `
189
207
  .replace(/&apos;/g, "'").replace(/&#39;/g, "'").replace(/&#x27;/g, "'")
190
208
  .replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&amp;/g, '&');
191
209
  }
192
-
210
+
193
211
  // Find dynamic tap config on element or ancestors
194
212
  function findDynamicTap(el) {
195
213
  var current = el;
196
214
  var depth = 0;
197
215
  var attrNames = ['data-tap-dynamic', 'data-tapdynamic', 'tapDynamic', 'data-dynamic-tap'];
216
+ var searchTrail = []; // DEBUG: Track search path
217
+
198
218
  while (current && current !== document.body && current !== document.documentElement && depth < 20) {
219
+ // DEBUG: Build search trail for Screen 19
220
+ var trailInfo = {
221
+ depth: depth,
222
+ tag: current.tagName,
223
+ id: current.id || '(none)',
224
+ class: (current.className && typeof current.className === 'string') ? current.className.substring(0,50) : '(none)'
225
+ };
226
+ searchTrail.push(trailInfo);
227
+
199
228
  if (current.getAttribute) {
200
229
  for (var i = 0; i < attrNames.length; i++) {
201
230
  var attr = current.getAttribute(attrNames[i]);
202
231
  if (attr && attr.length > 2) {
232
+ var rect = current.getBoundingClientRect ? current.getBoundingClientRect() : {};
233
+ debugScreen19Dynamic('FOUND data-tap-dynamic', {
234
+ attrName: attrNames[i],
235
+ depth: depth,
236
+ element: trailInfo,
237
+ size: rect.width + 'x' + rect.height,
238
+ configPreview: attr.substring(0, 100) + '...',
239
+ trail: searchTrail
240
+ });
203
241
  return { element: current, config: attr };
204
242
  }
205
243
  }
206
244
  if (current.dataset && current.dataset.tapDynamic) {
245
+ var rect2 = current.getBoundingClientRect ? current.getBoundingClientRect() : {};
246
+ debugScreen19Dynamic('FOUND dataset.tapDynamic', {
247
+ depth: depth,
248
+ element: trailInfo,
249
+ size: rect2.width + 'x' + rect2.height,
250
+ trail: searchTrail
251
+ });
207
252
  return { element: current, config: current.dataset.tapDynamic };
208
253
  }
209
254
  }
210
255
  current = current.parentElement;
211
256
  depth++;
212
257
  }
258
+ debugScreen19Dynamic('NO data-tap-dynamic found', { trail: searchTrail });
213
259
  return null;
214
260
  }
215
261
 
@@ -349,23 +395,78 @@ exports.injectedDynamicTapHandler = `
349
395
 
350
396
  // Click interceptor - capture phase, runs BEFORE onclick handlers
351
397
  function interceptClick(event) {
398
+ // ========== DEBUG: Screen 19 click logging ==========
399
+ if (isScreen19Dynamic()) {
400
+ var clickX = event.clientX;
401
+ var clickY = event.clientY;
402
+ var originalTarget = event.target;
403
+ var originalRect = originalTarget.getBoundingClientRect ? originalTarget.getBoundingClientRect() : {};
404
+ console.log('[SCREEN19-DEBUG][Click] Click at (' + clickX + ',' + clickY + ')', JSON.stringify({
405
+ originalTarget: {
406
+ tag: originalTarget.tagName,
407
+ id: originalTarget.id || '(none)',
408
+ class: (originalTarget.className && typeof originalTarget.className === 'string') ? originalTarget.className.substring(0,100) : '(none)',
409
+ size: originalRect.width + 'x' + originalRect.height
410
+ }
411
+ }));
412
+ }
413
+ // ========== END DEBUG ==========
414
+
352
415
  var result = findDynamicTap(event.target);
353
416
  if (!result) return;
354
-
417
+
418
+ // ========== DEBUG: Screen 19 - log when dynamic tap is found ==========
419
+ if (isScreen19Dynamic()) {
420
+ var rect = result.element.getBoundingClientRect ? result.element.getBoundingClientRect() : {};
421
+ var screenWidth = window.innerWidth;
422
+ var screenHeight = window.innerHeight;
423
+ var isFullScreen = (rect.width >= screenWidth * 0.9 && rect.height >= screenHeight * 0.9);
424
+ console.log('[SCREEN19-DEBUG][Click] DYNAMIC TAP WILL BE HANDLED', JSON.stringify({
425
+ element: {
426
+ tag: result.element.tagName,
427
+ id: result.element.id || '(none)',
428
+ class: (result.element.className && typeof result.element.className === 'string') ? result.element.className.substring(0,100) : '(none)',
429
+ size: rect.width + 'x' + rect.height
430
+ },
431
+ isFullScreen: isFullScreen,
432
+ WARNING: isFullScreen ? 'FULL SCREEN ELEMENT WITH DYNAMIC TAP - THIS IS THE BUG!' : 'normal element'
433
+ }));
434
+ }
435
+ // ========== END DEBUG ==========
436
+
355
437
  try {
356
438
  var configStr = decodeHtml(result.config);
357
439
  var config = JSON.parse(configStr);
440
+
441
+ // ========== DEBUG: Screen 19 - log parsed config ==========
442
+ if (isScreen19Dynamic()) {
443
+ console.log('[SCREEN19-DEBUG][Click] Parsed config:', JSON.stringify({
444
+ hasValues: !!(config && config.values),
445
+ valuesCount: config && config.values ? config.values.length : 0,
446
+ firstCondition: config && config.values && config.values[0] ? {
447
+ conditionType: config.values[0].conditionType,
448
+ rulesCount: config.values[0].rules ? config.values[0].rules.length : 0,
449
+ actionsCount: config.values[0].actions ? config.values[0].actions.length : 0
450
+ } : null
451
+ }));
452
+ }
453
+ // ========== END DEBUG ==========
454
+
358
455
  var handled = evalDynamicTap(config);
359
456
  if (handled) {
457
+ debugScreen19Dynamic('Click HANDLED by dynamic tap - event stopped', { handled: true });
360
458
  event.stopImmediatePropagation();
361
459
  event.preventDefault();
362
460
  return false;
363
461
  }
364
462
  } catch (e) {
365
463
  console.log('[RampKit] Dynamic tap error:', e);
464
+ if (isScreen19Dynamic()) {
465
+ console.log('[SCREEN19-DEBUG][Click] Dynamic tap parse error:', e.message);
466
+ }
366
467
  }
367
468
  }
368
-
469
+
369
470
  // Install interceptor on window in capture phase
370
471
  window.addEventListener('click', interceptClick, true);
371
472
  })();
@@ -378,68 +479,117 @@ exports.injectedButtonAnimations = `
378
479
  try {
379
480
  if (window.__rkButtonAnimApplied) return true;
380
481
  window.__rkButtonAnimApplied = true;
381
-
482
+
382
483
  var pressed = null;
383
484
  var pressedOriginalTransform = '';
384
485
  var pressedOriginalOpacity = '';
385
486
  var pressedOriginalTransition = '';
386
487
  var releaseTimer = null;
387
-
488
+
489
+ // ========== DEBUG: Screen 19 specific logging (REMOVE AFTER BUG FIX) ==========
490
+ var isScreen19 = function() {
491
+ // Check multiple ways to identify Screen 19
492
+ var screenId = window.__rampkitScreenId || '';
493
+ var screenIndex = window.__rampkitScreenIndex;
494
+ return screenId.indexOf('19') !== -1 ||
495
+ screenId.toLowerCase().indexOf('screen 19') !== -1 ||
496
+ screenId.toLowerCase().indexOf('screen19') !== -1 ||
497
+ screenIndex === 19 ||
498
+ screenIndex === 18; // 0-indexed, so screen 19 would be index 18
499
+ };
500
+
501
+ var debugScreen19 = function(msg, data) {
502
+ if (isScreen19()) {
503
+ console.log('[SCREEN19-DEBUG][ButtonAnim] ' + msg, JSON.stringify(data || {}));
504
+ }
505
+ };
506
+ // ========== END DEBUG ==========
507
+
388
508
  // Find interactive element - very permissive, looks for any clickable-looking element
389
509
  function findInteractive(el) {
390
510
  var current = el;
511
+ var debugTrail = []; // DEBUG: Track search path for Screen 19
512
+
391
513
  for (var i = 0; i < 20 && current && current !== document.body && current !== document.documentElement; i++) {
392
514
  if (!current || !current.tagName) { current = current.parentElement; continue; }
393
515
  var tag = current.tagName.toLowerCase();
394
-
516
+
395
517
  // Skip tiny elements (likely icons inside buttons)
396
518
  var rect = current.getBoundingClientRect();
397
519
  if (rect.width < 20 || rect.height < 20) { current = current.parentElement; continue; }
398
-
520
+
521
+ // DEBUG: Build trail for Screen 19
522
+ var debugInfo = {
523
+ depth: i,
524
+ tag: tag,
525
+ id: current.id || '(none)',
526
+ class: (current.className && typeof current.className === 'string') ? current.className.substring(0, 100) : '(none)',
527
+ size: rect.width + 'x' + rect.height
528
+ };
529
+ debugTrail.push(debugInfo);
530
+
399
531
  // Match standard interactive elements
400
- if (tag === 'button' || tag === 'a' || tag === 'input' || tag === 'select') return current;
401
-
532
+ if (tag === 'button' || tag === 'a' || tag === 'input' || tag === 'select') {
533
+ debugScreen19('MATCHED: standard tag', { reason: 'tag=' + tag, element: debugInfo, trail: debugTrail });
534
+ return current;
535
+ }
536
+
402
537
  // Match elements with any data attribute containing action/navigate/tap/click
403
538
  var attrs = current.attributes;
404
539
  if (attrs) {
405
540
  for (var j = 0; j < attrs.length; j++) {
406
541
  var attrName = attrs[j].name.toLowerCase();
407
- if (attrName.indexOf('click') !== -1 || attrName.indexOf('tap') !== -1 ||
542
+ if (attrName.indexOf('click') !== -1 || attrName.indexOf('tap') !== -1 ||
408
543
  attrName.indexOf('action') !== -1 || attrName.indexOf('navigate') !== -1 ||
409
544
  attrName.indexOf('press') !== -1) {
545
+ debugScreen19('MATCHED: data-attr', { reason: 'attr=' + attrName, value: attrs[j].value.substring(0,50), element: debugInfo, trail: debugTrail });
410
546
  return current;
411
547
  }
412
548
  }
413
549
  }
414
-
550
+
415
551
  // Match elements with onclick
416
- if (current.onclick || current.hasAttribute('onclick')) return current;
417
-
552
+ if (current.onclick || current.hasAttribute('onclick')) {
553
+ debugScreen19('MATCHED: onclick', { element: debugInfo, trail: debugTrail });
554
+ return current;
555
+ }
556
+
418
557
  // Match elements with role="button" or tabindex
419
- if (current.getAttribute('role') === 'button') return current;
420
-
558
+ if (current.getAttribute('role') === 'button') {
559
+ debugScreen19('MATCHED: role=button', { element: debugInfo, trail: debugTrail });
560
+ return current;
561
+ }
562
+
421
563
  // Match any element with an ID containing button/btn/cta
422
564
  var id = current.id || '';
423
- if (id && (id.toLowerCase().indexOf('button') !== -1 || id.toLowerCase().indexOf('btn') !== -1 || id.toLowerCase().indexOf('cta') !== -1)) return current;
424
-
565
+ if (id && (id.toLowerCase().indexOf('button') !== -1 || id.toLowerCase().indexOf('btn') !== -1 || id.toLowerCase().indexOf('cta') !== -1)) {
566
+ debugScreen19('MATCHED: button-like ID', { reason: 'id=' + id, element: debugInfo, trail: debugTrail });
567
+ return current;
568
+ }
569
+
425
570
  // Match elements with button-like classes
426
571
  var className = current.className;
427
572
  if (className && typeof className === 'string') {
428
573
  var cls = className.toLowerCase();
429
- if (cls.indexOf('btn') !== -1 || cls.indexOf('button') !== -1 || cls.indexOf('cta') !== -1 ||
574
+ if (cls.indexOf('btn') !== -1 || cls.indexOf('button') !== -1 || cls.indexOf('cta') !== -1 ||
430
575
  cls.indexOf('clickable') !== -1 || cls.indexOf('tappable') !== -1 || cls.indexOf('pressable') !== -1) {
576
+ debugScreen19('MATCHED: button-like class', { reason: 'class=' + className, element: debugInfo, trail: debugTrail });
431
577
  return current;
432
578
  }
433
579
  }
434
-
580
+
435
581
  // Match elements with cursor pointer
436
582
  try {
437
583
  var computed = window.getComputedStyle(current);
438
- if (computed && computed.cursor === 'pointer') return current;
584
+ if (computed && computed.cursor === 'pointer') {
585
+ debugScreen19('MATCHED: cursor:pointer', { element: debugInfo, trail: debugTrail });
586
+ return current;
587
+ }
439
588
  } catch(e) {}
440
-
589
+
441
590
  current = current.parentElement;
442
591
  }
592
+ debugScreen19('NO MATCH found', { originalTag: el.tagName, trail: debugTrail });
443
593
  return null;
444
594
  }
445
595
 
@@ -472,8 +622,43 @@ exports.injectedButtonAnimations = `
472
622
 
473
623
  function onTouchStart(e) {
474
624
  try {
625
+ // ========== DEBUG: Screen 19 touch logging ==========
626
+ if (isScreen19()) {
627
+ var touchX = e.touches ? e.touches[0].clientX : e.clientX;
628
+ var touchY = e.touches ? e.touches[0].clientY : e.clientY;
629
+ var originalTarget = e.target;
630
+ var originalRect = originalTarget.getBoundingClientRect ? originalTarget.getBoundingClientRect() : {};
631
+ console.log('[SCREEN19-DEBUG][TouchStart] Touch at (' + touchX + ',' + touchY + ')', JSON.stringify({
632
+ originalTarget: {
633
+ tag: originalTarget.tagName,
634
+ id: originalTarget.id || '(none)',
635
+ class: (originalTarget.className && typeof originalTarget.className === 'string') ? originalTarget.className.substring(0,100) : '(none)',
636
+ size: originalRect.width + 'x' + originalRect.height
637
+ }
638
+ }));
639
+ }
640
+ // ========== END DEBUG ==========
641
+
475
642
  var target = findInteractive(e.target);
476
643
  if (!target) return;
644
+
645
+ // ========== DEBUG: Screen 19 - log what element was found interactive ==========
646
+ if (isScreen19() && target) {
647
+ var targetRect = target.getBoundingClientRect();
648
+ var screenWidth = window.innerWidth;
649
+ var screenHeight = window.innerHeight;
650
+ var isFullScreen = (targetRect.width >= screenWidth * 0.9 && targetRect.height >= screenHeight * 0.9);
651
+ console.log('[SCREEN19-DEBUG][TouchStart] INTERACTIVE ELEMENT FOUND', JSON.stringify({
652
+ tag: target.tagName,
653
+ id: target.id || '(none)',
654
+ class: (target.className && typeof target.className === 'string') ? target.className.substring(0,100) : '(none)',
655
+ size: targetRect.width + 'x' + targetRect.height,
656
+ isFullScreen: isFullScreen,
657
+ WARNING: isFullScreen ? 'FULL SCREEN ELEMENT DETECTED - THIS IS THE BUG!' : 'normal element'
658
+ }));
659
+ }
660
+ // ========== END DEBUG ==========
661
+
477
662
  if (releaseTimer) { clearTimeout(releaseTimer); releaseTimer = null; }
478
663
  if (pressed && pressed !== target) { resetStyle(pressed); }
479
664
  applyPressedStyle(target);
@@ -1077,7 +1262,7 @@ function Overlay(props) {
1077
1262
  // Clear the queue
1078
1263
  pendingActionsRef.current[screenIndex] = [];
1079
1264
  };
1080
- // Activate a screen (set visibility flag and dispatch event)
1265
+ // Activate a screen (set visibility flag, dispatch event, and resume Lotties)
1081
1266
  const activateScreen = (screenIndex) => {
1082
1267
  var _a;
1083
1268
  const wv = webviewsRef.current[screenIndex];
@@ -1092,6 +1277,24 @@ function Overlay(props) {
1092
1277
  window.__rampkitScreenIndex = ${screenIndex};
1093
1278
  console.log('🔓 Screen ${screenIndex} ACTIVATED');
1094
1279
 
1280
+ // Resume all Lottie animations
1281
+ try {
1282
+ // lottie-web global API
1283
+ if (typeof lottie !== 'undefined' && lottie.play) {
1284
+ lottie.play();
1285
+ }
1286
+ // dotLottie players
1287
+ document.querySelectorAll('dotlottie-player, lottie-player').forEach(function(el) {
1288
+ if (el.play) el.play();
1289
+ });
1290
+ // lottie-web individual animations stored on window
1291
+ if (window.__rampkitLottieAnimations) {
1292
+ window.__rampkitLottieAnimations.forEach(function(anim) {
1293
+ if (anim && anim.play) anim.play();
1294
+ });
1295
+ }
1296
+ } catch(e) { console.log('Lottie play error:', e); }
1297
+
1095
1298
  // Dispatch custom event that HTML can listen to
1096
1299
  try {
1097
1300
  document.dispatchEvent(new CustomEvent('rampkit:screen-visible', {
@@ -1104,7 +1307,7 @@ function Overlay(props) {
1104
1307
  // Process any pending actions for this screen
1105
1308
  processPendingActions(screenIndex);
1106
1309
  };
1107
- // Deactivate a screen (clear visibility flag)
1310
+ // Deactivate a screen (clear visibility flag and pause Lotties)
1108
1311
  const deactivateScreen = (screenIndex) => {
1109
1312
  const wv = webviewsRef.current[screenIndex];
1110
1313
  if (!wv)
@@ -1115,6 +1318,24 @@ function Overlay(props) {
1115
1318
  const deactivateScript = `(function() {
1116
1319
  window.__rampkitScreenVisible = false;
1117
1320
  console.log('🔒 Screen ${screenIndex} DEACTIVATED');
1321
+
1322
+ // Pause all Lottie animations
1323
+ try {
1324
+ // lottie-web global API
1325
+ if (typeof lottie !== 'undefined' && lottie.pause) {
1326
+ lottie.pause();
1327
+ }
1328
+ // dotLottie players
1329
+ document.querySelectorAll('dotlottie-player, lottie-player').forEach(function(el) {
1330
+ if (el.pause) el.pause();
1331
+ });
1332
+ // lottie-web individual animations stored on window
1333
+ if (window.__rampkitLottieAnimations) {
1334
+ window.__rampkitLottieAnimations.forEach(function(anim) {
1335
+ if (anim && anim.pause) anim.pause();
1336
+ });
1337
+ }
1338
+ } catch(e) { console.log('Lottie pause error:', e); }
1118
1339
  })();`;
1119
1340
  // @ts-ignore: injectJavaScript exists on WebView instance
1120
1341
  wv.injectJavaScript(deactivateScript);
@@ -1322,26 +1543,26 @@ function Overlay(props) {
1322
1543
  const nextScreenAnim = screenAnims[nextIndex];
1323
1544
  const isForward = nextIndex > index;
1324
1545
  const direction = isForward ? 1 : -1;
1325
- // Slide animation: animate both screens simultaneously
1546
+ // Slide animation: animate both screens simultaneously using full screen width
1326
1547
  if (animationType === "slide") {
1327
1548
  setIsTransitioning(true);
1328
- // Set up next screen starting position (offscreen in direction of navigation)
1329
- nextScreenAnim.translateX.setValue(SLIDE_FADE_OFFSET * direction);
1549
+ // Set up next screen starting position (fully offscreen in direction of navigation)
1550
+ nextScreenAnim.translateX.setValue(windowWidth * direction);
1330
1551
  nextScreenAnim.opacity.setValue(1);
1331
- // Animate both screens
1552
+ // Animate both screens with smooth slide
1332
1553
  react_native_1.Animated.parallel([
1333
- // Current screen slides out
1554
+ // Current screen slides out (to the opposite side)
1334
1555
  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),
1556
+ toValue: -windowWidth * direction,
1557
+ duration: 300,
1558
+ easing: react_native_1.Easing.out(react_native_1.Easing.cubic),
1338
1559
  useNativeDriver: true,
1339
1560
  }),
1340
- // Next screen slides in
1561
+ // Next screen slides in (from offscreen to center)
1341
1562
  react_native_1.Animated.timing(nextScreenAnim.translateX, {
1342
1563
  toValue: 0,
1343
- duration: SLIDE_FADE_DURATION,
1344
- easing: react_native_1.Easing.out(react_native_1.Easing.ease),
1564
+ duration: 300,
1565
+ easing: react_native_1.Easing.out(react_native_1.Easing.cubic),
1345
1566
  useNativeDriver: true,
1346
1567
  }),
1347
1568
  ]).start(() => {
@@ -1705,7 +1926,7 @@ function Overlay(props) {
1705
1926
  !visible && styles.invisible,
1706
1927
  visible && { opacity: overlayOpacity },
1707
1928
  ], 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;
1929
+ var _a, _b, _c, _d;
1709
1930
  return ((0, jsx_runtime_1.jsx)(react_native_1.Animated.View, { style: [
1710
1931
  react_native_1.StyleSheet.absoluteFill,
1711
1932
  {
@@ -1722,7 +1943,8 @@ function Overlay(props) {
1722
1943
  // This prevents review/notification requests from firing on inactive screens at startup.
1723
1944
  `window.__rampkitScreenVisible = ${i === 0};
1724
1945
  window.__rampkitScreenIndex = ${i};
1725
- console.log('[RampKit] Screen ${i} visibility initialized: ' + (${i === 0} ? 'ACTIVE' : 'INACTIVE'));
1946
+ window.__rampkitScreenId = '${((_c = props.screens[i]) === null || _c === void 0 ? void 0 : _c.id) || ""}';
1947
+ console.log('[RampKit] Screen ${i} (ID: ${((_d = props.screens[i]) === null || _d === void 0 ? void 0 : _d.id) || "unknown"}) visibility initialized: ' + (${i === 0} ? 'ACTIVE' : 'INACTIVE'));
1726
1948
  ` + 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: () => {
1727
1949
  // Only initialize each screen ONCE to avoid repeated processing
1728
1950
  if (initializedScreensRef.current.has(i)) {
@@ -1758,10 +1980,46 @@ function Overlay(props) {
1758
1980
  if (i === 0) {
1759
1981
  activateScreen(i);
1760
1982
  }
1983
+ else {
1984
+ // For non-active screens, pause Lotties immediately after load
1985
+ // (they may have auto-started during page render)
1986
+ const wv = webviewsRef.current[i];
1987
+ if (wv) {
1988
+ const pauseLottiesScript = `(function() {
1989
+ try {
1990
+ if (typeof lottie !== 'undefined' && lottie.pause) lottie.pause();
1991
+ document.querySelectorAll('dotlottie-player, lottie-player').forEach(function(el) {
1992
+ if (el.pause) el.pause();
1993
+ });
1994
+ if (window.__rampkitLottieAnimations) {
1995
+ window.__rampkitLottieAnimations.forEach(function(anim) {
1996
+ if (anim && anim.pause) anim.pause();
1997
+ });
1998
+ }
1999
+ } catch(e) {}
2000
+ })();`;
2001
+ // @ts-ignore
2002
+ wv.injectJavaScript(pauseLottiesScript);
2003
+ }
2004
+ }
1761
2005
  }, onMessage: (ev) => {
1762
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
2006
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
1763
2007
  const raw = ev.nativeEvent.data;
1764
2008
  console.log("raw", raw);
2009
+ // ========== DEBUG: Screen 19 onMessage logging (REMOVE AFTER BUG FIX) ==========
2010
+ const screenId = ((_a = props.screens[i]) === null || _a === void 0 ? void 0 : _a.id) || "";
2011
+ const isScreen19OnMsg = screenId.indexOf('19') !== -1 ||
2012
+ screenId.toLowerCase().indexOf('screen 19') !== -1 ||
2013
+ screenId.toLowerCase().indexOf('screen19') !== -1 ||
2014
+ i === 19 || i === 18;
2015
+ if (isScreen19OnMsg) {
2016
+ console.log(`[SCREEN19-DEBUG][onMessage] Received message from screen ${i} (ID: ${screenId})`, JSON.stringify({
2017
+ rawPreview: raw.substring(0, 200),
2018
+ isActiveScreen: i === activeScreenIndexRef.current,
2019
+ activeScreenIndex: activeScreenIndexRef.current
2020
+ }));
2021
+ }
2022
+ // ========== END DEBUG ==========
1765
2023
  // Accept either raw strings or JSON payloads from your editor
1766
2024
  try {
1767
2025
  // JSON path
@@ -1887,7 +2145,7 @@ function Overlay(props) {
1887
2145
  if ((data === null || data === void 0 ? void 0 : data.type) === "rampkit:onboarding-finished") {
1888
2146
  setOnboardingCompleted(true);
1889
2147
  try {
1890
- (_a = props.onOnboardingFinished) === null || _a === void 0 ? void 0 : _a.call(props, data === null || data === void 0 ? void 0 : data.payload);
2148
+ (_b = props.onOnboardingFinished) === null || _b === void 0 ? void 0 : _b.call(props, data === null || data === void 0 ? void 0 : data.payload);
1891
2149
  }
1892
2150
  catch (_) { }
1893
2151
  handleRequestClose({ completed: true });
@@ -1896,7 +2154,7 @@ function Overlay(props) {
1896
2154
  // 6) Request to show paywall
1897
2155
  if ((data === null || data === void 0 ? void 0 : data.type) === "rampkit:show-paywall") {
1898
2156
  try {
1899
- (_b = props.onShowPaywall) === null || _b === void 0 ? void 0 : _b.call(props, data === null || data === void 0 ? void 0 : data.payload);
2157
+ (_c = props.onShowPaywall) === null || _c === void 0 ? void 0 : _c.call(props, data === null || data === void 0 ? void 0 : data.payload);
1900
2158
  }
1901
2159
  catch (_) { }
1902
2160
  return;
@@ -1907,9 +2165,9 @@ function Overlay(props) {
1907
2165
  if (questionId) {
1908
2166
  const response = {
1909
2167
  questionId,
1910
- answer: (_c = data === null || data === void 0 ? void 0 : data.answer) !== null && _c !== void 0 ? _c : "",
2168
+ answer: (_d = data === null || data === void 0 ? void 0 : data.answer) !== null && _d !== void 0 ? _d : "",
1911
2169
  questionText: data === null || data === void 0 ? void 0 : data.questionText,
1912
- screenName: (_d = props.screens[i]) === null || _d === void 0 ? void 0 : _d.id,
2170
+ screenName: (_e = props.screens[i]) === null || _e === void 0 ? void 0 : _e.id,
1913
2171
  answeredAt: new Date().toISOString(),
1914
2172
  };
1915
2173
  OnboardingResponseStorage_1.OnboardingResponseStorage.saveResponse(response);
@@ -1924,6 +2182,14 @@ function Overlay(props) {
1924
2182
  console.log(`[RampKit] Ignoring continue from inactive screen ${i}`);
1925
2183
  return;
1926
2184
  }
2185
+ // ========== DEBUG: Screen 19 continue logging ==========
2186
+ if (isScreen19OnMsg) {
2187
+ console.log(`[SCREEN19-DEBUG][onMessage] CONTINUE action triggered from screen ${i}`, JSON.stringify({
2188
+ animation: (data === null || data === void 0 ? void 0 : data.animation) || "fade",
2189
+ screenId: screenId
2190
+ }));
2191
+ }
2192
+ // ========== END DEBUG ==========
1927
2193
  handleAdvance(i, (data === null || data === void 0 ? void 0 : data.animation) || "fade");
1928
2194
  return;
1929
2195
  }
@@ -1935,6 +2201,15 @@ function Overlay(props) {
1935
2201
  return;
1936
2202
  }
1937
2203
  const target = data === null || data === void 0 ? void 0 : data.targetScreenId;
2204
+ // ========== DEBUG: Screen 19 navigate logging ==========
2205
+ if (isScreen19OnMsg) {
2206
+ console.log(`[SCREEN19-DEBUG][onMessage] NAVIGATE action triggered from screen ${i}`, JSON.stringify({
2207
+ target: target,
2208
+ animation: (data === null || data === void 0 ? void 0 : data.animation) || "fade",
2209
+ screenId: screenId
2210
+ }));
2211
+ }
2212
+ // ========== END DEBUG ==========
1938
2213
  if (target === "__goBack__") {
1939
2214
  handleGoBack(i, (data === null || data === void 0 ? void 0 : data.animation) || "fade");
1940
2215
  return;
@@ -1965,7 +2240,7 @@ function Overlay(props) {
1965
2240
  if ((data === null || data === void 0 ? void 0 : data.type) === "rampkit:close") {
1966
2241
  // Track close action for onboarding completion
1967
2242
  try {
1968
- (_e = props.onCloseAction) === null || _e === void 0 ? void 0 : _e.call(props, i, ((_f = props.screens[i]) === null || _f === void 0 ? void 0 : _f.id) || "");
2243
+ (_f = props.onCloseAction) === null || _f === void 0 ? void 0 : _f.call(props, i, ((_g = props.screens[i]) === null || _g === void 0 ? void 0 : _g.id) || "");
1969
2244
  }
1970
2245
  catch (_) { }
1971
2246
  handleRequestClose({ completed: true }); // Mark as completed so abandonment isn't tracked
@@ -1976,7 +2251,7 @@ function Overlay(props) {
1976
2251
  return;
1977
2252
  }
1978
2253
  }
1979
- catch (_l) {
2254
+ catch (_m) {
1980
2255
  // String path
1981
2256
  if (raw === "rampkit:tap" ||
1982
2257
  raw === "next" ||
@@ -2027,7 +2302,7 @@ function Overlay(props) {
2027
2302
  if (raw === "rampkit:onboarding-finished") {
2028
2303
  setOnboardingCompleted(true);
2029
2304
  try {
2030
- (_g = props.onOnboardingFinished) === null || _g === void 0 ? void 0 : _g.call(props, undefined);
2305
+ (_h = props.onOnboardingFinished) === null || _h === void 0 ? void 0 : _h.call(props, undefined);
2031
2306
  }
2032
2307
  catch (_) { }
2033
2308
  handleRequestClose({ completed: true });
@@ -2035,7 +2310,7 @@ function Overlay(props) {
2035
2310
  }
2036
2311
  if (raw === "rampkit:show-paywall") {
2037
2312
  try {
2038
- (_h = props.onShowPaywall) === null || _h === void 0 ? void 0 : _h.call(props);
2313
+ (_j = props.onShowPaywall) === null || _j === void 0 ? void 0 : _j.call(props);
2039
2314
  }
2040
2315
  catch (_) { }
2041
2316
  return;
@@ -2078,7 +2353,7 @@ function Overlay(props) {
2078
2353
  if (raw === "rampkit:close") {
2079
2354
  // Track close action for onboarding completion
2080
2355
  try {
2081
- (_j = props.onCloseAction) === null || _j === void 0 ? void 0 : _j.call(props, i, ((_k = props.screens[i]) === null || _k === void 0 ? void 0 : _k.id) || "");
2356
+ (_k = props.onCloseAction) === null || _k === void 0 ? void 0 : _k.call(props, i, ((_l = props.screens[i]) === null || _l === void 0 ? void 0 : _l.id) || "");
2082
2357
  }
2083
2358
  catch (_) { }
2084
2359
  handleRequestClose({ completed: true }); // Mark as completed so abandonment isn't tracked
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rampkit-expo-dev",
3
- "version": "0.0.80",
3
+ "version": "0.0.82",
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",