@magicfeedback/popup-sdk 1.8.5 → 1.9.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 +40 -0
- package/dist/assets/assets/style.css +113 -60
- package/dist/{chunk-EBJZDVC6.mjs → chunk-AKVMUQXO.mjs} +114 -61
- package/dist/chunk-AKVMUQXO.mjs.map +1 -0
- package/dist/{chunk-AV2TTQXB.mjs → chunk-MTV7T4OW.mjs} +114 -61
- package/dist/chunk-MTV7T4OW.mjs.map +1 -0
- package/dist/index.d.mts +42 -1
- package/dist/index.d.ts +42 -1
- package/dist/index.js +156 -61
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +47 -5
- package/dist/index.mjs.map +1 -1
- package/dist/react-native.d.mts +35 -0
- package/dist/react-native.d.ts +35 -0
- package/dist/react-native.js +156 -61
- package/dist/react-native.js.map +1 -1
- package/dist/react-native.mjs +47 -5
- package/dist/react-native.mjs.map +1 -1
- package/dist/{renderPopup-3CZ6WTXF.mjs → renderPopup-LEGTSBLD.mjs} +2 -2
- package/dist/{renderPopup-E2OLIXIQ.mjs → renderPopup-LEM2MLWT.mjs} +2 -2
- package/package.json +1 -1
- package/dist/chunk-AV2TTQXB.mjs.map +0 -1
- package/dist/chunk-EBJZDVC6.mjs.map +0 -1
- /package/dist/{renderPopup-3CZ6WTXF.mjs.map → renderPopup-LEGTSBLD.mjs.map} +0 -0
- /package/dist/{renderPopup-E2OLIXIQ.mjs.map → renderPopup-LEM2MLWT.mjs.map} +0 -0
package/dist/index.d.mts
CHANGED
|
@@ -192,6 +192,12 @@ interface FeedbackSinkOptions {
|
|
|
192
192
|
onSessionId?: (id: string) => void;
|
|
193
193
|
/** Callback invocado al cerrar la sesión (`completed:true`): el sessionId cacheado se olvida. */
|
|
194
194
|
onSessionReset?: () => void;
|
|
195
|
+
/**
|
|
196
|
+
* Callback invocado cuando el backend acepta el lote de cierre, con el sessionId del
|
|
197
|
+
* registro cerrado: el que llevaba el lote o, en una sesión de un solo lote, el que
|
|
198
|
+
* devuelve la respuesta. Ese registro se convierte en Feedback en segundos.
|
|
199
|
+
*/
|
|
200
|
+
onSessionClosed?: (id: string) => void;
|
|
195
201
|
}
|
|
196
202
|
/**
|
|
197
203
|
* Sink real: transforma el envelope y hace `POST {baseUrl}/sdk/feedback`.
|
|
@@ -226,6 +232,19 @@ interface DeepdotsLogger {
|
|
|
226
232
|
error?: (...args: unknown[]) => void;
|
|
227
233
|
info?: (...args: unknown[]) => void;
|
|
228
234
|
}
|
|
235
|
+
/**
|
|
236
|
+
* A session of the analytics channel as the Deepdots API sees it. Every session becomes ONE
|
|
237
|
+
* feedback, and `sessionId` is what the API stores as `sdkSessionId` on it: the value to look
|
|
238
|
+
* that feedback up with (`GET /feedbacks?filter={"where":{"sdkSessionId":"<sessionId>"}}`).
|
|
239
|
+
* A session that closes again keeps that one feedback: the API updates it.
|
|
240
|
+
* - `open`: the API acknowledged the session's first batch; its events keep accumulating.
|
|
241
|
+
* - `closed`: the API acknowledged the session's closing batch (`completed: true`); the
|
|
242
|
+
* feedback is created from it within seconds.
|
|
243
|
+
*/
|
|
244
|
+
interface FeedbackSession {
|
|
245
|
+
sessionId: string;
|
|
246
|
+
status: 'open' | 'closed';
|
|
247
|
+
}
|
|
229
248
|
interface DeepdotsInitParams {
|
|
230
249
|
/** API key for authentication */
|
|
231
250
|
apiKey?: string;
|
|
@@ -261,6 +280,17 @@ interface DeepdotsInitParams {
|
|
|
261
280
|
* logged when `debug` is true.
|
|
262
281
|
*/
|
|
263
282
|
analytics?: AnalyticsKeys;
|
|
283
|
+
/**
|
|
284
|
+
* Called when the analytics channel opens or closes a session (needs `analytics`), with the
|
|
285
|
+
* id the Deepdots API stores as `sdkSessionId` on the feedback the session becomes: send it
|
|
286
|
+
* to your backend to attach data to that feedback later. A session whose only batch is the
|
|
287
|
+
* closing one reports just `closed`. `closed` does not come when the page unloads before the
|
|
288
|
+
* closing request returns, for a session dropped after 30 min hidden, nor when the closing
|
|
289
|
+
* request fails (the API closes those itself, later): their id already came with `open`. Key
|
|
290
|
+
* by `sessionId`, not by order: the next session's `open` can arrive before the previous
|
|
291
|
+
* one's `closed`. Same value as `getFeedbackSessionId()` while the session is open.
|
|
292
|
+
*/
|
|
293
|
+
onFeedbackSession?: (session: FeedbackSession) => void;
|
|
264
294
|
/**
|
|
265
295
|
* IP geolocation (country/city) added to analytics. Default `true`. The lookup calls
|
|
266
296
|
* third-party services (ipapi.co, then ipwho.is, then ipinfo.io as fallbacks, 3 s timeout
|
|
@@ -698,6 +728,8 @@ declare class DeepdotsPopups {
|
|
|
698
728
|
private analytics;
|
|
699
729
|
/** feedbackSessionId cacheado del canal de analytics (devuelto por POST /sdk/feedback). */
|
|
700
730
|
private analyticsFeedbackSessionId;
|
|
731
|
+
/** `init({ onFeedbackSession })`: avisa al host al abrir y cerrar cada registro. */
|
|
732
|
+
private onFeedbackSession;
|
|
701
733
|
/** Timer del flush periódico de analytics (cada ANALYTICS_FLUSH_INTERVAL_MS). */
|
|
702
734
|
private analyticsFlushTimer;
|
|
703
735
|
/** Crash & error reporting (#14–17). Null hasta init(). */
|
|
@@ -741,6 +773,15 @@ declare class DeepdotsPopups {
|
|
|
741
773
|
getUserId(): string | null;
|
|
742
774
|
/** Session id de navegación actual. Null si tracking off. */
|
|
743
775
|
getSessionId(): string | null;
|
|
776
|
+
/**
|
|
777
|
+
* Id del registro de analytics abierto: el `sessionId` que devolvió `POST /sdk/feedback`,
|
|
778
|
+
* que la API guarda como `sdkSessionId` en el Feedback en que se convierte la sesión. No es
|
|
779
|
+
* `getSessionId()`. Null hasta que el backend acepta el primer lote y de nuevo al cerrar la
|
|
780
|
+
* sesión: para saber también qué registro se cerró, usa `init({ onFeedbackSession })`.
|
|
781
|
+
*/
|
|
782
|
+
getFeedbackSessionId(): string | null;
|
|
783
|
+
/** Avisa al host del registro abierto o cerrado; un fallo del host no corta el envío. */
|
|
784
|
+
private notifyFeedbackSession;
|
|
744
785
|
/** Activa/desactiva el tracking (identidad + sesión + analytics). Kill-switch del contrato §7bis. */
|
|
745
786
|
setTrackingEnabled(enabled: boolean): void;
|
|
746
787
|
/** Registra un evento de analítica (modelo GA: nombre + params). No-op si tracking off. */
|
|
@@ -1265,4 +1306,4 @@ declare function collectRnDevice(d: DeviceInfoLike): DeviceInfo;
|
|
|
1265
1306
|
*/
|
|
1266
1307
|
declare function setupReactNative(sdk: DeepdotsPopups, config: DeepdotsInitParams, deps?: ReactNativeSetupDeps): () => void;
|
|
1267
1308
|
|
|
1268
|
-
export { type AnalyticsFeedbackBody, type AnalyticsKeys, type AppStateLike, BrowserPopupRenderer, type BuildBodyOptions, type ContactAttributeValue, type ContactAttributes, type ContactBody, ContactManager, type CrashRecord, CrashReporter, type CrashSeverity, type DeepdotsConfig, type DeepdotsEvent, type DeepdotsEventType, type DeepdotsInitParams, type DeepdotsLogger, DeepdotsPopups, type DeviceInfo, type DeviceInfoLike, type DeviceSnapshot, type EventListener, type FeedbackKV, InMemoryStorage, type KeyValueStorage, LABELS, MAX_TRACKED_MESSAGES, MESSAGE_CHANNELS, type MessageChannel, MessageGuard, type MessageGuardVerdict, type MessageRejectionReason, type MessageStage, type MmkvLike, NATIVE_READY_GRACE_MS, NoopPopupRenderer, POPUP_TRIGGER_CONDITION_STATUSES, type PopupDefinition, type PopupLabels, type PopupLocale, type PopupRenderer, type PopupTrigger, type PopupTriggerCondition, type PopupTriggerConditionStatus, REVEAL_TIMEOUT_MS, RTL_LOCALES, type ReactNativeErrorUtils, ReactNativePopupRenderer, type ReactNativeRendererOptions, type ReactNativeSetupDeps, type ReactNativeSurveyPayload, type ReportErrorOptions, type ResolvedActionLabels, SUPPORTED_LANGUAGES, type SessionEndReason, type TrackMessageOptions, type TriggerConfig, buildAnalyticsFeedbackBody, buildMessageParams, buildSurveyHtml, collectRnDevice, crashRecordToParams, createDefaultRenderer, createFeedbackSink, directionFor, getLabels, isRtlLanguage, mmkvStorage, resolveActionLabels, resolveLocale, setupReactNative };
|
|
1309
|
+
export { type AnalyticsFeedbackBody, type AnalyticsKeys, type AppStateLike, BrowserPopupRenderer, type BuildBodyOptions, type ContactAttributeValue, type ContactAttributes, type ContactBody, ContactManager, type CrashRecord, CrashReporter, type CrashSeverity, type DeepdotsConfig, type DeepdotsEvent, type DeepdotsEventType, type DeepdotsInitParams, type DeepdotsLogger, DeepdotsPopups, type DeviceInfo, type DeviceInfoLike, type DeviceSnapshot, type EventListener, type FeedbackKV, type FeedbackSession, InMemoryStorage, type KeyValueStorage, LABELS, MAX_TRACKED_MESSAGES, MESSAGE_CHANNELS, type MessageChannel, MessageGuard, type MessageGuardVerdict, type MessageRejectionReason, type MessageStage, type MmkvLike, NATIVE_READY_GRACE_MS, NoopPopupRenderer, POPUP_TRIGGER_CONDITION_STATUSES, type PopupDefinition, type PopupLabels, type PopupLocale, type PopupRenderer, type PopupTrigger, type PopupTriggerCondition, type PopupTriggerConditionStatus, REVEAL_TIMEOUT_MS, RTL_LOCALES, type ReactNativeErrorUtils, ReactNativePopupRenderer, type ReactNativeRendererOptions, type ReactNativeSetupDeps, type ReactNativeSurveyPayload, type ReportErrorOptions, type ResolvedActionLabels, SUPPORTED_LANGUAGES, type SessionEndReason, type TrackMessageOptions, type TriggerConfig, buildAnalyticsFeedbackBody, buildMessageParams, buildSurveyHtml, collectRnDevice, crashRecordToParams, createDefaultRenderer, createFeedbackSink, directionFor, getLabels, isRtlLanguage, mmkvStorage, resolveActionLabels, resolveLocale, setupReactNative };
|
package/dist/index.d.ts
CHANGED
|
@@ -192,6 +192,12 @@ interface FeedbackSinkOptions {
|
|
|
192
192
|
onSessionId?: (id: string) => void;
|
|
193
193
|
/** Callback invocado al cerrar la sesión (`completed:true`): el sessionId cacheado se olvida. */
|
|
194
194
|
onSessionReset?: () => void;
|
|
195
|
+
/**
|
|
196
|
+
* Callback invocado cuando el backend acepta el lote de cierre, con el sessionId del
|
|
197
|
+
* registro cerrado: el que llevaba el lote o, en una sesión de un solo lote, el que
|
|
198
|
+
* devuelve la respuesta. Ese registro se convierte en Feedback en segundos.
|
|
199
|
+
*/
|
|
200
|
+
onSessionClosed?: (id: string) => void;
|
|
195
201
|
}
|
|
196
202
|
/**
|
|
197
203
|
* Sink real: transforma el envelope y hace `POST {baseUrl}/sdk/feedback`.
|
|
@@ -226,6 +232,19 @@ interface DeepdotsLogger {
|
|
|
226
232
|
error?: (...args: unknown[]) => void;
|
|
227
233
|
info?: (...args: unknown[]) => void;
|
|
228
234
|
}
|
|
235
|
+
/**
|
|
236
|
+
* A session of the analytics channel as the Deepdots API sees it. Every session becomes ONE
|
|
237
|
+
* feedback, and `sessionId` is what the API stores as `sdkSessionId` on it: the value to look
|
|
238
|
+
* that feedback up with (`GET /feedbacks?filter={"where":{"sdkSessionId":"<sessionId>"}}`).
|
|
239
|
+
* A session that closes again keeps that one feedback: the API updates it.
|
|
240
|
+
* - `open`: the API acknowledged the session's first batch; its events keep accumulating.
|
|
241
|
+
* - `closed`: the API acknowledged the session's closing batch (`completed: true`); the
|
|
242
|
+
* feedback is created from it within seconds.
|
|
243
|
+
*/
|
|
244
|
+
interface FeedbackSession {
|
|
245
|
+
sessionId: string;
|
|
246
|
+
status: 'open' | 'closed';
|
|
247
|
+
}
|
|
229
248
|
interface DeepdotsInitParams {
|
|
230
249
|
/** API key for authentication */
|
|
231
250
|
apiKey?: string;
|
|
@@ -261,6 +280,17 @@ interface DeepdotsInitParams {
|
|
|
261
280
|
* logged when `debug` is true.
|
|
262
281
|
*/
|
|
263
282
|
analytics?: AnalyticsKeys;
|
|
283
|
+
/**
|
|
284
|
+
* Called when the analytics channel opens or closes a session (needs `analytics`), with the
|
|
285
|
+
* id the Deepdots API stores as `sdkSessionId` on the feedback the session becomes: send it
|
|
286
|
+
* to your backend to attach data to that feedback later. A session whose only batch is the
|
|
287
|
+
* closing one reports just `closed`. `closed` does not come when the page unloads before the
|
|
288
|
+
* closing request returns, for a session dropped after 30 min hidden, nor when the closing
|
|
289
|
+
* request fails (the API closes those itself, later): their id already came with `open`. Key
|
|
290
|
+
* by `sessionId`, not by order: the next session's `open` can arrive before the previous
|
|
291
|
+
* one's `closed`. Same value as `getFeedbackSessionId()` while the session is open.
|
|
292
|
+
*/
|
|
293
|
+
onFeedbackSession?: (session: FeedbackSession) => void;
|
|
264
294
|
/**
|
|
265
295
|
* IP geolocation (country/city) added to analytics. Default `true`. The lookup calls
|
|
266
296
|
* third-party services (ipapi.co, then ipwho.is, then ipinfo.io as fallbacks, 3 s timeout
|
|
@@ -698,6 +728,8 @@ declare class DeepdotsPopups {
|
|
|
698
728
|
private analytics;
|
|
699
729
|
/** feedbackSessionId cacheado del canal de analytics (devuelto por POST /sdk/feedback). */
|
|
700
730
|
private analyticsFeedbackSessionId;
|
|
731
|
+
/** `init({ onFeedbackSession })`: avisa al host al abrir y cerrar cada registro. */
|
|
732
|
+
private onFeedbackSession;
|
|
701
733
|
/** Timer del flush periódico de analytics (cada ANALYTICS_FLUSH_INTERVAL_MS). */
|
|
702
734
|
private analyticsFlushTimer;
|
|
703
735
|
/** Crash & error reporting (#14–17). Null hasta init(). */
|
|
@@ -741,6 +773,15 @@ declare class DeepdotsPopups {
|
|
|
741
773
|
getUserId(): string | null;
|
|
742
774
|
/** Session id de navegación actual. Null si tracking off. */
|
|
743
775
|
getSessionId(): string | null;
|
|
776
|
+
/**
|
|
777
|
+
* Id del registro de analytics abierto: el `sessionId` que devolvió `POST /sdk/feedback`,
|
|
778
|
+
* que la API guarda como `sdkSessionId` en el Feedback en que se convierte la sesión. No es
|
|
779
|
+
* `getSessionId()`. Null hasta que el backend acepta el primer lote y de nuevo al cerrar la
|
|
780
|
+
* sesión: para saber también qué registro se cerró, usa `init({ onFeedbackSession })`.
|
|
781
|
+
*/
|
|
782
|
+
getFeedbackSessionId(): string | null;
|
|
783
|
+
/** Avisa al host del registro abierto o cerrado; un fallo del host no corta el envío. */
|
|
784
|
+
private notifyFeedbackSession;
|
|
744
785
|
/** Activa/desactiva el tracking (identidad + sesión + analytics). Kill-switch del contrato §7bis. */
|
|
745
786
|
setTrackingEnabled(enabled: boolean): void;
|
|
746
787
|
/** Registra un evento de analítica (modelo GA: nombre + params). No-op si tracking off. */
|
|
@@ -1265,4 +1306,4 @@ declare function collectRnDevice(d: DeviceInfoLike): DeviceInfo;
|
|
|
1265
1306
|
*/
|
|
1266
1307
|
declare function setupReactNative(sdk: DeepdotsPopups, config: DeepdotsInitParams, deps?: ReactNativeSetupDeps): () => void;
|
|
1267
1308
|
|
|
1268
|
-
export { type AnalyticsFeedbackBody, type AnalyticsKeys, type AppStateLike, BrowserPopupRenderer, type BuildBodyOptions, type ContactAttributeValue, type ContactAttributes, type ContactBody, ContactManager, type CrashRecord, CrashReporter, type CrashSeverity, type DeepdotsConfig, type DeepdotsEvent, type DeepdotsEventType, type DeepdotsInitParams, type DeepdotsLogger, DeepdotsPopups, type DeviceInfo, type DeviceInfoLike, type DeviceSnapshot, type EventListener, type FeedbackKV, InMemoryStorage, type KeyValueStorage, LABELS, MAX_TRACKED_MESSAGES, MESSAGE_CHANNELS, type MessageChannel, MessageGuard, type MessageGuardVerdict, type MessageRejectionReason, type MessageStage, type MmkvLike, NATIVE_READY_GRACE_MS, NoopPopupRenderer, POPUP_TRIGGER_CONDITION_STATUSES, type PopupDefinition, type PopupLabels, type PopupLocale, type PopupRenderer, type PopupTrigger, type PopupTriggerCondition, type PopupTriggerConditionStatus, REVEAL_TIMEOUT_MS, RTL_LOCALES, type ReactNativeErrorUtils, ReactNativePopupRenderer, type ReactNativeRendererOptions, type ReactNativeSetupDeps, type ReactNativeSurveyPayload, type ReportErrorOptions, type ResolvedActionLabels, SUPPORTED_LANGUAGES, type SessionEndReason, type TrackMessageOptions, type TriggerConfig, buildAnalyticsFeedbackBody, buildMessageParams, buildSurveyHtml, collectRnDevice, crashRecordToParams, createDefaultRenderer, createFeedbackSink, directionFor, getLabels, isRtlLanguage, mmkvStorage, resolveActionLabels, resolveLocale, setupReactNative };
|
|
1309
|
+
export { type AnalyticsFeedbackBody, type AnalyticsKeys, type AppStateLike, BrowserPopupRenderer, type BuildBodyOptions, type ContactAttributeValue, type ContactAttributes, type ContactBody, ContactManager, type CrashRecord, CrashReporter, type CrashSeverity, type DeepdotsConfig, type DeepdotsEvent, type DeepdotsEventType, type DeepdotsInitParams, type DeepdotsLogger, DeepdotsPopups, type DeviceInfo, type DeviceInfoLike, type DeviceSnapshot, type EventListener, type FeedbackKV, type FeedbackSession, InMemoryStorage, type KeyValueStorage, LABELS, MAX_TRACKED_MESSAGES, MESSAGE_CHANNELS, type MessageChannel, MessageGuard, type MessageGuardVerdict, type MessageRejectionReason, type MessageStage, type MmkvLike, NATIVE_READY_GRACE_MS, NoopPopupRenderer, POPUP_TRIGGER_CONDITION_STATUSES, type PopupDefinition, type PopupLabels, type PopupLocale, type PopupRenderer, type PopupTrigger, type PopupTriggerCondition, type PopupTriggerConditionStatus, REVEAL_TIMEOUT_MS, RTL_LOCALES, type ReactNativeErrorUtils, ReactNativePopupRenderer, type ReactNativeRendererOptions, type ReactNativeSetupDeps, type ReactNativeSurveyPayload, type ReportErrorOptions, type ResolvedActionLabels, SUPPORTED_LANGUAGES, type SessionEndReason, type TrackMessageOptions, type TriggerConfig, buildAnalyticsFeedbackBody, buildMessageParams, buildSurveyHtml, collectRnDevice, crashRecordToParams, createDefaultRenderer, createFeedbackSink, directionFor, getLabels, isRtlLanguage, mmkvStorage, resolveActionLabels, resolveLocale, setupReactNative };
|
package/dist/index.js
CHANGED
|
@@ -583,7 +583,9 @@ var init_style = __esm({
|
|
|
583
583
|
* repintar\xEDa su web.
|
|
584
584
|
* 4. El grupo .magicfeedback-radio se cualifica como div.magicfeedback-radio (la clase acaba
|
|
585
585
|
* tambi\xE9n en el <input> del boolean).
|
|
586
|
-
* 5.
|
|
586
|
+
* 5. Todo :hover va dentro de @media (hover: hover): en t\xE1ctil WebKit deja el hover pegado
|
|
587
|
+
* en el \xFAltimo punto tocado y la opci\xF3n de la p\xE1gina siguiente parec\xEDa seleccionada.
|
|
588
|
+
* 6. Al final, un bloque de reglas propias del popup (fuente en los controles y padding del
|
|
587
589
|
* radio nativo).
|
|
588
590
|
*
|
|
589
591
|
* Las variables --mf-* se dejan en :root a prop\xF3sito: el modal del priority-list se portea a
|
|
@@ -821,9 +823,11 @@ var init_style = __esm({
|
|
|
821
823
|
text-underline-offset: 2px;
|
|
822
824
|
}
|
|
823
825
|
|
|
824
|
-
|
|
825
|
-
.magicfeedback-
|
|
826
|
-
|
|
826
|
+
@media (hover: hover) {
|
|
827
|
+
.magicfeedback-info-message a:hover,
|
|
828
|
+
.magicfeedback-start-message a:hover {
|
|
829
|
+
color: var(--mf-primary-hover);
|
|
830
|
+
}
|
|
827
831
|
}
|
|
828
832
|
|
|
829
833
|
.magicfeedback-info-message ul,
|
|
@@ -1049,10 +1053,12 @@ div.magicfeedback-radio {
|
|
|
1049
1053
|
transition: var(--mf-transition-fast);
|
|
1050
1054
|
}
|
|
1051
1055
|
|
|
1052
|
-
|
|
1053
|
-
.magicfeedback-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
+
@media (hover: hover) {
|
|
1057
|
+
.magicfeedback-checkbox-container:hover,
|
|
1058
|
+
.magicfeedback-radio-container:hover {
|
|
1059
|
+
background-color: var(--mf-bg-hover);
|
|
1060
|
+
border-color: var(--mf-primary);
|
|
1061
|
+
}
|
|
1056
1062
|
}
|
|
1057
1063
|
|
|
1058
1064
|
.magicfeedback-checkbox-container:has(input:checked),
|
|
@@ -1119,9 +1125,11 @@ div.magicfeedback-radio {
|
|
|
1119
1125
|
height: inherit;
|
|
1120
1126
|
}
|
|
1121
1127
|
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1128
|
+
@media (hover: hover) {
|
|
1129
|
+
.magicfeedback-boolean-option label:hover {
|
|
1130
|
+
background-color: var(--mf-bg-hover);
|
|
1131
|
+
border-color: var(--mf-primary);
|
|
1132
|
+
}
|
|
1125
1133
|
}
|
|
1126
1134
|
|
|
1127
1135
|
.magicfeedback-boolean-option input[type="radio"]:checked + label {
|
|
@@ -1192,9 +1200,11 @@ div.magicfeedback-radio {
|
|
|
1192
1200
|
border: 2px solid transparent;
|
|
1193
1201
|
}
|
|
1194
1202
|
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1203
|
+
@media (hover: hover) {
|
|
1204
|
+
.magicfeedback-rating-option-label-container img:hover {
|
|
1205
|
+
transform: scale(1.1);
|
|
1206
|
+
border-color: var(--mf-primary);
|
|
1207
|
+
}
|
|
1198
1208
|
}
|
|
1199
1209
|
|
|
1200
1210
|
.magicfeedback-rating-option-label-container input[type="radio"]:checked + img {
|
|
@@ -1346,9 +1356,11 @@ div.magicfeedback-radio {
|
|
|
1346
1356
|
font-size: 0.8rem;
|
|
1347
1357
|
}
|
|
1348
1358
|
|
|
1349
|
-
|
|
1350
|
-
.magicfeedback-rating-number-option-row
|
|
1351
|
-
|
|
1359
|
+
@media (hover: hover) {
|
|
1360
|
+
.magicfeedback-rating-number-option-row .magicfeedback-rating-number-option-label-container:hover .magicfeedback-rating-number-value,
|
|
1361
|
+
.magicfeedback-rating-number-option-row-reverse .magicfeedback-rating-number-option-label-container:hover .magicfeedback-rating-number-value {
|
|
1362
|
+
background: var(--mf-primary-light);
|
|
1363
|
+
}
|
|
1352
1364
|
}
|
|
1353
1365
|
|
|
1354
1366
|
.magicfeedback-rating-number-option-row .magicfeedback-rating-number-option-label-container input[type="radio"]:checked + .magicfeedback-rating-number-value,
|
|
@@ -1385,8 +1397,10 @@ div.magicfeedback-radio {
|
|
|
1385
1397
|
font-size: var(--mf-font-size-sm);
|
|
1386
1398
|
}
|
|
1387
1399
|
|
|
1388
|
-
|
|
1389
|
-
|
|
1400
|
+
@media (hover: hover) {
|
|
1401
|
+
.magicfeedback-rating-number-option--extra .magicfeedback-rating-number-option-label-container:hover .magicfeedback-rating-number-value {
|
|
1402
|
+
background: var(--mf-primary-light);
|
|
1403
|
+
}
|
|
1390
1404
|
}
|
|
1391
1405
|
|
|
1392
1406
|
.magicfeedback-rating-number-option--extra .magicfeedback-rating-number-option-label-container input[type="radio"]:checked + .magicfeedback-rating-number-value {
|
|
@@ -1419,9 +1433,11 @@ div.magicfeedback-radio {
|
|
|
1419
1433
|
color: var(--mf-primary);
|
|
1420
1434
|
}
|
|
1421
1435
|
|
|
1422
|
-
|
|
1423
|
-
.magicfeedback-rating-number-option-column
|
|
1424
|
-
|
|
1436
|
+
@media (hover: hover) {
|
|
1437
|
+
.magicfeedback-rating-number-option-column .magicfeedback-rating-number-option-label-container:hover .magicfeedback-rating-number-value,
|
|
1438
|
+
.magicfeedback-rating-number-option-column-reverse .magicfeedback-rating-number-option-label-container:hover .magicfeedback-rating-number-value {
|
|
1439
|
+
background: var(--mf-primary-light);
|
|
1440
|
+
}
|
|
1425
1441
|
}
|
|
1426
1442
|
|
|
1427
1443
|
.magicfeedback-rating-number-option-column .magicfeedback-rating-number-option-label-container input[type="radio"]:checked + .magicfeedback-rating-number-value,
|
|
@@ -1475,10 +1491,12 @@ div.magicfeedback-radio {
|
|
|
1475
1491
|
transition: var(--mf-transition-fast);
|
|
1476
1492
|
}
|
|
1477
1493
|
|
|
1478
|
-
|
|
1479
|
-
.magicfeedback-rating-star-option:not(:checked) > .rating__star:hover
|
|
1480
|
-
|
|
1481
|
-
|
|
1494
|
+
@media (hover: hover) {
|
|
1495
|
+
.magicfeedback-rating-star-option:not(:checked) > .rating__star:hover,
|
|
1496
|
+
.magicfeedback-rating-star-option:not(:checked) > .rating__star:hover ~ span {
|
|
1497
|
+
color: #fbbf24;
|
|
1498
|
+
transform: scale(1.1);
|
|
1499
|
+
}
|
|
1482
1500
|
}
|
|
1483
1501
|
|
|
1484
1502
|
.magicfeedback-rating-star-selected {
|
|
@@ -1519,9 +1537,11 @@ div.magicfeedback-radio {
|
|
|
1519
1537
|
transition: var(--mf-transition-fast);
|
|
1520
1538
|
}
|
|
1521
1539
|
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1540
|
+
@media (hover: hover) {
|
|
1541
|
+
.magicfeedback-image-option-label-container:hover img {
|
|
1542
|
+
border-color: var(--mf-primary);
|
|
1543
|
+
box-shadow: var(--mf-shadow-md);
|
|
1544
|
+
}
|
|
1525
1545
|
}
|
|
1526
1546
|
|
|
1527
1547
|
.magicfeedback-image-option-label-container input:checked + img {
|
|
@@ -1562,9 +1582,11 @@ div.magicfeedback-radio {
|
|
|
1562
1582
|
background-color: var(--mf-bg-secondary);
|
|
1563
1583
|
}
|
|
1564
1584
|
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1585
|
+
@media (hover: hover) {
|
|
1586
|
+
.magicfeedback-multi-question-matrix-row-tr:hover {
|
|
1587
|
+
background-color: var(--mf-bg-hover);
|
|
1588
|
+
box-shadow: var(--mf-shadow-sm);
|
|
1589
|
+
}
|
|
1568
1590
|
}
|
|
1569
1591
|
|
|
1570
1592
|
.magicfeedback-multi-question-matrix-table td {
|
|
@@ -1600,9 +1622,11 @@ div.magicfeedback-radio {
|
|
|
1600
1622
|
transition: var(--mf-transition-fast);
|
|
1601
1623
|
}
|
|
1602
1624
|
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1625
|
+
@media (hover: hover) {
|
|
1626
|
+
.magicfeedback-priority-list-item:hover {
|
|
1627
|
+
box-shadow: var(--mf-shadow-sm);
|
|
1628
|
+
border-color: var(--mf-primary);
|
|
1629
|
+
}
|
|
1606
1630
|
}
|
|
1607
1631
|
|
|
1608
1632
|
.magicfeedback-priority-list-item-label {
|
|
@@ -1623,10 +1647,12 @@ div.magicfeedback-radio {
|
|
|
1623
1647
|
user-select: none;
|
|
1624
1648
|
}
|
|
1625
1649
|
|
|
1626
|
-
|
|
1627
|
-
.magicfeedback-priority-list-arrow-
|
|
1628
|
-
|
|
1629
|
-
|
|
1650
|
+
@media (hover: hover) {
|
|
1651
|
+
.magicfeedback-priority-list-arrow-up:hover,
|
|
1652
|
+
.magicfeedback-priority-list-arrow-down:hover {
|
|
1653
|
+
color: var(--mf-primary);
|
|
1654
|
+
transform: scale(1.2);
|
|
1655
|
+
}
|
|
1630
1656
|
}
|
|
1631
1657
|
|
|
1632
1658
|
/* ========================================
|
|
@@ -1733,10 +1759,12 @@ div.magicfeedback-radio {
|
|
|
1733
1759
|
box-shadow: var(--mf-shadow-md);
|
|
1734
1760
|
}
|
|
1735
1761
|
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1762
|
+
@media (hover: hover) {
|
|
1763
|
+
.magicfeedback-submit:hover {
|
|
1764
|
+
background-color: var(--mf-primary-hover);
|
|
1765
|
+
box-shadow: var(--mf-shadow-lg);
|
|
1766
|
+
transform: translateY(-2px);
|
|
1767
|
+
}
|
|
1740
1768
|
}
|
|
1741
1769
|
|
|
1742
1770
|
.magicfeedback-submit:active {
|
|
@@ -1762,9 +1790,11 @@ div.magicfeedback-radio {
|
|
|
1762
1790
|
transition: var(--mf-transition-fast);
|
|
1763
1791
|
}
|
|
1764
1792
|
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1793
|
+
@media (hover: hover) {
|
|
1794
|
+
.magicfeedback-back:hover {
|
|
1795
|
+
border-color: var(--mf-primary);
|
|
1796
|
+
background-color: var(--mf-bg-hover);
|
|
1797
|
+
}
|
|
1768
1798
|
}
|
|
1769
1799
|
|
|
1770
1800
|
/* ========================================
|
|
@@ -1784,8 +1814,10 @@ div.magicfeedback-radio {
|
|
|
1784
1814
|
transition: var(--mf-transition-fast);
|
|
1785
1815
|
}
|
|
1786
1816
|
|
|
1787
|
-
|
|
1788
|
-
|
|
1817
|
+
@media (hover: hover) {
|
|
1818
|
+
.magicfeedback-skip-container:hover {
|
|
1819
|
+
color: var(--mf-primary);
|
|
1820
|
+
}
|
|
1789
1821
|
}
|
|
1790
1822
|
|
|
1791
1823
|
.magicfeedback-skip-container input[type="checkbox"] {
|
|
@@ -1926,9 +1958,11 @@ div.magicfeedback-radio {
|
|
|
1926
1958
|
box-shadow: var(--mf-shadow-sm);
|
|
1927
1959
|
}
|
|
1928
1960
|
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1961
|
+
@media (hover: hover) {
|
|
1962
|
+
.magicfeedback-button:hover {
|
|
1963
|
+
background: var(--mf-bg-hover);
|
|
1964
|
+
border-color: var(--mf-primary);
|
|
1965
|
+
}
|
|
1932
1966
|
}
|
|
1933
1967
|
|
|
1934
1968
|
.magicfeedback-button:active {
|
|
@@ -1942,8 +1976,10 @@ div.magicfeedback-radio {
|
|
|
1942
1976
|
box-shadow: var(--mf-shadow-md);
|
|
1943
1977
|
}
|
|
1944
1978
|
|
|
1945
|
-
|
|
1946
|
-
|
|
1979
|
+
@media (hover: hover) {
|
|
1980
|
+
.magicfeedback-button-primary:hover {
|
|
1981
|
+
background: var(--mf-primary-hover);
|
|
1982
|
+
}
|
|
1947
1983
|
}
|
|
1948
1984
|
|
|
1949
1985
|
.magicfeedback-button-primary:active {
|
|
@@ -1969,8 +2005,10 @@ div.magicfeedback-radio {
|
|
|
1969
2005
|
box-shadow: var(--mf-shadow-md);
|
|
1970
2006
|
}
|
|
1971
2007
|
|
|
1972
|
-
|
|
1973
|
-
|
|
2008
|
+
@media (hover: hover) {
|
|
2009
|
+
.magicfeedback-start-message-button:hover {
|
|
2010
|
+
background: var(--mf-primary-hover);
|
|
2011
|
+
}
|
|
1974
2012
|
}
|
|
1975
2013
|
|
|
1976
2014
|
/* ========================================
|
|
@@ -2106,12 +2144,18 @@ div.magicfeedback-radio {
|
|
|
2106
2144
|
color: #666;
|
|
2107
2145
|
}
|
|
2108
2146
|
|
|
2109
|
-
.magicfeedback-modal-close:hover,
|
|
2110
2147
|
.magicfeedback-modal-close:focus {
|
|
2111
2148
|
color: #000;
|
|
2112
2149
|
outline: none;
|
|
2113
2150
|
}
|
|
2114
2151
|
|
|
2152
|
+
@media (hover: hover) {
|
|
2153
|
+
.magicfeedback-modal-close:hover {
|
|
2154
|
+
color: #000;
|
|
2155
|
+
outline: none;
|
|
2156
|
+
}
|
|
2157
|
+
}
|
|
2158
|
+
|
|
2115
2159
|
/* ========================================
|
|
2116
2160
|
FILE / IMAGE UPLOAD
|
|
2117
2161
|
======================================== */
|
|
@@ -2155,9 +2199,11 @@ div.magicfeedback-radio {
|
|
|
2155
2199
|
transition: var(--mf-transition);
|
|
2156
2200
|
}
|
|
2157
2201
|
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2202
|
+
@media (hover: hover) {
|
|
2203
|
+
.magicfeedback-upload-dropzone:hover {
|
|
2204
|
+
border-color: var(--mf-primary);
|
|
2205
|
+
background-color: var(--mf-bg-hover);
|
|
2206
|
+
}
|
|
2161
2207
|
}
|
|
2162
2208
|
|
|
2163
2209
|
.magicfeedback-upload-dropzone:focus-within {
|
|
@@ -2295,13 +2341,20 @@ div.magicfeedback-radio {
|
|
|
2295
2341
|
transition: var(--mf-transition-fast);
|
|
2296
2342
|
}
|
|
2297
2343
|
|
|
2298
|
-
.magicfeedback-upload-remove:hover,
|
|
2299
2344
|
.magicfeedback-upload-remove:focus-visible {
|
|
2300
2345
|
color: var(--mf-error);
|
|
2301
2346
|
background-color: var(--mf-primary-light);
|
|
2302
2347
|
outline: none;
|
|
2303
2348
|
}
|
|
2304
2349
|
|
|
2350
|
+
@media (hover: hover) {
|
|
2351
|
+
.magicfeedback-upload-remove:hover {
|
|
2352
|
+
color: var(--mf-error);
|
|
2353
|
+
background-color: var(--mf-primary-light);
|
|
2354
|
+
outline: none;
|
|
2355
|
+
}
|
|
2356
|
+
}
|
|
2357
|
+
|
|
2305
2358
|
.magicfeedback-upload-remove svg {
|
|
2306
2359
|
width: 16px;
|
|
2307
2360
|
height: 16px;
|
|
@@ -6816,8 +6869,10 @@ async function safeBodyText(res) {
|
|
|
6816
6869
|
function createFeedbackSink(options) {
|
|
6817
6870
|
let feedbackSessionId;
|
|
6818
6871
|
let firstPostInFlight = null;
|
|
6872
|
+
let generation = 0;
|
|
6819
6873
|
const url = `${options.baseUrl}/sdk/feedback`;
|
|
6820
6874
|
const post = async (body, final, sessionEnd = false) => {
|
|
6875
|
+
const postGeneration = generation;
|
|
6821
6876
|
const json = JSON.stringify(body);
|
|
6822
6877
|
const small = json.length <= KEEPALIVE_MAX_BYTES;
|
|
6823
6878
|
if (final) options.log?.("[DeepdotsAnalytics] final flush via fetch keepalive");
|
|
@@ -6847,9 +6902,25 @@ function createFeedbackSink(options) {
|
|
|
6847
6902
|
);
|
|
6848
6903
|
return;
|
|
6849
6904
|
}
|
|
6850
|
-
if (sessionEnd)
|
|
6905
|
+
if (sessionEnd) {
|
|
6906
|
+
let closedId = body.sessionId;
|
|
6907
|
+
try {
|
|
6908
|
+
const data = await res.json();
|
|
6909
|
+
closedId = data?.sessionId ?? closedId;
|
|
6910
|
+
} catch {
|
|
6911
|
+
}
|
|
6912
|
+
try {
|
|
6913
|
+
if (closedId) options.onSessionClosed?.(closedId);
|
|
6914
|
+
} catch {
|
|
6915
|
+
}
|
|
6916
|
+
return;
|
|
6917
|
+
}
|
|
6851
6918
|
try {
|
|
6852
6919
|
const data = await res.json();
|
|
6920
|
+
if (postGeneration !== generation) {
|
|
6921
|
+
options.log?.("[DeepdotsAnalytics] sessionId of a closed session ignored:", data?.sessionId);
|
|
6922
|
+
return;
|
|
6923
|
+
}
|
|
6853
6924
|
if (data?.sessionId && data.sessionId !== feedbackSessionId) {
|
|
6854
6925
|
feedbackSessionId = data.sessionId;
|
|
6855
6926
|
options.log?.("[DeepdotsAnalytics] feedbackSessionId cached:", feedbackSessionId);
|
|
@@ -6862,6 +6933,7 @@ function createFeedbackSink(options) {
|
|
|
6862
6933
|
if (meta?.resetSession) {
|
|
6863
6934
|
feedbackSessionId = void 0;
|
|
6864
6935
|
firstPostInFlight = null;
|
|
6936
|
+
generation++;
|
|
6865
6937
|
options.onSessionReset?.();
|
|
6866
6938
|
return;
|
|
6867
6939
|
}
|
|
@@ -6876,6 +6948,7 @@ function createFeedbackSink(options) {
|
|
|
6876
6948
|
if (sessionEnd) {
|
|
6877
6949
|
feedbackSessionId = void 0;
|
|
6878
6950
|
firstPostInFlight = null;
|
|
6951
|
+
generation++;
|
|
6879
6952
|
options.onSessionReset?.();
|
|
6880
6953
|
} else if (!feedbackSessionId) {
|
|
6881
6954
|
firstPostInFlight = sent.then(
|
|
@@ -7526,6 +7599,8 @@ var DeepdotsPopups = class {
|
|
|
7526
7599
|
this.analytics = null;
|
|
7527
7600
|
/** feedbackSessionId cacheado del canal de analytics (devuelto por POST /sdk/feedback). */
|
|
7528
7601
|
this.analyticsFeedbackSessionId = void 0;
|
|
7602
|
+
/** `init({ onFeedbackSession })`: avisa al host al abrir y cerrar cada registro. */
|
|
7603
|
+
this.onFeedbackSession = void 0;
|
|
7529
7604
|
/** Timer del flush periódico de analytics (cada ANALYTICS_FLUSH_INTERVAL_MS). */
|
|
7530
7605
|
this.analyticsFlushTimer = void 0;
|
|
7531
7606
|
/** Crash & error reporting (#14–17). Null hasta init(). */
|
|
@@ -7583,6 +7658,7 @@ var DeepdotsPopups = class {
|
|
|
7583
7658
|
this.renderChrome = config.renderChrome ?? true;
|
|
7584
7659
|
this.showProgressBar = config.showProgressBar;
|
|
7585
7660
|
this.surveyCss = config.surveyCss;
|
|
7661
|
+
this.onFeedbackSession = config.onFeedbackSession;
|
|
7586
7662
|
this.config = {
|
|
7587
7663
|
apiKey: config.apiKey || void 0,
|
|
7588
7664
|
debug: config.debug || false,
|
|
@@ -7616,7 +7692,9 @@ var DeepdotsPopups = class {
|
|
|
7616
7692
|
log: (...a) => this.log(...a),
|
|
7617
7693
|
onSessionId: (id) => {
|
|
7618
7694
|
this.analyticsFeedbackSessionId = id;
|
|
7695
|
+
this.notifyFeedbackSession(id, "open");
|
|
7619
7696
|
},
|
|
7697
|
+
onSessionClosed: (id) => this.notifyFeedbackSession(id, "closed"),
|
|
7620
7698
|
onSessionReset: () => {
|
|
7621
7699
|
this.analyticsFeedbackSessionId = void 0;
|
|
7622
7700
|
}
|
|
@@ -7691,6 +7769,23 @@ var DeepdotsPopups = class {
|
|
|
7691
7769
|
getSessionId() {
|
|
7692
7770
|
return this.tracking?.getSessionId() ?? null;
|
|
7693
7771
|
}
|
|
7772
|
+
/**
|
|
7773
|
+
* Id del registro de analytics abierto: el `sessionId` que devolvió `POST /sdk/feedback`,
|
|
7774
|
+
* que la API guarda como `sdkSessionId` en el Feedback en que se convierte la sesión. No es
|
|
7775
|
+
* `getSessionId()`. Null hasta que el backend acepta el primer lote y de nuevo al cerrar la
|
|
7776
|
+
* sesión: para saber también qué registro se cerró, usa `init({ onFeedbackSession })`.
|
|
7777
|
+
*/
|
|
7778
|
+
getFeedbackSessionId() {
|
|
7779
|
+
return this.analyticsFeedbackSessionId ?? null;
|
|
7780
|
+
}
|
|
7781
|
+
/** Avisa al host del registro abierto o cerrado; un fallo del host no corta el envío. */
|
|
7782
|
+
notifyFeedbackSession(sessionId, status) {
|
|
7783
|
+
try {
|
|
7784
|
+
this.onFeedbackSession?.({ sessionId, status });
|
|
7785
|
+
} catch (error) {
|
|
7786
|
+
this.log("analytics \xB7 onFeedbackSession threw:", error);
|
|
7787
|
+
}
|
|
7788
|
+
}
|
|
7694
7789
|
/** Activa/desactiva el tracking (identidad + sesión + analytics). Kill-switch del contrato §7bis. */
|
|
7695
7790
|
setTrackingEnabled(enabled) {
|
|
7696
7791
|
if (!enabled) this.closeSession("tracking_disabled");
|