@pocketping/widget 2.0.0 → 2.2.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 +1 -0
- package/dist/index.cjs +149 -24
- package/dist/index.d.cts +50 -8
- package/dist/index.d.ts +50 -8
- package/dist/index.js +149 -24
- package/dist/pocketping.min.global.js +61 -61
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6,23 +6,59 @@ import { Fragment as Fragment2 } from "preact";
|
|
|
6
6
|
import { useState as useState2, useEffect as useEffect2, useRef as useRef2, useCallback } from "preact/hooks";
|
|
7
7
|
|
|
8
8
|
// src/components/styles.ts
|
|
9
|
+
var DEFAULT_GRADIENT = { from: "#36e3ff", to: "#7c5cff", direction: "to right" };
|
|
10
|
+
function isGradient(value) {
|
|
11
|
+
return typeof value === "object" && value !== null && "from" in value && "to" in value;
|
|
12
|
+
}
|
|
13
|
+
function toCssColor(value) {
|
|
14
|
+
if (isGradient(value)) {
|
|
15
|
+
const direction = value.direction || "to right";
|
|
16
|
+
return `linear-gradient(${direction}, ${value.from}, ${value.to})`;
|
|
17
|
+
}
|
|
18
|
+
return value;
|
|
19
|
+
}
|
|
20
|
+
function getBaseColor(value) {
|
|
21
|
+
if (isGradient(value)) {
|
|
22
|
+
return value.to;
|
|
23
|
+
}
|
|
24
|
+
return value;
|
|
25
|
+
}
|
|
9
26
|
function resolveThemeColor(color, isDark, defaultLight, defaultDark) {
|
|
10
27
|
if (!color) {
|
|
11
|
-
return isDark ? defaultDark : defaultLight;
|
|
28
|
+
return toCssColor(isDark ? defaultDark : defaultLight);
|
|
12
29
|
}
|
|
13
30
|
if (typeof color === "string") {
|
|
14
31
|
return color;
|
|
15
32
|
}
|
|
16
|
-
|
|
33
|
+
if (isGradient(color)) {
|
|
34
|
+
return toCssColor(color);
|
|
35
|
+
}
|
|
36
|
+
const resolved = isDark ? color.dark : color.light;
|
|
37
|
+
return toCssColor(resolved);
|
|
38
|
+
}
|
|
39
|
+
function resolveBaseColor(color, isDark, defaultLight, defaultDark) {
|
|
40
|
+
if (!color) {
|
|
41
|
+
return getBaseColor(isDark ? defaultDark : defaultLight);
|
|
42
|
+
}
|
|
43
|
+
if (typeof color === "string") {
|
|
44
|
+
return color;
|
|
45
|
+
}
|
|
46
|
+
if (isGradient(color)) {
|
|
47
|
+
return getBaseColor(color);
|
|
48
|
+
}
|
|
49
|
+
const resolved = isDark ? color.dark : color.light;
|
|
50
|
+
return getBaseColor(resolved);
|
|
17
51
|
}
|
|
18
52
|
function styles(options) {
|
|
19
53
|
const { primaryColor, theme, headerColor, footerColor, chatBackground, toggleColor } = options;
|
|
20
54
|
const isDark = theme === "dark";
|
|
21
|
-
const resolvedHeaderColor = resolveThemeColor(headerColor, isDark,
|
|
55
|
+
const resolvedHeaderColor = resolveThemeColor(headerColor, isDark, DEFAULT_GRADIENT, "#202c33");
|
|
22
56
|
const resolvedFooterColor = resolveThemeColor(footerColor, isDark, "#f0f2f5", "#202c33");
|
|
23
|
-
const resolvedToggleColor = resolveThemeColor(toggleColor, isDark,
|
|
24
|
-
const
|
|
25
|
-
const
|
|
57
|
+
const resolvedToggleColor = resolveThemeColor(toggleColor, isDark, DEFAULT_GRADIENT, DEFAULT_GRADIENT);
|
|
58
|
+
const headerBaseColor = resolveBaseColor(headerColor, isDark, DEFAULT_GRADIENT, "#202c33");
|
|
59
|
+
const toggleBaseColor = resolveBaseColor(toggleColor, isDark, DEFAULT_GRADIENT, DEFAULT_GRADIENT);
|
|
60
|
+
const resolvedToggleHoverColor = adjustBrightness(toggleBaseColor, -15);
|
|
61
|
+
const resolvedSendButtonHoverColor = adjustBrightness(headerBaseColor, -15);
|
|
26
62
|
const whatsappPattern = isDark ? `url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23ffffff' fill-opacity='0.03'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E")` : `url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23000000' fill-opacity='0.03'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E")`;
|
|
27
63
|
const dotsPattern = isDark ? `url("data:image/svg+xml,%3Csvg width='20' height='20' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='10' cy='10' r='1' fill='%23ffffff' fill-opacity='0.05'/%3E%3C/svg%3E")` : `url("data:image/svg+xml,%3Csvg width='20' height='20' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='10' cy='10' r='1' fill='%23000000' fill-opacity='0.05'/%3E%3C/svg%3E")`;
|
|
28
64
|
const resolvedChatBg = resolveThemeColor(chatBackground, isDark, "whatsapp", "whatsapp");
|
|
@@ -121,7 +157,7 @@ function styles(options) {
|
|
|
121
157
|
right: 4px;
|
|
122
158
|
width: 12px;
|
|
123
159
|
height: 12px;
|
|
124
|
-
background: #
|
|
160
|
+
background: #ff5fd4;
|
|
125
161
|
border-radius: 50%;
|
|
126
162
|
border: 2px solid white;
|
|
127
163
|
}
|
|
@@ -277,8 +313,8 @@ function styles(options) {
|
|
|
277
313
|
}
|
|
278
314
|
|
|
279
315
|
.pp-status-dot.pp-online {
|
|
280
|
-
background: #
|
|
281
|
-
box-shadow: 0 0 0 2px rgba(
|
|
316
|
+
background: #ff5fd4;
|
|
317
|
+
box-shadow: 0 0 0 2px rgba(255, 95, 212, 0.3);
|
|
282
318
|
}
|
|
283
319
|
|
|
284
320
|
.pp-close-btn {
|
|
@@ -982,7 +1018,7 @@ function styles(options) {
|
|
|
982
1018
|
justify-content: center;
|
|
983
1019
|
gap: 16px;
|
|
984
1020
|
z-index: 100;
|
|
985
|
-
border: 3px dashed #
|
|
1021
|
+
border: 3px dashed #7c5cff;
|
|
986
1022
|
border-radius: 12px;
|
|
987
1023
|
margin: 4px;
|
|
988
1024
|
pointer-events: none;
|
|
@@ -991,7 +1027,7 @@ function styles(options) {
|
|
|
991
1027
|
.pp-drop-icon svg {
|
|
992
1028
|
width: 56px;
|
|
993
1029
|
height: 56px;
|
|
994
|
-
color: #
|
|
1030
|
+
color: #7c5cff;
|
|
995
1031
|
}
|
|
996
1032
|
|
|
997
1033
|
.pp-drop-text {
|
|
@@ -1132,7 +1168,7 @@ function styles(options) {
|
|
|
1132
1168
|
padding: 10px 20px;
|
|
1133
1169
|
border: none;
|
|
1134
1170
|
border-radius: 8px;
|
|
1135
|
-
background: #
|
|
1171
|
+
background: #7c5cff;
|
|
1136
1172
|
color: white;
|
|
1137
1173
|
font-size: 14px;
|
|
1138
1174
|
font-weight: 500;
|
|
@@ -1141,7 +1177,7 @@ function styles(options) {
|
|
|
1141
1177
|
}
|
|
1142
1178
|
|
|
1143
1179
|
.pp-edit-save:hover:not(:disabled) {
|
|
1144
|
-
background: #
|
|
1180
|
+
background: #6a4ee6;
|
|
1145
1181
|
}
|
|
1146
1182
|
|
|
1147
1183
|
.pp-edit-save:disabled {
|
|
@@ -1156,7 +1192,7 @@ function styles(options) {
|
|
|
1156
1192
|
gap: 10px;
|
|
1157
1193
|
padding: 8px 12px;
|
|
1158
1194
|
background: ${resolvedFooterColor};
|
|
1159
|
-
border-left: 4px solid #
|
|
1195
|
+
border-left: 4px solid #7c5cff;
|
|
1160
1196
|
}
|
|
1161
1197
|
|
|
1162
1198
|
.pp-reply-preview-content {
|
|
@@ -1167,7 +1203,7 @@ function styles(options) {
|
|
|
1167
1203
|
.pp-reply-label {
|
|
1168
1204
|
display: block;
|
|
1169
1205
|
font-size: 12px;
|
|
1170
|
-
color: #
|
|
1206
|
+
color: #7c5cff;
|
|
1171
1207
|
font-weight: 500;
|
|
1172
1208
|
margin-bottom: 2px;
|
|
1173
1209
|
}
|
|
@@ -1211,7 +1247,7 @@ function styles(options) {
|
|
|
1211
1247
|
/* Reply Quote in Message */
|
|
1212
1248
|
.pp-reply-quote {
|
|
1213
1249
|
background: ${isDark ? "rgba(0,0,0,0.2)" : "rgba(0,0,0,0.05)"};
|
|
1214
|
-
border-left: 3px solid #
|
|
1250
|
+
border-left: 3px solid #7c5cff;
|
|
1215
1251
|
padding: 6px 10px;
|
|
1216
1252
|
margin-bottom: 4px;
|
|
1217
1253
|
border-radius: 0 6px 6px 0;
|
|
@@ -1223,7 +1259,7 @@ function styles(options) {
|
|
|
1223
1259
|
.pp-reply-sender {
|
|
1224
1260
|
display: block;
|
|
1225
1261
|
font-weight: 500;
|
|
1226
|
-
color: #
|
|
1262
|
+
color: #7c5cff;
|
|
1227
1263
|
margin-bottom: 2px;
|
|
1228
1264
|
font-size: 12px;
|
|
1229
1265
|
}
|
|
@@ -1253,7 +1289,7 @@ function styles(options) {
|
|
|
1253
1289
|
/* Reply quote in visitor message bubble needs higher contrast */
|
|
1254
1290
|
.pp-message-visitor .pp-reply-quote {
|
|
1255
1291
|
background: ${isDark ? "rgba(0,0,0,0.2)" : "rgba(0,0,0,0.08)"};
|
|
1256
|
-
border-left-color: ${isDark ? "rgba(255,255,255,0.5)" : "#
|
|
1292
|
+
border-left-color: ${isDark ? "rgba(255,255,255,0.5)" : "#7c5cff"};
|
|
1257
1293
|
}
|
|
1258
1294
|
|
|
1259
1295
|
.pp-message-visitor .pp-reply-quote-clickable:hover {
|
|
@@ -1261,7 +1297,7 @@ function styles(options) {
|
|
|
1261
1297
|
}
|
|
1262
1298
|
|
|
1263
1299
|
.pp-message-visitor .pp-reply-sender {
|
|
1264
|
-
color: ${isDark ? "rgba(255,255,255,0.9)" : "#
|
|
1300
|
+
color: ${isDark ? "rgba(255,255,255,0.9)" : "#7c5cff"};
|
|
1265
1301
|
}
|
|
1266
1302
|
|
|
1267
1303
|
.pp-message-visitor .pp-reply-content {
|
|
@@ -1275,13 +1311,13 @@ function styles(options) {
|
|
|
1275
1311
|
|
|
1276
1312
|
@keyframes pp-highlight-pulse {
|
|
1277
1313
|
0% {
|
|
1278
|
-
box-shadow: 0 0 0 0 rgba(
|
|
1314
|
+
box-shadow: 0 0 0 0 rgba(124, 92, 255, 0.5);
|
|
1279
1315
|
}
|
|
1280
1316
|
30% {
|
|
1281
|
-
box-shadow: 0 0 0 6px rgba(
|
|
1317
|
+
box-shadow: 0 0 0 6px rgba(124, 92, 255, 0.25);
|
|
1282
1318
|
}
|
|
1283
1319
|
100% {
|
|
1284
|
-
box-shadow: 0 0 0 0 rgba(
|
|
1320
|
+
box-shadow: 0 0 0 0 rgba(124, 92, 255, 0);
|
|
1285
1321
|
}
|
|
1286
1322
|
}
|
|
1287
1323
|
|
|
@@ -1542,7 +1578,7 @@ function styles(options) {
|
|
|
1542
1578
|
margin-top: 12px;
|
|
1543
1579
|
border: none;
|
|
1544
1580
|
border-radius: 8px;
|
|
1545
|
-
background: #
|
|
1581
|
+
background: #7c5cff;
|
|
1546
1582
|
color: white;
|
|
1547
1583
|
font-size: 15px;
|
|
1548
1584
|
font-weight: 500;
|
|
@@ -1551,7 +1587,7 @@ function styles(options) {
|
|
|
1551
1587
|
}
|
|
1552
1588
|
|
|
1553
1589
|
.pp-prechat-submit:hover:not(:disabled) {
|
|
1554
|
-
background: #
|
|
1590
|
+
background: #6a4ee6;
|
|
1555
1591
|
}
|
|
1556
1592
|
|
|
1557
1593
|
.pp-prechat-submit:active:not(:disabled) {
|
|
@@ -2939,6 +2975,10 @@ var PocketPingClient = class {
|
|
|
2939
2975
|
this.currentTrackedElements = [];
|
|
2940
2976
|
this.inspectorMode = false;
|
|
2941
2977
|
this.inspectorCleanup = null;
|
|
2978
|
+
this.connectedAt = 0;
|
|
2979
|
+
this.disconnectNotified = false;
|
|
2980
|
+
this.boundHandleUnload = null;
|
|
2981
|
+
this.boundHandleVisibilityChange = null;
|
|
2942
2982
|
this.config = config;
|
|
2943
2983
|
}
|
|
2944
2984
|
// ─────────────────────────────────────────────────────────────────
|
|
@@ -3012,6 +3052,9 @@ var PocketPingClient = class {
|
|
|
3012
3052
|
welcomeMessage: this.config.welcomeMessage
|
|
3013
3053
|
});
|
|
3014
3054
|
this.storeSessionId(response.sessionId);
|
|
3055
|
+
this.connectedAt = Date.now();
|
|
3056
|
+
this.disconnectNotified = false;
|
|
3057
|
+
this.setupUnloadListeners();
|
|
3015
3058
|
this.connectRealtime();
|
|
3016
3059
|
if (response.inspectorMode) {
|
|
3017
3060
|
this.enableInspectorMode();
|
|
@@ -3023,6 +3066,8 @@ var PocketPingClient = class {
|
|
|
3023
3066
|
return this.session;
|
|
3024
3067
|
}
|
|
3025
3068
|
disconnect() {
|
|
3069
|
+
this.notifyDisconnect();
|
|
3070
|
+
this.cleanupUnloadListeners();
|
|
3026
3071
|
if (this.ws) {
|
|
3027
3072
|
this.ws.onclose = null;
|
|
3028
3073
|
this.ws.onmessage = null;
|
|
@@ -4226,6 +4271,86 @@ var PocketPingClient = class {
|
|
|
4226
4271
|
this.pollingFailures = 0;
|
|
4227
4272
|
}
|
|
4228
4273
|
// ─────────────────────────────────────────────────────────────────
|
|
4274
|
+
// Visitor Disconnect Notification
|
|
4275
|
+
// ─────────────────────────────────────────────────────────────────
|
|
4276
|
+
setupUnloadListeners() {
|
|
4277
|
+
this.boundHandleUnload = () => this.notifyDisconnect();
|
|
4278
|
+
window.addEventListener("beforeunload", this.boundHandleUnload);
|
|
4279
|
+
window.addEventListener("pagehide", this.boundHandleUnload);
|
|
4280
|
+
this.boundHandleVisibilityChange = () => {
|
|
4281
|
+
if (document.visibilityState === "hidden") {
|
|
4282
|
+
this.sendVisibilityPing("hidden");
|
|
4283
|
+
} else if (document.visibilityState === "visible") {
|
|
4284
|
+
this.sendVisibilityPing("visible");
|
|
4285
|
+
}
|
|
4286
|
+
};
|
|
4287
|
+
document.addEventListener("visibilitychange", this.boundHandleVisibilityChange);
|
|
4288
|
+
}
|
|
4289
|
+
cleanupUnloadListeners() {
|
|
4290
|
+
if (this.boundHandleUnload) {
|
|
4291
|
+
window.removeEventListener("beforeunload", this.boundHandleUnload);
|
|
4292
|
+
window.removeEventListener("pagehide", this.boundHandleUnload);
|
|
4293
|
+
this.boundHandleUnload = null;
|
|
4294
|
+
}
|
|
4295
|
+
if (this.boundHandleVisibilityChange) {
|
|
4296
|
+
document.removeEventListener("visibilitychange", this.boundHandleVisibilityChange);
|
|
4297
|
+
this.boundHandleVisibilityChange = null;
|
|
4298
|
+
}
|
|
4299
|
+
}
|
|
4300
|
+
/**
|
|
4301
|
+
* Notify backend that visitor is leaving
|
|
4302
|
+
* Uses sendBeacon for reliability on page unload
|
|
4303
|
+
*/
|
|
4304
|
+
notifyDisconnect() {
|
|
4305
|
+
if (this.disconnectNotified || !this.session) {
|
|
4306
|
+
return;
|
|
4307
|
+
}
|
|
4308
|
+
this.disconnectNotified = true;
|
|
4309
|
+
const sessionDuration = this.connectedAt ? Math.round((Date.now() - this.connectedAt) / 1e3) : 0;
|
|
4310
|
+
const url = this.config.endpoint.replace(/\/$/, "") + "/disconnect";
|
|
4311
|
+
const data = JSON.stringify({
|
|
4312
|
+
sessionId: this.session.sessionId,
|
|
4313
|
+
duration: sessionDuration,
|
|
4314
|
+
reason: "page_unload"
|
|
4315
|
+
});
|
|
4316
|
+
if (navigator.sendBeacon) {
|
|
4317
|
+
const blob = new Blob([data], { type: "application/json" });
|
|
4318
|
+
navigator.sendBeacon(url, blob);
|
|
4319
|
+
} else {
|
|
4320
|
+
try {
|
|
4321
|
+
const xhr = new XMLHttpRequest();
|
|
4322
|
+
xhr.open("POST", url, false);
|
|
4323
|
+
xhr.setRequestHeader("Content-Type", "application/json");
|
|
4324
|
+
xhr.send(data);
|
|
4325
|
+
} catch {
|
|
4326
|
+
}
|
|
4327
|
+
}
|
|
4328
|
+
}
|
|
4329
|
+
/**
|
|
4330
|
+
* Send visibility ping to backend (for inactivity tracking)
|
|
4331
|
+
*/
|
|
4332
|
+
sendVisibilityPing(state) {
|
|
4333
|
+
if (!this.session) return;
|
|
4334
|
+
const url = this.config.endpoint.replace(/\/$/, "") + "/visibility";
|
|
4335
|
+
const data = JSON.stringify({
|
|
4336
|
+
sessionId: this.session.sessionId,
|
|
4337
|
+
state,
|
|
4338
|
+
timestamp: Date.now()
|
|
4339
|
+
});
|
|
4340
|
+
if (state === "hidden" && navigator.sendBeacon) {
|
|
4341
|
+
const blob = new Blob([data], { type: "application/json" });
|
|
4342
|
+
navigator.sendBeacon(url, blob);
|
|
4343
|
+
} else {
|
|
4344
|
+
fetch(url, {
|
|
4345
|
+
method: "POST",
|
|
4346
|
+
headers: { "Content-Type": "application/json" },
|
|
4347
|
+
body: data,
|
|
4348
|
+
keepalive: true
|
|
4349
|
+
}).catch(() => {
|
|
4350
|
+
});
|
|
4351
|
+
}
|
|
4352
|
+
}
|
|
4353
|
+
// ─────────────────────────────────────────────────────────────────
|
|
4229
4354
|
// HTTP
|
|
4230
4355
|
// ─────────────────────────────────────────────────────────────────
|
|
4231
4356
|
async fetch(path, options) {
|