rampkit-expo-dev 0.0.83 → 0.0.84
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/RampkitOverlay.d.ts +2 -2
- package/build/RampkitOverlay.js +31 -258
- package/package.json +1 -1
|
@@ -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: 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(/"/g, '\"').replace(/"/g, '\"').replace(/"/g, '\"')\n .replace(/'/g, \"'\").replace(/'/g, \"'\").replace(/'/g, \"'\")\n .replace(/</g, '<').replace(/>/g, '>').replace(/&/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";
|
|
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(/"/g, '\"').replace(/"/g, '\"').replace(/"/g, '\"')\n .replace(/'/g, \"'\").replace(/'/g, \"'\").replace(/'/g, \"'\")\n .replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&');\n }\n\n // Find dynamic tap config on element or ancestors\n function findDynamicTap(el) {\n var current = el;\n var depth = 0;\n var attrNames = ['data-tap-dynamic', 'data-tapdynamic', 'tapDynamic', 'data-dynamic-tap'];\n while (current && current !== document.body && current !== document.documentElement && depth < 20) {\n if (current.getAttribute) {\n for (var i = 0; i < attrNames.length; i++) {\n var attr = current.getAttribute(attrNames[i]);\n if (attr && attr.length > 2) {\n return { element: current, config: attr };\n }\n }\n if (current.dataset && current.dataset.tapDynamic) {\n return { element: current, config: current.dataset.tapDynamic };\n }\n }\n current = current.parentElement;\n depth++;\n }\n return null;\n }\n \n // Get variables for condition evaluation - check ALL possible sources\n function getVars() {\n var vars = {};\n if (window.__rampkitVariables) {\n Object.keys(window.__rampkitVariables).forEach(function(k) {\n vars[k] = window.__rampkitVariables[k];\n });\n }\n if (window.__rampkitVars) {\n Object.keys(window.__rampkitVars).forEach(function(k) {\n vars[k] = window.__rampkitVars[k];\n });\n }\n if (window.RK_VARS) {\n Object.keys(window.RK_VARS).forEach(function(k) {\n vars[k] = window.RK_VARS[k];\n });\n }\n return vars;\n }\n \n // Evaluate a single rule\n function evalRule(rule, vars) {\n if (!rule || !rule.key) return false;\n var left = vars[rule.key];\n var right = rule.value;\n var op = rule.op || '=';\n if (left === undefined || left === null) left = '';\n if (right === undefined || right === null) right = '';\n var leftStr = String(left);\n var rightStr = String(right);\n var result = false;\n switch (op) {\n case '=': case '==': result = leftStr === rightStr; break;\n case '!=': case '<>': result = leftStr !== rightStr; break;\n case '>': result = parseFloat(left) > parseFloat(right); break;\n case '<': result = parseFloat(left) < parseFloat(right); break;\n case '>=': result = parseFloat(left) >= parseFloat(right); break;\n case '<=': result = parseFloat(left) <= parseFloat(right); break;\n default: result = false;\n }\n return result;\n }\n \n // Evaluate all rules (AND logic)\n function evalRules(rules, vars) {\n if (!rules || !rules.length) return true;\n for (var i = 0; i < rules.length; i++) {\n if (!evalRule(rules[i], vars)) return false;\n }\n return true;\n }\n \n // Execute an action\n function execAction(action) {\n if (!action || !action.type) return;\n var msg = null;\n var actionType = action.type.toLowerCase();\n \n switch (actionType) {\n case 'navigate':\n msg = { type: 'rampkit:navigate', targetScreenId: action.targetScreenId || '__continue__', animation: action.animation || 'fade' };\n break;\n case 'continue':\n msg = { type: 'rampkit:navigate', targetScreenId: '__continue__', animation: action.animation || 'fade' };\n break;\n case 'goback':\n msg = { type: 'rampkit:goBack', animation: action.animation || 'fade' };\n break;\n case 'close':\n msg = { type: 'rampkit:close' };\n break;\n case 'haptic':\n msg = { type: 'rampkit:haptic', hapticType: action.hapticType || 'impact', impactStyle: action.impactStyle || 'Medium', notificationType: action.notificationType };\n break;\n case 'showpaywall':\n msg = { type: 'rampkit:show-paywall', payload: action.payload || { paywallId: action.paywallId } };\n break;\n case 'requestreview':\n msg = { type: 'rampkit:request-review' };\n break;\n case 'requestnotificationpermission':\n msg = { type: 'rampkit:request-notification-permission' };\n break;\n case 'onboardingfinished':\n msg = { type: 'rampkit:onboarding-finished', payload: action.payload };\n break;\n case 'setvariable':\n case 'setstate':\n case 'updatevariable':\n case 'set':\n case 'assign':\n var varKey = action.key || action.variableName || action.name || action.variable;\n var varValue = action.variableValue !== undefined ? action.variableValue :\n action.value !== undefined ? action.value :\n action.newValue !== undefined ? action.newValue : undefined;\n if (varKey && varValue !== undefined) {\n if (window.__rampkitVariables) window.__rampkitVariables[varKey] = varValue;\n if (window.__rampkitVars) window.__rampkitVars[varKey] = varValue;\n var updateVars = {};\n updateVars[varKey] = varValue;\n msg = { type: 'rampkit:variables', vars: updateVars };\n }\n break;\n }\n if (msg) {\n try {\n if (window.ReactNativeWebView && window.ReactNativeWebView.postMessage) {\n window.ReactNativeWebView.postMessage(JSON.stringify(msg));\n }\n } catch(e) {}\n }\n }\n \n // Evaluate dynamic tap config\n function evalDynamicTap(config) {\n if (!config || !config.values) return false;\n var vars = getVars();\n var conditions = config.values;\n for (var i = 0; i < conditions.length; i++) {\n var cond = conditions[i];\n var condType = cond.conditionType || 'if';\n var rules = cond.rules || [];\n var actions = cond.actions || [];\n if (condType === 'else' || evalRules(rules, vars)) {\n for (var j = 0; j < actions.length; j++) {\n execAction(actions[j]);\n }\n return true;\n }\n }\n return false;\n }\n \n // Click interceptor - capture phase, runs BEFORE onclick handlers\n function interceptClick(event) {\n var result = findDynamicTap(event.target);\n if (!result) return;\n\n try {\n var configStr = decodeHtml(result.config);\n var config = JSON.parse(configStr);\n var handled = evalDynamicTap(config);\n if (handled) {\n event.stopImmediatePropagation();\n event.preventDefault();\n return false;\n }\n } catch (e) {\n console.log('[RampKit] Dynamic tap error:', e);\n }\n }\n\n // Install interceptor on window in capture phase\n window.addEventListener('click', interceptClick, true);\n})();\n";
|
|
6
|
+
export declare const injectedButtonAnimations = "\n(function(){\n try {\n if (window.__rkButtonAnimApplied) return true;\n window.__rkButtonAnimApplied = true;\n\n var pressed = null;\n var pressedOriginalTransform = '';\n var pressedOriginalOpacity = '';\n var pressedOriginalTransition = '';\n var releaseTimer = null;\n\n // Find interactive element - looks for clickable-looking elements\n function findInteractive(el) {\n var current = el;\n for (var i = 0; i < 20 && current && current !== document.body && current !== document.documentElement; i++) {\n if (!current || !current.tagName) { current = current.parentElement; continue; }\n var tag = current.tagName.toLowerCase();\n\n // Skip tiny elements (likely icons inside buttons)\n var rect = current.getBoundingClientRect();\n if (rect.width < 20 || rect.height < 20) { current = current.parentElement; continue; }\n\n // Match standard interactive elements\n if (tag === 'button' || tag === 'a' || tag === 'input' || tag === 'select') return current;\n\n // Match elements with tap/click-related data attributes\n // Exclude lifecycle attributes like data-on-open-actions, data-on-close-actions\n var attrs = current.attributes;\n if (attrs) {\n for (var j = 0; j < attrs.length; j++) {\n var attrName = attrs[j].name.toLowerCase();\n // Skip lifecycle attributes (on-open, on-close, on-load, on-appear, etc.)\n if (attrName.indexOf('on-open') !== -1 || attrName.indexOf('on-close') !== -1 ||\n attrName.indexOf('on-load') !== -1 || attrName.indexOf('on-appear') !== -1 ||\n attrName.indexOf('onopen') !== -1 || attrName.indexOf('onclose') !== -1 ||\n attrName.indexOf('onload') !== -1 || attrName.indexOf('onappear') !== -1) {\n continue;\n }\n // Match tap/click interaction attributes\n if (attrName.indexOf('click') !== -1 || attrName.indexOf('tap') !== -1 ||\n attrName.indexOf('action') !== -1 || attrName.indexOf('navigate') !== -1 ||\n attrName.indexOf('press') !== -1) {\n return current;\n }\n }\n }\n\n // Match elements with onclick\n if (current.onclick || current.hasAttribute('onclick')) return current;\n\n // Match elements with role=\"button\"\n if (current.getAttribute('role') === 'button') return current;\n\n // Match any element with an ID containing button/btn/cta\n var id = current.id || '';\n if (id && (id.toLowerCase().indexOf('button') !== -1 || id.toLowerCase().indexOf('btn') !== -1 || id.toLowerCase().indexOf('cta') !== -1)) return current;\n\n // Match elements with button-like classes\n var className = current.className;\n if (className && typeof className === 'string') {\n var cls = className.toLowerCase();\n if (cls.indexOf('btn') !== -1 || cls.indexOf('button') !== -1 || cls.indexOf('cta') !== -1 ||\n cls.indexOf('clickable') !== -1 || cls.indexOf('tappable') !== -1 || cls.indexOf('pressable') !== -1) {\n return current;\n }\n }\n\n // Match elements with cursor pointer\n try {\n var computed = window.getComputedStyle(current);\n if (computed && computed.cursor === 'pointer') return current;\n } catch(e) {}\n\n current = current.parentElement;\n }\n return null;\n }\n\n function applyPressedStyle(el) {\n if (!el || !el.style) return;\n // Save original styles\n pressedOriginalTransform = el.style.transform || '';\n pressedOriginalOpacity = el.style.opacity || '';\n pressedOriginalTransition = el.style.transition || '';\n // Apply pressed style with inline styles for maximum specificity\n el.style.transition = 'transform 80ms cubic-bezier(0.25, 0.1, 0.25, 1), opacity 80ms cubic-bezier(0.25, 0.1, 0.25, 1)';\n el.style.transform = 'scale(0.97)';\n el.style.opacity = '0.8';\n }\n\n function applyReleasedStyle(el) {\n if (!el || !el.style) return;\n // Apply spring-back animation\n el.style.transition = 'transform 280ms cubic-bezier(0.34, 1.56, 0.64, 1), opacity 280ms cubic-bezier(0.34, 1.56, 0.64, 1)';\n el.style.transform = pressedOriginalTransform || 'scale(1)';\n el.style.opacity = pressedOriginalOpacity || '1';\n }\n\n function resetStyle(el) {\n if (!el || !el.style) return;\n el.style.transform = pressedOriginalTransform;\n el.style.opacity = pressedOriginalOpacity;\n el.style.transition = pressedOriginalTransition;\n }\n\n function onTouchStart(e) {\n try {\n var target = findInteractive(e.target);\n if (!target) return;\n if (releaseTimer) { clearTimeout(releaseTimer); releaseTimer = null; }\n if (pressed && pressed !== target) { resetStyle(pressed); }\n applyPressedStyle(target);\n pressed = target;\n } catch(err) {}\n }\n \n function onTouchEnd(e) {\n try {\n if (!pressed) return;\n var t = pressed;\n applyReleasedStyle(t);\n releaseTimer = setTimeout(function() {\n resetStyle(t);\n releaseTimer = null;\n }, 300);\n pressed = null;\n } catch(err) {}\n }\n \n function onTouchCancel(e) {\n try {\n if (!pressed) return;\n resetStyle(pressed);\n pressed = null;\n if (releaseTimer) { clearTimeout(releaseTimer); releaseTimer = null; }\n } catch(err) {}\n }\n \n // Use capture phase for immediate response before any other handlers\n document.addEventListener('touchstart', onTouchStart, { passive: true, capture: true });\n document.addEventListener('touchend', onTouchEnd, { passive: true, capture: true });\n document.addEventListener('touchcancel', onTouchCancel, { passive: true, capture: true });\n // Mouse events for testing\n document.addEventListener('mousedown', onTouchStart, { passive: true, capture: true });\n document.addEventListener('mouseup', onTouchEnd, { passive: true, capture: true });\n \n } catch (err) {}\n true;\n})();\n";
|
|
7
7
|
export type ScreenPayload = {
|
|
8
8
|
id: string;
|
|
9
9
|
html: string;
|
package/build/RampkitOverlay.js
CHANGED
|
@@ -182,32 +182,6 @@ exports.injectedDynamicTapHandler = `
|
|
|
182
182
|
if (window.__rampkitClickInterceptorInstalled) return;
|
|
183
183
|
window.__rampkitClickInterceptorInstalled = true;
|
|
184
184
|
|
|
185
|
-
// ========== DEBUG: phone-21 (buggy screen) specific logging (REMOVE AFTER BUG FIX) ==========
|
|
186
|
-
var isBuggyScreen = function() {
|
|
187
|
-
var screenId = window.__rampkitScreenId || '';
|
|
188
|
-
var screenIndex = window.__rampkitScreenIndex;
|
|
189
|
-
return screenId === 'phone-21' || screenIndex === 18;
|
|
190
|
-
};
|
|
191
|
-
|
|
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) {}
|
|
207
|
-
}
|
|
208
|
-
};
|
|
209
|
-
// ========== END DEBUG ==========
|
|
210
|
-
|
|
211
185
|
// Decode HTML entities
|
|
212
186
|
function decodeHtml(str) {
|
|
213
187
|
if (!str) return str;
|
|
@@ -221,49 +195,21 @@ exports.injectedDynamicTapHandler = `
|
|
|
221
195
|
var current = el;
|
|
222
196
|
var depth = 0;
|
|
223
197
|
var attrNames = ['data-tap-dynamic', 'data-tapdynamic', 'tapDynamic', 'data-dynamic-tap'];
|
|
224
|
-
var searchTrail = []; // DEBUG: Track search path
|
|
225
|
-
|
|
226
198
|
while (current && current !== document.body && current !== document.documentElement && depth < 20) {
|
|
227
|
-
// DEBUG: Build search trail for Screen 19
|
|
228
|
-
var trailInfo = {
|
|
229
|
-
depth: depth,
|
|
230
|
-
tag: current.tagName,
|
|
231
|
-
id: current.id || '(none)',
|
|
232
|
-
class: (current.className && typeof current.className === 'string') ? current.className.substring(0,50) : '(none)'
|
|
233
|
-
};
|
|
234
|
-
searchTrail.push(trailInfo);
|
|
235
|
-
|
|
236
199
|
if (current.getAttribute) {
|
|
237
200
|
for (var i = 0; i < attrNames.length; i++) {
|
|
238
201
|
var attr = current.getAttribute(attrNames[i]);
|
|
239
202
|
if (attr && attr.length > 2) {
|
|
240
|
-
var rect = current.getBoundingClientRect ? current.getBoundingClientRect() : {};
|
|
241
|
-
debugBuggyScreen('DynamicTap', 'FOUND data-tap-dynamic', {
|
|
242
|
-
attrName: attrNames[i],
|
|
243
|
-
depth: depth,
|
|
244
|
-
element: trailInfo,
|
|
245
|
-
size: rect.width + 'x' + rect.height,
|
|
246
|
-
configPreview: attr.substring(0, 100) + '...',
|
|
247
|
-
trail: searchTrail
|
|
248
|
-
});
|
|
249
203
|
return { element: current, config: attr };
|
|
250
204
|
}
|
|
251
205
|
}
|
|
252
206
|
if (current.dataset && current.dataset.tapDynamic) {
|
|
253
|
-
var rect2 = current.getBoundingClientRect ? current.getBoundingClientRect() : {};
|
|
254
|
-
debugBuggyScreen('DynamicTap', 'FOUND dataset.tapDynamic', {
|
|
255
|
-
depth: depth,
|
|
256
|
-
element: trailInfo,
|
|
257
|
-
size: rect2.width + 'x' + rect2.height,
|
|
258
|
-
trail: searchTrail
|
|
259
|
-
});
|
|
260
207
|
return { element: current, config: current.dataset.tapDynamic };
|
|
261
208
|
}
|
|
262
209
|
}
|
|
263
210
|
current = current.parentElement;
|
|
264
211
|
depth++;
|
|
265
212
|
}
|
|
266
|
-
debugBuggyScreen('DynamicTap', 'NO data-tap-dynamic found', { trail: searchTrail });
|
|
267
213
|
return null;
|
|
268
214
|
}
|
|
269
215
|
|
|
@@ -403,75 +349,20 @@ exports.injectedDynamicTapHandler = `
|
|
|
403
349
|
|
|
404
350
|
// Click interceptor - capture phase, runs BEFORE onclick handlers
|
|
405
351
|
function interceptClick(event) {
|
|
406
|
-
// ========== DEBUG: phone-21 click logging ==========
|
|
407
|
-
if (isBuggyScreen()) {
|
|
408
|
-
var clickX = event.clientX;
|
|
409
|
-
var clickY = event.clientY;
|
|
410
|
-
var originalTarget = event.target;
|
|
411
|
-
var originalRect = originalTarget.getBoundingClientRect ? originalTarget.getBoundingClientRect() : {};
|
|
412
|
-
debugBuggyScreen('Click', 'Click at (' + clickX + ',' + clickY + ')', {
|
|
413
|
-
originalTarget: {
|
|
414
|
-
tag: originalTarget.tagName,
|
|
415
|
-
id: originalTarget.id || '(none)',
|
|
416
|
-
class: (originalTarget.className && typeof originalTarget.className === 'string') ? originalTarget.className.substring(0,100) : '(none)',
|
|
417
|
-
size: originalRect.width + 'x' + originalRect.height
|
|
418
|
-
}
|
|
419
|
-
});
|
|
420
|
-
}
|
|
421
|
-
// ========== END DEBUG ==========
|
|
422
|
-
|
|
423
352
|
var result = findDynamicTap(event.target);
|
|
424
353
|
if (!result) return;
|
|
425
354
|
|
|
426
|
-
// ========== DEBUG: phone-21 - log when dynamic tap is found ==========
|
|
427
|
-
if (isBuggyScreen()) {
|
|
428
|
-
var rect = result.element.getBoundingClientRect ? result.element.getBoundingClientRect() : {};
|
|
429
|
-
var screenWidth = window.innerWidth;
|
|
430
|
-
var screenHeight = window.innerHeight;
|
|
431
|
-
var isFullScreen = (rect.width >= screenWidth * 0.9 && rect.height >= screenHeight * 0.9);
|
|
432
|
-
debugBuggyScreen('Click', 'DYNAMIC TAP WILL BE HANDLED', {
|
|
433
|
-
element: {
|
|
434
|
-
tag: result.element.tagName,
|
|
435
|
-
id: result.element.id || '(none)',
|
|
436
|
-
class: (result.element.className && typeof result.element.className === 'string') ? result.element.className.substring(0,100) : '(none)',
|
|
437
|
-
size: rect.width + 'x' + rect.height
|
|
438
|
-
},
|
|
439
|
-
isFullScreen: isFullScreen,
|
|
440
|
-
WARNING: isFullScreen ? 'FULL SCREEN ELEMENT WITH DYNAMIC TAP - THIS IS THE BUG!' : 'normal element'
|
|
441
|
-
});
|
|
442
|
-
}
|
|
443
|
-
// ========== END DEBUG ==========
|
|
444
|
-
|
|
445
355
|
try {
|
|
446
356
|
var configStr = decodeHtml(result.config);
|
|
447
357
|
var config = JSON.parse(configStr);
|
|
448
|
-
|
|
449
|
-
// ========== DEBUG: phone-21 - log parsed config ==========
|
|
450
|
-
if (isBuggyScreen()) {
|
|
451
|
-
debugBuggyScreen('Click', 'Parsed config', {
|
|
452
|
-
hasValues: !!(config && config.values),
|
|
453
|
-
valuesCount: config && config.values ? config.values.length : 0,
|
|
454
|
-
firstCondition: config && config.values && config.values[0] ? {
|
|
455
|
-
conditionType: config.values[0].conditionType,
|
|
456
|
-
rulesCount: config.values[0].rules ? config.values[0].rules.length : 0,
|
|
457
|
-
actionsCount: config.values[0].actions ? config.values[0].actions.length : 0
|
|
458
|
-
} : null
|
|
459
|
-
});
|
|
460
|
-
}
|
|
461
|
-
// ========== END DEBUG ==========
|
|
462
|
-
|
|
463
358
|
var handled = evalDynamicTap(config);
|
|
464
359
|
if (handled) {
|
|
465
|
-
debugBuggyScreen('Click', 'HANDLED by dynamic tap - event stopped', { handled: true });
|
|
466
360
|
event.stopImmediatePropagation();
|
|
467
361
|
event.preventDefault();
|
|
468
362
|
return false;
|
|
469
363
|
}
|
|
470
364
|
} catch (e) {
|
|
471
365
|
console.log('[RampKit] Dynamic tap error:', e);
|
|
472
|
-
if (isBuggyScreen()) {
|
|
473
|
-
debugBuggyScreen('Click', 'Dynamic tap parse error', { error: e.message });
|
|
474
|
-
}
|
|
475
366
|
}
|
|
476
367
|
}
|
|
477
368
|
|
|
@@ -494,36 +385,9 @@ exports.injectedButtonAnimations = `
|
|
|
494
385
|
var pressedOriginalTransition = '';
|
|
495
386
|
var releaseTimer = null;
|
|
496
387
|
|
|
497
|
-
//
|
|
498
|
-
var isBuggyScreenAnim = function() {
|
|
499
|
-
var screenId = window.__rampkitScreenId || '';
|
|
500
|
-
var screenIndex = window.__rampkitScreenIndex;
|
|
501
|
-
return screenId === 'phone-21' || screenIndex === 18;
|
|
502
|
-
};
|
|
503
|
-
|
|
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) {}
|
|
518
|
-
}
|
|
519
|
-
};
|
|
520
|
-
// ========== END DEBUG ==========
|
|
521
|
-
|
|
522
|
-
// Find interactive element - very permissive, looks for any clickable-looking element
|
|
388
|
+
// Find interactive element - looks for clickable-looking elements
|
|
523
389
|
function findInteractive(el) {
|
|
524
390
|
var current = el;
|
|
525
|
-
var debugTrail = []; // DEBUG: Track search path for Screen 19
|
|
526
|
-
|
|
527
391
|
for (var i = 0; i < 20 && current && current !== document.body && current !== document.documentElement; i++) {
|
|
528
392
|
if (!current || !current.tagName) { current = current.parentElement; continue; }
|
|
529
393
|
var tag = current.tagName.toLowerCase();
|
|
@@ -532,54 +396,40 @@ exports.injectedButtonAnimations = `
|
|
|
532
396
|
var rect = current.getBoundingClientRect();
|
|
533
397
|
if (rect.width < 20 || rect.height < 20) { current = current.parentElement; continue; }
|
|
534
398
|
|
|
535
|
-
// DEBUG: Build trail for Screen 19
|
|
536
|
-
var debugInfo = {
|
|
537
|
-
depth: i,
|
|
538
|
-
tag: tag,
|
|
539
|
-
id: current.id || '(none)',
|
|
540
|
-
class: (current.className && typeof current.className === 'string') ? current.className.substring(0, 100) : '(none)',
|
|
541
|
-
size: rect.width + 'x' + rect.height
|
|
542
|
-
};
|
|
543
|
-
debugTrail.push(debugInfo);
|
|
544
|
-
|
|
545
399
|
// Match standard interactive elements
|
|
546
|
-
if (tag === 'button' || tag === 'a' || tag === 'input' || tag === 'select')
|
|
547
|
-
debugBuggyScreenAnim('ButtonAnim', 'MATCHED: standard tag', { reason: 'tag=' + tag, element: debugInfo, trail: debugTrail });
|
|
548
|
-
return current;
|
|
549
|
-
}
|
|
400
|
+
if (tag === 'button' || tag === 'a' || tag === 'input' || tag === 'select') return current;
|
|
550
401
|
|
|
551
|
-
// Match elements with
|
|
402
|
+
// Match elements with tap/click-related data attributes
|
|
403
|
+
// Exclude lifecycle attributes like data-on-open-actions, data-on-close-actions
|
|
552
404
|
var attrs = current.attributes;
|
|
553
405
|
if (attrs) {
|
|
554
406
|
for (var j = 0; j < attrs.length; j++) {
|
|
555
407
|
var attrName = attrs[j].name.toLowerCase();
|
|
408
|
+
// Skip lifecycle attributes (on-open, on-close, on-load, on-appear, etc.)
|
|
409
|
+
if (attrName.indexOf('on-open') !== -1 || attrName.indexOf('on-close') !== -1 ||
|
|
410
|
+
attrName.indexOf('on-load') !== -1 || attrName.indexOf('on-appear') !== -1 ||
|
|
411
|
+
attrName.indexOf('onopen') !== -1 || attrName.indexOf('onclose') !== -1 ||
|
|
412
|
+
attrName.indexOf('onload') !== -1 || attrName.indexOf('onappear') !== -1) {
|
|
413
|
+
continue;
|
|
414
|
+
}
|
|
415
|
+
// Match tap/click interaction attributes
|
|
556
416
|
if (attrName.indexOf('click') !== -1 || attrName.indexOf('tap') !== -1 ||
|
|
557
417
|
attrName.indexOf('action') !== -1 || attrName.indexOf('navigate') !== -1 ||
|
|
558
418
|
attrName.indexOf('press') !== -1) {
|
|
559
|
-
debugBuggyScreenAnim('ButtonAnim', 'MATCHED: data-attr', { reason: 'attr=' + attrName, value: attrs[j].value.substring(0,50), element: debugInfo, trail: debugTrail });
|
|
560
419
|
return current;
|
|
561
420
|
}
|
|
562
421
|
}
|
|
563
422
|
}
|
|
564
423
|
|
|
565
424
|
// Match elements with onclick
|
|
566
|
-
if (current.onclick || current.hasAttribute('onclick'))
|
|
567
|
-
debugBuggyScreenAnim('ButtonAnim', 'MATCHED: onclick', { element: debugInfo, trail: debugTrail });
|
|
568
|
-
return current;
|
|
569
|
-
}
|
|
425
|
+
if (current.onclick || current.hasAttribute('onclick')) return current;
|
|
570
426
|
|
|
571
|
-
// Match elements with role="button"
|
|
572
|
-
if (current.getAttribute('role') === 'button')
|
|
573
|
-
debugBuggyScreenAnim('ButtonAnim', 'MATCHED: role=button', { element: debugInfo, trail: debugTrail });
|
|
574
|
-
return current;
|
|
575
|
-
}
|
|
427
|
+
// Match elements with role="button"
|
|
428
|
+
if (current.getAttribute('role') === 'button') return current;
|
|
576
429
|
|
|
577
430
|
// Match any element with an ID containing button/btn/cta
|
|
578
431
|
var id = current.id || '';
|
|
579
|
-
if (id && (id.toLowerCase().indexOf('button') !== -1 || id.toLowerCase().indexOf('btn') !== -1 || id.toLowerCase().indexOf('cta') !== -1))
|
|
580
|
-
debugBuggyScreenAnim('ButtonAnim', 'MATCHED: button-like ID', { reason: 'id=' + id, element: debugInfo, trail: debugTrail });
|
|
581
|
-
return current;
|
|
582
|
-
}
|
|
432
|
+
if (id && (id.toLowerCase().indexOf('button') !== -1 || id.toLowerCase().indexOf('btn') !== -1 || id.toLowerCase().indexOf('cta') !== -1)) return current;
|
|
583
433
|
|
|
584
434
|
// Match elements with button-like classes
|
|
585
435
|
var className = current.className;
|
|
@@ -587,7 +437,6 @@ exports.injectedButtonAnimations = `
|
|
|
587
437
|
var cls = className.toLowerCase();
|
|
588
438
|
if (cls.indexOf('btn') !== -1 || cls.indexOf('button') !== -1 || cls.indexOf('cta') !== -1 ||
|
|
589
439
|
cls.indexOf('clickable') !== -1 || cls.indexOf('tappable') !== -1 || cls.indexOf('pressable') !== -1) {
|
|
590
|
-
debugBuggyScreenAnim('ButtonAnim', 'MATCHED: button-like class', { reason: 'class=' + className, element: debugInfo, trail: debugTrail });
|
|
591
440
|
return current;
|
|
592
441
|
}
|
|
593
442
|
}
|
|
@@ -595,18 +444,14 @@ exports.injectedButtonAnimations = `
|
|
|
595
444
|
// Match elements with cursor pointer
|
|
596
445
|
try {
|
|
597
446
|
var computed = window.getComputedStyle(current);
|
|
598
|
-
if (computed && computed.cursor === 'pointer')
|
|
599
|
-
debugBuggyScreenAnim('ButtonAnim', 'MATCHED: cursor:pointer', { element: debugInfo, trail: debugTrail });
|
|
600
|
-
return current;
|
|
601
|
-
}
|
|
447
|
+
if (computed && computed.cursor === 'pointer') return current;
|
|
602
448
|
} catch(e) {}
|
|
603
449
|
|
|
604
450
|
current = current.parentElement;
|
|
605
451
|
}
|
|
606
|
-
debugBuggyScreenAnim('ButtonAnim', 'NO MATCH found', { originalTag: el.tagName, trail: debugTrail });
|
|
607
452
|
return null;
|
|
608
453
|
}
|
|
609
|
-
|
|
454
|
+
|
|
610
455
|
function applyPressedStyle(el) {
|
|
611
456
|
if (!el || !el.style) return;
|
|
612
457
|
// Save original styles
|
|
@@ -618,7 +463,7 @@ exports.injectedButtonAnimations = `
|
|
|
618
463
|
el.style.transform = 'scale(0.97)';
|
|
619
464
|
el.style.opacity = '0.8';
|
|
620
465
|
}
|
|
621
|
-
|
|
466
|
+
|
|
622
467
|
function applyReleasedStyle(el) {
|
|
623
468
|
if (!el || !el.style) return;
|
|
624
469
|
// Apply spring-back animation
|
|
@@ -626,53 +471,18 @@ exports.injectedButtonAnimations = `
|
|
|
626
471
|
el.style.transform = pressedOriginalTransform || 'scale(1)';
|
|
627
472
|
el.style.opacity = pressedOriginalOpacity || '1';
|
|
628
473
|
}
|
|
629
|
-
|
|
474
|
+
|
|
630
475
|
function resetStyle(el) {
|
|
631
476
|
if (!el || !el.style) return;
|
|
632
477
|
el.style.transform = pressedOriginalTransform;
|
|
633
478
|
el.style.opacity = pressedOriginalOpacity;
|
|
634
479
|
el.style.transition = pressedOriginalTransition;
|
|
635
480
|
}
|
|
636
|
-
|
|
481
|
+
|
|
637
482
|
function onTouchStart(e) {
|
|
638
483
|
try {
|
|
639
|
-
// ========== DEBUG: phone-21 touch logging ==========
|
|
640
|
-
if (isBuggyScreenAnim()) {
|
|
641
|
-
var touchX = e.touches ? e.touches[0].clientX : e.clientX;
|
|
642
|
-
var touchY = e.touches ? e.touches[0].clientY : e.clientY;
|
|
643
|
-
var originalTarget = e.target;
|
|
644
|
-
var originalRect = originalTarget.getBoundingClientRect ? originalTarget.getBoundingClientRect() : {};
|
|
645
|
-
debugBuggyScreenAnim('TouchStart', 'Touch at (' + touchX + ',' + touchY + ')', {
|
|
646
|
-
originalTarget: {
|
|
647
|
-
tag: originalTarget.tagName,
|
|
648
|
-
id: originalTarget.id || '(none)',
|
|
649
|
-
class: (originalTarget.className && typeof originalTarget.className === 'string') ? originalTarget.className.substring(0,100) : '(none)',
|
|
650
|
-
size: originalRect.width + 'x' + originalRect.height
|
|
651
|
-
}
|
|
652
|
-
});
|
|
653
|
-
}
|
|
654
|
-
// ========== END DEBUG ==========
|
|
655
|
-
|
|
656
484
|
var target = findInteractive(e.target);
|
|
657
485
|
if (!target) return;
|
|
658
|
-
|
|
659
|
-
// ========== DEBUG: phone-21 - log what element was found interactive ==========
|
|
660
|
-
if (isBuggyScreenAnim() && target) {
|
|
661
|
-
var targetRect = target.getBoundingClientRect();
|
|
662
|
-
var screenWidth = window.innerWidth;
|
|
663
|
-
var screenHeight = window.innerHeight;
|
|
664
|
-
var isFullScreen = (targetRect.width >= screenWidth * 0.9 && targetRect.height >= screenHeight * 0.9);
|
|
665
|
-
debugBuggyScreenAnim('TouchStart', 'INTERACTIVE ELEMENT FOUND', {
|
|
666
|
-
tag: target.tagName,
|
|
667
|
-
id: target.id || '(none)',
|
|
668
|
-
class: (target.className && typeof target.className === 'string') ? target.className.substring(0,100) : '(none)',
|
|
669
|
-
size: targetRect.width + 'x' + targetRect.height,
|
|
670
|
-
isFullScreen: isFullScreen,
|
|
671
|
-
WARNING: isFullScreen ? 'FULL SCREEN ELEMENT DETECTED - THIS IS THE BUG!' : 'normal element'
|
|
672
|
-
});
|
|
673
|
-
}
|
|
674
|
-
// ========== END DEBUG ==========
|
|
675
|
-
|
|
676
486
|
if (releaseTimer) { clearTimeout(releaseTimer); releaseTimer = null; }
|
|
677
487
|
if (pressed && pressed !== target) { resetStyle(pressed); }
|
|
678
488
|
applyPressedStyle(target);
|
|
@@ -2017,29 +1827,9 @@ function Overlay(props) {
|
|
|
2017
1827
|
}
|
|
2018
1828
|
}
|
|
2019
1829
|
}, onMessage: (ev) => {
|
|
2020
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k
|
|
1830
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
2021
1831
|
const raw = ev.nativeEvent.data;
|
|
2022
1832
|
console.log("raw", raw);
|
|
2023
|
-
// ========== DEBUG: phone-21 onMessage logging (REMOVE AFTER BUG FIX) ==========
|
|
2024
|
-
const screenId = ((_a = props.screens[i]) === null || _a === void 0 ? void 0 : _a.id) || "";
|
|
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({
|
|
2028
|
-
rawPreview: raw.substring(0, 200),
|
|
2029
|
-
isActiveScreen: i === activeScreenIndexRef.current,
|
|
2030
|
-
activeScreenIndex: activeScreenIndexRef.current
|
|
2031
|
-
}));
|
|
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 (_) { }
|
|
2042
|
-
// ========== END DEBUG ==========
|
|
2043
1833
|
// Accept either raw strings or JSON payloads from your editor
|
|
2044
1834
|
try {
|
|
2045
1835
|
// JSON path
|
|
@@ -2165,7 +1955,7 @@ function Overlay(props) {
|
|
|
2165
1955
|
if ((data === null || data === void 0 ? void 0 : data.type) === "rampkit:onboarding-finished") {
|
|
2166
1956
|
setOnboardingCompleted(true);
|
|
2167
1957
|
try {
|
|
2168
|
-
(
|
|
1958
|
+
(_a = props.onOnboardingFinished) === null || _a === void 0 ? void 0 : _a.call(props, data === null || data === void 0 ? void 0 : data.payload);
|
|
2169
1959
|
}
|
|
2170
1960
|
catch (_) { }
|
|
2171
1961
|
handleRequestClose({ completed: true });
|
|
@@ -2174,7 +1964,7 @@ function Overlay(props) {
|
|
|
2174
1964
|
// 6) Request to show paywall
|
|
2175
1965
|
if ((data === null || data === void 0 ? void 0 : data.type) === "rampkit:show-paywall") {
|
|
2176
1966
|
try {
|
|
2177
|
-
(
|
|
1967
|
+
(_b = props.onShowPaywall) === null || _b === void 0 ? void 0 : _b.call(props, data === null || data === void 0 ? void 0 : data.payload);
|
|
2178
1968
|
}
|
|
2179
1969
|
catch (_) { }
|
|
2180
1970
|
return;
|
|
@@ -2185,9 +1975,9 @@ function Overlay(props) {
|
|
|
2185
1975
|
if (questionId) {
|
|
2186
1976
|
const response = {
|
|
2187
1977
|
questionId,
|
|
2188
|
-
answer: (
|
|
1978
|
+
answer: (_c = data === null || data === void 0 ? void 0 : data.answer) !== null && _c !== void 0 ? _c : "",
|
|
2189
1979
|
questionText: data === null || data === void 0 ? void 0 : data.questionText,
|
|
2190
|
-
screenName: (
|
|
1980
|
+
screenName: (_d = props.screens[i]) === null || _d === void 0 ? void 0 : _d.id,
|
|
2191
1981
|
answeredAt: new Date().toISOString(),
|
|
2192
1982
|
};
|
|
2193
1983
|
OnboardingResponseStorage_1.OnboardingResponseStorage.saveResponse(response);
|
|
@@ -2202,14 +1992,6 @@ function Overlay(props) {
|
|
|
2202
1992
|
console.log(`[RampKit] Ignoring continue from inactive screen ${i}`);
|
|
2203
1993
|
return;
|
|
2204
1994
|
}
|
|
2205
|
-
// ========== DEBUG: phone-21 continue logging ==========
|
|
2206
|
-
if (isBuggyScreenOnMsg) {
|
|
2207
|
-
console.log(`[BUGGY-SCREEN][onMessage] CONTINUE action triggered from screen ${i}`, JSON.stringify({
|
|
2208
|
-
animation: (data === null || data === void 0 ? void 0 : data.animation) || "fade",
|
|
2209
|
-
screenId: screenId
|
|
2210
|
-
}));
|
|
2211
|
-
}
|
|
2212
|
-
// ========== END DEBUG ==========
|
|
2213
1995
|
handleAdvance(i, (data === null || data === void 0 ? void 0 : data.animation) || "fade");
|
|
2214
1996
|
return;
|
|
2215
1997
|
}
|
|
@@ -2221,15 +2003,6 @@ function Overlay(props) {
|
|
|
2221
2003
|
return;
|
|
2222
2004
|
}
|
|
2223
2005
|
const target = data === null || data === void 0 ? void 0 : data.targetScreenId;
|
|
2224
|
-
// ========== DEBUG: phone-21 navigate logging ==========
|
|
2225
|
-
if (isBuggyScreenOnMsg) {
|
|
2226
|
-
console.log(`[BUGGY-SCREEN][onMessage] NAVIGATE action triggered from screen ${i}`, JSON.stringify({
|
|
2227
|
-
target: target,
|
|
2228
|
-
animation: (data === null || data === void 0 ? void 0 : data.animation) || "fade",
|
|
2229
|
-
screenId: screenId
|
|
2230
|
-
}));
|
|
2231
|
-
}
|
|
2232
|
-
// ========== END DEBUG ==========
|
|
2233
2006
|
if (target === "__goBack__") {
|
|
2234
2007
|
handleGoBack(i, (data === null || data === void 0 ? void 0 : data.animation) || "fade");
|
|
2235
2008
|
return;
|
|
@@ -2260,7 +2033,7 @@ function Overlay(props) {
|
|
|
2260
2033
|
if ((data === null || data === void 0 ? void 0 : data.type) === "rampkit:close") {
|
|
2261
2034
|
// Track close action for onboarding completion
|
|
2262
2035
|
try {
|
|
2263
|
-
(
|
|
2036
|
+
(_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) || "");
|
|
2264
2037
|
}
|
|
2265
2038
|
catch (_) { }
|
|
2266
2039
|
handleRequestClose({ completed: true }); // Mark as completed so abandonment isn't tracked
|
|
@@ -2271,7 +2044,7 @@ function Overlay(props) {
|
|
|
2271
2044
|
return;
|
|
2272
2045
|
}
|
|
2273
2046
|
}
|
|
2274
|
-
catch (
|
|
2047
|
+
catch (_l) {
|
|
2275
2048
|
// String path
|
|
2276
2049
|
if (raw === "rampkit:tap" ||
|
|
2277
2050
|
raw === "next" ||
|
|
@@ -2322,7 +2095,7 @@ function Overlay(props) {
|
|
|
2322
2095
|
if (raw === "rampkit:onboarding-finished") {
|
|
2323
2096
|
setOnboardingCompleted(true);
|
|
2324
2097
|
try {
|
|
2325
|
-
(
|
|
2098
|
+
(_g = props.onOnboardingFinished) === null || _g === void 0 ? void 0 : _g.call(props, undefined);
|
|
2326
2099
|
}
|
|
2327
2100
|
catch (_) { }
|
|
2328
2101
|
handleRequestClose({ completed: true });
|
|
@@ -2330,7 +2103,7 @@ function Overlay(props) {
|
|
|
2330
2103
|
}
|
|
2331
2104
|
if (raw === "rampkit:show-paywall") {
|
|
2332
2105
|
try {
|
|
2333
|
-
(
|
|
2106
|
+
(_h = props.onShowPaywall) === null || _h === void 0 ? void 0 : _h.call(props);
|
|
2334
2107
|
}
|
|
2335
2108
|
catch (_) { }
|
|
2336
2109
|
return;
|
|
@@ -2373,7 +2146,7 @@ function Overlay(props) {
|
|
|
2373
2146
|
if (raw === "rampkit:close") {
|
|
2374
2147
|
// Track close action for onboarding completion
|
|
2375
2148
|
try {
|
|
2376
|
-
(
|
|
2149
|
+
(_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) || "");
|
|
2377
2150
|
}
|
|
2378
2151
|
catch (_) { }
|
|
2379
2152
|
handleRequestClose({ completed: true }); // Mark as completed so abandonment isn't tracked
|
package/package.json
CHANGED