@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/react-native.d.mts
CHANGED
|
@@ -122,6 +122,19 @@ interface DeepdotsLogger {
|
|
|
122
122
|
error?: (...args: unknown[]) => void;
|
|
123
123
|
info?: (...args: unknown[]) => void;
|
|
124
124
|
}
|
|
125
|
+
/**
|
|
126
|
+
* A session of the analytics channel as the Deepdots API sees it. Every session becomes ONE
|
|
127
|
+
* feedback, and `sessionId` is what the API stores as `sdkSessionId` on it: the value to look
|
|
128
|
+
* that feedback up with (`GET /feedbacks?filter={"where":{"sdkSessionId":"<sessionId>"}}`).
|
|
129
|
+
* A session that closes again keeps that one feedback: the API updates it.
|
|
130
|
+
* - `open`: the API acknowledged the session's first batch; its events keep accumulating.
|
|
131
|
+
* - `closed`: the API acknowledged the session's closing batch (`completed: true`); the
|
|
132
|
+
* feedback is created from it within seconds.
|
|
133
|
+
*/
|
|
134
|
+
interface FeedbackSession {
|
|
135
|
+
sessionId: string;
|
|
136
|
+
status: 'open' | 'closed';
|
|
137
|
+
}
|
|
125
138
|
interface DeepdotsInitParams {
|
|
126
139
|
/** API key for authentication */
|
|
127
140
|
apiKey?: string;
|
|
@@ -157,6 +170,17 @@ interface DeepdotsInitParams {
|
|
|
157
170
|
* logged when `debug` is true.
|
|
158
171
|
*/
|
|
159
172
|
analytics?: AnalyticsKeys;
|
|
173
|
+
/**
|
|
174
|
+
* Called when the analytics channel opens or closes a session (needs `analytics`), with the
|
|
175
|
+
* id the Deepdots API stores as `sdkSessionId` on the feedback the session becomes: send it
|
|
176
|
+
* to your backend to attach data to that feedback later. A session whose only batch is the
|
|
177
|
+
* closing one reports just `closed`. `closed` does not come when the page unloads before the
|
|
178
|
+
* closing request returns, for a session dropped after 30 min hidden, nor when the closing
|
|
179
|
+
* request fails (the API closes those itself, later): their id already came with `open`. Key
|
|
180
|
+
* by `sessionId`, not by order: the next session's `open` can arrive before the previous
|
|
181
|
+
* one's `closed`. Same value as `getFeedbackSessionId()` while the session is open.
|
|
182
|
+
*/
|
|
183
|
+
onFeedbackSession?: (session: FeedbackSession) => void;
|
|
160
184
|
/**
|
|
161
185
|
* IP geolocation (country/city) added to analytics. Default `true`. The lookup calls
|
|
162
186
|
* third-party services (ipapi.co, then ipwho.is, then ipinfo.io as fallbacks, 3 s timeout
|
|
@@ -392,6 +416,8 @@ declare class DeepdotsPopups {
|
|
|
392
416
|
private analytics;
|
|
393
417
|
/** feedbackSessionId cacheado del canal de analytics (devuelto por POST /sdk/feedback). */
|
|
394
418
|
private analyticsFeedbackSessionId;
|
|
419
|
+
/** `init({ onFeedbackSession })`: avisa al host al abrir y cerrar cada registro. */
|
|
420
|
+
private onFeedbackSession;
|
|
395
421
|
/** Timer del flush periódico de analytics (cada ANALYTICS_FLUSH_INTERVAL_MS). */
|
|
396
422
|
private analyticsFlushTimer;
|
|
397
423
|
/** Crash & error reporting (#14–17). Null hasta init(). */
|
|
@@ -435,6 +461,15 @@ declare class DeepdotsPopups {
|
|
|
435
461
|
getUserId(): string | null;
|
|
436
462
|
/** Session id de navegación actual. Null si tracking off. */
|
|
437
463
|
getSessionId(): string | null;
|
|
464
|
+
/**
|
|
465
|
+
* Id del registro de analytics abierto: el `sessionId` que devolvió `POST /sdk/feedback`,
|
|
466
|
+
* que la API guarda como `sdkSessionId` en el Feedback en que se convierte la sesión. No es
|
|
467
|
+
* `getSessionId()`. Null hasta que el backend acepta el primer lote y de nuevo al cerrar la
|
|
468
|
+
* sesión: para saber también qué registro se cerró, usa `init({ onFeedbackSession })`.
|
|
469
|
+
*/
|
|
470
|
+
getFeedbackSessionId(): string | null;
|
|
471
|
+
/** Avisa al host del registro abierto o cerrado; un fallo del host no corta el envío. */
|
|
472
|
+
private notifyFeedbackSession;
|
|
438
473
|
/** Activa/desactiva el tracking (identidad + sesión + analytics). Kill-switch del contrato §7bis. */
|
|
439
474
|
setTrackingEnabled(enabled: boolean): void;
|
|
440
475
|
/** Registra un evento de analítica (modelo GA: nombre + params). No-op si tracking off. */
|
package/dist/react-native.d.ts
CHANGED
|
@@ -122,6 +122,19 @@ interface DeepdotsLogger {
|
|
|
122
122
|
error?: (...args: unknown[]) => void;
|
|
123
123
|
info?: (...args: unknown[]) => void;
|
|
124
124
|
}
|
|
125
|
+
/**
|
|
126
|
+
* A session of the analytics channel as the Deepdots API sees it. Every session becomes ONE
|
|
127
|
+
* feedback, and `sessionId` is what the API stores as `sdkSessionId` on it: the value to look
|
|
128
|
+
* that feedback up with (`GET /feedbacks?filter={"where":{"sdkSessionId":"<sessionId>"}}`).
|
|
129
|
+
* A session that closes again keeps that one feedback: the API updates it.
|
|
130
|
+
* - `open`: the API acknowledged the session's first batch; its events keep accumulating.
|
|
131
|
+
* - `closed`: the API acknowledged the session's closing batch (`completed: true`); the
|
|
132
|
+
* feedback is created from it within seconds.
|
|
133
|
+
*/
|
|
134
|
+
interface FeedbackSession {
|
|
135
|
+
sessionId: string;
|
|
136
|
+
status: 'open' | 'closed';
|
|
137
|
+
}
|
|
125
138
|
interface DeepdotsInitParams {
|
|
126
139
|
/** API key for authentication */
|
|
127
140
|
apiKey?: string;
|
|
@@ -157,6 +170,17 @@ interface DeepdotsInitParams {
|
|
|
157
170
|
* logged when `debug` is true.
|
|
158
171
|
*/
|
|
159
172
|
analytics?: AnalyticsKeys;
|
|
173
|
+
/**
|
|
174
|
+
* Called when the analytics channel opens or closes a session (needs `analytics`), with the
|
|
175
|
+
* id the Deepdots API stores as `sdkSessionId` on the feedback the session becomes: send it
|
|
176
|
+
* to your backend to attach data to that feedback later. A session whose only batch is the
|
|
177
|
+
* closing one reports just `closed`. `closed` does not come when the page unloads before the
|
|
178
|
+
* closing request returns, for a session dropped after 30 min hidden, nor when the closing
|
|
179
|
+
* request fails (the API closes those itself, later): their id already came with `open`. Key
|
|
180
|
+
* by `sessionId`, not by order: the next session's `open` can arrive before the previous
|
|
181
|
+
* one's `closed`. Same value as `getFeedbackSessionId()` while the session is open.
|
|
182
|
+
*/
|
|
183
|
+
onFeedbackSession?: (session: FeedbackSession) => void;
|
|
160
184
|
/**
|
|
161
185
|
* IP geolocation (country/city) added to analytics. Default `true`. The lookup calls
|
|
162
186
|
* third-party services (ipapi.co, then ipwho.is, then ipinfo.io as fallbacks, 3 s timeout
|
|
@@ -392,6 +416,8 @@ declare class DeepdotsPopups {
|
|
|
392
416
|
private analytics;
|
|
393
417
|
/** feedbackSessionId cacheado del canal de analytics (devuelto por POST /sdk/feedback). */
|
|
394
418
|
private analyticsFeedbackSessionId;
|
|
419
|
+
/** `init({ onFeedbackSession })`: avisa al host al abrir y cerrar cada registro. */
|
|
420
|
+
private onFeedbackSession;
|
|
395
421
|
/** Timer del flush periódico de analytics (cada ANALYTICS_FLUSH_INTERVAL_MS). */
|
|
396
422
|
private analyticsFlushTimer;
|
|
397
423
|
/** Crash & error reporting (#14–17). Null hasta init(). */
|
|
@@ -435,6 +461,15 @@ declare class DeepdotsPopups {
|
|
|
435
461
|
getUserId(): string | null;
|
|
436
462
|
/** Session id de navegación actual. Null si tracking off. */
|
|
437
463
|
getSessionId(): string | null;
|
|
464
|
+
/**
|
|
465
|
+
* Id del registro de analytics abierto: el `sessionId` que devolvió `POST /sdk/feedback`,
|
|
466
|
+
* que la API guarda como `sdkSessionId` en el Feedback en que se convierte la sesión. No es
|
|
467
|
+
* `getSessionId()`. Null hasta que el backend acepta el primer lote y de nuevo al cerrar la
|
|
468
|
+
* sesión: para saber también qué registro se cerró, usa `init({ onFeedbackSession })`.
|
|
469
|
+
*/
|
|
470
|
+
getFeedbackSessionId(): string | null;
|
|
471
|
+
/** Avisa al host del registro abierto o cerrado; un fallo del host no corta el envío. */
|
|
472
|
+
private notifyFeedbackSession;
|
|
438
473
|
/** Activa/desactiva el tracking (identidad + sesión + analytics). Kill-switch del contrato §7bis. */
|
|
439
474
|
setTrackingEnabled(enabled: boolean): void;
|
|
440
475
|
/** Registra un evento de analítica (modelo GA: nombre + params). No-op si tracking off. */
|
package/dist/react-native.js
CHANGED
|
@@ -563,7 +563,9 @@ var init_style = __esm({
|
|
|
563
563
|
* repintar\xEDa su web.
|
|
564
564
|
* 4. El grupo .magicfeedback-radio se cualifica como div.magicfeedback-radio (la clase acaba
|
|
565
565
|
* tambi\xE9n en el <input> del boolean).
|
|
566
|
-
* 5.
|
|
566
|
+
* 5. Todo :hover va dentro de @media (hover: hover): en t\xE1ctil WebKit deja el hover pegado
|
|
567
|
+
* en el \xFAltimo punto tocado y la opci\xF3n de la p\xE1gina siguiente parec\xEDa seleccionada.
|
|
568
|
+
* 6. Al final, un bloque de reglas propias del popup (fuente en los controles y padding del
|
|
567
569
|
* radio nativo).
|
|
568
570
|
*
|
|
569
571
|
* Las variables --mf-* se dejan en :root a prop\xF3sito: el modal del priority-list se portea a
|
|
@@ -801,9 +803,11 @@ var init_style = __esm({
|
|
|
801
803
|
text-underline-offset: 2px;
|
|
802
804
|
}
|
|
803
805
|
|
|
804
|
-
|
|
805
|
-
.magicfeedback-
|
|
806
|
-
|
|
806
|
+
@media (hover: hover) {
|
|
807
|
+
.magicfeedback-info-message a:hover,
|
|
808
|
+
.magicfeedback-start-message a:hover {
|
|
809
|
+
color: var(--mf-primary-hover);
|
|
810
|
+
}
|
|
807
811
|
}
|
|
808
812
|
|
|
809
813
|
.magicfeedback-info-message ul,
|
|
@@ -1029,10 +1033,12 @@ div.magicfeedback-radio {
|
|
|
1029
1033
|
transition: var(--mf-transition-fast);
|
|
1030
1034
|
}
|
|
1031
1035
|
|
|
1032
|
-
|
|
1033
|
-
.magicfeedback-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
+
@media (hover: hover) {
|
|
1037
|
+
.magicfeedback-checkbox-container:hover,
|
|
1038
|
+
.magicfeedback-radio-container:hover {
|
|
1039
|
+
background-color: var(--mf-bg-hover);
|
|
1040
|
+
border-color: var(--mf-primary);
|
|
1041
|
+
}
|
|
1036
1042
|
}
|
|
1037
1043
|
|
|
1038
1044
|
.magicfeedback-checkbox-container:has(input:checked),
|
|
@@ -1099,9 +1105,11 @@ div.magicfeedback-radio {
|
|
|
1099
1105
|
height: inherit;
|
|
1100
1106
|
}
|
|
1101
1107
|
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1108
|
+
@media (hover: hover) {
|
|
1109
|
+
.magicfeedback-boolean-option label:hover {
|
|
1110
|
+
background-color: var(--mf-bg-hover);
|
|
1111
|
+
border-color: var(--mf-primary);
|
|
1112
|
+
}
|
|
1105
1113
|
}
|
|
1106
1114
|
|
|
1107
1115
|
.magicfeedback-boolean-option input[type="radio"]:checked + label {
|
|
@@ -1172,9 +1180,11 @@ div.magicfeedback-radio {
|
|
|
1172
1180
|
border: 2px solid transparent;
|
|
1173
1181
|
}
|
|
1174
1182
|
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1183
|
+
@media (hover: hover) {
|
|
1184
|
+
.magicfeedback-rating-option-label-container img:hover {
|
|
1185
|
+
transform: scale(1.1);
|
|
1186
|
+
border-color: var(--mf-primary);
|
|
1187
|
+
}
|
|
1178
1188
|
}
|
|
1179
1189
|
|
|
1180
1190
|
.magicfeedback-rating-option-label-container input[type="radio"]:checked + img {
|
|
@@ -1326,9 +1336,11 @@ div.magicfeedback-radio {
|
|
|
1326
1336
|
font-size: 0.8rem;
|
|
1327
1337
|
}
|
|
1328
1338
|
|
|
1329
|
-
|
|
1330
|
-
.magicfeedback-rating-number-option-row
|
|
1331
|
-
|
|
1339
|
+
@media (hover: hover) {
|
|
1340
|
+
.magicfeedback-rating-number-option-row .magicfeedback-rating-number-option-label-container:hover .magicfeedback-rating-number-value,
|
|
1341
|
+
.magicfeedback-rating-number-option-row-reverse .magicfeedback-rating-number-option-label-container:hover .magicfeedback-rating-number-value {
|
|
1342
|
+
background: var(--mf-primary-light);
|
|
1343
|
+
}
|
|
1332
1344
|
}
|
|
1333
1345
|
|
|
1334
1346
|
.magicfeedback-rating-number-option-row .magicfeedback-rating-number-option-label-container input[type="radio"]:checked + .magicfeedback-rating-number-value,
|
|
@@ -1365,8 +1377,10 @@ div.magicfeedback-radio {
|
|
|
1365
1377
|
font-size: var(--mf-font-size-sm);
|
|
1366
1378
|
}
|
|
1367
1379
|
|
|
1368
|
-
|
|
1369
|
-
|
|
1380
|
+
@media (hover: hover) {
|
|
1381
|
+
.magicfeedback-rating-number-option--extra .magicfeedback-rating-number-option-label-container:hover .magicfeedback-rating-number-value {
|
|
1382
|
+
background: var(--mf-primary-light);
|
|
1383
|
+
}
|
|
1370
1384
|
}
|
|
1371
1385
|
|
|
1372
1386
|
.magicfeedback-rating-number-option--extra .magicfeedback-rating-number-option-label-container input[type="radio"]:checked + .magicfeedback-rating-number-value {
|
|
@@ -1399,9 +1413,11 @@ div.magicfeedback-radio {
|
|
|
1399
1413
|
color: var(--mf-primary);
|
|
1400
1414
|
}
|
|
1401
1415
|
|
|
1402
|
-
|
|
1403
|
-
.magicfeedback-rating-number-option-column
|
|
1404
|
-
|
|
1416
|
+
@media (hover: hover) {
|
|
1417
|
+
.magicfeedback-rating-number-option-column .magicfeedback-rating-number-option-label-container:hover .magicfeedback-rating-number-value,
|
|
1418
|
+
.magicfeedback-rating-number-option-column-reverse .magicfeedback-rating-number-option-label-container:hover .magicfeedback-rating-number-value {
|
|
1419
|
+
background: var(--mf-primary-light);
|
|
1420
|
+
}
|
|
1405
1421
|
}
|
|
1406
1422
|
|
|
1407
1423
|
.magicfeedback-rating-number-option-column .magicfeedback-rating-number-option-label-container input[type="radio"]:checked + .magicfeedback-rating-number-value,
|
|
@@ -1455,10 +1471,12 @@ div.magicfeedback-radio {
|
|
|
1455
1471
|
transition: var(--mf-transition-fast);
|
|
1456
1472
|
}
|
|
1457
1473
|
|
|
1458
|
-
|
|
1459
|
-
.magicfeedback-rating-star-option:not(:checked) > .rating__star:hover
|
|
1460
|
-
|
|
1461
|
-
|
|
1474
|
+
@media (hover: hover) {
|
|
1475
|
+
.magicfeedback-rating-star-option:not(:checked) > .rating__star:hover,
|
|
1476
|
+
.magicfeedback-rating-star-option:not(:checked) > .rating__star:hover ~ span {
|
|
1477
|
+
color: #fbbf24;
|
|
1478
|
+
transform: scale(1.1);
|
|
1479
|
+
}
|
|
1462
1480
|
}
|
|
1463
1481
|
|
|
1464
1482
|
.magicfeedback-rating-star-selected {
|
|
@@ -1499,9 +1517,11 @@ div.magicfeedback-radio {
|
|
|
1499
1517
|
transition: var(--mf-transition-fast);
|
|
1500
1518
|
}
|
|
1501
1519
|
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1520
|
+
@media (hover: hover) {
|
|
1521
|
+
.magicfeedback-image-option-label-container:hover img {
|
|
1522
|
+
border-color: var(--mf-primary);
|
|
1523
|
+
box-shadow: var(--mf-shadow-md);
|
|
1524
|
+
}
|
|
1505
1525
|
}
|
|
1506
1526
|
|
|
1507
1527
|
.magicfeedback-image-option-label-container input:checked + img {
|
|
@@ -1542,9 +1562,11 @@ div.magicfeedback-radio {
|
|
|
1542
1562
|
background-color: var(--mf-bg-secondary);
|
|
1543
1563
|
}
|
|
1544
1564
|
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1565
|
+
@media (hover: hover) {
|
|
1566
|
+
.magicfeedback-multi-question-matrix-row-tr:hover {
|
|
1567
|
+
background-color: var(--mf-bg-hover);
|
|
1568
|
+
box-shadow: var(--mf-shadow-sm);
|
|
1569
|
+
}
|
|
1548
1570
|
}
|
|
1549
1571
|
|
|
1550
1572
|
.magicfeedback-multi-question-matrix-table td {
|
|
@@ -1580,9 +1602,11 @@ div.magicfeedback-radio {
|
|
|
1580
1602
|
transition: var(--mf-transition-fast);
|
|
1581
1603
|
}
|
|
1582
1604
|
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1605
|
+
@media (hover: hover) {
|
|
1606
|
+
.magicfeedback-priority-list-item:hover {
|
|
1607
|
+
box-shadow: var(--mf-shadow-sm);
|
|
1608
|
+
border-color: var(--mf-primary);
|
|
1609
|
+
}
|
|
1586
1610
|
}
|
|
1587
1611
|
|
|
1588
1612
|
.magicfeedback-priority-list-item-label {
|
|
@@ -1603,10 +1627,12 @@ div.magicfeedback-radio {
|
|
|
1603
1627
|
user-select: none;
|
|
1604
1628
|
}
|
|
1605
1629
|
|
|
1606
|
-
|
|
1607
|
-
.magicfeedback-priority-list-arrow-
|
|
1608
|
-
|
|
1609
|
-
|
|
1630
|
+
@media (hover: hover) {
|
|
1631
|
+
.magicfeedback-priority-list-arrow-up:hover,
|
|
1632
|
+
.magicfeedback-priority-list-arrow-down:hover {
|
|
1633
|
+
color: var(--mf-primary);
|
|
1634
|
+
transform: scale(1.2);
|
|
1635
|
+
}
|
|
1610
1636
|
}
|
|
1611
1637
|
|
|
1612
1638
|
/* ========================================
|
|
@@ -1713,10 +1739,12 @@ div.magicfeedback-radio {
|
|
|
1713
1739
|
box-shadow: var(--mf-shadow-md);
|
|
1714
1740
|
}
|
|
1715
1741
|
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1742
|
+
@media (hover: hover) {
|
|
1743
|
+
.magicfeedback-submit:hover {
|
|
1744
|
+
background-color: var(--mf-primary-hover);
|
|
1745
|
+
box-shadow: var(--mf-shadow-lg);
|
|
1746
|
+
transform: translateY(-2px);
|
|
1747
|
+
}
|
|
1720
1748
|
}
|
|
1721
1749
|
|
|
1722
1750
|
.magicfeedback-submit:active {
|
|
@@ -1742,9 +1770,11 @@ div.magicfeedback-radio {
|
|
|
1742
1770
|
transition: var(--mf-transition-fast);
|
|
1743
1771
|
}
|
|
1744
1772
|
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1773
|
+
@media (hover: hover) {
|
|
1774
|
+
.magicfeedback-back:hover {
|
|
1775
|
+
border-color: var(--mf-primary);
|
|
1776
|
+
background-color: var(--mf-bg-hover);
|
|
1777
|
+
}
|
|
1748
1778
|
}
|
|
1749
1779
|
|
|
1750
1780
|
/* ========================================
|
|
@@ -1764,8 +1794,10 @@ div.magicfeedback-radio {
|
|
|
1764
1794
|
transition: var(--mf-transition-fast);
|
|
1765
1795
|
}
|
|
1766
1796
|
|
|
1767
|
-
|
|
1768
|
-
|
|
1797
|
+
@media (hover: hover) {
|
|
1798
|
+
.magicfeedback-skip-container:hover {
|
|
1799
|
+
color: var(--mf-primary);
|
|
1800
|
+
}
|
|
1769
1801
|
}
|
|
1770
1802
|
|
|
1771
1803
|
.magicfeedback-skip-container input[type="checkbox"] {
|
|
@@ -1906,9 +1938,11 @@ div.magicfeedback-radio {
|
|
|
1906
1938
|
box-shadow: var(--mf-shadow-sm);
|
|
1907
1939
|
}
|
|
1908
1940
|
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1941
|
+
@media (hover: hover) {
|
|
1942
|
+
.magicfeedback-button:hover {
|
|
1943
|
+
background: var(--mf-bg-hover);
|
|
1944
|
+
border-color: var(--mf-primary);
|
|
1945
|
+
}
|
|
1912
1946
|
}
|
|
1913
1947
|
|
|
1914
1948
|
.magicfeedback-button:active {
|
|
@@ -1922,8 +1956,10 @@ div.magicfeedback-radio {
|
|
|
1922
1956
|
box-shadow: var(--mf-shadow-md);
|
|
1923
1957
|
}
|
|
1924
1958
|
|
|
1925
|
-
|
|
1926
|
-
|
|
1959
|
+
@media (hover: hover) {
|
|
1960
|
+
.magicfeedback-button-primary:hover {
|
|
1961
|
+
background: var(--mf-primary-hover);
|
|
1962
|
+
}
|
|
1927
1963
|
}
|
|
1928
1964
|
|
|
1929
1965
|
.magicfeedback-button-primary:active {
|
|
@@ -1949,8 +1985,10 @@ div.magicfeedback-radio {
|
|
|
1949
1985
|
box-shadow: var(--mf-shadow-md);
|
|
1950
1986
|
}
|
|
1951
1987
|
|
|
1952
|
-
|
|
1953
|
-
|
|
1988
|
+
@media (hover: hover) {
|
|
1989
|
+
.magicfeedback-start-message-button:hover {
|
|
1990
|
+
background: var(--mf-primary-hover);
|
|
1991
|
+
}
|
|
1954
1992
|
}
|
|
1955
1993
|
|
|
1956
1994
|
/* ========================================
|
|
@@ -2086,12 +2124,18 @@ div.magicfeedback-radio {
|
|
|
2086
2124
|
color: #666;
|
|
2087
2125
|
}
|
|
2088
2126
|
|
|
2089
|
-
.magicfeedback-modal-close:hover,
|
|
2090
2127
|
.magicfeedback-modal-close:focus {
|
|
2091
2128
|
color: #000;
|
|
2092
2129
|
outline: none;
|
|
2093
2130
|
}
|
|
2094
2131
|
|
|
2132
|
+
@media (hover: hover) {
|
|
2133
|
+
.magicfeedback-modal-close:hover {
|
|
2134
|
+
color: #000;
|
|
2135
|
+
outline: none;
|
|
2136
|
+
}
|
|
2137
|
+
}
|
|
2138
|
+
|
|
2095
2139
|
/* ========================================
|
|
2096
2140
|
FILE / IMAGE UPLOAD
|
|
2097
2141
|
======================================== */
|
|
@@ -2135,9 +2179,11 @@ div.magicfeedback-radio {
|
|
|
2135
2179
|
transition: var(--mf-transition);
|
|
2136
2180
|
}
|
|
2137
2181
|
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2182
|
+
@media (hover: hover) {
|
|
2183
|
+
.magicfeedback-upload-dropzone:hover {
|
|
2184
|
+
border-color: var(--mf-primary);
|
|
2185
|
+
background-color: var(--mf-bg-hover);
|
|
2186
|
+
}
|
|
2141
2187
|
}
|
|
2142
2188
|
|
|
2143
2189
|
.magicfeedback-upload-dropzone:focus-within {
|
|
@@ -2275,13 +2321,20 @@ div.magicfeedback-radio {
|
|
|
2275
2321
|
transition: var(--mf-transition-fast);
|
|
2276
2322
|
}
|
|
2277
2323
|
|
|
2278
|
-
.magicfeedback-upload-remove:hover,
|
|
2279
2324
|
.magicfeedback-upload-remove:focus-visible {
|
|
2280
2325
|
color: var(--mf-error);
|
|
2281
2326
|
background-color: var(--mf-primary-light);
|
|
2282
2327
|
outline: none;
|
|
2283
2328
|
}
|
|
2284
2329
|
|
|
2330
|
+
@media (hover: hover) {
|
|
2331
|
+
.magicfeedback-upload-remove:hover {
|
|
2332
|
+
color: var(--mf-error);
|
|
2333
|
+
background-color: var(--mf-primary-light);
|
|
2334
|
+
outline: none;
|
|
2335
|
+
}
|
|
2336
|
+
}
|
|
2337
|
+
|
|
2285
2338
|
.magicfeedback-upload-remove svg {
|
|
2286
2339
|
width: 16px;
|
|
2287
2340
|
height: 16px;
|
|
@@ -4376,8 +4429,10 @@ async function safeBodyText(res) {
|
|
|
4376
4429
|
function createFeedbackSink(options) {
|
|
4377
4430
|
let feedbackSessionId;
|
|
4378
4431
|
let firstPostInFlight = null;
|
|
4432
|
+
let generation = 0;
|
|
4379
4433
|
const url = `${options.baseUrl}/sdk/feedback`;
|
|
4380
4434
|
const post = async (body, final, sessionEnd = false) => {
|
|
4435
|
+
const postGeneration = generation;
|
|
4381
4436
|
const json = JSON.stringify(body);
|
|
4382
4437
|
const small = json.length <= KEEPALIVE_MAX_BYTES;
|
|
4383
4438
|
if (final) options.log?.("[DeepdotsAnalytics] final flush via fetch keepalive");
|
|
@@ -4407,9 +4462,25 @@ function createFeedbackSink(options) {
|
|
|
4407
4462
|
);
|
|
4408
4463
|
return;
|
|
4409
4464
|
}
|
|
4410
|
-
if (sessionEnd)
|
|
4465
|
+
if (sessionEnd) {
|
|
4466
|
+
let closedId = body.sessionId;
|
|
4467
|
+
try {
|
|
4468
|
+
const data = await res.json();
|
|
4469
|
+
closedId = data?.sessionId ?? closedId;
|
|
4470
|
+
} catch {
|
|
4471
|
+
}
|
|
4472
|
+
try {
|
|
4473
|
+
if (closedId) options.onSessionClosed?.(closedId);
|
|
4474
|
+
} catch {
|
|
4475
|
+
}
|
|
4476
|
+
return;
|
|
4477
|
+
}
|
|
4411
4478
|
try {
|
|
4412
4479
|
const data = await res.json();
|
|
4480
|
+
if (postGeneration !== generation) {
|
|
4481
|
+
options.log?.("[DeepdotsAnalytics] sessionId of a closed session ignored:", data?.sessionId);
|
|
4482
|
+
return;
|
|
4483
|
+
}
|
|
4413
4484
|
if (data?.sessionId && data.sessionId !== feedbackSessionId) {
|
|
4414
4485
|
feedbackSessionId = data.sessionId;
|
|
4415
4486
|
options.log?.("[DeepdotsAnalytics] feedbackSessionId cached:", feedbackSessionId);
|
|
@@ -4422,6 +4493,7 @@ function createFeedbackSink(options) {
|
|
|
4422
4493
|
if (meta?.resetSession) {
|
|
4423
4494
|
feedbackSessionId = void 0;
|
|
4424
4495
|
firstPostInFlight = null;
|
|
4496
|
+
generation++;
|
|
4425
4497
|
options.onSessionReset?.();
|
|
4426
4498
|
return;
|
|
4427
4499
|
}
|
|
@@ -4436,6 +4508,7 @@ function createFeedbackSink(options) {
|
|
|
4436
4508
|
if (sessionEnd) {
|
|
4437
4509
|
feedbackSessionId = void 0;
|
|
4438
4510
|
firstPostInFlight = null;
|
|
4511
|
+
generation++;
|
|
4439
4512
|
options.onSessionReset?.();
|
|
4440
4513
|
} else if (!feedbackSessionId) {
|
|
4441
4514
|
firstPostInFlight = sent.then(
|
|
@@ -5086,6 +5159,8 @@ var DeepdotsPopups = class {
|
|
|
5086
5159
|
this.analytics = null;
|
|
5087
5160
|
/** feedbackSessionId cacheado del canal de analytics (devuelto por POST /sdk/feedback). */
|
|
5088
5161
|
this.analyticsFeedbackSessionId = void 0;
|
|
5162
|
+
/** `init({ onFeedbackSession })`: avisa al host al abrir y cerrar cada registro. */
|
|
5163
|
+
this.onFeedbackSession = void 0;
|
|
5089
5164
|
/** Timer del flush periódico de analytics (cada ANALYTICS_FLUSH_INTERVAL_MS). */
|
|
5090
5165
|
this.analyticsFlushTimer = void 0;
|
|
5091
5166
|
/** Crash & error reporting (#14–17). Null hasta init(). */
|
|
@@ -5143,6 +5218,7 @@ var DeepdotsPopups = class {
|
|
|
5143
5218
|
this.renderChrome = config.renderChrome ?? true;
|
|
5144
5219
|
this.showProgressBar = config.showProgressBar;
|
|
5145
5220
|
this.surveyCss = config.surveyCss;
|
|
5221
|
+
this.onFeedbackSession = config.onFeedbackSession;
|
|
5146
5222
|
this.config = {
|
|
5147
5223
|
apiKey: config.apiKey || void 0,
|
|
5148
5224
|
debug: config.debug || false,
|
|
@@ -5176,7 +5252,9 @@ var DeepdotsPopups = class {
|
|
|
5176
5252
|
log: (...a) => this.log(...a),
|
|
5177
5253
|
onSessionId: (id) => {
|
|
5178
5254
|
this.analyticsFeedbackSessionId = id;
|
|
5255
|
+
this.notifyFeedbackSession(id, "open");
|
|
5179
5256
|
},
|
|
5257
|
+
onSessionClosed: (id) => this.notifyFeedbackSession(id, "closed"),
|
|
5180
5258
|
onSessionReset: () => {
|
|
5181
5259
|
this.analyticsFeedbackSessionId = void 0;
|
|
5182
5260
|
}
|
|
@@ -5251,6 +5329,23 @@ var DeepdotsPopups = class {
|
|
|
5251
5329
|
getSessionId() {
|
|
5252
5330
|
return this.tracking?.getSessionId() ?? null;
|
|
5253
5331
|
}
|
|
5332
|
+
/**
|
|
5333
|
+
* Id del registro de analytics abierto: el `sessionId` que devolvió `POST /sdk/feedback`,
|
|
5334
|
+
* que la API guarda como `sdkSessionId` en el Feedback en que se convierte la sesión. No es
|
|
5335
|
+
* `getSessionId()`. Null hasta que el backend acepta el primer lote y de nuevo al cerrar la
|
|
5336
|
+
* sesión: para saber también qué registro se cerró, usa `init({ onFeedbackSession })`.
|
|
5337
|
+
*/
|
|
5338
|
+
getFeedbackSessionId() {
|
|
5339
|
+
return this.analyticsFeedbackSessionId ?? null;
|
|
5340
|
+
}
|
|
5341
|
+
/** Avisa al host del registro abierto o cerrado; un fallo del host no corta el envío. */
|
|
5342
|
+
notifyFeedbackSession(sessionId, status) {
|
|
5343
|
+
try {
|
|
5344
|
+
this.onFeedbackSession?.({ sessionId, status });
|
|
5345
|
+
} catch (error) {
|
|
5346
|
+
this.log("analytics \xB7 onFeedbackSession threw:", error);
|
|
5347
|
+
}
|
|
5348
|
+
}
|
|
5254
5349
|
/** Activa/desactiva el tracking (identidad + sesión + analytics). Kill-switch del contrato §7bis. */
|
|
5255
5350
|
setTrackingEnabled(enabled) {
|
|
5256
5351
|
if (!enabled) this.closeSession("tracking_disabled");
|