@magicfeedback/popup-sdk 1.5.0 → 1.7.0
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 +34 -1
- package/dist/assets/assets/style.css +1545 -602
- package/dist/chunk-W6MPSWMS.mjs +2302 -0
- package/dist/chunk-W6MPSWMS.mjs.map +1 -0
- package/dist/chunk-WNIUIOKF.mjs +2261 -0
- package/dist/chunk-WNIUIOKF.mjs.map +1 -0
- package/dist/index.d.mts +92 -1
- package/dist/index.d.ts +92 -1
- package/dist/index.js +3710 -1050
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +105 -33
- package/dist/index.mjs.map +1 -1
- package/dist/react-native.d.mts +6 -0
- package/dist/react-native.d.ts +6 -0
- package/dist/react-native.js +2252 -90
- package/dist/react-native.js.map +1 -1
- package/dist/react-native.mjs +94 -33
- package/dist/react-native.mjs.map +1 -1
- package/dist/{renderPopup-4WZ7V435.mjs → renderPopup-EWGKG53W.mjs} +77 -61
- package/dist/renderPopup-EWGKG53W.mjs.map +1 -0
- package/dist/renderPopup-IHGYFMXO.mjs +3114 -0
- package/dist/renderPopup-IHGYFMXO.mjs.map +1 -0
- package/package.json +2 -2
- package/dist/chunk-D7QAGWGC.mjs +0 -176
- package/dist/chunk-D7QAGWGC.mjs.map +0 -1
- package/dist/chunk-JSBMP4MI.mjs +0 -197
- package/dist/chunk-JSBMP4MI.mjs.map +0 -1
- package/dist/renderPopup-4WZ7V435.mjs.map +0 -1
- package/dist/renderPopup-PXJEND4Y.mjs +0 -2626
- package/dist/renderPopup-PXJEND4Y.mjs.map +0 -1
|
@@ -2,11 +2,51 @@ import {
|
|
|
2
2
|
buildFontFaceCss,
|
|
3
3
|
buildFontFamilyValue,
|
|
4
4
|
buildSurveyIdentity,
|
|
5
|
+
directionFor,
|
|
6
|
+
getLabels,
|
|
7
|
+
resolveActionLabels,
|
|
5
8
|
sdkError,
|
|
6
9
|
sdkLog,
|
|
7
10
|
sdkWarn,
|
|
8
11
|
style_default
|
|
9
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-WNIUIOKF.mjs";
|
|
13
|
+
|
|
14
|
+
// src/ui/logo.ts
|
|
15
|
+
var BASE_CSS = "max-height:40px; max-width:100%; object-fit:contain; display:block; margin:12px 0 0 0;";
|
|
16
|
+
var MAX_HEIGHT = {
|
|
17
|
+
small: "30px",
|
|
18
|
+
medium: "50px",
|
|
19
|
+
large: "70px"
|
|
20
|
+
};
|
|
21
|
+
function insertPopupLogo(parent, anchor, style, id) {
|
|
22
|
+
if (!style?.logo) return null;
|
|
23
|
+
if (parent.ownerDocument.getElementById(id)) return null;
|
|
24
|
+
const img = parent.ownerDocument.createElement("img");
|
|
25
|
+
img.id = id;
|
|
26
|
+
img.src = style.logo;
|
|
27
|
+
img.alt = "Logo";
|
|
28
|
+
img.style.cssText = BASE_CSS;
|
|
29
|
+
if (style.logoSize && MAX_HEIGHT[style.logoSize]) {
|
|
30
|
+
img.style.maxHeight = MAX_HEIGHT[style.logoSize];
|
|
31
|
+
}
|
|
32
|
+
switch (style.logoPosition) {
|
|
33
|
+
case "left":
|
|
34
|
+
img.style.margin = "12px 0 0 0";
|
|
35
|
+
img.style.setProperty("margin-inline-start", "0");
|
|
36
|
+
img.style.setProperty("margin-inline-end", "16px");
|
|
37
|
+
break;
|
|
38
|
+
case "right":
|
|
39
|
+
img.style.margin = "12px 0 0 0";
|
|
40
|
+
img.style.setProperty("margin-inline-start", "auto");
|
|
41
|
+
img.style.setProperty("margin-inline-end", "0");
|
|
42
|
+
break;
|
|
43
|
+
case "center":
|
|
44
|
+
img.style.margin = "12px auto 0 auto";
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
parent.insertBefore(img, anchor);
|
|
48
|
+
return img;
|
|
49
|
+
}
|
|
10
50
|
|
|
11
51
|
// src/ui/renderPopup.ts
|
|
12
52
|
import magicfeedback from "@magicfeedback/native";
|
|
@@ -102,6 +142,9 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
|
|
|
102
142
|
let stylesInjected = false;
|
|
103
143
|
let pageDepth = 0;
|
|
104
144
|
let onStartPage = false;
|
|
145
|
+
let labels = getLabels(options?.language);
|
|
146
|
+
let actionLabels = resolveActionLabels(actions, options?.language);
|
|
147
|
+
let direction = directionFor(options?.language);
|
|
105
148
|
const isDark = style?.theme === "dark";
|
|
106
149
|
const theme = {
|
|
107
150
|
popupBg: isDark ? "#1e1e1e" : "#fff",
|
|
@@ -111,7 +154,6 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
|
|
|
111
154
|
// oscuros con texto blanco sobre el fondo claro del popup.
|
|
112
155
|
colorScheme: isDark ? "dark" : "light",
|
|
113
156
|
textPrimary: isDark ? "#f0f0f0" : "#111",
|
|
114
|
-
closeBtnHoverBg: isDark ? "rgba(255,255,255,0.10)" : "rgba(0,0,0,0.06)",
|
|
115
157
|
closeBtnHoverColor: isDark ? "#fff" : "#000000",
|
|
116
158
|
textMuted: isDark ? "#9ca3af" : "#6b7280",
|
|
117
159
|
progressTrack: isDark ? "#3f3f46" : "#e5e7eb"
|
|
@@ -129,6 +171,7 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
|
|
|
129
171
|
const popup = document.createElement("div");
|
|
130
172
|
popup.id = "dd-popup";
|
|
131
173
|
popup.className = "deepdots-popup";
|
|
174
|
+
popup.setAttribute("dir", direction);
|
|
132
175
|
popup.style.cssText = `
|
|
133
176
|
position: relative;
|
|
134
177
|
display: flex;
|
|
@@ -158,7 +201,7 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
|
|
|
158
201
|
const titleEl = document.createElement("h2");
|
|
159
202
|
titleEl.id = "dd-title";
|
|
160
203
|
titleEl.className = "deepdots-popup-title";
|
|
161
|
-
titleEl.style.cssText = `margin:0; font-size:17px; font-weight:600; line-height:1.3; color:${theme.textPrimary}; text-transform:none; text-align:
|
|
204
|
+
titleEl.style.cssText = `margin:0; font-size:17px; font-weight:600; line-height:1.3; color:${theme.textPrimary}; text-transform:none; text-align:start; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;`;
|
|
162
205
|
titleEl.hidden = true;
|
|
163
206
|
const setTitle = (value) => {
|
|
164
207
|
if (!value) return;
|
|
@@ -170,10 +213,10 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
|
|
|
170
213
|
const closeBtn = document.createElement("button");
|
|
171
214
|
closeBtn.id = "dd-close";
|
|
172
215
|
closeBtn.type = "button";
|
|
173
|
-
closeBtn.setAttribute("aria-label",
|
|
216
|
+
closeBtn.setAttribute("aria-label", labels.closeAria);
|
|
174
217
|
closeBtn.innerHTML = `
|
|
175
|
-
<svg width="
|
|
176
|
-
<path d="
|
|
218
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
219
|
+
<path d="M5 5L19 19M5 19L19 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="butt"/>
|
|
177
220
|
</svg>
|
|
178
221
|
`;
|
|
179
222
|
closeBtn.style.cssText = `
|
|
@@ -188,17 +231,15 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
|
|
|
188
231
|
cursor:pointer;
|
|
189
232
|
color:${theme.textPrimary};
|
|
190
233
|
padding:4px;
|
|
191
|
-
transition: color .15s ease, transform .15s ease
|
|
234
|
+
transition: color .15s ease, transform .15s ease;
|
|
192
235
|
box-shadow: none !important;
|
|
193
236
|
`;
|
|
194
237
|
closeBtn.onmouseenter = () => {
|
|
195
238
|
closeBtn.style.color = theme.closeBtnHoverColor;
|
|
196
|
-
closeBtn.style.background = theme.closeBtnHoverBg;
|
|
197
239
|
closeBtn.style.transform = "scale(1.06)";
|
|
198
240
|
};
|
|
199
241
|
closeBtn.onmouseleave = () => {
|
|
200
242
|
closeBtn.style.color = theme.textPrimary;
|
|
201
|
-
closeBtn.style.background = "transparent";
|
|
202
243
|
closeBtn.style.transform = "scale(1)";
|
|
203
244
|
};
|
|
204
245
|
closeBtn.onclick = () => {
|
|
@@ -231,7 +272,7 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
|
|
|
231
272
|
progressLabel.appendChild(progressTotal);
|
|
232
273
|
const progressFollowUp = document.createElement("span");
|
|
233
274
|
progressFollowUp.id = "dd-progress-followup";
|
|
234
|
-
progressFollowUp.textContent =
|
|
275
|
+
progressFollowUp.textContent = labels.followUp;
|
|
235
276
|
progressFollowUp.style.cssText = "display:none; font-size:12px; font-weight:600; color:#fff; background:rgba(59,130,246,0.44); border-radius:999px; padding:2px 10px;";
|
|
236
277
|
progressHead.appendChild(progressLabel);
|
|
237
278
|
progressHead.appendChild(progressFollowUp);
|
|
@@ -263,8 +304,8 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
|
|
|
263
304
|
progressCurrent.textContent = `${Math.round(pct)}%`;
|
|
264
305
|
progressTotal.textContent = "";
|
|
265
306
|
} else {
|
|
266
|
-
progressCurrent.textContent =
|
|
267
|
-
progressTotal.textContent = ` of ${total}`;
|
|
307
|
+
progressCurrent.textContent = `${labels.question} ${label}`;
|
|
308
|
+
progressTotal.textContent = ` ${labels.of} ${total}`;
|
|
268
309
|
}
|
|
269
310
|
progressFollowUp.style.display = p.followup ? "inline-block" : "none";
|
|
270
311
|
}
|
|
@@ -301,7 +342,7 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
|
|
|
301
342
|
const spinnerEl = document.createElement("div");
|
|
302
343
|
spinnerEl.className = "mf-spinner";
|
|
303
344
|
spinnerEl.setAttribute("role", "status");
|
|
304
|
-
spinnerEl.setAttribute("aria-label",
|
|
345
|
+
spinnerEl.setAttribute("aria-label", labels.loadingAria);
|
|
305
346
|
spinnerEl.innerHTML = '<div class="mf-spinner-circle"></div>';
|
|
306
347
|
spinnerEl.style.cssText = "position:absolute; top:50%; left:50%; transform:translate(-50%,-50%);";
|
|
307
348
|
const formDivId = `magicfeedback-form-${surveyId}`;
|
|
@@ -320,7 +361,7 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
|
|
|
320
361
|
const backButton = document.createElement("button");
|
|
321
362
|
backButton.id = "dd-back";
|
|
322
363
|
backButton.className = "dd-nav-btn";
|
|
323
|
-
backButton.textContent =
|
|
364
|
+
backButton.textContent = actionLabels.back;
|
|
324
365
|
backButton.style.cssText = `
|
|
325
366
|
background: transparent;
|
|
326
367
|
color: ${theme.textMuted};
|
|
@@ -350,7 +391,7 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
|
|
|
350
391
|
const startButton = document.createElement("button");
|
|
351
392
|
startButton.id = "dd-start";
|
|
352
393
|
startButton.className = "dd-nav-btn";
|
|
353
|
-
startButton.textContent =
|
|
394
|
+
startButton.textContent = actionLabels.start;
|
|
354
395
|
startButton.style.cssText = `
|
|
355
396
|
background: #1E293B;
|
|
356
397
|
color: #fff;
|
|
@@ -377,7 +418,7 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
|
|
|
377
418
|
const closeButton = document.createElement("button");
|
|
378
419
|
closeButton.id = "dd-complete";
|
|
379
420
|
closeButton.className = "dd-nav-btn";
|
|
380
|
-
closeButton.textContent =
|
|
421
|
+
closeButton.textContent = actionLabels.complete;
|
|
381
422
|
closeButton.style.cssText = `
|
|
382
423
|
background: #1E293B;
|
|
383
424
|
color: #fff;
|
|
@@ -408,7 +449,7 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
|
|
|
408
449
|
const submitButton = document.createElement("button");
|
|
409
450
|
submitButton.id = "dd-submit";
|
|
410
451
|
submitButton.className = "dd-nav-btn";
|
|
411
|
-
submitButton.textContent =
|
|
452
|
+
submitButton.textContent = actionLabels.accept;
|
|
412
453
|
submitButton.style.cssText = `
|
|
413
454
|
background: #1E293B;
|
|
414
455
|
color: #fff;
|
|
@@ -432,6 +473,19 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
|
|
|
432
473
|
formInstance?.send?.();
|
|
433
474
|
}
|
|
434
475
|
};
|
|
476
|
+
function applyLabels(lang) {
|
|
477
|
+
labels = getLabels(lang);
|
|
478
|
+
actionLabels = resolveActionLabels(actions, lang);
|
|
479
|
+
backButton.textContent = actionLabels.back;
|
|
480
|
+
startButton.textContent = actionLabels.start;
|
|
481
|
+
closeButton.textContent = actionLabels.complete;
|
|
482
|
+
submitButton.textContent = actionLabels.accept;
|
|
483
|
+
closeBtn.setAttribute("aria-label", labels.closeAria);
|
|
484
|
+
spinnerEl.setAttribute("aria-label", labels.loadingAria);
|
|
485
|
+
progressFollowUp.textContent = labels.followUp;
|
|
486
|
+
direction = directionFor(lang);
|
|
487
|
+
popup.setAttribute("dir", direction);
|
|
488
|
+
}
|
|
435
489
|
backButton.style.display = "none";
|
|
436
490
|
startButton.style.display = "none";
|
|
437
491
|
submitButton.style.display = "none";
|
|
@@ -552,6 +606,8 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
|
|
|
552
606
|
addSuccessScreen: false
|
|
553
607
|
};
|
|
554
608
|
generateOptions.onLoadedEvent = ({ formData }) => {
|
|
609
|
+
const surveyLang = Array.isArray(formData?.lang) ? formData.lang.find((l) => typeof l === "string" && l.trim().length > 0) : void 0;
|
|
610
|
+
if (surveyLang) applyLabels(surveyLang);
|
|
555
611
|
try {
|
|
556
612
|
} catch {
|
|
557
613
|
}
|
|
@@ -588,47 +644,7 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
|
|
|
588
644
|
backButton.style.color = s.buttonSecondaryColor;
|
|
589
645
|
backButton.style.border = "none";
|
|
590
646
|
}
|
|
591
|
-
|
|
592
|
-
if (!document.getElementById("deepdots-popup-logo")) {
|
|
593
|
-
const logoImg = document.createElement("img");
|
|
594
|
-
logoImg.id = "deepdots-popup-logo";
|
|
595
|
-
logoImg.src = s.logo;
|
|
596
|
-
logoImg.alt = "Logo";
|
|
597
|
-
logoImg.style.cssText = "max-height:40px; max-width:100%; object-fit:contain;";
|
|
598
|
-
if (s.logoSize) {
|
|
599
|
-
switch (s.logoSize) {
|
|
600
|
-
case "small":
|
|
601
|
-
logoImg.style.maxHeight = "30px";
|
|
602
|
-
break;
|
|
603
|
-
case "medium":
|
|
604
|
-
logoImg.style.maxHeight = "50px";
|
|
605
|
-
break;
|
|
606
|
-
case "large":
|
|
607
|
-
logoImg.style.maxHeight = "70px";
|
|
608
|
-
break;
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
|
-
if (s.logoPosition) {
|
|
612
|
-
switch (s.logoPosition) {
|
|
613
|
-
case "left":
|
|
614
|
-
logoImg.style.margin = "0 16px 42px 0";
|
|
615
|
-
logoImg.style.display = "block";
|
|
616
|
-
logoImg.style.marginLeft = "0";
|
|
617
|
-
break;
|
|
618
|
-
case "right":
|
|
619
|
-
logoImg.style.margin = "0 0 42px 16px";
|
|
620
|
-
logoImg.style.display = "block";
|
|
621
|
-
logoImg.style.marginLeft = "auto";
|
|
622
|
-
break;
|
|
623
|
-
case "center":
|
|
624
|
-
logoImg.style.margin = "0 auto 42px auto";
|
|
625
|
-
logoImg.style.display = "block";
|
|
626
|
-
break;
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
containerContent.insertBefore(logoImg, main);
|
|
630
|
-
}
|
|
631
|
-
}
|
|
647
|
+
insertPopupLogo(popup, progressEl, s, "deepdots-popup-logo");
|
|
632
648
|
if (s.startMessage && s.startMessage !== "") {
|
|
633
649
|
sdkLog(s.startMessage);
|
|
634
650
|
onStartPage = true;
|
|
@@ -652,13 +668,13 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
|
|
|
652
668
|
if (errText) {
|
|
653
669
|
setLoading(false);
|
|
654
670
|
if (errText.toLowerCase().includes("no response")) {
|
|
655
|
-
errorHint.textContent =
|
|
671
|
+
errorHint.textContent = labels.errorRequired;
|
|
656
672
|
errorHint.style.display = "block";
|
|
657
673
|
emit("popup_clicked", surveyId, { action: "validation_error_required" });
|
|
658
674
|
updateNavButtons();
|
|
659
675
|
return;
|
|
660
676
|
}
|
|
661
|
-
errorHint.textContent =
|
|
677
|
+
errorHint.textContent = labels.errorSubmit;
|
|
662
678
|
errorHint.style.display = "block";
|
|
663
679
|
emit("popup_clicked", surveyId, { action: "submit_error", error: errText });
|
|
664
680
|
return;
|
|
@@ -696,4 +712,4 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
|
|
|
696
712
|
export {
|
|
697
713
|
renderPopup
|
|
698
714
|
};
|
|
699
|
-
//# sourceMappingURL=renderPopup-
|
|
715
|
+
//# sourceMappingURL=renderPopup-EWGKG53W.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/ui/logo.ts","../src/ui/renderPopup.ts"],"sourcesContent":["/**\n * Logo del popup (viene en `formData.style` del survey, no del `init`).\n *\n * Vive encima de la barra de progreso, como hermano del header: la marca abre la tarjeta y el\n * progreso queda pegado a la pregunta. Antes se insertaba DENTRO del contenido (web) o del área\n * scrollable (WebView de RN), así que la barra quedaba por encima del logo y en RN el logo se\n * iba con el scroll.\n *\n * El hueco inferior lo pone el bloque siguiente (`.deepdots-progress` cuando se ve, o el\n * `padding-top` del contenido cuando no), así que aquí solo se separa del header.\n */\nexport interface PopupLogoStyle {\n logo?: string;\n logoSize?: string;\n logoPosition?: string;\n}\n\nconst BASE_CSS = 'max-height:40px; max-width:100%; object-fit:contain; display:block; margin:12px 0 0 0;';\n\nconst MAX_HEIGHT: Record<string, string> = {\n small: '30px',\n medium: '50px',\n large: '70px',\n};\n\n/**\n * Inserta el logo en `parent`, justo antes de `anchor` (la barra de progreso).\n * No-op si el estilo no trae logo o si ya existe uno con ese `id`.\n */\nexport function insertPopupLogo(\n parent: HTMLElement,\n anchor: HTMLElement | null,\n style: PopupLogoStyle | undefined,\n id: string,\n): HTMLImageElement | null {\n if (!style?.logo) return null;\n if (parent.ownerDocument.getElementById(id)) return null;\n\n const img = parent.ownerDocument.createElement('img');\n img.id = id;\n img.src = style.logo;\n img.alt = 'Logo';\n img.style.cssText = BASE_CSS;\n\n if (style.logoSize && MAX_HEIGHT[style.logoSize]) {\n img.style.maxHeight = MAX_HEIGHT[style.logoSize];\n }\n // Márgenes lógicos (inline-start/end) en vez de left/right: con un survey RTL (árabe) el\n // popup se pinta con dir=\"rtl\" y el logo tiene que acompañar al resto del chrome. En LTR\n // el resultado es idéntico al de antes.\n switch (style.logoPosition) {\n case 'left':\n img.style.margin = '12px 0 0 0';\n img.style.setProperty('margin-inline-start', '0');\n img.style.setProperty('margin-inline-end', '16px');\n break;\n case 'right':\n img.style.margin = '12px 0 0 0';\n img.style.setProperty('margin-inline-start', 'auto');\n img.style.setProperty('margin-inline-end', '0');\n break;\n case 'center':\n img.style.margin = '12px auto 0 auto';\n break;\n }\n\n parent.insertBefore(img, anchor);\n return img;\n}\n","import {DeepdotsEventType, PopupActions, PopupStyle, FormData} from '../types';\nimport { buildSurveyIdentity } from '../tracking/tracking-manager';\nimport type { PopupRenderOptions } from '../platform/renderer';\nimport { buildFontFaceCss, buildFontFamilyValue } from './font';\nimport { insertPopupLogo } from './logo';\nimport { sdkLog, sdkWarn, sdkError } from '../util/logger';\nimport { directionFor, getLabels, resolveActionLabels } from '../i18n/labels';\nimport magicfeedback from \"@magicfeedback/native\";\nimport magicfeedbackCss from '../assets/style.css';\n\n// Inserta la hoja de estilos de MagicFeedback directamente en el popup para garantizar estilos incluso si el bundler no la inyecta globalmente.\nfunction ensureMagicFeedbackStyles(_popup: HTMLElement) {\n const STYLE_ID = 'magicfeedback-sdk-styles';\n if (document.getElementById(STYLE_ID)) return;\n const style = document.createElement('style');\n style.id = STYLE_ID;\n style.textContent = magicfeedbackCss;\n document.head.appendChild(style);\n}\n\n// Añade estilos de spinner si no existen\nfunction ensureSpinnerStyles(_popup: HTMLElement) {\n if (document.getElementById('deepdots-spinner-styles')) return;\n const style = document.createElement('style');\n style.id = 'deepdots-spinner-styles';\n style.textContent = `\n /* El enunciado trae margin-top:20px del CSS de surveys, que sumaba al hueco de la barra\n de progreso y descompensaba la simetría. Solo se anula en el primero: entre preguntas\n de la misma página sigue separando. */\n .deepdots-popup .magicfeedback-questions .magicfeedback-div:first-child .magicfeedback-label { margin-top: 0; }\n @keyframes ddspin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }\n .mf-spinner { display:flex; justify-content:center; align-items:center; padding:8px 0; }\n .mf-spinner-circle { width:28px; height:28px; border:3px solid #e0e6ed; border-top-color:#1E293B; border-radius:50%; animation: ddspin 0.9s linear infinite; }\n `;\n document.head.appendChild(style);\n}\n\nfunction ensureResponsiveStyles(_popup: HTMLElement) {\n if (document.getElementById('deepdots-responsive-styles')) return;\n const style = document.createElement('style');\n style.id = 'deepdots-responsive-styles';\n style.textContent = `\n /* Responsive adjustments */\n @media (max-width: 640px) {\n .deepdots-popup {\n width: calc(100% - 24px) !important;\n max-width: calc(100% - 24px) !important;\n height: auto !important;\n max-height: 90vh !important;\n border-radius: 12px !important;\n padding: calc(16px + env(safe-area-inset-top)) 16px calc(16px + env(safe-area-inset-bottom)) 16px !important;\n box-sizing: border-box;\n }\n .deepdots-popup .mf-spinner-circle { width: 32px; height: 32px; border-width: 4px; }\n .deepdots-popup button { font-size: 16px !important; }\n .deepdots-popup-header button { width:48px; height:48px; }\n .deepdots-popup-header button svg { width:26px; height:26px; }\n /* Apilados en el orden del DOM: la acción principal (Send/Start/Complete) arriba y\n Back debajo. */\n .deepdots-popup-footer { flex-direction: column !important; gap: 4px !important; }\n .deepdots-popup-footer button { width: 100%; }\n }\n @media (max-width: 400px) {\n .deepdots-popup { padding: calc(12px + env(safe-area-inset-top)) 12px calc(12px + env(safe-area-inset-bottom)) 12px !important; }\n .deepdots-popup-header button { width:48px; height:48px; }\n .deepdots-popup-header button svg { width:26px; height:26px; }\n }\n @media (orientation: landscape) and (max-height: 480px) {\n .deepdots-popup {\n height: 100vh !important;\n max-height: 100vh !important;\n overflow-y: auto !important;\n }\n }\n `;\n document.head.appendChild(style);\n}\n\n/**\n * CSS del host, en un <style> propio añadido DESPUÉS de los del SDK y de\n * `@magicfeedback/native` para que gane en cascada sin tocar ninguno de los dos.\n * Se reemplaza en cada render por si cambia entre popups.\n */\nfunction ensureCustomCss(css?: string) {\n const STYLE_ID = 'deepdots-custom-css';\n const existing = document.getElementById(STYLE_ID);\n if (!css) {\n existing?.remove();\n return;\n }\n const el = (existing as HTMLStyleElement | null) ?? document.createElement('style');\n el.id = STYLE_ID;\n if (el.textContent !== css) el.textContent = css;\n // Reanexar mueve el nodo al final del head: garantiza que va tras las hojas del SDK.\n document.head.appendChild(el);\n}\n\n// Inyecta (una sola vez) el @font-face de la fuente personalizada.\nfunction ensureFontFace(family: string, url: string) {\n const css = buildFontFaceCss(family, url);\n if (!css) return;\n const STYLE_ID = 'deepdots-font-face';\n let el = document.getElementById(STYLE_ID) as HTMLStyleElement | null;\n if (!el) {\n el = document.createElement('style');\n el.id = STYLE_ID;\n document.head.appendChild(el);\n }\n if (el.textContent !== css) el.textContent = css;\n}\n\n/**\n * Renderiza el popup dentro del contenedor dado usando MagicFeedback para la encuesta.\n */\nexport async function renderPopup(\n container: HTMLElement,\n surveyId: string,\n productId: string,\n actions: PopupActions | undefined,\n emit: (type: DeepdotsEventType, surveyId: string, data?: Record<string, unknown>) => void,\n onClose: () => void,\n env: string = 'production',\n userId?: string,\n style?: PopupStyle,\n sessionId?: string,\n miniService?: string,\n analyticsFeedbackSessionId?: string,\n options?: PopupRenderOptions,\n): Promise<void> {\n let surveyCompletedEmitted = false;\n let stylesInjected = false;\n // Profundidad de navegación dentro del survey: +1 al avanzar, -1 al volver. Sustituye a\n // `total > 1 && progress > 0 && progress < total`, que escondía el Back cuando la pantalla\n // siguiente era una follow-up dinámica (no entran en el grafo: suman +0.5 al progress y\n // dejan el total igual, así que un survey de una pregunta con follow-up nunca lo mostraba).\n let pageDepth = 0;\n let onStartPage = false;\n\n // Textos del chrome (botones, progreso, aria-labels, errores). Arrancan con el idioma que\n // conoce el init y se re-resuelven en `onLoadedEvent` con el idioma del survey\n // (`formData.lang[0]`, el configurado en la integración), que es el que manda: un survey\n // en danés debe traer también su footer en danés aunque el host no declare idioma.\n let labels = getLabels(options?.language);\n let actionLabels = resolveActionLabels(actions, options?.language);\n // Dirección del chrome. Desde `@magicfeedback/native` 2.2.22 el survey se voltea solo\n // (`dir=\"rtl\"` en SU contenedor) para los idiomas RTL; si el header, el footer y la barra\n // de progreso se quedaran en LTR, media tarjeta miraría a cada lado. Se marca siempre,\n // también en `ltr`, para no heredar la dirección de la página del host.\n let direction = directionFor(options?.language);\n\n const isDark = style?.theme === 'dark';\n const theme = {\n popupBg: isDark ? '#1e1e1e' : '#fff',\n // El popup fija su propio fondo, así que debe fijar también el esquema de color.\n // Sin esto los controles de formulario (input/textarea/select) caen al estilo por\n // defecto del navegador: en un host con `prefers-color-scheme: dark` se pintan\n // oscuros con texto blanco sobre el fondo claro del popup.\n colorScheme: isDark ? 'dark' : 'light',\n textPrimary: isDark ? '#f0f0f0' : '#111',\n closeBtnHoverColor: isDark ? '#fff' : '#000000',\n textMuted: isDark ? '#9ca3af' : '#6b7280',\n progressTrack: isDark ? '#3f3f46' : '#e5e7eb',\n };\n\n const positionMap: Record<string, { justifyContent: string; alignItems: string; padding?: string; background: string }> = {\n 'center': { justifyContent: 'center', alignItems: 'center', background: 'rgba(0,0,0,0.5)' },\n 'bottom': { justifyContent: 'center', alignItems: 'flex-end', padding: '16px', background: 'transparent' },\n 'bottom-right': { justifyContent: 'flex-end', alignItems: 'flex-end', padding: '16px', background: 'transparent' },\n 'bottom-left': { justifyContent: 'flex-start', alignItems: 'flex-end', padding: '16px', background: 'transparent' },\n 'top': { justifyContent: 'center', alignItems: 'flex-start', padding: '16px', background: 'transparent' },\n 'top-right': { justifyContent: 'flex-end', alignItems: 'flex-start', padding: '16px', background: 'transparent' },\n 'top-left': { justifyContent: 'flex-start', alignItems: 'flex-start', padding: '16px', background: 'transparent' },\n };\n const pos = positionMap[style?.position ?? 'center'] ?? positionMap['center'];\n\n // Crear popup base\n const popup = document.createElement('div');\n popup.id = 'dd-popup';\n popup.className = 'deepdots-popup';\n popup.setAttribute('dir', direction);\n popup.style.cssText = `\n position: relative;\n display: flex;\n flex-direction: column;\n justify-content: flex-start;\n background: ${theme.popupBg};\n color-scheme: ${theme.colorScheme};\n border-radius: 8px;\n padding: 24px;\n box-shadow: 0 4px 6px rgba(0,0,0,0.1);\n max-width: 600px;\n width: 90%;\n max-height: 90vh;\n min-height: 200px;\n `;\n\n const font = style?.font;\n if (font?.family) {\n const familyValue = buildFontFamilyValue(font.family);\n // El survey vive dentro del contenedor y hereda esta fuente.\n popup.style.fontFamily = familyValue;\n // La variable habilita que el <h2> (Montserrat por defecto) también la use.\n popup.style.setProperty('--deepdots-font', familyValue);\n // Los controles de formulario (button/input/textarea/select) NO heredan\n // font-family por defecto; esta clase activa la regla que los fuerza a heredar.\n popup.classList.add('deepdots-has-font');\n if (font.url) ensureFontFace(font.family, font.url);\n }\n\n // Sección header (título + botón cerrar)\n const header = document.createElement('div');\n header.className = 'deepdots-popup-header';\n header.style.cssText = 'display:flex; justify-content:space-between; align-items:center; gap:12px; width:100%; flex:0 0 auto;';\n\n // Título: `textContent`, nunca innerHTML — el valor viene de la API.\n const titleEl = document.createElement('h2');\n titleEl.id = 'dd-title';\n titleEl.className = 'deepdots-popup-title';\n // text-transform/text-align/margin neutralizan la regla `.deepdots-popup h2` del CSS del\n // survey (uppercase, centrado, margin-bottom 40px), pensada para los enunciados.\n titleEl.style.cssText = `margin:0; font-size:17px; font-weight:600; line-height:1.3; color:${theme.textPrimary}; text-transform:none; text-align:start; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;`;\n titleEl.hidden = true;\n const setTitle = (value?: string) => {\n if (!value) return;\n titleEl.textContent = value;\n titleEl.hidden = false;\n };\n setTitle(options?.title);\n header.appendChild(titleEl);\n\n // Botón de cierre (X)\n const closeBtn = document.createElement('button');\n closeBtn.id = 'dd-close';\n closeBtn.type = 'button';\n closeBtn.setAttribute('aria-label', labels.closeAria);\n closeBtn.innerHTML = `\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M5 5L19 19M5 19L19 5\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"butt\"/>\n </svg>\n `;\n closeBtn.style.cssText = `\n background:transparent;\n border:none;\n width:32px;\n height:32px;\n display:flex;\n align-items:center;\n justify-content:center;\n border-radius: 8px;\n cursor:pointer;\n color:${theme.textPrimary};\n padding:4px;\n transition: color .15s ease, transform .15s ease;\n box-shadow: none !important;\n `;\n closeBtn.onmouseenter = () => {\n closeBtn.style.color = theme.closeBtnHoverColor;\n closeBtn.style.transform = 'scale(1.06)';\n };\n closeBtn.onmouseleave = () => {\n closeBtn.style.color = theme.textPrimary;\n closeBtn.style.transform = 'scale(1)';\n };\n closeBtn.onclick = () => {\n emit('popup_clicked', surveyId, {action: 'close_icon'});\n onClose();\n };\n closeBtn.style.flex = '0 0 auto';\n closeBtn.style.marginLeft = 'auto';\n header.appendChild(closeBtn);\n\n // Barra de progreso (\"Question X of Y\" + barra), espejo de LineProgressQuestion (MagicSurvey).\n // `undefined` en el init deja decidir a la plataforma (style.showProgressBar).\n let progressEnabled = options?.showProgressBar === true;\n let progressShowUnit = true;\n let progressUnit: 'percentage' | 'fraction' = 'fraction';\n\n const progressEl = document.createElement('div');\n progressEl.id = 'dd-progress';\n progressEl.className = 'deepdots-progress';\n // Sin padding horizontal propio: se alinea con el título y con el contenido. El vertical es\n // el mismo arriba y abajo, y del mismo valor que el padding de la tarjeta.\n progressEl.style.cssText = 'display:none; flex-direction:column; gap:8px; width:100%; flex:0 0 auto; padding:16px 0; box-sizing:border-box;';\n const progressHead = document.createElement('div');\n progressHead.className = 'deepdots-progress-head';\n progressHead.style.cssText = 'display:flex; flex-direction:row; justify-content:space-between; align-items:center; width:100%; gap:8px;';\n const progressLabel = document.createElement('span');\n progressLabel.id = 'dd-progress-label';\n progressLabel.style.cssText = 'font-size:13px; line-height:1.2;';\n // \"Question 1\" en negrita y \"of 3\" en regular gris, como el mockup.\n const progressCurrent = document.createElement('span');\n progressCurrent.id = 'dd-progress-current';\n progressCurrent.style.cssText = `font-weight:700; color:${theme.textPrimary};`;\n const progressTotal = document.createElement('span');\n progressTotal.id = 'dd-progress-total';\n progressTotal.style.cssText = `font-weight:400; color:${theme.textMuted};`;\n progressLabel.appendChild(progressCurrent);\n progressLabel.appendChild(progressTotal);\n const progressFollowUp = document.createElement('span');\n progressFollowUp.id = 'dd-progress-followup';\n progressFollowUp.textContent = labels.followUp;\n progressFollowUp.style.cssText = 'display:none; font-size:12px; font-weight:600; color:#fff; background:rgba(59,130,246,0.44); border-radius:999px; padding:2px 10px;';\n progressHead.appendChild(progressLabel);\n progressHead.appendChild(progressFollowUp);\n const progressTrack = document.createElement('div');\n progressTrack.className = 'deepdots-progress-track';\n progressTrack.style.cssText = `width:100%; height:4px; border-radius:999px; background:${theme.progressTrack}; overflow:hidden;`;\n const progressBar = document.createElement('div');\n progressBar.id = 'dd-progress-bar';\n progressBar.style.cssText = 'height:100%; width:0%; background:#22C55E; border-radius:999px; transition:width 450ms ease;';\n progressTrack.appendChild(progressBar);\n progressEl.appendChild(progressHead);\n progressEl.appendChild(progressTrack);\n\n function updateProgress(p: { progress?: number; total?: number; completed?: boolean; followup?: boolean }) {\n const total = typeof p.total === 'number' ? p.total : 0;\n const progress = typeof p.progress === 'number' ? p.progress : 0;\n if (!progressEnabled || onStartPage || p.completed || total <= 1) {\n progressEl.style.display = 'none';\n // Sin barra, el hueco cabecera→pregunta lo pone el contenido.\n containerContent.style.paddingTop = '16px';\n return;\n }\n progressEl.style.display = 'flex';\n // Con barra, el hueco inferior ya lo pone el bloque de progreso: no duplicarlo.\n containerContent.style.paddingTop = '0';\n // La barra usa el valor real (las follow-up suman +0.5 y avanzan media casilla); la\n // etiqueta redondea hacia abajo, porque una follow-up es un paso DENTRO de la misma\n // pregunta y no la siguiente.\n const current = Math.min(total, Math.max(1, progress + 1));\n const pct = Math.min(100, Math.max(0, (current / total) * 100));\n progressBar.style.width = `${pct}%`;\n const label = Math.min(total, Math.max(1, Math.floor(progress) + 1));\n progressLabel.style.display = progressShowUnit ? 'block' : 'none';\n if (progressUnit === 'percentage') {\n progressCurrent.textContent = `${Math.round(pct)}%`;\n progressTotal.textContent = '';\n } else {\n progressCurrent.textContent = `${labels.question} ${label}`;\n progressTotal.textContent = ` ${labels.of} ${total}`;\n }\n progressFollowUp.style.display = p.followup ? 'inline-block' : 'none';\n }\n\n ensureMagicFeedbackStyles(popup);\n ensureSpinnerStyles(popup);\n ensureResponsiveStyles(popup);\n // El último en entrar: el CSS del host gana sobre todo lo anterior.\n ensureCustomCss(options?.surveyCss);\n\n const containerContent = document.createElement('div');\n containerContent.id = 'dd-content';\n // Estaba escrito 'conetent'; el HTML del WebView siempre usó la forma correcta. Con\n // `surveyCss` esta clase pasa a ser superficie pública, así que las dos rutas deben coincidir.\n containerContent.className = 'deepdots-popup-container-content';\n // El popup es una columna: solo el bloque de preguntas hace scroll, para que el footer con\n // las acciones quede siempre pegado al borde inferior (antes vivía dentro del área\n // scrollable y en un survey largo había que bajar hasta el final para ver \"Send\").\n // Sin sangrado extra: el contenido se alinea con el título y con la barra de progreso\n // (antes sumaba 20px a los lados sobre el padding de la tarjeta). `overflow:hidden` deja\n // el scroll en `main`, no en el contenedor.\n containerContent.style.cssText = 'display:flex; flex-direction:column; flex:1 1 auto; min-height:0; padding:16px 0 0 0; overflow:hidden;'\n\n // Sección principal (main) - Contenedor formulario + spinner\n const main = document.createElement('div');\n main.id = 'dd-main';\n main.className = 'deepdots-popup-main';\n main.style.cssText = 'display:flex; flex-direction:column; width:100%; flex:1 1 auto; min-height:0; overflow-y:auto;';\n\n const formWrapper = document.createElement('div');\n formWrapper.id = 'dd-form-wrapper';\n formWrapper.style.cssText = 'width:100%; flex: 1 1 auto;';\n\n // Contenedor de aviso de error de validación\n const errorHint = document.createElement('div');\n errorHint.id = 'dd-error';\n errorHint.className = 'deepdots-error-hint';\n errorHint.style.cssText = `\n display: none;\n margin: 12px 0 0 0;\n padding: 10px 12px;\n border-radius: 6px;\n background: #FEF3C7; /* amber-100 */\n color: #92400E; /* amber-700 */\n border: 1px solid #FCD34D; /* amber-300 */\n font-size: 13px;\n `;\n errorHint.setAttribute('role', 'alert');\n errorHint.setAttribute('aria-live', 'polite');\n\n const spinnerEl = document.createElement('div');\n spinnerEl.className = 'mf-spinner';\n spinnerEl.setAttribute('role', 'status');\n spinnerEl.setAttribute('aria-label', labels.loadingAria);\n spinnerEl.innerHTML = '<div class=\"mf-spinner-circle\"></div>';\n spinnerEl.style.cssText = 'position:absolute; top:50%; left:50%; transform:translate(-50%,-50%);';\n\n const formDivId = `magicfeedback-form-${surveyId}`;\n const formHost = document.createElement('div');\n formHost.id = formDivId;\n formHost.style.cssText = 'width:100%; visibility:hidden;';\n\n formWrapper.appendChild(spinnerEl);\n formWrapper.appendChild(formHost);\n main.appendChild(formWrapper);\n // Insertar el hint justo antes del footer\n main.appendChild(errorHint);\n\n // Sección footer (acciones) - botones en extremos\n const footer = document.createElement('div');\n footer.id = 'dd-footer';\n footer.className = 'deepdots-popup-footer';\n footer.setAttribute('data-actions-wrapper', 'true');\n footer.style.cssText = 'display:flex; flex-direction: row-reverse ;justify-content:space-between; align-items:center; gap:4px; margin-top:auto; width:100%; padding-top:12px;';\n\n // Botones\n const backButton = document.createElement('button');\n backButton.id = 'dd-back';\n backButton.className = 'dd-nav-btn';\n backButton.textContent = actionLabels.back;\n // Secundario como botón de texto: sin borde, fondo ni sombra, para que el primario sea\n // la única CTA con peso visual.\n backButton.style.cssText = `\n background: transparent;\n color: ${theme.textMuted};\n border: none;\n min-height: 44px;\n padding: 12px 24px;\n border-radius: 6px;\n cursor: pointer;\n font-size: 15px;\n font-weight: 600;\n transition: filter .15s ease;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n text-align: center;\n `;\n backButton.onmouseenter = () => {\n backButton.style.filter = 'brightness(0.9)';\n }\n backButton.onmouseleave = () => {\n backButton.style.filter = 'brightness(1)';\n }\n backButton.onclick = () => {\n emit('popup_clicked', surveyId, {action: 'back'});\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (formInstance as any)?.back?.();\n };\n\n // Boton start survyes, solo aprece cuando la encuesta empieza con mensaje de inicio\n // Width de 100% para que ocupe todo el espacio disponible\n const startButton = document.createElement('button');\n startButton.id = 'dd-start';\n startButton.className = 'dd-nav-btn';\n startButton.textContent = actionLabels.start;\n startButton.style.cssText = `\n background: #1E293B;\n color: #fff;\n border: none;\n min-height: 44px;\n padding: 12px 24px;\n border-radius: 6px;\n cursor: pointer;\n font-size: 15px;\n font-weight: 600;\n box-shadow: 0 2px 4px rgba(0,0,0,0.1);\n transition: filter .15s ease;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n text-align: center;\n `;\n startButton.onclick = () => {\n emit('popup_clicked', surveyId, {action: 'start_survey'});\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (formInstance as any)?.startForm?.();\n onStartPage = false;\n updateProgress({progress: formInstance?.progress, total: formInstance?.total});\n };\n\n // Botón cerrar popup, solo aparece al terminar la encuesta\n // Width de 100% para que ocupe todo el espacio disponible\n const closeButton = document.createElement('button');\n closeButton.id = 'dd-complete';\n closeButton.className = 'dd-nav-btn';\n closeButton.textContent = actionLabels.complete;\n closeButton.style.cssText = `\n background: #1E293B;\n color: #fff;\n border: none;\n min-height: 44px;\n padding: 12px 24px;\n border-radius: 6px;\n cursor: pointer;\n font-size: 15px;\n font-weight: 600;\n box-shadow: 0 2px 4px rgba(0,0,0,0.1);\n transition: filter .15s ease;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n text-align: center;\n `;\n closeButton.onmouseenter = () => {\n closeButton.style.filter = 'brightness(0.9)';\n }\n closeButton.onmouseleave = () => {\n closeButton.style.filter = 'brightness(1)';\n }\n closeButton.onclick = () => {\n emit('popup_clicked', surveyId, {action: 'complete'});\n onClose();\n };\n\n // Botón send, si es primera pagina ocupara el espacio completo pero si no estara al lado derecho\n const submitButton = document.createElement('button');\n submitButton.id = 'dd-submit';\n submitButton.className = 'dd-nav-btn';\n submitButton.textContent = actionLabels.accept;\n submitButton.style.cssText = `\n background: #1E293B;\n color: #fff;\n border: none;\n min-height: 44px;\n padding: 12px 24px;\n border-radius: 6px;\n cursor: pointer;\n font-size: 15px;\n font-weight: 600;\n box-shadow: 0 2px 4px rgba(0,0,0,0.1);\n transition: filter .15s ease;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n text-align: center;\n `;\n submitButton.onclick = () => {\n if (!surveyCompletedEmitted) {\n emit('popup_clicked', surveyId, {action: 'manual_send'});\n // Dispara envío nativo si existe\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (formInstance as any)?.send?.();\n }\n };\n\n /**\n * Re-resuelve todos los textos del chrome para `lang`. Se llama cuando el survey ya cargó\n * y se conoce su idioma. Las etiquetas que configure la plataforma por popup\n * (`actions.*.label`) siguen ganando: `resolveActionLabels` solo rellena las que falten.\n * El contador de progreso no se toca aquí porque `updateProgress` lo repinta justo después\n * leyendo `labels`.\n */\n function applyLabels(lang: string): void {\n labels = getLabels(lang);\n actionLabels = resolveActionLabels(actions, lang);\n backButton.textContent = actionLabels.back;\n startButton.textContent = actionLabels.start;\n closeButton.textContent = actionLabels.complete;\n submitButton.textContent = actionLabels.accept;\n closeBtn.setAttribute('aria-label', labels.closeAria);\n spinnerEl.setAttribute('aria-label', labels.loadingAria);\n progressFollowUp.textContent = labels.followUp;\n // El survey ya se ha volteado a sí mismo: el chrome tiene que acompañarlo.\n direction = directionFor(lang);\n popup.setAttribute('dir', direction);\n }\n\n backButton.style.display = 'none';\n startButton.style.display = 'none';\n submitButton.style.display = 'none';\n closeButton.style.display = 'none';\n\n // Insertar botones dentro del footer en orden visual (row-reverse deja primario a la derecha)\n footer.appendChild(submitButton);\n footer.appendChild(backButton);\n footer.appendChild(closeButton);\n footer.appendChild(startButton);\n\n // Añadir footer al main y main al containerContent\n containerContent.appendChild(main);\n // El footer va fuera del área scrollable, como hermano de `main`.\n footer.style.flex = '0 0 auto';\n containerContent.appendChild(footer);\n\n // Helper para controlar visibilidad de botones según estado\n type ViewState = 'loading' | 'start' | 'in_progress_first' | 'in_progress_next' | 'completed' | 'error';\n\n function updateButtons(state: ViewState) {\n // Por defecto, ocultar todos\n backButton.style.display = 'none';\n startButton.style.display = 'none';\n submitButton.style.display = 'none';\n closeButton.style.display = 'none';\n // Reset widths por estado\n backButton.style.width = '';\n startButton.style.width = '';\n submitButton.style.width = '';\n closeButton.style.width = '';\n\n switch (state) {\n case 'loading':\n // Footer se ocultará desde setLoading\n break;\n case 'start':\n // Solo botón Start a ancho completo\n startButton.style.display = 'inline-flex';\n startButton.style.width = '100%';\n break;\n case 'in_progress_first':\n // Solo botón Send (lado derecho), ancho auto\n submitButton.style.display = 'inline-flex';\n submitButton.style.width = '';\n setLoading(false);\n break;\n case 'in_progress_next':\n // Mostrar Back (izquierda) + Send (derecha)\n backButton.style.display = 'inline-flex';\n submitButton.style.display = 'inline-flex';\n setLoading(false);\n break;\n case 'completed':\n // Mostrar Close/Complete a ancho completo como acción principal\n closeButton.style.display = 'inline-flex';\n closeButton.style.width = '100%';\n setLoading(false);\n break;\n case 'error':\n // En error, permitir cerrar (ancho auto)\n // closeButton.style.display = 'inline-flex';\n setLoading(false);\n break;\n }\n }\n\n /** Estado de navegación según la profundidad recorrida (no según `total`). */\n function updateNavButtons() {\n updateButtons(pageDepth > 0 ? 'in_progress_next' : 'in_progress_first');\n }\n\n /**\n * Pantalla final con el `successMessage` configurado en la plataforma. La pinta el popup y\n * no `@magicfeedback/native`, cuyo `renderSuccess` usa `textContent` (el mensaje es HTML del\n * editor: imagen + texto) y cuyo fallback es un literal que ignora el estilo del survey.\n * Va por innerHTML igual que `renderStartMessage` con el mensaje de inicio.\n */\n let successMessageHtml = '';\n function showSuccessScreen() {\n progressEl.style.display = 'none';\n formWrapper.style.display = 'none';\n let done = main.querySelector('.deepdots-success') as HTMLElement | null;\n if (!done) {\n done = document.createElement('div');\n done.className = 'deepdots-success';\n done.style.cssText = `width:100%; text-align:center; padding:24px 0; color:${theme.textPrimary};`;\n main.insertBefore(done, errorHint);\n }\n done.innerHTML = successMessageHtml || '<p>Thank you for your feedback!</p>';\n done.querySelectorAll('img').forEach((img) => {\n img.style.cssText = 'max-width:100%; height:auto; margin:0 auto 16px auto; display:block;';\n });\n }\n\n // Ensamblar popup\n popup.appendChild(header);\n popup.appendChild(progressEl);\n popup.appendChild(containerContent);\n\n container.innerHTML = '';\n container.appendChild(popup);\n container.style.display = 'flex';\n container.style.justifyContent = pos.justifyContent;\n container.style.alignItems = pos.alignItems;\n container.style.background = pos.background;\n if (pos.padding) container.style.padding = pos.padding;\n\n // Gestión dinámica de loading\n function setLoading(isLoading: boolean) {\n spinnerEl.style.display = isLoading ? 'flex' : 'none';\n if (!isLoading) {\n formHost.style.visibility = 'visible';\n }\n // Ocultar totalmente los botones cuando está cargando\n footer.style.display = isLoading ? 'none' : 'flex';\n // Ajustar estados de los botones por si se muestran\n backButton.disabled = isLoading;\n startButton.disabled = isLoading;\n closeButton.disabled = isLoading;\n submitButton.disabled = isLoading;\n submitButton.style.opacity = isLoading ? '0.6' : '1';\n submitButton.style.cursor = isLoading ? 'not-allowed' : 'pointer';\n // No sobrescribir el estado de botones al finalizar la carga.\n if (isLoading) {\n updateButtons('loading');\n }\n }\n\n // Estado inicial\n setLoading(true);\n\n // Entorno navegador\n if (typeof window === 'undefined' || typeof document === 'undefined') {\n return;\n }\n\n // Referencia instancia formulario\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let formInstance: any = null;\n\n try {\n if (!magicfeedback || typeof magicfeedback.form !== 'function') {\n sdkWarn('[MagicFeedback] form() no disponible. Fallback manual.');\n setLoading(false);\n return;\n }\n magicfeedback.init({\n debug: true,\n env: env === 'production' ? 'prod' : 'dev'}\n );\n // Contrato Fase 1 §5: profile = identidad del usuario; metadata = contexto de tracking (session_id + user_id)\n const { profile, metadata } = buildSurveyIdentity(userId ?? null, sessionId ?? null, miniService ?? null, analyticsFeedbackSessionId ?? null);\n formInstance = magicfeedback.form(surveyId, productId, profile, metadata);\n\n interface TypedGenerateOptions {\n addButton: boolean;\n getMetaData: boolean;\n addSuccessScreen: boolean;\n onLoadedEvent?: (args: {\n formData: FormData,\n progress?: number, total?: number\n }) => void;\n beforeSubmitEvent?: () => void;\n afterSubmitEvent?: (args: { error?: string, completed: boolean, progress: number, total: number, followup?: boolean }) => void;\n onBackEvent?: (args: { error?: string, progress: number, total: number, followup: boolean }) => void;\n }\n\n const generateOptions: TypedGenerateOptions = {\n addButton: false,\n getMetaData: true,\n // La pantalla final la pinta el popup: `renderSuccess` de @magicfeedback/native usa\n // textContent, así que el mensaje de la plataforma (HTML con imagen) no se vería, y\n // su fallback es un literal genérico que ignora `style.successMessage`.\n addSuccessScreen: false,\n };\n generateOptions.onLoadedEvent = ({formData}) => {\n // Idioma del survey: el que la plataforma configura en la integración y con el que\n // `@magicfeedback/native` localiza preguntas y placeholders. Manda sobre el del init\n // para que el chrome no se quede en inglés delante de un survey traducido.\n const surveyLang = Array.isArray(formData?.lang)\n ? formData.lang.find((l) => typeof l === 'string' && l.trim().length > 0)\n : undefined;\n if (surveyLang) applyLabels(surveyLang);\n // Calcular altura disponible y aplicarla al main (restando header + footer + paddings)\n try {\n /*\n const headerHeight = header.getBoundingClientRect().height;\n const footerHeight = footer.getBoundingClientRect().height;\n const paddingY = 48; // 24px top + 24px bottom\n const viewportLimit = window.innerHeight * 0.8; // coincide con max-height del popup\n const available = viewportLimit - headerHeight - footerHeight - paddingY;\n if (available > 120) { // asegurar un mínimo razonable\n main.style.maxHeight = available + 'px';\n } */\n } catch {\n // silencioso\n }\n // Personalización del popup basada en formData.style\n const s = formData?.style;\n if (s && !stylesInjected) {\n stylesInjected = true;\n if (s.successMessage) successMessageHtml = s.successMessage;\n // La barra de progreso la decide el host (init) y, si no se pronuncia, la plataforma.\n if (options?.showProgressBar === undefined) progressEnabled = s.showProgressBar === true;\n if (s.showProgressUnit !== undefined) progressShowUnit = s.showProgressUnit !== false;\n if (s.progressUnit) progressUnit = s.progressUnit;\n if (s.loadingBarColor) {\n progressBar.style.background = s.loadingBarColor;\n progressFollowUp.style.background = s.loadingBarColor;\n }\n // Fondo del contenedor popup\n if (s.boxBackgroundColor) {\n popup.style.background = s.boxBackgroundColor;\n }\n // Alineación del contenido principal\n if (s.contentAlign) {\n // 'top' => start, 'center' => center\n main.style.justifyContent = s.contentAlign === 'center' ? 'center' : 'flex-start';\n }\n // Botón primario (submit, start)\n if (s.buttonPrimaryColor) {\n submitButton.style.background = s.buttonPrimaryColor;\n submitButton.style.border = 'none';\n submitButton.style.color = '#fff';\n\n startButton.style.background = s.buttonPrimaryColor;\n startButton.style.border = 'none';\n startButton.style.color = '#fff';\n\n closeButton.style.background = s.buttonPrimaryColor;\n closeButton.style.border = 'none';\n closeButton.style.color = '#fff';\n }\n // Botón secundario (back) — outlined: fondo blanco, letra y borde del color secundario\n if (s.buttonSecondaryColor) {\n // Botón de texto: solo tiñe la etiqueta, sin recuperar fondo ni borde.\n backButton.style.background = 'transparent';\n backButton.style.color = s.buttonSecondaryColor;\n backButton.style.border = 'none';\n }\n // El logo va encima de la barra de progreso, como hermano del header.\n insertPopupLogo(popup, progressEl, s, 'deepdots-popup-logo');\n\n if (s.startMessage && s.startMessage !== '') {\n // Si hay mensaje de inicio, mostrar botón Start inicialmente\n sdkLog(s.startMessage);\n onStartPage = true;\n updateButtons('start');\n } else {\n // Si no hay mensaje de inicio, mostrar estado de primera página (solo Send)\n updateButtons('in_progress_first');\n }\n } else {\n // Sin estilos, asumir primera página normal\n updateButtons('in_progress_first');\n }\n\n // El total solo se conoce con el form ya montado.\n updateProgress({progress: formInstance.progress, total: formInstance.total});\n emit('popup_clicked', surveyId, {action: 'loaded'});\n setLoading(false); // hace visible el formulario y oculta el spinner\n };\n generateOptions.beforeSubmitEvent = () => {\n setLoading(true);\n emit('popup_clicked', surveyId, {action: 'before_submit'});\n };\n generateOptions.afterSubmitEvent = ({error, completed, total, progress, followup}) => {\n // No cambiar estado de loading aquí; lo gestiona cada transición\n // Normalizar el error a texto seguro\n const errText = error ? (typeof error === 'string' ? error : ((error as unknown as {message?: string}).message ?? String(error))) : '';\n if (errText) {\n // Desactivar loading para que se vean los botones\n setLoading(false);\n // Caso específico: error de pregunta obligatoria\n if (errText.toLowerCase().includes('no response')) {\n errorHint.textContent = labels.errorRequired;\n errorHint.style.display = 'block';\n emit('popup_clicked', surveyId, {action: 'validation_error_required'});\n // La página no ha cambiado: el estado de navegación se queda como estaba.\n updateNavButtons();\n return;\n }\n // Otros errores: mostrar mensaje genérico y permitir cerrar\n errorHint.textContent = labels.errorSubmit;\n errorHint.style.display = 'block';\n emit('popup_clicked', surveyId, {action: 'submit_error', error: errText});\n // updateButtons('error');\n return;\n }\n // Limpiar hint si no hay error\n errorHint.style.display = 'none';\n setLoading(false);\n if (completed) {\n emit('survey_completed', surveyId, {action: 'completed'});\n surveyCompletedEmitted = true;\n showSuccessScreen();\n updateButtons('completed');\n updateProgress({progress, total, completed: true});\n return;\n }\n emit('popup_clicked', surveyId, {action: 'partial'});\n pageDepth++;\n updateNavButtons();\n updateProgress({progress, total, followup});\n };\n generateOptions.onBackEvent = ({progress, error, followup}) => {\n emit('popup_clicked', surveyId, {action: 'back'});\n // Con error (\"No page found\") no hubo navegación: la profundidad no se toca.\n if (!error) pageDepth = Math.max(0, pageDepth - 1);\n updateNavButtons();\n // onBackEvent no trae `total`: se lee del form, que es su dueño.\n updateProgress({progress, total: formInstance.total, followup});\n };\n\n // Ejecutar generación con opciones tipadas\n formInstance.generate(formDivId, generateOptions)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n .catch((err: any) => {\n sdkError('[MagicFeedback] Error generating form:', err);\n setLoading(false);\n });\n } catch (e) {\n sdkError('[MagicFeedback] Exception initializing form:', e);\n setLoading(false);\n }\n}\n"],"mappings":"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","names":[]}
|