@magicfeedback/popup-sdk 1.0.9 → 1.0.11

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
@@ -1774,7 +1774,7 @@ function ensureResponsiveStyles(popup) {
1774
1774
  `;
1775
1775
  popup.appendChild(style);
1776
1776
  }
1777
- async function renderPopup(container, surveyId, productId, actions, emit, onClose) {
1777
+ async function renderPopup(container, surveyId, productId, actions, emit, onClose, env = "production") {
1778
1778
  let surveyCompletedEmitted = false;
1779
1779
  let stylesInjected = false;
1780
1780
  const popup = document.createElement("div");
@@ -1799,7 +1799,7 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
1799
1799
  closeBtn.type = "button";
1800
1800
  closeBtn.setAttribute("aria-label", "Close popup");
1801
1801
  closeBtn.innerHTML = `
1802
- <svg width="28" height="28" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
1802
+ <svg width="28" height="28" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
1803
1803
  <path d="M6 6L18 18M6 18L18 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
1804
1804
  </svg>
1805
1805
  `;
@@ -1850,6 +1850,20 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
1850
1850
  main.style.cssText = "display:flex; flex-direction:column; width:100%; max-height:80vh; overflow-y:auto;";
1851
1851
  const formWrapper = document.createElement("div");
1852
1852
  formWrapper.style.cssText = "width:100%; flex: 1 1 auto;";
1853
+ const errorHint = document.createElement("div");
1854
+ errorHint.className = "deepdots-error-hint";
1855
+ errorHint.style.cssText = `
1856
+ display: none;
1857
+ margin: 12px 0 0 0;
1858
+ padding: 10px 12px;
1859
+ border-radius: 6px;
1860
+ background: #FEF3C7; /* amber-100 */
1861
+ color: #92400E; /* amber-700 */
1862
+ border: 1px solid #FCD34D; /* amber-300 */
1863
+ font-size: 13px;
1864
+ `;
1865
+ errorHint.setAttribute("role", "alert");
1866
+ errorHint.setAttribute("aria-live", "polite");
1853
1867
  const spinnerEl = document.createElement("div");
1854
1868
  spinnerEl.className = "mf-spinner";
1855
1869
  spinnerEl.setAttribute("role", "status");
@@ -1863,6 +1877,7 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
1863
1877
  formWrapper.appendChild(spinnerEl);
1864
1878
  formWrapper.appendChild(formHost);
1865
1879
  main.appendChild(formWrapper);
1880
+ main.appendChild(errorHint);
1866
1881
  const footer = document.createElement("div");
1867
1882
  footer.className = "deepdots-popup-footer";
1868
1883
  footer.setAttribute("data-actions-wrapper", "true");
@@ -2007,7 +2022,6 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
2007
2022
  setLoading(false);
2008
2023
  break;
2009
2024
  case "error":
2010
- closeButton.style.display = "inline-flex";
2011
2025
  setLoading(false);
2012
2026
  break;
2013
2027
  }
@@ -2044,13 +2058,13 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
2044
2058
  setLoading(false);
2045
2059
  return;
2046
2060
  }
2047
- import_native.default.init({ debug: true, env: "prod" });
2061
+ import_native.default.init({ debug: true, env: env === "production" ? "prod" : "dev" });
2048
2062
  formInstance = import_native.default.form(surveyId, productId);
2049
2063
  const generateOptions = {
2050
2064
  addButton: false,
2051
2065
  getMetaData: true
2052
2066
  };
2053
- generateOptions.onLoadedEvent = ({ formData, progress }) => {
2067
+ generateOptions.onLoadedEvent = ({ formData }) => {
2054
2068
  try {
2055
2069
  } catch (e) {
2056
2070
  }
@@ -2136,11 +2150,23 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
2136
2150
  emit("popup_clicked", surveyId, { action: "before_submit" });
2137
2151
  };
2138
2152
  generateOptions.afterSubmitEvent = ({ error, completed, total, progress }) => {
2139
- if (error) {
2140
- emit("popup_clicked", surveyId, { action: "submit_error", error });
2141
- updateButtons("error");
2153
+ const errText = error ? typeof error === "string" ? error : error.message ?? String(error) : "";
2154
+ if (errText) {
2155
+ setLoading(false);
2156
+ if (errText.toLowerCase().includes("no response")) {
2157
+ errorHint.textContent = "Please answer the required question to continue.";
2158
+ errorHint.style.display = "block";
2159
+ emit("popup_clicked", surveyId, { action: "validation_error_required" });
2160
+ updateButtons("in_progress_next");
2161
+ return;
2162
+ }
2163
+ errorHint.textContent = "An error occurred while submitting. Please try again or close the popup.";
2164
+ errorHint.style.display = "block";
2165
+ emit("popup_clicked", surveyId, { action: "submit_error", error: errText });
2142
2166
  return;
2143
2167
  }
2168
+ errorHint.style.display = "none";
2169
+ setLoading(false);
2144
2170
  if (completed) {
2145
2171
  emit("survey_completed", surveyId, { action: "completed" });
2146
2172
  surveyCompletedEmitted = true;
@@ -2183,6 +2209,9 @@ function setupTrigger(popups, trigger) {
2183
2209
  case "exit":
2184
2210
  setupExitTrigger(popups, trigger);
2185
2211
  break;
2212
+ case "click":
2213
+ setupClickTrigger(popups, trigger);
2214
+ break;
2186
2215
  }
2187
2216
  }
2188
2217
  function setupTimeTrigger(popups, trigger) {
@@ -2205,23 +2234,120 @@ function setupScrollTrigger(popups, trigger) {
2205
2234
  popups.debug(`Scroll trigger set for ${threshold}%`);
2206
2235
  }
2207
2236
  function setupExitTrigger(popups, trigger) {
2208
- const handler = (e) => {
2209
- if (e.clientY <= 0) {
2210
- popups.triggerSurvey(trigger.surveyId);
2211
- document.removeEventListener("mouseout", handler);
2237
+ let fired = false;
2238
+ let lastUrl = typeof window !== "undefined" ? window.location.href : "";
2239
+ const historyRef = typeof window !== "undefined" ? window.history : null;
2240
+ const originalPushState = historyRef ? historyRef.pushState.bind(historyRef) : null;
2241
+ const originalReplaceState = historyRef ? historyRef.replaceState.bind(historyRef) : null;
2242
+ const cleanup = () => {
2243
+ document.removeEventListener("click", handleNavClick, true);
2244
+ window.removeEventListener("popstate", handlePopState);
2245
+ if (historyRef && originalPushState) historyRef.pushState = originalPushState;
2246
+ if (historyRef && originalReplaceState) historyRef.replaceState = originalReplaceState;
2247
+ };
2248
+ const fireOnce = () => {
2249
+ if (fired) return;
2250
+ fired = true;
2251
+ popups.triggerSurvey(trigger.surveyId);
2252
+ cleanup();
2253
+ };
2254
+ const handleNavClick = (e) => {
2255
+ if (fired) return;
2256
+ if (e.defaultPrevented) return;
2257
+ if (e.button !== 0) return;
2258
+ if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;
2259
+ const target = e.target?.closest?.("a");
2260
+ if (!target) return;
2261
+ const href = target.getAttribute("href");
2262
+ if (!href || href.startsWith("#")) return;
2263
+ const targetAttr = target.getAttribute("target");
2264
+ if (targetAttr && targetAttr !== "_self") return;
2265
+ let url;
2266
+ try {
2267
+ url = new URL(href, window.location.href);
2268
+ } catch {
2269
+ return;
2270
+ }
2271
+ if (url.origin !== window.location.origin) return;
2272
+ e.preventDefault();
2273
+ fireOnce();
2274
+ };
2275
+ const shouldBlockUrl = (rawUrl) => {
2276
+ if (!rawUrl) return false;
2277
+ let url;
2278
+ try {
2279
+ url = rawUrl instanceof URL ? rawUrl : new URL(rawUrl, window.location.href);
2280
+ } catch {
2281
+ return false;
2282
+ }
2283
+ if (url.origin !== window.location.origin) return false;
2284
+ if (url.href === window.location.href) return false;
2285
+ return true;
2286
+ };
2287
+ const handlePopState = () => {
2288
+ if (fired) return;
2289
+ fireOnce();
2290
+ if (historyRef && originalPushState && lastUrl) {
2291
+ originalPushState(null, document.title, lastUrl);
2212
2292
  }
2213
2293
  };
2214
- document.addEventListener("mouseout", handler);
2215
- popups.debug("Exit intent trigger set");
2294
+ if (historyRef && originalPushState && originalReplaceState) {
2295
+ historyRef.pushState = function(data, unused, url) {
2296
+ if (!fired && shouldBlockUrl(url)) {
2297
+ fireOnce();
2298
+ return;
2299
+ }
2300
+ const result = originalPushState(data, unused, url);
2301
+ lastUrl = window.location.href;
2302
+ return result;
2303
+ };
2304
+ historyRef.replaceState = function(data, unused, url) {
2305
+ if (!fired && shouldBlockUrl(url)) {
2306
+ fireOnce();
2307
+ return;
2308
+ }
2309
+ const result = originalReplaceState(data, unused, url);
2310
+ lastUrl = window.location.href;
2311
+ return result;
2312
+ };
2313
+ }
2314
+ document.addEventListener("click", handleNavClick, true);
2315
+ window.addEventListener("popstate", handlePopState);
2316
+ popups.debug("Exit intent trigger set (navigation/spa)");
2317
+ }
2318
+ function setupClickTrigger(popups, trigger) {
2319
+ const targetId = typeof trigger.value === "string" ? trigger.value : "";
2320
+ if (!targetId) {
2321
+ popups.debug("Click trigger missing element id", trigger);
2322
+ return;
2323
+ }
2324
+ const attach = () => {
2325
+ const el = document.getElementById(targetId);
2326
+ if (!el) {
2327
+ popups.debug("Click trigger target not found", targetId);
2328
+ return false;
2329
+ }
2330
+ const handler = (e) => {
2331
+ if (e.defaultPrevented) return;
2332
+ popups.triggerSurvey(trigger.surveyId);
2333
+ el.removeEventListener("click", handler);
2334
+ };
2335
+ el.addEventListener("click", handler);
2336
+ popups.debug(`Click trigger set for #${targetId}`);
2337
+ return true;
2338
+ };
2339
+ if (typeof document === "undefined") return;
2340
+ if (attach()) return;
2341
+ window.addEventListener("DOMContentLoaded", () => attach(), { once: true });
2216
2342
  }
2217
2343
 
2218
2344
  // src/config/env.ts
2219
2345
  var ENVIRONMENT_MAP = {
2220
2346
  development: {
2221
- apiBaseUrl: "https://api-dev.magicfeedback.com"
2347
+ apiBaseUrl: "https://api-dev.deepdots.com"
2222
2348
  },
2223
2349
  production: {
2224
- apiBaseUrl: "https://api.magicfeedback.com"
2350
+ apiBaseUrl: "https://api.deepdots.com"
2225
2351
  }
2226
2352
  };
2227
2353
  function resolveEnvironment(nodeEnv) {
@@ -2303,10 +2429,10 @@ var BrowserPopupRenderer = class {
2303
2429
  document.body.appendChild(this.container);
2304
2430
  }
2305
2431
  }
2306
- show(surveyId, productId, actions, emit, onClose) {
2432
+ show(surveyId, productId, actions, emit, onClose, env = "production") {
2307
2433
  if (!this.container) this.init();
2308
2434
  if (!this.container) return;
2309
- renderPopup(this.container, surveyId, productId, actions, emit, onClose);
2435
+ renderPopup(this.container, surveyId, productId, actions, emit, onClose, env);
2310
2436
  }
2311
2437
  hide() {
2312
2438
  if (this.container) {
@@ -2339,8 +2465,12 @@ var DeepdotsPopups = class {
2339
2465
  this.pendingAutoLaunch = false;
2340
2466
  this.answeredSurveys = /* @__PURE__ */ new Set();
2341
2467
  this.lastShown = /* @__PURE__ */ new Map();
2468
+ // popupId -> timestamp mostrado
2469
+ this.surveyToPopupId = /* @__PURE__ */ new Map();
2470
+ // surveyId -> popupId
2471
+ this.baseUrl = "";
2472
+ this.env = "production";
2342
2473
  }
2343
- // popupId -> timestamp mostrado
2344
2474
  /** Initialize the SDK with configuration */
2345
2475
  init(config) {
2346
2476
  if (this.initialized) {
@@ -2348,12 +2478,14 @@ var DeepdotsPopups = class {
2348
2478
  return;
2349
2479
  }
2350
2480
  const env = resolveEnvironment(config.nodeEnv);
2481
+ this.baseUrl = env.apiBaseUrl;
2482
+ this.env = config.nodeEnv || "production";
2351
2483
  this.config = {
2352
2484
  apiKey: config.apiKey || void 0,
2353
- baseUrl: env.apiBaseUrl,
2354
2485
  mode: config.mode || "client",
2355
2486
  debug: config.debug || false,
2356
- popups: config.popups || []
2487
+ popups: config.popups || [],
2488
+ userId: config.userId || void 0
2357
2489
  };
2358
2490
  this.initialized = true;
2359
2491
  this.log("SDK initialized", this.config);
@@ -2402,8 +2534,9 @@ var DeepdotsPopups = class {
2402
2534
  if (isDefinition) {
2403
2535
  const def = options;
2404
2536
  this.log("Showing popup (definition)", def);
2537
+ this.surveyToPopupId.set(def.surveyId, def.id);
2405
2538
  this.renderPopup(def.surveyId, def.productId, def.actions);
2406
- this.emitEvent("popup_shown", def.surveyId);
2539
+ this.emitEvent("popup_shown", def.surveyId, { popupId: def.id });
2407
2540
  } else {
2408
2541
  const opt = options;
2409
2542
  this.log("Showing popup (legacy options)", opt);
@@ -2432,9 +2565,10 @@ var DeepdotsPopups = class {
2432
2565
  configureTriggersFromDefinitions() {
2433
2566
  const derived = [];
2434
2567
  const validDefs = this.validatePopupDefinitions(this.popupDefinitions);
2568
+ console.log("validDefs", validDefs);
2435
2569
  validDefs.forEach((def) => {
2436
- if (!def.trigger) return;
2437
- const t = def.trigger;
2570
+ if (!def.triggers) return;
2571
+ const t = def.triggers;
2438
2572
  let type;
2439
2573
  switch (t.type) {
2440
2574
  case "time_on_page":
@@ -2446,11 +2580,14 @@ var DeepdotsPopups = class {
2446
2580
  case "exit":
2447
2581
  type = "exit";
2448
2582
  break;
2583
+ case "click":
2584
+ type = "click";
2585
+ break;
2449
2586
  default:
2450
2587
  this.debug("Unsupported trigger type", t.type);
2451
2588
  return;
2452
2589
  }
2453
- const value = type === "time" ? t.value * 1e3 : t.value;
2590
+ const value = type === "time" && typeof t.value === "number" ? t.value * 1e3 : t.value;
2454
2591
  derived.push({ type, value, surveyId: def.surveyId });
2455
2592
  });
2456
2593
  if (derived.length) {
@@ -2472,10 +2609,52 @@ var DeepdotsPopups = class {
2472
2609
  this.lastShown.set(def.id, Date.now());
2473
2610
  }
2474
2611
  shouldShow(def) {
2475
- const conditions = def.trigger.condition || [];
2612
+ if (!this.matchesSegmentsPath(def)) {
2613
+ return false;
2614
+ }
2615
+ const conditions = def.triggers.condition || [];
2476
2616
  if (!conditions.length) return true;
2477
2617
  return conditions.every((c) => this.evaluateCondition(def, c));
2478
2618
  }
2619
+ matchesSegmentsPath(def) {
2620
+ const paths = def.segments?.path;
2621
+ if (!paths || paths.length === 0) return true;
2622
+ if (typeof window === "undefined" || !window.location) {
2623
+ this.debug("No window.location available for path comparison", { popupId: def.id, paths });
2624
+ return true;
2625
+ }
2626
+ const currentPath = window.location.pathname || "";
2627
+ const currentHref = window.location.href || "";
2628
+ const normalize = (value) => {
2629
+ if (value.length > 1 && value.endsWith("/")) return value.slice(0, -1);
2630
+ return value;
2631
+ };
2632
+ const normalizedPath = normalize(currentPath);
2633
+ const normalizedHref = normalize(currentHref);
2634
+ const matches = paths.some((rawCandidate) => {
2635
+ const candidate = normalize(rawCandidate);
2636
+ let match = false;
2637
+ if (candidate.startsWith("http://") || candidate.startsWith("https://")) {
2638
+ match = normalizedHref === candidate;
2639
+ } else if (candidate.startsWith("/")) {
2640
+ match = normalizedHref.includes(candidate);
2641
+ } else {
2642
+ match = normalizedPath === candidate;
2643
+ }
2644
+ this.debug("Path comparison", {
2645
+ popupId: def.id,
2646
+ candidate,
2647
+ currentPath: normalizedPath,
2648
+ currentHref: normalizedHref,
2649
+ match
2650
+ });
2651
+ return match;
2652
+ });
2653
+ if (!matches) {
2654
+ this.debug("No path match for popup", { popupId: def.id, paths, currentPath: normalizedPath });
2655
+ }
2656
+ return matches;
2657
+ }
2479
2658
  evaluateCondition(def, condition) {
2480
2659
  if (!condition.answered && this.answeredSurveys.has(def.surveyId)) {
2481
2660
  return false;
@@ -2494,29 +2673,59 @@ var DeepdotsPopups = class {
2494
2673
  markSurveyAnswered(surveyId) {
2495
2674
  this.answeredSurveys.add(surveyId);
2496
2675
  }
2497
- /** Simula fetch al servidor para obtener popups */
2676
+ /** Fetch al servidor para obtener popups */
2498
2677
  async fetchPopupsFromServer() {
2499
- await new Promise((res) => setTimeout(res, 50));
2500
- return this.generateFakePopups();
2678
+ const apiKey = this.config?.apiKey;
2679
+ const baseUrl = this.baseUrl;
2680
+ if (!apiKey || !baseUrl) {
2681
+ this.log("Missing apiKey or baseUrl. Skipping popups fetch.");
2682
+ return [];
2683
+ }
2684
+ const endpoint = `${baseUrl}/sdk/${encodeURIComponent(apiKey)}/popups`;
2685
+ try {
2686
+ const response = await fetch(endpoint);
2687
+ if (!response.ok) {
2688
+ this.log("Failed to fetch popups", response.status, response.statusText);
2689
+ return [];
2690
+ }
2691
+ const raw = await response.text();
2692
+ const parsed = JSON.parse(raw);
2693
+ if (!Array.isArray(parsed)) {
2694
+ this.log("Unexpected popups payload", parsed);
2695
+ return [];
2696
+ }
2697
+ console.log("res: ", parsed, this.validatePopupDefinitions(parsed));
2698
+ return parsed;
2699
+ } catch (error) {
2700
+ this.log("Error fetching popups", error);
2701
+ return [];
2702
+ }
2501
2703
  }
2502
- /** Genera datos fake para pruebas en modo server */
2503
- generateFakePopups() {
2504
- return [
2505
- {
2506
- id: "popup-123",
2507
- title: "Would you like to help us improve?",
2508
- message: "<p>Take a quick survey and share your thoughts.</p>",
2509
- trigger: { type: "time_on_page", value: 1, condition: [{ answered: false, cooldownDays: 7 }] },
2510
- actions: {
2511
- accept: { label: "Take Survey", surveyId: "survey-abc" },
2512
- decline: { label: "Not Now", cooldownDays: 7 }
2513
- },
2514
- surveyId: "survey-abc",
2515
- productId: "product-xyz",
2516
- style: { theme: "light", position: "bottom-right", imageUrl: null },
2517
- segments: { lang: ["en"], path: ["/checkout"] }
2704
+ /** Notifica eventos de popup a la API */
2705
+ async postPopupEvent(status, popupId, userId) {
2706
+ const apiKey = this.config?.apiKey;
2707
+ const baseUrl = this.baseUrl;
2708
+ if (!apiKey || !baseUrl) {
2709
+ return;
2710
+ }
2711
+ const endpoint = `${baseUrl}/sdk/popups`;
2712
+ try {
2713
+ const response = await fetch(endpoint, {
2714
+ method: "POST",
2715
+ headers: { "Content-Type": "application/json" },
2716
+ body: JSON.stringify({
2717
+ publicKey: apiKey,
2718
+ status,
2719
+ popupId,
2720
+ userId: userId || void 0
2721
+ })
2722
+ });
2723
+ if (!response.ok) {
2724
+ this.log("Failed to post popup event", response.status, response.statusText);
2518
2725
  }
2519
- ];
2726
+ } catch (error) {
2727
+ this.log("Error posting popup event", error);
2728
+ }
2520
2729
  }
2521
2730
  /** Add an event listener */
2522
2731
  on(eventType, listener) {
@@ -2556,11 +2765,26 @@ var DeepdotsPopups = class {
2556
2765
  /** Render the popup UI */
2557
2766
  renderPopup(surveyId, productId, actions) {
2558
2767
  if (this.renderer) {
2559
- this.renderer.show(surveyId, productId, actions, (type, id, payload) => this.emitEvent(type, id, payload), () => this.hidePopup());
2768
+ this.renderer.show(
2769
+ surveyId,
2770
+ productId,
2771
+ actions,
2772
+ (type, id, payload) => this.emitEvent(type, id, payload),
2773
+ () => this.hidePopup(),
2774
+ this.env
2775
+ );
2560
2776
  return;
2561
2777
  }
2562
2778
  if (!this.popupContainer) return;
2563
- renderPopup(this.popupContainer, surveyId, productId, actions, (type, id, payload) => this.emitEvent(type, id, payload), () => this.hidePopup());
2779
+ renderPopup(
2780
+ this.popupContainer,
2781
+ surveyId,
2782
+ productId,
2783
+ actions,
2784
+ (type, id, payload) => this.emitEvent(type, id, payload),
2785
+ () => this.hidePopup(),
2786
+ this.env
2787
+ );
2564
2788
  }
2565
2789
  /** Hide the popup */
2566
2790
  hidePopup() {
@@ -2580,6 +2804,16 @@ var DeepdotsPopups = class {
2580
2804
  if (type === "survey_completed") {
2581
2805
  this.markSurveyAnswered(surveyId);
2582
2806
  }
2807
+ if (type === "popup_shown" || type === "survey_completed") {
2808
+ const popupIdFromData = data?.popupId;
2809
+ const popupId = popupIdFromData || this.surveyToPopupId.get(surveyId);
2810
+ if (popupId) {
2811
+ const userIdFromData = data?.userId;
2812
+ void this.postPopupEvent(type === "popup_shown" ? "opened" : "completed", popupId, userIdFromData || this.config?.userId);
2813
+ } else {
2814
+ this.debug("No popupId available to post event", { type, surveyId });
2815
+ }
2816
+ }
2583
2817
  const listeners = this.listeners.get(type);
2584
2818
  if (listeners) {
2585
2819
  listeners.forEach((listener) => {
@@ -2612,10 +2846,26 @@ var DeepdotsPopups = class {
2612
2846
  isPopupDefinition(value) {
2613
2847
  if (typeof value !== "object" || value === null) return false;
2614
2848
  const v = value;
2615
- return typeof v.id === "string" && typeof v.title === "string" && typeof v.message === "string" && typeof v.surveyId === "string" && typeof v.productId === "string" && !!v.trigger;
2849
+ const trigger = v.triggers || v.triggers;
2850
+ if (!trigger) return false;
2851
+ return typeof v.id === "string" && typeof v.title === "string" && typeof v.message === "string" && typeof v.surveyId === "string" && typeof v.productId === "string";
2852
+ }
2853
+ normalizePopupDefinition(def) {
2854
+ if (typeof def !== "object" || def === null) return null;
2855
+ const raw = def;
2856
+ const trigger = raw.triggers || raw.triggers;
2857
+ if (!trigger) return null;
2858
+ const condition = trigger.condition ?? raw.conditions ?? [];
2859
+ return {
2860
+ ...raw,
2861
+ triggers: {
2862
+ ...trigger,
2863
+ condition
2864
+ }
2865
+ };
2616
2866
  }
2617
2867
  validatePopupDefinitions(defs) {
2618
- return defs.filter((d) => this.isPopupDefinition(d));
2868
+ return defs.map((def) => this.normalizePopupDefinition(def)).filter((def) => !!def && this.isPopupDefinition(def));
2619
2869
  }
2620
2870
  };
2621
2871
  export {