rampkit-expo-dev 0.0.25 → 0.0.27
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 +1 -0
- package/build/RampkitOverlay.js +102 -25
- package/package.json +1 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
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";
|
|
2
2
|
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";
|
|
3
|
+
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";
|
|
3
4
|
export type ScreenPayload = {
|
|
4
5
|
id: string;
|
|
5
6
|
html: string;
|
package/build/RampkitOverlay.js
CHANGED
|
@@ -36,7 +36,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
36
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.injectedNoSelect = exports.injectedHardening = void 0;
|
|
39
|
+
exports.injectedVarsHandler = exports.injectedNoSelect = exports.injectedHardening = void 0;
|
|
40
40
|
exports.showRampkitOverlay = showRampkitOverlay;
|
|
41
41
|
exports.hideRampkitOverlay = hideRampkitOverlay;
|
|
42
42
|
exports.closeRampkitOverlay = closeRampkitOverlay;
|
|
@@ -125,6 +125,54 @@ exports.injectedNoSelect = `
|
|
|
125
125
|
true;
|
|
126
126
|
})();
|
|
127
127
|
`;
|
|
128
|
+
// Robust variable handler that ensures variables are always received and applied
|
|
129
|
+
// This runs after content loads and sets up listeners for incoming variable updates
|
|
130
|
+
exports.injectedVarsHandler = `
|
|
131
|
+
(function(){
|
|
132
|
+
try {
|
|
133
|
+
if (window.__rkVarsHandlerApplied) return true;
|
|
134
|
+
window.__rkVarsHandlerApplied = true;
|
|
135
|
+
|
|
136
|
+
// Handler function that updates variables and notifies the page
|
|
137
|
+
window.__rkHandleVarsUpdate = function(vars) {
|
|
138
|
+
if (!vars || typeof vars !== 'object') return;
|
|
139
|
+
// Update the global variables object
|
|
140
|
+
window.__rampkitVariables = vars;
|
|
141
|
+
// Dispatch a custom event that the page's JS can listen to for re-rendering
|
|
142
|
+
try {
|
|
143
|
+
document.dispatchEvent(new CustomEvent('rampkit:vars-updated', { detail: vars }));
|
|
144
|
+
} catch(e) {}
|
|
145
|
+
// Also try calling a global handler if the page defined one
|
|
146
|
+
try {
|
|
147
|
+
if (typeof window.onRampkitVarsUpdate === 'function') {
|
|
148
|
+
window.onRampkitVarsUpdate(vars);
|
|
149
|
+
}
|
|
150
|
+
} catch(e) {}
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
// Listen for message events from React Native
|
|
154
|
+
document.addEventListener('message', function(event) {
|
|
155
|
+
try {
|
|
156
|
+
var data = event.data;
|
|
157
|
+
if (data && data.type === 'rampkit:variables' && data.vars) {
|
|
158
|
+
window.__rkHandleVarsUpdate(data.vars);
|
|
159
|
+
}
|
|
160
|
+
} catch(e) {}
|
|
161
|
+
}, false);
|
|
162
|
+
|
|
163
|
+
// Also listen on window for compatibility
|
|
164
|
+
window.addEventListener('message', function(event) {
|
|
165
|
+
try {
|
|
166
|
+
var data = event.data;
|
|
167
|
+
if (data && data.type === 'rampkit:variables' && data.vars) {
|
|
168
|
+
window.__rkHandleVarsUpdate(data.vars);
|
|
169
|
+
}
|
|
170
|
+
} catch(e) {}
|
|
171
|
+
}, false);
|
|
172
|
+
} catch (_) {}
|
|
173
|
+
true;
|
|
174
|
+
})();
|
|
175
|
+
`;
|
|
128
176
|
function performRampkitHaptic(event) {
|
|
129
177
|
if (!event || event.action !== "haptic") {
|
|
130
178
|
// Backwards compatible default
|
|
@@ -225,7 +273,7 @@ function preloadRampkitOverlay(opts) {
|
|
|
225
273
|
opacity: 0,
|
|
226
274
|
top: -1000,
|
|
227
275
|
left: -1000,
|
|
228
|
-
}, children: (0, jsx_runtime_1.jsx)(react_native_webview_1.WebView, { originWhitelist: ["*"], source: { html: docs[0] || "<html></html>" }, injectedJavaScriptBeforeContentLoaded: exports.injectedHardening, injectedJavaScript: exports.injectedNoSelect, automaticallyAdjustContentInsets: false, contentInsetAdjustmentBehavior: "never", bounces: false, scrollEnabled: false, allowsInlineMediaPlayback: true, mediaPlaybackRequiresUserAction: false, cacheEnabled: true, hideKeyboardAccessoryView: true }) }));
|
|
276
|
+
}, 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, automaticallyAdjustContentInsets: false, contentInsetAdjustmentBehavior: "never", bounces: false, scrollEnabled: false, allowsInlineMediaPlayback: true, mediaPlaybackRequiresUserAction: false, cacheEnabled: true, hideKeyboardAccessoryView: true }) }));
|
|
229
277
|
preloadSibling = new react_native_root_siblings_1.default((0, jsx_runtime_1.jsx)(HiddenPreloader, {}));
|
|
230
278
|
}
|
|
231
279
|
catch (e) {
|
|
@@ -404,11 +452,38 @@ function Overlay(props) {
|
|
|
404
452
|
.replace(/`/g, "\\`");
|
|
405
453
|
return `(function(){try{document.dispatchEvent(new MessageEvent('message',{data:${json}}));}catch(e){}})();`;
|
|
406
454
|
}
|
|
455
|
+
// Build a script that directly sets variables and triggers updates
|
|
456
|
+
// This is more reliable than dispatching events which may not be caught
|
|
457
|
+
function buildDirectVarsScript(vars) {
|
|
458
|
+
const json = JSON.stringify(vars)
|
|
459
|
+
.replace(/\\/g, "\\\\")
|
|
460
|
+
.replace(/`/g, "\\`");
|
|
461
|
+
return `(function(){
|
|
462
|
+
try {
|
|
463
|
+
var newVars = ${json};
|
|
464
|
+
// Directly update the global variables object
|
|
465
|
+
window.__rampkitVariables = newVars;
|
|
466
|
+
// Call the handler if available
|
|
467
|
+
if (typeof window.__rkHandleVarsUpdate === 'function') {
|
|
468
|
+
window.__rkHandleVarsUpdate(newVars);
|
|
469
|
+
}
|
|
470
|
+
// Dispatch custom event for any listeners
|
|
471
|
+
try {
|
|
472
|
+
document.dispatchEvent(new CustomEvent('rampkit:vars-updated', {detail: newVars}));
|
|
473
|
+
} catch(e) {}
|
|
474
|
+
// Call global callback if defined
|
|
475
|
+
if (typeof window.onRampkitVarsUpdate === 'function') {
|
|
476
|
+
window.onRampkitVarsUpdate(newVars);
|
|
477
|
+
}
|
|
478
|
+
} catch(e) {
|
|
479
|
+
console.log('[Rampkit] buildDirectVarsScript error:', e);
|
|
480
|
+
}
|
|
481
|
+
})();`;
|
|
482
|
+
}
|
|
407
483
|
function sendVarsToWebView(i, isInitialLoad = false) {
|
|
408
484
|
const wv = webviewsRef.current[i];
|
|
409
485
|
if (!wv)
|
|
410
486
|
return;
|
|
411
|
-
const payload = { type: "rampkit:variables", vars: varsRef.current };
|
|
412
487
|
if (__DEV__)
|
|
413
488
|
console.log("[Rampkit] sendVarsToWebView", i, varsRef.current, { isInitialLoad });
|
|
414
489
|
// Only update the stale filter timestamp during initial page load,
|
|
@@ -418,8 +493,10 @@ function Overlay(props) {
|
|
|
418
493
|
if (isInitialLoad) {
|
|
419
494
|
lastInitSendRef.current[i] = Date.now();
|
|
420
495
|
}
|
|
496
|
+
// Use direct variable setting instead of MessageEvent dispatch
|
|
497
|
+
// This is more reliable as it doesn't depend on event listeners being set up
|
|
421
498
|
// @ts-ignore: injectJavaScript exists on WebView instance
|
|
422
|
-
wv.injectJavaScript(
|
|
499
|
+
wv.injectJavaScript(buildDirectVarsScript(varsRef.current));
|
|
423
500
|
}
|
|
424
501
|
function broadcastVars() {
|
|
425
502
|
if (__DEV__)
|
|
@@ -427,14 +504,12 @@ function Overlay(props) {
|
|
|
427
504
|
recipients: webviewsRef.current.length,
|
|
428
505
|
vars: varsRef.current,
|
|
429
506
|
});
|
|
507
|
+
const script = buildDirectVarsScript(varsRef.current);
|
|
430
508
|
for (let i = 0; i < webviewsRef.current.length; i++) {
|
|
431
509
|
const wv = webviewsRef.current[i];
|
|
432
510
|
if (wv) {
|
|
433
511
|
// @ts-ignore: injectJavaScript exists on WebView instance
|
|
434
|
-
wv.injectJavaScript(
|
|
435
|
-
type: "rampkit:variables",
|
|
436
|
-
vars: varsRef.current,
|
|
437
|
-
}));
|
|
512
|
+
wv.injectJavaScript(script);
|
|
438
513
|
}
|
|
439
514
|
}
|
|
440
515
|
}
|
|
@@ -485,12 +560,20 @@ function Overlay(props) {
|
|
|
485
560
|
// ensure current page is synced with latest vars when selected
|
|
486
561
|
if (__DEV__)
|
|
487
562
|
console.log("[Rampkit] onPageSelected", pos);
|
|
488
|
-
//
|
|
489
|
-
//
|
|
490
|
-
//
|
|
563
|
+
// Send vars multiple times with increasing delays to ensure the webview
|
|
564
|
+
// receives them. The first send might fail if the webview isn't fully ready,
|
|
565
|
+
// so we retry a few times.
|
|
491
566
|
requestAnimationFrame(() => {
|
|
492
567
|
sendVarsToWebView(pos);
|
|
493
568
|
});
|
|
569
|
+
// Retry after a short delay in case the first send didn't work
|
|
570
|
+
setTimeout(() => {
|
|
571
|
+
sendVarsToWebView(pos);
|
|
572
|
+
}, 50);
|
|
573
|
+
// Final retry to catch any edge cases
|
|
574
|
+
setTimeout(() => {
|
|
575
|
+
sendVarsToWebView(pos);
|
|
576
|
+
}, 150);
|
|
494
577
|
// Track screen change event
|
|
495
578
|
if (props.onScreenChange && props.screens[pos]) {
|
|
496
579
|
props.onScreenChange(pos, props.screens[pos].id);
|
|
@@ -571,7 +654,7 @@ function Overlay(props) {
|
|
|
571
654
|
styles.root,
|
|
572
655
|
!visible && styles.invisible,
|
|
573
656
|
visible && { opacity: overlayOpacity },
|
|
574
|
-
], pointerEvents: visible && !isClosing ? "auto" : "none", 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, 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: () => {
|
|
657
|
+
], pointerEvents: visible && !isClosing ? "auto" : "none", 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, 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: () => {
|
|
575
658
|
setLoadedCount((c) => c + 1);
|
|
576
659
|
if (i === 0) {
|
|
577
660
|
setFirstPageLoaded(true);
|
|
@@ -599,28 +682,22 @@ function Overlay(props) {
|
|
|
599
682
|
typeof data.vars === "object") {
|
|
600
683
|
if (__DEV__)
|
|
601
684
|
console.log("[Rampkit] received variables from page", i, data.vars);
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
685
|
+
// Accept all variable updates from pages without filtering.
|
|
686
|
+
// The previous filter was too aggressive and blocked legitimate
|
|
687
|
+
// user interactions that happened within 600ms of page load.
|
|
688
|
+
// We now trust that pages send correct variable updates.
|
|
605
689
|
let changed = false;
|
|
690
|
+
const newVars = {};
|
|
606
691
|
for (const [key, value] of Object.entries(data.vars)) {
|
|
607
692
|
const hasHostVal = Object.prototype.hasOwnProperty.call(varsRef.current, key);
|
|
608
693
|
const hostVal = varsRef.current[key];
|
|
609
|
-
if (now - lastInit < 600 &&
|
|
610
|
-
hasHostVal &&
|
|
611
|
-
hostVal !== undefined &&
|
|
612
|
-
value !== hostVal) {
|
|
613
|
-
if (__DEV__)
|
|
614
|
-
console.log("[Rampkit] ignore stale var from page", i, key, value, "kept", hostVal);
|
|
615
|
-
continue;
|
|
616
|
-
}
|
|
617
694
|
if (!hasHostVal || hostVal !== value) {
|
|
618
|
-
|
|
695
|
+
newVars[key] = value;
|
|
619
696
|
changed = true;
|
|
620
697
|
}
|
|
621
698
|
}
|
|
622
699
|
if (changed) {
|
|
623
|
-
varsRef.current = { ...varsRef.current, ...
|
|
700
|
+
varsRef.current = { ...varsRef.current, ...newVars };
|
|
624
701
|
broadcastVars();
|
|
625
702
|
}
|
|
626
703
|
return;
|
package/package.json
CHANGED