@magicfeedback/popup-sdk 1.3.0 → 1.4.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.mjs CHANGED
@@ -19,6 +19,10 @@ var POPUP_TRIGGER_CONDITION_STATUSES = [
19
19
  ];
20
20
 
21
21
  // src/triggers/index.ts
22
+ function toNumericValue(value, fallback) {
23
+ const n = Number(value);
24
+ return Number.isFinite(n) ? n : fallback;
25
+ }
22
26
  function setupTrigger(popups, trigger) {
23
27
  switch (trigger.type) {
24
28
  case "time":
@@ -39,14 +43,14 @@ function setupTrigger(popups, trigger) {
39
43
  }
40
44
  }
41
45
  function setupTimeTrigger(popups, trigger) {
42
- const delay = trigger.value || 5e3;
46
+ const delay = toNumericValue(trigger.value, 5e3);
43
47
  setTimeout(() => {
44
48
  popups.triggerSurvey(trigger.surveyId, trigger.popupId);
45
49
  }, delay);
46
50
  popups.debug(`Time trigger set for ${delay}ms`);
47
51
  }
48
52
  function setupScrollTrigger(popups, trigger) {
49
- const threshold = trigger.value || 50;
53
+ const threshold = toNumericValue(trigger.value, 50);
50
54
  const handler = () => {
51
55
  const scrollPercentage = window.scrollY / (document.documentElement.scrollHeight - window.innerHeight) * 100;
52
56
  if (scrollPercentage >= threshold) {
@@ -221,6 +225,16 @@ function buildSurveyHtml(opts) {
221
225
  const colorScheme = isDark ? "dark" : "light";
222
226
  const textPrimary = isDark ? "#f0f0f0" : "#111";
223
227
  const pos = POSITION_MAP[opts.position ?? "center"] ?? POSITION_MAP.center;
228
+ const chrome = opts.chrome !== false;
229
+ const bodyBg = chrome ? pos.background : "transparent";
230
+ const bodyPadding = chrome ? pos.padding : "0";
231
+ const bodyDisplay = chrome ? "flex" : "block";
232
+ const cardBg = chrome ? popupBg : "transparent";
233
+ const cardShadow = chrome ? "0 4px 6px rgba(0,0,0,0.1)" : "none";
234
+ const cardRadius = chrome ? "8px" : "0";
235
+ const cardMaxWidth = chrome ? "600px" : "none";
236
+ const cardWidth = chrome ? "90%" : "100%";
237
+ const cardMinHeight = chrome ? "200px" : "0";
224
238
  const backLabel = JSON.stringify(opts.actions?.back?.label ?? "Back");
225
239
  const startLabel = JSON.stringify(opts.actions?.start?.label ?? "Start survey");
226
240
  const completeLabel = JSON.stringify(opts.actions?.complete?.label ?? "Complete survey");
@@ -232,8 +246,8 @@ function buildSurveyHtml(opts) {
232
246
  ${style_default}
233
247
  ${fontFaceCss}
234
248
  html,body{margin:0;padding:0;height:100%;font-family:${fontFamilyValue}}
235
- body{display:flex;justify-content:${pos.justifyContent};align-items:${pos.alignItems};background:${pos.background};padding:${pos.padding};box-sizing:border-box}
236
- .deepdots-popup{position:relative;display:flex;flex-direction:column;justify-content:flex-start;background:${popupBg};color-scheme:${colorScheme};border-radius:8px;padding:24px;box-shadow:0 4px 6px rgba(0,0,0,0.1);max-width:600px;width:90%;min-height:200px;box-sizing:border-box}
249
+ body{display:${bodyDisplay};justify-content:${pos.justifyContent};align-items:${pos.alignItems};background:${bodyBg};padding:${bodyPadding};box-sizing:border-box}
250
+ .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};box-sizing:border-box}
237
251
  .deepdots-popup-header{display:flex;justify-content:flex-end;align-items:center;width:100%}
238
252
  #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}
239
253
  .deepdots-popup-container-content{display:flex;flex-direction:column;padding:0 20px 12px 20px;max-height:80vh;overflow:hidden;box-sizing:border-box}
@@ -291,6 +305,7 @@ body{display:flex;justify-content:${pos.justifyContent};align-items:${pos.alignI
291
305
  function emit(s){ try{ if(window.ReactNativeWebView){ window.ReactNativeWebView.postMessage(s); } }catch(e){} }
292
306
  function emitJSON(n,p){ try{ emit(JSON.stringify({name:n,payload:p||{}})); }catch(e){} }
293
307
  window.DeepdotsClose = function(){ emitJSON('popup_close'); };
308
+ var chromeOn=${chrome ? "true" : "false"};
294
309
 
295
310
  var popup=document.getElementById('dd-popup');
296
311
  var main=document.getElementById('dd-main');
@@ -366,7 +381,7 @@ body{display:flex;justify-content:${pos.justifyContent};align-items:${pos.alignI
366
381
  var s=args && args.formData ? args.formData.style : null;
367
382
  if(s && !stylesInjected){
368
383
  stylesInjected=true;
369
- if(s.boxBackgroundColor){ popup.style.background=s.boxBackgroundColor; }
384
+ if(chromeOn && s.boxBackgroundColor){ popup.style.background=s.boxBackgroundColor; }
370
385
  if(s.contentAlign){ main.style.justifyContent = s.contentAlign==='center' ? 'center' : 'flex-start'; }
371
386
  if(s.buttonPrimaryColor){
372
387
  submitBtn.style.background=s.buttonPrimaryColor; submitBtn.style.border='none'; submitBtn.style.color='#fff';
@@ -455,7 +470,7 @@ var ReactNativePopupRenderer = class {
455
470
  }
456
471
  init() {
457
472
  }
458
- show(surveyId, productId, actions, emit, onClose, env = "production", userId, style, sessionId, miniService, analyticsFeedbackSessionId) {
473
+ show(surveyId, productId, actions, emit, onClose, env = "production", userId, style, sessionId, miniService, analyticsFeedbackSessionId, renderChrome) {
459
474
  this.emitFn = emit;
460
475
  this.onCloseFn = onClose;
461
476
  this.currentSurveyId = surveyId;
@@ -470,7 +485,9 @@ var ReactNativePopupRenderer = class {
470
485
  font: style?.font,
471
486
  theme: style?.theme,
472
487
  position: style?.position,
473
- actions
488
+ actions,
489
+ // renderChrome:false (init) → HTML sin tarjeta/overlay: el host lo envuelve en su Modal.
490
+ chrome: renderChrome
474
491
  });
475
492
  if (this.options.onShow) {
476
493
  this.options.onShow({ surveyId, productId, html });
@@ -561,13 +578,13 @@ var BrowserPopupRenderer = class {
561
578
  document.body.appendChild(this.container);
562
579
  }
563
580
  }
564
- show(surveyId, productId, actions, emit, onClose, env = "production", userId, style, sessionId, miniService, analyticsFeedbackSessionId) {
581
+ show(surveyId, productId, actions, emit, onClose, env = "production", userId, style, sessionId, miniService, analyticsFeedbackSessionId, _renderChrome) {
565
582
  if (this.visible) return;
566
583
  if (!this.container || !document.body.contains(this.container)) this.init();
567
584
  if (!this.container) return;
568
585
  this.visible = true;
569
586
  const container = this.container;
570
- void import("./renderPopup-NJK7Z46E.mjs").then(({ renderPopup }) => {
587
+ void import("./renderPopup-TCKR5Z3P.mjs").then(({ renderPopup }) => {
571
588
  renderPopup(container, surveyId, productId, actions, emit, onClose, env, userId, style, sessionId, miniService, analyticsFeedbackSessionId);
572
589
  });
573
590
  }
@@ -1415,6 +1432,8 @@ var DeepdotsPopups = class {
1415
1432
  this.deferredExitTimers = [];
1416
1433
  this.baseUrl = "";
1417
1434
  this.env = "production";
1435
+ /** Si el SDK pinta el "modal" del popup (RN). Default true; false = el host lo envuelve. */
1436
+ this.renderChrome = true;
1418
1437
  /** Identidad + sesión (Fase 1 tracking). Null hasta init(). */
1419
1438
  this.tracking = null;
1420
1439
  /** Capa de analytics (canal separado del feedback). Null hasta init(). */
@@ -1465,6 +1484,7 @@ var DeepdotsPopups = class {
1465
1484
  const env = resolveEnvironment(config.nodeEnv);
1466
1485
  this.baseUrl = env.apiBaseUrl;
1467
1486
  this.env = config.nodeEnv || "production";
1487
+ this.renderChrome = config.renderChrome ?? true;
1468
1488
  this.config = {
1469
1489
  apiKey: config.apiKey || void 0,
1470
1490
  debug: config.debug || false,
@@ -1650,6 +1670,22 @@ var DeepdotsPopups = class {
1650
1670
  trackFunnelStep(funnel, step, taskId, params) {
1651
1671
  this.track("deepdots_funnel_step", { funnel, step, task_id: taskId, ...params ?? {} });
1652
1672
  }
1673
+ /**
1674
+ * Product Effectiveness: una interacción significativa del usuario (`interaction_type` es la
1675
+ * dimensión de agrupación, p. ej. `get_help`, `homepage`, `contact_support`).
1676
+ *
1677
+ * Existe como evento RESERVADO para que la convención no la invente cada host: un `track()`
1678
+ * custom acaba como `deepdots_event_…` y no lo cuenta la analítica de effectiveness.
1679
+ * Un `interactionType` vacío se descarta con warning (no aporta dato agrupable).
1680
+ */
1681
+ trackMeaningfulInteraction(interactionType, params) {
1682
+ const type = typeof interactionType === "string" ? interactionType.trim() : "";
1683
+ if (!type) {
1684
+ console.warn("[DeepdotsPopups] trackMeaningfulInteraction discarded: empty interaction_type");
1685
+ return;
1686
+ }
1687
+ this.track("deepdots_meaningful_interaction", { interaction_type: type, ...params ?? {} });
1688
+ }
1653
1689
  /**
1654
1690
  * Messaging (#18–22): registra una etapa del funnel de una notificación (push/in-app).
1655
1691
  * No-op si tracking off. El evento se descarta (con warning) si el `channel` no es válido,
@@ -2250,13 +2286,14 @@ var DeepdotsPopups = class {
2250
2286
  style,
2251
2287
  sessionId,
2252
2288
  miniService,
2253
- analyticsFeedbackSessionId
2289
+ analyticsFeedbackSessionId,
2290
+ this.renderChrome
2254
2291
  );
2255
2292
  return;
2256
2293
  }
2257
2294
  if (!this.popupContainer) return;
2258
2295
  const container = this.popupContainer;
2259
- void import("./renderPopup-NJK7Z46E.mjs").then(({ renderPopup }) => {
2296
+ void import("./renderPopup-TCKR5Z3P.mjs").then(({ renderPopup }) => {
2260
2297
  renderPopup(
2261
2298
  container,
2262
2299
  surveyId,