@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/index.js
CHANGED
|
@@ -466,6 +466,82 @@ var init_labels = __esm({
|
|
|
466
466
|
}
|
|
467
467
|
});
|
|
468
468
|
|
|
469
|
+
// src/ui/reveal.ts
|
|
470
|
+
function revealWhenPainted(root, reveal) {
|
|
471
|
+
const pending2 = Array.from(root.querySelectorAll("img")).filter((img) => !img.complete);
|
|
472
|
+
if (!pending2.length) {
|
|
473
|
+
reveal();
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
let left = pending2.length;
|
|
477
|
+
const onSettled = () => {
|
|
478
|
+
left -= 1;
|
|
479
|
+
if (left <= 0) reveal();
|
|
480
|
+
};
|
|
481
|
+
pending2.forEach((img) => {
|
|
482
|
+
img.addEventListener("load", onSettled, { once: true });
|
|
483
|
+
img.addEventListener("error", onSettled, { once: true });
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
var REVEAL_TIMEOUT_MS;
|
|
487
|
+
var init_reveal = __esm({
|
|
488
|
+
"src/ui/reveal.ts"() {
|
|
489
|
+
"use strict";
|
|
490
|
+
REVEAL_TIMEOUT_MS = 1200;
|
|
491
|
+
}
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
// src/ui/surveyPalette.ts
|
|
495
|
+
function resolveSurveyPrimaryColor(style) {
|
|
496
|
+
for (const candidate of [style?.primaryColor, style?.buttonPrimaryColor]) {
|
|
497
|
+
const value = (candidate ?? "").trim();
|
|
498
|
+
if (HEX_COLOR.test(value)) return value;
|
|
499
|
+
}
|
|
500
|
+
return null;
|
|
501
|
+
}
|
|
502
|
+
function surveyPrimaryVars(color) {
|
|
503
|
+
return [
|
|
504
|
+
["--mf-primary", color],
|
|
505
|
+
["--mf-primary-hover", `color-mix(in srgb, ${color} 85%, black)`],
|
|
506
|
+
["--mf-primary-light", `color-mix(in srgb, ${color} 15%, white)`],
|
|
507
|
+
["--mf-primary-border", `color-mix(in srgb, ${color} 35%, transparent)`],
|
|
508
|
+
["--mf-border-focus", color]
|
|
509
|
+
];
|
|
510
|
+
}
|
|
511
|
+
function applySurveyPrimaryColor(el, style) {
|
|
512
|
+
const color = resolveSurveyPrimaryColor(style);
|
|
513
|
+
if (!color) return;
|
|
514
|
+
for (const [name, value] of surveyPrimaryVars(color)) {
|
|
515
|
+
el.style.setProperty(name, value);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
var HEX_COLOR, PRIMARY_COLOR_JS;
|
|
519
|
+
var init_surveyPalette = __esm({
|
|
520
|
+
"src/ui/surveyPalette.ts"() {
|
|
521
|
+
"use strict";
|
|
522
|
+
HEX_COLOR = /^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;
|
|
523
|
+
PRIMARY_COLOR_JS = `
|
|
524
|
+
function ddResolveSurveyPrimaryColor(style){
|
|
525
|
+
var hex=/^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;
|
|
526
|
+
var candidates=[style&&style.primaryColor, style&&style.buttonPrimaryColor];
|
|
527
|
+
for(var i=0;i<candidates.length;i++){
|
|
528
|
+
var value=(candidates[i]||'').trim();
|
|
529
|
+
if(hex.test(value)){ return value; }
|
|
530
|
+
}
|
|
531
|
+
return null;
|
|
532
|
+
}
|
|
533
|
+
function ddApplySurveyPrimaryColor(el, style){
|
|
534
|
+
var color=ddResolveSurveyPrimaryColor(style);
|
|
535
|
+
if(!color||!el){ return; }
|
|
536
|
+
el.style.setProperty('--mf-primary', color);
|
|
537
|
+
el.style.setProperty('--mf-primary-hover', 'color-mix(in srgb, '+color+' 85%, black)');
|
|
538
|
+
el.style.setProperty('--mf-primary-light', 'color-mix(in srgb, '+color+' 15%, white)');
|
|
539
|
+
el.style.setProperty('--mf-primary-border', 'color-mix(in srgb, '+color+' 35%, transparent)');
|
|
540
|
+
el.style.setProperty('--mf-border-focus', color);
|
|
541
|
+
}`;
|
|
542
|
+
}
|
|
543
|
+
});
|
|
544
|
+
|
|
469
545
|
// src/assets/style.css
|
|
470
546
|
var style_default;
|
|
471
547
|
var init_style = __esm({
|
|
@@ -2355,9 +2431,9 @@ var init_logo = __esm({
|
|
|
2355
2431
|
}
|
|
2356
2432
|
});
|
|
2357
2433
|
|
|
2358
|
-
// node_modules/@magicfeedback/native/dist/magicfeedback-sdk.browser.js
|
|
2434
|
+
// ../deepdots-popup-sdk/node_modules/@magicfeedback/native/dist/magicfeedback-sdk.browser.js
|
|
2359
2435
|
var require_magicfeedback_sdk_browser = __commonJS({
|
|
2360
|
-
"node_modules/@magicfeedback/native/dist/magicfeedback-sdk.browser.js"(exports, module2) {
|
|
2436
|
+
"../deepdots-popup-sdk/node_modules/@magicfeedback/native/dist/magicfeedback-sdk.browser.js"(exports, module2) {
|
|
2361
2437
|
"use strict";
|
|
2362
2438
|
!(function(e, t) {
|
|
2363
2439
|
"object" == typeof exports && "object" == typeof module2 ? module2.exports = t() : "function" == typeof define && define.amd ? define([], t) : "object" == typeof exports ? exports.magicfeedback = t() : e.magicfeedback = t();
|
|
@@ -4755,6 +4831,8 @@ var require_magicfeedback_sdk_browser = __commonJS({
|
|
|
4755
4831
|
// src/ui/renderPopup.ts
|
|
4756
4832
|
var renderPopup_exports = {};
|
|
4757
4833
|
__export(renderPopup_exports, {
|
|
4834
|
+
REVEAL_TIMEOUT_MS: () => REVEAL_TIMEOUT_MS,
|
|
4835
|
+
SURVEY_ALIGNMENT_STYLE_ID: () => SURVEY_ALIGNMENT_STYLE_ID,
|
|
4758
4836
|
renderPopup: () => renderPopup
|
|
4759
4837
|
});
|
|
4760
4838
|
function ensureMagicFeedbackStyles(_popup) {
|
|
@@ -4765,6 +4843,17 @@ function ensureMagicFeedbackStyles(_popup) {
|
|
|
4765
4843
|
style.textContent = style_default;
|
|
4766
4844
|
document.head.appendChild(style);
|
|
4767
4845
|
}
|
|
4846
|
+
function ensureSurveyAlignmentStyles() {
|
|
4847
|
+
if (document.getElementById(SURVEY_ALIGNMENT_STYLE_ID)) return;
|
|
4848
|
+
const style = document.createElement("style");
|
|
4849
|
+
style.id = SURVEY_ALIGNMENT_STYLE_ID;
|
|
4850
|
+
style.textContent = `
|
|
4851
|
+
.deepdots-popup .magicfeedback-container,
|
|
4852
|
+
.deepdots-popup .magicfeedback-form,
|
|
4853
|
+
.deepdots-popup .magicfeedback-div { padding-left: 0; padding-right: 0; }
|
|
4854
|
+
`;
|
|
4855
|
+
document.head.appendChild(style);
|
|
4856
|
+
}
|
|
4768
4857
|
function ensureSpinnerStyles(_popup) {
|
|
4769
4858
|
if (document.getElementById("deepdots-spinner-styles")) return;
|
|
4770
4859
|
const style = document.createElement("style");
|
|
@@ -5017,6 +5106,7 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
|
|
|
5017
5106
|
progressFollowUp.style.display = p.followup ? "inline-block" : "none";
|
|
5018
5107
|
}
|
|
5019
5108
|
ensureMagicFeedbackStyles(popup);
|
|
5109
|
+
ensureSurveyAlignmentStyles();
|
|
5020
5110
|
ensureSpinnerStyles(popup);
|
|
5021
5111
|
ensureResponsiveStyles(popup);
|
|
5022
5112
|
ensureCustomCss(options?.surveyCss);
|
|
@@ -5075,7 +5165,7 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
|
|
|
5075
5165
|
border: none;
|
|
5076
5166
|
min-height: 44px;
|
|
5077
5167
|
padding: 12px 24px;
|
|
5078
|
-
border-radius:
|
|
5168
|
+
border-radius: 999px; /* p\xEDldora, como el Button de Material3 en KMP */
|
|
5079
5169
|
cursor: pointer;
|
|
5080
5170
|
font-size: 15px;
|
|
5081
5171
|
font-weight: 600;
|
|
@@ -5105,7 +5195,7 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
|
|
|
5105
5195
|
border: none;
|
|
5106
5196
|
min-height: 44px;
|
|
5107
5197
|
padding: 12px 24px;
|
|
5108
|
-
border-radius:
|
|
5198
|
+
border-radius: 999px; /* p\xEDldora, como el Button de Material3 en KMP */
|
|
5109
5199
|
cursor: pointer;
|
|
5110
5200
|
font-size: 15px;
|
|
5111
5201
|
font-weight: 600;
|
|
@@ -5132,7 +5222,7 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
|
|
|
5132
5222
|
border: none;
|
|
5133
5223
|
min-height: 44px;
|
|
5134
5224
|
padding: 12px 24px;
|
|
5135
|
-
border-radius:
|
|
5225
|
+
border-radius: 999px; /* p\xEDldora, como el Button de Material3 en KMP */
|
|
5136
5226
|
cursor: pointer;
|
|
5137
5227
|
font-size: 15px;
|
|
5138
5228
|
font-weight: 600;
|
|
@@ -5163,7 +5253,7 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
|
|
|
5163
5253
|
border: none;
|
|
5164
5254
|
min-height: 44px;
|
|
5165
5255
|
padding: 12px 24px;
|
|
5166
|
-
border-radius:
|
|
5256
|
+
border-radius: 999px; /* p\xEDldora, como el Button de Material3 en KMP */
|
|
5167
5257
|
cursor: pointer;
|
|
5168
5258
|
font-size: 15px;
|
|
5169
5259
|
font-weight: 600;
|
|
@@ -5265,14 +5355,35 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
|
|
|
5265
5355
|
container.innerHTML = "";
|
|
5266
5356
|
container.appendChild(popup);
|
|
5267
5357
|
container.style.display = "flex";
|
|
5358
|
+
container.style.visibility = "hidden";
|
|
5359
|
+
container.style.pointerEvents = "none";
|
|
5268
5360
|
container.style.justifyContent = pos.justifyContent;
|
|
5269
5361
|
container.style.alignItems = pos.alignItems;
|
|
5270
5362
|
container.style.background = pos.background;
|
|
5271
5363
|
if (pos.padding) container.style.padding = pos.padding;
|
|
5364
|
+
let revealed = false;
|
|
5365
|
+
let revealTimer = null;
|
|
5366
|
+
function reveal() {
|
|
5367
|
+
if (revealed) return;
|
|
5368
|
+
revealed = true;
|
|
5369
|
+
if (revealTimer !== null) {
|
|
5370
|
+
clearTimeout(revealTimer);
|
|
5371
|
+
revealTimer = null;
|
|
5372
|
+
}
|
|
5373
|
+
if (!container.contains(popup)) return;
|
|
5374
|
+
container.style.visibility = "visible";
|
|
5375
|
+
container.style.pointerEvents = "";
|
|
5376
|
+
}
|
|
5377
|
+
function revealWhenPainted2() {
|
|
5378
|
+
if (revealed) return;
|
|
5379
|
+
revealWhenPainted(popup, reveal);
|
|
5380
|
+
}
|
|
5381
|
+
revealTimer = setTimeout(reveal, REVEAL_TIMEOUT_MS);
|
|
5272
5382
|
function setLoading(isLoading) {
|
|
5273
5383
|
spinnerEl.style.display = isLoading ? "flex" : "none";
|
|
5274
5384
|
if (!isLoading) {
|
|
5275
5385
|
formHost.style.visibility = "visible";
|
|
5386
|
+
revealWhenPainted2();
|
|
5276
5387
|
}
|
|
5277
5388
|
footer.style.display = isLoading ? "none" : "flex";
|
|
5278
5389
|
backButton.disabled = isLoading;
|
|
@@ -5335,6 +5446,7 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
|
|
|
5335
5446
|
if (s.contentAlign) {
|
|
5336
5447
|
main.style.justifyContent = s.contentAlign === "center" ? "center" : "flex-start";
|
|
5337
5448
|
}
|
|
5449
|
+
applySurveyPrimaryColor(popup, s);
|
|
5338
5450
|
if (s.buttonPrimaryColor) {
|
|
5339
5451
|
submitButton.style.background = s.buttonPrimaryColor;
|
|
5340
5452
|
submitButton.style.border = "none";
|
|
@@ -5416,17 +5528,21 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
|
|
|
5416
5528
|
setLoading(false);
|
|
5417
5529
|
}
|
|
5418
5530
|
}
|
|
5419
|
-
var import_native;
|
|
5531
|
+
var import_native, SURVEY_ALIGNMENT_STYLE_ID;
|
|
5420
5532
|
var init_renderPopup = __esm({
|
|
5421
5533
|
"src/ui/renderPopup.ts"() {
|
|
5422
5534
|
"use strict";
|
|
5423
5535
|
init_tracking_manager();
|
|
5424
5536
|
init_font();
|
|
5425
5537
|
init_logo();
|
|
5538
|
+
init_surveyPalette();
|
|
5426
5539
|
init_logger();
|
|
5427
5540
|
init_labels();
|
|
5541
|
+
init_reveal();
|
|
5428
5542
|
import_native = __toESM(require_magicfeedback_sdk_browser());
|
|
5429
5543
|
init_style();
|
|
5544
|
+
init_reveal();
|
|
5545
|
+
SURVEY_ALIGNMENT_STYLE_ID = "deepdots-survey-alignment";
|
|
5430
5546
|
}
|
|
5431
5547
|
});
|
|
5432
5548
|
|
|
@@ -5442,8 +5558,10 @@ __export(index_exports, {
|
|
|
5442
5558
|
MAX_TRACKED_MESSAGES: () => MAX_TRACKED_MESSAGES,
|
|
5443
5559
|
MESSAGE_CHANNELS: () => MESSAGE_CHANNELS,
|
|
5444
5560
|
MessageGuard: () => MessageGuard,
|
|
5561
|
+
NATIVE_READY_GRACE_MS: () => NATIVE_READY_GRACE_MS,
|
|
5445
5562
|
NoopPopupRenderer: () => NoopPopupRenderer,
|
|
5446
5563
|
POPUP_TRIGGER_CONDITION_STATUSES: () => POPUP_TRIGGER_CONDITION_STATUSES,
|
|
5564
|
+
REVEAL_TIMEOUT_MS: () => REVEAL_TIMEOUT_MS,
|
|
5447
5565
|
RTL_LOCALES: () => RTL_LOCALES,
|
|
5448
5566
|
ReactNativePopupRenderer: () => ReactNativePopupRenderer,
|
|
5449
5567
|
SUPPORTED_LANGUAGES: () => SUPPORTED_LANGUAGES,
|
|
@@ -5658,7 +5776,33 @@ init_tracking_manager();
|
|
|
5658
5776
|
// src/ui/surveyHtml.ts
|
|
5659
5777
|
init_font();
|
|
5660
5778
|
init_labels();
|
|
5779
|
+
init_reveal();
|
|
5780
|
+
init_surveyPalette();
|
|
5661
5781
|
init_style();
|
|
5782
|
+
var REVEAL_JS = `
|
|
5783
|
+
function ddCreateReveal(popup, onReveal, timeoutMs){
|
|
5784
|
+
var revealed=false, timer=null;
|
|
5785
|
+
function reveal(){
|
|
5786
|
+
if(revealed){ return; }
|
|
5787
|
+
revealed=true;
|
|
5788
|
+
if(timer){ clearTimeout(timer); timer=null; }
|
|
5789
|
+
onReveal();
|
|
5790
|
+
}
|
|
5791
|
+
function revealWhenPainted(){
|
|
5792
|
+
if(revealed){ return; }
|
|
5793
|
+
var imgs=popup.querySelectorAll('img'), pending=[];
|
|
5794
|
+
for(var i=0;i<imgs.length;i++){ if(!imgs[i].complete){ pending.push(imgs[i]); } }
|
|
5795
|
+
if(!pending.length){ reveal(); return; }
|
|
5796
|
+
var left=pending.length;
|
|
5797
|
+
function onSettled(){ left--; if(left<=0){ reveal(); } }
|
|
5798
|
+
for(var j=0;j<pending.length;j++){
|
|
5799
|
+
pending[j].addEventListener('load', onSettled);
|
|
5800
|
+
pending[j].addEventListener('error', onSettled);
|
|
5801
|
+
}
|
|
5802
|
+
}
|
|
5803
|
+
timer=setTimeout(reveal, timeoutMs);
|
|
5804
|
+
return { reveal: reveal, whenPainted: revealWhenPainted };
|
|
5805
|
+
}`;
|
|
5662
5806
|
var POSITION_MAP = {
|
|
5663
5807
|
center: { justifyContent: "center", alignItems: "center", padding: "0", background: "rgba(0,0,0,0.5)" },
|
|
5664
5808
|
bottom: { justifyContent: "center", alignItems: "flex-end", padding: "16px", background: "transparent" },
|
|
@@ -5732,7 +5876,13 @@ function buildSurveyHtml(opts) {
|
|
|
5732
5876
|
${style_default}
|
|
5733
5877
|
${fontFaceCss}
|
|
5734
5878
|
html,body{margin:0;padding:0;height:100%;font-family:${fontFamilyValue}}
|
|
5735
|
-
|
|
5879
|
+
/* Apertura diferida: ni la tarjeta ni el velo se pintan hasta que el survey est\xE1 listo
|
|
5880
|
+
(\`dd-ready\`). Si el fondo entrara antes, en RN se ver\xEDa el velo oscuro varios cientos de ms
|
|
5881
|
+
antes que el contenido, que es la misma mala sensaci\xF3n que el spinner. */
|
|
5882
|
+
body{display:${bodyDisplay};justify-content:${pos.justifyContent};align-items:${pos.alignItems};background:transparent;padding:${bodyPadding};box-sizing:border-box}
|
|
5883
|
+
body.dd-ready{background:${bodyBg}}
|
|
5884
|
+
#dd-popup{visibility:hidden}
|
|
5885
|
+
body.dd-ready #dd-popup{visibility:visible}
|
|
5736
5886
|
.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}
|
|
5737
5887
|
.deepdots-popup-header{display:flex;justify-content:space-between;align-items:center;gap:12px;width:100%;flex:0 0 auto}
|
|
5738
5888
|
/* Neutraliza la regla \`.deepdots-popup h2\` del CSS del survey (uppercase, centrado y
|
|
@@ -5766,6 +5916,13 @@ body{display:${bodyDisplay};justify-content:${pos.justifyContent};align-items:${
|
|
|
5766
5916
|
#dd-form-wrapper{width:100%;flex:1 1 auto}
|
|
5767
5917
|
#mf{width:100%;box-sizing:border-box;visibility:hidden}
|
|
5768
5918
|
.deepdots-popup-main *{max-width:100%;box-sizing:border-box}
|
|
5919
|
+
/* El margen lateral lo pone la tarjeta: el CSS del survey lo a\xF1ade otra vez en el contenedor, en
|
|
5920
|
+
el formulario y en el bloque de cada pregunta, y eso deja el enunciado y las opciones m\xE1s
|
|
5921
|
+
adentro que el logo, el t\xEDtulo y la barra de progreso. Solo el lateral; el vertical separa las
|
|
5922
|
+
preguntas. Mismas reglas que en el popup DOM (renderPopup.ts). */
|
|
5923
|
+
.deepdots-popup .magicfeedback-container,
|
|
5924
|
+
.deepdots-popup .magicfeedback-form,
|
|
5925
|
+
.deepdots-popup .magicfeedback-div{padding-left:0;padding-right:0}
|
|
5769
5926
|
#dd-logo{max-height:40px;max-width:100%;object-fit:contain;display:block;margin:12px 0 0 0}
|
|
5770
5927
|
.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}
|
|
5771
5928
|
/* Pantalla final: el HTML del editor de la plataforma (imagen + texto), centrado. */
|
|
@@ -5773,7 +5930,7 @@ body{display:${bodyDisplay};justify-content:${pos.justifyContent};align-items:${
|
|
|
5773
5930
|
.deepdots-success img{max-width:100%;height:auto;margin:0 auto 16px auto;display:block}
|
|
5774
5931
|
.deepdots-success p{margin:0;font-size:16px;font-weight:600;line-height:1.4}
|
|
5775
5932
|
.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}
|
|
5776
|
-
.dd-nav-btn{display:none;border:none;min-height:44px;padding:12px 24px;border-radius:
|
|
5933
|
+
.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}
|
|
5777
5934
|
/* Secundario como bot\xF3n de texto: sin borde ni fondo, para que el primario sea la \xFAnica CTA. */
|
|
5778
5935
|
#dd-back{background:transparent;color:${textMuted};border:none}
|
|
5779
5936
|
#dd-start,#dd-complete,#dd-submit{background:#1E293B;color:#fff;border:none}
|
|
@@ -5998,9 +6155,23 @@ ${customCss}
|
|
|
5998
6155
|
}
|
|
5999
6156
|
}
|
|
6000
6157
|
|
|
6158
|
+
${PRIMARY_COLOR_JS}
|
|
6159
|
+
${REVEAL_JS}
|
|
6160
|
+
// El popup se ense\xF1a cuando el survey est\xE1 pintado; \`ready\` deja al host abrir su propio
|
|
6161
|
+
// Modal en ese momento en vez de montar un WebView en blanco.
|
|
6162
|
+
var ddReveal=ddCreateReveal(popup, function(){
|
|
6163
|
+
document.body.classList.add('dd-ready');
|
|
6164
|
+
emitJSON('ready');
|
|
6165
|
+
}, ${REVEAL_TIMEOUT_MS});
|
|
6166
|
+
|
|
6001
6167
|
function setLoading(isLoading){
|
|
6002
6168
|
spinner.style.display=isLoading?'flex':'none';
|
|
6003
|
-
if(!isLoading){
|
|
6169
|
+
if(!isLoading){
|
|
6170
|
+
formHost.style.visibility='visible';
|
|
6171
|
+
// Fin de la carga, sea por survey cargado o por error. Entre p\xE1ginas es no-op: la
|
|
6172
|
+
// revelaci\xF3n solo act\xFAa la primera vez.
|
|
6173
|
+
ddReveal.whenPainted();
|
|
6174
|
+
}
|
|
6004
6175
|
footer.style.display=isLoading?'none':'flex';
|
|
6005
6176
|
backBtn.disabled=isLoading; startBtn.disabled=isLoading; completeBtn.disabled=isLoading; submitBtn.disabled=isLoading;
|
|
6006
6177
|
if(isLoading){ updateButtons(null); }
|
|
@@ -6043,6 +6214,10 @@ ${customCss}
|
|
|
6043
6214
|
if(s.loadingBarColor){ progressBar.style.background=s.loadingBarColor; progressFollowUp.style.background=s.loadingBarColor; }
|
|
6044
6215
|
if(chromeOn && s.boxBackgroundColor){ popup.style.background=s.boxBackgroundColor; }
|
|
6045
6216
|
if(s.contentAlign){ main.style.justifyContent = s.contentAlign==='center' ? 'center' : 'flex-start'; }
|
|
6217
|
+
// El survey pinta sus controles con --mf-primary, que sale de primaryColor; si la
|
|
6218
|
+
// integraci\xF3n solo configura el del bot\xF3n, el popup mezclar\xEDa el color de la marca
|
|
6219
|
+
// con el gris azulado por defecto del paquete.
|
|
6220
|
+
ddApplySurveyPrimaryColor(popup, s);
|
|
6046
6221
|
if(s.buttonPrimaryColor){
|
|
6047
6222
|
submitBtn.style.background=s.buttonPrimaryColor; submitBtn.style.border='none'; submitBtn.style.color='#fff';
|
|
6048
6223
|
startBtn.style.background=s.buttonPrimaryColor; startBtn.style.border='none'; startBtn.style.color='#fff';
|
|
@@ -6134,7 +6309,9 @@ ${customCss}
|
|
|
6134
6309
|
}
|
|
6135
6310
|
|
|
6136
6311
|
// src/platform/react-native-renderer.ts
|
|
6312
|
+
init_reveal();
|
|
6137
6313
|
init_logger();
|
|
6314
|
+
var NATIVE_READY_GRACE_MS = 500;
|
|
6138
6315
|
var ReactNativePopupRenderer = class {
|
|
6139
6316
|
constructor(options = {}) {
|
|
6140
6317
|
this.options = options;
|
|
@@ -6142,6 +6319,8 @@ var ReactNativePopupRenderer = class {
|
|
|
6142
6319
|
this.onCloseFn = null;
|
|
6143
6320
|
this.currentSurveyId = null;
|
|
6144
6321
|
this.partialEmitted = false;
|
|
6322
|
+
this.readyEmitted = false;
|
|
6323
|
+
this.readyTimer = null;
|
|
6145
6324
|
}
|
|
6146
6325
|
init() {
|
|
6147
6326
|
}
|
|
@@ -6150,6 +6329,8 @@ var ReactNativePopupRenderer = class {
|
|
|
6150
6329
|
this.onCloseFn = onClose;
|
|
6151
6330
|
this.currentSurveyId = surveyId;
|
|
6152
6331
|
this.partialEmitted = false;
|
|
6332
|
+
this.readyEmitted = false;
|
|
6333
|
+
this.armReadyFallback(surveyId);
|
|
6153
6334
|
const { profile, metadata } = buildSurveyIdentity(userId ?? null, sessionId ?? null, miniService ?? null, analyticsFeedbackSessionId ?? null);
|
|
6154
6335
|
const html = buildSurveyHtml({
|
|
6155
6336
|
surveyId,
|
|
@@ -6177,9 +6358,32 @@ var ReactNativePopupRenderer = class {
|
|
|
6177
6358
|
}
|
|
6178
6359
|
}
|
|
6179
6360
|
hide() {
|
|
6361
|
+
this.clearReadyFallback();
|
|
6180
6362
|
this.options.onHide?.();
|
|
6181
6363
|
this.currentSurveyId = null;
|
|
6182
6364
|
}
|
|
6365
|
+
/** Respaldo del aviso de listo por si el WebView no llega a ejecutar el HTML. */
|
|
6366
|
+
armReadyFallback(surveyId) {
|
|
6367
|
+
this.clearReadyFallback();
|
|
6368
|
+
if (!this.options.onReady) return;
|
|
6369
|
+
this.readyTimer = setTimeout(() => {
|
|
6370
|
+
this.readyTimer = null;
|
|
6371
|
+
this.emitReady(surveyId);
|
|
6372
|
+
}, REVEAL_TIMEOUT_MS + NATIVE_READY_GRACE_MS);
|
|
6373
|
+
}
|
|
6374
|
+
clearReadyFallback() {
|
|
6375
|
+
if (this.readyTimer !== null) {
|
|
6376
|
+
clearTimeout(this.readyTimer);
|
|
6377
|
+
this.readyTimer = null;
|
|
6378
|
+
}
|
|
6379
|
+
}
|
|
6380
|
+
/** Idempotente: el WebView puede avisar a la vez que vence el respaldo. */
|
|
6381
|
+
emitReady(surveyId) {
|
|
6382
|
+
if (this.readyEmitted) return;
|
|
6383
|
+
this.readyEmitted = true;
|
|
6384
|
+
this.clearReadyFallback();
|
|
6385
|
+
this.options.onReady?.({ surveyId });
|
|
6386
|
+
}
|
|
6183
6387
|
/**
|
|
6184
6388
|
* El host la conecta al `onMessage` del WebView. Traduce los mensajes del survey a
|
|
6185
6389
|
* eventos del SDK: primera interacción → `popup_clicked` (PARTIAL), completado →
|
|
@@ -6195,6 +6399,9 @@ var ReactNativePopupRenderer = class {
|
|
|
6195
6399
|
name = raw;
|
|
6196
6400
|
}
|
|
6197
6401
|
switch (name) {
|
|
6402
|
+
case "ready":
|
|
6403
|
+
this.emitReady(surveyId);
|
|
6404
|
+
break;
|
|
6198
6405
|
case "loaded":
|
|
6199
6406
|
case "before_submit":
|
|
6200
6407
|
case "after_submit":
|
|
@@ -6222,6 +6429,33 @@ function createReactNativeRenderer() {
|
|
|
6222
6429
|
return new ReactNativePopupRenderer();
|
|
6223
6430
|
}
|
|
6224
6431
|
|
|
6432
|
+
// src/ui/preload.ts
|
|
6433
|
+
var defaultLoader = () => Promise.resolve().then(() => (init_renderPopup(), renderPopup_exports));
|
|
6434
|
+
var pending = null;
|
|
6435
|
+
function preloadRenderPopup(loader = defaultLoader) {
|
|
6436
|
+
if (pending) return pending;
|
|
6437
|
+
try {
|
|
6438
|
+
pending = loader().then(() => void 0).catch(() => {
|
|
6439
|
+
pending = null;
|
|
6440
|
+
});
|
|
6441
|
+
} catch {
|
|
6442
|
+
pending = null;
|
|
6443
|
+
return Promise.resolve();
|
|
6444
|
+
}
|
|
6445
|
+
return pending;
|
|
6446
|
+
}
|
|
6447
|
+
function schedulePreloadRenderPopup(loader) {
|
|
6448
|
+
const run = () => {
|
|
6449
|
+
void preloadRenderPopup(loader);
|
|
6450
|
+
};
|
|
6451
|
+
const idle = globalThis.requestIdleCallback;
|
|
6452
|
+
if (typeof idle === "function") {
|
|
6453
|
+
idle(run, { timeout: 2e3 });
|
|
6454
|
+
return;
|
|
6455
|
+
}
|
|
6456
|
+
setTimeout(run, 0);
|
|
6457
|
+
}
|
|
6458
|
+
|
|
6225
6459
|
// src/platform/renderer.ts
|
|
6226
6460
|
var NoopPopupRenderer = class {
|
|
6227
6461
|
show() {
|
|
@@ -6256,6 +6490,13 @@ var BrowserPopupRenderer = class {
|
|
|
6256
6490
|
document.body.appendChild(this.container);
|
|
6257
6491
|
}
|
|
6258
6492
|
}
|
|
6493
|
+
/**
|
|
6494
|
+
* Descarga el chunk de `renderPopup` antes de que ningún trigger dispare, para que abrir el
|
|
6495
|
+
* popup no empiece por esperar ~238 KB de JS.
|
|
6496
|
+
*/
|
|
6497
|
+
preload() {
|
|
6498
|
+
schedulePreloadRenderPopup();
|
|
6499
|
+
}
|
|
6259
6500
|
show(surveyId, productId, actions, emit, onClose, env = "production", userId, style, sessionId, miniService, analyticsFeedbackSessionId, _renderChrome, options) {
|
|
6260
6501
|
if (this.visible) return;
|
|
6261
6502
|
if (!this.container || !document.body.contains(this.container)) this.init();
|
|
@@ -6270,6 +6511,8 @@ var BrowserPopupRenderer = class {
|
|
|
6270
6511
|
this.visible = false;
|
|
6271
6512
|
if (this.container) {
|
|
6272
6513
|
this.container.style.display = "none";
|
|
6514
|
+
this.container.style.visibility = "";
|
|
6515
|
+
this.container.style.pointerEvents = "";
|
|
6273
6516
|
this.container.innerHTML = "";
|
|
6274
6517
|
}
|
|
6275
6518
|
}
|
|
@@ -7018,6 +7261,75 @@ var CrashReporter = class {
|
|
|
7018
7261
|
}
|
|
7019
7262
|
};
|
|
7020
7263
|
|
|
7264
|
+
// src/core/popup-state-store.ts
|
|
7265
|
+
var POPUP_STATE_STORAGE_KEY = "deepdots.popups.state";
|
|
7266
|
+
var MAX_TRACKED_POPUP_ENTRIES = 200;
|
|
7267
|
+
function emptyState() {
|
|
7268
|
+
return { lastShown: {}, progress: {} };
|
|
7269
|
+
}
|
|
7270
|
+
function isValidTimestamp(value) {
|
|
7271
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
7272
|
+
}
|
|
7273
|
+
function capEntries(entries, timestampOf) {
|
|
7274
|
+
if (entries.length <= MAX_TRACKED_POPUP_ENTRIES) return entries;
|
|
7275
|
+
return [...entries].sort((a, b) => timestampOf(b[1]) - timestampOf(a[1])).slice(0, MAX_TRACKED_POPUP_ENTRIES);
|
|
7276
|
+
}
|
|
7277
|
+
function readPopupState(storage) {
|
|
7278
|
+
let raw = null;
|
|
7279
|
+
try {
|
|
7280
|
+
raw = storage.getItem(POPUP_STATE_STORAGE_KEY);
|
|
7281
|
+
} catch {
|
|
7282
|
+
return emptyState();
|
|
7283
|
+
}
|
|
7284
|
+
if (!raw) return emptyState();
|
|
7285
|
+
let parsed;
|
|
7286
|
+
try {
|
|
7287
|
+
parsed = JSON.parse(raw);
|
|
7288
|
+
} catch {
|
|
7289
|
+
return emptyState();
|
|
7290
|
+
}
|
|
7291
|
+
if (typeof parsed !== "object" || parsed === null) return emptyState();
|
|
7292
|
+
const source = parsed;
|
|
7293
|
+
const state = emptyState();
|
|
7294
|
+
if (typeof source.lastShown === "object" && source.lastShown !== null) {
|
|
7295
|
+
const valid = Object.entries(source.lastShown).filter((entry) => isValidTimestamp(entry[1]));
|
|
7296
|
+
capEntries(valid, (timestamp) => timestamp).forEach(([popupId, timestamp]) => {
|
|
7297
|
+
state.lastShown[popupId] = timestamp;
|
|
7298
|
+
});
|
|
7299
|
+
}
|
|
7300
|
+
if (typeof source.progress === "object" && source.progress !== null) {
|
|
7301
|
+
const valid = Object.entries(source.progress).filter((entry) => {
|
|
7302
|
+
const value = entry[1];
|
|
7303
|
+
if (typeof value !== "object" || value === null) return false;
|
|
7304
|
+
const candidate = value;
|
|
7305
|
+
return POPUP_TRIGGER_CONDITION_STATUSES.includes(candidate.status) && isValidTimestamp(candidate.timestamp);
|
|
7306
|
+
});
|
|
7307
|
+
capEntries(valid, (entry) => entry.timestamp).forEach(([surveyId, entry]) => {
|
|
7308
|
+
state.progress[surveyId] = { status: entry.status, timestamp: entry.timestamp };
|
|
7309
|
+
});
|
|
7310
|
+
}
|
|
7311
|
+
return state;
|
|
7312
|
+
}
|
|
7313
|
+
function writePopupState(storage, state) {
|
|
7314
|
+
const capped = emptyState();
|
|
7315
|
+
capEntries(Object.entries(state.lastShown), (timestamp) => timestamp).forEach(([popupId, timestamp]) => {
|
|
7316
|
+
capped.lastShown[popupId] = timestamp;
|
|
7317
|
+
});
|
|
7318
|
+
capEntries(Object.entries(state.progress), (entry) => entry.timestamp).forEach(([surveyId, entry]) => {
|
|
7319
|
+
capped.progress[surveyId] = entry;
|
|
7320
|
+
});
|
|
7321
|
+
try {
|
|
7322
|
+
storage.setItem(POPUP_STATE_STORAGE_KEY, JSON.stringify(capped));
|
|
7323
|
+
} catch {
|
|
7324
|
+
}
|
|
7325
|
+
}
|
|
7326
|
+
function clearPopupState(storage) {
|
|
7327
|
+
try {
|
|
7328
|
+
storage.removeItem(POPUP_STATE_STORAGE_KEY);
|
|
7329
|
+
} catch {
|
|
7330
|
+
}
|
|
7331
|
+
}
|
|
7332
|
+
|
|
7021
7333
|
// src/core/deepdots-popups.ts
|
|
7022
7334
|
init_logger();
|
|
7023
7335
|
|
|
@@ -7108,6 +7420,10 @@ var DeepdotsPopups = class {
|
|
|
7108
7420
|
this.popupDefinitions = [];
|
|
7109
7421
|
this.popupsLoaded = false;
|
|
7110
7422
|
this.pendingAutoLaunch = false;
|
|
7423
|
+
// Estado que alimenta las reglas de redisplay. Copia de trabajo en memoria; la fuente
|
|
7424
|
+
// duradera es el storage (`popup-state-store`), rehidratada en `init()` — sin eso, una
|
|
7425
|
+
// recarga reiniciaba el cooldown y el popup volvía a salir. `answeredSurveys` se deriva
|
|
7426
|
+
// de las entradas COMPLETED de `surveyProgress` (los dos los escribe `markSurveyAnswered`).
|
|
7111
7427
|
this.answeredSurveys = /* @__PURE__ */ new Set();
|
|
7112
7428
|
this.surveyProgress = /* @__PURE__ */ new Map();
|
|
7113
7429
|
this.lastShown = /* @__PURE__ */ new Map();
|
|
@@ -7183,6 +7499,7 @@ var DeepdotsPopups = class {
|
|
|
7183
7499
|
};
|
|
7184
7500
|
const storage = config.storage ?? createDefaultStorage();
|
|
7185
7501
|
this.storage = storage;
|
|
7502
|
+
this.loadPopupState(storage);
|
|
7186
7503
|
this.tracking = new TrackingManager({
|
|
7187
7504
|
storage,
|
|
7188
7505
|
clientUserId: this.config.userId,
|
|
@@ -7272,6 +7589,7 @@ var DeepdotsPopups = class {
|
|
|
7272
7589
|
this.popupDefinitions = this.validatePopupDefinitions(defs);
|
|
7273
7590
|
this.popupsLoaded = true;
|
|
7274
7591
|
this.log("Popups loaded from API", this.popupDefinitions);
|
|
7592
|
+
if (this.popupDefinitions.length) this.renderer.preload?.();
|
|
7275
7593
|
this.configureTriggersFromDefinitions();
|
|
7276
7594
|
this.processDeferredExitQueue();
|
|
7277
7595
|
if (this.pendingAutoLaunch) {
|
|
@@ -7450,6 +7768,10 @@ var DeepdotsPopups = class {
|
|
|
7450
7768
|
}) : null;
|
|
7451
7769
|
this.analytics?.resetUserScope();
|
|
7452
7770
|
this.messageGuard.reset();
|
|
7771
|
+
this.lastShown.clear();
|
|
7772
|
+
this.surveyProgress.clear();
|
|
7773
|
+
this.answeredSurveys.clear();
|
|
7774
|
+
clearPopupState(storage);
|
|
7453
7775
|
this.log("tracking \xB7 user_change \xB7 user_id:", this.tracking.getUserId());
|
|
7454
7776
|
this.openSession();
|
|
7455
7777
|
}
|
|
@@ -7621,6 +7943,7 @@ var DeepdotsPopups = class {
|
|
|
7621
7943
|
this.log("Showing popup (definition)", def);
|
|
7622
7944
|
this.surveyToPopupId.set(def.surveyId, def.id);
|
|
7623
7945
|
this.lastShown.set(def.id, Date.now());
|
|
7946
|
+
this.persistPopupState();
|
|
7624
7947
|
this.renderPopup(def.surveyId, def.productId, def.actions, def.style, def.title);
|
|
7625
7948
|
this.emitEvent("popup_shown", def.surveyId, { popupId: def.id });
|
|
7626
7949
|
}
|
|
@@ -7754,7 +8077,7 @@ var DeepdotsPopups = class {
|
|
|
7754
8077
|
processDeferredExitQueue() {
|
|
7755
8078
|
const queue = this.getDeferredExitQueue();
|
|
7756
8079
|
if (!queue.length) return;
|
|
7757
|
-
const
|
|
8080
|
+
const pending2 = [];
|
|
7758
8081
|
const now = Date.now();
|
|
7759
8082
|
queue.forEach((item) => {
|
|
7760
8083
|
const def = this.popupDefinitions.find((popup) => popup.id === item.id && popup.surveyId === item.surveyId);
|
|
@@ -7765,10 +8088,10 @@ var DeepdotsPopups = class {
|
|
|
7765
8088
|
this.tryShowDeferredExitPopup(item);
|
|
7766
8089
|
return;
|
|
7767
8090
|
}
|
|
7768
|
-
|
|
8091
|
+
pending2.push(item);
|
|
7769
8092
|
this.scheduleDeferredExitPopup(item);
|
|
7770
8093
|
});
|
|
7771
|
-
this.setDeferredExitQueue(
|
|
8094
|
+
this.setDeferredExitQueue(pending2);
|
|
7772
8095
|
}
|
|
7773
8096
|
scheduleDeferredExitPopup(item) {
|
|
7774
8097
|
if (typeof window === "undefined") return;
|
|
@@ -7841,7 +8164,7 @@ var DeepdotsPopups = class {
|
|
|
7841
8164
|
async fetchPopupsFromServer() {
|
|
7842
8165
|
const apiKey = this.config?.apiKey;
|
|
7843
8166
|
const baseUrl = this.baseUrl;
|
|
7844
|
-
const userId = this.config?.userId;
|
|
8167
|
+
const userId = this.tracking?.getUserId() ?? this.config?.userId;
|
|
7845
8168
|
if (!apiKey || !baseUrl) {
|
|
7846
8169
|
this.log("Missing apiKey or baseUrl. Skipping popups fetch.");
|
|
7847
8170
|
return [];
|
|
@@ -8100,6 +8423,29 @@ var DeepdotsPopups = class {
|
|
|
8100
8423
|
return;
|
|
8101
8424
|
}
|
|
8102
8425
|
this.surveyProgress.set(surveyId, { status, timestamp: Date.now() });
|
|
8426
|
+
this.persistPopupState();
|
|
8427
|
+
}
|
|
8428
|
+
/**
|
|
8429
|
+
* Rehidrata el estado de redisplay desde el storage. `answeredSurveys` se reconstruye
|
|
8430
|
+
* desde las entradas COMPLETED: es exactamente lo que persiste `markSurveyAnswered`.
|
|
8431
|
+
*/
|
|
8432
|
+
loadPopupState(storage) {
|
|
8433
|
+
const state = readPopupState(storage);
|
|
8434
|
+
Object.entries(state.lastShown).forEach(([popupId, timestamp]) => {
|
|
8435
|
+
this.lastShown.set(popupId, timestamp);
|
|
8436
|
+
});
|
|
8437
|
+
Object.entries(state.progress).forEach(([surveyId, entry]) => {
|
|
8438
|
+
this.surveyProgress.set(surveyId, { status: entry.status, timestamp: entry.timestamp });
|
|
8439
|
+
if (entry.status === "COMPLETED") this.answeredSurveys.add(surveyId);
|
|
8440
|
+
});
|
|
8441
|
+
}
|
|
8442
|
+
/** Vuelca el estado de redisplay al storage. Sin storage (o bloqueado) degrada a memoria. */
|
|
8443
|
+
persistPopupState() {
|
|
8444
|
+
if (!this.storage) return;
|
|
8445
|
+
writePopupState(this.storage, {
|
|
8446
|
+
lastShown: Object.fromEntries(this.lastShown),
|
|
8447
|
+
progress: Object.fromEntries(this.surveyProgress)
|
|
8448
|
+
});
|
|
8103
8449
|
}
|
|
8104
8450
|
isPopupDefinition(value) {
|
|
8105
8451
|
if (typeof value !== "object" || value === null) return false;
|
|
@@ -8171,6 +8517,7 @@ var DeepdotsPopups = class {
|
|
|
8171
8517
|
|
|
8172
8518
|
// src/index.ts
|
|
8173
8519
|
init_tracking_manager();
|
|
8520
|
+
init_reveal();
|
|
8174
8521
|
init_labels();
|
|
8175
8522
|
|
|
8176
8523
|
// src/react-native/setup.ts
|