@locdo.tech/botiq-chat-sdk 0.2.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-Bo1fPZM3.js → npm-D7UnWA_n.js} +223 -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 };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
//#region src/core/config.ts
|
|
2
|
-
var e = "
|
|
2
|
+
var e = "https://bot-q-backend.vercel.app", t = {
|
|
3
3
|
name: "BotIQ",
|
|
4
4
|
design: {
|
|
5
5
|
colors: {
|
|
@@ -17,18 +17,33 @@ var e = "http://localhost:3001", 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",
|
|
29
|
-
"poppins"
|
|
30
|
+
"poppins",
|
|
31
|
+
"nunito",
|
|
32
|
+
"dm-sans",
|
|
33
|
+
"raleway",
|
|
34
|
+
"lato",
|
|
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"
|
|
30
45
|
]);
|
|
31
|
-
function
|
|
46
|
+
function c(e) {
|
|
32
47
|
let t = e.colors;
|
|
33
48
|
if (![
|
|
34
49
|
t.primary,
|
|
@@ -38,10 +53,15 @@ function o(e) {
|
|
|
38
53
|
t.background,
|
|
39
54
|
t.text
|
|
40
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;
|
|
41
|
-
let { width:
|
|
42
|
-
|
|
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));
|
|
43
63
|
}
|
|
44
|
-
async function
|
|
64
|
+
async function l(e, n) {
|
|
45
65
|
try {
|
|
46
66
|
let r = await fetch(`${n}/widget/meta`, {
|
|
47
67
|
headers: { "X-Api-Key": e },
|
|
@@ -49,15 +69,18 @@ async function s(e, n) {
|
|
|
49
69
|
});
|
|
50
70
|
if (!r.ok) return t;
|
|
51
71
|
let i = await r.json();
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
|
55
78
|
};
|
|
56
79
|
} catch {
|
|
57
80
|
return t;
|
|
58
81
|
}
|
|
59
82
|
}
|
|
60
|
-
function
|
|
83
|
+
function u(t) {
|
|
61
84
|
return {
|
|
62
85
|
apiKey: t.apiKey,
|
|
63
86
|
apiUrl: e
|
|
@@ -65,39 +88,34 @@ function c(t) {
|
|
|
65
88
|
}
|
|
66
89
|
//#endregion
|
|
67
90
|
//#region src/core/session.ts
|
|
68
|
-
var
|
|
69
|
-
function
|
|
91
|
+
var d = "botiq:sessionId", f = "botiq:history:", p = 10;
|
|
92
|
+
function m() {
|
|
70
93
|
try {
|
|
71
|
-
let e = localStorage.getItem(
|
|
72
|
-
return e || (e = crypto.randomUUID(), localStorage.setItem(
|
|
94
|
+
let e = localStorage.getItem(d);
|
|
95
|
+
return e || (e = crypto.randomUUID(), localStorage.setItem(d, e)), e;
|
|
73
96
|
} catch {
|
|
74
97
|
return crypto.randomUUID();
|
|
75
98
|
}
|
|
76
99
|
}
|
|
77
|
-
function
|
|
100
|
+
function h(e) {
|
|
78
101
|
try {
|
|
79
|
-
let t = localStorage.getItem(
|
|
102
|
+
let t = localStorage.getItem(f + e);
|
|
80
103
|
return t ? JSON.parse(t) : [];
|
|
81
104
|
} catch {
|
|
82
105
|
return [];
|
|
83
106
|
}
|
|
84
107
|
}
|
|
85
|
-
function
|
|
108
|
+
function g(e, t) {
|
|
86
109
|
try {
|
|
87
|
-
let n = [...
|
|
88
|
-
localStorage.setItem(
|
|
110
|
+
let n = [...h(e), ...t].slice(-p);
|
|
111
|
+
localStorage.setItem(f + e, JSON.stringify(n));
|
|
89
112
|
} catch {}
|
|
90
113
|
}
|
|
91
114
|
//#endregion
|
|
92
115
|
//#region src/core/api.ts
|
|
93
|
-
|
|
94
|
-
401: "API key không hợp lệ.",
|
|
95
|
-
403: "Widget không được phép trên trang này.",
|
|
96
|
-
429: "Bot đã đạt giới hạn tin nhắn tháng này."
|
|
97
|
-
};
|
|
98
|
-
async function g(e, t, n, r, i) {
|
|
116
|
+
async function _(e, t, n, r, i, a) {
|
|
99
117
|
try {
|
|
100
|
-
let
|
|
118
|
+
let o = await fetch(`${e}/widget/chat`, {
|
|
101
119
|
method: "POST",
|
|
102
120
|
headers: {
|
|
103
121
|
"Content-Type": "application/json",
|
|
@@ -109,35 +127,35 @@ async function g(e, t, n, r, i) {
|
|
|
109
127
|
history: i
|
|
110
128
|
})
|
|
111
129
|
});
|
|
112
|
-
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;
|
|
113
131
|
} catch {
|
|
114
|
-
return
|
|
132
|
+
return a.errorMessage;
|
|
115
133
|
}
|
|
116
134
|
}
|
|
117
135
|
//#endregion
|
|
118
136
|
//#region src/core/state.ts
|
|
119
|
-
var
|
|
137
|
+
var v = {
|
|
120
138
|
messages: [],
|
|
121
139
|
isLoading: !1,
|
|
122
140
|
isOpen: !1
|
|
123
|
-
},
|
|
124
|
-
function
|
|
125
|
-
return
|
|
141
|
+
}, y = /* @__PURE__ */ new Set();
|
|
142
|
+
function b() {
|
|
143
|
+
return v;
|
|
126
144
|
}
|
|
127
|
-
function
|
|
128
|
-
Object.assign(
|
|
145
|
+
function x(e) {
|
|
146
|
+
Object.assign(v, e);
|
|
129
147
|
let t = {
|
|
130
|
-
...
|
|
131
|
-
messages: [...
|
|
148
|
+
...v,
|
|
149
|
+
messages: [...v.messages]
|
|
132
150
|
};
|
|
133
|
-
|
|
151
|
+
y.forEach((e) => e(t));
|
|
134
152
|
}
|
|
135
|
-
function
|
|
136
|
-
return
|
|
153
|
+
function S(e) {
|
|
154
|
+
return y.add(e), () => y.delete(e);
|
|
137
155
|
}
|
|
138
156
|
//#endregion
|
|
139
157
|
//#region src/core/styles.ts
|
|
140
|
-
var
|
|
158
|
+
var C = {
|
|
141
159
|
inter: {
|
|
142
160
|
url: "https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap",
|
|
143
161
|
family: "'Inter', system-ui, -apple-system, sans-serif"
|
|
@@ -149,20 +167,52 @@ var S = {
|
|
|
149
167
|
poppins: {
|
|
150
168
|
url: "https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600&display=swap",
|
|
151
169
|
family: "'Poppins', system-ui, -apple-system, sans-serif"
|
|
170
|
+
},
|
|
171
|
+
nunito: {
|
|
172
|
+
url: "https://fonts.googleapis.com/css2?family=Nunito:wght@400;500;600&display=swap",
|
|
173
|
+
family: "'Nunito', system-ui, -apple-system, sans-serif"
|
|
174
|
+
},
|
|
175
|
+
"dm-sans": {
|
|
176
|
+
url: "https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600&display=swap",
|
|
177
|
+
family: "'DM Sans', system-ui, -apple-system, sans-serif"
|
|
178
|
+
},
|
|
179
|
+
raleway: {
|
|
180
|
+
url: "https://fonts.googleapis.com/css2?family=Raleway:wght@400;500;600&display=swap",
|
|
181
|
+
family: "'Raleway', system-ui, -apple-system, sans-serif"
|
|
182
|
+
},
|
|
183
|
+
lato: {
|
|
184
|
+
url: "https://fonts.googleapis.com/css2?family=Lato:wght@400;700&display=swap",
|
|
185
|
+
family: "'Lato', system-ui, -apple-system, sans-serif"
|
|
186
|
+
},
|
|
187
|
+
playfair: {
|
|
188
|
+
url: "https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;500;600&display=swap",
|
|
189
|
+
family: "'Playfair Display', Georgia, serif"
|
|
152
190
|
}
|
|
153
191
|
};
|
|
154
|
-
function
|
|
155
|
-
|
|
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; }" : "";
|
|
156
206
|
return `
|
|
157
|
-
@import url('${
|
|
207
|
+
@import url('${c.url}');
|
|
158
208
|
|
|
159
209
|
:host {
|
|
160
210
|
position: fixed;
|
|
161
211
|
bottom: 24px;
|
|
162
|
-
${
|
|
212
|
+
${u}
|
|
163
213
|
z-index: 2147483647;
|
|
164
214
|
display: block;
|
|
165
|
-
font-family: ${
|
|
215
|
+
font-family: ${c.family};
|
|
166
216
|
--color-primary: ${t.primary};
|
|
167
217
|
--color-header: ${t.header};
|
|
168
218
|
--color-user: ${t.userBubble};
|
|
@@ -176,7 +226,7 @@ function C(e) {
|
|
|
176
226
|
--shadow-sm: 0 2px 8px rgba(0,0,0,.4);
|
|
177
227
|
--shadow-md: 0 8px 32px rgba(0,0,0,.5);
|
|
178
228
|
--shadow-lg: 0 16px 48px rgba(0,0,0,.6);
|
|
179
|
-
--radius-bubble: ${
|
|
229
|
+
--radius-bubble: ${l};
|
|
180
230
|
--radius-msg: 18px;
|
|
181
231
|
--chat-w: ${n.width}px;
|
|
182
232
|
--chat-h: ${n.height}px;
|
|
@@ -189,7 +239,7 @@ function C(e) {
|
|
|
189
239
|
width: 56px;
|
|
190
240
|
height: 56px;
|
|
191
241
|
border-radius: var(--radius-bubble);
|
|
192
|
-
background:
|
|
242
|
+
background: ${p};
|
|
193
243
|
border: none;
|
|
194
244
|
cursor: pointer;
|
|
195
245
|
display: flex;
|
|
@@ -213,7 +263,7 @@ function C(e) {
|
|
|
213
263
|
.chat-window {
|
|
214
264
|
position: absolute;
|
|
215
265
|
bottom: 72px;
|
|
216
|
-
${
|
|
266
|
+
${f}
|
|
217
267
|
width: var(--chat-w);
|
|
218
268
|
height: var(--chat-h);
|
|
219
269
|
background: var(--color-bg);
|
|
@@ -222,7 +272,7 @@ function C(e) {
|
|
|
222
272
|
display: flex;
|
|
223
273
|
flex-direction: column;
|
|
224
274
|
overflow: hidden;
|
|
225
|
-
transform-origin: ${
|
|
275
|
+
transform-origin: ${d};
|
|
226
276
|
transform: scale(.94) translateY(8px);
|
|
227
277
|
opacity: 0;
|
|
228
278
|
pointer-events: none;
|
|
@@ -233,7 +283,7 @@ function C(e) {
|
|
|
233
283
|
|
|
234
284
|
/* ── Header ─────────────────────────────── */
|
|
235
285
|
.chat-header {
|
|
236
|
-
background:
|
|
286
|
+
background: ${m};
|
|
237
287
|
padding: 16px 16px 14px;
|
|
238
288
|
display: flex;
|
|
239
289
|
align-items: center;
|
|
@@ -250,6 +300,7 @@ function C(e) {
|
|
|
250
300
|
align-items: center;
|
|
251
301
|
justify-content: center;
|
|
252
302
|
flex-shrink: 0;
|
|
303
|
+
overflow: hidden;
|
|
253
304
|
}
|
|
254
305
|
|
|
255
306
|
.avatar svg { width: 20px; height: 20px; fill: #fff; }
|
|
@@ -315,7 +366,7 @@ function C(e) {
|
|
|
315
366
|
}
|
|
316
367
|
|
|
317
368
|
.message.user .message-bubble {
|
|
318
|
-
background:
|
|
369
|
+
background: ${h};
|
|
319
370
|
color: #fff;
|
|
320
371
|
border-bottom-right-radius: 4px;
|
|
321
372
|
}
|
|
@@ -451,7 +502,7 @@ function C(e) {
|
|
|
451
502
|
width: 38px;
|
|
452
503
|
height: 38px;
|
|
453
504
|
border-radius: 10px;
|
|
454
|
-
background:
|
|
505
|
+
background: ${p};
|
|
455
506
|
border: none;
|
|
456
507
|
cursor: pointer;
|
|
457
508
|
display: flex;
|
|
@@ -465,131 +516,189 @@ function C(e) {
|
|
|
465
516
|
.send-btn:active { transform: scale(0.94); }
|
|
466
517
|
.send-btn:disabled { background: var(--gray-200); cursor: not-allowed; filter: none; }
|
|
467
518
|
.send-btn svg { width: 18px; height: 18px; fill: #fff; }
|
|
519
|
+
|
|
520
|
+
${g}
|
|
521
|
+
${E(a)}
|
|
522
|
+
${o ? T(o) : ""}
|
|
468
523
|
`;
|
|
469
524
|
}
|
|
470
525
|
//#endregion
|
|
471
526
|
//#region src/core/ui.ts
|
|
472
|
-
var
|
|
473
|
-
function
|
|
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;
|
|
536
|
+
}
|
|
537
|
+
function F(e) {
|
|
474
538
|
return e.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
475
539
|
}
|
|
476
|
-
function
|
|
477
|
-
let
|
|
478
|
-
|
|
479
|
-
|
|
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" });
|
|
480
548
|
let t = document.createElement("style");
|
|
481
|
-
t.textContent =
|
|
482
|
-
<span class="icon-chat">${
|
|
483
|
-
<span class="icon-close">${
|
|
484
|
-
`,
|
|
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 = `
|
|
485
553
|
<div class="chat-header">
|
|
486
|
-
<div class="avatar">${
|
|
554
|
+
<div class="avatar">${P(o.avatar)}</div>
|
|
487
555
|
<div class="header-text">
|
|
488
|
-
<span class="bot-name">${
|
|
489
|
-
<span class="bot-status"
|
|
556
|
+
<span class="bot-name">${F(a)}</span>
|
|
557
|
+
<span class="bot-status">${F(n.statusOnline)}</span>
|
|
490
558
|
</div>
|
|
491
|
-
<button class="close-btn" aria-label="
|
|
559
|
+
<button class="close-btn" aria-label="${F(n.ariaCloseChat)}">×</button>
|
|
492
560
|
</div>
|
|
493
561
|
<div class="messages" id="messages-container"></div>
|
|
494
562
|
<div class="chat-footer">
|
|
495
563
|
<div class="input-row">
|
|
496
564
|
<textarea
|
|
497
565
|
class="input"
|
|
498
|
-
placeholder="${
|
|
566
|
+
placeholder="${F(p.placeholder || n.inputPlaceholder)}"
|
|
499
567
|
rows="1"
|
|
500
568
|
maxlength="2000"
|
|
501
569
|
aria-label="Message input"
|
|
502
570
|
></textarea>
|
|
503
|
-
<button class="send-btn" aria-label="
|
|
504
|
-
${
|
|
571
|
+
<button class="send-btn" aria-label="${F(n.ariaSendMessage)}">
|
|
572
|
+
${M}
|
|
505
573
|
</button>
|
|
506
574
|
</div>
|
|
507
|
-
<a class="botiq-badge" href="${
|
|
508
|
-
|
|
575
|
+
<a class="botiq-badge" href="${O}" target="_blank" rel="noopener noreferrer">
|
|
576
|
+
${F(n.poweredBy)} <span class="botiq-badge-name">BotIQ</span>
|
|
509
577
|
</a>
|
|
510
578
|
</div>
|
|
511
|
-
`,
|
|
512
|
-
|
|
513
|
-
}),
|
|
514
|
-
e.key === "Enter" && !e.shiftKey && (e.preventDefault(),
|
|
515
|
-
}),
|
|
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);
|
|
516
584
|
}
|
|
517
|
-
function
|
|
518
|
-
let e =
|
|
519
|
-
!e ||
|
|
585
|
+
function h() {
|
|
586
|
+
let e = d.value.trim();
|
|
587
|
+
!e || f.disabled || (d.value = "", d.style.height = "auto", r(e));
|
|
520
588
|
}
|
|
521
|
-
function
|
|
589
|
+
function g(e) {
|
|
522
590
|
if (e.messages.length === 0 && !e.isLoading) {
|
|
523
|
-
let e =
|
|
524
|
-
|
|
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 = `
|
|
525
593
|
<div class="empty-state">
|
|
526
|
-
${
|
|
527
|
-
<span class="greeting">${
|
|
594
|
+
${N}
|
|
595
|
+
<span class="greeting">${F(p.greeting || n.defaultGreeting)}</span>
|
|
528
596
|
${e}
|
|
529
597
|
</div>
|
|
530
|
-
`,
|
|
531
|
-
e.addEventListener("click", () =>
|
|
598
|
+
`, u.querySelectorAll(".chip").forEach((e) => {
|
|
599
|
+
e.addEventListener("click", () => r(e.textContent ?? ""));
|
|
532
600
|
});
|
|
533
601
|
return;
|
|
534
602
|
}
|
|
535
603
|
let t = e.messages.map((e) => `
|
|
536
604
|
<div class="message ${e.role}">
|
|
537
|
-
<div class="message-bubble">${
|
|
605
|
+
<div class="message-bubble">${e.role === "assistant" ? I(e.content) : F(e.content)}</div>
|
|
538
606
|
</div>
|
|
539
|
-
`).join(""),
|
|
540
|
-
|
|
607
|
+
`).join(""), i = e.isLoading ? "<div class=\"typing\"><span></span><span></span><span></span></div>" : "";
|
|
608
|
+
u.innerHTML = t + i, u.scrollTop = u.scrollHeight;
|
|
541
609
|
}
|
|
542
|
-
function
|
|
543
|
-
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);
|
|
544
612
|
}
|
|
545
613
|
return {
|
|
546
|
-
mount:
|
|
547
|
-
update:
|
|
614
|
+
mount: m,
|
|
615
|
+
update: _
|
|
548
616
|
};
|
|
549
617
|
}
|
|
550
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
|
|
551
659
|
//#region src/builds/npm/index.ts
|
|
552
|
-
function
|
|
660
|
+
function V(e) {
|
|
553
661
|
if (!e.apiKey) return console.warn("[BotIQ] apiKey is required"), () => void 0;
|
|
554
|
-
let t =
|
|
555
|
-
|
|
662
|
+
let t = u(e), n = m();
|
|
663
|
+
x({ messages: h(n) });
|
|
556
664
|
let r = document.createElement("div");
|
|
557
665
|
document.body.appendChild(r);
|
|
558
|
-
let i = () => void 0, a = !1;
|
|
559
|
-
|
|
666
|
+
let i = () => void 0, a = !1, o = B(void 0);
|
|
667
|
+
l(t.apiKey, t.apiUrl).then((e) => {
|
|
560
668
|
if (a) return;
|
|
561
|
-
|
|
562
|
-
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());
|
|
563
672
|
});
|
|
564
|
-
function
|
|
565
|
-
let r =
|
|
673
|
+
function s(e) {
|
|
674
|
+
let r = b();
|
|
566
675
|
if (r.isLoading) return;
|
|
567
676
|
let i = {
|
|
568
677
|
role: "user",
|
|
569
678
|
content: e
|
|
570
679
|
};
|
|
571
|
-
|
|
680
|
+
x({
|
|
572
681
|
messages: [...r.messages, i],
|
|
573
682
|
isLoading: !0
|
|
574
|
-
}),
|
|
683
|
+
}), _(t.apiUrl, t.apiKey, n, e, r.messages, o).then((e) => {
|
|
575
684
|
let t = {
|
|
576
685
|
role: "assistant",
|
|
577
686
|
content: e
|
|
578
687
|
};
|
|
579
|
-
|
|
580
|
-
messages: [...
|
|
688
|
+
x({
|
|
689
|
+
messages: [...b().messages, t],
|
|
581
690
|
isLoading: !1
|
|
582
|
-
}),
|
|
691
|
+
}), g(n, [i, t]);
|
|
583
692
|
}).catch(() => {
|
|
584
|
-
|
|
693
|
+
x({ isLoading: !1 });
|
|
585
694
|
});
|
|
586
695
|
}
|
|
587
|
-
function
|
|
588
|
-
|
|
696
|
+
function c() {
|
|
697
|
+
x({ isOpen: !b().isOpen });
|
|
589
698
|
}
|
|
590
699
|
return () => {
|
|
591
700
|
a = !0, i(), r.remove();
|
|
592
701
|
};
|
|
593
702
|
}
|
|
594
703
|
//#endregion
|
|
595
|
-
export {
|
|
704
|
+
export { V as t };
|
package/dist/sdk/react.js
CHANGED
package/dist/sdk/vue.js
CHANGED