@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/README.md +6 -0
- package/dist/index.d.mts +30 -3
- package/dist/index.d.ts +30 -3
- package/dist/index.js +47 -10
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +48 -11
- package/dist/index.mjs.map +1 -1
- package/dist/react-native.d.mts +22 -2
- package/dist/react-native.d.ts +22 -2
- package/dist/react-native.js +47 -10
- package/dist/react-native.js.map +1 -1
- package/dist/react-native.mjs +48 -11
- package/dist/react-native.mjs.map +1 -1
- package/dist/{renderPopup-NJK7Z46E.mjs → renderPopup-TCKR5Z3P.mjs} +2 -2
- package/dist/{renderPopup-NJK7Z46E.mjs.map → renderPopup-TCKR5Z3P.mjs.map} +1 -1
- package/dist/{renderPopup-ZYXOUBCP.mjs → renderPopup-UYMGEBSI.mjs} +2 -2
- package/dist/{renderPopup-ZYXOUBCP.mjs.map → renderPopup-UYMGEBSI.mjs.map} +1 -1
- package/package.json +5 -10
package/dist/react-native.d.mts
CHANGED
|
@@ -162,6 +162,15 @@ interface DeepdotsInitParams {
|
|
|
162
162
|
* `setContactAttributes` after init (sends only when values changed from the last sync).
|
|
163
163
|
*/
|
|
164
164
|
contactAttributes?: Record<string, string | number | boolean>;
|
|
165
|
+
/**
|
|
166
|
+
* Whether the SDK renders the popup "modal" (card + backdrop + positioning) around the survey.
|
|
167
|
+
* Default `true`. Only affects React Native (the survey WebView HTML); the web DOM popup is
|
|
168
|
+
* unaffected. With `false` the survey is delivered transparent and edge-to-edge so the host
|
|
169
|
+
* mounts its own Modal/container and controls the styling — avoids the "double modal" when the
|
|
170
|
+
* host already wraps the WebView. The survey stays fully functional (bridge, form, nav buttons,
|
|
171
|
+
* close). Ver `ReactNativePopupRenderer`.
|
|
172
|
+
*/
|
|
173
|
+
renderChrome?: boolean;
|
|
165
174
|
}
|
|
166
175
|
/**
|
|
167
176
|
* Options for configuring survey triggers
|
|
@@ -243,7 +252,7 @@ interface PopupRenderer {
|
|
|
243
252
|
/** Preparar recursos si aplica */
|
|
244
253
|
init?(): void;
|
|
245
254
|
/** Mostrar popup */
|
|
246
|
-
show(surveyId: string, productId: string, actions: PopupActions | undefined, emit: (type: DeepdotsEventType, surveyId: string, data?: Record<string, unknown>) => void, onClose: () => void, env?: string, userId?: string, style?: PopupStyle, sessionId?: string, miniService?: string, analyticsFeedbackSessionId?: string): void;
|
|
255
|
+
show(surveyId: string, productId: string, actions: PopupActions | undefined, emit: (type: DeepdotsEventType, surveyId: string, data?: Record<string, unknown>) => void, onClose: () => void, env?: string, userId?: string, style?: PopupStyle, sessionId?: string, miniService?: string, analyticsFeedbackSessionId?: string, renderChrome?: boolean): void;
|
|
247
256
|
/** Ocultar popup */
|
|
248
257
|
hide(): void;
|
|
249
258
|
}
|
|
@@ -323,6 +332,8 @@ declare class DeepdotsPopups {
|
|
|
323
332
|
private deferredExitTimers;
|
|
324
333
|
private baseUrl;
|
|
325
334
|
private env;
|
|
335
|
+
/** Si el SDK pinta el "modal" del popup (RN). Default true; false = el host lo envuelve. */
|
|
336
|
+
private renderChrome;
|
|
326
337
|
/** Identidad + sesión (Fase 1 tracking). Null hasta init(). */
|
|
327
338
|
private tracking;
|
|
328
339
|
/** Capa de analytics (canal separado del feedback). Null hasta init(). */
|
|
@@ -394,6 +405,15 @@ declare class DeepdotsPopups {
|
|
|
394
405
|
trackFindabilityFriction(frictionTopic: string, params?: Record<string, unknown>): void;
|
|
395
406
|
/** Funnel: un paso del embudo, correlacionado por `taskId`. El backend reconstruye conversión/drop-off/tiempo. */
|
|
396
407
|
trackFunnelStep(funnel: string, step: string, taskId: string, params?: Record<string, unknown>): void;
|
|
408
|
+
/**
|
|
409
|
+
* Product Effectiveness: una interacción significativa del usuario (`interaction_type` es la
|
|
410
|
+
* dimensión de agrupación, p. ej. `get_help`, `homepage`, `contact_support`).
|
|
411
|
+
*
|
|
412
|
+
* Existe como evento RESERVADO para que la convención no la invente cada host: un `track()`
|
|
413
|
+
* custom acaba como `deepdots_event_…` y no lo cuenta la analítica de effectiveness.
|
|
414
|
+
* Un `interactionType` vacío se descarta con warning (no aporta dato agrupable).
|
|
415
|
+
*/
|
|
416
|
+
trackMeaningfulInteraction(interactionType: string, params?: Record<string, unknown>): void;
|
|
397
417
|
/**
|
|
398
418
|
* Messaging (#18–22): registra una etapa del funnel de una notificación (push/in-app).
|
|
399
419
|
* No-op si tracking off. El evento se descarta (con warning) si el `channel` no es válido,
|
|
@@ -612,7 +632,7 @@ declare class ReactNativePopupRenderer implements PopupRenderer {
|
|
|
612
632
|
private partialEmitted;
|
|
613
633
|
constructor(options?: ReactNativeRendererOptions);
|
|
614
634
|
init(): void;
|
|
615
|
-
show(surveyId: string, productId: string, actions: PopupActions | undefined, emit: EmitFn, onClose: () => void, env?: string, userId?: string, style?: PopupStyle, sessionId?: string, miniService?: string, analyticsFeedbackSessionId?: string): void;
|
|
635
|
+
show(surveyId: string, productId: string, actions: PopupActions | undefined, emit: EmitFn, onClose: () => void, env?: string, userId?: string, style?: PopupStyle, sessionId?: string, miniService?: string, analyticsFeedbackSessionId?: string, renderChrome?: boolean): void;
|
|
616
636
|
hide(): void;
|
|
617
637
|
/**
|
|
618
638
|
* El host la conecta al `onMessage` del WebView. Traduce los mensajes del survey a
|
package/dist/react-native.d.ts
CHANGED
|
@@ -162,6 +162,15 @@ interface DeepdotsInitParams {
|
|
|
162
162
|
* `setContactAttributes` after init (sends only when values changed from the last sync).
|
|
163
163
|
*/
|
|
164
164
|
contactAttributes?: Record<string, string | number | boolean>;
|
|
165
|
+
/**
|
|
166
|
+
* Whether the SDK renders the popup "modal" (card + backdrop + positioning) around the survey.
|
|
167
|
+
* Default `true`. Only affects React Native (the survey WebView HTML); the web DOM popup is
|
|
168
|
+
* unaffected. With `false` the survey is delivered transparent and edge-to-edge so the host
|
|
169
|
+
* mounts its own Modal/container and controls the styling — avoids the "double modal" when the
|
|
170
|
+
* host already wraps the WebView. The survey stays fully functional (bridge, form, nav buttons,
|
|
171
|
+
* close). Ver `ReactNativePopupRenderer`.
|
|
172
|
+
*/
|
|
173
|
+
renderChrome?: boolean;
|
|
165
174
|
}
|
|
166
175
|
/**
|
|
167
176
|
* Options for configuring survey triggers
|
|
@@ -243,7 +252,7 @@ interface PopupRenderer {
|
|
|
243
252
|
/** Preparar recursos si aplica */
|
|
244
253
|
init?(): void;
|
|
245
254
|
/** Mostrar popup */
|
|
246
|
-
show(surveyId: string, productId: string, actions: PopupActions | undefined, emit: (type: DeepdotsEventType, surveyId: string, data?: Record<string, unknown>) => void, onClose: () => void, env?: string, userId?: string, style?: PopupStyle, sessionId?: string, miniService?: string, analyticsFeedbackSessionId?: string): void;
|
|
255
|
+
show(surveyId: string, productId: string, actions: PopupActions | undefined, emit: (type: DeepdotsEventType, surveyId: string, data?: Record<string, unknown>) => void, onClose: () => void, env?: string, userId?: string, style?: PopupStyle, sessionId?: string, miniService?: string, analyticsFeedbackSessionId?: string, renderChrome?: boolean): void;
|
|
247
256
|
/** Ocultar popup */
|
|
248
257
|
hide(): void;
|
|
249
258
|
}
|
|
@@ -323,6 +332,8 @@ declare class DeepdotsPopups {
|
|
|
323
332
|
private deferredExitTimers;
|
|
324
333
|
private baseUrl;
|
|
325
334
|
private env;
|
|
335
|
+
/** Si el SDK pinta el "modal" del popup (RN). Default true; false = el host lo envuelve. */
|
|
336
|
+
private renderChrome;
|
|
326
337
|
/** Identidad + sesión (Fase 1 tracking). Null hasta init(). */
|
|
327
338
|
private tracking;
|
|
328
339
|
/** Capa de analytics (canal separado del feedback). Null hasta init(). */
|
|
@@ -394,6 +405,15 @@ declare class DeepdotsPopups {
|
|
|
394
405
|
trackFindabilityFriction(frictionTopic: string, params?: Record<string, unknown>): void;
|
|
395
406
|
/** Funnel: un paso del embudo, correlacionado por `taskId`. El backend reconstruye conversión/drop-off/tiempo. */
|
|
396
407
|
trackFunnelStep(funnel: string, step: string, taskId: string, params?: Record<string, unknown>): void;
|
|
408
|
+
/**
|
|
409
|
+
* Product Effectiveness: una interacción significativa del usuario (`interaction_type` es la
|
|
410
|
+
* dimensión de agrupación, p. ej. `get_help`, `homepage`, `contact_support`).
|
|
411
|
+
*
|
|
412
|
+
* Existe como evento RESERVADO para que la convención no la invente cada host: un `track()`
|
|
413
|
+
* custom acaba como `deepdots_event_…` y no lo cuenta la analítica de effectiveness.
|
|
414
|
+
* Un `interactionType` vacío se descarta con warning (no aporta dato agrupable).
|
|
415
|
+
*/
|
|
416
|
+
trackMeaningfulInteraction(interactionType: string, params?: Record<string, unknown>): void;
|
|
397
417
|
/**
|
|
398
418
|
* Messaging (#18–22): registra una etapa del funnel de una notificación (push/in-app).
|
|
399
419
|
* No-op si tracking off. El evento se descarta (con warning) si el `channel` no es válido,
|
|
@@ -612,7 +632,7 @@ declare class ReactNativePopupRenderer implements PopupRenderer {
|
|
|
612
632
|
private partialEmitted;
|
|
613
633
|
constructor(options?: ReactNativeRendererOptions);
|
|
614
634
|
init(): void;
|
|
615
|
-
show(surveyId: string, productId: string, actions: PopupActions | undefined, emit: EmitFn, onClose: () => void, env?: string, userId?: string, style?: PopupStyle, sessionId?: string, miniService?: string, analyticsFeedbackSessionId?: string): void;
|
|
635
|
+
show(surveyId: string, productId: string, actions: PopupActions | undefined, emit: EmitFn, onClose: () => void, env?: string, userId?: string, style?: PopupStyle, sessionId?: string, miniService?: string, analyticsFeedbackSessionId?: string, renderChrome?: boolean): void;
|
|
616
636
|
hide(): void;
|
|
617
637
|
/**
|
|
618
638
|
* El host la conecta al `onMessage` del WebView. Traduce los mensajes del survey a
|
package/dist/react-native.js
CHANGED
|
@@ -614,7 +614,7 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
|
|
|
614
614
|
};
|
|
615
615
|
generateOptions.onLoadedEvent = ({ formData }) => {
|
|
616
616
|
try {
|
|
617
|
-
} catch
|
|
617
|
+
} catch {
|
|
618
618
|
}
|
|
619
619
|
const s = formData?.style;
|
|
620
620
|
if (s && !stylesInjected) {
|
|
@@ -779,6 +779,10 @@ var POPUP_TRIGGER_CONDITION_STATUSES = [
|
|
|
779
779
|
];
|
|
780
780
|
|
|
781
781
|
// src/triggers/index.ts
|
|
782
|
+
function toNumericValue(value, fallback) {
|
|
783
|
+
const n = Number(value);
|
|
784
|
+
return Number.isFinite(n) ? n : fallback;
|
|
785
|
+
}
|
|
782
786
|
function setupTrigger(popups, trigger) {
|
|
783
787
|
switch (trigger.type) {
|
|
784
788
|
case "time":
|
|
@@ -799,14 +803,14 @@ function setupTrigger(popups, trigger) {
|
|
|
799
803
|
}
|
|
800
804
|
}
|
|
801
805
|
function setupTimeTrigger(popups, trigger) {
|
|
802
|
-
const delay = trigger.value
|
|
806
|
+
const delay = toNumericValue(trigger.value, 5e3);
|
|
803
807
|
setTimeout(() => {
|
|
804
808
|
popups.triggerSurvey(trigger.surveyId, trigger.popupId);
|
|
805
809
|
}, delay);
|
|
806
810
|
popups.debug(`Time trigger set for ${delay}ms`);
|
|
807
811
|
}
|
|
808
812
|
function setupScrollTrigger(popups, trigger) {
|
|
809
|
-
const threshold = trigger.value
|
|
813
|
+
const threshold = toNumericValue(trigger.value, 50);
|
|
810
814
|
const handler = () => {
|
|
811
815
|
const scrollPercentage = window.scrollY / (document.documentElement.scrollHeight - window.innerHeight) * 100;
|
|
812
816
|
if (scrollPercentage >= threshold) {
|
|
@@ -986,6 +990,16 @@ function buildSurveyHtml(opts) {
|
|
|
986
990
|
const colorScheme = isDark ? "dark" : "light";
|
|
987
991
|
const textPrimary = isDark ? "#f0f0f0" : "#111";
|
|
988
992
|
const pos = POSITION_MAP[opts.position ?? "center"] ?? POSITION_MAP.center;
|
|
993
|
+
const chrome = opts.chrome !== false;
|
|
994
|
+
const bodyBg = chrome ? pos.background : "transparent";
|
|
995
|
+
const bodyPadding = chrome ? pos.padding : "0";
|
|
996
|
+
const bodyDisplay = chrome ? "flex" : "block";
|
|
997
|
+
const cardBg = chrome ? popupBg : "transparent";
|
|
998
|
+
const cardShadow = chrome ? "0 4px 6px rgba(0,0,0,0.1)" : "none";
|
|
999
|
+
const cardRadius = chrome ? "8px" : "0";
|
|
1000
|
+
const cardMaxWidth = chrome ? "600px" : "none";
|
|
1001
|
+
const cardWidth = chrome ? "90%" : "100%";
|
|
1002
|
+
const cardMinHeight = chrome ? "200px" : "0";
|
|
989
1003
|
const backLabel = JSON.stringify(opts.actions?.back?.label ?? "Back");
|
|
990
1004
|
const startLabel = JSON.stringify(opts.actions?.start?.label ?? "Start survey");
|
|
991
1005
|
const completeLabel = JSON.stringify(opts.actions?.complete?.label ?? "Complete survey");
|
|
@@ -997,8 +1011,8 @@ function buildSurveyHtml(opts) {
|
|
|
997
1011
|
${style_default}
|
|
998
1012
|
${fontFaceCss}
|
|
999
1013
|
html,body{margin:0;padding:0;height:100%;font-family:${fontFamilyValue}}
|
|
1000
|
-
body{display
|
|
1001
|
-
.deepdots-popup{position:relative;display:flex;flex-direction:column;justify-content:flex-start;background:${
|
|
1014
|
+
body{display:${bodyDisplay};justify-content:${pos.justifyContent};align-items:${pos.alignItems};background:${bodyBg};padding:${bodyPadding};box-sizing:border-box}
|
|
1015
|
+
.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}
|
|
1002
1016
|
.deepdots-popup-header{display:flex;justify-content:flex-end;align-items:center;width:100%}
|
|
1003
1017
|
#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}
|
|
1004
1018
|
.deepdots-popup-container-content{display:flex;flex-direction:column;padding:0 20px 12px 20px;max-height:80vh;overflow:hidden;box-sizing:border-box}
|
|
@@ -1056,6 +1070,7 @@ body{display:flex;justify-content:${pos.justifyContent};align-items:${pos.alignI
|
|
|
1056
1070
|
function emit(s){ try{ if(window.ReactNativeWebView){ window.ReactNativeWebView.postMessage(s); } }catch(e){} }
|
|
1057
1071
|
function emitJSON(n,p){ try{ emit(JSON.stringify({name:n,payload:p||{}})); }catch(e){} }
|
|
1058
1072
|
window.DeepdotsClose = function(){ emitJSON('popup_close'); };
|
|
1073
|
+
var chromeOn=${chrome ? "true" : "false"};
|
|
1059
1074
|
|
|
1060
1075
|
var popup=document.getElementById('dd-popup');
|
|
1061
1076
|
var main=document.getElementById('dd-main');
|
|
@@ -1131,7 +1146,7 @@ body{display:flex;justify-content:${pos.justifyContent};align-items:${pos.alignI
|
|
|
1131
1146
|
var s=args && args.formData ? args.formData.style : null;
|
|
1132
1147
|
if(s && !stylesInjected){
|
|
1133
1148
|
stylesInjected=true;
|
|
1134
|
-
if(s.boxBackgroundColor){ popup.style.background=s.boxBackgroundColor; }
|
|
1149
|
+
if(chromeOn && s.boxBackgroundColor){ popup.style.background=s.boxBackgroundColor; }
|
|
1135
1150
|
if(s.contentAlign){ main.style.justifyContent = s.contentAlign==='center' ? 'center' : 'flex-start'; }
|
|
1136
1151
|
if(s.buttonPrimaryColor){
|
|
1137
1152
|
submitBtn.style.background=s.buttonPrimaryColor; submitBtn.style.border='none'; submitBtn.style.color='#fff';
|
|
@@ -1221,7 +1236,7 @@ var ReactNativePopupRenderer = class {
|
|
|
1221
1236
|
}
|
|
1222
1237
|
init() {
|
|
1223
1238
|
}
|
|
1224
|
-
show(surveyId, productId, actions, emit, onClose, env = "production", userId, style, sessionId, miniService, analyticsFeedbackSessionId) {
|
|
1239
|
+
show(surveyId, productId, actions, emit, onClose, env = "production", userId, style, sessionId, miniService, analyticsFeedbackSessionId, renderChrome) {
|
|
1225
1240
|
this.emitFn = emit;
|
|
1226
1241
|
this.onCloseFn = onClose;
|
|
1227
1242
|
this.currentSurveyId = surveyId;
|
|
@@ -1236,7 +1251,9 @@ var ReactNativePopupRenderer = class {
|
|
|
1236
1251
|
font: style?.font,
|
|
1237
1252
|
theme: style?.theme,
|
|
1238
1253
|
position: style?.position,
|
|
1239
|
-
actions
|
|
1254
|
+
actions,
|
|
1255
|
+
// renderChrome:false (init) → HTML sin tarjeta/overlay: el host lo envuelve en su Modal.
|
|
1256
|
+
chrome: renderChrome
|
|
1240
1257
|
});
|
|
1241
1258
|
if (this.options.onShow) {
|
|
1242
1259
|
this.options.onShow({ surveyId, productId, html });
|
|
@@ -1327,7 +1344,7 @@ var BrowserPopupRenderer = class {
|
|
|
1327
1344
|
document.body.appendChild(this.container);
|
|
1328
1345
|
}
|
|
1329
1346
|
}
|
|
1330
|
-
show(surveyId, productId, actions, emit, onClose, env = "production", userId, style, sessionId, miniService, analyticsFeedbackSessionId) {
|
|
1347
|
+
show(surveyId, productId, actions, emit, onClose, env = "production", userId, style, sessionId, miniService, analyticsFeedbackSessionId, _renderChrome) {
|
|
1331
1348
|
if (this.visible) return;
|
|
1332
1349
|
if (!this.container || !document.body.contains(this.container)) this.init();
|
|
1333
1350
|
if (!this.container) return;
|
|
@@ -2188,6 +2205,8 @@ var DeepdotsPopups = class {
|
|
|
2188
2205
|
this.deferredExitTimers = [];
|
|
2189
2206
|
this.baseUrl = "";
|
|
2190
2207
|
this.env = "production";
|
|
2208
|
+
/** Si el SDK pinta el "modal" del popup (RN). Default true; false = el host lo envuelve. */
|
|
2209
|
+
this.renderChrome = true;
|
|
2191
2210
|
/** Identidad + sesión (Fase 1 tracking). Null hasta init(). */
|
|
2192
2211
|
this.tracking = null;
|
|
2193
2212
|
/** Capa de analytics (canal separado del feedback). Null hasta init(). */
|
|
@@ -2238,6 +2257,7 @@ var DeepdotsPopups = class {
|
|
|
2238
2257
|
const env = resolveEnvironment(config.nodeEnv);
|
|
2239
2258
|
this.baseUrl = env.apiBaseUrl;
|
|
2240
2259
|
this.env = config.nodeEnv || "production";
|
|
2260
|
+
this.renderChrome = config.renderChrome ?? true;
|
|
2241
2261
|
this.config = {
|
|
2242
2262
|
apiKey: config.apiKey || void 0,
|
|
2243
2263
|
debug: config.debug || false,
|
|
@@ -2423,6 +2443,22 @@ var DeepdotsPopups = class {
|
|
|
2423
2443
|
trackFunnelStep(funnel, step, taskId, params) {
|
|
2424
2444
|
this.track("deepdots_funnel_step", { funnel, step, task_id: taskId, ...params ?? {} });
|
|
2425
2445
|
}
|
|
2446
|
+
/**
|
|
2447
|
+
* Product Effectiveness: una interacción significativa del usuario (`interaction_type` es la
|
|
2448
|
+
* dimensión de agrupación, p. ej. `get_help`, `homepage`, `contact_support`).
|
|
2449
|
+
*
|
|
2450
|
+
* Existe como evento RESERVADO para que la convención no la invente cada host: un `track()`
|
|
2451
|
+
* custom acaba como `deepdots_event_…` y no lo cuenta la analítica de effectiveness.
|
|
2452
|
+
* Un `interactionType` vacío se descarta con warning (no aporta dato agrupable).
|
|
2453
|
+
*/
|
|
2454
|
+
trackMeaningfulInteraction(interactionType, params) {
|
|
2455
|
+
const type = typeof interactionType === "string" ? interactionType.trim() : "";
|
|
2456
|
+
if (!type) {
|
|
2457
|
+
console.warn("[DeepdotsPopups] trackMeaningfulInteraction discarded: empty interaction_type");
|
|
2458
|
+
return;
|
|
2459
|
+
}
|
|
2460
|
+
this.track("deepdots_meaningful_interaction", { interaction_type: type, ...params ?? {} });
|
|
2461
|
+
}
|
|
2426
2462
|
/**
|
|
2427
2463
|
* Messaging (#18–22): registra una etapa del funnel de una notificación (push/in-app).
|
|
2428
2464
|
* No-op si tracking off. El evento se descarta (con warning) si el `channel` no es válido,
|
|
@@ -3023,7 +3059,8 @@ var DeepdotsPopups = class {
|
|
|
3023
3059
|
style,
|
|
3024
3060
|
sessionId,
|
|
3025
3061
|
miniService,
|
|
3026
|
-
analyticsFeedbackSessionId
|
|
3062
|
+
analyticsFeedbackSessionId,
|
|
3063
|
+
this.renderChrome
|
|
3027
3064
|
);
|
|
3028
3065
|
return;
|
|
3029
3066
|
}
|