@magicfeedback/popup-sdk 1.7.2 → 1.8.1

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/dist/index.mjs CHANGED
@@ -1,4 +1,5 @@
1
1
  import {
2
+ BUSY_JS,
2
3
  InMemoryStorage,
3
4
  LABELS,
4
5
  PRIMARY_COLOR_JS,
@@ -20,7 +21,7 @@ import {
20
21
  sdkWarn,
21
22
  setLogger,
22
23
  style_default
23
- } from "./chunk-XHR3MHJO.mjs";
24
+ } from "./chunk-AV2TTQXB.mjs";
24
25
 
25
26
  // src/types/index.ts
26
27
  var POPUP_TRIGGER_CONDITION_STATUSES = [
@@ -429,6 +430,7 @@ ${customCss}
429
430
  var footer=document.getElementById('dd-footer');
430
431
  var spinner=document.getElementById('dd-spinner');
431
432
  var formHost=document.getElementById('mf');
433
+ var formWrapper=document.getElementById('dd-form-wrapper');
432
434
  var errorHint=document.getElementById('dd-error');
433
435
  var backBtn=document.getElementById('dd-back');
434
436
  var startBtn=document.getElementById('dd-start');
@@ -588,6 +590,7 @@ ${customCss}
588
590
  }
589
591
 
590
592
  ${PRIMARY_COLOR_JS}
593
+ ${BUSY_JS}
591
594
  ${REVEAL_JS}
592
595
  // El popup se ense\xF1a cuando el survey est\xE1 pintado; \`ready\` deja al host abrir su propio
593
596
  // Modal en ese momento en vez de montar un WebView en blanco.
@@ -598,6 +601,11 @@ ${REVEAL_JS}
598
601
 
599
602
  function setLoading(isLoading){
600
603
  spinner.style.display=isLoading?'flex':'none';
604
+ // El spinner no tapa el survey (28px en posicion absoluta), asi que sin esto el usuario
605
+ // puede seguir cambiando de opcion mientras se envia la pagina, y ese cambio ya no viaja
606
+ // con ella. Se bloquea el wrapper, que es el elemento estable: el div de dentro lo
607
+ // sustituye @magicfeedback/native por su propio contenedor al generar el survey.
608
+ ddSetSurveyBusy(formWrapper, isLoading);
601
609
  if(!isLoading){
602
610
  formHost.style.visibility='visible';
603
611
  // Fin de la carga, sea por survey cargado o por error. Entre p\xE1ginas es no-op: la
@@ -860,7 +868,7 @@ function createReactNativeRenderer() {
860
868
  }
861
869
 
862
870
  // src/ui/preload.ts
863
- var defaultLoader = () => import("./renderPopup-5QXL6EJW.mjs");
871
+ var defaultLoader = () => import("./renderPopup-3CZ6WTXF.mjs");
864
872
  var pending = null;
865
873
  function preloadRenderPopup(loader = defaultLoader) {
866
874
  if (pending) return pending;
@@ -933,7 +941,7 @@ var BrowserPopupRenderer = class {
933
941
  if (!this.container) return;
934
942
  this.visible = true;
935
943
  const container = this.container;
936
- void import("./renderPopup-5QXL6EJW.mjs").then(({ renderPopup }) => {
944
+ void import("./renderPopup-3CZ6WTXF.mjs").then(({ renderPopup }) => {
937
945
  renderPopup(container, surveyId, productId, actions, emit, onClose, env, userId, style, sessionId, miniService, analyticsFeedbackSessionId, options);
938
946
  });
939
947
  }
@@ -2371,6 +2379,9 @@ var DeepdotsPopups = class {
2371
2379
  this.emitEvent("popup_shown", def.surveyId, { popupId: def.id });
2372
2380
  }
2373
2381
  shouldShow(def, pathUrl, skipPathCheck = false) {
2382
+ if (this.isPathExcluded(def, pathUrl)) {
2383
+ return false;
2384
+ }
2374
2385
  if (!skipPathCheck && !this.matchesSegmentsPath(def, pathUrl)) {
2375
2386
  return false;
2376
2387
  }
@@ -2401,40 +2412,85 @@ var DeepdotsPopups = class {
2401
2412
  }
2402
2413
  return matches;
2403
2414
  }
2415
+ /** `segments.path`: rutas donde el popup PUEDE mostrarse. Sin lista, en todas. */
2404
2416
  matchesSegmentsPath(def, pathUrl) {
2405
2417
  const paths = def.segments?.path;
2406
- if (!paths || paths.length === 0) return true;
2407
- if (typeof window === "undefined" || !window.location) {
2418
+ if (!Array.isArray(paths) || paths.length === 0) return true;
2419
+ const location = this.resolveCurrentLocation(pathUrl);
2420
+ if (!location) {
2408
2421
  this.debug("No window.location available for path comparison", { popupId: def.id, paths });
2409
2422
  return true;
2410
2423
  }
2411
- const normalizedHref = this.normalizeUrl(pathUrl || window.location.href || "");
2412
- const currentUrl = this.safeParseUrl(normalizedHref);
2413
- const normalizedPath = this.normalizeUrl(currentUrl?.pathname || window.location.pathname || "");
2414
2424
  const matches = paths.some((rawCandidate) => {
2415
- const candidate = this.normalizeUrl(rawCandidate);
2416
- let match = false;
2417
- if (candidate.startsWith("http://") || candidate.startsWith("https://")) {
2418
- match = normalizedHref === candidate;
2419
- } else if (candidate.startsWith("/")) {
2420
- match = normalizedHref.includes(candidate);
2421
- } else {
2422
- match = normalizedPath === candidate;
2423
- }
2425
+ const match = this.matchesPathCandidate(rawCandidate, location);
2424
2426
  this.debug("Path comparison", {
2425
2427
  popupId: def.id,
2426
- candidate,
2427
- currentPath: normalizedPath,
2428
- currentHref: normalizedHref,
2428
+ candidate: rawCandidate,
2429
+ currentPath: location.path,
2430
+ currentHref: location.href,
2429
2431
  match
2430
2432
  });
2431
2433
  return match;
2432
2434
  });
2433
2435
  if (!matches) {
2434
- this.debug("No path match for popup", { popupId: def.id, paths, currentPath: normalizedPath });
2436
+ this.debug("No path match for popup", { popupId: def.id, paths, currentPath: location.path });
2435
2437
  }
2436
2438
  return matches;
2437
2439
  }
2440
+ /**
2441
+ * `segments.excludedPaths`: rutas donde el popup NO debe mostrarse. Gana sobre
2442
+ * `segments.path` (`path: ['/']` + `excludedPaths: ['/cart']` = en todas menos el
2443
+ * carrito) y se aplica también cuando no hay `path` (= en todas menos las excluidas).
2444
+ */
2445
+ isPathExcluded(def, pathUrl) {
2446
+ const excluded = def.segments?.excludedPaths;
2447
+ if (!Array.isArray(excluded) || excluded.length === 0) return false;
2448
+ const location = this.resolveCurrentLocation(pathUrl);
2449
+ if (!location) {
2450
+ this.debug("No window.location available for excluded path comparison", { popupId: def.id, excluded });
2451
+ return false;
2452
+ }
2453
+ const hit = excluded.find((rawCandidate) => this.matchesPathCandidate(rawCandidate, location));
2454
+ if (hit !== void 0) {
2455
+ this.debug("Popup excluded by path", {
2456
+ popupId: def.id,
2457
+ candidate: hit,
2458
+ currentPath: location.path,
2459
+ currentHref: location.href
2460
+ });
2461
+ return true;
2462
+ }
2463
+ return false;
2464
+ }
2465
+ /**
2466
+ * Compara UN candidato de `segments.path`/`segments.excludedPaths` con la ruta
2467
+ * actual. Mismas reglas para incluir y para excluir:
2468
+ * - URL absoluta → href completo exacto
2469
+ * - empieza por / → subcadena del href (así entran las rutas con hash: `/#/home`)
2470
+ * - resto → pathname exacto
2471
+ * Ignora entradas que no sean string: el backend puede colar un `null` en la lista
2472
+ * y no puede tumbar la evaluación del trigger entero (mismo fallo que hubo con
2473
+ * `segments.lang`).
2474
+ */
2475
+ matchesPathCandidate(rawCandidate, location) {
2476
+ if (typeof rawCandidate !== "string") return false;
2477
+ const candidate = this.normalizeUrl(rawCandidate);
2478
+ if (!candidate) return false;
2479
+ if (candidate.startsWith("http://") || candidate.startsWith("https://")) {
2480
+ return location.href === candidate;
2481
+ }
2482
+ if (candidate.startsWith("/")) {
2483
+ return location.href.includes(candidate);
2484
+ }
2485
+ return location.path === candidate;
2486
+ }
2487
+ /** href + pathname normalizados de la ruta a evaluar, o null si no hay `window.location`. */
2488
+ resolveCurrentLocation(pathUrl) {
2489
+ if (typeof window === "undefined" || !window.location) return null;
2490
+ const href = this.normalizeUrl(pathUrl || window.location.href || "");
2491
+ const parsed = this.safeParseUrl(href);
2492
+ return { href, path: this.normalizeUrl(parsed?.pathname || window.location.pathname || "") };
2493
+ }
2438
2494
  evaluateCooldown(def, condition) {
2439
2495
  switch (condition.answered) {
2440
2496
  case "SHOWED":
@@ -2731,7 +2787,7 @@ var DeepdotsPopups = class {
2731
2787
  }
2732
2788
  if (!this.popupContainer) return;
2733
2789
  const container = this.popupContainer;
2734
- void import("./renderPopup-5QXL6EJW.mjs").then(({ renderPopup }) => {
2790
+ void import("./renderPopup-3CZ6WTXF.mjs").then(({ renderPopup }) => {
2735
2791
  renderPopup(
2736
2792
  container,
2737
2793
  surveyId,