wakz-chat-widget 4.0.0 → 4.0.1
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 +71 -0
- package/index.js +88 -8
- package/package.json +41 -1
package/README.md
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# wakz-chat-widget
|
|
2
|
+
|
|
3
|
+
**Premium AI chat widget by WAKZ** — A production-grade, self-contained chat widget using Shadow DOM.
|
|
4
|
+
|
|
5
|
+
> Competes with Intercom & Crisp in quality. **Zero external dependencies** — pure vanilla JavaScript.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- Shadow DOM isolation (no CSS conflicts)
|
|
10
|
+
- Multi-language support (English, Arabic, French) with full RTL
|
|
11
|
+
- Device detection (model, platform, type)
|
|
12
|
+
- Online/offline status with animated indicators
|
|
13
|
+
- Message polling with deduplication
|
|
14
|
+
- Mobile responsive (full-screen on small devices)
|
|
15
|
+
- Typing indicator animations
|
|
16
|
+
- Welcome messages
|
|
17
|
+
- Human agent badge support
|
|
18
|
+
- Auto-resizing textarea input
|
|
19
|
+
- Keyboard shortcuts (Enter to send, Shift+Enter for newline, Escape to close)
|
|
20
|
+
- Smooth animations and transitions
|
|
21
|
+
- Configurable theming (colors, position)
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install wakz-chat-widget
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Usage
|
|
30
|
+
|
|
31
|
+
Copy `index.js` from `node_modules/wakz-chat-widget/` to your public folder and include it:
|
|
32
|
+
|
|
33
|
+
```html
|
|
34
|
+
<script src="/wakz-widget.js"
|
|
35
|
+
data-api-key="YOUR_API_KEY"
|
|
36
|
+
data-server="https://your-server.com"
|
|
37
|
+
async>
|
|
38
|
+
</script>
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Configuration
|
|
42
|
+
|
|
43
|
+
The widget fetches its configuration from your server's `/api/v1/embed/config` endpoint. Configurable options include:
|
|
44
|
+
|
|
45
|
+
| Option | Type | Default | Description |
|
|
46
|
+
|--------|------|---------|-------------|
|
|
47
|
+
| `botName` | string | `'WAKZ'` | Bot display name |
|
|
48
|
+
| `welcomeMessage` | string | `''` | Initial welcome message |
|
|
49
|
+
| `primaryColor` | string | `'#171717'` | Primary theme color |
|
|
50
|
+
| `chatBg` | string | `'#f8f9fa'` | Chat area background |
|
|
51
|
+
| `btnColor` | string | `'#171717'` | FAB button color |
|
|
52
|
+
| `widgetBg` | string | `'#ffffff'` | Widget background |
|
|
53
|
+
| `position` | string | `'bottom-right'` | Widget position |
|
|
54
|
+
| `language` | string | `'en'` | Language (`en`, `ar`, `fr`) |
|
|
55
|
+
| `showStatus` | boolean | `true` | Show online/offline dot |
|
|
56
|
+
| `online` | boolean | `true` | Initial status |
|
|
57
|
+
|
|
58
|
+
## Version History
|
|
59
|
+
|
|
60
|
+
### v2.2.0
|
|
61
|
+
- Added device model, platform, and type detection (User-Agent Client Hints API + UA fallback)
|
|
62
|
+
- Device info sent with session data for dashboard analytics
|
|
63
|
+
|
|
64
|
+
### v2.0.0
|
|
65
|
+
- Complete rewrite with Shadow DOM architecture
|
|
66
|
+
- Multi-language support (EN/AR/FR) with RTL
|
|
67
|
+
- Production-grade UI with animations
|
|
68
|
+
|
|
69
|
+
## License
|
|
70
|
+
|
|
71
|
+
MIT
|
package/index.js
CHANGED
|
@@ -210,11 +210,23 @@
|
|
|
210
210
|
primaryColor: '#111111',
|
|
211
211
|
chatBg: '#ffffff',
|
|
212
212
|
btnColor: '#111111',
|
|
213
|
-
widgetBg: '#
|
|
213
|
+
widgetBg: '#f5f5f5',
|
|
214
214
|
position: 'bottom-right',
|
|
215
215
|
language: 'en',
|
|
216
216
|
showStatus: true,
|
|
217
|
-
online: true
|
|
217
|
+
online: true,
|
|
218
|
+
/* v4.0.1 — Advanced customization */
|
|
219
|
+
fabShape: 'circle',
|
|
220
|
+
fabIcon: 'chat',
|
|
221
|
+
triggerMode: 'manual',
|
|
222
|
+
triggerDelay: 5,
|
|
223
|
+
displayMode: 'modal',
|
|
224
|
+
botBubbleColor: '#ffffff',
|
|
225
|
+
botTextColor: '#333333',
|
|
226
|
+
userBubbleColor: '#111111',
|
|
227
|
+
userTextColor: '#ffffff',
|
|
228
|
+
headerColor: '',
|
|
229
|
+
headerTextColor: ''
|
|
218
230
|
};
|
|
219
231
|
|
|
220
232
|
/* ════════════════════════════════════════════════════════════════
|
|
@@ -1067,7 +1079,8 @@
|
|
|
1067
1079
|
|
|
1068
1080
|
/* ══════════════ FLOATING HEADER (pill, absolute over messages) ══════════════ */
|
|
1069
1081
|
var headerWrap = _el('div', { className: 'wakz-header-wrap' });
|
|
1070
|
-
|
|
1082
|
+
self._headerEl = _el('div', { className: 'wakz-header' });
|
|
1083
|
+
var header = self._headerEl;
|
|
1071
1084
|
|
|
1072
1085
|
/* Specular highlight (real DOM element, not ::before) */
|
|
1073
1086
|
header.appendChild(_el('div', { className: 'wakz-specular' }));
|
|
@@ -1224,6 +1237,8 @@
|
|
|
1224
1237
|
self._chatWindow.classList.add('wakz-visible');
|
|
1225
1238
|
self._overlay.classList.add('wakz-visible');
|
|
1226
1239
|
self._toggleBtn.classList.add('wakz-fab-hidden');
|
|
1240
|
+
/* Re-fetch config on every open to get latest customizations */
|
|
1241
|
+
self._fetchConfig();
|
|
1227
1242
|
/* Fetch history on first open (after config is loaded) */
|
|
1228
1243
|
if (self._configLoaded && !self._hasFetchedHistory) {
|
|
1229
1244
|
self._fetchHistory();
|
|
@@ -1261,27 +1276,38 @@
|
|
|
1261
1276
|
method: 'GET',
|
|
1262
1277
|
headers: { 'Accept': 'application/json' }
|
|
1263
1278
|
}, 30000)
|
|
1264
|
-
.then(function (res) {
|
|
1279
|
+
.then(function (res) {
|
|
1280
|
+
if (!res.ok) {
|
|
1281
|
+
self._handleConfigError(true);
|
|
1282
|
+
return null;
|
|
1283
|
+
}
|
|
1284
|
+
return res.json();
|
|
1285
|
+
})
|
|
1265
1286
|
.then(function (data) {
|
|
1266
1287
|
if (data && data.success && data.config) {
|
|
1267
1288
|
self.config = Object.assign({}, _DEFAULTS, data.config);
|
|
1268
1289
|
self._configLoaded = true;
|
|
1269
1290
|
self._applyConfig();
|
|
1270
|
-
} else {
|
|
1271
|
-
self._handleConfigError();
|
|
1291
|
+
} else if (data !== null) {
|
|
1292
|
+
self._handleConfigError(true);
|
|
1272
1293
|
}
|
|
1273
1294
|
})
|
|
1274
1295
|
.catch(function (err) {
|
|
1275
|
-
self._handleConfigError();
|
|
1296
|
+
self._handleConfigError(false);
|
|
1276
1297
|
});
|
|
1277
1298
|
};
|
|
1278
1299
|
|
|
1279
1300
|
/** Handle config fetch failure — show offline state */
|
|
1280
|
-
WAKZWidget.prototype._handleConfigError = function () {
|
|
1301
|
+
WAKZWidget.prototype._handleConfigError = function (isPermanent) {
|
|
1281
1302
|
var self = this;
|
|
1282
1303
|
self._configError = true;
|
|
1283
1304
|
self.config.online = false;
|
|
1284
1305
|
|
|
1306
|
+
/* Hide FAB entirely if key is permanently invalid */
|
|
1307
|
+
if (isPermanent && self._toggleBtn) {
|
|
1308
|
+
self._toggleBtn.style.display = 'none';
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1285
1311
|
/* Update FAB dot to red */
|
|
1286
1312
|
if (self._statusDot) {
|
|
1287
1313
|
self._statusDot.className = 'wakz-fab-dot offline';
|
|
@@ -1314,6 +1340,10 @@
|
|
|
1314
1340
|
hostStyle.setProperty('--wakz-btn', cfg.btnColor);
|
|
1315
1341
|
hostStyle.setProperty('--wakz-chat-bg', cfg.chatBg);
|
|
1316
1342
|
hostStyle.setProperty('--wakz-widget-bg', cfg.widgetBg);
|
|
1343
|
+
hostStyle.setProperty('--wakz-bot-bubble', cfg.botBubbleColor || '#ffffff');
|
|
1344
|
+
hostStyle.setProperty('--wakz-bot-text', cfg.botTextColor || '#333333');
|
|
1345
|
+
hostStyle.setProperty('--wakz-user-bubble', cfg.userBubbleColor || '#111111');
|
|
1346
|
+
hostStyle.setProperty('--wakz-user-text', cfg.userTextColor || '#ffffff');
|
|
1317
1347
|
|
|
1318
1348
|
/* ── RTL ── */
|
|
1319
1349
|
if (isRtl) self._root.classList.add('wakz-rtl');
|
|
@@ -1363,6 +1393,56 @@
|
|
|
1363
1393
|
/* ── Send button label ── */
|
|
1364
1394
|
self._sendBtn.setAttribute('aria-label', str.sendMessage);
|
|
1365
1395
|
|
|
1396
|
+
/* ── FAB Icon ── */
|
|
1397
|
+
var iconKey = cfg.fabIcon || 'chat';
|
|
1398
|
+
if (iconKey === 'chat') {
|
|
1399
|
+
self._toggleBtn.innerHTML = _ICONS.chatBubble;
|
|
1400
|
+
} else if (_ICONS[iconKey]) {
|
|
1401
|
+
self._toggleBtn.innerHTML = _ICONS[iconKey];
|
|
1402
|
+
}
|
|
1403
|
+
/* Re-append status dot after innerHTML change */
|
|
1404
|
+
if (self._statusDot && self._statusDot.parentNode !== self._toggleBtn) {
|
|
1405
|
+
self._toggleBtn.appendChild(self._statusDot);
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1408
|
+
/* ── FAB Shape ── */
|
|
1409
|
+
if (cfg.fabShape === 'pill') {
|
|
1410
|
+
self._toggleBtn.style.borderRadius = '9999px';
|
|
1411
|
+
self._toggleBtn.style.width = 'auto';
|
|
1412
|
+
self._toggleBtn.style.padding = '0 20px';
|
|
1413
|
+
} else {
|
|
1414
|
+
self._toggleBtn.style.borderRadius = '50%';
|
|
1415
|
+
self._toggleBtn.style.width = '56px';
|
|
1416
|
+
self._toggleBtn.style.padding = '0';
|
|
1417
|
+
}
|
|
1418
|
+
|
|
1419
|
+
/* ── Display Mode ── */
|
|
1420
|
+
if (cfg.displayMode === 'fullscreen') {
|
|
1421
|
+
self._chatWindow.classList.add('wakz-mode-fullscreen');
|
|
1422
|
+
self._chatWindow.classList.remove('wakz-mode-modal');
|
|
1423
|
+
} else {
|
|
1424
|
+
self._chatWindow.classList.add('wakz-mode-modal');
|
|
1425
|
+
self._chatWindow.classList.remove('wakz-mode-fullscreen');
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
/* ── Auto Trigger ── */
|
|
1429
|
+
if (cfg.triggerMode === 'auto' && !self.isOpen) {
|
|
1430
|
+
var autoDelay = Math.max(1, Math.min(60, parseInt(cfg.triggerDelay) || 5)) * 1000;
|
|
1431
|
+
setTimeout(function () {
|
|
1432
|
+
if (!self.isOpen) self.toggleChat(true);
|
|
1433
|
+
}, autoDelay);
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
/* ── Header Colors (only apply if explicitly customized) ── */
|
|
1437
|
+
if (cfg.headerColor) {
|
|
1438
|
+
self._headerEl.style.background = cfg.headerColor;
|
|
1439
|
+
}
|
|
1440
|
+
if (cfg.headerTextColor) {
|
|
1441
|
+
self._headerTitleEl.style.color = cfg.headerTextColor;
|
|
1442
|
+
self._headerSubtitleEl.style.color = cfg.headerTextColor + 'aa';
|
|
1443
|
+
self._closeBtn.style.color = cfg.headerTextColor;
|
|
1444
|
+
}
|
|
1445
|
+
|
|
1366
1446
|
/* ── If chat is already open, show welcome message ── */
|
|
1367
1447
|
if (self.isOpen && self.messages.length === 0 && cfg.welcomeMessage) {
|
|
1368
1448
|
self._appendWelcomeMessage(cfg.welcomeMessage);
|
package/package.json
CHANGED
|
@@ -1 +1,41 @@
|
|
|
1
|
-
{
|
|
1
|
+
{
|
|
2
|
+
"name": "wakz-chat-widget",
|
|
3
|
+
"version": "4.0.1",
|
|
4
|
+
"description": "WAKZ Chat Widget — Liquid Glass design with Shadow DOM isolation, CSS Variables, Data-Driven customization, zero dependencies.",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"prepublishOnly": "echo 'Ready to publish wakz-chat-widget v4.0.1'"
|
|
8
|
+
},
|
|
9
|
+
"keywords": [
|
|
10
|
+
"chat",
|
|
11
|
+
"widget",
|
|
12
|
+
"ai",
|
|
13
|
+
"chatbot",
|
|
14
|
+
"wakz",
|
|
15
|
+
"embed",
|
|
16
|
+
"shadow-dom",
|
|
17
|
+
"customer-support",
|
|
18
|
+
"live-chat",
|
|
19
|
+
"saas",
|
|
20
|
+
"rtl",
|
|
21
|
+
"arabic",
|
|
22
|
+
"device-detection",
|
|
23
|
+
"zero-dependencies",
|
|
24
|
+
"css-variables",
|
|
25
|
+
"data-driven",
|
|
26
|
+
"liquid-glass"
|
|
27
|
+
],
|
|
28
|
+
"author": "mohamed64 <mohamed01140251843sayed@gmail.com>",
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": ""
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"index.js",
|
|
36
|
+
"README.md"
|
|
37
|
+
],
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=12.0.0"
|
|
40
|
+
}
|
|
41
|
+
}
|