@magicfeedback/popup-sdk 1.15.0 → 1.16.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/dist/index.js CHANGED
@@ -256,7 +256,8 @@ var init_labels = __esm({
256
256
  closeAria: "Close popup",
257
257
  loadingAria: "Loading survey",
258
258
  errorRequired: "Please answer the required question to continue.",
259
- errorSubmit: "An error occurred while submitting. Please try again or close the popup."
259
+ errorSubmit: "An error occurred while submitting. Please try again or close the popup.",
260
+ errorLoad: "We couldn't load this survey."
260
261
  };
261
262
  ES = {
262
263
  accept: "Enviar",
@@ -270,7 +271,8 @@ var init_labels = __esm({
270
271
  closeAria: "Cerrar ventana emergente",
271
272
  loadingAria: "Cargando encuesta",
272
273
  errorRequired: "Responde la pregunta obligatoria para continuar.",
273
- errorSubmit: "Se produjo un error al enviar. Int\xE9ntalo de nuevo o cierra la ventana."
274
+ errorSubmit: "Se produjo un error al enviar. Int\xE9ntalo de nuevo o cierra la ventana.",
275
+ errorLoad: "No se ha podido cargar la encuesta."
274
276
  };
275
277
  DA = {
276
278
  accept: "Send",
@@ -284,7 +286,8 @@ var init_labels = __esm({
284
286
  closeAria: "Luk pop op",
285
287
  loadingAria: "Indl\xE6ser unders\xF8gelse",
286
288
  errorRequired: "Besvar venligst det obligatoriske sp\xF8rgsm\xE5l for at forts\xE6tte.",
287
- errorSubmit: "Der opstod en fejl under afsendelsen. Pr\xF8v igen, eller luk pop op-vinduet."
289
+ errorSubmit: "Der opstod en fejl under afsendelsen. Pr\xF8v igen, eller luk pop op-vinduet.",
290
+ errorLoad: "Unders\xF8gelsen kunne ikke indl\xE6ses."
288
291
  };
289
292
  NO = {
290
293
  accept: "Send",
@@ -298,7 +301,8 @@ var init_labels = __esm({
298
301
  closeAria: "Lukk popup",
299
302
  loadingAria: "Laster unders\xF8kelse",
300
303
  errorRequired: "Svar p\xE5 det obligatoriske sp\xF8rsm\xE5let for \xE5 fortsette.",
301
- errorSubmit: "Det oppstod en feil under innsendingen. Pr\xF8v igjen, eller lukk popupen."
304
+ errorSubmit: "Det oppstod en feil under innsendingen. Pr\xF8v igjen, eller lukk popupen.",
305
+ errorLoad: "Unders\xF8kelsen kunne ikke lastes inn."
302
306
  };
303
307
  SV = {
304
308
  accept: "Skicka",
@@ -312,7 +316,8 @@ var init_labels = __esm({
312
316
  closeAria: "St\xE4ng popup",
313
317
  loadingAria: "Laddar unders\xF6kning",
314
318
  errorRequired: "Svara p\xE5 den obligatoriska fr\xE5gan f\xF6r att forts\xE4tta.",
315
- errorSubmit: "Ett fel uppstod vid inskickningen. F\xF6rs\xF6k igen eller st\xE4ng popupen."
319
+ errorSubmit: "Ett fel uppstod vid inskickningen. F\xF6rs\xF6k igen eller st\xE4ng popupen.",
320
+ errorLoad: "Enk\xE4ten kunde inte laddas."
316
321
  };
317
322
  FI = {
318
323
  accept: "L\xE4het\xE4",
@@ -326,7 +331,8 @@ var init_labels = __esm({
326
331
  closeAria: "Sulje ponnahdusikkuna",
327
332
  loadingAria: "Ladataan kysely\xE4",
328
333
  errorRequired: "Vastaa pakolliseen kysymykseen jatkaaksesi.",
329
- errorSubmit: "L\xE4hetyksess\xE4 tapahtui virhe. Yrit\xE4 uudelleen tai sulje ponnahdusikkuna."
334
+ errorSubmit: "L\xE4hetyksess\xE4 tapahtui virhe. Yrit\xE4 uudelleen tai sulje ponnahdusikkuna.",
335
+ errorLoad: "Kysely\xE4 ei voitu ladata."
330
336
  };
331
337
  DE = {
332
338
  accept: "Senden",
@@ -340,7 +346,8 @@ var init_labels = __esm({
340
346
  closeAria: "Popup schlie\xDFen",
341
347
  loadingAria: "Umfrage wird geladen",
342
348
  errorRequired: "Bitte beantworte die Pflichtfrage, um fortzufahren.",
343
- errorSubmit: "Beim Senden ist ein Fehler aufgetreten. Versuche es erneut oder schlie\xDFe das Popup."
349
+ errorSubmit: "Beim Senden ist ein Fehler aufgetreten. Versuche es erneut oder schlie\xDFe das Popup.",
350
+ errorLoad: "Die Umfrage konnte nicht geladen werden."
344
351
  };
345
352
  FR = {
346
353
  accept: "Envoyer",
@@ -354,7 +361,8 @@ var init_labels = __esm({
354
361
  closeAria: "Fermer la fen\xEAtre",
355
362
  loadingAria: "Chargement de l'enqu\xEAte",
356
363
  errorRequired: "Veuillez r\xE9pondre \xE0 la question obligatoire pour continuer.",
357
- errorSubmit: "Une erreur s'est produite lors de l'envoi. R\xE9essayez ou fermez la fen\xEAtre."
364
+ errorSubmit: "Une erreur s'est produite lors de l'envoi. R\xE9essayez ou fermez la fen\xEAtre.",
365
+ errorLoad: "Impossible de charger l'enqu\xEAte."
358
366
  };
359
367
  PT = {
360
368
  accept: "Enviar",
@@ -368,7 +376,8 @@ var init_labels = __esm({
368
376
  closeAria: "Fechar janela",
369
377
  loadingAria: "A carregar question\xE1rio",
370
378
  errorRequired: "Responda \xE0 pergunta obrigat\xF3ria para continuar.",
371
- errorSubmit: "Ocorreu um erro ao enviar. Tente novamente ou feche a janela."
379
+ errorSubmit: "Ocorreu um erro ao enviar. Tente novamente ou feche a janela.",
380
+ errorLoad: "N\xE3o foi poss\xEDvel carregar o inqu\xE9rito."
372
381
  };
373
382
  AR = {
374
383
  accept: "\u0625\u0631\u0633\u0627\u0644",
@@ -382,7 +391,8 @@ var init_labels = __esm({
382
391
  closeAria: "\u0625\u063A\u0644\u0627\u0642 \u0627\u0644\u0646\u0627\u0641\u0630\u0629 \u0627\u0644\u0645\u0646\u0628\u062B\u0642\u0629",
383
392
  loadingAria: "\u062C\u0627\u0631\u064D \u062A\u062D\u0645\u064A\u0644 \u0627\u0644\u0627\u0633\u062A\u0628\u064A\u0627\u0646",
384
393
  errorRequired: "\u064A\u0631\u062C\u0649 \u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u0639\u0644\u0649 \u0627\u0644\u0633\u0624\u0627\u0644 \u0627\u0644\u0645\u0637\u0644\u0648\u0628 \u0644\u0644\u0645\u062A\u0627\u0628\u0639\u0629.",
385
- errorSubmit: "\u062D\u062F\u062B \u062E\u0637\u0623 \u0623\u062B\u0646\u0627\u0621 \u0627\u0644\u0625\u0631\u0633\u0627\u0644. \u064A\u0631\u062C\u0649 \u0627\u0644\u0645\u062D\u0627\u0648\u0644\u0629 \u0645\u0631\u0629 \u0623\u062E\u0631\u0649 \u0623\u0648 \u0625\u063A\u0644\u0627\u0642 \u0627\u0644\u0646\u0627\u0641\u0630\u0629."
394
+ errorSubmit: "\u062D\u062F\u062B \u062E\u0637\u0623 \u0623\u062B\u0646\u0627\u0621 \u0627\u0644\u0625\u0631\u0633\u0627\u0644. \u064A\u0631\u062C\u0649 \u0627\u0644\u0645\u062D\u0627\u0648\u0644\u0629 \u0645\u0631\u0629 \u0623\u062E\u0631\u0649 \u0623\u0648 \u0625\u063A\u0644\u0627\u0642 \u0627\u0644\u0646\u0627\u0641\u0630\u0629.",
395
+ errorLoad: "\u062A\u0639\u0630\u0651\u0631 \u062A\u062D\u0645\u064A\u0644 \u0627\u0644\u0627\u0633\u062A\u0628\u064A\u0627\u0646."
386
396
  };
387
397
  BN = {
388
398
  accept: "\u09AA\u09BE\u09A0\u09BE\u09A8",
@@ -396,7 +406,8 @@ var init_labels = __esm({
396
406
  closeAria: "\u09AA\u09AA\u0986\u09AA \u09AC\u09A8\u09CD\u09A7 \u0995\u09B0\u09C1\u09A8",
397
407
  loadingAria: "\u099C\u09B0\u09BF\u09AA \u09B2\u09CB\u09A1 \u09B9\u099A\u09CD\u099B\u09C7",
398
408
  errorRequired: "\u099A\u09BE\u09B2\u09BF\u09AF\u09BC\u09C7 \u09AF\u09C7\u09A4\u09C7 \u0986\u09AC\u09B6\u09CD\u09AF\u0995 \u09AA\u09CD\u09B0\u09B6\u09CD\u09A8\u09C7\u09B0 \u0989\u09A4\u09CD\u09A4\u09B0 \u09A6\u09BF\u09A8\u0964",
399
- errorSubmit: "\u099C\u09AE\u09BE \u09A6\u09C7\u0993\u09AF\u09BC\u09BE\u09B0 \u09B8\u09AE\u09AF\u09BC \u098F\u0995\u099F\u09BF \u09A4\u09CD\u09B0\u09C1\u099F\u09BF \u0998\u099F\u09C7\u099B\u09C7\u0964 \u0986\u09AC\u09BE\u09B0 \u099A\u09C7\u09B7\u09CD\u099F\u09BE \u0995\u09B0\u09C1\u09A8 \u09AC\u09BE \u09AA\u09AA\u0986\u09AA \u09AC\u09A8\u09CD\u09A7 \u0995\u09B0\u09C1\u09A8\u0964"
409
+ errorSubmit: "\u099C\u09AE\u09BE \u09A6\u09C7\u0993\u09AF\u09BC\u09BE\u09B0 \u09B8\u09AE\u09AF\u09BC \u098F\u0995\u099F\u09BF \u09A4\u09CD\u09B0\u09C1\u099F\u09BF \u0998\u099F\u09C7\u099B\u09C7\u0964 \u0986\u09AC\u09BE\u09B0 \u099A\u09C7\u09B7\u09CD\u099F\u09BE \u0995\u09B0\u09C1\u09A8 \u09AC\u09BE \u09AA\u09AA\u0986\u09AA \u09AC\u09A8\u09CD\u09A7 \u0995\u09B0\u09C1\u09A8\u0964",
410
+ errorLoad: "\u09B8\u09AE\u09C0\u0995\u09CD\u09B7\u09BE\u099F\u09BF \u09B2\u09CB\u09A1 \u0995\u09B0\u09BE \u09AF\u09BE\u09AF\u09BC\u09A8\u09BF\u0964"
400
411
  };
401
412
  ZH_CN = {
402
413
  accept: "\u53D1\u9001",
@@ -410,7 +421,8 @@ var init_labels = __esm({
410
421
  closeAria: "\u5173\u95ED\u5F39\u7A97",
411
422
  loadingAria: "\u6B63\u5728\u52A0\u8F7D\u95EE\u5377",
412
423
  errorRequired: "\u8BF7\u56DE\u7B54\u5FC5\u7B54\u9898\u540E\u7EE7\u7EED\u3002",
413
- errorSubmit: "\u63D0\u4EA4\u65F6\u51FA\u9519\u3002\u8BF7\u91CD\u8BD5\u6216\u5173\u95ED\u5F39\u7A97\u3002"
424
+ errorSubmit: "\u63D0\u4EA4\u65F6\u51FA\u9519\u3002\u8BF7\u91CD\u8BD5\u6216\u5173\u95ED\u5F39\u7A97\u3002",
425
+ errorLoad: "\u65E0\u6CD5\u52A0\u8F7D\u95EE\u5377\u3002"
414
426
  };
415
427
  LABELS = {
416
428
  en: EN,
@@ -5824,10 +5836,11 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
5824
5836
  closeBtn.style.color = theme.textPrimary;
5825
5837
  closeBtn.style.transform = "scale(1)";
5826
5838
  };
5827
- closeBtn.onclick = () => {
5839
+ const closeFromChrome = () => {
5828
5840
  emit("popup_clicked", surveyId, { action: "close_icon" });
5829
5841
  onClose();
5830
5842
  };
5843
+ closeBtn.onclick = closeFromChrome;
5831
5844
  closeBtn.style.flex = "0 0 auto";
5832
5845
  closeBtn.style.marginLeft = "auto";
5833
5846
  header.appendChild(closeBtn);
@@ -5935,6 +5948,12 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
5935
5948
  formWrapper.appendChild(spinnerEl);
5936
5949
  formWrapper.appendChild(formHost);
5937
5950
  main.appendChild(formWrapper);
5951
+ const loadErrorEl = document.createElement("div");
5952
+ loadErrorEl.id = "dd-load-error";
5953
+ loadErrorEl.className = "deepdots-load-error";
5954
+ loadErrorEl.setAttribute("role", "alert");
5955
+ loadErrorEl.style.cssText = `display:none; width:100%; text-align:center; padding:24px 0; font-size:15px; color:${theme.textPrimary};`;
5956
+ main.appendChild(loadErrorEl);
5938
5957
  main.appendChild(errorHint);
5939
5958
  const footer = document.createElement("div");
5940
5959
  footer.id = "dd-footer";
@@ -6050,6 +6069,13 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
6050
6069
  justify-content: center;
6051
6070
  text-align: center;
6052
6071
  `;
6072
+ const cancelButton = document.createElement("button");
6073
+ cancelButton.id = "dd-cancel";
6074
+ cancelButton.type = "button";
6075
+ cancelButton.className = "dd-nav-btn";
6076
+ cancelButton.textContent = actionLabels.decline;
6077
+ cancelButton.style.cssText = submitButton.style.cssText;
6078
+ cancelButton.onclick = closeFromChrome;
6053
6079
  submitButton.onclick = () => {
6054
6080
  if (!surveyCompletedEmitted) {
6055
6081
  emit("popup_clicked", surveyId, { action: "manual_send" });
@@ -6063,6 +6089,8 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
6063
6089
  startButton.textContent = actionLabels.start;
6064
6090
  closeButton.textContent = actionLabels.complete;
6065
6091
  submitButton.textContent = actionLabels.accept;
6092
+ cancelButton.textContent = actionLabels.decline;
6093
+ loadErrorEl.textContent = labels.errorLoad;
6066
6094
  closeBtn.setAttribute("aria-label", labels.closeAria);
6067
6095
  spinnerEl.setAttribute("aria-label", labels.loadingAria);
6068
6096
  progressFollowUp.textContent = labels.followUp;
@@ -6073,10 +6101,12 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
6073
6101
  startButton.style.display = "none";
6074
6102
  submitButton.style.display = "none";
6075
6103
  closeButton.style.display = "none";
6104
+ cancelButton.style.display = "none";
6076
6105
  footer.appendChild(submitButton);
6077
6106
  footer.appendChild(backButton);
6078
6107
  footer.appendChild(closeButton);
6079
6108
  footer.appendChild(startButton);
6109
+ footer.appendChild(cancelButton);
6080
6110
  containerContent.appendChild(main);
6081
6111
  footer.style.flex = "0 0 auto";
6082
6112
  containerContent.appendChild(footer);
@@ -6085,6 +6115,7 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
6085
6115
  startButton.style.display = "none";
6086
6116
  submitButton.style.display = "none";
6087
6117
  closeButton.style.display = "none";
6118
+ cancelButton.style.display = "none";
6088
6119
  backButton.style.width = "";
6089
6120
  startButton.style.width = "";
6090
6121
  submitButton.style.width = "";
@@ -6114,6 +6145,9 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
6114
6145
  case "error":
6115
6146
  setLoading(false);
6116
6147
  break;
6148
+ case "load_error":
6149
+ cancelButton.style.display = "inline-flex";
6150
+ break;
6117
6151
  }
6118
6152
  }
6119
6153
  function updateNavButtons() {
@@ -6135,6 +6169,20 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
6135
6169
  img.style.cssText = "max-width:100%; height:auto; margin:0 auto 16px auto; display:block;";
6136
6170
  });
6137
6171
  }
6172
+ let loadFailed = false;
6173
+ function showLoadError(reason) {
6174
+ sdkWarn("[Deepdots] survey failed to load:", reason);
6175
+ if (loadFailed) return;
6176
+ loadFailed = true;
6177
+ progressEl.style.display = "none";
6178
+ formWrapper.style.display = "none";
6179
+ errorHint.style.display = "none";
6180
+ loadErrorEl.textContent = labels.errorLoad;
6181
+ loadErrorEl.style.display = "block";
6182
+ setLoading(false);
6183
+ updateButtons("load_error");
6184
+ reveal();
6185
+ }
6138
6186
  popup.appendChild(header);
6139
6187
  popup.appendChild(progressEl);
6140
6188
  popup.appendChild(containerContent);
@@ -6199,7 +6247,7 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
6199
6247
  try {
6200
6248
  if (!import_native.default || typeof import_native.default.form !== "function") {
6201
6249
  sdkWarn("[MagicFeedback] form() no disponible. Fallback manual.");
6202
- setLoading(false);
6250
+ showLoadError("form() not available");
6203
6251
  return;
6204
6252
  }
6205
6253
  import_native.default.init(
@@ -6225,7 +6273,11 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
6225
6273
  // quitado el `inert`. La apertura va aparte (ver autofocusOnOpen).
6226
6274
  autofocus: "navigation"
6227
6275
  };
6228
- generateOptions.onLoadedEvent = ({ formData, lang }) => {
6276
+ generateOptions.onLoadedEvent = ({ formData, lang, error }) => {
6277
+ if (error) {
6278
+ showLoadError(error);
6279
+ return;
6280
+ }
6229
6281
  const shownLang = typeof lang === "string" && lang.trim().length > 0 ? lang : void 0;
6230
6282
  const surveyLang = shownLang ?? (Array.isArray(formData?.lang) ? formData.lang.find((l) => typeof l === "string" && l.trim().length > 0) : void 0);
6231
6283
  if (surveyLang) applyLabels(surveyLang);
@@ -6324,11 +6376,11 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
6324
6376
  };
6325
6377
  formInstance.generate(formDivId, generateOptions).catch((err) => {
6326
6378
  sdkError("[MagicFeedback] Error generating form:", err);
6327
- setLoading(false);
6379
+ showLoadError(err);
6328
6380
  });
6329
6381
  } catch (e) {
6330
6382
  sdkError("[MagicFeedback] Exception initializing form:", e);
6331
- setLoading(false);
6383
+ showLoadError(e);
6332
6384
  }
6333
6385
  }
6334
6386
  var import_native, SURVEY_ALIGNMENT_STYLE_ID;
@@ -6664,12 +6716,14 @@ function buildSurveyHtml(opts) {
6664
6716
  const startLabel = jsonForScript(initActionLabels.start);
6665
6717
  const completeLabel = jsonForScript(initActionLabels.complete);
6666
6718
  const submitLabel = jsonForScript(initActionLabels.accept);
6719
+ const cancelLabel = jsonForScript(initActionLabels.decline);
6667
6720
  const labelsTableJson = jsonForScript(LABELS);
6668
6721
  const actionOverridesJson = jsonForScript({
6669
6722
  accept: trimmedOrNull(opts.actions?.accept?.label),
6670
6723
  start: trimmedOrNull(opts.actions?.start?.label),
6671
6724
  complete: trimmedOrNull(opts.actions?.complete?.label),
6672
- back: trimmedOrNull(opts.actions?.back?.label)
6725
+ back: trimmedOrNull(opts.actions?.back?.label),
6726
+ decline: trimmedOrNull(opts.actions?.decline?.label)
6673
6727
  });
6674
6728
  const initLangJson = jsonForScript(opts.language ?? "");
6675
6729
  const initDirection = directionFor(opts.language);
@@ -6731,6 +6785,7 @@ body.dd-ready #dd-popup{visibility:visible}
6731
6785
  #dd-logo{max-height:40px;max-width:100%;object-fit:contain;display:block;margin:12px 0 0 0}
6732
6786
  .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}
6733
6787
  /* Pantalla final: el HTML del editor de la plataforma (imagen + texto), centrado. */
6788
+ .deepdots-load-error{display:none;width:100%;text-align:center;padding:24px 0;font-size:15px;color:${textPrimary}}
6734
6789
  .deepdots-success{display:none;width:100%;text-align:center;padding:24px 0;color:${textPrimary}}
6735
6790
  .deepdots-success img{max-width:100%;height:auto;margin:0 auto 16px auto;display:block}
6736
6791
  .deepdots-success p{margin:0;font-size:16px;font-weight:600;line-height:1.4}
@@ -6738,7 +6793,7 @@ body.dd-ready #dd-popup{visibility:visible}
6738
6793
  .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}
6739
6794
  /* Secundario como bot\xF3n de texto: sin borde ni fondo, para que el primario sea la \xFAnica CTA. */
6740
6795
  #dd-back{background:transparent;color:${textMuted};border:none}
6741
- #dd-start,#dd-complete,#dd-submit{background:#1E293B;color:#fff;border:none}
6796
+ #dd-start,#dd-complete,#dd-submit,#dd-cancel{background:#1E293B;color:#fff;border:none}
6742
6797
  #dd-submit:disabled,#dd-start:disabled,#dd-back:disabled,#dd-complete:disabled{opacity:0.6;cursor:not-allowed}
6743
6798
  .mf-spinner{display:none;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}
6744
6799
  .mf-spinner-circle{width:28px;height:28px;border:3px solid #e0e6ed;border-top-color:#1E293B;border-radius:50%;animation:ddspin 0.9s linear infinite}
@@ -6779,6 +6834,7 @@ ${customCss}
6779
6834
  <div class="mf-spinner" id="dd-spinner" role="status" aria-label="${initLabels.loadingAria}"><div class="mf-spinner-circle"></div></div>
6780
6835
  <div id="mf"></div>
6781
6836
  </div>
6837
+ <div class="deepdots-load-error" id="dd-load-error" role="alert"></div>
6782
6838
  <div class="deepdots-error-hint" id="dd-error" role="alert" aria-live="polite"></div>
6783
6839
  </div>
6784
6840
  <div class="deepdots-popup-footer" id="dd-footer">
@@ -6786,6 +6842,7 @@ ${customCss}
6786
6842
  <button type="button" class="dd-nav-btn" id="dd-back"></button>
6787
6843
  <button type="button" class="dd-nav-btn" id="dd-complete"></button>
6788
6844
  <button type="button" class="dd-nav-btn" id="dd-start"></button>
6845
+ <button type="button" class="dd-nav-btn" id="dd-cancel"></button>
6789
6846
  </div>
6790
6847
  </div>
6791
6848
  </div>
@@ -6808,6 +6865,8 @@ ${customCss}
6808
6865
  var startBtn=document.getElementById('dd-start');
6809
6866
  var completeBtn=document.getElementById('dd-complete');
6810
6867
  var submitBtn=document.getElementById('dd-submit');
6868
+ var cancelBtn=document.getElementById('dd-cancel');
6869
+ var loadErrorEl=document.getElementById('dd-load-error');
6811
6870
  var titleEl=document.getElementById('dd-title');
6812
6871
  var progressEl=document.getElementById('dd-progress');
6813
6872
  var progressLabel=document.getElementById('dd-progress-label');
@@ -6837,6 +6896,8 @@ ${customCss}
6837
6896
  startBtn.textContent=DD_ACTION_OVERRIDES.start||next.start;
6838
6897
  completeBtn.textContent=DD_ACTION_OVERRIDES.complete||next.complete;
6839
6898
  submitBtn.textContent=DD_ACTION_OVERRIDES.accept||next.accept;
6899
+ cancelBtn.textContent=DD_ACTION_OVERRIDES.decline||next.decline;
6900
+ loadErrorEl.textContent=next.errorLoad;
6840
6901
  if(closeEl){ closeEl.setAttribute('aria-label',next.closeAria); }
6841
6902
  if(spinner){ spinner.setAttribute('aria-label',next.loadingAria); }
6842
6903
  progressFollowUp.textContent=next.followUp;
@@ -6891,6 +6952,7 @@ ${customCss}
6891
6952
  startBtn.textContent=${startLabel};
6892
6953
  completeBtn.textContent=${completeLabel};
6893
6954
  submitBtn.textContent=${submitLabel};
6955
+ cancelBtn.textContent=${cancelLabel};
6894
6956
 
6895
6957
  closeEl.onclick=function(){ emitJSON('popup_close'); };
6896
6958
  backBtn.onclick=function(){ if(window.DeepdotsForm && window.DeepdotsForm.back){ window.DeepdotsForm.back(); } };
@@ -6902,6 +6964,8 @@ ${customCss}
6902
6964
  }
6903
6965
  };
6904
6966
  completeBtn.onclick=function(){ emitJSON('popup_close'); };
6967
+ // \xDAnica acci\xF3n del survey que no carga: cierra igual que la X.
6968
+ cancelBtn.onclick=function(){ emitJSON('popup_close'); };
6905
6969
  var surveyCompletedEmitted=false;
6906
6970
  submitBtn.onclick=function(){
6907
6971
  if(surveyCompletedEmitted) return;
@@ -6943,6 +7007,7 @@ ${customCss}
6943
7007
  startBtn.style.display='none';
6944
7008
  submitBtn.style.display='none';
6945
7009
  completeBtn.style.display='none';
7010
+ cancelBtn.style.display='none';
6946
7011
  backBtn.style.width='';
6947
7012
  startBtn.style.width='';
6948
7013
  submitBtn.style.width='';
@@ -6958,6 +7023,8 @@ ${customCss}
6958
7023
  } else if(state==='completed'){
6959
7024
  completeBtn.style.display='inline-flex';
6960
7025
  completeBtn.style.width='100%';
7026
+ } else if(state==='load_error'){
7027
+ cancelBtn.style.display='inline-flex';
6961
7028
  }
6962
7029
  }
6963
7030
 
@@ -7004,6 +7071,26 @@ ${REVEAL_JS}
7004
7071
  }
7005
7072
  setLoading(true);
7006
7073
 
7074
+ // Survey que no ha cargado (406 de /info, sin red, bundle del CDN ca\xEDdo). Antes se emit\xEDa
7075
+ // \`loaded\` y se pintaba un Send sobre un survey vac\xEDo. Espejo de KMP: aviso traducido, la X
7076
+ // sigue, un \xFAnico Cancel, y se revela ya (manda \`ready\`): no hay nada m\xE1s que esperar.
7077
+ // No es interacci\xF3n del usuario: el renderer no lo convierte en popup_clicked.
7078
+ var ddLoadFailed=false;
7079
+ function ddShowLoadError(name, reason){
7080
+ if(ddLoadFailed){ return; }
7081
+ ddLoadFailed=true;
7082
+ var why=(reason && reason.message) ? reason.message : String(reason);
7083
+ emitJSON(name, { message: why });
7084
+ progressEl.style.display='none';
7085
+ formWrapper.style.display='none';
7086
+ errorHint.style.display='none';
7087
+ loadErrorEl.textContent=DD_LABELS_ACTIVE.errorLoad;
7088
+ loadErrorEl.style.display='block';
7089
+ setLoading(false);
7090
+ updateButtons('load_error');
7091
+ ddReveal.reveal();
7092
+ }
7093
+
7007
7094
  var initialized=false;
7008
7095
  function initMF(){
7009
7096
  if(initialized || !window.magicfeedback) return initialized;
@@ -7027,6 +7114,7 @@ ${REVEAL_JS}
7027
7114
  // de native sin esta opci\xF3n la ignoran.
7028
7115
  autofocus:'navigation',
7029
7116
  onLoadedEvent:function(args){
7117
+ if(args && args.error){ ddShowLoadError('error:load', args.error); return; }
7030
7118
  // Idioma en el que native muestra el survey: manda sobre el del init para que el
7031
7119
  // chrome no se quede en ingl\xE9s delante de un survey traducido. Native < 2.3 no lo
7032
7120
  // env\xEDa: entonces el primero de formData.lang (el idioma por defecto).
@@ -7130,13 +7218,13 @@ ${REVEAL_JS}
7130
7218
  updateProgress({ progress:p&&p.progress, total:form.total, completed:false, followup:p&&p.followup });
7131
7219
  emitJSON('back', p);
7132
7220
  }
7133
- }).catch(function(e){ setLoading(false); emit('error:init'); });
7134
- }catch(e){ setLoading(false); emit('error:exception'); }
7221
+ }).catch(function(e){ ddShowLoadError('error:init', e); });
7222
+ }catch(e){ ddShowLoadError('error:exception', e); }
7135
7223
  return true;
7136
7224
  }
7137
7225
  var s=document.createElement('script'); s.src=${JSON.stringify(cdn)}; s.async=true;
7138
7226
  s.onload=function(){ initMF(); };
7139
- s.onerror=function(){ setLoading(false); emit('error:load'); };
7227
+ s.onerror=function(){ ddShowLoadError('error:load', 'survey script failed to load'); };
7140
7228
  document.head.appendChild(s);
7141
7229
  var tries=0, t=setInterval(function(){ if(initMF()||++tries>40){ clearInterval(t); } },150);
7142
7230
  })();
@@ -7255,6 +7343,7 @@ var ReactNativePopupRenderer = class {
7255
7343
  this.onCloseFn?.();
7256
7344
  break;
7257
7345
  default:
7346
+ if (typeof name === "string" && name.startsWith("error:")) this.emitReady(surveyId);
7258
7347
  break;
7259
7348
  }
7260
7349
  }