@magicfeedback/popup-sdk 1.7.0 → 1.7.2
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/README.md +33 -0
- package/dist/{chunk-WNIUIOKF.mjs → chunk-322DDMX6.mjs} +69 -1
- package/dist/chunk-322DDMX6.mjs.map +1 -0
- package/dist/{chunk-W6MPSWMS.mjs → chunk-XHR3MHJO.mjs} +69 -1
- package/dist/chunk-XHR3MHJO.mjs.map +1 -0
- package/dist/index.d.mts +81 -6
- package/dist/index.d.ts +81 -6
- package/dist/index.js +361 -14
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +239 -10
- package/dist/index.mjs.map +1 -1
- package/dist/react-native.d.mts +48 -5
- package/dist/react-native.d.ts +48 -5
- package/dist/react-native.js +374 -22
- package/dist/react-native.js.map +1 -1
- package/dist/react-native.mjs +255 -20
- package/dist/react-native.mjs.map +1 -1
- package/dist/{renderPopup-IHGYFMXO.mjs → renderPopup-5QXL6EJW.mjs} +48 -8
- package/dist/renderPopup-5QXL6EJW.mjs.map +1 -0
- package/dist/{renderPopup-EWGKG53W.mjs → renderPopup-SNDPX5RX.mjs} +46 -6
- package/dist/renderPopup-SNDPX5RX.mjs.map +1 -0
- package/package.json +4 -3
- package/dist/chunk-W6MPSWMS.mjs.map +0 -1
- package/dist/chunk-WNIUIOKF.mjs.map +0 -1
- package/dist/renderPopup-EWGKG53W.mjs.map +0 -1
- package/dist/renderPopup-IHGYFMXO.mjs.map +0 -1
package/dist/react-native.js
CHANGED
|
@@ -446,6 +446,82 @@ var init_labels = __esm({
|
|
|
446
446
|
}
|
|
447
447
|
});
|
|
448
448
|
|
|
449
|
+
// src/ui/reveal.ts
|
|
450
|
+
function revealWhenPainted(root, reveal) {
|
|
451
|
+
const pending2 = Array.from(root.querySelectorAll("img")).filter((img) => !img.complete);
|
|
452
|
+
if (!pending2.length) {
|
|
453
|
+
reveal();
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
let left = pending2.length;
|
|
457
|
+
const onSettled = () => {
|
|
458
|
+
left -= 1;
|
|
459
|
+
if (left <= 0) reveal();
|
|
460
|
+
};
|
|
461
|
+
pending2.forEach((img) => {
|
|
462
|
+
img.addEventListener("load", onSettled, { once: true });
|
|
463
|
+
img.addEventListener("error", onSettled, { once: true });
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
var REVEAL_TIMEOUT_MS;
|
|
467
|
+
var init_reveal = __esm({
|
|
468
|
+
"src/ui/reveal.ts"() {
|
|
469
|
+
"use strict";
|
|
470
|
+
REVEAL_TIMEOUT_MS = 1200;
|
|
471
|
+
}
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
// src/ui/surveyPalette.ts
|
|
475
|
+
function resolveSurveyPrimaryColor(style) {
|
|
476
|
+
for (const candidate of [style?.primaryColor, style?.buttonPrimaryColor]) {
|
|
477
|
+
const value = (candidate ?? "").trim();
|
|
478
|
+
if (HEX_COLOR.test(value)) return value;
|
|
479
|
+
}
|
|
480
|
+
return null;
|
|
481
|
+
}
|
|
482
|
+
function surveyPrimaryVars(color) {
|
|
483
|
+
return [
|
|
484
|
+
["--mf-primary", color],
|
|
485
|
+
["--mf-primary-hover", `color-mix(in srgb, ${color} 85%, black)`],
|
|
486
|
+
["--mf-primary-light", `color-mix(in srgb, ${color} 15%, white)`],
|
|
487
|
+
["--mf-primary-border", `color-mix(in srgb, ${color} 35%, transparent)`],
|
|
488
|
+
["--mf-border-focus", color]
|
|
489
|
+
];
|
|
490
|
+
}
|
|
491
|
+
function applySurveyPrimaryColor(el, style) {
|
|
492
|
+
const color = resolveSurveyPrimaryColor(style);
|
|
493
|
+
if (!color) return;
|
|
494
|
+
for (const [name, value] of surveyPrimaryVars(color)) {
|
|
495
|
+
el.style.setProperty(name, value);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
var HEX_COLOR, PRIMARY_COLOR_JS;
|
|
499
|
+
var init_surveyPalette = __esm({
|
|
500
|
+
"src/ui/surveyPalette.ts"() {
|
|
501
|
+
"use strict";
|
|
502
|
+
HEX_COLOR = /^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;
|
|
503
|
+
PRIMARY_COLOR_JS = `
|
|
504
|
+
function ddResolveSurveyPrimaryColor(style){
|
|
505
|
+
var hex=/^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;
|
|
506
|
+
var candidates=[style&&style.primaryColor, style&&style.buttonPrimaryColor];
|
|
507
|
+
for(var i=0;i<candidates.length;i++){
|
|
508
|
+
var value=(candidates[i]||'').trim();
|
|
509
|
+
if(hex.test(value)){ return value; }
|
|
510
|
+
}
|
|
511
|
+
return null;
|
|
512
|
+
}
|
|
513
|
+
function ddApplySurveyPrimaryColor(el, style){
|
|
514
|
+
var color=ddResolveSurveyPrimaryColor(style);
|
|
515
|
+
if(!color||!el){ return; }
|
|
516
|
+
el.style.setProperty('--mf-primary', color);
|
|
517
|
+
el.style.setProperty('--mf-primary-hover', 'color-mix(in srgb, '+color+' 85%, black)');
|
|
518
|
+
el.style.setProperty('--mf-primary-light', 'color-mix(in srgb, '+color+' 15%, white)');
|
|
519
|
+
el.style.setProperty('--mf-primary-border', 'color-mix(in srgb, '+color+' 35%, transparent)');
|
|
520
|
+
el.style.setProperty('--mf-border-focus', color);
|
|
521
|
+
}`;
|
|
522
|
+
}
|
|
523
|
+
});
|
|
524
|
+
|
|
449
525
|
// src/assets/style.css
|
|
450
526
|
var style_default;
|
|
451
527
|
var init_style = __esm({
|
|
@@ -2338,6 +2414,8 @@ var init_logo = __esm({
|
|
|
2338
2414
|
// src/ui/renderPopup.ts
|
|
2339
2415
|
var renderPopup_exports = {};
|
|
2340
2416
|
__export(renderPopup_exports, {
|
|
2417
|
+
REVEAL_TIMEOUT_MS: () => REVEAL_TIMEOUT_MS,
|
|
2418
|
+
SURVEY_ALIGNMENT_STYLE_ID: () => SURVEY_ALIGNMENT_STYLE_ID,
|
|
2341
2419
|
renderPopup: () => renderPopup
|
|
2342
2420
|
});
|
|
2343
2421
|
function ensureMagicFeedbackStyles(_popup) {
|
|
@@ -2348,6 +2426,17 @@ function ensureMagicFeedbackStyles(_popup) {
|
|
|
2348
2426
|
style.textContent = style_default;
|
|
2349
2427
|
document.head.appendChild(style);
|
|
2350
2428
|
}
|
|
2429
|
+
function ensureSurveyAlignmentStyles() {
|
|
2430
|
+
if (document.getElementById(SURVEY_ALIGNMENT_STYLE_ID)) return;
|
|
2431
|
+
const style = document.createElement("style");
|
|
2432
|
+
style.id = SURVEY_ALIGNMENT_STYLE_ID;
|
|
2433
|
+
style.textContent = `
|
|
2434
|
+
.deepdots-popup .magicfeedback-container,
|
|
2435
|
+
.deepdots-popup .magicfeedback-form,
|
|
2436
|
+
.deepdots-popup .magicfeedback-div { padding-left: 0; padding-right: 0; }
|
|
2437
|
+
`;
|
|
2438
|
+
document.head.appendChild(style);
|
|
2439
|
+
}
|
|
2351
2440
|
function ensureSpinnerStyles(_popup) {
|
|
2352
2441
|
if (document.getElementById("deepdots-spinner-styles")) return;
|
|
2353
2442
|
const style = document.createElement("style");
|
|
@@ -2600,6 +2689,7 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
|
|
|
2600
2689
|
progressFollowUp.style.display = p.followup ? "inline-block" : "none";
|
|
2601
2690
|
}
|
|
2602
2691
|
ensureMagicFeedbackStyles(popup);
|
|
2692
|
+
ensureSurveyAlignmentStyles();
|
|
2603
2693
|
ensureSpinnerStyles(popup);
|
|
2604
2694
|
ensureResponsiveStyles(popup);
|
|
2605
2695
|
ensureCustomCss(options?.surveyCss);
|
|
@@ -2658,7 +2748,7 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
|
|
|
2658
2748
|
border: none;
|
|
2659
2749
|
min-height: 44px;
|
|
2660
2750
|
padding: 12px 24px;
|
|
2661
|
-
border-radius:
|
|
2751
|
+
border-radius: 999px; /* p\xEDldora, como el Button de Material3 en KMP */
|
|
2662
2752
|
cursor: pointer;
|
|
2663
2753
|
font-size: 15px;
|
|
2664
2754
|
font-weight: 600;
|
|
@@ -2688,7 +2778,7 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
|
|
|
2688
2778
|
border: none;
|
|
2689
2779
|
min-height: 44px;
|
|
2690
2780
|
padding: 12px 24px;
|
|
2691
|
-
border-radius:
|
|
2781
|
+
border-radius: 999px; /* p\xEDldora, como el Button de Material3 en KMP */
|
|
2692
2782
|
cursor: pointer;
|
|
2693
2783
|
font-size: 15px;
|
|
2694
2784
|
font-weight: 600;
|
|
@@ -2715,7 +2805,7 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
|
|
|
2715
2805
|
border: none;
|
|
2716
2806
|
min-height: 44px;
|
|
2717
2807
|
padding: 12px 24px;
|
|
2718
|
-
border-radius:
|
|
2808
|
+
border-radius: 999px; /* p\xEDldora, como el Button de Material3 en KMP */
|
|
2719
2809
|
cursor: pointer;
|
|
2720
2810
|
font-size: 15px;
|
|
2721
2811
|
font-weight: 600;
|
|
@@ -2746,7 +2836,7 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
|
|
|
2746
2836
|
border: none;
|
|
2747
2837
|
min-height: 44px;
|
|
2748
2838
|
padding: 12px 24px;
|
|
2749
|
-
border-radius:
|
|
2839
|
+
border-radius: 999px; /* p\xEDldora, como el Button de Material3 en KMP */
|
|
2750
2840
|
cursor: pointer;
|
|
2751
2841
|
font-size: 15px;
|
|
2752
2842
|
font-weight: 600;
|
|
@@ -2848,14 +2938,35 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
|
|
|
2848
2938
|
container.innerHTML = "";
|
|
2849
2939
|
container.appendChild(popup);
|
|
2850
2940
|
container.style.display = "flex";
|
|
2941
|
+
container.style.visibility = "hidden";
|
|
2942
|
+
container.style.pointerEvents = "none";
|
|
2851
2943
|
container.style.justifyContent = pos.justifyContent;
|
|
2852
2944
|
container.style.alignItems = pos.alignItems;
|
|
2853
2945
|
container.style.background = pos.background;
|
|
2854
2946
|
if (pos.padding) container.style.padding = pos.padding;
|
|
2947
|
+
let revealed = false;
|
|
2948
|
+
let revealTimer = null;
|
|
2949
|
+
function reveal() {
|
|
2950
|
+
if (revealed) return;
|
|
2951
|
+
revealed = true;
|
|
2952
|
+
if (revealTimer !== null) {
|
|
2953
|
+
clearTimeout(revealTimer);
|
|
2954
|
+
revealTimer = null;
|
|
2955
|
+
}
|
|
2956
|
+
if (!container.contains(popup)) return;
|
|
2957
|
+
container.style.visibility = "visible";
|
|
2958
|
+
container.style.pointerEvents = "";
|
|
2959
|
+
}
|
|
2960
|
+
function revealWhenPainted2() {
|
|
2961
|
+
if (revealed) return;
|
|
2962
|
+
revealWhenPainted(popup, reveal);
|
|
2963
|
+
}
|
|
2964
|
+
revealTimer = setTimeout(reveal, REVEAL_TIMEOUT_MS);
|
|
2855
2965
|
function setLoading(isLoading) {
|
|
2856
2966
|
spinnerEl.style.display = isLoading ? "flex" : "none";
|
|
2857
2967
|
if (!isLoading) {
|
|
2858
2968
|
formHost.style.visibility = "visible";
|
|
2969
|
+
revealWhenPainted2();
|
|
2859
2970
|
}
|
|
2860
2971
|
footer.style.display = isLoading ? "none" : "flex";
|
|
2861
2972
|
backButton.disabled = isLoading;
|
|
@@ -2918,6 +3029,7 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
|
|
|
2918
3029
|
if (s.contentAlign) {
|
|
2919
3030
|
main.style.justifyContent = s.contentAlign === "center" ? "center" : "flex-start";
|
|
2920
3031
|
}
|
|
3032
|
+
applySurveyPrimaryColor(popup, s);
|
|
2921
3033
|
if (s.buttonPrimaryColor) {
|
|
2922
3034
|
submitButton.style.background = s.buttonPrimaryColor;
|
|
2923
3035
|
submitButton.style.border = "none";
|
|
@@ -2999,17 +3111,21 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
|
|
|
2999
3111
|
setLoading(false);
|
|
3000
3112
|
}
|
|
3001
3113
|
}
|
|
3002
|
-
var import_native;
|
|
3114
|
+
var import_native, SURVEY_ALIGNMENT_STYLE_ID;
|
|
3003
3115
|
var init_renderPopup = __esm({
|
|
3004
3116
|
"src/ui/renderPopup.ts"() {
|
|
3005
3117
|
"use strict";
|
|
3006
3118
|
init_tracking_manager();
|
|
3007
3119
|
init_font();
|
|
3008
3120
|
init_logo();
|
|
3121
|
+
init_surveyPalette();
|
|
3009
3122
|
init_logger();
|
|
3010
3123
|
init_labels();
|
|
3124
|
+
init_reveal();
|
|
3011
3125
|
import_native = __toESM(require("@magicfeedback/native"));
|
|
3012
3126
|
init_style();
|
|
3127
|
+
init_reveal();
|
|
3128
|
+
SURVEY_ALIGNMENT_STYLE_ID = "deepdots-survey-alignment";
|
|
3013
3129
|
}
|
|
3014
3130
|
});
|
|
3015
3131
|
|
|
@@ -3220,7 +3336,33 @@ init_tracking_manager();
|
|
|
3220
3336
|
// src/ui/surveyHtml.ts
|
|
3221
3337
|
init_font();
|
|
3222
3338
|
init_labels();
|
|
3339
|
+
init_reveal();
|
|
3340
|
+
init_surveyPalette();
|
|
3223
3341
|
init_style();
|
|
3342
|
+
var REVEAL_JS = `
|
|
3343
|
+
function ddCreateReveal(popup, onReveal, timeoutMs){
|
|
3344
|
+
var revealed=false, timer=null;
|
|
3345
|
+
function reveal(){
|
|
3346
|
+
if(revealed){ return; }
|
|
3347
|
+
revealed=true;
|
|
3348
|
+
if(timer){ clearTimeout(timer); timer=null; }
|
|
3349
|
+
onReveal();
|
|
3350
|
+
}
|
|
3351
|
+
function revealWhenPainted(){
|
|
3352
|
+
if(revealed){ return; }
|
|
3353
|
+
var imgs=popup.querySelectorAll('img'), pending=[];
|
|
3354
|
+
for(var i=0;i<imgs.length;i++){ if(!imgs[i].complete){ pending.push(imgs[i]); } }
|
|
3355
|
+
if(!pending.length){ reveal(); return; }
|
|
3356
|
+
var left=pending.length;
|
|
3357
|
+
function onSettled(){ left--; if(left<=0){ reveal(); } }
|
|
3358
|
+
for(var j=0;j<pending.length;j++){
|
|
3359
|
+
pending[j].addEventListener('load', onSettled);
|
|
3360
|
+
pending[j].addEventListener('error', onSettled);
|
|
3361
|
+
}
|
|
3362
|
+
}
|
|
3363
|
+
timer=setTimeout(reveal, timeoutMs);
|
|
3364
|
+
return { reveal: reveal, whenPainted: revealWhenPainted };
|
|
3365
|
+
}`;
|
|
3224
3366
|
var POSITION_MAP = {
|
|
3225
3367
|
center: { justifyContent: "center", alignItems: "center", padding: "0", background: "rgba(0,0,0,0.5)" },
|
|
3226
3368
|
bottom: { justifyContent: "center", alignItems: "flex-end", padding: "16px", background: "transparent" },
|
|
@@ -3294,7 +3436,13 @@ function buildSurveyHtml(opts) {
|
|
|
3294
3436
|
${style_default}
|
|
3295
3437
|
${fontFaceCss}
|
|
3296
3438
|
html,body{margin:0;padding:0;height:100%;font-family:${fontFamilyValue}}
|
|
3297
|
-
|
|
3439
|
+
/* Apertura diferida: ni la tarjeta ni el velo se pintan hasta que el survey est\xE1 listo
|
|
3440
|
+
(\`dd-ready\`). Si el fondo entrara antes, en RN se ver\xEDa el velo oscuro varios cientos de ms
|
|
3441
|
+
antes que el contenido, que es la misma mala sensaci\xF3n que el spinner. */
|
|
3442
|
+
body{display:${bodyDisplay};justify-content:${pos.justifyContent};align-items:${pos.alignItems};background:transparent;padding:${bodyPadding};box-sizing:border-box}
|
|
3443
|
+
body.dd-ready{background:${bodyBg}}
|
|
3444
|
+
#dd-popup{visibility:hidden}
|
|
3445
|
+
body.dd-ready #dd-popup{visibility:visible}
|
|
3298
3446
|
.deepdots-popup{position:relative;display:flex;flex-direction:column;justify-content:flex-start;background:${cardBg};color-scheme:${colorScheme};border-radius:${cardRadius};padding:24px;box-shadow:${cardShadow};max-width:${cardMaxWidth};width:${cardWidth};min-height:${cardMinHeight};height:${cardHeight};max-height:${cardMaxHeight};box-sizing:border-box}
|
|
3299
3447
|
.deepdots-popup-header{display:flex;justify-content:space-between;align-items:center;gap:12px;width:100%;flex:0 0 auto}
|
|
3300
3448
|
/* Neutraliza la regla \`.deepdots-popup h2\` del CSS del survey (uppercase, centrado y
|
|
@@ -3328,6 +3476,13 @@ body{display:${bodyDisplay};justify-content:${pos.justifyContent};align-items:${
|
|
|
3328
3476
|
#dd-form-wrapper{width:100%;flex:1 1 auto}
|
|
3329
3477
|
#mf{width:100%;box-sizing:border-box;visibility:hidden}
|
|
3330
3478
|
.deepdots-popup-main *{max-width:100%;box-sizing:border-box}
|
|
3479
|
+
/* El margen lateral lo pone la tarjeta: el CSS del survey lo a\xF1ade otra vez en el contenedor, en
|
|
3480
|
+
el formulario y en el bloque de cada pregunta, y eso deja el enunciado y las opciones m\xE1s
|
|
3481
|
+
adentro que el logo, el t\xEDtulo y la barra de progreso. Solo el lateral; el vertical separa las
|
|
3482
|
+
preguntas. Mismas reglas que en el popup DOM (renderPopup.ts). */
|
|
3483
|
+
.deepdots-popup .magicfeedback-container,
|
|
3484
|
+
.deepdots-popup .magicfeedback-form,
|
|
3485
|
+
.deepdots-popup .magicfeedback-div{padding-left:0;padding-right:0}
|
|
3331
3486
|
#dd-logo{max-height:40px;max-width:100%;object-fit:contain;display:block;margin:12px 0 0 0}
|
|
3332
3487
|
.deepdots-error-hint{display:none;margin:12px 0 0 0;padding:10px 12px;border-radius:6px;background:#FEF3C7;color:#92400E;border:1px solid #FCD34D;font-size:13px}
|
|
3333
3488
|
/* Pantalla final: el HTML del editor de la plataforma (imagen + texto), centrado. */
|
|
@@ -3335,7 +3490,7 @@ body{display:${bodyDisplay};justify-content:${pos.justifyContent};align-items:${
|
|
|
3335
3490
|
.deepdots-success img{max-width:100%;height:auto;margin:0 auto 16px auto;display:block}
|
|
3336
3491
|
.deepdots-success p{margin:0;font-size:16px;font-weight:600;line-height:1.4}
|
|
3337
3492
|
.deepdots-popup-footer{display:flex;flex-direction:row-reverse;justify-content:space-between;align-items:center;gap:4px;margin-top:auto;width:100%;padding-top:12px}
|
|
3338
|
-
.dd-nav-btn{display:none;border:none;min-height:44px;padding:12px 24px;border-radius:
|
|
3493
|
+
.dd-nav-btn{display:none;border:none;min-height:44px;padding:12px 24px;border-radius:999px;cursor:pointer;font-size:15px;font-weight:600;align-items:center;justify-content:center;text-align:center}
|
|
3339
3494
|
/* Secundario como bot\xF3n de texto: sin borde ni fondo, para que el primario sea la \xFAnica CTA. */
|
|
3340
3495
|
#dd-back{background:transparent;color:${textMuted};border:none}
|
|
3341
3496
|
#dd-start,#dd-complete,#dd-submit{background:#1E293B;color:#fff;border:none}
|
|
@@ -3560,9 +3715,23 @@ ${customCss}
|
|
|
3560
3715
|
}
|
|
3561
3716
|
}
|
|
3562
3717
|
|
|
3718
|
+
${PRIMARY_COLOR_JS}
|
|
3719
|
+
${REVEAL_JS}
|
|
3720
|
+
// El popup se ense\xF1a cuando el survey est\xE1 pintado; \`ready\` deja al host abrir su propio
|
|
3721
|
+
// Modal en ese momento en vez de montar un WebView en blanco.
|
|
3722
|
+
var ddReveal=ddCreateReveal(popup, function(){
|
|
3723
|
+
document.body.classList.add('dd-ready');
|
|
3724
|
+
emitJSON('ready');
|
|
3725
|
+
}, ${REVEAL_TIMEOUT_MS});
|
|
3726
|
+
|
|
3563
3727
|
function setLoading(isLoading){
|
|
3564
3728
|
spinner.style.display=isLoading?'flex':'none';
|
|
3565
|
-
if(!isLoading){
|
|
3729
|
+
if(!isLoading){
|
|
3730
|
+
formHost.style.visibility='visible';
|
|
3731
|
+
// Fin de la carga, sea por survey cargado o por error. Entre p\xE1ginas es no-op: la
|
|
3732
|
+
// revelaci\xF3n solo act\xFAa la primera vez.
|
|
3733
|
+
ddReveal.whenPainted();
|
|
3734
|
+
}
|
|
3566
3735
|
footer.style.display=isLoading?'none':'flex';
|
|
3567
3736
|
backBtn.disabled=isLoading; startBtn.disabled=isLoading; completeBtn.disabled=isLoading; submitBtn.disabled=isLoading;
|
|
3568
3737
|
if(isLoading){ updateButtons(null); }
|
|
@@ -3605,6 +3774,10 @@ ${customCss}
|
|
|
3605
3774
|
if(s.loadingBarColor){ progressBar.style.background=s.loadingBarColor; progressFollowUp.style.background=s.loadingBarColor; }
|
|
3606
3775
|
if(chromeOn && s.boxBackgroundColor){ popup.style.background=s.boxBackgroundColor; }
|
|
3607
3776
|
if(s.contentAlign){ main.style.justifyContent = s.contentAlign==='center' ? 'center' : 'flex-start'; }
|
|
3777
|
+
// El survey pinta sus controles con --mf-primary, que sale de primaryColor; si la
|
|
3778
|
+
// integraci\xF3n solo configura el del bot\xF3n, el popup mezclar\xEDa el color de la marca
|
|
3779
|
+
// con el gris azulado por defecto del paquete.
|
|
3780
|
+
ddApplySurveyPrimaryColor(popup, s);
|
|
3608
3781
|
if(s.buttonPrimaryColor){
|
|
3609
3782
|
submitBtn.style.background=s.buttonPrimaryColor; submitBtn.style.border='none'; submitBtn.style.color='#fff';
|
|
3610
3783
|
startBtn.style.background=s.buttonPrimaryColor; startBtn.style.border='none'; startBtn.style.color='#fff';
|
|
@@ -3696,7 +3869,9 @@ ${customCss}
|
|
|
3696
3869
|
}
|
|
3697
3870
|
|
|
3698
3871
|
// src/platform/react-native-renderer.ts
|
|
3872
|
+
init_reveal();
|
|
3699
3873
|
init_logger();
|
|
3874
|
+
var NATIVE_READY_GRACE_MS = 500;
|
|
3700
3875
|
var ReactNativePopupRenderer = class {
|
|
3701
3876
|
constructor(options = {}) {
|
|
3702
3877
|
this.options = options;
|
|
@@ -3704,6 +3879,8 @@ var ReactNativePopupRenderer = class {
|
|
|
3704
3879
|
this.onCloseFn = null;
|
|
3705
3880
|
this.currentSurveyId = null;
|
|
3706
3881
|
this.partialEmitted = false;
|
|
3882
|
+
this.readyEmitted = false;
|
|
3883
|
+
this.readyTimer = null;
|
|
3707
3884
|
}
|
|
3708
3885
|
init() {
|
|
3709
3886
|
}
|
|
@@ -3712,6 +3889,8 @@ var ReactNativePopupRenderer = class {
|
|
|
3712
3889
|
this.onCloseFn = onClose;
|
|
3713
3890
|
this.currentSurveyId = surveyId;
|
|
3714
3891
|
this.partialEmitted = false;
|
|
3892
|
+
this.readyEmitted = false;
|
|
3893
|
+
this.armReadyFallback(surveyId);
|
|
3715
3894
|
const { profile, metadata } = buildSurveyIdentity(userId ?? null, sessionId ?? null, miniService ?? null, analyticsFeedbackSessionId ?? null);
|
|
3716
3895
|
const html = buildSurveyHtml({
|
|
3717
3896
|
surveyId,
|
|
@@ -3739,9 +3918,32 @@ var ReactNativePopupRenderer = class {
|
|
|
3739
3918
|
}
|
|
3740
3919
|
}
|
|
3741
3920
|
hide() {
|
|
3921
|
+
this.clearReadyFallback();
|
|
3742
3922
|
this.options.onHide?.();
|
|
3743
3923
|
this.currentSurveyId = null;
|
|
3744
3924
|
}
|
|
3925
|
+
/** Respaldo del aviso de listo por si el WebView no llega a ejecutar el HTML. */
|
|
3926
|
+
armReadyFallback(surveyId) {
|
|
3927
|
+
this.clearReadyFallback();
|
|
3928
|
+
if (!this.options.onReady) return;
|
|
3929
|
+
this.readyTimer = setTimeout(() => {
|
|
3930
|
+
this.readyTimer = null;
|
|
3931
|
+
this.emitReady(surveyId);
|
|
3932
|
+
}, REVEAL_TIMEOUT_MS + NATIVE_READY_GRACE_MS);
|
|
3933
|
+
}
|
|
3934
|
+
clearReadyFallback() {
|
|
3935
|
+
if (this.readyTimer !== null) {
|
|
3936
|
+
clearTimeout(this.readyTimer);
|
|
3937
|
+
this.readyTimer = null;
|
|
3938
|
+
}
|
|
3939
|
+
}
|
|
3940
|
+
/** Idempotente: el WebView puede avisar a la vez que vence el respaldo. */
|
|
3941
|
+
emitReady(surveyId) {
|
|
3942
|
+
if (this.readyEmitted) return;
|
|
3943
|
+
this.readyEmitted = true;
|
|
3944
|
+
this.clearReadyFallback();
|
|
3945
|
+
this.options.onReady?.({ surveyId });
|
|
3946
|
+
}
|
|
3745
3947
|
/**
|
|
3746
3948
|
* El host la conecta al `onMessage` del WebView. Traduce los mensajes del survey a
|
|
3747
3949
|
* eventos del SDK: primera interacción → `popup_clicked` (PARTIAL), completado →
|
|
@@ -3757,6 +3959,9 @@ var ReactNativePopupRenderer = class {
|
|
|
3757
3959
|
name = raw;
|
|
3758
3960
|
}
|
|
3759
3961
|
switch (name) {
|
|
3962
|
+
case "ready":
|
|
3963
|
+
this.emitReady(surveyId);
|
|
3964
|
+
break;
|
|
3760
3965
|
case "loaded":
|
|
3761
3966
|
case "before_submit":
|
|
3762
3967
|
case "after_submit":
|
|
@@ -3784,6 +3989,33 @@ function createReactNativeRenderer() {
|
|
|
3784
3989
|
return new ReactNativePopupRenderer();
|
|
3785
3990
|
}
|
|
3786
3991
|
|
|
3992
|
+
// src/ui/preload.ts
|
|
3993
|
+
var defaultLoader = () => Promise.resolve().then(() => (init_renderPopup(), renderPopup_exports));
|
|
3994
|
+
var pending = null;
|
|
3995
|
+
function preloadRenderPopup(loader = defaultLoader) {
|
|
3996
|
+
if (pending) return pending;
|
|
3997
|
+
try {
|
|
3998
|
+
pending = loader().then(() => void 0).catch(() => {
|
|
3999
|
+
pending = null;
|
|
4000
|
+
});
|
|
4001
|
+
} catch {
|
|
4002
|
+
pending = null;
|
|
4003
|
+
return Promise.resolve();
|
|
4004
|
+
}
|
|
4005
|
+
return pending;
|
|
4006
|
+
}
|
|
4007
|
+
function schedulePreloadRenderPopup(loader) {
|
|
4008
|
+
const run = () => {
|
|
4009
|
+
void preloadRenderPopup(loader);
|
|
4010
|
+
};
|
|
4011
|
+
const idle = globalThis.requestIdleCallback;
|
|
4012
|
+
if (typeof idle === "function") {
|
|
4013
|
+
idle(run, { timeout: 2e3 });
|
|
4014
|
+
return;
|
|
4015
|
+
}
|
|
4016
|
+
setTimeout(run, 0);
|
|
4017
|
+
}
|
|
4018
|
+
|
|
3787
4019
|
// src/platform/renderer.ts
|
|
3788
4020
|
var NoopPopupRenderer = class {
|
|
3789
4021
|
show() {
|
|
@@ -3818,6 +4050,13 @@ var BrowserPopupRenderer = class {
|
|
|
3818
4050
|
document.body.appendChild(this.container);
|
|
3819
4051
|
}
|
|
3820
4052
|
}
|
|
4053
|
+
/**
|
|
4054
|
+
* Descarga el chunk de `renderPopup` antes de que ningún trigger dispare, para que abrir el
|
|
4055
|
+
* popup no empiece por esperar ~238 KB de JS.
|
|
4056
|
+
*/
|
|
4057
|
+
preload() {
|
|
4058
|
+
schedulePreloadRenderPopup();
|
|
4059
|
+
}
|
|
3821
4060
|
show(surveyId, productId, actions, emit, onClose, env = "production", userId, style, sessionId, miniService, analyticsFeedbackSessionId, _renderChrome, options) {
|
|
3822
4061
|
if (this.visible) return;
|
|
3823
4062
|
if (!this.container || !document.body.contains(this.container)) this.init();
|
|
@@ -3832,6 +4071,8 @@ var BrowserPopupRenderer = class {
|
|
|
3832
4071
|
this.visible = false;
|
|
3833
4072
|
if (this.container) {
|
|
3834
4073
|
this.container.style.display = "none";
|
|
4074
|
+
this.container.style.visibility = "";
|
|
4075
|
+
this.container.style.pointerEvents = "";
|
|
3835
4076
|
this.container.innerHTML = "";
|
|
3836
4077
|
}
|
|
3837
4078
|
}
|
|
@@ -4580,6 +4821,75 @@ var CrashReporter = class {
|
|
|
4580
4821
|
}
|
|
4581
4822
|
};
|
|
4582
4823
|
|
|
4824
|
+
// src/core/popup-state-store.ts
|
|
4825
|
+
var POPUP_STATE_STORAGE_KEY = "deepdots.popups.state";
|
|
4826
|
+
var MAX_TRACKED_POPUP_ENTRIES = 200;
|
|
4827
|
+
function emptyState() {
|
|
4828
|
+
return { lastShown: {}, progress: {} };
|
|
4829
|
+
}
|
|
4830
|
+
function isValidTimestamp(value) {
|
|
4831
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
4832
|
+
}
|
|
4833
|
+
function capEntries(entries, timestampOf) {
|
|
4834
|
+
if (entries.length <= MAX_TRACKED_POPUP_ENTRIES) return entries;
|
|
4835
|
+
return [...entries].sort((a, b) => timestampOf(b[1]) - timestampOf(a[1])).slice(0, MAX_TRACKED_POPUP_ENTRIES);
|
|
4836
|
+
}
|
|
4837
|
+
function readPopupState(storage) {
|
|
4838
|
+
let raw = null;
|
|
4839
|
+
try {
|
|
4840
|
+
raw = storage.getItem(POPUP_STATE_STORAGE_KEY);
|
|
4841
|
+
} catch {
|
|
4842
|
+
return emptyState();
|
|
4843
|
+
}
|
|
4844
|
+
if (!raw) return emptyState();
|
|
4845
|
+
let parsed;
|
|
4846
|
+
try {
|
|
4847
|
+
parsed = JSON.parse(raw);
|
|
4848
|
+
} catch {
|
|
4849
|
+
return emptyState();
|
|
4850
|
+
}
|
|
4851
|
+
if (typeof parsed !== "object" || parsed === null) return emptyState();
|
|
4852
|
+
const source = parsed;
|
|
4853
|
+
const state = emptyState();
|
|
4854
|
+
if (typeof source.lastShown === "object" && source.lastShown !== null) {
|
|
4855
|
+
const valid = Object.entries(source.lastShown).filter((entry) => isValidTimestamp(entry[1]));
|
|
4856
|
+
capEntries(valid, (timestamp) => timestamp).forEach(([popupId, timestamp]) => {
|
|
4857
|
+
state.lastShown[popupId] = timestamp;
|
|
4858
|
+
});
|
|
4859
|
+
}
|
|
4860
|
+
if (typeof source.progress === "object" && source.progress !== null) {
|
|
4861
|
+
const valid = Object.entries(source.progress).filter((entry) => {
|
|
4862
|
+
const value = entry[1];
|
|
4863
|
+
if (typeof value !== "object" || value === null) return false;
|
|
4864
|
+
const candidate = value;
|
|
4865
|
+
return POPUP_TRIGGER_CONDITION_STATUSES.includes(candidate.status) && isValidTimestamp(candidate.timestamp);
|
|
4866
|
+
});
|
|
4867
|
+
capEntries(valid, (entry) => entry.timestamp).forEach(([surveyId, entry]) => {
|
|
4868
|
+
state.progress[surveyId] = { status: entry.status, timestamp: entry.timestamp };
|
|
4869
|
+
});
|
|
4870
|
+
}
|
|
4871
|
+
return state;
|
|
4872
|
+
}
|
|
4873
|
+
function writePopupState(storage, state) {
|
|
4874
|
+
const capped = emptyState();
|
|
4875
|
+
capEntries(Object.entries(state.lastShown), (timestamp) => timestamp).forEach(([popupId, timestamp]) => {
|
|
4876
|
+
capped.lastShown[popupId] = timestamp;
|
|
4877
|
+
});
|
|
4878
|
+
capEntries(Object.entries(state.progress), (entry) => entry.timestamp).forEach(([surveyId, entry]) => {
|
|
4879
|
+
capped.progress[surveyId] = entry;
|
|
4880
|
+
});
|
|
4881
|
+
try {
|
|
4882
|
+
storage.setItem(POPUP_STATE_STORAGE_KEY, JSON.stringify(capped));
|
|
4883
|
+
} catch {
|
|
4884
|
+
}
|
|
4885
|
+
}
|
|
4886
|
+
function clearPopupState(storage) {
|
|
4887
|
+
try {
|
|
4888
|
+
storage.removeItem(POPUP_STATE_STORAGE_KEY);
|
|
4889
|
+
} catch {
|
|
4890
|
+
}
|
|
4891
|
+
}
|
|
4892
|
+
|
|
4583
4893
|
// src/core/deepdots-popups.ts
|
|
4584
4894
|
init_logger();
|
|
4585
4895
|
|
|
@@ -4670,6 +4980,10 @@ var DeepdotsPopups = class {
|
|
|
4670
4980
|
this.popupDefinitions = [];
|
|
4671
4981
|
this.popupsLoaded = false;
|
|
4672
4982
|
this.pendingAutoLaunch = false;
|
|
4983
|
+
// Estado que alimenta las reglas de redisplay. Copia de trabajo en memoria; la fuente
|
|
4984
|
+
// duradera es el storage (`popup-state-store`), rehidratada en `init()` — sin eso, una
|
|
4985
|
+
// recarga reiniciaba el cooldown y el popup volvía a salir. `answeredSurveys` se deriva
|
|
4986
|
+
// de las entradas COMPLETED de `surveyProgress` (los dos los escribe `markSurveyAnswered`).
|
|
4673
4987
|
this.answeredSurveys = /* @__PURE__ */ new Set();
|
|
4674
4988
|
this.surveyProgress = /* @__PURE__ */ new Map();
|
|
4675
4989
|
this.lastShown = /* @__PURE__ */ new Map();
|
|
@@ -4745,6 +5059,7 @@ var DeepdotsPopups = class {
|
|
|
4745
5059
|
};
|
|
4746
5060
|
const storage = config.storage ?? createDefaultStorage();
|
|
4747
5061
|
this.storage = storage;
|
|
5062
|
+
this.loadPopupState(storage);
|
|
4748
5063
|
this.tracking = new TrackingManager({
|
|
4749
5064
|
storage,
|
|
4750
5065
|
clientUserId: this.config.userId,
|
|
@@ -4834,6 +5149,7 @@ var DeepdotsPopups = class {
|
|
|
4834
5149
|
this.popupDefinitions = this.validatePopupDefinitions(defs);
|
|
4835
5150
|
this.popupsLoaded = true;
|
|
4836
5151
|
this.log("Popups loaded from API", this.popupDefinitions);
|
|
5152
|
+
if (this.popupDefinitions.length) this.renderer.preload?.();
|
|
4837
5153
|
this.configureTriggersFromDefinitions();
|
|
4838
5154
|
this.processDeferredExitQueue();
|
|
4839
5155
|
if (this.pendingAutoLaunch) {
|
|
@@ -5012,6 +5328,10 @@ var DeepdotsPopups = class {
|
|
|
5012
5328
|
}) : null;
|
|
5013
5329
|
this.analytics?.resetUserScope();
|
|
5014
5330
|
this.messageGuard.reset();
|
|
5331
|
+
this.lastShown.clear();
|
|
5332
|
+
this.surveyProgress.clear();
|
|
5333
|
+
this.answeredSurveys.clear();
|
|
5334
|
+
clearPopupState(storage);
|
|
5015
5335
|
this.log("tracking \xB7 user_change \xB7 user_id:", this.tracking.getUserId());
|
|
5016
5336
|
this.openSession();
|
|
5017
5337
|
}
|
|
@@ -5183,6 +5503,7 @@ var DeepdotsPopups = class {
|
|
|
5183
5503
|
this.log("Showing popup (definition)", def);
|
|
5184
5504
|
this.surveyToPopupId.set(def.surveyId, def.id);
|
|
5185
5505
|
this.lastShown.set(def.id, Date.now());
|
|
5506
|
+
this.persistPopupState();
|
|
5186
5507
|
this.renderPopup(def.surveyId, def.productId, def.actions, def.style, def.title);
|
|
5187
5508
|
this.emitEvent("popup_shown", def.surveyId, { popupId: def.id });
|
|
5188
5509
|
}
|
|
@@ -5316,7 +5637,7 @@ var DeepdotsPopups = class {
|
|
|
5316
5637
|
processDeferredExitQueue() {
|
|
5317
5638
|
const queue = this.getDeferredExitQueue();
|
|
5318
5639
|
if (!queue.length) return;
|
|
5319
|
-
const
|
|
5640
|
+
const pending2 = [];
|
|
5320
5641
|
const now = Date.now();
|
|
5321
5642
|
queue.forEach((item) => {
|
|
5322
5643
|
const def = this.popupDefinitions.find((popup) => popup.id === item.id && popup.surveyId === item.surveyId);
|
|
@@ -5327,10 +5648,10 @@ var DeepdotsPopups = class {
|
|
|
5327
5648
|
this.tryShowDeferredExitPopup(item);
|
|
5328
5649
|
return;
|
|
5329
5650
|
}
|
|
5330
|
-
|
|
5651
|
+
pending2.push(item);
|
|
5331
5652
|
this.scheduleDeferredExitPopup(item);
|
|
5332
5653
|
});
|
|
5333
|
-
this.setDeferredExitQueue(
|
|
5654
|
+
this.setDeferredExitQueue(pending2);
|
|
5334
5655
|
}
|
|
5335
5656
|
scheduleDeferredExitPopup(item) {
|
|
5336
5657
|
if (typeof window === "undefined") return;
|
|
@@ -5403,7 +5724,7 @@ var DeepdotsPopups = class {
|
|
|
5403
5724
|
async fetchPopupsFromServer() {
|
|
5404
5725
|
const apiKey = this.config?.apiKey;
|
|
5405
5726
|
const baseUrl = this.baseUrl;
|
|
5406
|
-
const userId = this.config?.userId;
|
|
5727
|
+
const userId = this.tracking?.getUserId() ?? this.config?.userId;
|
|
5407
5728
|
if (!apiKey || !baseUrl) {
|
|
5408
5729
|
this.log("Missing apiKey or baseUrl. Skipping popups fetch.");
|
|
5409
5730
|
return [];
|
|
@@ -5662,6 +5983,29 @@ var DeepdotsPopups = class {
|
|
|
5662
5983
|
return;
|
|
5663
5984
|
}
|
|
5664
5985
|
this.surveyProgress.set(surveyId, { status, timestamp: Date.now() });
|
|
5986
|
+
this.persistPopupState();
|
|
5987
|
+
}
|
|
5988
|
+
/**
|
|
5989
|
+
* Rehidrata el estado de redisplay desde el storage. `answeredSurveys` se reconstruye
|
|
5990
|
+
* desde las entradas COMPLETED: es exactamente lo que persiste `markSurveyAnswered`.
|
|
5991
|
+
*/
|
|
5992
|
+
loadPopupState(storage) {
|
|
5993
|
+
const state = readPopupState(storage);
|
|
5994
|
+
Object.entries(state.lastShown).forEach(([popupId, timestamp]) => {
|
|
5995
|
+
this.lastShown.set(popupId, timestamp);
|
|
5996
|
+
});
|
|
5997
|
+
Object.entries(state.progress).forEach(([surveyId, entry]) => {
|
|
5998
|
+
this.surveyProgress.set(surveyId, { status: entry.status, timestamp: entry.timestamp });
|
|
5999
|
+
if (entry.status === "COMPLETED") this.answeredSurveys.add(surveyId);
|
|
6000
|
+
});
|
|
6001
|
+
}
|
|
6002
|
+
/** Vuelca el estado de redisplay al storage. Sin storage (o bloqueado) degrada a memoria. */
|
|
6003
|
+
persistPopupState() {
|
|
6004
|
+
if (!this.storage) return;
|
|
6005
|
+
writePopupState(this.storage, {
|
|
6006
|
+
lastShown: Object.fromEntries(this.lastShown),
|
|
6007
|
+
progress: Object.fromEntries(this.surveyProgress)
|
|
6008
|
+
});
|
|
5665
6009
|
}
|
|
5666
6010
|
isPopupDefinition(value) {
|
|
5667
6011
|
if (typeof value !== "object" || value === null) return false;
|
|
@@ -5805,16 +6149,24 @@ function DeepdotsProvider({ config, children }) {
|
|
|
5805
6149
|
}, []);
|
|
5806
6150
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DeepdotsContext.Provider, { value: sdk, children: [
|
|
5807
6151
|
children,
|
|
5808
|
-
survey ?
|
|
5809
|
-
|
|
5810
|
-
|
|
5811
|
-
|
|
5812
|
-
|
|
5813
|
-
|
|
5814
|
-
|
|
5815
|
-
|
|
5816
|
-
|
|
5817
|
-
|
|
6152
|
+
survey ? (
|
|
6153
|
+
// El Modal se abre en cuanto hay popup, y es el HTML del WebView el que se revela solo
|
|
6154
|
+
// cuando el survey está pintado (apertura diferida): con el Modal transparente, hasta ese
|
|
6155
|
+
// momento no se ve nada, ni velo ni spinner. No se difiere el Modal con `onReady` porque
|
|
6156
|
+
// React Native no monta los hijos de un Modal cerrado: el WebView no llegaría a cargar y
|
|
6157
|
+
// el aviso no llegaría nunca. El host que quiera diferir su contenedor debe montar el
|
|
6158
|
+
// WebView invisible (ver el ejemplo de `ReactNativePopupRenderer`).
|
|
6159
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.Modal, { visible: true, transparent: true, animationType: "slide", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.View, { style: { flex: 1 }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
6160
|
+
import_react_native_webview.WebView,
|
|
6161
|
+
{
|
|
6162
|
+
style: { flex: 1 },
|
|
6163
|
+
originWhitelist: ["*"],
|
|
6164
|
+
javaScriptEnabled: true,
|
|
6165
|
+
source: { html: survey.html, baseUrl: "https://sdk.deepdots.com/" },
|
|
6166
|
+
onMessage: (e) => rendererRef.current?.handleMessage(e.nativeEvent.data)
|
|
6167
|
+
}
|
|
6168
|
+
) }) })
|
|
6169
|
+
) : null
|
|
5818
6170
|
] });
|
|
5819
6171
|
}
|
|
5820
6172
|
//# sourceMappingURL=react-native.js.map
|