@magicfeedback/popup-sdk 1.7.1 → 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 +74 -6
- package/dist/index.d.ts +74 -6
- package/dist/index.js +257 -12
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +137 -10
- package/dist/index.mjs.map +1 -1
- package/dist/react-native.d.mts +41 -5
- package/dist/react-native.d.ts +41 -5
- package/dist/react-native.js +272 -22
- package/dist/react-native.js.map +1 -1
- package/dist/react-native.mjs +153 -20
- package/dist/react-native.mjs.map +1 -1
- package/dist/{renderPopup-HHQMAW3G.mjs → renderPopup-5QXL6EJW.mjs} +46 -6
- 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-HHQMAW3G.mjs.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
InMemoryStorage,
|
|
3
3
|
LABELS,
|
|
4
|
+
PRIMARY_COLOR_JS,
|
|
4
5
|
RESOLVE_LOCALE_JS,
|
|
6
|
+
REVEAL_TIMEOUT_MS,
|
|
5
7
|
RTL_LOCALES,
|
|
6
8
|
STORAGE_KEYS,
|
|
7
9
|
SUPPORTED_LANGUAGES,
|
|
@@ -18,7 +20,7 @@ import {
|
|
|
18
20
|
sdkWarn,
|
|
19
21
|
setLogger,
|
|
20
22
|
style_default
|
|
21
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-XHR3MHJO.mjs";
|
|
22
24
|
|
|
23
25
|
// src/types/index.ts
|
|
24
26
|
var POPUP_TRIGGER_CONDITION_STATUSES = [
|
|
@@ -209,6 +211,30 @@ function resolveEnvironment(nodeEnv) {
|
|
|
209
211
|
}
|
|
210
212
|
|
|
211
213
|
// src/ui/surveyHtml.ts
|
|
214
|
+
var REVEAL_JS = `
|
|
215
|
+
function ddCreateReveal(popup, onReveal, timeoutMs){
|
|
216
|
+
var revealed=false, timer=null;
|
|
217
|
+
function reveal(){
|
|
218
|
+
if(revealed){ return; }
|
|
219
|
+
revealed=true;
|
|
220
|
+
if(timer){ clearTimeout(timer); timer=null; }
|
|
221
|
+
onReveal();
|
|
222
|
+
}
|
|
223
|
+
function revealWhenPainted(){
|
|
224
|
+
if(revealed){ return; }
|
|
225
|
+
var imgs=popup.querySelectorAll('img'), pending=[];
|
|
226
|
+
for(var i=0;i<imgs.length;i++){ if(!imgs[i].complete){ pending.push(imgs[i]); } }
|
|
227
|
+
if(!pending.length){ reveal(); return; }
|
|
228
|
+
var left=pending.length;
|
|
229
|
+
function onSettled(){ left--; if(left<=0){ reveal(); } }
|
|
230
|
+
for(var j=0;j<pending.length;j++){
|
|
231
|
+
pending[j].addEventListener('load', onSettled);
|
|
232
|
+
pending[j].addEventListener('error', onSettled);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
timer=setTimeout(reveal, timeoutMs);
|
|
236
|
+
return { reveal: reveal, whenPainted: revealWhenPainted };
|
|
237
|
+
}`;
|
|
212
238
|
var POSITION_MAP = {
|
|
213
239
|
center: { justifyContent: "center", alignItems: "center", padding: "0", background: "rgba(0,0,0,0.5)" },
|
|
214
240
|
bottom: { justifyContent: "center", alignItems: "flex-end", padding: "16px", background: "transparent" },
|
|
@@ -282,7 +308,13 @@ function buildSurveyHtml(opts) {
|
|
|
282
308
|
${style_default}
|
|
283
309
|
${fontFaceCss}
|
|
284
310
|
html,body{margin:0;padding:0;height:100%;font-family:${fontFamilyValue}}
|
|
285
|
-
|
|
311
|
+
/* Apertura diferida: ni la tarjeta ni el velo se pintan hasta que el survey est\xE1 listo
|
|
312
|
+
(\`dd-ready\`). Si el fondo entrara antes, en RN se ver\xEDa el velo oscuro varios cientos de ms
|
|
313
|
+
antes que el contenido, que es la misma mala sensaci\xF3n que el spinner. */
|
|
314
|
+
body{display:${bodyDisplay};justify-content:${pos.justifyContent};align-items:${pos.alignItems};background:transparent;padding:${bodyPadding};box-sizing:border-box}
|
|
315
|
+
body.dd-ready{background:${bodyBg}}
|
|
316
|
+
#dd-popup{visibility:hidden}
|
|
317
|
+
body.dd-ready #dd-popup{visibility:visible}
|
|
286
318
|
.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}
|
|
287
319
|
.deepdots-popup-header{display:flex;justify-content:space-between;align-items:center;gap:12px;width:100%;flex:0 0 auto}
|
|
288
320
|
/* Neutraliza la regla \`.deepdots-popup h2\` del CSS del survey (uppercase, centrado y
|
|
@@ -316,6 +348,13 @@ body{display:${bodyDisplay};justify-content:${pos.justifyContent};align-items:${
|
|
|
316
348
|
#dd-form-wrapper{width:100%;flex:1 1 auto}
|
|
317
349
|
#mf{width:100%;box-sizing:border-box;visibility:hidden}
|
|
318
350
|
.deepdots-popup-main *{max-width:100%;box-sizing:border-box}
|
|
351
|
+
/* El margen lateral lo pone la tarjeta: el CSS del survey lo a\xF1ade otra vez en el contenedor, en
|
|
352
|
+
el formulario y en el bloque de cada pregunta, y eso deja el enunciado y las opciones m\xE1s
|
|
353
|
+
adentro que el logo, el t\xEDtulo y la barra de progreso. Solo el lateral; el vertical separa las
|
|
354
|
+
preguntas. Mismas reglas que en el popup DOM (renderPopup.ts). */
|
|
355
|
+
.deepdots-popup .magicfeedback-container,
|
|
356
|
+
.deepdots-popup .magicfeedback-form,
|
|
357
|
+
.deepdots-popup .magicfeedback-div{padding-left:0;padding-right:0}
|
|
319
358
|
#dd-logo{max-height:40px;max-width:100%;object-fit:contain;display:block;margin:12px 0 0 0}
|
|
320
359
|
.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}
|
|
321
360
|
/* Pantalla final: el HTML del editor de la plataforma (imagen + texto), centrado. */
|
|
@@ -323,7 +362,7 @@ body{display:${bodyDisplay};justify-content:${pos.justifyContent};align-items:${
|
|
|
323
362
|
.deepdots-success img{max-width:100%;height:auto;margin:0 auto 16px auto;display:block}
|
|
324
363
|
.deepdots-success p{margin:0;font-size:16px;font-weight:600;line-height:1.4}
|
|
325
364
|
.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}
|
|
326
|
-
.dd-nav-btn{display:none;border:none;min-height:44px;padding:12px 24px;border-radius:
|
|
365
|
+
.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}
|
|
327
366
|
/* Secundario como bot\xF3n de texto: sin borde ni fondo, para que el primario sea la \xFAnica CTA. */
|
|
328
367
|
#dd-back{background:transparent;color:${textMuted};border:none}
|
|
329
368
|
#dd-start,#dd-complete,#dd-submit{background:#1E293B;color:#fff;border:none}
|
|
@@ -548,9 +587,23 @@ ${customCss}
|
|
|
548
587
|
}
|
|
549
588
|
}
|
|
550
589
|
|
|
590
|
+
${PRIMARY_COLOR_JS}
|
|
591
|
+
${REVEAL_JS}
|
|
592
|
+
// El popup se ense\xF1a cuando el survey est\xE1 pintado; \`ready\` deja al host abrir su propio
|
|
593
|
+
// Modal en ese momento en vez de montar un WebView en blanco.
|
|
594
|
+
var ddReveal=ddCreateReveal(popup, function(){
|
|
595
|
+
document.body.classList.add('dd-ready');
|
|
596
|
+
emitJSON('ready');
|
|
597
|
+
}, ${REVEAL_TIMEOUT_MS});
|
|
598
|
+
|
|
551
599
|
function setLoading(isLoading){
|
|
552
600
|
spinner.style.display=isLoading?'flex':'none';
|
|
553
|
-
if(!isLoading){
|
|
601
|
+
if(!isLoading){
|
|
602
|
+
formHost.style.visibility='visible';
|
|
603
|
+
// Fin de la carga, sea por survey cargado o por error. Entre p\xE1ginas es no-op: la
|
|
604
|
+
// revelaci\xF3n solo act\xFAa la primera vez.
|
|
605
|
+
ddReveal.whenPainted();
|
|
606
|
+
}
|
|
554
607
|
footer.style.display=isLoading?'none':'flex';
|
|
555
608
|
backBtn.disabled=isLoading; startBtn.disabled=isLoading; completeBtn.disabled=isLoading; submitBtn.disabled=isLoading;
|
|
556
609
|
if(isLoading){ updateButtons(null); }
|
|
@@ -593,6 +646,10 @@ ${customCss}
|
|
|
593
646
|
if(s.loadingBarColor){ progressBar.style.background=s.loadingBarColor; progressFollowUp.style.background=s.loadingBarColor; }
|
|
594
647
|
if(chromeOn && s.boxBackgroundColor){ popup.style.background=s.boxBackgroundColor; }
|
|
595
648
|
if(s.contentAlign){ main.style.justifyContent = s.contentAlign==='center' ? 'center' : 'flex-start'; }
|
|
649
|
+
// El survey pinta sus controles con --mf-primary, que sale de primaryColor; si la
|
|
650
|
+
// integraci\xF3n solo configura el del bot\xF3n, el popup mezclar\xEDa el color de la marca
|
|
651
|
+
// con el gris azulado por defecto del paquete.
|
|
652
|
+
ddApplySurveyPrimaryColor(popup, s);
|
|
596
653
|
if(s.buttonPrimaryColor){
|
|
597
654
|
submitBtn.style.background=s.buttonPrimaryColor; submitBtn.style.border='none'; submitBtn.style.color='#fff';
|
|
598
655
|
startBtn.style.background=s.buttonPrimaryColor; startBtn.style.border='none'; startBtn.style.color='#fff';
|
|
@@ -684,6 +741,7 @@ ${customCss}
|
|
|
684
741
|
}
|
|
685
742
|
|
|
686
743
|
// src/platform/react-native-renderer.ts
|
|
744
|
+
var NATIVE_READY_GRACE_MS = 500;
|
|
687
745
|
var ReactNativePopupRenderer = class {
|
|
688
746
|
constructor(options = {}) {
|
|
689
747
|
this.options = options;
|
|
@@ -691,6 +749,8 @@ var ReactNativePopupRenderer = class {
|
|
|
691
749
|
this.onCloseFn = null;
|
|
692
750
|
this.currentSurveyId = null;
|
|
693
751
|
this.partialEmitted = false;
|
|
752
|
+
this.readyEmitted = false;
|
|
753
|
+
this.readyTimer = null;
|
|
694
754
|
}
|
|
695
755
|
init() {
|
|
696
756
|
}
|
|
@@ -699,6 +759,8 @@ var ReactNativePopupRenderer = class {
|
|
|
699
759
|
this.onCloseFn = onClose;
|
|
700
760
|
this.currentSurveyId = surveyId;
|
|
701
761
|
this.partialEmitted = false;
|
|
762
|
+
this.readyEmitted = false;
|
|
763
|
+
this.armReadyFallback(surveyId);
|
|
702
764
|
const { profile, metadata } = buildSurveyIdentity(userId ?? null, sessionId ?? null, miniService ?? null, analyticsFeedbackSessionId ?? null);
|
|
703
765
|
const html = buildSurveyHtml({
|
|
704
766
|
surveyId,
|
|
@@ -726,9 +788,32 @@ var ReactNativePopupRenderer = class {
|
|
|
726
788
|
}
|
|
727
789
|
}
|
|
728
790
|
hide() {
|
|
791
|
+
this.clearReadyFallback();
|
|
729
792
|
this.options.onHide?.();
|
|
730
793
|
this.currentSurveyId = null;
|
|
731
794
|
}
|
|
795
|
+
/** Respaldo del aviso de listo por si el WebView no llega a ejecutar el HTML. */
|
|
796
|
+
armReadyFallback(surveyId) {
|
|
797
|
+
this.clearReadyFallback();
|
|
798
|
+
if (!this.options.onReady) return;
|
|
799
|
+
this.readyTimer = setTimeout(() => {
|
|
800
|
+
this.readyTimer = null;
|
|
801
|
+
this.emitReady(surveyId);
|
|
802
|
+
}, REVEAL_TIMEOUT_MS + NATIVE_READY_GRACE_MS);
|
|
803
|
+
}
|
|
804
|
+
clearReadyFallback() {
|
|
805
|
+
if (this.readyTimer !== null) {
|
|
806
|
+
clearTimeout(this.readyTimer);
|
|
807
|
+
this.readyTimer = null;
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
/** Idempotente: el WebView puede avisar a la vez que vence el respaldo. */
|
|
811
|
+
emitReady(surveyId) {
|
|
812
|
+
if (this.readyEmitted) return;
|
|
813
|
+
this.readyEmitted = true;
|
|
814
|
+
this.clearReadyFallback();
|
|
815
|
+
this.options.onReady?.({ surveyId });
|
|
816
|
+
}
|
|
732
817
|
/**
|
|
733
818
|
* El host la conecta al `onMessage` del WebView. Traduce los mensajes del survey a
|
|
734
819
|
* eventos del SDK: primera interacción → `popup_clicked` (PARTIAL), completado →
|
|
@@ -744,6 +829,9 @@ var ReactNativePopupRenderer = class {
|
|
|
744
829
|
name = raw;
|
|
745
830
|
}
|
|
746
831
|
switch (name) {
|
|
832
|
+
case "ready":
|
|
833
|
+
this.emitReady(surveyId);
|
|
834
|
+
break;
|
|
747
835
|
case "loaded":
|
|
748
836
|
case "before_submit":
|
|
749
837
|
case "after_submit":
|
|
@@ -771,6 +859,33 @@ function createReactNativeRenderer() {
|
|
|
771
859
|
return new ReactNativePopupRenderer();
|
|
772
860
|
}
|
|
773
861
|
|
|
862
|
+
// src/ui/preload.ts
|
|
863
|
+
var defaultLoader = () => import("./renderPopup-5QXL6EJW.mjs");
|
|
864
|
+
var pending = null;
|
|
865
|
+
function preloadRenderPopup(loader = defaultLoader) {
|
|
866
|
+
if (pending) return pending;
|
|
867
|
+
try {
|
|
868
|
+
pending = loader().then(() => void 0).catch(() => {
|
|
869
|
+
pending = null;
|
|
870
|
+
});
|
|
871
|
+
} catch {
|
|
872
|
+
pending = null;
|
|
873
|
+
return Promise.resolve();
|
|
874
|
+
}
|
|
875
|
+
return pending;
|
|
876
|
+
}
|
|
877
|
+
function schedulePreloadRenderPopup(loader) {
|
|
878
|
+
const run = () => {
|
|
879
|
+
void preloadRenderPopup(loader);
|
|
880
|
+
};
|
|
881
|
+
const idle = globalThis.requestIdleCallback;
|
|
882
|
+
if (typeof idle === "function") {
|
|
883
|
+
idle(run, { timeout: 2e3 });
|
|
884
|
+
return;
|
|
885
|
+
}
|
|
886
|
+
setTimeout(run, 0);
|
|
887
|
+
}
|
|
888
|
+
|
|
774
889
|
// src/platform/renderer.ts
|
|
775
890
|
var NoopPopupRenderer = class {
|
|
776
891
|
show() {
|
|
@@ -805,13 +920,20 @@ var BrowserPopupRenderer = class {
|
|
|
805
920
|
document.body.appendChild(this.container);
|
|
806
921
|
}
|
|
807
922
|
}
|
|
923
|
+
/**
|
|
924
|
+
* Descarga el chunk de `renderPopup` antes de que ningún trigger dispare, para que abrir el
|
|
925
|
+
* popup no empiece por esperar ~238 KB de JS.
|
|
926
|
+
*/
|
|
927
|
+
preload() {
|
|
928
|
+
schedulePreloadRenderPopup();
|
|
929
|
+
}
|
|
808
930
|
show(surveyId, productId, actions, emit, onClose, env = "production", userId, style, sessionId, miniService, analyticsFeedbackSessionId, _renderChrome, options) {
|
|
809
931
|
if (this.visible) return;
|
|
810
932
|
if (!this.container || !document.body.contains(this.container)) this.init();
|
|
811
933
|
if (!this.container) return;
|
|
812
934
|
this.visible = true;
|
|
813
935
|
const container = this.container;
|
|
814
|
-
void import("./renderPopup-
|
|
936
|
+
void import("./renderPopup-5QXL6EJW.mjs").then(({ renderPopup }) => {
|
|
815
937
|
renderPopup(container, surveyId, productId, actions, emit, onClose, env, userId, style, sessionId, miniService, analyticsFeedbackSessionId, options);
|
|
816
938
|
});
|
|
817
939
|
}
|
|
@@ -819,6 +941,8 @@ var BrowserPopupRenderer = class {
|
|
|
819
941
|
this.visible = false;
|
|
820
942
|
if (this.container) {
|
|
821
943
|
this.container.style.display = "none";
|
|
944
|
+
this.container.style.visibility = "";
|
|
945
|
+
this.container.style.pointerEvents = "";
|
|
822
946
|
this.container.innerHTML = "";
|
|
823
947
|
}
|
|
824
948
|
}
|
|
@@ -1888,6 +2012,7 @@ var DeepdotsPopups = class {
|
|
|
1888
2012
|
this.popupDefinitions = this.validatePopupDefinitions(defs);
|
|
1889
2013
|
this.popupsLoaded = true;
|
|
1890
2014
|
this.log("Popups loaded from API", this.popupDefinitions);
|
|
2015
|
+
if (this.popupDefinitions.length) this.renderer.preload?.();
|
|
1891
2016
|
this.configureTriggersFromDefinitions();
|
|
1892
2017
|
this.processDeferredExitQueue();
|
|
1893
2018
|
if (this.pendingAutoLaunch) {
|
|
@@ -2375,7 +2500,7 @@ var DeepdotsPopups = class {
|
|
|
2375
2500
|
processDeferredExitQueue() {
|
|
2376
2501
|
const queue = this.getDeferredExitQueue();
|
|
2377
2502
|
if (!queue.length) return;
|
|
2378
|
-
const
|
|
2503
|
+
const pending2 = [];
|
|
2379
2504
|
const now = Date.now();
|
|
2380
2505
|
queue.forEach((item) => {
|
|
2381
2506
|
const def = this.popupDefinitions.find((popup) => popup.id === item.id && popup.surveyId === item.surveyId);
|
|
@@ -2386,10 +2511,10 @@ var DeepdotsPopups = class {
|
|
|
2386
2511
|
this.tryShowDeferredExitPopup(item);
|
|
2387
2512
|
return;
|
|
2388
2513
|
}
|
|
2389
|
-
|
|
2514
|
+
pending2.push(item);
|
|
2390
2515
|
this.scheduleDeferredExitPopup(item);
|
|
2391
2516
|
});
|
|
2392
|
-
this.setDeferredExitQueue(
|
|
2517
|
+
this.setDeferredExitQueue(pending2);
|
|
2393
2518
|
}
|
|
2394
2519
|
scheduleDeferredExitPopup(item) {
|
|
2395
2520
|
if (typeof window === "undefined") return;
|
|
@@ -2462,7 +2587,7 @@ var DeepdotsPopups = class {
|
|
|
2462
2587
|
async fetchPopupsFromServer() {
|
|
2463
2588
|
const apiKey = this.config?.apiKey;
|
|
2464
2589
|
const baseUrl = this.baseUrl;
|
|
2465
|
-
const userId = this.config?.userId;
|
|
2590
|
+
const userId = this.tracking?.getUserId() ?? this.config?.userId;
|
|
2466
2591
|
if (!apiKey || !baseUrl) {
|
|
2467
2592
|
this.log("Missing apiKey or baseUrl. Skipping popups fetch.");
|
|
2468
2593
|
return [];
|
|
@@ -2606,7 +2731,7 @@ var DeepdotsPopups = class {
|
|
|
2606
2731
|
}
|
|
2607
2732
|
if (!this.popupContainer) return;
|
|
2608
2733
|
const container = this.popupContainer;
|
|
2609
|
-
void import("./renderPopup-
|
|
2734
|
+
void import("./renderPopup-5QXL6EJW.mjs").then(({ renderPopup }) => {
|
|
2610
2735
|
renderPopup(
|
|
2611
2736
|
container,
|
|
2612
2737
|
surveyId,
|
|
@@ -2861,8 +2986,10 @@ export {
|
|
|
2861
2986
|
MAX_TRACKED_MESSAGES,
|
|
2862
2987
|
MESSAGE_CHANNELS,
|
|
2863
2988
|
MessageGuard,
|
|
2989
|
+
NATIVE_READY_GRACE_MS,
|
|
2864
2990
|
NoopPopupRenderer,
|
|
2865
2991
|
POPUP_TRIGGER_CONDITION_STATUSES,
|
|
2992
|
+
REVEAL_TIMEOUT_MS,
|
|
2866
2993
|
RTL_LOCALES,
|
|
2867
2994
|
ReactNativePopupRenderer,
|
|
2868
2995
|
SUPPORTED_LANGUAGES,
|