rampkit-expo-dev 0.0.41 → 0.0.43

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,7 +2,7 @@ import { RampKitContext } 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 injectedButtonAnimations = "\n(function(){\n try {\n if (window.__rkButtonAnimApplied) return true;\n window.__rkButtonAnimApplied = true;\n \n // Add styles for button animations\n var style = document.createElement('style');\n style.id = 'rk-button-anim-style';\n style.innerHTML = `\n /* Base transition for all interactive elements */\n [data-rampkit-action],\n [data-rampkit-navigate],\n [data-rampkit-tap],\n [onclick],\n button,\n a[href],\n .rk-interactive,\n .rk-button {\n transform: scale(1);\n opacity: 1;\n will-change: transform, opacity;\n }\n \n /* Pressed state - applied via JS */\n .rk-pressed {\n transform: scale(0.97) !important;\n opacity: 0.8 !important;\n transition: transform 80ms cubic-bezier(0.25, 0.1, 0.25, 1), \n opacity 80ms cubic-bezier(0.25, 0.1, 0.25, 1) !important;\n }\n \n /* Released state - spring-like bounce back */\n .rk-released {\n transform: scale(1) !important;\n opacity: 1 !important;\n transition: transform 280ms cubic-bezier(0.34, 1.56, 0.64, 1), \n opacity 280ms cubic-bezier(0.34, 1.56, 0.64, 1) !important;\n }\n `;\n document.head.appendChild(style);\n \n // Check if element is interactive\n function isInteractive(el) {\n if (!el || !el.tagName) return false;\n var tag = el.tagName.toLowerCase();\n if (tag === 'button' || tag === 'a') return true;\n if (el.hasAttribute('data-rampkit-action')) return true;\n if (el.hasAttribute('data-rampkit-navigate')) return true;\n if (el.hasAttribute('data-rampkit-tap')) return true;\n if (el.hasAttribute('onclick')) return true;\n if (el.classList.contains('rk-interactive')) return true;\n if (el.classList.contains('rk-button')) return true;\n return false;\n }\n \n // Find the interactive parent element\n function findInteractiveElement(el) {\n var current = el;\n var maxDepth = 10; // Prevent infinite loops\n while (current && maxDepth > 0) {\n if (isInteractive(current)) return current;\n current = current.parentElement;\n maxDepth--;\n }\n return null;\n }\n \n // Track currently pressed element\n var pressedElement = null;\n var pressTimeout = null;\n \n // Handle touch start - immediate press animation\n function handleTouchStart(e) {\n try {\n var target = findInteractiveElement(e.target);\n if (!target) return;\n \n // Clear any pending release animation\n if (pressTimeout) {\n clearTimeout(pressTimeout);\n pressTimeout = null;\n }\n \n // Remove released class and add pressed class\n target.classList.remove('rk-released');\n target.classList.add('rk-pressed');\n pressedElement = target;\n } catch(_) {}\n }\n \n // Handle touch end - spring release animation\n function handleTouchEnd(e) {\n try {\n if (!pressedElement) return;\n var target = pressedElement;\n \n // Switch from pressed to released for spring animation\n target.classList.remove('rk-pressed');\n target.classList.add('rk-released');\n \n // Clean up after animation completes\n pressTimeout = setTimeout(function() {\n target.classList.remove('rk-released');\n pressTimeout = null;\n }, 300);\n \n pressedElement = null;\n } catch(_) {}\n }\n \n // Handle touch cancel - reset without animation\n function handleTouchCancel(e) {\n try {\n if (!pressedElement) return;\n pressedElement.classList.remove('rk-pressed');\n pressedElement.classList.remove('rk-released');\n pressedElement = null;\n if (pressTimeout) {\n clearTimeout(pressTimeout);\n pressTimeout = null;\n }\n } catch(_) {}\n }\n \n // Use capture phase to get events before they're handled\n document.addEventListener('touchstart', handleTouchStart, { passive: true, capture: true });\n document.addEventListener('touchend', handleTouchEnd, { passive: true, capture: true });\n document.addEventListener('touchcancel', handleTouchCancel, { passive: true, capture: true });\n \n // Also handle mouse events for web testing\n document.addEventListener('mousedown', handleTouchStart, { passive: true, capture: true });\n document.addEventListener('mouseup', handleTouchEnd, { passive: true, capture: true });\n document.addEventListener('mouseleave', handleTouchCancel, { passive: true, capture: true });\n \n } catch (_) {}\n true;\n})();\n";
5
+ export declare const injectedButtonAnimations = "\n(function(){\n try {\n if (window.__rkButtonAnimApplied) return true;\n window.__rkButtonAnimApplied = true;\n \n var pressed = null;\n var pressedOriginalTransform = '';\n var pressedOriginalOpacity = '';\n var pressedOriginalTransition = '';\n var releaseTimer = null;\n \n // Find interactive element - very permissive, looks for any clickable-looking element\n function findInteractive(el) {\n var current = el;\n for (var i = 0; i < 20 && current && current !== document.body && current !== document.documentElement; i++) {\n if (!current || !current.tagName) { current = current.parentElement; continue; }\n var tag = current.tagName.toLowerCase();\n \n // Skip tiny elements (likely icons inside buttons)\n var rect = current.getBoundingClientRect();\n if (rect.width < 20 || rect.height < 20) { current = current.parentElement; continue; }\n \n // Match standard interactive elements\n if (tag === 'button' || tag === 'a' || tag === 'input' || tag === 'select') return current;\n \n // Match elements with any data attribute containing action/navigate/tap/click\n var attrs = current.attributes;\n if (attrs) {\n for (var j = 0; j < attrs.length; j++) {\n var attrName = attrs[j].name.toLowerCase();\n if (attrName.indexOf('click') !== -1 || attrName.indexOf('tap') !== -1 || \n attrName.indexOf('action') !== -1 || attrName.indexOf('navigate') !== -1 ||\n attrName.indexOf('press') !== -1) {\n return current;\n }\n }\n }\n \n // Match elements with onclick\n if (current.onclick || current.hasAttribute('onclick')) return current;\n \n // Match elements with role=\"button\" or tabindex\n if (current.getAttribute('role') === 'button') return current;\n \n // Match any element with an ID containing button/btn/cta\n var id = current.id || '';\n if (id && (id.toLowerCase().indexOf('button') !== -1 || id.toLowerCase().indexOf('btn') !== -1 || id.toLowerCase().indexOf('cta') !== -1)) return current;\n \n // Match elements with button-like classes\n var className = current.className;\n if (className && typeof className === 'string') {\n var cls = className.toLowerCase();\n if (cls.indexOf('btn') !== -1 || cls.indexOf('button') !== -1 || cls.indexOf('cta') !== -1 || \n cls.indexOf('clickable') !== -1 || cls.indexOf('tappable') !== -1 || cls.indexOf('pressable') !== -1) {\n return current;\n }\n }\n \n // Match elements with cursor pointer\n try {\n var computed = window.getComputedStyle(current);\n if (computed && computed.cursor === 'pointer') return current;\n } catch(e) {}\n \n current = current.parentElement;\n }\n return null;\n }\n \n function applyPressedStyle(el) {\n if (!el || !el.style) return;\n // Save original styles\n pressedOriginalTransform = el.style.transform || '';\n pressedOriginalOpacity = el.style.opacity || '';\n pressedOriginalTransition = el.style.transition || '';\n // Apply pressed style with inline styles for maximum specificity\n el.style.transition = 'transform 80ms cubic-bezier(0.25, 0.1, 0.25, 1), opacity 80ms cubic-bezier(0.25, 0.1, 0.25, 1)';\n el.style.transform = 'scale(0.97)';\n el.style.opacity = '0.8';\n }\n \n function applyReleasedStyle(el) {\n if (!el || !el.style) return;\n // Apply spring-back animation\n el.style.transition = 'transform 280ms cubic-bezier(0.34, 1.56, 0.64, 1), opacity 280ms cubic-bezier(0.34, 1.56, 0.64, 1)';\n el.style.transform = pressedOriginalTransform || 'scale(1)';\n el.style.opacity = pressedOriginalOpacity || '1';\n }\n \n function resetStyle(el) {\n if (!el || !el.style) return;\n el.style.transform = pressedOriginalTransform;\n el.style.opacity = pressedOriginalOpacity;\n el.style.transition = pressedOriginalTransition;\n }\n \n function onTouchStart(e) {\n try {\n var target = findInteractive(e.target);\n if (!target) return;\n if (releaseTimer) { clearTimeout(releaseTimer); releaseTimer = null; }\n if (pressed && pressed !== target) { resetStyle(pressed); }\n applyPressedStyle(target);\n pressed = target;\n } catch(err) {}\n }\n \n function onTouchEnd(e) {\n try {\n if (!pressed) return;\n var t = pressed;\n applyReleasedStyle(t);\n releaseTimer = setTimeout(function() {\n resetStyle(t);\n releaseTimer = null;\n }, 300);\n pressed = null;\n } catch(err) {}\n }\n \n function onTouchCancel(e) {\n try {\n if (!pressed) return;\n resetStyle(pressed);\n pressed = null;\n if (releaseTimer) { clearTimeout(releaseTimer); releaseTimer = null; }\n } catch(err) {}\n }\n \n // Use capture phase for immediate response before any other handlers\n document.addEventListener('touchstart', onTouchStart, { passive: true, capture: true });\n document.addEventListener('touchend', onTouchEnd, { passive: true, capture: true });\n document.addEventListener('touchcancel', onTouchCancel, { passive: true, capture: true });\n // Mouse events for testing\n document.addEventListener('mousedown', onTouchStart, { passive: true, capture: true });\n document.addEventListener('mouseup', onTouchEnd, { passive: true, capture: true });\n \n } catch (err) {}\n true;\n})();\n";
6
6
  export type ScreenPayload = {
7
7
  id: string;
8
8
  html: string;
@@ -175,142 +175,146 @@ exports.injectedVarsHandler = `
175
175
  `;
176
176
  // Button tap animation script - handles spring animations for interactive elements
177
177
  // Triggers on touchstart (not click) for immediate feedback
178
+ // Uses inline styles for maximum compatibility
178
179
  exports.injectedButtonAnimations = `
179
180
  (function(){
180
181
  try {
181
182
  if (window.__rkButtonAnimApplied) return true;
182
183
  window.__rkButtonAnimApplied = true;
183
184
 
184
- // Add styles for button animations
185
- var style = document.createElement('style');
186
- style.id = 'rk-button-anim-style';
187
- style.innerHTML = \`
188
- /* Base transition for all interactive elements */
189
- [data-rampkit-action],
190
- [data-rampkit-navigate],
191
- [data-rampkit-tap],
192
- [onclick],
193
- button,
194
- a[href],
195
- .rk-interactive,
196
- .rk-button {
197
- transform: scale(1);
198
- opacity: 1;
199
- will-change: transform, opacity;
200
- }
201
-
202
- /* Pressed state - applied via JS */
203
- .rk-pressed {
204
- transform: scale(0.97) !important;
205
- opacity: 0.8 !important;
206
- transition: transform 80ms cubic-bezier(0.25, 0.1, 0.25, 1),
207
- opacity 80ms cubic-bezier(0.25, 0.1, 0.25, 1) !important;
208
- }
209
-
210
- /* Released state - spring-like bounce back */
211
- .rk-released {
212
- transform: scale(1) !important;
213
- opacity: 1 !important;
214
- transition: transform 280ms cubic-bezier(0.34, 1.56, 0.64, 1),
215
- opacity 280ms cubic-bezier(0.34, 1.56, 0.64, 1) !important;
216
- }
217
- \`;
218
- document.head.appendChild(style);
185
+ var pressed = null;
186
+ var pressedOriginalTransform = '';
187
+ var pressedOriginalOpacity = '';
188
+ var pressedOriginalTransition = '';
189
+ var releaseTimer = null;
219
190
 
220
- // Check if element is interactive
221
- function isInteractive(el) {
222
- if (!el || !el.tagName) return false;
223
- var tag = el.tagName.toLowerCase();
224
- if (tag === 'button' || tag === 'a') return true;
225
- if (el.hasAttribute('data-rampkit-action')) return true;
226
- if (el.hasAttribute('data-rampkit-navigate')) return true;
227
- if (el.hasAttribute('data-rampkit-tap')) return true;
228
- if (el.hasAttribute('onclick')) return true;
229
- if (el.classList.contains('rk-interactive')) return true;
230
- if (el.classList.contains('rk-button')) return true;
231
- return false;
232
- }
233
-
234
- // Find the interactive parent element
235
- function findInteractiveElement(el) {
191
+ // Find interactive element - very permissive, looks for any clickable-looking element
192
+ function findInteractive(el) {
236
193
  var current = el;
237
- var maxDepth = 10; // Prevent infinite loops
238
- while (current && maxDepth > 0) {
239
- if (isInteractive(current)) return current;
194
+ for (var i = 0; i < 20 && current && current !== document.body && current !== document.documentElement; i++) {
195
+ if (!current || !current.tagName) { current = current.parentElement; continue; }
196
+ var tag = current.tagName.toLowerCase();
197
+
198
+ // Skip tiny elements (likely icons inside buttons)
199
+ var rect = current.getBoundingClientRect();
200
+ if (rect.width < 20 || rect.height < 20) { current = current.parentElement; continue; }
201
+
202
+ // Match standard interactive elements
203
+ if (tag === 'button' || tag === 'a' || tag === 'input' || tag === 'select') return current;
204
+
205
+ // Match elements with any data attribute containing action/navigate/tap/click
206
+ var attrs = current.attributes;
207
+ if (attrs) {
208
+ for (var j = 0; j < attrs.length; j++) {
209
+ var attrName = attrs[j].name.toLowerCase();
210
+ if (attrName.indexOf('click') !== -1 || attrName.indexOf('tap') !== -1 ||
211
+ attrName.indexOf('action') !== -1 || attrName.indexOf('navigate') !== -1 ||
212
+ attrName.indexOf('press') !== -1) {
213
+ return current;
214
+ }
215
+ }
216
+ }
217
+
218
+ // Match elements with onclick
219
+ if (current.onclick || current.hasAttribute('onclick')) return current;
220
+
221
+ // Match elements with role="button" or tabindex
222
+ if (current.getAttribute('role') === 'button') return current;
223
+
224
+ // Match any element with an ID containing button/btn/cta
225
+ var id = current.id || '';
226
+ if (id && (id.toLowerCase().indexOf('button') !== -1 || id.toLowerCase().indexOf('btn') !== -1 || id.toLowerCase().indexOf('cta') !== -1)) return current;
227
+
228
+ // Match elements with button-like classes
229
+ var className = current.className;
230
+ if (className && typeof className === 'string') {
231
+ var cls = className.toLowerCase();
232
+ if (cls.indexOf('btn') !== -1 || cls.indexOf('button') !== -1 || cls.indexOf('cta') !== -1 ||
233
+ cls.indexOf('clickable') !== -1 || cls.indexOf('tappable') !== -1 || cls.indexOf('pressable') !== -1) {
234
+ return current;
235
+ }
236
+ }
237
+
238
+ // Match elements with cursor pointer
239
+ try {
240
+ var computed = window.getComputedStyle(current);
241
+ if (computed && computed.cursor === 'pointer') return current;
242
+ } catch(e) {}
243
+
240
244
  current = current.parentElement;
241
- maxDepth--;
242
245
  }
243
246
  return null;
244
247
  }
245
248
 
246
- // Track currently pressed element
247
- var pressedElement = null;
248
- var pressTimeout = null;
249
+ function applyPressedStyle(el) {
250
+ if (!el || !el.style) return;
251
+ // Save original styles
252
+ pressedOriginalTransform = el.style.transform || '';
253
+ pressedOriginalOpacity = el.style.opacity || '';
254
+ pressedOriginalTransition = el.style.transition || '';
255
+ // Apply pressed style with inline styles for maximum specificity
256
+ 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)';
257
+ el.style.transform = 'scale(0.97)';
258
+ el.style.opacity = '0.8';
259
+ }
260
+
261
+ function applyReleasedStyle(el) {
262
+ if (!el || !el.style) return;
263
+ // Apply spring-back animation
264
+ 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)';
265
+ el.style.transform = pressedOriginalTransform || 'scale(1)';
266
+ el.style.opacity = pressedOriginalOpacity || '1';
267
+ }
268
+
269
+ function resetStyle(el) {
270
+ if (!el || !el.style) return;
271
+ el.style.transform = pressedOriginalTransform;
272
+ el.style.opacity = pressedOriginalOpacity;
273
+ el.style.transition = pressedOriginalTransition;
274
+ }
249
275
 
250
- // Handle touch start - immediate press animation
251
- function handleTouchStart(e) {
276
+ function onTouchStart(e) {
252
277
  try {
253
- var target = findInteractiveElement(e.target);
278
+ var target = findInteractive(e.target);
254
279
  if (!target) return;
255
-
256
- // Clear any pending release animation
257
- if (pressTimeout) {
258
- clearTimeout(pressTimeout);
259
- pressTimeout = null;
260
- }
261
-
262
- // Remove released class and add pressed class
263
- target.classList.remove('rk-released');
264
- target.classList.add('rk-pressed');
265
- pressedElement = target;
266
- } catch(_) {}
280
+ if (releaseTimer) { clearTimeout(releaseTimer); releaseTimer = null; }
281
+ if (pressed && pressed !== target) { resetStyle(pressed); }
282
+ applyPressedStyle(target);
283
+ pressed = target;
284
+ } catch(err) {}
267
285
  }
268
286
 
269
- // Handle touch end - spring release animation
270
- function handleTouchEnd(e) {
287
+ function onTouchEnd(e) {
271
288
  try {
272
- if (!pressedElement) return;
273
- var target = pressedElement;
274
-
275
- // Switch from pressed to released for spring animation
276
- target.classList.remove('rk-pressed');
277
- target.classList.add('rk-released');
278
-
279
- // Clean up after animation completes
280
- pressTimeout = setTimeout(function() {
281
- target.classList.remove('rk-released');
282
- pressTimeout = null;
289
+ if (!pressed) return;
290
+ var t = pressed;
291
+ applyReleasedStyle(t);
292
+ releaseTimer = setTimeout(function() {
293
+ resetStyle(t);
294
+ releaseTimer = null;
283
295
  }, 300);
284
-
285
- pressedElement = null;
286
- } catch(_) {}
296
+ pressed = null;
297
+ } catch(err) {}
287
298
  }
288
299
 
289
- // Handle touch cancel - reset without animation
290
- function handleTouchCancel(e) {
300
+ function onTouchCancel(e) {
291
301
  try {
292
- if (!pressedElement) return;
293
- pressedElement.classList.remove('rk-pressed');
294
- pressedElement.classList.remove('rk-released');
295
- pressedElement = null;
296
- if (pressTimeout) {
297
- clearTimeout(pressTimeout);
298
- pressTimeout = null;
299
- }
300
- } catch(_) {}
302
+ if (!pressed) return;
303
+ resetStyle(pressed);
304
+ pressed = null;
305
+ if (releaseTimer) { clearTimeout(releaseTimer); releaseTimer = null; }
306
+ } catch(err) {}
301
307
  }
302
308
 
303
- // Use capture phase to get events before they're handled
304
- document.addEventListener('touchstart', handleTouchStart, { passive: true, capture: true });
305
- document.addEventListener('touchend', handleTouchEnd, { passive: true, capture: true });
306
- document.addEventListener('touchcancel', handleTouchCancel, { passive: true, capture: true });
309
+ // Use capture phase for immediate response before any other handlers
310
+ document.addEventListener('touchstart', onTouchStart, { passive: true, capture: true });
311
+ document.addEventListener('touchend', onTouchEnd, { passive: true, capture: true });
312
+ document.addEventListener('touchcancel', onTouchCancel, { passive: true, capture: true });
313
+ // Mouse events for testing
314
+ document.addEventListener('mousedown', onTouchStart, { passive: true, capture: true });
315
+ document.addEventListener('mouseup', onTouchEnd, { passive: true, capture: true });
307
316
 
308
- // Also handle mouse events for web testing
309
- document.addEventListener('mousedown', handleTouchStart, { passive: true, capture: true });
310
- document.addEventListener('mouseup', handleTouchEnd, { passive: true, capture: true });
311
- document.addEventListener('mouseleave', handleTouchCancel, { passive: true, capture: true });
312
-
313
- } catch (_) {}
317
+ } catch (err) {}
314
318
  true;
315
319
  })();
316
320
  `;
@@ -413,7 +417,7 @@ function preloadRampkitOverlay(opts) {
413
417
  opacity: 0,
414
418
  top: -1000,
415
419
  left: -1000,
416
- }, children: (0, jsx_runtime_1.jsx)(react_native_webview_1.WebView, { originWhitelist: ["*"], source: { html: docs[0] || "<html></html>" }, injectedJavaScriptBeforeContentLoaded: exports.injectedHardening, injectedJavaScript: exports.injectedNoSelect + exports.injectedVarsHandler + exports.injectedButtonAnimations, automaticallyAdjustContentInsets: false, contentInsetAdjustmentBehavior: "never", bounces: false, scrollEnabled: false, allowsInlineMediaPlayback: true, mediaPlaybackRequiresUserAction: false, cacheEnabled: true, hideKeyboardAccessoryView: true }) }));
420
+ }, children: (0, jsx_runtime_1.jsx)(react_native_webview_1.WebView, { originWhitelist: ["*"], source: { html: docs[0] || "<html></html>" }, injectedJavaScriptBeforeContentLoaded: exports.injectedHardening + exports.injectedButtonAnimations, injectedJavaScript: exports.injectedNoSelect + exports.injectedVarsHandler + exports.injectedButtonAnimations, automaticallyAdjustContentInsets: false, contentInsetAdjustmentBehavior: "never", bounces: false, scrollEnabled: false, allowsInlineMediaPlayback: true, mediaPlaybackRequiresUserAction: false, cacheEnabled: true, hideKeyboardAccessoryView: true }) }));
417
421
  preloadSibling = new react_native_root_siblings_1.default((0, jsx_runtime_1.jsx)(HiddenPreloader, {}));
418
422
  }
419
423
  catch (e) {
@@ -968,7 +972,7 @@ function Overlay(props) {
968
972
  opacity: pagerOpacity,
969
973
  transform: [{ translateX: pagerTranslateX }],
970
974
  },
971
- ], children: (0, jsx_runtime_1.jsx)(react_native_pager_view_1.default, { ref: pagerRef, style: react_native_1.StyleSheet.absoluteFill, scrollEnabled: false, initialPage: 0, onPageSelected: onPageSelected, offscreenPageLimit: props.screens.length, overScrollMode: "never", children: docs.map((doc, i) => ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.page, renderToHardwareTextureAndroid: true, children: (0, jsx_runtime_1.jsx)(react_native_webview_1.WebView, { ref: (r) => (webviewsRef.current[i] = r), style: styles.webview, originWhitelist: ["*"], source: { html: doc }, injectedJavaScriptBeforeContentLoaded: exports.injectedHardening, injectedJavaScript: exports.injectedNoSelect + exports.injectedVarsHandler + exports.injectedButtonAnimations, automaticallyAdjustContentInsets: false, contentInsetAdjustmentBehavior: "never", bounces: false, scrollEnabled: false, overScrollMode: "never", scalesPageToFit: false, showsHorizontalScrollIndicator: false, dataDetectorTypes: "none", allowsLinkPreview: false, allowsInlineMediaPlayback: true, mediaPlaybackRequiresUserAction: false, cacheEnabled: true, javaScriptEnabled: true, domStorageEnabled: true, hideKeyboardAccessoryView: true, onLoadEnd: () => {
975
+ ], children: (0, jsx_runtime_1.jsx)(react_native_pager_view_1.default, { ref: pagerRef, style: react_native_1.StyleSheet.absoluteFill, scrollEnabled: false, initialPage: 0, onPageSelected: onPageSelected, offscreenPageLimit: props.screens.length, overScrollMode: "never", children: docs.map((doc, i) => ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.page, renderToHardwareTextureAndroid: true, children: (0, jsx_runtime_1.jsx)(react_native_webview_1.WebView, { ref: (r) => (webviewsRef.current[i] = r), style: styles.webview, originWhitelist: ["*"], source: { html: doc }, injectedJavaScriptBeforeContentLoaded: exports.injectedHardening + exports.injectedButtonAnimations, injectedJavaScript: exports.injectedNoSelect + exports.injectedVarsHandler + exports.injectedButtonAnimations, automaticallyAdjustContentInsets: false, contentInsetAdjustmentBehavior: "never", bounces: false, scrollEnabled: false, overScrollMode: "never", scalesPageToFit: false, showsHorizontalScrollIndicator: false, dataDetectorTypes: "none", allowsLinkPreview: false, allowsInlineMediaPlayback: true, mediaPlaybackRequiresUserAction: false, cacheEnabled: true, javaScriptEnabled: true, domStorageEnabled: true, hideKeyboardAccessoryView: true, onLoadEnd: () => {
972
976
  setLoadedCount((c) => c + 1);
973
977
  if (i === 0) {
974
978
  setFirstPageLoaded(true);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rampkit-expo-dev",
3
- "version": "0.0.41",
3
+ "version": "0.0.43",
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",