@magicfeedback/popup-sdk 1.7.1 → 1.8.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.
@@ -1,6 +1,8 @@
1
1
  import {
2
2
  LABELS,
3
+ PRIMARY_COLOR_JS,
3
4
  RESOLVE_LOCALE_JS,
5
+ REVEAL_TIMEOUT_MS,
4
6
  RTL_LOCALES,
5
7
  STORAGE_KEYS,
6
8
  TrackingManager,
@@ -15,7 +17,7 @@ import {
15
17
  sdkWarn,
16
18
  setLogger,
17
19
  style_default
18
- } from "./chunk-WNIUIOKF.mjs";
20
+ } from "./chunk-322DDMX6.mjs";
19
21
 
20
22
  // src/react-native/index.tsx
21
23
  import { createContext, useContext, useEffect, useRef, useState } from "react";
@@ -211,6 +213,30 @@ function resolveEnvironment(nodeEnv) {
211
213
  }
212
214
 
213
215
  // src/ui/surveyHtml.ts
216
+ var REVEAL_JS = `
217
+ function ddCreateReveal(popup, onReveal, timeoutMs){
218
+ var revealed=false, timer=null;
219
+ function reveal(){
220
+ if(revealed){ return; }
221
+ revealed=true;
222
+ if(timer){ clearTimeout(timer); timer=null; }
223
+ onReveal();
224
+ }
225
+ function revealWhenPainted(){
226
+ if(revealed){ return; }
227
+ var imgs=popup.querySelectorAll('img'), pending=[];
228
+ for(var i=0;i<imgs.length;i++){ if(!imgs[i].complete){ pending.push(imgs[i]); } }
229
+ if(!pending.length){ reveal(); return; }
230
+ var left=pending.length;
231
+ function onSettled(){ left--; if(left<=0){ reveal(); } }
232
+ for(var j=0;j<pending.length;j++){
233
+ pending[j].addEventListener('load', onSettled);
234
+ pending[j].addEventListener('error', onSettled);
235
+ }
236
+ }
237
+ timer=setTimeout(reveal, timeoutMs);
238
+ return { reveal: reveal, whenPainted: revealWhenPainted };
239
+ }`;
214
240
  var POSITION_MAP = {
215
241
  center: { justifyContent: "center", alignItems: "center", padding: "0", background: "rgba(0,0,0,0.5)" },
216
242
  bottom: { justifyContent: "center", alignItems: "flex-end", padding: "16px", background: "transparent" },
@@ -284,7 +310,13 @@ function buildSurveyHtml(opts) {
284
310
  ${style_default}
285
311
  ${fontFaceCss}
286
312
  html,body{margin:0;padding:0;height:100%;font-family:${fontFamilyValue}}
287
- body{display:${bodyDisplay};justify-content:${pos.justifyContent};align-items:${pos.alignItems};background:${bodyBg};padding:${bodyPadding};box-sizing:border-box}
313
+ /* Apertura diferida: ni la tarjeta ni el velo se pintan hasta que el survey est\xE1 listo
314
+ (\`dd-ready\`). Si el fondo entrara antes, en RN se ver\xEDa el velo oscuro varios cientos de ms
315
+ antes que el contenido, que es la misma mala sensaci\xF3n que el spinner. */
316
+ body{display:${bodyDisplay};justify-content:${pos.justifyContent};align-items:${pos.alignItems};background:transparent;padding:${bodyPadding};box-sizing:border-box}
317
+ body.dd-ready{background:${bodyBg}}
318
+ #dd-popup{visibility:hidden}
319
+ body.dd-ready #dd-popup{visibility:visible}
288
320
  .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}
289
321
  .deepdots-popup-header{display:flex;justify-content:space-between;align-items:center;gap:12px;width:100%;flex:0 0 auto}
290
322
  /* Neutraliza la regla \`.deepdots-popup h2\` del CSS del survey (uppercase, centrado y
@@ -318,6 +350,13 @@ body{display:${bodyDisplay};justify-content:${pos.justifyContent};align-items:${
318
350
  #dd-form-wrapper{width:100%;flex:1 1 auto}
319
351
  #mf{width:100%;box-sizing:border-box;visibility:hidden}
320
352
  .deepdots-popup-main *{max-width:100%;box-sizing:border-box}
353
+ /* El margen lateral lo pone la tarjeta: el CSS del survey lo a\xF1ade otra vez en el contenedor, en
354
+ el formulario y en el bloque de cada pregunta, y eso deja el enunciado y las opciones m\xE1s
355
+ adentro que el logo, el t\xEDtulo y la barra de progreso. Solo el lateral; el vertical separa las
356
+ preguntas. Mismas reglas que en el popup DOM (renderPopup.ts). */
357
+ .deepdots-popup .magicfeedback-container,
358
+ .deepdots-popup .magicfeedback-form,
359
+ .deepdots-popup .magicfeedback-div{padding-left:0;padding-right:0}
321
360
  #dd-logo{max-height:40px;max-width:100%;object-fit:contain;display:block;margin:12px 0 0 0}
322
361
  .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}
323
362
  /* Pantalla final: el HTML del editor de la plataforma (imagen + texto), centrado. */
@@ -325,7 +364,7 @@ body{display:${bodyDisplay};justify-content:${pos.justifyContent};align-items:${
325
364
  .deepdots-success img{max-width:100%;height:auto;margin:0 auto 16px auto;display:block}
326
365
  .deepdots-success p{margin:0;font-size:16px;font-weight:600;line-height:1.4}
327
366
  .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}
328
- .dd-nav-btn{display:none;border:none;min-height:44px;padding:12px 24px;border-radius:6px;cursor:pointer;font-size:15px;font-weight:600;align-items:center;justify-content:center;text-align:center}
367
+ .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}
329
368
  /* Secundario como bot\xF3n de texto: sin borde ni fondo, para que el primario sea la \xFAnica CTA. */
330
369
  #dd-back{background:transparent;color:${textMuted};border:none}
331
370
  #dd-start,#dd-complete,#dd-submit{background:#1E293B;color:#fff;border:none}
@@ -550,9 +589,23 @@ ${customCss}
550
589
  }
551
590
  }
552
591
 
592
+ ${PRIMARY_COLOR_JS}
593
+ ${REVEAL_JS}
594
+ // El popup se ense\xF1a cuando el survey est\xE1 pintado; \`ready\` deja al host abrir su propio
595
+ // Modal en ese momento en vez de montar un WebView en blanco.
596
+ var ddReveal=ddCreateReveal(popup, function(){
597
+ document.body.classList.add('dd-ready');
598
+ emitJSON('ready');
599
+ }, ${REVEAL_TIMEOUT_MS});
600
+
553
601
  function setLoading(isLoading){
554
602
  spinner.style.display=isLoading?'flex':'none';
555
- if(!isLoading){ formHost.style.visibility='visible'; }
603
+ if(!isLoading){
604
+ formHost.style.visibility='visible';
605
+ // Fin de la carga, sea por survey cargado o por error. Entre p\xE1ginas es no-op: la
606
+ // revelaci\xF3n solo act\xFAa la primera vez.
607
+ ddReveal.whenPainted();
608
+ }
556
609
  footer.style.display=isLoading?'none':'flex';
557
610
  backBtn.disabled=isLoading; startBtn.disabled=isLoading; completeBtn.disabled=isLoading; submitBtn.disabled=isLoading;
558
611
  if(isLoading){ updateButtons(null); }
@@ -595,6 +648,10 @@ ${customCss}
595
648
  if(s.loadingBarColor){ progressBar.style.background=s.loadingBarColor; progressFollowUp.style.background=s.loadingBarColor; }
596
649
  if(chromeOn && s.boxBackgroundColor){ popup.style.background=s.boxBackgroundColor; }
597
650
  if(s.contentAlign){ main.style.justifyContent = s.contentAlign==='center' ? 'center' : 'flex-start'; }
651
+ // El survey pinta sus controles con --mf-primary, que sale de primaryColor; si la
652
+ // integraci\xF3n solo configura el del bot\xF3n, el popup mezclar\xEDa el color de la marca
653
+ // con el gris azulado por defecto del paquete.
654
+ ddApplySurveyPrimaryColor(popup, s);
598
655
  if(s.buttonPrimaryColor){
599
656
  submitBtn.style.background=s.buttonPrimaryColor; submitBtn.style.border='none'; submitBtn.style.color='#fff';
600
657
  startBtn.style.background=s.buttonPrimaryColor; startBtn.style.border='none'; startBtn.style.color='#fff';
@@ -686,6 +743,7 @@ ${customCss}
686
743
  }
687
744
 
688
745
  // src/platform/react-native-renderer.ts
746
+ var NATIVE_READY_GRACE_MS = 500;
689
747
  var ReactNativePopupRenderer = class {
690
748
  constructor(options = {}) {
691
749
  this.options = options;
@@ -693,6 +751,8 @@ var ReactNativePopupRenderer = class {
693
751
  this.onCloseFn = null;
694
752
  this.currentSurveyId = null;
695
753
  this.partialEmitted = false;
754
+ this.readyEmitted = false;
755
+ this.readyTimer = null;
696
756
  }
697
757
  init() {
698
758
  }
@@ -701,6 +761,8 @@ var ReactNativePopupRenderer = class {
701
761
  this.onCloseFn = onClose;
702
762
  this.currentSurveyId = surveyId;
703
763
  this.partialEmitted = false;
764
+ this.readyEmitted = false;
765
+ this.armReadyFallback(surveyId);
704
766
  const { profile, metadata } = buildSurveyIdentity(userId ?? null, sessionId ?? null, miniService ?? null, analyticsFeedbackSessionId ?? null);
705
767
  const html = buildSurveyHtml({
706
768
  surveyId,
@@ -728,9 +790,32 @@ var ReactNativePopupRenderer = class {
728
790
  }
729
791
  }
730
792
  hide() {
793
+ this.clearReadyFallback();
731
794
  this.options.onHide?.();
732
795
  this.currentSurveyId = null;
733
796
  }
797
+ /** Respaldo del aviso de listo por si el WebView no llega a ejecutar el HTML. */
798
+ armReadyFallback(surveyId) {
799
+ this.clearReadyFallback();
800
+ if (!this.options.onReady) return;
801
+ this.readyTimer = setTimeout(() => {
802
+ this.readyTimer = null;
803
+ this.emitReady(surveyId);
804
+ }, REVEAL_TIMEOUT_MS + NATIVE_READY_GRACE_MS);
805
+ }
806
+ clearReadyFallback() {
807
+ if (this.readyTimer !== null) {
808
+ clearTimeout(this.readyTimer);
809
+ this.readyTimer = null;
810
+ }
811
+ }
812
+ /** Idempotente: el WebView puede avisar a la vez que vence el respaldo. */
813
+ emitReady(surveyId) {
814
+ if (this.readyEmitted) return;
815
+ this.readyEmitted = true;
816
+ this.clearReadyFallback();
817
+ this.options.onReady?.({ surveyId });
818
+ }
734
819
  /**
735
820
  * El host la conecta al `onMessage` del WebView. Traduce los mensajes del survey a
736
821
  * eventos del SDK: primera interacción → `popup_clicked` (PARTIAL), completado →
@@ -746,6 +831,9 @@ var ReactNativePopupRenderer = class {
746
831
  name = raw;
747
832
  }
748
833
  switch (name) {
834
+ case "ready":
835
+ this.emitReady(surveyId);
836
+ break;
749
837
  case "loaded":
750
838
  case "before_submit":
751
839
  case "after_submit":
@@ -773,6 +861,33 @@ function createReactNativeRenderer() {
773
861
  return new ReactNativePopupRenderer();
774
862
  }
775
863
 
864
+ // src/ui/preload.ts
865
+ var defaultLoader = () => import("./renderPopup-SNDPX5RX.mjs");
866
+ var pending = null;
867
+ function preloadRenderPopup(loader = defaultLoader) {
868
+ if (pending) return pending;
869
+ try {
870
+ pending = loader().then(() => void 0).catch(() => {
871
+ pending = null;
872
+ });
873
+ } catch {
874
+ pending = null;
875
+ return Promise.resolve();
876
+ }
877
+ return pending;
878
+ }
879
+ function schedulePreloadRenderPopup(loader) {
880
+ const run = () => {
881
+ void preloadRenderPopup(loader);
882
+ };
883
+ const idle = globalThis.requestIdleCallback;
884
+ if (typeof idle === "function") {
885
+ idle(run, { timeout: 2e3 });
886
+ return;
887
+ }
888
+ setTimeout(run, 0);
889
+ }
890
+
776
891
  // src/platform/renderer.ts
777
892
  var NoopPopupRenderer = class {
778
893
  show() {
@@ -807,13 +922,20 @@ var BrowserPopupRenderer = class {
807
922
  document.body.appendChild(this.container);
808
923
  }
809
924
  }
925
+ /**
926
+ * Descarga el chunk de `renderPopup` antes de que ningún trigger dispare, para que abrir el
927
+ * popup no empiece por esperar ~238 KB de JS.
928
+ */
929
+ preload() {
930
+ schedulePreloadRenderPopup();
931
+ }
810
932
  show(surveyId, productId, actions, emit, onClose, env = "production", userId, style, sessionId, miniService, analyticsFeedbackSessionId, _renderChrome, options) {
811
933
  if (this.visible) return;
812
934
  if (!this.container || !document.body.contains(this.container)) this.init();
813
935
  if (!this.container) return;
814
936
  this.visible = true;
815
937
  const container = this.container;
816
- void import("./renderPopup-EWGKG53W.mjs").then(({ renderPopup }) => {
938
+ void import("./renderPopup-SNDPX5RX.mjs").then(({ renderPopup }) => {
817
939
  renderPopup(container, surveyId, productId, actions, emit, onClose, env, userId, style, sessionId, miniService, analyticsFeedbackSessionId, options);
818
940
  });
819
941
  }
@@ -821,6 +943,8 @@ var BrowserPopupRenderer = class {
821
943
  this.visible = false;
822
944
  if (this.container) {
823
945
  this.container.style.display = "none";
946
+ this.container.style.visibility = "";
947
+ this.container.style.pointerEvents = "";
824
948
  this.container.innerHTML = "";
825
949
  }
826
950
  }
@@ -1890,6 +2014,7 @@ var DeepdotsPopups = class {
1890
2014
  this.popupDefinitions = this.validatePopupDefinitions(defs);
1891
2015
  this.popupsLoaded = true;
1892
2016
  this.log("Popups loaded from API", this.popupDefinitions);
2017
+ if (this.popupDefinitions.length) this.renderer.preload?.();
1893
2018
  this.configureTriggersFromDefinitions();
1894
2019
  this.processDeferredExitQueue();
1895
2020
  if (this.pendingAutoLaunch) {
@@ -2248,6 +2373,9 @@ var DeepdotsPopups = class {
2248
2373
  this.emitEvent("popup_shown", def.surveyId, { popupId: def.id });
2249
2374
  }
2250
2375
  shouldShow(def, pathUrl, skipPathCheck = false) {
2376
+ if (this.isPathExcluded(def, pathUrl)) {
2377
+ return false;
2378
+ }
2251
2379
  if (!skipPathCheck && !this.matchesSegmentsPath(def, pathUrl)) {
2252
2380
  return false;
2253
2381
  }
@@ -2278,40 +2406,85 @@ var DeepdotsPopups = class {
2278
2406
  }
2279
2407
  return matches;
2280
2408
  }
2409
+ /** `segments.path`: rutas donde el popup PUEDE mostrarse. Sin lista, en todas. */
2281
2410
  matchesSegmentsPath(def, pathUrl) {
2282
2411
  const paths = def.segments?.path;
2283
- if (!paths || paths.length === 0) return true;
2284
- if (typeof window === "undefined" || !window.location) {
2412
+ if (!Array.isArray(paths) || paths.length === 0) return true;
2413
+ const location = this.resolveCurrentLocation(pathUrl);
2414
+ if (!location) {
2285
2415
  this.debug("No window.location available for path comparison", { popupId: def.id, paths });
2286
2416
  return true;
2287
2417
  }
2288
- const normalizedHref = this.normalizeUrl(pathUrl || window.location.href || "");
2289
- const currentUrl = this.safeParseUrl(normalizedHref);
2290
- const normalizedPath = this.normalizeUrl(currentUrl?.pathname || window.location.pathname || "");
2291
2418
  const matches = paths.some((rawCandidate) => {
2292
- const candidate = this.normalizeUrl(rawCandidate);
2293
- let match = false;
2294
- if (candidate.startsWith("http://") || candidate.startsWith("https://")) {
2295
- match = normalizedHref === candidate;
2296
- } else if (candidate.startsWith("/")) {
2297
- match = normalizedHref.includes(candidate);
2298
- } else {
2299
- match = normalizedPath === candidate;
2300
- }
2419
+ const match = this.matchesPathCandidate(rawCandidate, location);
2301
2420
  this.debug("Path comparison", {
2302
2421
  popupId: def.id,
2303
- candidate,
2304
- currentPath: normalizedPath,
2305
- currentHref: normalizedHref,
2422
+ candidate: rawCandidate,
2423
+ currentPath: location.path,
2424
+ currentHref: location.href,
2306
2425
  match
2307
2426
  });
2308
2427
  return match;
2309
2428
  });
2310
2429
  if (!matches) {
2311
- this.debug("No path match for popup", { popupId: def.id, paths, currentPath: normalizedPath });
2430
+ this.debug("No path match for popup", { popupId: def.id, paths, currentPath: location.path });
2312
2431
  }
2313
2432
  return matches;
2314
2433
  }
2434
+ /**
2435
+ * `segments.excludedPaths`: rutas donde el popup NO debe mostrarse. Gana sobre
2436
+ * `segments.path` (`path: ['/']` + `excludedPaths: ['/cart']` = en todas menos el
2437
+ * carrito) y se aplica también cuando no hay `path` (= en todas menos las excluidas).
2438
+ */
2439
+ isPathExcluded(def, pathUrl) {
2440
+ const excluded = def.segments?.excludedPaths;
2441
+ if (!Array.isArray(excluded) || excluded.length === 0) return false;
2442
+ const location = this.resolveCurrentLocation(pathUrl);
2443
+ if (!location) {
2444
+ this.debug("No window.location available for excluded path comparison", { popupId: def.id, excluded });
2445
+ return false;
2446
+ }
2447
+ const hit = excluded.find((rawCandidate) => this.matchesPathCandidate(rawCandidate, location));
2448
+ if (hit !== void 0) {
2449
+ this.debug("Popup excluded by path", {
2450
+ popupId: def.id,
2451
+ candidate: hit,
2452
+ currentPath: location.path,
2453
+ currentHref: location.href
2454
+ });
2455
+ return true;
2456
+ }
2457
+ return false;
2458
+ }
2459
+ /**
2460
+ * Compara UN candidato de `segments.path`/`segments.excludedPaths` con la ruta
2461
+ * actual. Mismas reglas para incluir y para excluir:
2462
+ * - URL absoluta → href completo exacto
2463
+ * - empieza por / → subcadena del href (así entran las rutas con hash: `/#/home`)
2464
+ * - resto → pathname exacto
2465
+ * Ignora entradas que no sean string: el backend puede colar un `null` en la lista
2466
+ * y no puede tumbar la evaluación del trigger entero (mismo fallo que hubo con
2467
+ * `segments.lang`).
2468
+ */
2469
+ matchesPathCandidate(rawCandidate, location) {
2470
+ if (typeof rawCandidate !== "string") return false;
2471
+ const candidate = this.normalizeUrl(rawCandidate);
2472
+ if (!candidate) return false;
2473
+ if (candidate.startsWith("http://") || candidate.startsWith("https://")) {
2474
+ return location.href === candidate;
2475
+ }
2476
+ if (candidate.startsWith("/")) {
2477
+ return location.href.includes(candidate);
2478
+ }
2479
+ return location.path === candidate;
2480
+ }
2481
+ /** href + pathname normalizados de la ruta a evaluar, o null si no hay `window.location`. */
2482
+ resolveCurrentLocation(pathUrl) {
2483
+ if (typeof window === "undefined" || !window.location) return null;
2484
+ const href = this.normalizeUrl(pathUrl || window.location.href || "");
2485
+ const parsed = this.safeParseUrl(href);
2486
+ return { href, path: this.normalizeUrl(parsed?.pathname || window.location.pathname || "") };
2487
+ }
2315
2488
  evaluateCooldown(def, condition) {
2316
2489
  switch (condition.answered) {
2317
2490
  case "SHOWED":
@@ -2377,7 +2550,7 @@ var DeepdotsPopups = class {
2377
2550
  processDeferredExitQueue() {
2378
2551
  const queue = this.getDeferredExitQueue();
2379
2552
  if (!queue.length) return;
2380
- const pending = [];
2553
+ const pending2 = [];
2381
2554
  const now = Date.now();
2382
2555
  queue.forEach((item) => {
2383
2556
  const def = this.popupDefinitions.find((popup) => popup.id === item.id && popup.surveyId === item.surveyId);
@@ -2388,10 +2561,10 @@ var DeepdotsPopups = class {
2388
2561
  this.tryShowDeferredExitPopup(item);
2389
2562
  return;
2390
2563
  }
2391
- pending.push(item);
2564
+ pending2.push(item);
2392
2565
  this.scheduleDeferredExitPopup(item);
2393
2566
  });
2394
- this.setDeferredExitQueue(pending);
2567
+ this.setDeferredExitQueue(pending2);
2395
2568
  }
2396
2569
  scheduleDeferredExitPopup(item) {
2397
2570
  if (typeof window === "undefined") return;
@@ -2464,7 +2637,7 @@ var DeepdotsPopups = class {
2464
2637
  async fetchPopupsFromServer() {
2465
2638
  const apiKey = this.config?.apiKey;
2466
2639
  const baseUrl = this.baseUrl;
2467
- const userId = this.config?.userId;
2640
+ const userId = this.tracking?.getUserId() ?? this.config?.userId;
2468
2641
  if (!apiKey || !baseUrl) {
2469
2642
  this.log("Missing apiKey or baseUrl. Skipping popups fetch.");
2470
2643
  return [];
@@ -2608,7 +2781,7 @@ var DeepdotsPopups = class {
2608
2781
  }
2609
2782
  if (!this.popupContainer) return;
2610
2783
  const container = this.popupContainer;
2611
- void import("./renderPopup-EWGKG53W.mjs").then(({ renderPopup }) => {
2784
+ void import("./renderPopup-SNDPX5RX.mjs").then(({ renderPopup }) => {
2612
2785
  renderPopup(
2613
2786
  container,
2614
2787
  surveyId,
@@ -2889,16 +3062,24 @@ function DeepdotsProvider({ config, children }) {
2889
3062
  }, []);
2890
3063
  return /* @__PURE__ */ jsxs(DeepdotsContext.Provider, { value: sdk, children: [
2891
3064
  children,
2892
- survey ? /* @__PURE__ */ jsx(Modal, { visible: true, transparent: true, animationType: "slide", children: /* @__PURE__ */ jsx(View, { style: { flex: 1 }, children: /* @__PURE__ */ jsx(
2893
- WebView,
2894
- {
2895
- style: { flex: 1 },
2896
- originWhitelist: ["*"],
2897
- javaScriptEnabled: true,
2898
- source: { html: survey.html, baseUrl: "https://sdk.deepdots.com/" },
2899
- onMessage: (e) => rendererRef.current?.handleMessage(e.nativeEvent.data)
2900
- }
2901
- ) }) }) : null
3065
+ survey ? (
3066
+ // El Modal se abre en cuanto hay popup, y es el HTML del WebView el que se revela solo
3067
+ // cuando el survey está pintado (apertura diferida): con el Modal transparente, hasta ese
3068
+ // momento no se ve nada, ni velo ni spinner. No se difiere el Modal con `onReady` porque
3069
+ // React Native no monta los hijos de un Modal cerrado: el WebView no llegaría a cargar y
3070
+ // el aviso no llegaría nunca. El host que quiera diferir su contenedor debe montar el
3071
+ // WebView invisible (ver el ejemplo de `ReactNativePopupRenderer`).
3072
+ /* @__PURE__ */ jsx(Modal, { visible: true, transparent: true, animationType: "slide", children: /* @__PURE__ */ jsx(View, { style: { flex: 1 }, children: /* @__PURE__ */ jsx(
3073
+ WebView,
3074
+ {
3075
+ style: { flex: 1 },
3076
+ originWhitelist: ["*"],
3077
+ javaScriptEnabled: true,
3078
+ source: { html: survey.html, baseUrl: "https://sdk.deepdots.com/" },
3079
+ onMessage: (e) => rendererRef.current?.handleMessage(e.nativeEvent.data)
3080
+ }
3081
+ ) }) })
3082
+ ) : null
2902
3083
  ] });
2903
3084
  }
2904
3085
  export {