rampkit-expo-dev 0.0.30 → 0.0.32
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 +0 -1
- package/build/RampkitOverlay.js +65 -90
- package/package.json +1 -1
|
@@ -2,7 +2,6 @@ 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 injectedTemplateResolver: string;
|
|
6
5
|
export type ScreenPayload = {
|
|
7
6
|
id: string;
|
|
8
7
|
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.
|
|
39
|
+
exports.injectedVarsHandler = exports.injectedNoSelect = exports.injectedHardening = void 0;
|
|
40
40
|
exports.showRampkitOverlay = showRampkitOverlay;
|
|
41
41
|
exports.hideRampkitOverlay = hideRampkitOverlay;
|
|
42
42
|
exports.closeRampkitOverlay = closeRampkitOverlay;
|
|
@@ -173,84 +173,6 @@ exports.injectedVarsHandler = `
|
|
|
173
173
|
true;
|
|
174
174
|
})();
|
|
175
175
|
`;
|
|
176
|
-
// Template resolution script that replaces ${device.xxx} and ${user.xxx} with actual values
|
|
177
|
-
// Built using string concatenation to avoid template literal escaping issues
|
|
178
|
-
exports.injectedTemplateResolver = [
|
|
179
|
-
"(function(){",
|
|
180
|
-
" try {",
|
|
181
|
-
" if (window.__rkTemplateResolverApplied) return true;",
|
|
182
|
-
" window.__rkTemplateResolverApplied = true;",
|
|
183
|
-
" ",
|
|
184
|
-
" console.log('[Rampkit] Template resolver starting...');",
|
|
185
|
-
" console.log('[Rampkit] rampkitContext:', JSON.stringify(window.rampkitContext));",
|
|
186
|
-
" ",
|
|
187
|
-
" function buildVarMap() {",
|
|
188
|
-
" var vars = {};",
|
|
189
|
-
" var ctx = window.rampkitContext || { device: {}, user: {} };",
|
|
190
|
-
" var state = window.__rampkitVariables || {};",
|
|
191
|
-
" if (ctx.device) {",
|
|
192
|
-
" Object.keys(ctx.device).forEach(function(key) {",
|
|
193
|
-
" vars['device.' + key] = ctx.device[key];",
|
|
194
|
-
" });",
|
|
195
|
-
" }",
|
|
196
|
-
" if (ctx.user) {",
|
|
197
|
-
" Object.keys(ctx.user).forEach(function(key) {",
|
|
198
|
-
" vars['user.' + key] = ctx.user[key];",
|
|
199
|
-
" });",
|
|
200
|
-
" }",
|
|
201
|
-
" Object.keys(state).forEach(function(key) {",
|
|
202
|
-
" vars[key] = state[key];",
|
|
203
|
-
" });",
|
|
204
|
-
" console.log('[Rampkit] Variable map:', JSON.stringify(vars));",
|
|
205
|
-
" return vars;",
|
|
206
|
-
" }",
|
|
207
|
-
" ",
|
|
208
|
-
" function formatValue(value) {",
|
|
209
|
-
" if (value === undefined || value === null) return '';",
|
|
210
|
-
" if (typeof value === 'boolean') return value ? 'true' : 'false';",
|
|
211
|
-
" if (typeof value === 'object') return JSON.stringify(value);",
|
|
212
|
-
" return String(value);",
|
|
213
|
-
" }",
|
|
214
|
-
" ",
|
|
215
|
-
" function resolveAllTemplates() {",
|
|
216
|
-
" console.log('[Rampkit] Resolving templates...');",
|
|
217
|
-
" var vars = buildVarMap();",
|
|
218
|
-
" var pattern = /\\$\\{([A-Za-z_][A-Za-z0-9_.]*)\\}/g;",
|
|
219
|
-
" var bodyHtml = document.body.innerHTML;",
|
|
220
|
-
" var marker = String.fromCharCode(36, 123);", // $ = 36, { = 123
|
|
221
|
-
" var hasTemplates = bodyHtml.indexOf(marker) !== -1;",
|
|
222
|
-
" console.log('[Rampkit] Body has templates:', hasTemplates);",
|
|
223
|
-
" if (hasTemplates) {",
|
|
224
|
-
" var newHtml = bodyHtml.replace(pattern, function(match, varName) {",
|
|
225
|
-
" console.log('[Rampkit] Found template:', match, 'varName:', varName);",
|
|
226
|
-
" if (vars.hasOwnProperty(varName)) {",
|
|
227
|
-
" var value = formatValue(vars[varName]);",
|
|
228
|
-
" console.log('[Rampkit] Replacing with:', value);",
|
|
229
|
-
" return value;",
|
|
230
|
-
" }",
|
|
231
|
-
" console.log('[Rampkit] No value found for:', varName);",
|
|
232
|
-
" return match;",
|
|
233
|
-
" });",
|
|
234
|
-
" if (newHtml !== bodyHtml) {",
|
|
235
|
-
" document.body.innerHTML = newHtml;",
|
|
236
|
-
" console.log('[Rampkit] Templates resolved!');",
|
|
237
|
-
" }",
|
|
238
|
-
" }",
|
|
239
|
-
" }",
|
|
240
|
-
" ",
|
|
241
|
-
" setTimeout(resolveAllTemplates, 50);",
|
|
242
|
-
" setTimeout(resolveAllTemplates, 200);",
|
|
243
|
-
" window.rampkitResolveTemplates = resolveAllTemplates;",
|
|
244
|
-
" document.addEventListener('rampkit:vars-updated', function() {",
|
|
245
|
-
" setTimeout(resolveAllTemplates, 0);",
|
|
246
|
-
" });",
|
|
247
|
-
" console.log('[Rampkit] Template resolver initialized');",
|
|
248
|
-
" } catch(e) {",
|
|
249
|
-
" console.log('[Rampkit] Template resolver error:', e);",
|
|
250
|
-
" }",
|
|
251
|
-
" true;",
|
|
252
|
-
"})();",
|
|
253
|
-
].join("\n");
|
|
254
176
|
function performRampkitHaptic(event) {
|
|
255
177
|
if (!event || event.action !== "haptic") {
|
|
256
178
|
// Backwards compatible default
|
|
@@ -300,13 +222,15 @@ function performRampkitHaptic(event) {
|
|
|
300
222
|
}
|
|
301
223
|
let sibling = null;
|
|
302
224
|
let preloadSibling = null;
|
|
303
|
-
|
|
225
|
+
// Cache is now disabled - always rebuild docs to ensure templates are resolved with current context
|
|
226
|
+
// const preloadCache = new Map<string, string[]>();
|
|
304
227
|
let activeCloseHandler = null;
|
|
305
228
|
function showRampkitOverlay(opts) {
|
|
306
|
-
console.log("showRampkitOverlay");
|
|
229
|
+
console.log("[RampKit] showRampkitOverlay called, context:", opts.rampkitContext ? "present" : "missing");
|
|
307
230
|
if (sibling)
|
|
308
231
|
return; // already visible
|
|
309
|
-
|
|
232
|
+
// Always build fresh docs to ensure templates are resolved with current context
|
|
233
|
+
const prebuiltDocs = undefined;
|
|
310
234
|
sibling = new react_native_root_siblings_1.default(((0, jsx_runtime_1.jsx)(Overlay, { onboardingId: opts.onboardingId, screens: opts.screens, variables: opts.variables, requiredScripts: opts.requiredScripts, rampkitContext: opts.rampkitContext, prebuiltDocs: prebuiltDocs, onRequestClose: () => {
|
|
311
235
|
var _a;
|
|
312
236
|
activeCloseHandler = null;
|
|
@@ -336,14 +260,11 @@ function closeRampkitOverlay() {
|
|
|
336
260
|
hideRampkitOverlay();
|
|
337
261
|
}
|
|
338
262
|
function preloadRampkitOverlay(opts) {
|
|
263
|
+
// Preloading is now simplified - just warm up the WebView process
|
|
339
264
|
try {
|
|
340
|
-
if (preloadCache.has(opts.onboardingId))
|
|
341
|
-
return;
|
|
342
|
-
const docs = opts.screens.map((s) => buildHtmlDocument(s, opts.variables, opts.requiredScripts, opts.rampkitContext));
|
|
343
|
-
preloadCache.set(opts.onboardingId, docs);
|
|
344
|
-
// Mount a hidden WebView to warm up the WebView process and cache
|
|
345
265
|
if (preloadSibling)
|
|
346
266
|
return;
|
|
267
|
+
const docs = opts.screens.map((s) => buildHtmlDocument(s, opts.variables, opts.requiredScripts, opts.rampkitContext));
|
|
347
268
|
const HiddenPreloader = () => ((0, jsx_runtime_1.jsx)(react_native_1.View, { pointerEvents: "none", style: {
|
|
348
269
|
position: "absolute",
|
|
349
270
|
width: 1,
|
|
@@ -351,17 +272,62 @@ function preloadRampkitOverlay(opts) {
|
|
|
351
272
|
opacity: 0,
|
|
352
273
|
top: -1000,
|
|
353
274
|
left: -1000,
|
|
354
|
-
}, 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
|
|
275
|
+
}, 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 }) }));
|
|
355
276
|
preloadSibling = new react_native_root_siblings_1.default((0, jsx_runtime_1.jsx)(HiddenPreloader, {}));
|
|
356
277
|
}
|
|
357
278
|
catch (e) {
|
|
358
279
|
// best-effort preloading; ignore errors
|
|
359
280
|
}
|
|
360
281
|
}
|
|
282
|
+
/**
|
|
283
|
+
* Resolve device/user templates in a string
|
|
284
|
+
* Replaces ${device.xxx} and ${user.xxx} with actual values from context
|
|
285
|
+
*/
|
|
286
|
+
function resolveContextTemplates(text, context) {
|
|
287
|
+
if (!text || !text.includes("${"))
|
|
288
|
+
return text;
|
|
289
|
+
// Build variable map
|
|
290
|
+
const vars = {};
|
|
291
|
+
// Device vars
|
|
292
|
+
if (context.device) {
|
|
293
|
+
Object.entries(context.device).forEach(([key, value]) => {
|
|
294
|
+
vars[`device.${key}`] = value;
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
// User vars
|
|
298
|
+
if (context.user) {
|
|
299
|
+
Object.entries(context.user).forEach(([key, value]) => {
|
|
300
|
+
vars[`user.${key}`] = value;
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
console.log("[RampKit] Resolving templates with vars:", JSON.stringify(vars));
|
|
304
|
+
// Replace ${varName} patterns
|
|
305
|
+
return text.replace(/\$\{([A-Za-z_][A-Za-z0-9_.]*)\}/g, (match, varName) => {
|
|
306
|
+
if (vars.hasOwnProperty(varName)) {
|
|
307
|
+
const value = vars[varName];
|
|
308
|
+
console.log(`[RampKit] Replacing ${match} with:`, value);
|
|
309
|
+
if (value === undefined || value === null)
|
|
310
|
+
return "";
|
|
311
|
+
if (typeof value === "boolean")
|
|
312
|
+
return value ? "true" : "false";
|
|
313
|
+
if (typeof value === "object")
|
|
314
|
+
return JSON.stringify(value);
|
|
315
|
+
return String(value);
|
|
316
|
+
}
|
|
317
|
+
// Not a device/user var - leave for state variable handling
|
|
318
|
+
return match;
|
|
319
|
+
});
|
|
320
|
+
}
|
|
361
321
|
function buildHtmlDocument(screen, variables, requiredScripts, rampkitContext) {
|
|
322
|
+
console.log("[RampKit] buildHtmlDocument called");
|
|
323
|
+
console.log("[RampKit] rampkitContext received:", rampkitContext ? JSON.stringify(rampkitContext).slice(0, 200) : "undefined");
|
|
362
324
|
const css = screen.css || "";
|
|
363
|
-
|
|
325
|
+
let html = screen.html || "";
|
|
364
326
|
const js = screen.js || "";
|
|
327
|
+
// Log if HTML contains device/user templates
|
|
328
|
+
if (html.includes("${device.") || html.includes("${user.")) {
|
|
329
|
+
console.log("[RampKit] HTML contains device/user templates");
|
|
330
|
+
}
|
|
365
331
|
const scripts = (requiredScripts || [])
|
|
366
332
|
.map((src) => `<script src="${src}"></script>`)
|
|
367
333
|
.join("\n");
|
|
@@ -418,6 +384,15 @@ function buildHtmlDocument(screen, variables, requiredScripts, rampkitContext) {
|
|
|
418
384
|
installedAt: new Date().toISOString(),
|
|
419
385
|
},
|
|
420
386
|
};
|
|
387
|
+
// Resolve device/user templates in HTML BEFORE sending to WebView
|
|
388
|
+
const originalHtml = html;
|
|
389
|
+
html = resolveContextTemplates(html, context);
|
|
390
|
+
if (originalHtml !== html) {
|
|
391
|
+
console.log("[RampKit] Templates were resolved in HTML");
|
|
392
|
+
}
|
|
393
|
+
else if (originalHtml.includes("${device.") || originalHtml.includes("${user.")) {
|
|
394
|
+
console.log("[RampKit] WARNING: HTML still contains unresolved device/user templates!");
|
|
395
|
+
}
|
|
421
396
|
return `<!doctype html>
|
|
422
397
|
<html>
|
|
423
398
|
<head>
|
|
@@ -760,7 +735,7 @@ function Overlay(props) {
|
|
|
760
735
|
styles.root,
|
|
761
736
|
!visible && styles.invisible,
|
|
762
737
|
visible && { opacity: overlayOpacity },
|
|
763
|
-
], 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
|
|
738
|
+
], 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: () => {
|
|
764
739
|
setLoadedCount((c) => c + 1);
|
|
765
740
|
if (i === 0) {
|
|
766
741
|
setFirstPageLoaded(true);
|
package/package.json
CHANGED