@magicfeedback/popup-sdk 1.6.0 → 1.7.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,15 +1,24 @@
1
1
  import {
2
2
  InMemoryStorage,
3
+ LABELS,
4
+ RESOLVE_LOCALE_JS,
5
+ RTL_LOCALES,
3
6
  STORAGE_KEYS,
7
+ SUPPORTED_LANGUAGES,
4
8
  TrackingManager,
5
9
  buildFontFaceCss,
6
10
  buildFontFamilyValue,
7
11
  buildSurveyIdentity,
8
12
  createDefaultStorage,
13
+ directionFor,
14
+ getLabels,
15
+ isRtlLanguage,
16
+ resolveActionLabels,
17
+ resolveLocale,
9
18
  sdkWarn,
10
19
  setLogger,
11
20
  style_default
12
- } from "./chunk-AN7JIVWB.mjs";
21
+ } from "./chunk-W6MPSWMS.mjs";
13
22
 
14
23
  // src/types/index.ts
15
24
  var POPUP_TRIGGER_CONDITION_STATUSES = [
@@ -212,9 +221,13 @@ var POSITION_MAP = {
212
221
  function jsonForScript(value) {
213
222
  return JSON.stringify(value ?? null).replace(/</g, "\\u003C").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
214
223
  }
224
+ function trimmedOrNull(value) {
225
+ const trimmed = typeof value === "string" ? value.trim() : "";
226
+ return trimmed ? value : null;
227
+ }
215
228
  function buildSurveyHtml(opts) {
216
229
  const env = opts.env === "development" ? "dev" : "prod";
217
- const version = opts.version ?? "2.2.8";
230
+ const version = opts.version ?? "2.2.22";
218
231
  const cdn = `https://cdn.jsdelivr.net/npm/@magicfeedback/native@${version}/dist/magicfeedback-sdk.browser.js`;
219
232
  const sid = jsonForScript(opts.surveyId);
220
233
  const pid = jsonForScript(opts.productId);
@@ -246,10 +259,22 @@ function buildSurveyHtml(opts) {
246
259
  const titleJson = jsonForScript(opts.title ?? "");
247
260
  const customCss = (opts.surveyCss ?? "").replace(/<\/\s*style/gi, "<\\/style");
248
261
  const progressPref = opts.showProgressBar === void 0 ? "null" : String(opts.showProgressBar);
249
- const backLabel = jsonForScript(opts.actions?.back?.label ?? "Back");
250
- const startLabel = jsonForScript(opts.actions?.start?.label ?? "Start survey");
251
- const completeLabel = jsonForScript(opts.actions?.complete?.label ?? "Complete survey");
252
- const submitLabel = jsonForScript(opts.actions?.accept?.label ?? "Send");
262
+ const initLabels = getLabels(opts.language);
263
+ const initActionLabels = resolveActionLabels(opts.actions, opts.language);
264
+ const backLabel = jsonForScript(initActionLabels.back);
265
+ const startLabel = jsonForScript(initActionLabels.start);
266
+ const completeLabel = jsonForScript(initActionLabels.complete);
267
+ const submitLabel = jsonForScript(initActionLabels.accept);
268
+ const labelsTableJson = jsonForScript(LABELS);
269
+ const actionOverridesJson = jsonForScript({
270
+ accept: trimmedOrNull(opts.actions?.accept?.label),
271
+ start: trimmedOrNull(opts.actions?.start?.label),
272
+ complete: trimmedOrNull(opts.actions?.complete?.label),
273
+ back: trimmedOrNull(opts.actions?.back?.label)
274
+ });
275
+ const initLangJson = jsonForScript(opts.language ?? "");
276
+ const initDirection = directionFor(opts.language);
277
+ const rtlLocalesJson = jsonForScript(RTL_LOCALES);
253
278
  return `<!DOCTYPE html><html><head>
254
279
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
255
280
  <meta name="color-scheme" content="${colorScheme}"/>
@@ -262,8 +287,8 @@ body{display:${bodyDisplay};justify-content:${pos.justifyContent};align-items:${
262
287
  .deepdots-popup-header{display:flex;justify-content:space-between;align-items:center;gap:12px;width:100%;flex:0 0 auto}
263
288
  /* Neutraliza la regla \`.deepdots-popup h2\` del CSS del survey (uppercase, centrado y
264
289
  margin-bottom 40px), pensada para los enunciados y no para el t\xEDtulo de la cabecera. */
265
- #dd-title{margin:0;font-family:var(--deepdots-font,'Montserrat',inherit);font-size:17px;font-weight:600;line-height:1.3;color:${textPrimary};text-transform:none;text-align:left;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
266
- #dd-close{background:transparent;border:none;width:32px;height:32px;display:flex;align-items:center;justify-content:center;border-radius:8px;cursor:pointer;color:${textPrimary};padding:4px;flex:0 0 auto;margin-left:auto}
290
+ #dd-title{margin:0;font-family:var(--deepdots-font,'Montserrat',inherit);font-size:17px;font-weight:600;line-height:1.3;color:${textPrimary};text-transform:none;text-align:start;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
291
+ #dd-close{background:transparent;border:none;width:32px;height:32px;display:flex;align-items:center;justify-content:center;border-radius:8px;cursor:pointer;color:${textPrimary};padding:4px;flex:0 0 auto;margin-inline-start:auto}
267
292
  /* Progreso alineado con la cabecera: sin padding horizontal propio, lo marca la tarjeta.
268
293
  El vertical es el mismo arriba y abajo, y del mismo valor que el padding de la tarjeta. */
269
294
  .deepdots-progress{display:none;flex-direction:column;gap:8px;width:100%;flex:0 0 auto;padding:16px 0;box-sizing:border-box}
@@ -320,10 +345,10 @@ body{display:${bodyDisplay};justify-content:${pos.justifyContent};align-items:${
320
345
  ${customCss}
321
346
  </style>
322
347
  </head><body>
323
- <div class="${popupClass}" id="dd-popup">
348
+ <div class="${popupClass}" id="dd-popup" dir="${initDirection}">
324
349
  <div class="deepdots-popup-header">
325
350
  <h2 id="dd-title" class="deepdots-popup-title" hidden></h2>
326
- <button type="button" id="dd-close" aria-label="Close popup">
351
+ <button type="button" id="dd-close" aria-label="${initLabels.closeAria}">
327
352
  <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
328
353
  <path d="M5 5L19 19M5 19L19 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="butt"/>
329
354
  </svg>
@@ -332,23 +357,23 @@ ${customCss}
332
357
  <div class="deepdots-progress" id="dd-progress">
333
358
  <div class="deepdots-progress-head">
334
359
  <span id="dd-progress-label"><span id="dd-progress-current"></span><span id="dd-progress-total"></span></span>
335
- <span id="dd-progress-followup">Follow-up</span>
360
+ <span id="dd-progress-followup">${initLabels.followUp}</span>
336
361
  </div>
337
362
  <div class="deepdots-progress-track"><div id="dd-progress-bar"></div></div>
338
363
  </div>
339
364
  <div class="deepdots-popup-container-content" id="dd-content">
340
365
  <div class="deepdots-popup-main" id="dd-main">
341
366
  <div id="dd-form-wrapper">
342
- <div class="mf-spinner" id="dd-spinner" role="status" aria-label="Loading survey"><div class="mf-spinner-circle"></div></div>
367
+ <div class="mf-spinner" id="dd-spinner" role="status" aria-label="${initLabels.loadingAria}"><div class="mf-spinner-circle"></div></div>
343
368
  <div id="mf"></div>
344
369
  </div>
345
370
  <div class="deepdots-error-hint" id="dd-error" role="alert" aria-live="polite"></div>
346
371
  </div>
347
372
  <div class="deepdots-popup-footer" id="dd-footer">
348
- <button type="button" class="dd-nav-btn" id="dd-submit">Send</button>
349
- <button type="button" class="dd-nav-btn" id="dd-back">Back</button>
350
- <button type="button" class="dd-nav-btn" id="dd-complete">Complete survey</button>
351
- <button type="button" class="dd-nav-btn" id="dd-start">Start survey</button>
373
+ <button type="button" class="dd-nav-btn" id="dd-submit"></button>
374
+ <button type="button" class="dd-nav-btn" id="dd-back"></button>
375
+ <button type="button" class="dd-nav-btn" id="dd-complete"></button>
376
+ <button type="button" class="dd-nav-btn" id="dd-start"></button>
352
377
  </div>
353
378
  </div>
354
379
  </div>
@@ -377,6 +402,32 @@ ${customCss}
377
402
  var progressTotal=document.getElementById('dd-progress-total');
378
403
  var progressFollowUp=document.getElementById('dd-progress-followup');
379
404
  var progressBar=document.getElementById('dd-progress-bar');
405
+ var closeEl=document.getElementById('dd-close');
406
+
407
+ // --- i18n del chrome -------------------------------------------------------------------
408
+ // La tabla completa viaja embebida porque el idioma del survey (\`formData.lang[0]\`) solo se
409
+ // conoce ya dentro del WebView. \`ddResolveLocale\` es el espejo del \`resolveLocale\` de TS
410
+ // (paridad cubierta por test).
411
+ var DD_LABELS=${labelsTableJson};
412
+ var DD_ACTION_OVERRIDES=${actionOverridesJson};
413
+ ${RESOLVE_LOCALE_JS}
414
+ var DD_LABELS_ACTIVE=DD_LABELS[ddResolveLocale(${initLangJson})];
415
+ var DD_RTL=${rtlLocalesJson};
416
+ function ddIsRtl(lang){ return DD_RTL.indexOf(ddResolveLocale(lang))!==-1; }
417
+ function ddApplyLabels(lang){
418
+ var next=DD_LABELS[ddResolveLocale(lang)];
419
+ if(!next) return;
420
+ DD_LABELS_ACTIVE=next;
421
+ // El survey ya se ha volteado a s\xED mismo: el chrome tiene que acompa\xF1arlo.
422
+ popup.setAttribute('dir', ddIsRtl(lang) ? 'rtl' : 'ltr');
423
+ backBtn.textContent=DD_ACTION_OVERRIDES.back||next.back;
424
+ startBtn.textContent=DD_ACTION_OVERRIDES.start||next.start;
425
+ completeBtn.textContent=DD_ACTION_OVERRIDES.complete||next.complete;
426
+ submitBtn.textContent=DD_ACTION_OVERRIDES.accept||next.accept;
427
+ if(closeEl){ closeEl.setAttribute('aria-label',next.closeAria); }
428
+ if(spinner){ spinner.setAttribute('aria-label',next.loadingAria); }
429
+ progressFollowUp.textContent=next.followUp;
430
+ }
380
431
 
381
432
  function setTitle(t){
382
433
  if(!t) return;
@@ -417,8 +468,8 @@ ${customCss}
417
468
  progressCurrent.textContent=Math.round(pct)+'%';
418
469
  progressTotal.textContent='';
419
470
  } else {
420
- progressCurrent.textContent='Question '+label;
421
- progressTotal.textContent=' of '+total;
471
+ progressCurrent.textContent=DD_LABELS_ACTIVE.question+' '+label;
472
+ progressTotal.textContent=' '+DD_LABELS_ACTIVE.of+' '+total;
422
473
  }
423
474
  progressFollowUp.style.display=p&&p.followup?'inline-block':'none';
424
475
  }
@@ -428,7 +479,7 @@ ${customCss}
428
479
  completeBtn.textContent=${completeLabel};
429
480
  submitBtn.textContent=${submitLabel};
430
481
 
431
- document.getElementById('dd-close').onclick=function(){ emitJSON('popup_close'); };
482
+ closeEl.onclick=function(){ emitJSON('popup_close'); };
432
483
  backBtn.onclick=function(){ if(window.DeepdotsForm && window.DeepdotsForm.back){ window.DeepdotsForm.back(); } };
433
484
  startBtn.onclick=function(){
434
485
  if(window.DeepdotsForm && window.DeepdotsForm.startForm){
@@ -523,6 +574,14 @@ ${customCss}
523
574
  // fallback es un literal gen\xE9rico que ignora style.successMessage.
524
575
  addSuccessScreen:false,
525
576
  onLoadedEvent:function(args){
577
+ // Idioma del survey: manda sobre el del init para que el chrome no se quede en
578
+ // ingl\xE9s delante de un survey traducido.
579
+ var langs=args && args.formData ? args.formData.lang : null;
580
+ if(langs && langs.length){
581
+ for(var li=0;li<langs.length;li++){
582
+ if(typeof langs[li]==='string' && langs[li].trim()){ ddApplyLabels(langs[li]); break; }
583
+ }
584
+ }
526
585
  var s=args && args.formData ? args.formData.style : null;
527
586
  if(s && !stylesInjected){
528
587
  stylesInjected=true;
@@ -549,8 +608,10 @@ ${customCss}
549
608
  if(s.logoSize==='small'){ logoImg.style.maxHeight='30px'; }
550
609
  else if(s.logoSize==='medium'){ logoImg.style.maxHeight='50px'; }
551
610
  else if(s.logoSize==='large'){ logoImg.style.maxHeight='70px'; }
552
- if(s.logoPosition==='left'){ logoImg.style.margin='12px 16px 0 0'; logoImg.style.marginLeft='0'; }
553
- else if(s.logoPosition==='right'){ logoImg.style.margin='12px 0 0 16px'; logoImg.style.marginLeft='auto'; }
611
+ // M\xE1rgenes l\xF3gicos: con un survey RTL el popup va con dir="rtl" y el logo
612
+ // tiene que acompa\xF1ar al chrome. En LTR el resultado es el mismo de antes.
613
+ if(s.logoPosition==='left'){ logoImg.style.margin='12px 0 0 0'; logoImg.style.setProperty('margin-inline-start','0'); logoImg.style.setProperty('margin-inline-end','16px'); }
614
+ else if(s.logoPosition==='right'){ logoImg.style.margin='12px 0 0 0'; logoImg.style.setProperty('margin-inline-start','auto'); logoImg.style.setProperty('margin-inline-end','0'); }
554
615
  else if(s.logoPosition==='center'){ logoImg.style.margin='12px auto 0 auto'; }
555
616
  // Encima de la barra de progreso, como hermano del header (espejo de ui/logo.ts en
556
617
  // web). Fuera de #dd-main, as\xED el logo no se va con el scroll del formulario.
@@ -576,12 +637,12 @@ ${customCss}
576
637
  setLoading(false);
577
638
  if(error.toLowerCase().indexOf('no response')!==-1){
578
639
  // La p\xE1gina no ha cambiado: el estado de navegaci\xF3n se queda como estaba.
579
- errorHint.textContent='Please answer the required question to continue.';
640
+ errorHint.textContent=DD_LABELS_ACTIVE.errorRequired;
580
641
  errorHint.style.display='block';
581
642
  updateNavButtons();
582
643
  return;
583
644
  }
584
- errorHint.textContent='An error occurred while submitting. Please try again or close the popup.';
645
+ errorHint.textContent=DD_LABELS_ACTIVE.errorSubmit;
585
646
  errorHint.style.display='block';
586
647
  return;
587
648
  }
@@ -653,7 +714,8 @@ var ReactNativePopupRenderer = class {
653
714
  chrome: renderChrome,
654
715
  title: options?.title,
655
716
  showProgressBar: options?.showProgressBar,
656
- surveyCss: options?.surveyCss
717
+ surveyCss: options?.surveyCss,
718
+ language: options?.language
657
719
  });
658
720
  if (this.options.onShow) {
659
721
  this.options.onShow({ surveyId, productId, html });
@@ -749,7 +811,7 @@ var BrowserPopupRenderer = class {
749
811
  if (!this.container) return;
750
812
  this.visible = true;
751
813
  const container = this.container;
752
- void import("./renderPopup-M6MKTDEH.mjs").then(({ renderPopup }) => {
814
+ void import("./renderPopup-HHQMAW3G.mjs").then(({ renderPopup }) => {
753
815
  renderPopup(container, surveyId, productId, actions, emit, onClose, env, userId, style, sessionId, miniService, analyticsFeedbackSessionId, options);
754
816
  });
755
817
  }
@@ -1501,6 +1563,75 @@ var CrashReporter = class {
1501
1563
  }
1502
1564
  };
1503
1565
 
1566
+ // src/core/popup-state-store.ts
1567
+ var POPUP_STATE_STORAGE_KEY = "deepdots.popups.state";
1568
+ var MAX_TRACKED_POPUP_ENTRIES = 200;
1569
+ function emptyState() {
1570
+ return { lastShown: {}, progress: {} };
1571
+ }
1572
+ function isValidTimestamp(value) {
1573
+ return typeof value === "number" && Number.isFinite(value);
1574
+ }
1575
+ function capEntries(entries, timestampOf) {
1576
+ if (entries.length <= MAX_TRACKED_POPUP_ENTRIES) return entries;
1577
+ return [...entries].sort((a, b) => timestampOf(b[1]) - timestampOf(a[1])).slice(0, MAX_TRACKED_POPUP_ENTRIES);
1578
+ }
1579
+ function readPopupState(storage) {
1580
+ let raw = null;
1581
+ try {
1582
+ raw = storage.getItem(POPUP_STATE_STORAGE_KEY);
1583
+ } catch {
1584
+ return emptyState();
1585
+ }
1586
+ if (!raw) return emptyState();
1587
+ let parsed;
1588
+ try {
1589
+ parsed = JSON.parse(raw);
1590
+ } catch {
1591
+ return emptyState();
1592
+ }
1593
+ if (typeof parsed !== "object" || parsed === null) return emptyState();
1594
+ const source = parsed;
1595
+ const state = emptyState();
1596
+ if (typeof source.lastShown === "object" && source.lastShown !== null) {
1597
+ const valid = Object.entries(source.lastShown).filter((entry) => isValidTimestamp(entry[1]));
1598
+ capEntries(valid, (timestamp) => timestamp).forEach(([popupId, timestamp]) => {
1599
+ state.lastShown[popupId] = timestamp;
1600
+ });
1601
+ }
1602
+ if (typeof source.progress === "object" && source.progress !== null) {
1603
+ const valid = Object.entries(source.progress).filter((entry) => {
1604
+ const value = entry[1];
1605
+ if (typeof value !== "object" || value === null) return false;
1606
+ const candidate = value;
1607
+ return POPUP_TRIGGER_CONDITION_STATUSES.includes(candidate.status) && isValidTimestamp(candidate.timestamp);
1608
+ });
1609
+ capEntries(valid, (entry) => entry.timestamp).forEach(([surveyId, entry]) => {
1610
+ state.progress[surveyId] = { status: entry.status, timestamp: entry.timestamp };
1611
+ });
1612
+ }
1613
+ return state;
1614
+ }
1615
+ function writePopupState(storage, state) {
1616
+ const capped = emptyState();
1617
+ capEntries(Object.entries(state.lastShown), (timestamp) => timestamp).forEach(([popupId, timestamp]) => {
1618
+ capped.lastShown[popupId] = timestamp;
1619
+ });
1620
+ capEntries(Object.entries(state.progress), (entry) => entry.timestamp).forEach(([surveyId, entry]) => {
1621
+ capped.progress[surveyId] = entry;
1622
+ });
1623
+ try {
1624
+ storage.setItem(POPUP_STATE_STORAGE_KEY, JSON.stringify(capped));
1625
+ } catch {
1626
+ }
1627
+ }
1628
+ function clearPopupState(storage) {
1629
+ try {
1630
+ storage.removeItem(POPUP_STATE_STORAGE_KEY);
1631
+ } catch {
1632
+ }
1633
+ }
1634
+
1504
1635
  // src/analytics/messaging.ts
1505
1636
  var MESSAGE_CHANNELS = ["push", "in_app"];
1506
1637
  function buildMessageParams(stage, o) {
@@ -1588,6 +1719,10 @@ var DeepdotsPopups = class {
1588
1719
  this.popupDefinitions = [];
1589
1720
  this.popupsLoaded = false;
1590
1721
  this.pendingAutoLaunch = false;
1722
+ // Estado que alimenta las reglas de redisplay. Copia de trabajo en memoria; la fuente
1723
+ // duradera es el storage (`popup-state-store`), rehidratada en `init()` — sin eso, una
1724
+ // recarga reiniciaba el cooldown y el popup volvía a salir. `answeredSurveys` se deriva
1725
+ // de las entradas COMPLETED de `surveyProgress` (los dos los escribe `markSurveyAnswered`).
1591
1726
  this.answeredSurveys = /* @__PURE__ */ new Set();
1592
1727
  this.surveyProgress = /* @__PURE__ */ new Map();
1593
1728
  this.lastShown = /* @__PURE__ */ new Map();
@@ -1663,6 +1798,7 @@ var DeepdotsPopups = class {
1663
1798
  };
1664
1799
  const storage = config.storage ?? createDefaultStorage();
1665
1800
  this.storage = storage;
1801
+ this.loadPopupState(storage);
1666
1802
  this.tracking = new TrackingManager({
1667
1803
  storage,
1668
1804
  clientUserId: this.config.userId,
@@ -1930,6 +2066,10 @@ var DeepdotsPopups = class {
1930
2066
  }) : null;
1931
2067
  this.analytics?.resetUserScope();
1932
2068
  this.messageGuard.reset();
2069
+ this.lastShown.clear();
2070
+ this.surveyProgress.clear();
2071
+ this.answeredSurveys.clear();
2072
+ clearPopupState(storage);
1933
2073
  this.log("tracking \xB7 user_change \xB7 user_id:", this.tracking.getUserId());
1934
2074
  this.openSession();
1935
2075
  }
@@ -2101,6 +2241,7 @@ var DeepdotsPopups = class {
2101
2241
  this.log("Showing popup (definition)", def);
2102
2242
  this.surveyToPopupId.set(def.surveyId, def.id);
2103
2243
  this.lastShown.set(def.id, Date.now());
2244
+ this.persistPopupState();
2104
2245
  this.renderPopup(def.surveyId, def.productId, def.actions, def.style, def.title);
2105
2246
  this.emitEvent("popup_shown", def.surveyId, { popupId: def.id });
2106
2247
  }
@@ -2459,13 +2600,13 @@ var DeepdotsPopups = class {
2459
2600
  miniService,
2460
2601
  analyticsFeedbackSessionId,
2461
2602
  this.renderChrome,
2462
- { title, showProgressBar: this.showProgressBar, surveyCss: this.surveyCss }
2603
+ { title, showProgressBar: this.showProgressBar, surveyCss: this.surveyCss, language: this.language }
2463
2604
  );
2464
2605
  return;
2465
2606
  }
2466
2607
  if (!this.popupContainer) return;
2467
2608
  const container = this.popupContainer;
2468
- void import("./renderPopup-M6MKTDEH.mjs").then(({ renderPopup }) => {
2609
+ void import("./renderPopup-HHQMAW3G.mjs").then(({ renderPopup }) => {
2469
2610
  renderPopup(
2470
2611
  container,
2471
2612
  surveyId,
@@ -2479,7 +2620,7 @@ var DeepdotsPopups = class {
2479
2620
  sessionId,
2480
2621
  miniService,
2481
2622
  analyticsFeedbackSessionId,
2482
- { title, showProgressBar: this.showProgressBar, surveyCss: this.surveyCss }
2623
+ { title, showProgressBar: this.showProgressBar, surveyCss: this.surveyCss, language: this.language }
2483
2624
  );
2484
2625
  });
2485
2626
  }
@@ -2580,6 +2721,29 @@ var DeepdotsPopups = class {
2580
2721
  return;
2581
2722
  }
2582
2723
  this.surveyProgress.set(surveyId, { status, timestamp: Date.now() });
2724
+ this.persistPopupState();
2725
+ }
2726
+ /**
2727
+ * Rehidrata el estado de redisplay desde el storage. `answeredSurveys` se reconstruye
2728
+ * desde las entradas COMPLETED: es exactamente lo que persiste `markSurveyAnswered`.
2729
+ */
2730
+ loadPopupState(storage) {
2731
+ const state = readPopupState(storage);
2732
+ Object.entries(state.lastShown).forEach(([popupId, timestamp]) => {
2733
+ this.lastShown.set(popupId, timestamp);
2734
+ });
2735
+ Object.entries(state.progress).forEach(([surveyId, entry]) => {
2736
+ this.surveyProgress.set(surveyId, { status: entry.status, timestamp: entry.timestamp });
2737
+ if (entry.status === "COMPLETED") this.answeredSurveys.add(surveyId);
2738
+ });
2739
+ }
2740
+ /** Vuelca el estado de redisplay al storage. Sin storage (o bloqueado) degrada a memoria. */
2741
+ persistPopupState() {
2742
+ if (!this.storage) return;
2743
+ writePopupState(this.storage, {
2744
+ lastShown: Object.fromEntries(this.lastShown),
2745
+ progress: Object.fromEntries(this.surveyProgress)
2746
+ });
2583
2747
  }
2584
2748
  isPopupDefinition(value) {
2585
2749
  if (typeof value !== "object" || value === null) return false;
@@ -2693,12 +2857,15 @@ export {
2693
2857
  CrashReporter,
2694
2858
  DeepdotsPopups,
2695
2859
  InMemoryStorage,
2860
+ LABELS,
2696
2861
  MAX_TRACKED_MESSAGES,
2697
2862
  MESSAGE_CHANNELS,
2698
2863
  MessageGuard,
2699
2864
  NoopPopupRenderer,
2700
2865
  POPUP_TRIGGER_CONDITION_STATUSES,
2866
+ RTL_LOCALES,
2701
2867
  ReactNativePopupRenderer,
2868
+ SUPPORTED_LANGUAGES,
2702
2869
  buildAnalyticsFeedbackBody,
2703
2870
  buildMessageParams,
2704
2871
  buildSurveyHtml,
@@ -2706,7 +2873,12 @@ export {
2706
2873
  crashRecordToParams,
2707
2874
  createDefaultRenderer,
2708
2875
  createFeedbackSink,
2876
+ directionFor,
2877
+ getLabels,
2878
+ isRtlLanguage,
2709
2879
  mmkvStorage,
2880
+ resolveActionLabels,
2881
+ resolveLocale,
2710
2882
  setupReactNative
2711
2883
  };
2712
2884
  //# sourceMappingURL=index.mjs.map