@locdo.tech/botiq-chat-sdk 0.3.0 → 0.3.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/dist/sdk/index.js +1 -1
- package/dist/sdk/{npm-6G46H82M.js → npm-D7UnWA_n.js} +194 -114
- package/dist/sdk/react.js +1 -1
- package/dist/sdk/vue.js +1 -1
- package/package.json +1 -1
package/dist/sdk/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as e } from "./npm-
|
|
1
|
+
import { t as e } from "./npm-D7UnWA_n.js";
|
|
2
2
|
export { e as init };
|
|
@@ -17,12 +17,13 @@ var e = "https://bot-q-backend.vercel.app", t = {
|
|
|
17
17
|
height: 520
|
|
18
18
|
},
|
|
19
19
|
content: {
|
|
20
|
-
greeting: "
|
|
20
|
+
greeting: "",
|
|
21
21
|
suggestionChips: [],
|
|
22
|
-
placeholder: "
|
|
22
|
+
placeholder: ""
|
|
23
23
|
},
|
|
24
24
|
font: "inter"
|
|
25
|
-
}
|
|
25
|
+
},
|
|
26
|
+
widgetLanguage: "vi"
|
|
26
27
|
}, n = /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/, r = new Set(["bottom-right", "bottom-left"]), i = new Set(["circle", "square"]), a = new Set([
|
|
27
28
|
"inter",
|
|
28
29
|
"plus-jakarta",
|
|
@@ -32,8 +33,17 @@ var e = "https://bot-q-backend.vercel.app", t = {
|
|
|
32
33
|
"raleway",
|
|
33
34
|
"lato",
|
|
34
35
|
"playfair"
|
|
36
|
+
]), o = new Set([
|
|
37
|
+
"none",
|
|
38
|
+
"fade",
|
|
39
|
+
"slide-up",
|
|
40
|
+
"bounce"
|
|
41
|
+
]), s = new Set([
|
|
42
|
+
"dots-bounce",
|
|
43
|
+
"dots-pulse",
|
|
44
|
+
"bar"
|
|
35
45
|
]);
|
|
36
|
-
function
|
|
46
|
+
function c(e) {
|
|
37
47
|
let t = e.colors;
|
|
38
48
|
if (![
|
|
39
49
|
t.primary,
|
|
@@ -43,10 +53,15 @@ function o(e) {
|
|
|
43
53
|
t.background,
|
|
44
54
|
t.text
|
|
45
55
|
].every((e) => typeof e == "string" && n.test(e)) || !r.has(e.layout.position) || !i.has(e.layout.buttonShape) || !a.has(e.font)) return !1;
|
|
46
|
-
let { width:
|
|
47
|
-
|
|
56
|
+
let { width: c, height: l } = e.layout;
|
|
57
|
+
if (!Number.isFinite(c) || c < 280 || c > 800 || !Number.isFinite(l) || l < 200 || l > 900) return !1;
|
|
58
|
+
if (e.gradient) {
|
|
59
|
+
let t = e.gradient;
|
|
60
|
+
if (t.type !== "linear" && t.type !== "radial" || !n.test(t.from) || !n.test(t.to) || t.angle !== void 0 && (!Number.isFinite(t.angle) || t.angle < 0 || t.angle > 360)) return !1;
|
|
61
|
+
}
|
|
62
|
+
return !(e.animation && (!o.has(e.animation.bubbleOpen) || !s.has(e.animation.typingIndicator)) || e.customCSS !== void 0 && (typeof e.customCSS != "string" || e.customCSS.length > 8e3));
|
|
48
63
|
}
|
|
49
|
-
async function
|
|
64
|
+
async function l(e, n) {
|
|
50
65
|
try {
|
|
51
66
|
let r = await fetch(`${n}/widget/meta`, {
|
|
52
67
|
headers: { "X-Api-Key": e },
|
|
@@ -54,15 +69,18 @@ async function s(e, n) {
|
|
|
54
69
|
});
|
|
55
70
|
if (!r.ok) return t;
|
|
56
71
|
let i = await r.json();
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
72
|
+
if (!i?.design?.colors || !i?.design?.layout || !i?.design?.content || !c(i.design)) return t;
|
|
73
|
+
let a = typeof i.name == "string" && i.name.length > 0 ? i.name : "BotIQ", o = i.widgetLanguage === "en" ? "en" : "vi";
|
|
74
|
+
return {
|
|
75
|
+
name: a,
|
|
76
|
+
design: i.design,
|
|
77
|
+
widgetLanguage: o
|
|
60
78
|
};
|
|
61
79
|
} catch {
|
|
62
80
|
return t;
|
|
63
81
|
}
|
|
64
82
|
}
|
|
65
|
-
function
|
|
83
|
+
function u(t) {
|
|
66
84
|
return {
|
|
67
85
|
apiKey: t.apiKey,
|
|
68
86
|
apiUrl: e
|
|
@@ -70,39 +88,34 @@ function c(t) {
|
|
|
70
88
|
}
|
|
71
89
|
//#endregion
|
|
72
90
|
//#region src/core/session.ts
|
|
73
|
-
var
|
|
74
|
-
function
|
|
91
|
+
var d = "botiq:sessionId", f = "botiq:history:", p = 10;
|
|
92
|
+
function m() {
|
|
75
93
|
try {
|
|
76
|
-
let e = localStorage.getItem(
|
|
77
|
-
return e || (e = crypto.randomUUID(), localStorage.setItem(
|
|
94
|
+
let e = localStorage.getItem(d);
|
|
95
|
+
return e || (e = crypto.randomUUID(), localStorage.setItem(d, e)), e;
|
|
78
96
|
} catch {
|
|
79
97
|
return crypto.randomUUID();
|
|
80
98
|
}
|
|
81
99
|
}
|
|
82
|
-
function
|
|
100
|
+
function h(e) {
|
|
83
101
|
try {
|
|
84
|
-
let t = localStorage.getItem(
|
|
102
|
+
let t = localStorage.getItem(f + e);
|
|
85
103
|
return t ? JSON.parse(t) : [];
|
|
86
104
|
} catch {
|
|
87
105
|
return [];
|
|
88
106
|
}
|
|
89
107
|
}
|
|
90
|
-
function
|
|
108
|
+
function g(e, t) {
|
|
91
109
|
try {
|
|
92
|
-
let n = [...
|
|
93
|
-
localStorage.setItem(
|
|
110
|
+
let n = [...h(e), ...t].slice(-p);
|
|
111
|
+
localStorage.setItem(f + e, JSON.stringify(n));
|
|
94
112
|
} catch {}
|
|
95
113
|
}
|
|
96
114
|
//#endregion
|
|
97
115
|
//#region src/core/api.ts
|
|
98
|
-
|
|
99
|
-
401: "API key không hợp lệ.",
|
|
100
|
-
403: "Widget không được phép trên trang này.",
|
|
101
|
-
429: "Bot đã đạt giới hạn tin nhắn tháng này."
|
|
102
|
-
};
|
|
103
|
-
async function g(e, t, n, r, i) {
|
|
116
|
+
async function _(e, t, n, r, i, a) {
|
|
104
117
|
try {
|
|
105
|
-
let
|
|
118
|
+
let o = await fetch(`${e}/widget/chat`, {
|
|
106
119
|
method: "POST",
|
|
107
120
|
headers: {
|
|
108
121
|
"Content-Type": "application/json",
|
|
@@ -114,35 +127,35 @@ async function g(e, t, n, r, i) {
|
|
|
114
127
|
history: i
|
|
115
128
|
})
|
|
116
129
|
});
|
|
117
|
-
return
|
|
130
|
+
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;
|
|
118
131
|
} catch {
|
|
119
|
-
return
|
|
132
|
+
return a.errorMessage;
|
|
120
133
|
}
|
|
121
134
|
}
|
|
122
135
|
//#endregion
|
|
123
136
|
//#region src/core/state.ts
|
|
124
|
-
var
|
|
137
|
+
var v = {
|
|
125
138
|
messages: [],
|
|
126
139
|
isLoading: !1,
|
|
127
140
|
isOpen: !1
|
|
128
|
-
},
|
|
129
|
-
function
|
|
130
|
-
return
|
|
141
|
+
}, y = /* @__PURE__ */ new Set();
|
|
142
|
+
function b() {
|
|
143
|
+
return v;
|
|
131
144
|
}
|
|
132
|
-
function
|
|
133
|
-
Object.assign(
|
|
145
|
+
function x(e) {
|
|
146
|
+
Object.assign(v, e);
|
|
134
147
|
let t = {
|
|
135
|
-
...
|
|
136
|
-
messages: [...
|
|
148
|
+
...v,
|
|
149
|
+
messages: [...v.messages]
|
|
137
150
|
};
|
|
138
|
-
|
|
151
|
+
y.forEach((e) => e(t));
|
|
139
152
|
}
|
|
140
|
-
function
|
|
141
|
-
return
|
|
153
|
+
function S(e) {
|
|
154
|
+
return y.add(e), () => y.delete(e);
|
|
142
155
|
}
|
|
143
156
|
//#endregion
|
|
144
157
|
//#region src/core/styles.ts
|
|
145
|
-
var
|
|
158
|
+
var C = {
|
|
146
159
|
inter: {
|
|
147
160
|
url: "https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap",
|
|
148
161
|
family: "'Inter', system-ui, -apple-system, sans-serif"
|
|
@@ -176,18 +189,30 @@ var S = {
|
|
|
176
189
|
family: "'Playfair Display', Georgia, serif"
|
|
177
190
|
}
|
|
178
191
|
};
|
|
179
|
-
function
|
|
180
|
-
|
|
192
|
+
function w(e, t) {
|
|
193
|
+
if (!t) return e;
|
|
194
|
+
let n = t.angle ?? 135;
|
|
195
|
+
return t.type === "linear" ? `linear-gradient(${n}deg, ${t.from}, ${t.to})` : `radial-gradient(circle, ${t.from}, ${t.to})`;
|
|
196
|
+
}
|
|
197
|
+
function T(e) {
|
|
198
|
+
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, "");
|
|
199
|
+
}
|
|
200
|
+
function E(e) {
|
|
201
|
+
let t = e?.bubbleOpen ?? "none", n = e?.typingIndicator ?? "dots-bounce";
|
|
202
|
+
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");
|
|
203
|
+
}
|
|
204
|
+
function D(e) {
|
|
205
|
+
let { colors: t, layout: n, font: r, gradient: i, animation: a, customCSS: o, whiteLabel: s } = e, c = C[r] ?? C.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 = w(t.primary, i), m = w(t.header, i), h = w(t.userBubble, i), g = s ? ".botiq-badge { display: none !important; }" : "";
|
|
181
206
|
return `
|
|
182
|
-
@import url('${
|
|
207
|
+
@import url('${c.url}');
|
|
183
208
|
|
|
184
209
|
:host {
|
|
185
210
|
position: fixed;
|
|
186
211
|
bottom: 24px;
|
|
187
|
-
${
|
|
212
|
+
${u}
|
|
188
213
|
z-index: 2147483647;
|
|
189
214
|
display: block;
|
|
190
|
-
font-family: ${
|
|
215
|
+
font-family: ${c.family};
|
|
191
216
|
--color-primary: ${t.primary};
|
|
192
217
|
--color-header: ${t.header};
|
|
193
218
|
--color-user: ${t.userBubble};
|
|
@@ -201,7 +226,7 @@ function C(e) {
|
|
|
201
226
|
--shadow-sm: 0 2px 8px rgba(0,0,0,.4);
|
|
202
227
|
--shadow-md: 0 8px 32px rgba(0,0,0,.5);
|
|
203
228
|
--shadow-lg: 0 16px 48px rgba(0,0,0,.6);
|
|
204
|
-
--radius-bubble: ${
|
|
229
|
+
--radius-bubble: ${l};
|
|
205
230
|
--radius-msg: 18px;
|
|
206
231
|
--chat-w: ${n.width}px;
|
|
207
232
|
--chat-h: ${n.height}px;
|
|
@@ -214,7 +239,7 @@ function C(e) {
|
|
|
214
239
|
width: 56px;
|
|
215
240
|
height: 56px;
|
|
216
241
|
border-radius: var(--radius-bubble);
|
|
217
|
-
background:
|
|
242
|
+
background: ${p};
|
|
218
243
|
border: none;
|
|
219
244
|
cursor: pointer;
|
|
220
245
|
display: flex;
|
|
@@ -238,7 +263,7 @@ function C(e) {
|
|
|
238
263
|
.chat-window {
|
|
239
264
|
position: absolute;
|
|
240
265
|
bottom: 72px;
|
|
241
|
-
${
|
|
266
|
+
${f}
|
|
242
267
|
width: var(--chat-w);
|
|
243
268
|
height: var(--chat-h);
|
|
244
269
|
background: var(--color-bg);
|
|
@@ -247,7 +272,7 @@ function C(e) {
|
|
|
247
272
|
display: flex;
|
|
248
273
|
flex-direction: column;
|
|
249
274
|
overflow: hidden;
|
|
250
|
-
transform-origin: ${
|
|
275
|
+
transform-origin: ${d};
|
|
251
276
|
transform: scale(.94) translateY(8px);
|
|
252
277
|
opacity: 0;
|
|
253
278
|
pointer-events: none;
|
|
@@ -258,7 +283,7 @@ function C(e) {
|
|
|
258
283
|
|
|
259
284
|
/* ── Header ─────────────────────────────── */
|
|
260
285
|
.chat-header {
|
|
261
|
-
background:
|
|
286
|
+
background: ${m};
|
|
262
287
|
padding: 16px 16px 14px;
|
|
263
288
|
display: flex;
|
|
264
289
|
align-items: center;
|
|
@@ -341,7 +366,7 @@ function C(e) {
|
|
|
341
366
|
}
|
|
342
367
|
|
|
343
368
|
.message.user .message-bubble {
|
|
344
|
-
background:
|
|
369
|
+
background: ${h};
|
|
345
370
|
color: #fff;
|
|
346
371
|
border-bottom-right-radius: 4px;
|
|
347
372
|
}
|
|
@@ -477,7 +502,7 @@ function C(e) {
|
|
|
477
502
|
width: 38px;
|
|
478
503
|
height: 38px;
|
|
479
504
|
border-radius: 10px;
|
|
480
|
-
background:
|
|
505
|
+
background: ${p};
|
|
481
506
|
border: none;
|
|
482
507
|
cursor: pointer;
|
|
483
508
|
display: flex;
|
|
@@ -491,134 +516,189 @@ function C(e) {
|
|
|
491
516
|
.send-btn:active { transform: scale(0.94); }
|
|
492
517
|
.send-btn:disabled { background: var(--gray-200); cursor: not-allowed; filter: none; }
|
|
493
518
|
.send-btn svg { width: 18px; height: 18px; fill: #fff; }
|
|
519
|
+
|
|
520
|
+
${g}
|
|
521
|
+
${E(a)}
|
|
522
|
+
${o ? T(o) : ""}
|
|
494
523
|
`;
|
|
495
524
|
}
|
|
496
525
|
//#endregion
|
|
497
526
|
//#region src/core/ui.ts
|
|
498
|
-
var
|
|
499
|
-
function
|
|
500
|
-
|
|
527
|
+
var O = "https://bot-q-frontend.vercel.app/", k = "<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>", A = "<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>", j = "<svg viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M12 2a2 2 0 012 2c0 .74-.4 1.38-1 1.72V7h3a3 3 0 013 3v8a3 3 0 01-3 3H8a3 3 0 01-3-3v-8a3 3 0 013-3h3V5.72A2 2 0 0110 4a2 2 0 012-2zm-2 9a1.5 1.5 0 100 3 1.5 1.5 0 000-3zm4 0a1.5 1.5 0 100 3 1.5 1.5 0 000-3z\"/>\n</svg>", M = "<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>", N = "<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>";
|
|
528
|
+
function P(e) {
|
|
529
|
+
if (!e || e.type === "icon") return j;
|
|
530
|
+
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%">${F(e.value)}</span>`;
|
|
531
|
+
if (e.type === "initials") {
|
|
532
|
+
let t = e.bgColor ?? "#F97316";
|
|
533
|
+
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">${F(e.value.slice(0, 2).toUpperCase())}</div>`;
|
|
534
|
+
}
|
|
535
|
+
return e.type === "image" ? `<img src="${F(e.value)}" style="width:100%;height:100%;object-fit:cover;border-radius:50%" alt="" />` : j;
|
|
501
536
|
}
|
|
502
|
-
function
|
|
537
|
+
function F(e) {
|
|
503
538
|
return e.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
504
539
|
}
|
|
505
|
-
function
|
|
506
|
-
let
|
|
507
|
-
|
|
508
|
-
|
|
540
|
+
function I(e) {
|
|
541
|
+
let t = F(e).replace(/\x00/g, ""), n = [];
|
|
542
|
+
return t = t.replace(/`([^`]+)`/g, (e, t) => (n.push(`<code>${t}</code>`), `\x00CODE${n.length - 1}\x00`)), t = t.replace(/\*\*\*(.+?)\*\*\*/g, "<strong><em>$1</em></strong>"), t = t.replace(/\*\*(.+?)\*\*/g, "<strong>$1</strong>"), t = t.replace(/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g, "<em>$1</em>"), t = t.replace(/\[([^\]]+)\]\((https?:\/\/[^)]+)\)/g, "<a href=\"$2\" target=\"_blank\" rel=\"noopener noreferrer\">$1</a>"), t = t.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1"), t = t.replace(/\n/g, "<br>"), t = t.replace(/\x00CODE(\d+)\x00/g, (e, t) => n[Number(t)]), t;
|
|
543
|
+
}
|
|
544
|
+
function L(e, t, n, r, i) {
|
|
545
|
+
let { name: a, design: o } = t, s, c, l, u, d, f, { content: p } = o;
|
|
546
|
+
function m(e) {
|
|
547
|
+
e.setAttribute("data-position", o.layout.position), s = e.attachShadow({ mode: "open" });
|
|
509
548
|
let t = document.createElement("style");
|
|
510
|
-
t.textContent =
|
|
511
|
-
<span class="icon-chat">${
|
|
512
|
-
<span class="icon-close">${
|
|
513
|
-
`,
|
|
549
|
+
t.textContent = D(o), s.appendChild(t), c = document.createElement("button"), c.className = "bubble", c.setAttribute("aria-label", n.ariaOpenChat), c.innerHTML = `
|
|
550
|
+
<span class="icon-chat">${k}</span>
|
|
551
|
+
<span class="icon-close">${A}</span>
|
|
552
|
+
`, 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 = `
|
|
514
553
|
<div class="chat-header">
|
|
515
|
-
<div class="avatar">${
|
|
554
|
+
<div class="avatar">${P(o.avatar)}</div>
|
|
516
555
|
<div class="header-text">
|
|
517
|
-
<span class="bot-name">${
|
|
518
|
-
<span class="bot-status"
|
|
556
|
+
<span class="bot-name">${F(a)}</span>
|
|
557
|
+
<span class="bot-status">${F(n.statusOnline)}</span>
|
|
519
558
|
</div>
|
|
520
|
-
<button class="close-btn" aria-label="
|
|
559
|
+
<button class="close-btn" aria-label="${F(n.ariaCloseChat)}">×</button>
|
|
521
560
|
</div>
|
|
522
561
|
<div class="messages" id="messages-container"></div>
|
|
523
562
|
<div class="chat-footer">
|
|
524
563
|
<div class="input-row">
|
|
525
564
|
<textarea
|
|
526
565
|
class="input"
|
|
527
|
-
placeholder="${
|
|
566
|
+
placeholder="${F(p.placeholder || n.inputPlaceholder)}"
|
|
528
567
|
rows="1"
|
|
529
568
|
maxlength="2000"
|
|
530
569
|
aria-label="Message input"
|
|
531
570
|
></textarea>
|
|
532
|
-
<button class="send-btn" aria-label="
|
|
533
|
-
${
|
|
571
|
+
<button class="send-btn" aria-label="${F(n.ariaSendMessage)}">
|
|
572
|
+
${M}
|
|
534
573
|
</button>
|
|
535
574
|
</div>
|
|
536
|
-
<a class="botiq-badge" href="${
|
|
537
|
-
|
|
575
|
+
<a class="botiq-badge" href="${O}" target="_blank" rel="noopener noreferrer">
|
|
576
|
+
${F(n.poweredBy)} <span class="botiq-badge-name">BotIQ</span>
|
|
538
577
|
</a>
|
|
539
578
|
</div>
|
|
540
|
-
`,
|
|
541
|
-
|
|
542
|
-
}),
|
|
543
|
-
e.key === "Enter" && !e.shiftKey && (e.preventDefault(),
|
|
544
|
-
}),
|
|
579
|
+
`, l.querySelector(".close-btn").addEventListener("click", i), u = l.querySelector("#messages-container"), d = l.querySelector(".input"), f = l.querySelector(".send-btn"), d.addEventListener("input", () => {
|
|
580
|
+
d.style.height = "auto", d.style.height = Math.min(d.scrollHeight, 100) + "px";
|
|
581
|
+
}), d.addEventListener("keydown", (e) => {
|
|
582
|
+
e.key === "Enter" && !e.shiftKey && (e.preventDefault(), h());
|
|
583
|
+
}), f.addEventListener("click", h), s.appendChild(l);
|
|
545
584
|
}
|
|
546
|
-
function
|
|
547
|
-
let e =
|
|
548
|
-
!e ||
|
|
585
|
+
function h() {
|
|
586
|
+
let e = d.value.trim();
|
|
587
|
+
!e || f.disabled || (d.value = "", d.style.height = "auto", r(e));
|
|
549
588
|
}
|
|
550
|
-
function
|
|
589
|
+
function g(e) {
|
|
551
590
|
if (e.messages.length === 0 && !e.isLoading) {
|
|
552
|
-
let e =
|
|
553
|
-
|
|
591
|
+
let e = p.suggestionChips.length > 0 ? `<div class="chips">${p.suggestionChips.map((e) => `<button class="chip">${F(e)}</button>`).join("")}</div>` : "";
|
|
592
|
+
u.innerHTML = `
|
|
554
593
|
<div class="empty-state">
|
|
555
|
-
${
|
|
556
|
-
<span class="greeting">${
|
|
594
|
+
${N}
|
|
595
|
+
<span class="greeting">${F(p.greeting || n.defaultGreeting)}</span>
|
|
557
596
|
${e}
|
|
558
597
|
</div>
|
|
559
|
-
`,
|
|
560
|
-
e.addEventListener("click", () =>
|
|
598
|
+
`, u.querySelectorAll(".chip").forEach((e) => {
|
|
599
|
+
e.addEventListener("click", () => r(e.textContent ?? ""));
|
|
561
600
|
});
|
|
562
601
|
return;
|
|
563
602
|
}
|
|
564
603
|
let t = e.messages.map((e) => `
|
|
565
604
|
<div class="message ${e.role}">
|
|
566
|
-
<div class="message-bubble">${
|
|
605
|
+
<div class="message-bubble">${e.role === "assistant" ? I(e.content) : F(e.content)}</div>
|
|
567
606
|
</div>
|
|
568
|
-
`).join(""),
|
|
569
|
-
|
|
607
|
+
`).join(""), i = e.isLoading ? "<div class=\"typing\"><span></span><span></span><span></span></div>" : "";
|
|
608
|
+
u.innerHTML = t + i, u.scrollTop = u.scrollHeight;
|
|
570
609
|
}
|
|
571
|
-
function
|
|
572
|
-
e.isOpen ? (
|
|
610
|
+
function _(e) {
|
|
611
|
+
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);
|
|
573
612
|
}
|
|
574
613
|
return {
|
|
575
|
-
mount:
|
|
576
|
-
update:
|
|
614
|
+
mount: m,
|
|
615
|
+
update: _
|
|
577
616
|
};
|
|
578
617
|
}
|
|
579
618
|
//#endregion
|
|
619
|
+
//#region src/i18n/vi.ts
|
|
620
|
+
var R = {
|
|
621
|
+
statusOnline: "Trực tuyến",
|
|
622
|
+
inputPlaceholder: "Nhắn tin...",
|
|
623
|
+
defaultGreeting: "Xin chào! Tôi có thể giúp gì cho bạn?",
|
|
624
|
+
errorMessage: "Xin lỗi, không thể kết nối. Vui lòng thử lại.",
|
|
625
|
+
errorAuth: "API key không hợp lệ.",
|
|
626
|
+
errorForbidden: "Widget không được phép trên trang này.",
|
|
627
|
+
errorQuota: "Bot đã đạt giới hạn tin nhắn tháng này.",
|
|
628
|
+
errorGeneric: "Đang gặp sự cố kỹ thuật, vui lòng liên hệ trực tiếp.",
|
|
629
|
+
typingIndicator: "Đang soạn tin...",
|
|
630
|
+
quotaExceeded: "Bot đã hết lượt chat tháng này.",
|
|
631
|
+
trialExpired: "Dịch vụ tạm dừng. Vui lòng liên hệ hỗ trợ.",
|
|
632
|
+
poweredBy: "Powered by",
|
|
633
|
+
ariaOpenChat: "Mở khung chat",
|
|
634
|
+
ariaCloseChat: "Đóng khung chat",
|
|
635
|
+
ariaSendMessage: "Gửi tin nhắn"
|
|
636
|
+
}, z = {
|
|
637
|
+
statusOnline: "Online",
|
|
638
|
+
inputPlaceholder: "Type a message...",
|
|
639
|
+
defaultGreeting: "Hello! How can I help you?",
|
|
640
|
+
errorMessage: "Sorry, something went wrong. Please try again.",
|
|
641
|
+
errorAuth: "Invalid API key.",
|
|
642
|
+
errorForbidden: "Widget is not allowed on this page.",
|
|
643
|
+
errorQuota: "This bot has reached its monthly message limit.",
|
|
644
|
+
errorGeneric: "Technical issue, please contact us directly.",
|
|
645
|
+
typingIndicator: "Typing...",
|
|
646
|
+
quotaExceeded: "This bot has reached its monthly chat limit.",
|
|
647
|
+
trialExpired: "Service paused. Please contact support.",
|
|
648
|
+
poweredBy: "Powered by",
|
|
649
|
+
ariaOpenChat: "Open chat",
|
|
650
|
+
ariaCloseChat: "Close chat",
|
|
651
|
+
ariaSendMessage: "Send message"
|
|
652
|
+
};
|
|
653
|
+
//#endregion
|
|
654
|
+
//#region src/i18n/index.ts
|
|
655
|
+
function B(e) {
|
|
656
|
+
return e === "en" ? z : R;
|
|
657
|
+
}
|
|
658
|
+
//#endregion
|
|
580
659
|
//#region src/builds/npm/index.ts
|
|
581
|
-
function
|
|
660
|
+
function V(e) {
|
|
582
661
|
if (!e.apiKey) return console.warn("[BotIQ] apiKey is required"), () => void 0;
|
|
583
|
-
let t =
|
|
584
|
-
|
|
662
|
+
let t = u(e), n = m();
|
|
663
|
+
x({ messages: h(n) });
|
|
585
664
|
let r = document.createElement("div");
|
|
586
665
|
document.body.appendChild(r);
|
|
587
|
-
let i = () => void 0, a = !1;
|
|
588
|
-
|
|
666
|
+
let i = () => void 0, a = !1, o = B(void 0);
|
|
667
|
+
l(t.apiKey, t.apiUrl).then((e) => {
|
|
589
668
|
if (a) return;
|
|
590
|
-
|
|
591
|
-
n
|
|
669
|
+
o = B(e.widgetLanguage);
|
|
670
|
+
let n = L(t, e, o, s, c);
|
|
671
|
+
n.mount(r), i = S((e) => n.update(e)), n.update(b());
|
|
592
672
|
});
|
|
593
|
-
function
|
|
594
|
-
let r =
|
|
673
|
+
function s(e) {
|
|
674
|
+
let r = b();
|
|
595
675
|
if (r.isLoading) return;
|
|
596
676
|
let i = {
|
|
597
677
|
role: "user",
|
|
598
678
|
content: e
|
|
599
679
|
};
|
|
600
|
-
|
|
680
|
+
x({
|
|
601
681
|
messages: [...r.messages, i],
|
|
602
682
|
isLoading: !0
|
|
603
|
-
}),
|
|
683
|
+
}), _(t.apiUrl, t.apiKey, n, e, r.messages, o).then((e) => {
|
|
604
684
|
let t = {
|
|
605
685
|
role: "assistant",
|
|
606
686
|
content: e
|
|
607
687
|
};
|
|
608
|
-
|
|
609
|
-
messages: [...
|
|
688
|
+
x({
|
|
689
|
+
messages: [...b().messages, t],
|
|
610
690
|
isLoading: !1
|
|
611
|
-
}),
|
|
691
|
+
}), g(n, [i, t]);
|
|
612
692
|
}).catch(() => {
|
|
613
|
-
|
|
693
|
+
x({ isLoading: !1 });
|
|
614
694
|
});
|
|
615
695
|
}
|
|
616
|
-
function
|
|
617
|
-
|
|
696
|
+
function c() {
|
|
697
|
+
x({ isOpen: !b().isOpen });
|
|
618
698
|
}
|
|
619
699
|
return () => {
|
|
620
700
|
a = !0, i(), r.remove();
|
|
621
701
|
};
|
|
622
702
|
}
|
|
623
703
|
//#endregion
|
|
624
|
-
export {
|
|
704
|
+
export { V as t };
|
package/dist/sdk/react.js
CHANGED
package/dist/sdk/vue.js
CHANGED