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.
Files changed (3) hide show
  1. package/README.md +71 -0
  2. package/index.js +88 -8
  3. 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: '#ffffff',
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
- var header = _el('div', { className: 'wakz-header' });
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) { return res.json(); })
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
- { "name": "wakz-chat-widget", "version": "4.0.0", "description": "WAKZ Chat Widget — Liquid Glass design with Shadow DOM isolation", "main": "index.js", "keywords": ["chat", "widget", "wakz", "liquid-glass", "shadow-dom"], "author": "WAKZ", "license": "MIT" }
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
+ }