@locdo.tech/botiq-chat-sdk 0.3.4 → 0.5.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.
@@ -1,816 +0,0 @@
1
- //#region src/core/config.ts
2
- var e = "https://bot-q-backend.vercel.app", t = {
3
- colors: {
4
- primary: "#F97316",
5
- header: "#F97316",
6
- userBubble: "#F97316",
7
- botBubble: "#1A1A1A",
8
- background: "#000000",
9
- text: "#FFFFFF",
10
- inputBackground: "#1A1A1A"
11
- },
12
- layout: {
13
- position: "bottom-right",
14
- buttonShape: "circle",
15
- width: 360,
16
- height: 520
17
- },
18
- content: {
19
- greeting: "",
20
- suggestionChips: [],
21
- placeholder: ""
22
- },
23
- font: "inter"
24
- }, n = {
25
- name: "BotIQ",
26
- design: t,
27
- widgetLanguage: "vi"
28
- }, r = /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/, i = new Set(["bottom-right", "bottom-left"]), a = new Set(["circle", "square"]), o = new Set([
29
- "inter",
30
- "plus-jakarta",
31
- "poppins",
32
- "nunito",
33
- "dm-sans",
34
- "raleway",
35
- "lato",
36
- "playfair"
37
- ]), s = new Set([
38
- "none",
39
- "fade",
40
- "slide-up",
41
- "bounce"
42
- ]), c = new Set([
43
- "dots-bounce",
44
- "dots-pulse",
45
- "bar"
46
- ]);
47
- function l(e) {
48
- let t = e.colors;
49
- if (t.inputBackground ||= "#1A1A1A", ![
50
- t.primary,
51
- t.header,
52
- t.userBubble,
53
- t.botBubble,
54
- t.background,
55
- t.text,
56
- t.inputBackground
57
- ].every((e) => typeof e == "string" && r.test(e)) || !i.has(e.layout.position) || !a.has(e.layout.buttonShape) || !o.has(e.font)) return !1;
58
- let { width: n, height: l } = e.layout;
59
- if (!Number.isFinite(n) || n < 280 || n > 800 || !Number.isFinite(l) || l < 200 || l > 900) return !1;
60
- if (e.gradient) {
61
- let t = e.gradient;
62
- if (t.type !== "linear" && t.type !== "radial" || !r.test(t.from) || !r.test(t.to) || t.angle !== void 0 && (!Number.isFinite(t.angle) || t.angle < 0 || t.angle > 360)) return !1;
63
- }
64
- return !(e.animation && (!s.has(e.animation.bubbleOpen) || !c.has(e.animation.typingIndicator)) || e.customCSS !== void 0 && (typeof e.customCSS != "string" || e.customCSS.length > 8e3));
65
- }
66
- var u = 8e3;
67
- function d(e, t) {
68
- return fetch(`${t}/widget/meta`, {
69
- headers: { "X-Api-Key": e },
70
- referrerPolicy: "no-referrer-when-downgrade",
71
- signal: AbortSignal.timeout(u)
72
- });
73
- }
74
- async function f(e, r) {
75
- let i;
76
- try {
77
- i = await d(e, r);
78
- } catch {
79
- try {
80
- i = await d(e, r);
81
- } catch {
82
- return n;
83
- }
84
- }
85
- if (i.status === 401 || i.status === 403) return null;
86
- if (!i.ok) return n;
87
- let a;
88
- try {
89
- a = await i.json();
90
- } catch {
91
- return n;
92
- }
93
- let o = typeof a.name == "string" && a.name.length > 0 ? a.name : n.name, s = a.widgetLanguage === "en" ? "en" : "vi";
94
- return !a.design?.colors || !a.design?.layout || !a.design?.content || !l(a.design) ? {
95
- name: o,
96
- design: t,
97
- widgetLanguage: s
98
- } : {
99
- name: o,
100
- design: a.design,
101
- widgetLanguage: s
102
- };
103
- }
104
- function p(t) {
105
- return {
106
- apiKey: t.apiKey,
107
- apiUrl: e
108
- };
109
- }
110
- //#endregion
111
- //#region src/core/session.ts
112
- var m = "botiq:sessionId", h = "botiq:sessionId:", g = "botiq:history:", _ = 10;
113
- function v() {
114
- try {
115
- let e = localStorage.getItem(m);
116
- localStorage.removeItem(m), e && localStorage.removeItem(g + e);
117
- } catch {}
118
- }
119
- function y(e) {
120
- try {
121
- let t = h + e, n = localStorage.getItem(t);
122
- return n || (n = crypto.randomUUID(), localStorage.setItem(t, n)), n;
123
- } catch {
124
- return crypto.randomUUID();
125
- }
126
- }
127
- function b(e, t) {
128
- try {
129
- let n = localStorage.getItem(`${g}${e}:${t}`);
130
- return n ? JSON.parse(n) : [];
131
- } catch {
132
- return [];
133
- }
134
- }
135
- function x(e, t, n) {
136
- try {
137
- let r = [...b(e, t), ...n].slice(-_);
138
- localStorage.setItem(`${g}${e}:${t}`, JSON.stringify(r));
139
- } catch {}
140
- }
141
- //#endregion
142
- //#region src/core/api.ts
143
- async function S(e, t, n, r, i, a) {
144
- try {
145
- let o = await fetch(`${e}/widget/chat`, {
146
- method: "POST",
147
- headers: {
148
- "Content-Type": "application/json",
149
- "X-Api-Key": t
150
- },
151
- referrerPolicy: "no-referrer-when-downgrade",
152
- body: JSON.stringify({
153
- sessionId: n,
154
- message: r,
155
- history: i
156
- })
157
- });
158
- return o.ok ? (await o.json()).reply || a.errorMessage : o.status === 401 ? a.errorAuth : o.status === 403 ? a.errorForbidden : o.status === 429 ? a.errorQuota : a.errorGeneric;
159
- } catch {
160
- return a.errorMessage;
161
- }
162
- }
163
- //#endregion
164
- //#region src/core/state.ts
165
- var C = {
166
- messages: [],
167
- isLoading: !1,
168
- isOpen: !1
169
- }, w = /* @__PURE__ */ new Set();
170
- function T() {
171
- return C;
172
- }
173
- function E(e) {
174
- Object.assign(C, e);
175
- let t = {
176
- ...C,
177
- messages: [...C.messages]
178
- };
179
- w.forEach((e) => e(t));
180
- }
181
- function D(e) {
182
- return w.add(e), () => w.delete(e);
183
- }
184
- //#endregion
185
- //#region src/core/styles.ts
186
- var O = {
187
- inter: {
188
- url: "https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap",
189
- family: "'Inter', system-ui, -apple-system, sans-serif"
190
- },
191
- "plus-jakarta": {
192
- url: "https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600&display=swap",
193
- family: "'Plus Jakarta Sans', system-ui, -apple-system, sans-serif"
194
- },
195
- poppins: {
196
- url: "https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600&display=swap",
197
- family: "'Poppins', system-ui, -apple-system, sans-serif"
198
- },
199
- nunito: {
200
- url: "https://fonts.googleapis.com/css2?family=Nunito:wght@400;500;600&display=swap",
201
- family: "'Nunito', system-ui, -apple-system, sans-serif"
202
- },
203
- "dm-sans": {
204
- url: "https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600&display=swap",
205
- family: "'DM Sans', system-ui, -apple-system, sans-serif"
206
- },
207
- raleway: {
208
- url: "https://fonts.googleapis.com/css2?family=Raleway:wght@400;500;600&display=swap",
209
- family: "'Raleway', system-ui, -apple-system, sans-serif"
210
- },
211
- lato: {
212
- url: "https://fonts.googleapis.com/css2?family=Lato:wght@400;700&display=swap",
213
- family: "'Lato', system-ui, -apple-system, sans-serif"
214
- },
215
- playfair: {
216
- url: "https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;500;600&display=swap",
217
- family: "'Playfair Display', Georgia, serif"
218
- }
219
- };
220
- function k(e, t) {
221
- if (!t) return e;
222
- let n = t.angle ?? 135;
223
- return t.type === "linear" ? `linear-gradient(${n}deg, ${t.from}, ${t.to})` : `radial-gradient(circle, ${t.from}, ${t.to})`;
224
- }
225
- function A(e) {
226
- return e.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\\[0-9a-fA-F]{1,6}\s?/g, "x").replace(/@import\b[^;]*;?/gi, "").replace(/url\s*\(\s*["']?\s*(?!data:)[^)]*["']?\s*\)/gi, "url(\"\")").replace(/expression\s*\(/gi, "expression_(").replace(/javascript\s*:/gi, "blocked:").replace(/-moz-binding\s*:/gi, "").replace(/\bbehavior\s*:/gi, "");
227
- }
228
- function j(e) {
229
- let t = e?.bubbleOpen ?? "none", n = e?.typingIndicator ?? "dots-bounce";
230
- return [t === "fade" ? "@keyframes biq-open-fade { from { opacity: 0; } to { opacity: 1; } }\n.chat-window.open { animation: biq-open-fade .22s ease forwards; }" : t === "slide-up" ? "@keyframes biq-open-slide { from { opacity: 0; transform: scale(1) translateY(20px); } to { opacity: 1; transform: scale(1) translateY(0); } }\n.chat-window.open { animation: biq-open-slide .25s cubic-bezier(.22,1,.36,1) forwards; }" : t === "bounce" ? "@keyframes biq-open-bounce { 0% { opacity: 0; transform: scale(.85) translateY(8px); } 60% { transform: scale(1.03) translateY(-3px); } 100% { opacity: 1; transform: scale(1) translateY(0); } }\n.chat-window.open { animation: biq-open-bounce .35s cubic-bezier(.34,1.56,.64,1) forwards; }" : "", n === "dots-pulse" ? "@keyframes biq-pulse { 0%, 100% { opacity: 0.3; transform: scale(1); } 50% { opacity: 1; transform: scale(1.3); } }\n.typing span { animation: biq-pulse 1.2s infinite ease-in-out; }" : n === "bar" ? ".typing { gap: 3px; align-items: flex-end; }\n.typing span { width: 3px; height: 14px; border-radius: 2px; animation: biq-bar 1s infinite ease-in-out; }\n.typing span:nth-child(1) { animation-delay: 0s; }\n.typing span:nth-child(2) { animation-delay: .15s; height: 20px; }\n.typing span:nth-child(3) { animation-delay: .3s; }\n@keyframes biq-bar { 0%, 100% { transform: scaleY(.4); opacity: .5; } 50% { transform: scaleY(1); opacity: 1; } }" : ""].filter(Boolean).join("\n");
231
- }
232
- function M(e) {
233
- let { colors: t, layout: n, font: r, gradient: i, animation: a, customCSS: o, whiteLabel: s } = e, c = O[r] ?? O.inter, l = n.buttonShape === "square" ? "14px" : "50%", u = n.position === "bottom-left" ? "right: auto; left: 24px;" : "right: 24px;", d = n.position === "bottom-left" ? "bottom left" : "bottom right", f = n.position === "bottom-left" ? "right: auto; left: 0;" : "right: 0;", p = k(t.primary, i), m = k(t.header, i), h = k(t.userBubble, i), g = s ? ".botiq-badge { display: none !important; }" : "";
234
- return `
235
- @import url('${c.url}');
236
-
237
- :host {
238
- position: fixed;
239
- bottom: 24px;
240
- ${u}
241
- z-index: 2147483647;
242
- display: block;
243
- font-family: ${c.family};
244
- --color-primary: ${t.primary};
245
- --color-header: ${t.header};
246
- --color-user: ${t.userBubble};
247
- --color-bot: ${t.botBubble};
248
- --color-bg: ${t.background};
249
- --color-text: ${t.text};
250
- --color-input-bg: ${t.inputBackground};
251
- --gray-50: #1A1A1A;
252
- --gray-100: #222222;
253
- --gray-200: #2D2D2D;
254
- --gray-400: #9CA3AF;
255
- --shadow-sm: 0 2px 8px rgba(0,0,0,.4);
256
- --shadow-md: 0 8px 32px rgba(0,0,0,.5);
257
- --shadow-lg: 0 16px 48px rgba(0,0,0,.6);
258
- --radius-bubble: ${l};
259
- --radius-msg: 18px;
260
- --chat-w: ${n.width}px;
261
- --chat-h: ${n.height}px;
262
- }
263
-
264
- *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
265
-
266
- /* ── Bubble ─────────────────────────────── */
267
- .bubble {
268
- width: 56px;
269
- height: 56px;
270
- border-radius: var(--radius-bubble);
271
- background: ${p};
272
- border: none;
273
- cursor: pointer;
274
- display: flex;
275
- align-items: center;
276
- justify-content: center;
277
- box-shadow: var(--shadow-md);
278
- transition: transform .2s ease, box-shadow .2s ease;
279
- outline: none;
280
- }
281
-
282
- .bubble:hover { transform: scale(1.08); box-shadow: var(--shadow-lg); }
283
- .bubble:active { transform: scale(0.96); }
284
-
285
- .bubble svg { width: 26px; height: 26px; fill: #fff; transition: opacity .15s; }
286
- .bubble .icon-chat { opacity: 1; }
287
- .bubble .icon-close { opacity: 0; position: absolute; }
288
- .bubble.open .icon-chat { opacity: 0; }
289
- .bubble.open .icon-close { opacity: 1; }
290
-
291
- /* ── Chat Window ────────────────────────── */
292
- .chat-window {
293
- position: absolute;
294
- bottom: 72px;
295
- ${f}
296
- width: var(--chat-w);
297
- height: var(--chat-h);
298
- background: var(--color-bg);
299
- border-radius: 20px;
300
- box-shadow: var(--shadow-lg);
301
- display: flex;
302
- flex-direction: column;
303
- overflow: hidden;
304
- transform-origin: ${d};
305
- transform: scale(.94) translateY(8px);
306
- opacity: 0;
307
- pointer-events: none;
308
- transition: transform .22s cubic-bezier(.34,1.56,.64,1), opacity .18s ease;
309
- }
310
-
311
- .chat-window.open { transform: scale(1) translateY(0); opacity: 1; pointer-events: all; }
312
-
313
- /* ── Header ─────────────────────────────── */
314
- .chat-header {
315
- background: ${m};
316
- padding: 16px 16px 14px;
317
- display: flex;
318
- align-items: center;
319
- gap: 10px;
320
- flex-shrink: 0;
321
- }
322
-
323
- .avatar {
324
- width: 36px;
325
- height: 36px;
326
- border-radius: 50%;
327
- background: rgba(255,255,255,.2);
328
- display: flex;
329
- align-items: center;
330
- justify-content: center;
331
- flex-shrink: 0;
332
- overflow: hidden;
333
- }
334
-
335
- .avatar svg { width: 20px; height: 20px; fill: #fff; }
336
-
337
- .header-text { flex: 1; min-width: 0; }
338
-
339
- .bot-name {
340
- color: #fff;
341
- font-weight: 600;
342
- font-size: 15px;
343
- line-height: 1.2;
344
- display: block;
345
- white-space: nowrap;
346
- overflow: hidden;
347
- text-overflow: ellipsis;
348
- }
349
-
350
- .bot-status { color: rgba(255,255,255,.75); font-size: 12px; display: block; margin-top: 1px; }
351
-
352
- .close-btn {
353
- width: 30px;
354
- height: 30px;
355
- border-radius: 50%;
356
- background: rgba(255,255,255,.15);
357
- border: none;
358
- cursor: pointer;
359
- color: #fff;
360
- font-size: 18px;
361
- display: flex;
362
- align-items: center;
363
- justify-content: center;
364
- flex-shrink: 0;
365
- transition: background .15s;
366
- }
367
- .close-btn:hover { background: rgba(255,255,255,.25); }
368
-
369
- /* ── Messages ───────────────────────────── */
370
- .messages {
371
- flex: 1;
372
- overflow-y: auto;
373
- padding: 16px 14px;
374
- display: flex;
375
- flex-direction: column;
376
- gap: 10px;
377
- scroll-behavior: smooth;
378
- }
379
-
380
- .messages::-webkit-scrollbar { width: 4px; }
381
- .messages::-webkit-scrollbar-track { background: transparent; }
382
- .messages::-webkit-scrollbar-thumb { background: var(--gray-200); border-radius: 2px; }
383
-
384
- .message { display: flex; flex-direction: column; max-width: 82%; }
385
- .message.user { align-self: flex-end; align-items: flex-end; }
386
- .message.assistant { align-self: flex-start; align-items: flex-start; max-width: 92%; }
387
-
388
- .message-bubble {
389
- padding: 10px 14px;
390
- border-radius: var(--radius-msg);
391
- font-size: 14px;
392
- line-height: 1.5;
393
- white-space: normal;
394
- word-break: break-word;
395
- overflow-x: auto;
396
- }
397
-
398
- /* ── Markdown inline elements ───────────────────────── */
399
- .message-bubble strong { font-weight: 600; }
400
- .message-bubble em { font-style: italic; }
401
- .message-bubble a { color: var(--color-primary); text-decoration: underline; word-break: break-all; }
402
- .message-bubble code {
403
- font-family: monospace;
404
- font-size: 12px;
405
- padding: 1px 5px;
406
- border-radius: 4px;
407
- background: rgba(255,255,255,.1);
408
- white-space: pre-wrap;
409
- }
410
-
411
- /* ── Markdown tables ─────────────────────────────────── */
412
- .message-bubble table {
413
- border-collapse: collapse;
414
- min-width: 100%;
415
- font-size: 12.5px;
416
- display: block;
417
- overflow-x: auto;
418
- margin: 4px 0;
419
- }
420
- .message-bubble th,
421
- .message-bubble td {
422
- border: 1px solid rgba(255,255,255,.15);
423
- padding: 5px 10px;
424
- text-align: left;
425
- }
426
- .message-bubble th { background: rgba(255,255,255,.08); font-weight: 600; white-space: nowrap; }
427
- .message-bubble td { white-space: normal; }
428
- .message-bubble tr:nth-child(even) td { background: rgba(255,255,255,.04); }
429
-
430
- /* ── Markdown lists ──────────────────────────────────── */
431
- .message-bubble ul,
432
- .message-bubble ol { padding-left: 18px; margin: 2px 0; }
433
- .message-bubble li { margin: 2px 0; }
434
-
435
- .message.user .message-bubble {
436
- background: ${h};
437
- color: #fff;
438
- border-bottom-right-radius: 4px;
439
- white-space: pre-wrap;
440
- }
441
-
442
- .message.assistant .message-bubble {
443
- background: var(--color-bot);
444
- color: var(--color-text);
445
- border-bottom-left-radius: 4px;
446
- }
447
-
448
- /* ── Typing Indicator ───────────────────── */
449
- .typing {
450
- display: flex;
451
- align-items: center;
452
- gap: 4px;
453
- padding: 12px 14px;
454
- background: var(--color-bot);
455
- border-radius: var(--radius-msg);
456
- border-bottom-left-radius: 4px;
457
- align-self: flex-start;
458
- width: fit-content;
459
- }
460
-
461
- .typing span {
462
- width: 7px;
463
- height: 7px;
464
- border-radius: 50%;
465
- background: var(--color-primary);
466
- opacity: 0.5;
467
- animation: bounce 1.2s infinite ease-in-out;
468
- }
469
-
470
- .typing span:nth-child(2) { animation-delay: .2s; }
471
- .typing span:nth-child(3) { animation-delay: .4s; }
472
-
473
- @keyframes bounce {
474
- 0%, 60%, 100% { transform: translateY(0); }
475
- 30% { transform: translateY(-6px); }
476
- }
477
-
478
- /* ── Empty / Greeting State ─────────────── */
479
- .empty-state {
480
- flex: 1;
481
- display: flex;
482
- flex-direction: column;
483
- align-items: center;
484
- justify-content: center;
485
- gap: 8px;
486
- color: var(--gray-400);
487
- font-size: 13px;
488
- text-align: center;
489
- padding: 24px;
490
- }
491
-
492
- .empty-state svg { width: 40px; height: 40px; fill: var(--gray-200); margin-bottom: 4px; }
493
- .empty-state .greeting { color: var(--color-text); font-size: 13px; opacity: 0.7; }
494
-
495
- /* ── Suggestion Chips ───────────────────── */
496
- .chips {
497
- display: flex;
498
- flex-wrap: wrap;
499
- gap: 6px;
500
- justify-content: center;
501
- margin-top: 4px;
502
- }
503
-
504
- .chip {
505
- padding: 5px 12px;
506
- border-radius: 16px;
507
- border: 1.5px solid var(--color-primary);
508
- color: var(--color-primary);
509
- background: transparent;
510
- font-size: 12px;
511
- font-family: inherit;
512
- cursor: pointer;
513
- transition: background .15s, color .15s;
514
- }
515
-
516
- .chip:hover {
517
- background: var(--color-primary);
518
- color: #fff;
519
- }
520
-
521
- /* ── Footer / Input ─────────────────────── */
522
- .chat-footer {
523
- border-top: 1px solid var(--gray-100);
524
- padding: 10px 12px;
525
- background: var(--color-bg);
526
- flex-shrink: 0;
527
- }
528
-
529
- .input-row { display: flex; align-items: flex-end; gap: 8px; }
530
-
531
- /* Subtle attribution — half-opacity, hover lifts to full. Doesn't steal focus
532
- from tenant branding but reminds the customer this is powered by BotIQ. */
533
- .botiq-badge {
534
- display: block;
535
- text-align: center;
536
- font-size: 10px;
537
- font-weight: 400;
538
- color: var(--color-text);
539
- opacity: 0.4;
540
- text-decoration: none;
541
- margin-top: 6px;
542
- letter-spacing: 0.02em;
543
- transition: opacity .15s;
544
- }
545
- .botiq-badge:hover { opacity: 0.85; }
546
- .botiq-badge-name { font-weight: 600; color: var(--color-primary); }
547
-
548
- .input {
549
- flex: 1;
550
- min-height: 38px;
551
- max-height: 100px;
552
- border: 1.5px solid var(--gray-200);
553
- border-radius: 12px;
554
- padding: 9px 12px;
555
- font-family: inherit;
556
- font-size: 14px;
557
- color: var(--color-text);
558
- resize: none;
559
- outline: none;
560
- background: var(--color-input-bg);
561
- line-height: 1.4;
562
- overflow-y: auto;
563
- transition: border-color .15s;
564
- }
565
-
566
- .input:focus { border-color: var(--color-primary); background: var(--color-input-bg); }
567
- .input::placeholder { color: var(--gray-400); }
568
-
569
- .send-btn {
570
- width: 38px;
571
- height: 38px;
572
- border-radius: 10px;
573
- background: ${p};
574
- border: none;
575
- cursor: pointer;
576
- display: flex;
577
- align-items: center;
578
- justify-content: center;
579
- flex-shrink: 0;
580
- transition: filter .15s, transform .1s;
581
- }
582
-
583
- .send-btn:hover { filter: brightness(0.88); }
584
- .send-btn:active { transform: scale(0.94); }
585
- .send-btn:disabled { background: var(--gray-200); cursor: not-allowed; filter: none; }
586
- .send-btn svg { width: 18px; height: 18px; fill: #fff; }
587
-
588
- ${g}
589
- ${j(a)}
590
- ${o ? A(o) : ""}
591
- `;
592
- }
593
- //#endregion
594
- //#region src/core/assets.ts
595
- var N = "data:image/png;base64,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", P = "https://bot-q-frontend.vercel.app/", F = "<svg viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M20 2H4a2 2 0 00-2 2v18l4-4h14a2 2 0 002-2V4a2 2 0 00-2-2z\"/>\n</svg>", I = "<svg viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"/>\n</svg>", L = `<img src="${N}" alt="" style="width:100%;height:100%;object-fit:cover;border-radius:50%" />`, R = "<svg viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M2.01 21L23 12 2.01 3 2 10l15 2-15 2z\"/>\n</svg>", z = "<svg viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M20 2H4a2 2 0 00-2 2v18l4-4h14a2 2 0 002-2V4a2 2 0 00-2-2zm-2 10H6v-2h12v2zm0-3H6V7h12v2z\"/>\n</svg>";
596
- function B(e) {
597
- if (!e || e.type === "icon") return L;
598
- if (e.type === "emoji") return `<span style="font-size:22px;line-height:1;display:flex;align-items:center;justify-content:center;width:100%;height:100%">${V(e.value)}</span>`;
599
- if (e.type === "initials") {
600
- let t = e.bgColor ?? "#F97316";
601
- return `<div style="width:100%;height:100%;border-radius:50%;background:${/^#[0-9A-Fa-f]{3,6}$/.test(t) ? t : "#F97316"};display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:700;color:#fff">${V(e.value.slice(0, 2).toUpperCase())}</div>`;
602
- }
603
- return e.type === "image" ? `<img src="${V(e.value)}" style="width:100%;height:100%;object-fit:cover;border-radius:50%" alt="" />` : L;
604
- }
605
- function V(e) {
606
- return e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#x27;");
607
- }
608
- function H(e) {
609
- let t = [];
610
- return e = e.replace(/`([^`]+)`/g, (e, n) => (t.push(`<code>${n}</code>`), `\x00CODE${t.length - 1}\x00`)), e = e.replace(/\*\*\*(.+?)\*\*\*/g, "<strong><em>$1</em></strong>"), e = e.replace(/\*\*(.+?)\*\*/g, "<strong>$1</strong>"), e = e.replace(/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g, "<em>$1</em>"), e = e.replace(/\[([^\]]+)\]\(([^()]*(?:\([^()]*\))*[^()]*)\)/g, (e, t, n) => /^https?:\/\//.test(n) ? `<a href="${n}" target="_blank" rel="noopener noreferrer">${t}</a>` : t), e = e.replace(/\x00CODE(\d+)\x00/g, (e, n) => t[Number(n)]), e;
611
- }
612
- function U(e) {
613
- return /^\|[\s\-:|]+\|$/.test(e);
614
- }
615
- function W(e) {
616
- return e.replace(/^\|/, "").replace(/\|$/, "").split("|").map((e) => e.trim());
617
- }
618
- function G(e) {
619
- let t = V(e).replace(/\x00/g, "").split("\n"), n = [], r = 0;
620
- for (; r < t.length;) {
621
- let e = t[r].trim();
622
- if (e.startsWith("|") && e.endsWith("|")) {
623
- let e = [];
624
- for (; r < t.length && t[r].trim().startsWith("|") && t[r].trim().endsWith("|");) e.push(t[r].trim()), r++;
625
- let i = e.findIndex(U), a = i > 0 ? e.slice(0, i) : [], o = i >= 0 ? e.slice(i + 1) : e, s = "<table>";
626
- a.length > 0 && (s += "<thead>" + a.map((e) => "<tr>" + W(e).map((e) => `<th>${H(e)}</th>`).join("") + "</tr>").join("") + "</thead>"), o.length > 0 && (s += "<tbody>" + o.map((e) => "<tr>" + W(e).map((e) => `<td>${H(e)}</td>`).join("") + "</tr>").join("") + "</tbody>"), s += "</table>", n.push(s);
627
- continue;
628
- }
629
- if (/^[-*]\s/.test(e)) {
630
- let e = [];
631
- for (; r < t.length && /^\s*[-*]\s/.test(t[r]);) e.push(t[r].trim().replace(/^[-*]\s+/, "")), r++;
632
- n.push("<ul>" + e.map((e) => `<li>${H(e)}</li>`).join("") + "</ul>");
633
- continue;
634
- }
635
- if (/^\d+\.\s/.test(e)) {
636
- let e = [];
637
- for (; r < t.length && /^\s*\d+\.\s/.test(t[r]);) e.push(t[r].trim().replace(/^\d+\.\s+/, "")), r++;
638
- n.push("<ol>" + e.map((e) => `<li>${H(e)}</li>`).join("") + "</ol>");
639
- continue;
640
- }
641
- if (e === "") {
642
- n.push("<br>"), r++;
643
- continue;
644
- }
645
- n.push(H(e)), n.push("<br>"), r++;
646
- }
647
- for (; n.length > 0 && n[n.length - 1] === "<br>";) n.pop();
648
- return n.join("");
649
- }
650
- function K(e, t, n, r, i) {
651
- let { name: a, design: o } = t, s, c, l, u, d, f, { content: p } = o;
652
- function m(e) {
653
- e.setAttribute("data-position", o.layout.position), s = e.attachShadow({ mode: "closed" });
654
- let t = document.createElement("style");
655
- t.textContent = M(o), s.appendChild(t), c = document.createElement("button"), c.className = "bubble", c.setAttribute("aria-label", n.ariaOpenChat), c.innerHTML = `
656
- <span class="icon-chat">${F}</span>
657
- <span class="icon-close">${I}</span>
658
- `, c.addEventListener("click", i), s.appendChild(c), l = document.createElement("div"), l.className = "chat-window", l.setAttribute("role", "dialog"), l.setAttribute("aria-label", `${a} chat`), l.innerHTML = `
659
- <div class="chat-header">
660
- <div class="avatar">${B(o.avatar)}</div>
661
- <div class="header-text">
662
- <span class="bot-name">${V(a)}</span>
663
- <span class="bot-status">${V(n.statusOnline)}</span>
664
- </div>
665
- <button class="close-btn" aria-label="${V(n.ariaCloseChat)}">×</button>
666
- </div>
667
- <div class="messages" id="messages-container" role="log" aria-live="polite" aria-atomic="false"></div>
668
- <div class="chat-footer">
669
- <div class="input-row">
670
- <textarea
671
- class="input"
672
- placeholder="${V(p.placeholder || n.inputPlaceholder)}"
673
- rows="1"
674
- maxlength="2000"
675
- aria-label="Message input"
676
- ></textarea>
677
- <button class="send-btn" aria-label="${V(n.ariaSendMessage)}">
678
- ${R}
679
- </button>
680
- </div>
681
- <a class="botiq-badge" href="${P}" target="_blank" rel="noopener noreferrer">
682
- ${V(n.poweredBy)} <span class="botiq-badge-name">BotIQ</span>
683
- </a>
684
- </div>
685
- `, l.querySelector(".close-btn").addEventListener("click", i), u = l.querySelector("#messages-container"), d = l.querySelector(".input"), f = l.querySelector(".send-btn"), d.addEventListener("input", () => {
686
- d.style.height = "auto", d.style.height = Math.min(d.scrollHeight, 100) + "px";
687
- }), d.addEventListener("keydown", (e) => {
688
- e.key === "Enter" && !e.shiftKey && (e.preventDefault(), h());
689
- }), f.addEventListener("click", h), s.appendChild(l);
690
- }
691
- function h() {
692
- let e = d.value.trim();
693
- !e || f.disabled || (d.value = "", d.style.height = "auto", r(e));
694
- }
695
- function g(e) {
696
- if (e.messages.length === 0 && !e.isLoading) {
697
- let e = p.suggestionChips.length > 0 ? `<div class="chips">${p.suggestionChips.map((e) => `<button class="chip">${V(e)}</button>`).join("")}</div>` : "";
698
- u.innerHTML = `
699
- <div class="empty-state">
700
- ${z}
701
- <span class="greeting">${V(p.greeting || n.defaultGreeting)}</span>
702
- ${e}
703
- </div>
704
- `, u.querySelectorAll(".chip").forEach((e) => {
705
- e.addEventListener("click", () => r(e.textContent ?? ""));
706
- });
707
- return;
708
- }
709
- let t = e.messages.map((e) => `
710
- <div class="message ${e.role}">
711
- <div class="message-bubble">${e.role === "assistant" ? G(e.content) : V(e.content)}</div>
712
- </div>
713
- `).join(""), i = e.isLoading ? "<div class=\"typing\"><span></span><span></span><span></span></div>" : "";
714
- u.innerHTML = t + i, u.scrollTop = u.scrollHeight;
715
- }
716
- function _(e) {
717
- e.isOpen ? (l.classList.add("open"), c.classList.add("open"), c.setAttribute("aria-label", n.ariaCloseChat), requestAnimationFrame(() => d.focus())) : (l.classList.remove("open"), c.classList.remove("open"), c.setAttribute("aria-label", n.ariaOpenChat)), f.disabled = e.isLoading, g(e);
718
- }
719
- return {
720
- mount: m,
721
- update: _
722
- };
723
- }
724
- //#endregion
725
- //#region src/i18n/vi.ts
726
- var q = {
727
- statusOnline: "Trực tuyến",
728
- inputPlaceholder: "Nhắn tin...",
729
- defaultGreeting: "Xin chào! Tôi có thể giúp gì cho bạn?",
730
- errorMessage: "Xin lỗi, không thể kết nối. Vui lòng thử lại.",
731
- errorAuth: "API key không hợp lệ.",
732
- errorForbidden: "Widget không được phép trên trang này.",
733
- errorQuota: "Bot đã đạt giới hạn tin nhắn tháng này.",
734
- errorGeneric: "Đang gặp sự cố kỹ thuật, vui lòng liên hệ trực tiếp.",
735
- typingIndicator: "Đang soạn tin...",
736
- quotaExceeded: "Bot đã hết lượt chat tháng này.",
737
- trialExpired: "Dịch vụ tạm dừng. Vui lòng liên hệ hỗ trợ.",
738
- poweredBy: "Powered by",
739
- ariaOpenChat: "Mở khung chat",
740
- ariaCloseChat: "Đóng khung chat",
741
- ariaSendMessage: "Gửi tin nhắn"
742
- }, J = {
743
- statusOnline: "Online",
744
- inputPlaceholder: "Type a message...",
745
- defaultGreeting: "Hello! How can I help you?",
746
- errorMessage: "Sorry, something went wrong. Please try again.",
747
- errorAuth: "Invalid API key.",
748
- errorForbidden: "Widget is not allowed on this page.",
749
- errorQuota: "This bot has reached its monthly message limit.",
750
- errorGeneric: "Technical issue, please contact us directly.",
751
- typingIndicator: "Typing...",
752
- quotaExceeded: "This bot has reached its monthly chat limit.",
753
- trialExpired: "Service paused. Please contact support.",
754
- poweredBy: "Powered by",
755
- ariaOpenChat: "Open chat",
756
- ariaCloseChat: "Close chat",
757
- ariaSendMessage: "Send message"
758
- };
759
- //#endregion
760
- //#region src/i18n/index.ts
761
- function Y(e) {
762
- return e === "en" ? J : q;
763
- }
764
- //#endregion
765
- //#region src/builds/npm/index.ts
766
- function X(e) {
767
- if (!e.apiKey) return console.warn("[BotIQ] apiKey is required"), () => void 0;
768
- let t = p(e);
769
- v();
770
- let n = t.apiKey.slice(-16), r = y(n);
771
- E({ messages: b(n, r) });
772
- let i = document.createElement("div");
773
- document.body.appendChild(i);
774
- let a = () => void 0, o = !1, s = Y(void 0);
775
- f(t.apiKey, t.apiUrl).then((e) => {
776
- if (o) return;
777
- if (e === null) {
778
- console.warn("[BotIQ] Widget not authorised on this origin — skipped mount"), i.remove();
779
- return;
780
- }
781
- s = Y(e.widgetLanguage);
782
- let n = K(t, e, s, c, l);
783
- n.mount(i), a = D((e) => n.update(e)), n.update(T());
784
- });
785
- function c(e) {
786
- let i = T();
787
- if (i.isLoading) return;
788
- let a = {
789
- role: "user",
790
- content: e
791
- };
792
- E({
793
- messages: [...i.messages, a],
794
- isLoading: !0
795
- }), S(t.apiUrl, t.apiKey, r, e, i.messages, s).then((e) => {
796
- let t = {
797
- role: "assistant",
798
- content: e
799
- };
800
- E({
801
- messages: [...T().messages, t],
802
- isLoading: !1
803
- }), x(n, r, [a, t]);
804
- }).catch(() => {
805
- E({ isLoading: !1 });
806
- });
807
- }
808
- function l() {
809
- E({ isOpen: !T().isOpen });
810
- }
811
- return () => {
812
- o = !0, a(), i.remove();
813
- };
814
- }
815
- //#endregion
816
- export { X as t };