rampkit-expo-dev 0.0.82 → 0.0.83

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 // ========== 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";
5
+ export declare const injectedDynamicTapHandler = "\n(function() {\n if (window.__rampkitClickInterceptorInstalled) return;\n window.__rampkitClickInterceptorInstalled = true;\n\n // ========== DEBUG: phone-21 (buggy screen) specific logging (REMOVE AFTER BUG FIX) ==========\n var isBuggyScreen = function() {\n var screenId = window.__rampkitScreenId || '';\n var screenIndex = window.__rampkitScreenIndex;\n return screenId === 'phone-21' || screenIndex === 18;\n };\n\n var debugBuggyScreen = function(source, msg, data) {\n if (isBuggyScreen()) {\n var logData = { source: source, msg: msg, data: data };\n console.log('[BUGGY-SCREEN][' + source + '] ' + msg, JSON.stringify(data || {}));\n // Send to React Native via postMessage for visibility in RN console\n try {\n if (window.ReactNativeWebView && window.ReactNativeWebView.postMessage) {\n window.ReactNativeWebView.postMessage(JSON.stringify({\n type: 'rampkit:debug-buggy-screen',\n source: source,\n message: msg,\n data: data\n }));\n }\n } catch(e) {}\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 debugBuggyScreen('DynamicTap', '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 debugBuggyScreen('DynamicTap', '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 debugBuggyScreen('DynamicTap', '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: phone-21 click logging ==========\n if (isBuggyScreen()) {\n var clickX = event.clientX;\n var clickY = event.clientY;\n var originalTarget = event.target;\n var originalRect = originalTarget.getBoundingClientRect ? originalTarget.getBoundingClientRect() : {};\n debugBuggyScreen('Click', 'Click at (' + clickX + ',' + clickY + ')', {\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: phone-21 - log when dynamic tap is found ==========\n if (isBuggyScreen()) {\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 debugBuggyScreen('Click', 'DYNAMIC TAP WILL BE HANDLED', {\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: phone-21 - log parsed config ==========\n if (isBuggyScreen()) {\n debugBuggyScreen('Click', 'Parsed config', {\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 debugBuggyScreen('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 (isBuggyScreen()) {\n debugBuggyScreen('Click', 'Dynamic tap parse error', { 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: phone-21 (buggy screen) specific logging (REMOVE AFTER BUG FIX) ==========\n var isBuggyScreenAnim = function() {\n var screenId = window.__rampkitScreenId || '';\n var screenIndex = window.__rampkitScreenIndex;\n return screenId === 'phone-21' || screenIndex === 18;\n };\n\n var debugBuggyScreenAnim = function(source, msg, data) {\n if (isBuggyScreenAnim()) {\n console.log('[BUGGY-SCREEN][' + source + '] ' + msg, JSON.stringify(data || {}));\n // Send to React Native via postMessage for visibility\n try {\n if (window.ReactNativeWebView && window.ReactNativeWebView.postMessage) {\n window.ReactNativeWebView.postMessage(JSON.stringify({\n type: 'rampkit:debug-buggy-screen',\n source: source,\n message: msg,\n data: data\n }));\n }\n } catch(e) {}\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 debugBuggyScreenAnim('ButtonAnim', '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 debugBuggyScreenAnim('ButtonAnim', '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 debugBuggyScreenAnim('ButtonAnim', '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 debugBuggyScreenAnim('ButtonAnim', '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 debugBuggyScreenAnim('ButtonAnim', '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 debugBuggyScreenAnim('ButtonAnim', '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 debugBuggyScreenAnim('ButtonAnim', 'MATCHED: cursor:pointer', { element: debugInfo, trail: debugTrail });\n return current;\n }\n } catch(e) {}\n\n current = current.parentElement;\n }\n debugBuggyScreenAnim('ButtonAnim', '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: phone-21 touch logging ==========\n if (isBuggyScreenAnim()) {\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 debugBuggyScreenAnim('TouchStart', 'Touch at (' + touchX + ',' + touchY + ')', {\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: phone-21 - log what element was found interactive ==========\n if (isBuggyScreenAnim() && 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 debugBuggyScreenAnim('TouchStart', 'INTERACTIVE ELEMENT FOUND', {\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;
@@ -182,20 +182,28 @@ exports.injectedDynamicTapHandler = `
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() {
185
+ // ========== DEBUG: phone-21 (buggy screen) specific logging (REMOVE AFTER BUG FIX) ==========
186
+ var isBuggyScreen = function() {
187
187
  var screenId = window.__rampkitScreenId || '';
188
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;
189
+ return screenId === 'phone-21' || screenIndex === 18;
194
190
  };
195
191
 
196
- var debugScreen19Dynamic = function(msg, data) {
197
- if (isScreen19Dynamic()) {
198
- console.log('[SCREEN19-DEBUG][DynamicTap] ' + msg, JSON.stringify(data || {}));
192
+ var debugBuggyScreen = function(source, msg, data) {
193
+ if (isBuggyScreen()) {
194
+ var logData = { source: source, msg: msg, data: data };
195
+ console.log('[BUGGY-SCREEN][' + source + '] ' + msg, JSON.stringify(data || {}));
196
+ // Send to React Native via postMessage for visibility in RN console
197
+ try {
198
+ if (window.ReactNativeWebView && window.ReactNativeWebView.postMessage) {
199
+ window.ReactNativeWebView.postMessage(JSON.stringify({
200
+ type: 'rampkit:debug-buggy-screen',
201
+ source: source,
202
+ message: msg,
203
+ data: data
204
+ }));
205
+ }
206
+ } catch(e) {}
199
207
  }
200
208
  };
201
209
  // ========== END DEBUG ==========
@@ -230,7 +238,7 @@ exports.injectedDynamicTapHandler = `
230
238
  var attr = current.getAttribute(attrNames[i]);
231
239
  if (attr && attr.length > 2) {
232
240
  var rect = current.getBoundingClientRect ? current.getBoundingClientRect() : {};
233
- debugScreen19Dynamic('FOUND data-tap-dynamic', {
241
+ debugBuggyScreen('DynamicTap', 'FOUND data-tap-dynamic', {
234
242
  attrName: attrNames[i],
235
243
  depth: depth,
236
244
  element: trailInfo,
@@ -243,7 +251,7 @@ exports.injectedDynamicTapHandler = `
243
251
  }
244
252
  if (current.dataset && current.dataset.tapDynamic) {
245
253
  var rect2 = current.getBoundingClientRect ? current.getBoundingClientRect() : {};
246
- debugScreen19Dynamic('FOUND dataset.tapDynamic', {
254
+ debugBuggyScreen('DynamicTap', 'FOUND dataset.tapDynamic', {
247
255
  depth: depth,
248
256
  element: trailInfo,
249
257
  size: rect2.width + 'x' + rect2.height,
@@ -255,7 +263,7 @@ exports.injectedDynamicTapHandler = `
255
263
  current = current.parentElement;
256
264
  depth++;
257
265
  }
258
- debugScreen19Dynamic('NO data-tap-dynamic found', { trail: searchTrail });
266
+ debugBuggyScreen('DynamicTap', 'NO data-tap-dynamic found', { trail: searchTrail });
259
267
  return null;
260
268
  }
261
269
 
@@ -395,33 +403,33 @@ exports.injectedDynamicTapHandler = `
395
403
 
396
404
  // Click interceptor - capture phase, runs BEFORE onclick handlers
397
405
  function interceptClick(event) {
398
- // ========== DEBUG: Screen 19 click logging ==========
399
- if (isScreen19Dynamic()) {
406
+ // ========== DEBUG: phone-21 click logging ==========
407
+ if (isBuggyScreen()) {
400
408
  var clickX = event.clientX;
401
409
  var clickY = event.clientY;
402
410
  var originalTarget = event.target;
403
411
  var originalRect = originalTarget.getBoundingClientRect ? originalTarget.getBoundingClientRect() : {};
404
- console.log('[SCREEN19-DEBUG][Click] Click at (' + clickX + ',' + clickY + ')', JSON.stringify({
412
+ debugBuggyScreen('Click', 'Click at (' + clickX + ',' + clickY + ')', {
405
413
  originalTarget: {
406
414
  tag: originalTarget.tagName,
407
415
  id: originalTarget.id || '(none)',
408
416
  class: (originalTarget.className && typeof originalTarget.className === 'string') ? originalTarget.className.substring(0,100) : '(none)',
409
417
  size: originalRect.width + 'x' + originalRect.height
410
418
  }
411
- }));
419
+ });
412
420
  }
413
421
  // ========== END DEBUG ==========
414
422
 
415
423
  var result = findDynamicTap(event.target);
416
424
  if (!result) return;
417
425
 
418
- // ========== DEBUG: Screen 19 - log when dynamic tap is found ==========
419
- if (isScreen19Dynamic()) {
426
+ // ========== DEBUG: phone-21 - log when dynamic tap is found ==========
427
+ if (isBuggyScreen()) {
420
428
  var rect = result.element.getBoundingClientRect ? result.element.getBoundingClientRect() : {};
421
429
  var screenWidth = window.innerWidth;
422
430
  var screenHeight = window.innerHeight;
423
431
  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({
432
+ debugBuggyScreen('Click', 'DYNAMIC TAP WILL BE HANDLED', {
425
433
  element: {
426
434
  tag: result.element.tagName,
427
435
  id: result.element.id || '(none)',
@@ -430,7 +438,7 @@ exports.injectedDynamicTapHandler = `
430
438
  },
431
439
  isFullScreen: isFullScreen,
432
440
  WARNING: isFullScreen ? 'FULL SCREEN ELEMENT WITH DYNAMIC TAP - THIS IS THE BUG!' : 'normal element'
433
- }));
441
+ });
434
442
  }
435
443
  // ========== END DEBUG ==========
436
444
 
@@ -438,9 +446,9 @@ exports.injectedDynamicTapHandler = `
438
446
  var configStr = decodeHtml(result.config);
439
447
  var config = JSON.parse(configStr);
440
448
 
441
- // ========== DEBUG: Screen 19 - log parsed config ==========
442
- if (isScreen19Dynamic()) {
443
- console.log('[SCREEN19-DEBUG][Click] Parsed config:', JSON.stringify({
449
+ // ========== DEBUG: phone-21 - log parsed config ==========
450
+ if (isBuggyScreen()) {
451
+ debugBuggyScreen('Click', 'Parsed config', {
444
452
  hasValues: !!(config && config.values),
445
453
  valuesCount: config && config.values ? config.values.length : 0,
446
454
  firstCondition: config && config.values && config.values[0] ? {
@@ -448,21 +456,21 @@ exports.injectedDynamicTapHandler = `
448
456
  rulesCount: config.values[0].rules ? config.values[0].rules.length : 0,
449
457
  actionsCount: config.values[0].actions ? config.values[0].actions.length : 0
450
458
  } : null
451
- }));
459
+ });
452
460
  }
453
461
  // ========== END DEBUG ==========
454
462
 
455
463
  var handled = evalDynamicTap(config);
456
464
  if (handled) {
457
- debugScreen19Dynamic('Click HANDLED by dynamic tap - event stopped', { handled: true });
465
+ debugBuggyScreen('Click', 'HANDLED by dynamic tap - event stopped', { handled: true });
458
466
  event.stopImmediatePropagation();
459
467
  event.preventDefault();
460
468
  return false;
461
469
  }
462
470
  } catch (e) {
463
471
  console.log('[RampKit] Dynamic tap error:', e);
464
- if (isScreen19Dynamic()) {
465
- console.log('[SCREEN19-DEBUG][Click] Dynamic tap parse error:', e.message);
472
+ if (isBuggyScreen()) {
473
+ debugBuggyScreen('Click', 'Dynamic tap parse error', { error: e.message });
466
474
  }
467
475
  }
468
476
  }
@@ -486,21 +494,27 @@ exports.injectedButtonAnimations = `
486
494
  var pressedOriginalTransition = '';
487
495
  var releaseTimer = null;
488
496
 
489
- // ========== DEBUG: Screen 19 specific logging (REMOVE AFTER BUG FIX) ==========
490
- var isScreen19 = function() {
491
- // Check multiple ways to identify Screen 19
497
+ // ========== DEBUG: phone-21 (buggy screen) specific logging (REMOVE AFTER BUG FIX) ==========
498
+ var isBuggyScreenAnim = function() {
492
499
  var screenId = window.__rampkitScreenId || '';
493
500
  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
501
+ return screenId === 'phone-21' || screenIndex === 18;
499
502
  };
500
503
 
501
- var debugScreen19 = function(msg, data) {
502
- if (isScreen19()) {
503
- console.log('[SCREEN19-DEBUG][ButtonAnim] ' + msg, JSON.stringify(data || {}));
504
+ var debugBuggyScreenAnim = function(source, msg, data) {
505
+ if (isBuggyScreenAnim()) {
506
+ console.log('[BUGGY-SCREEN][' + source + '] ' + msg, JSON.stringify(data || {}));
507
+ // Send to React Native via postMessage for visibility
508
+ try {
509
+ if (window.ReactNativeWebView && window.ReactNativeWebView.postMessage) {
510
+ window.ReactNativeWebView.postMessage(JSON.stringify({
511
+ type: 'rampkit:debug-buggy-screen',
512
+ source: source,
513
+ message: msg,
514
+ data: data
515
+ }));
516
+ }
517
+ } catch(e) {}
504
518
  }
505
519
  };
506
520
  // ========== END DEBUG ==========
@@ -530,7 +544,7 @@ exports.injectedButtonAnimations = `
530
544
 
531
545
  // Match standard interactive elements
532
546
  if (tag === 'button' || tag === 'a' || tag === 'input' || tag === 'select') {
533
- debugScreen19('MATCHED: standard tag', { reason: 'tag=' + tag, element: debugInfo, trail: debugTrail });
547
+ debugBuggyScreenAnim('ButtonAnim', 'MATCHED: standard tag', { reason: 'tag=' + tag, element: debugInfo, trail: debugTrail });
534
548
  return current;
535
549
  }
536
550
 
@@ -542,7 +556,7 @@ exports.injectedButtonAnimations = `
542
556
  if (attrName.indexOf('click') !== -1 || attrName.indexOf('tap') !== -1 ||
543
557
  attrName.indexOf('action') !== -1 || attrName.indexOf('navigate') !== -1 ||
544
558
  attrName.indexOf('press') !== -1) {
545
- debugScreen19('MATCHED: data-attr', { reason: 'attr=' + attrName, value: attrs[j].value.substring(0,50), element: debugInfo, trail: debugTrail });
559
+ debugBuggyScreenAnim('ButtonAnim', 'MATCHED: data-attr', { reason: 'attr=' + attrName, value: attrs[j].value.substring(0,50), element: debugInfo, trail: debugTrail });
546
560
  return current;
547
561
  }
548
562
  }
@@ -550,20 +564,20 @@ exports.injectedButtonAnimations = `
550
564
 
551
565
  // Match elements with onclick
552
566
  if (current.onclick || current.hasAttribute('onclick')) {
553
- debugScreen19('MATCHED: onclick', { element: debugInfo, trail: debugTrail });
567
+ debugBuggyScreenAnim('ButtonAnim', 'MATCHED: onclick', { element: debugInfo, trail: debugTrail });
554
568
  return current;
555
569
  }
556
570
 
557
571
  // Match elements with role="button" or tabindex
558
572
  if (current.getAttribute('role') === 'button') {
559
- debugScreen19('MATCHED: role=button', { element: debugInfo, trail: debugTrail });
573
+ debugBuggyScreenAnim('ButtonAnim', 'MATCHED: role=button', { element: debugInfo, trail: debugTrail });
560
574
  return current;
561
575
  }
562
576
 
563
577
  // Match any element with an ID containing button/btn/cta
564
578
  var id = current.id || '';
565
579
  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 });
580
+ debugBuggyScreenAnim('ButtonAnim', 'MATCHED: button-like ID', { reason: 'id=' + id, element: debugInfo, trail: debugTrail });
567
581
  return current;
568
582
  }
569
583
 
@@ -573,7 +587,7 @@ exports.injectedButtonAnimations = `
573
587
  var cls = className.toLowerCase();
574
588
  if (cls.indexOf('btn') !== -1 || cls.indexOf('button') !== -1 || cls.indexOf('cta') !== -1 ||
575
589
  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 });
590
+ debugBuggyScreenAnim('ButtonAnim', 'MATCHED: button-like class', { reason: 'class=' + className, element: debugInfo, trail: debugTrail });
577
591
  return current;
578
592
  }
579
593
  }
@@ -582,14 +596,14 @@ exports.injectedButtonAnimations = `
582
596
  try {
583
597
  var computed = window.getComputedStyle(current);
584
598
  if (computed && computed.cursor === 'pointer') {
585
- debugScreen19('MATCHED: cursor:pointer', { element: debugInfo, trail: debugTrail });
599
+ debugBuggyScreenAnim('ButtonAnim', 'MATCHED: cursor:pointer', { element: debugInfo, trail: debugTrail });
586
600
  return current;
587
601
  }
588
602
  } catch(e) {}
589
603
 
590
604
  current = current.parentElement;
591
605
  }
592
- debugScreen19('NO MATCH found', { originalTag: el.tagName, trail: debugTrail });
606
+ debugBuggyScreenAnim('ButtonAnim', 'NO MATCH found', { originalTag: el.tagName, trail: debugTrail });
593
607
  return null;
594
608
  }
595
609
 
@@ -622,40 +636,40 @@ exports.injectedButtonAnimations = `
622
636
 
623
637
  function onTouchStart(e) {
624
638
  try {
625
- // ========== DEBUG: Screen 19 touch logging ==========
626
- if (isScreen19()) {
639
+ // ========== DEBUG: phone-21 touch logging ==========
640
+ if (isBuggyScreenAnim()) {
627
641
  var touchX = e.touches ? e.touches[0].clientX : e.clientX;
628
642
  var touchY = e.touches ? e.touches[0].clientY : e.clientY;
629
643
  var originalTarget = e.target;
630
644
  var originalRect = originalTarget.getBoundingClientRect ? originalTarget.getBoundingClientRect() : {};
631
- console.log('[SCREEN19-DEBUG][TouchStart] Touch at (' + touchX + ',' + touchY + ')', JSON.stringify({
645
+ debugBuggyScreenAnim('TouchStart', 'Touch at (' + touchX + ',' + touchY + ')', {
632
646
  originalTarget: {
633
647
  tag: originalTarget.tagName,
634
648
  id: originalTarget.id || '(none)',
635
649
  class: (originalTarget.className && typeof originalTarget.className === 'string') ? originalTarget.className.substring(0,100) : '(none)',
636
650
  size: originalRect.width + 'x' + originalRect.height
637
651
  }
638
- }));
652
+ });
639
653
  }
640
654
  // ========== END DEBUG ==========
641
655
 
642
656
  var target = findInteractive(e.target);
643
657
  if (!target) return;
644
658
 
645
- // ========== DEBUG: Screen 19 - log what element was found interactive ==========
646
- if (isScreen19() && target) {
659
+ // ========== DEBUG: phone-21 - log what element was found interactive ==========
660
+ if (isBuggyScreenAnim() && target) {
647
661
  var targetRect = target.getBoundingClientRect();
648
662
  var screenWidth = window.innerWidth;
649
663
  var screenHeight = window.innerHeight;
650
664
  var isFullScreen = (targetRect.width >= screenWidth * 0.9 && targetRect.height >= screenHeight * 0.9);
651
- console.log('[SCREEN19-DEBUG][TouchStart] INTERACTIVE ELEMENT FOUND', JSON.stringify({
665
+ debugBuggyScreenAnim('TouchStart', 'INTERACTIVE ELEMENT FOUND', {
652
666
  tag: target.tagName,
653
667
  id: target.id || '(none)',
654
668
  class: (target.className && typeof target.className === 'string') ? target.className.substring(0,100) : '(none)',
655
669
  size: targetRect.width + 'x' + targetRect.height,
656
670
  isFullScreen: isFullScreen,
657
671
  WARNING: isFullScreen ? 'FULL SCREEN ELEMENT DETECTED - THIS IS THE BUG!' : 'normal element'
658
- }));
672
+ });
659
673
  }
660
674
  // ========== END DEBUG ==========
661
675
 
@@ -2006,19 +2020,25 @@ function Overlay(props) {
2006
2020
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
2007
2021
  const raw = ev.nativeEvent.data;
2008
2022
  console.log("raw", raw);
2009
- // ========== DEBUG: Screen 19 onMessage logging (REMOVE AFTER BUG FIX) ==========
2023
+ // ========== DEBUG: phone-21 onMessage logging (REMOVE AFTER BUG FIX) ==========
2010
2024
  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({
2025
+ const isBuggyScreenOnMsg = screenId === 'phone-21' || i === 18;
2026
+ if (isBuggyScreenOnMsg) {
2027
+ console.log(`[BUGGY-SCREEN][onMessage] Received message from screen ${i} (ID: ${screenId})`, JSON.stringify({
2017
2028
  rawPreview: raw.substring(0, 200),
2018
2029
  isActiveScreen: i === activeScreenIndexRef.current,
2019
2030
  activeScreenIndex: activeScreenIndexRef.current
2020
2031
  }));
2021
2032
  }
2033
+ // Also handle debug messages from WebView
2034
+ try {
2035
+ const debugData = JSON.parse(raw);
2036
+ if ((debugData === null || debugData === void 0 ? void 0 : debugData.type) === 'rampkit:debug-buggy-screen') {
2037
+ console.log(`[BUGGY-SCREEN][${debugData.source}] ${debugData.message}`, JSON.stringify(debugData.data || {}));
2038
+ return; // Don't process further, it's just a debug message
2039
+ }
2040
+ }
2041
+ catch (_) { }
2022
2042
  // ========== END DEBUG ==========
2023
2043
  // Accept either raw strings or JSON payloads from your editor
2024
2044
  try {
@@ -2182,9 +2202,9 @@ function Overlay(props) {
2182
2202
  console.log(`[RampKit] Ignoring continue from inactive screen ${i}`);
2183
2203
  return;
2184
2204
  }
2185
- // ========== DEBUG: Screen 19 continue logging ==========
2186
- if (isScreen19OnMsg) {
2187
- console.log(`[SCREEN19-DEBUG][onMessage] CONTINUE action triggered from screen ${i}`, JSON.stringify({
2205
+ // ========== DEBUG: phone-21 continue logging ==========
2206
+ if (isBuggyScreenOnMsg) {
2207
+ console.log(`[BUGGY-SCREEN][onMessage] CONTINUE action triggered from screen ${i}`, JSON.stringify({
2188
2208
  animation: (data === null || data === void 0 ? void 0 : data.animation) || "fade",
2189
2209
  screenId: screenId
2190
2210
  }));
@@ -2201,9 +2221,9 @@ function Overlay(props) {
2201
2221
  return;
2202
2222
  }
2203
2223
  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({
2224
+ // ========== DEBUG: phone-21 navigate logging ==========
2225
+ if (isBuggyScreenOnMsg) {
2226
+ console.log(`[BUGGY-SCREEN][onMessage] NAVIGATE action triggered from screen ${i}`, JSON.stringify({
2207
2227
  target: target,
2208
2228
  animation: (data === null || data === void 0 ? void 0 : data.animation) || "fade",
2209
2229
  screenId: screenId
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rampkit-expo-dev",
3
- "version": "0.0.82",
3
+ "version": "0.0.83",
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",