chatbotlite 0.4.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -2
- package/dist/client/index.cjs +39 -6
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.d.cts +5 -0
- package/dist/client/index.d.ts +5 -0
- package/dist/client/index.js +39 -6
- package/dist/client/index.js.map +1 -1
- package/dist/core/index.cjs +56 -54
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +5 -1
- package/dist/core/index.d.ts +5 -1
- package/dist/core/index.js +56 -54
- package/dist/core/index.js.map +1 -1
- package/dist/embed.global.js +101 -0
- package/dist/embed.global.js.map +1 -0
- package/dist/index.cjs +69 -57
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +69 -57
- package/dist/index.js.map +1 -1
- package/dist/react/index.cjs +293 -214
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.js +293 -214
- package/dist/react/index.js.map +1 -1
- package/package.json +3 -2
package/dist/react/index.js
CHANGED
|
@@ -3,8 +3,60 @@ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
|
3
3
|
|
|
4
4
|
// src/react/ChatWidget.tsx
|
|
5
5
|
|
|
6
|
+
// src/core/tools.ts
|
|
7
|
+
var MARKER_RE = /\[SKILL:(\w+)((?:\s+\w+=(?:"[^"]*"|[\w./@*+,:-]+))*)\s*\]/g;
|
|
8
|
+
var ARG_RE = /(\w+)=("([^"]*)"|([\w./@*+,:-]+))/g;
|
|
9
|
+
function coerce(value) {
|
|
10
|
+
if (value === "true") return true;
|
|
11
|
+
if (value === "false") return false;
|
|
12
|
+
if (/^-?\d+(?:\.\d+)?$/.test(value)) return Number(value);
|
|
13
|
+
return value;
|
|
14
|
+
}
|
|
15
|
+
function parseToolMarkers(text) {
|
|
16
|
+
const markers = [];
|
|
17
|
+
let m;
|
|
18
|
+
MARKER_RE.lastIndex = 0;
|
|
19
|
+
while ((m = MARKER_RE.exec(text)) !== null) {
|
|
20
|
+
const name = m[1];
|
|
21
|
+
const argsRaw = m[2] ?? "";
|
|
22
|
+
const args = {};
|
|
23
|
+
let a;
|
|
24
|
+
ARG_RE.lastIndex = 0;
|
|
25
|
+
while ((a = ARG_RE.exec(argsRaw)) !== null) {
|
|
26
|
+
const key = a[1];
|
|
27
|
+
const value = a[3] ?? a[4] ?? "";
|
|
28
|
+
args[key] = coerce(value);
|
|
29
|
+
}
|
|
30
|
+
markers.push({ name, args, raw: m[0] });
|
|
31
|
+
}
|
|
32
|
+
return markers;
|
|
33
|
+
}
|
|
34
|
+
function stripToolMarkers(text) {
|
|
35
|
+
return text.replace(MARKER_RE, "").replace(/\s+\n/g, "\n").trim();
|
|
36
|
+
}
|
|
37
|
+
function buildToolsPromptAddendum(enabledTools) {
|
|
38
|
+
if (enabledTools.length === 0) return "";
|
|
39
|
+
const examples = {
|
|
40
|
+
uploadForReview: '[SKILL:uploadForReview purpose="T4 slip" accept="image/*,application/pdf" maxMb=10] \u2014 collect a document for human review (bytes go to webhook, you never see content)',
|
|
41
|
+
scheduleCallback: '[SKILL:scheduleCallback durationMin=15 timezone="America/Vancouver"] \u2014 let the user pick a callback time slot',
|
|
42
|
+
requestPayment: '[SKILL:requestPayment amount=4250 currency="cad" reason="initial deposit"] \u2014 collect payment via inline card'
|
|
43
|
+
};
|
|
44
|
+
const lines = enabledTools.filter((t) => examples[t]).map((t) => `- ${examples[t]}`);
|
|
45
|
+
if (lines.length === 0) return "";
|
|
46
|
+
return [
|
|
47
|
+
"",
|
|
48
|
+
"## Available tools",
|
|
49
|
+
"When you need one of these workflows, emit the marker INLINE in your reply.",
|
|
50
|
+
"Write a short message first, THEN the marker. The marker will be replaced by an interactive card.",
|
|
51
|
+
"Pause the conversation after emitting \u2014 wait for the tool result before continuing.",
|
|
52
|
+
"",
|
|
53
|
+
...lines
|
|
54
|
+
].join("\n");
|
|
55
|
+
}
|
|
56
|
+
|
|
6
57
|
// src/core/prompts.ts
|
|
7
|
-
function buildSystemPrompt(knowledge) {
|
|
58
|
+
function buildSystemPrompt(knowledge, enabledTools = []) {
|
|
59
|
+
const toolsAddendum = buildToolsPromptAddendum(enabledTools);
|
|
8
60
|
return [
|
|
9
61
|
"You are an AI assistant on a business website. Use ONLY the knowledge below to answer.",
|
|
10
62
|
"",
|
|
@@ -17,8 +69,9 @@ function buildSystemPrompt(knowledge) {
|
|
|
17
69
|
"- For anything not covered in the knowledge above, say the owner will follow up \u2014 do NOT guess.",
|
|
18
70
|
'- If the caller is clearly a vendor/sales pitch, say: "This does not look like a customer service request, so we will not continue this thread."',
|
|
19
71
|
`- If wrong number or asked to stop, say: "Sorry about that. We won't text again."`,
|
|
20
|
-
"- Match the caller's language automatically."
|
|
21
|
-
|
|
72
|
+
"- Match the caller's language automatically.",
|
|
73
|
+
toolsAddendum
|
|
74
|
+
].filter(Boolean).join("\n");
|
|
22
75
|
}
|
|
23
76
|
|
|
24
77
|
// src/core/guards.ts
|
|
@@ -141,10 +194,12 @@ var ChatBot = class {
|
|
|
141
194
|
timeoutMs;
|
|
142
195
|
cachedSystemPrompt;
|
|
143
196
|
guards;
|
|
197
|
+
knowledge;
|
|
144
198
|
constructor(init) {
|
|
145
199
|
if (!init.knowledge || typeof init.knowledge !== "string" || init.knowledge.trim().length === 0) {
|
|
146
200
|
throw new Error("chatbotlite: knowledge is required (a non-empty markdown string).");
|
|
147
201
|
}
|
|
202
|
+
this.knowledge = init.knowledge;
|
|
148
203
|
this.keys = init.providers.keys ?? {};
|
|
149
204
|
this.steps = resolveChain(init.providers);
|
|
150
205
|
this.fetcher = init.options?.fetch ?? globalThis.fetch.bind(globalThis);
|
|
@@ -152,6 +207,14 @@ var ChatBot = class {
|
|
|
152
207
|
this.cachedSystemPrompt = buildSystemPrompt(init.knowledge);
|
|
153
208
|
this.guards = init.guards ?? {};
|
|
154
209
|
}
|
|
210
|
+
/** Build system prompt for given opts — uses cached if no enabledTools, else rebuilds. */
|
|
211
|
+
resolveSystemPrompt(opts) {
|
|
212
|
+
if (opts.systemPrompt) return opts.systemPrompt;
|
|
213
|
+
if (opts.enabledTools && opts.enabledTools.length > 0) {
|
|
214
|
+
return buildSystemPrompt(this.knowledge, opts.enabledTools);
|
|
215
|
+
}
|
|
216
|
+
return this.cachedSystemPrompt;
|
|
217
|
+
}
|
|
155
218
|
/** Run an LLM judge against content. Fail-open on errors. */
|
|
156
219
|
async judge(config, content) {
|
|
157
220
|
const endpoint = PROVIDER_ENDPOINTS[config.provider];
|
|
@@ -188,7 +251,7 @@ var ChatBot = class {
|
|
|
188
251
|
* event: error data: {"message":"...","attempts":[...]}
|
|
189
252
|
*/
|
|
190
253
|
async replyStream(message, opts = {}) {
|
|
191
|
-
const systemPrompt =
|
|
254
|
+
const systemPrompt = this.resolveSystemPrompt(opts);
|
|
192
255
|
const messages = [
|
|
193
256
|
{ role: "system", content: systemPrompt },
|
|
194
257
|
...opts.history ?? [],
|
|
@@ -301,7 +364,7 @@ data: ${data}
|
|
|
301
364
|
return this.reply(message, opts);
|
|
302
365
|
}
|
|
303
366
|
const dataUrls = await Promise.all(images.map(fileToDataUrl));
|
|
304
|
-
const systemPrompt =
|
|
367
|
+
const systemPrompt = this.resolveSystemPrompt(opts);
|
|
305
368
|
const userContent = [];
|
|
306
369
|
if (message) userContent.push({ type: "text", text: message });
|
|
307
370
|
for (const url of dataUrls) userContent.push({ type: "image_url", image_url: { url } });
|
|
@@ -381,7 +444,7 @@ data: ${data}
|
|
|
381
444
|
};
|
|
382
445
|
}
|
|
383
446
|
}
|
|
384
|
-
const systemPrompt =
|
|
447
|
+
const systemPrompt = this.resolveSystemPrompt(opts);
|
|
385
448
|
const messages = [
|
|
386
449
|
{ role: "system", content: systemPrompt },
|
|
387
450
|
...opts.history ?? [],
|
|
@@ -494,38 +557,6 @@ function normalizeChainEntry(entry, keys) {
|
|
|
494
557
|
}
|
|
495
558
|
return { provider, model, label: `${provider}/${model}` };
|
|
496
559
|
}
|
|
497
|
-
|
|
498
|
-
// src/core/tools.ts
|
|
499
|
-
var MARKER_RE = /\[SKILL:(\w+)((?:\s+\w+=(?:"[^"]*"|[\w./@*+,:-]+))*)\s*\]/g;
|
|
500
|
-
var ARG_RE = /(\w+)=("([^"]*)"|([\w./@*+,:-]+))/g;
|
|
501
|
-
function coerce(value) {
|
|
502
|
-
if (value === "true") return true;
|
|
503
|
-
if (value === "false") return false;
|
|
504
|
-
if (/^-?\d+(?:\.\d+)?$/.test(value)) return Number(value);
|
|
505
|
-
return value;
|
|
506
|
-
}
|
|
507
|
-
function parseToolMarkers(text) {
|
|
508
|
-
const markers = [];
|
|
509
|
-
let m;
|
|
510
|
-
MARKER_RE.lastIndex = 0;
|
|
511
|
-
while ((m = MARKER_RE.exec(text)) !== null) {
|
|
512
|
-
const name = m[1];
|
|
513
|
-
const argsRaw = m[2] ?? "";
|
|
514
|
-
const args = {};
|
|
515
|
-
let a;
|
|
516
|
-
ARG_RE.lastIndex = 0;
|
|
517
|
-
while ((a = ARG_RE.exec(argsRaw)) !== null) {
|
|
518
|
-
const key = a[1];
|
|
519
|
-
const value = a[3] ?? a[4] ?? "";
|
|
520
|
-
args[key] = coerce(value);
|
|
521
|
-
}
|
|
522
|
-
markers.push({ name, args, raw: m[0] });
|
|
523
|
-
}
|
|
524
|
-
return markers;
|
|
525
|
-
}
|
|
526
|
-
function stripToolMarkers(text) {
|
|
527
|
-
return text.replace(MARKER_RE, "").replace(/\s+\n/g, "\n").trim();
|
|
528
|
-
}
|
|
529
560
|
var CLOUD_ICON = "M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12";
|
|
530
561
|
function UploadForReview(props) {
|
|
531
562
|
const {
|
|
@@ -982,12 +1013,15 @@ var BOLT = "\u26A1";
|
|
|
982
1013
|
var DEFAULT_PRIMARY = "#0f172a";
|
|
983
1014
|
var DEFAULT_ON_PRIMARY = "#ffffff";
|
|
984
1015
|
var SURFACE = "#ffffff";
|
|
985
|
-
var
|
|
1016
|
+
var CHAT_BG = "#f5f1eb";
|
|
1017
|
+
var BUBBLE_BOT = "#ffffff";
|
|
1018
|
+
var INPUT_BG = "#f1f3f5";
|
|
986
1019
|
var BORDER = "#e5e7eb";
|
|
1020
|
+
var BORDER_LIGHT = "rgba(15,23,42,0.06)";
|
|
987
1021
|
var TEXT_BODY = "#0f172a";
|
|
988
1022
|
var TEXT_MUTED = "#64748b";
|
|
989
1023
|
var TEXT_FAINT = "#94a3b8";
|
|
990
|
-
var FONT_STACK =
|
|
1024
|
+
var FONT_STACK = `-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif`;
|
|
991
1025
|
var STYLE_TAG_ID = "chatbotlite-widget-styles";
|
|
992
1026
|
var KEYFRAMES = `
|
|
993
1027
|
@keyframes chatbotlite-pop { 0% { opacity: 0; transform: scale(0.6); } 100% { opacity: 1; transform: scale(1); } }
|
|
@@ -999,8 +1033,8 @@ var KEYFRAMES = `
|
|
|
999
1033
|
.chatbotlite-launcher { transition: transform 180ms cubic-bezier(0.4, 0, 0.2, 1), box-shadow 180ms cubic-bezier(0.4, 0, 0.2, 1); animation: chatbotlite-pop 320ms cubic-bezier(0.34, 1.56, 0.64, 1), chatbotlite-pulse 3.6s ease-in-out 1.2s 2; }
|
|
1000
1034
|
.chatbotlite-launcher:hover { transform: translateY(-2px) scale(1.04); }
|
|
1001
1035
|
.chatbotlite-launcher:active { transform: translateY(0) scale(0.98); }
|
|
1002
|
-
.chatbotlite-close { transition: background 120ms ease; }
|
|
1003
|
-
.chatbotlite-close:hover { background: rgba(
|
|
1036
|
+
.chatbotlite-close { transition: background 120ms ease, color 120ms ease; }
|
|
1037
|
+
.chatbotlite-close:hover { background: rgba(15,23,42,0.06); color: ${TEXT_BODY}; }
|
|
1004
1038
|
.chatbotlite-send { transition: transform 120ms ease, opacity 120ms ease, box-shadow 120ms ease; }
|
|
1005
1039
|
.chatbotlite-send:not(:disabled):hover { transform: translateY(-1px); }
|
|
1006
1040
|
.chatbotlite-send:not(:disabled):active { transform: translateY(0); }
|
|
@@ -1008,8 +1042,8 @@ var KEYFRAMES = `
|
|
|
1008
1042
|
.chatbotlite-msg { animation: chatbotlite-fade-in 220ms cubic-bezier(0.4, 0, 0.2, 1); }
|
|
1009
1043
|
.chatbotlite-dot { display: inline-block; width: 6px; height: 6px; border-radius: 50%; background: ${TEXT_FAINT}; margin-right: 4px; animation: chatbotlite-dot 1.2s ease-in-out infinite; }
|
|
1010
1044
|
.chatbotlite-cursor { display: inline-block; width: 2px; height: 1em; background: currentColor; vertical-align: text-bottom; margin-left: 1px; animation: chatbotlite-cursor 1s steps(1) infinite; }
|
|
1011
|
-
.chatbotlite-
|
|
1012
|
-
.chatbotlite-
|
|
1045
|
+
.chatbotlite-icon-btn:hover:not(:disabled) { background: rgba(15,23,42,0.06) !important; opacity: 1 !important; }
|
|
1046
|
+
.chatbotlite-icon-btn:active:not(:disabled) { transform: scale(0.92); }
|
|
1013
1047
|
.chatbotlite-dot:nth-child(2) { animation-delay: 0.15s; }
|
|
1014
1048
|
.chatbotlite-dot:nth-child(3) { animation-delay: 0.3s; margin-right: 0; }
|
|
1015
1049
|
.chatbotlite-brand:hover { color: ${TEXT_MUTED} !important; }
|
|
@@ -1156,17 +1190,19 @@ function ChatWidget(props) {
|
|
|
1156
1190
|
return void 0;
|
|
1157
1191
|
}, [open]);
|
|
1158
1192
|
async function fetchReplyFromEndpoint(text, history, attachedFiles, onToken) {
|
|
1193
|
+
const enabledTools = Object.keys(tools);
|
|
1159
1194
|
let body;
|
|
1160
1195
|
const headers = { Accept: "text/event-stream, application/json" };
|
|
1161
1196
|
if (attachedFiles.length > 0) {
|
|
1162
1197
|
const form = new FormData();
|
|
1163
1198
|
form.append("message", text);
|
|
1164
1199
|
form.append("transcript", JSON.stringify(history));
|
|
1200
|
+
form.append("enabledTools", JSON.stringify(enabledTools));
|
|
1165
1201
|
for (const f of attachedFiles) form.append("attachments", f, f.name);
|
|
1166
1202
|
body = form;
|
|
1167
1203
|
} else {
|
|
1168
1204
|
headers["Content-Type"] = "application/json";
|
|
1169
|
-
body = JSON.stringify({ message: text, transcript: history });
|
|
1205
|
+
body = JSON.stringify({ message: text, transcript: history, enabledTools });
|
|
1170
1206
|
}
|
|
1171
1207
|
const res = await fetch(props.endpoint, { method: "POST", headers, body });
|
|
1172
1208
|
if (!res.ok) throw new Error(`Endpoint ${res.status}: ${await res.text().catch(() => "")}`);
|
|
@@ -1323,17 +1359,34 @@ function ChatWidget(props) {
|
|
|
1323
1359
|
},
|
|
1324
1360
|
children: [
|
|
1325
1361
|
/* @__PURE__ */ jsxs("header", { style: {
|
|
1326
|
-
padding: "16px
|
|
1327
|
-
background:
|
|
1328
|
-
color:
|
|
1362
|
+
padding: "14px 16px",
|
|
1363
|
+
background: SURFACE,
|
|
1364
|
+
color: TEXT_BODY,
|
|
1329
1365
|
display: "flex",
|
|
1330
1366
|
justifyContent: "space-between",
|
|
1331
1367
|
alignItems: "center",
|
|
1332
|
-
gap: 12
|
|
1368
|
+
gap: 12,
|
|
1369
|
+
borderBottom: `1px solid ${BORDER_LIGHT}`
|
|
1333
1370
|
}, children: [
|
|
1334
|
-
/* @__PURE__ */ jsxs("div", { style: { display: "flex",
|
|
1335
|
-
/* @__PURE__ */ jsx("
|
|
1336
|
-
|
|
1371
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 10, minWidth: 0 }, children: [
|
|
1372
|
+
/* @__PURE__ */ jsx("div", { style: {
|
|
1373
|
+
width: 36,
|
|
1374
|
+
height: 36,
|
|
1375
|
+
borderRadius: "50%",
|
|
1376
|
+
background: primary,
|
|
1377
|
+
color: onPrimary,
|
|
1378
|
+
display: "flex",
|
|
1379
|
+
alignItems: "center",
|
|
1380
|
+
justifyContent: "center",
|
|
1381
|
+
fontSize: 16,
|
|
1382
|
+
fontWeight: 600,
|
|
1383
|
+
flexShrink: 0,
|
|
1384
|
+
letterSpacing: "-0.02em"
|
|
1385
|
+
}, children: resolvedTitle.charAt(0).toUpperCase() }),
|
|
1386
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", lineHeight: 1.2, minWidth: 0 }, children: [
|
|
1387
|
+
/* @__PURE__ */ jsx("span", { style: { fontWeight: 600, fontSize: 15, letterSpacing: "-0.01em", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", color: TEXT_BODY }, children: resolvedTitle }),
|
|
1388
|
+
/* @__PURE__ */ jsx("span", { style: { fontSize: 12, color: TEXT_MUTED, marginTop: 2, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: subtitle ?? (sending ? "typing\u2026" : "online") })
|
|
1389
|
+
] })
|
|
1337
1390
|
] }),
|
|
1338
1391
|
/* @__PURE__ */ jsx(
|
|
1339
1392
|
"button",
|
|
@@ -1344,7 +1397,7 @@ function ChatWidget(props) {
|
|
|
1344
1397
|
style: {
|
|
1345
1398
|
background: "transparent",
|
|
1346
1399
|
border: "none",
|
|
1347
|
-
color:
|
|
1400
|
+
color: TEXT_MUTED,
|
|
1348
1401
|
width: 32,
|
|
1349
1402
|
height: 32,
|
|
1350
1403
|
borderRadius: 10,
|
|
@@ -1371,7 +1424,7 @@ function ChatWidget(props) {
|
|
|
1371
1424
|
display: "flex",
|
|
1372
1425
|
flexDirection: "column",
|
|
1373
1426
|
gap: 8,
|
|
1374
|
-
background:
|
|
1427
|
+
background: CHAT_BG
|
|
1375
1428
|
},
|
|
1376
1429
|
children: [
|
|
1377
1430
|
messages.map((m) => /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 6, alignItems: m.role === "user" ? "flex-end" : "stretch" }, children: [
|
|
@@ -1381,18 +1434,18 @@ function ChatWidget(props) {
|
|
|
1381
1434
|
className: "chatbotlite-msg",
|
|
1382
1435
|
style: {
|
|
1383
1436
|
alignSelf: m.role === "user" ? "flex-end" : "flex-start",
|
|
1384
|
-
maxWidth: "
|
|
1385
|
-
padding: "
|
|
1386
|
-
borderRadius:
|
|
1387
|
-
background: m.role === "user" ? primary :
|
|
1437
|
+
maxWidth: "78%",
|
|
1438
|
+
padding: "8px 12px",
|
|
1439
|
+
borderRadius: 18,
|
|
1440
|
+
background: m.role === "user" ? primary : BUBBLE_BOT,
|
|
1388
1441
|
color: m.role === "user" ? onPrimary : TEXT_BODY,
|
|
1389
|
-
border:
|
|
1390
|
-
fontSize: 14,
|
|
1391
|
-
lineHeight: 1.
|
|
1442
|
+
border: "none",
|
|
1443
|
+
fontSize: 14.5,
|
|
1444
|
+
lineHeight: 1.4,
|
|
1392
1445
|
letterSpacing: "-0.005em",
|
|
1393
1446
|
whiteSpace: "pre-wrap",
|
|
1394
1447
|
wordBreak: "break-word",
|
|
1395
|
-
boxShadow: m.role === "user" ? "
|
|
1448
|
+
boxShadow: m.role === "user" ? "none" : "0 1px 0.5px rgba(15,23,42,0.05)"
|
|
1396
1449
|
},
|
|
1397
1450
|
children: [
|
|
1398
1451
|
m.content,
|
|
@@ -1407,7 +1460,7 @@ function ChatWidget(props) {
|
|
|
1407
1460
|
onPrimary,
|
|
1408
1461
|
border: BORDER,
|
|
1409
1462
|
surface: SURFACE,
|
|
1410
|
-
surfaceMuted:
|
|
1463
|
+
surfaceMuted: CHAT_BG,
|
|
1411
1464
|
textBody: TEXT_BODY,
|
|
1412
1465
|
textMuted: TEXT_MUTED
|
|
1413
1466
|
};
|
|
@@ -1490,17 +1543,16 @@ function ChatWidget(props) {
|
|
|
1490
1543
|
return null;
|
|
1491
1544
|
})
|
|
1492
1545
|
] }, m.id)),
|
|
1493
|
-
sending && /* @__PURE__ */ jsxs(
|
|
1546
|
+
sending && messages[messages.length - 1]?.content === "" && /* @__PURE__ */ jsxs(
|
|
1494
1547
|
"div",
|
|
1495
1548
|
{
|
|
1496
1549
|
className: "chatbotlite-msg",
|
|
1497
1550
|
style: {
|
|
1498
1551
|
alignSelf: "flex-start",
|
|
1499
|
-
padding: "
|
|
1500
|
-
borderRadius:
|
|
1501
|
-
background:
|
|
1502
|
-
|
|
1503
|
-
boxShadow: "0 1px 2px rgba(15,23,42,0.04)"
|
|
1552
|
+
padding: "10px 14px",
|
|
1553
|
+
borderRadius: 18,
|
|
1554
|
+
background: BUBBLE_BOT,
|
|
1555
|
+
boxShadow: "0 1px 0.5px rgba(15,23,42,0.05)"
|
|
1504
1556
|
},
|
|
1505
1557
|
children: [
|
|
1506
1558
|
/* @__PURE__ */ jsx("span", { className: "chatbotlite-dot" }),
|
|
@@ -1512,172 +1564,199 @@ function ChatWidget(props) {
|
|
|
1512
1564
|
]
|
|
1513
1565
|
}
|
|
1514
1566
|
),
|
|
1515
|
-
/* @__PURE__ */
|
|
1516
|
-
|
|
1517
|
-
flexDirection: "column",
|
|
1518
|
-
padding: 12,
|
|
1519
|
-
gap: 8,
|
|
1567
|
+
files.length > 0 && /* @__PURE__ */ jsx("div", { style: {
|
|
1568
|
+
padding: "8px 12px 0",
|
|
1520
1569
|
background: SURFACE,
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
},
|
|
1538
|
-
children: [
|
|
1539
|
-
/* @__PURE__ */ jsxs("span", { style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: [
|
|
1540
|
-
"\u{1F4CE} ",
|
|
1541
|
-
f.name
|
|
1542
|
-
] }),
|
|
1543
|
-
/* @__PURE__ */ jsx(
|
|
1544
|
-
"button",
|
|
1545
|
-
{
|
|
1546
|
-
onClick: () => removeFile(i),
|
|
1547
|
-
"aria-label": `Remove ${f.name}`,
|
|
1548
|
-
style: {
|
|
1549
|
-
background: "transparent",
|
|
1550
|
-
border: "none",
|
|
1551
|
-
cursor: "pointer",
|
|
1552
|
-
color: TEXT_MUTED,
|
|
1553
|
-
fontSize: 14,
|
|
1554
|
-
lineHeight: 1,
|
|
1555
|
-
padding: 0
|
|
1556
|
-
},
|
|
1557
|
-
children: "\xD7"
|
|
1558
|
-
}
|
|
1559
|
-
)
|
|
1560
|
-
]
|
|
1570
|
+
display: "flex",
|
|
1571
|
+
flexWrap: "wrap",
|
|
1572
|
+
gap: 6
|
|
1573
|
+
}, children: files.map((f, i) => /* @__PURE__ */ jsxs(
|
|
1574
|
+
"span",
|
|
1575
|
+
{
|
|
1576
|
+
style: {
|
|
1577
|
+
display: "inline-flex",
|
|
1578
|
+
alignItems: "center",
|
|
1579
|
+
gap: 6,
|
|
1580
|
+
padding: "4px 8px 4px 10px",
|
|
1581
|
+
borderRadius: 999,
|
|
1582
|
+
background: INPUT_BG,
|
|
1583
|
+
fontSize: 12,
|
|
1584
|
+
color: TEXT_BODY,
|
|
1585
|
+
maxWidth: 200
|
|
1561
1586
|
},
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
"input",
|
|
1568
|
-
{
|
|
1569
|
-
ref: fileInputRef,
|
|
1570
|
-
type: "file",
|
|
1571
|
-
multiple: true,
|
|
1572
|
-
accept: acceptAttr,
|
|
1573
|
-
style: { display: "none" },
|
|
1574
|
-
onChange: (e) => {
|
|
1575
|
-
if (e.target.files) addFiles(e.target.files);
|
|
1576
|
-
e.target.value = "";
|
|
1577
|
-
}
|
|
1578
|
-
}
|
|
1579
|
-
),
|
|
1587
|
+
children: [
|
|
1588
|
+
/* @__PURE__ */ jsxs("span", { style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: [
|
|
1589
|
+
"\u{1F4CE} ",
|
|
1590
|
+
f.name
|
|
1591
|
+
] }),
|
|
1580
1592
|
/* @__PURE__ */ jsx(
|
|
1581
1593
|
"button",
|
|
1582
1594
|
{
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
style: {
|
|
1588
|
-
width: 40,
|
|
1589
|
-
height: 40,
|
|
1590
|
-
borderRadius: 10,
|
|
1591
|
-
background: SURFACE_MUTED,
|
|
1592
|
-
border: `1px solid ${BORDER}`,
|
|
1593
|
-
cursor: sending || files.length >= maxFiles ? "default" : "pointer",
|
|
1594
|
-
opacity: sending || files.length >= maxFiles ? 0.4 : 1,
|
|
1595
|
-
fontSize: 16,
|
|
1596
|
-
transition: "background 120ms ease, transform 80ms ease"
|
|
1597
|
-
},
|
|
1598
|
-
children: "\u{1F4CE}"
|
|
1595
|
+
onClick: () => removeFile(i),
|
|
1596
|
+
"aria-label": `Remove ${f.name}`,
|
|
1597
|
+
style: { background: "transparent", border: "none", cursor: "pointer", color: TEXT_MUTED, fontSize: 14, lineHeight: 1, padding: 0 },
|
|
1598
|
+
children: "\xD7"
|
|
1599
1599
|
}
|
|
1600
1600
|
)
|
|
1601
|
-
]
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
fontSize: 16,
|
|
1619
|
-
transition: "background 120ms ease, color 120ms ease, border-color 120ms ease, transform 80ms ease"
|
|
1620
|
-
},
|
|
1621
|
-
children: "\u{1F399}\uFE0F"
|
|
1622
|
-
}
|
|
1623
|
-
),
|
|
1601
|
+
]
|
|
1602
|
+
},
|
|
1603
|
+
`${f.name}-${i}`
|
|
1604
|
+
)) }),
|
|
1605
|
+
/* @__PURE__ */ jsx("div", { style: {
|
|
1606
|
+
padding: "10px 12px 12px",
|
|
1607
|
+
background: SURFACE
|
|
1608
|
+
}, children: /* @__PURE__ */ jsxs("div", { style: {
|
|
1609
|
+
display: "flex",
|
|
1610
|
+
alignItems: "flex-end",
|
|
1611
|
+
gap: 6,
|
|
1612
|
+
padding: "6px 6px 6px 10px",
|
|
1613
|
+
background: INPUT_BG,
|
|
1614
|
+
borderRadius: 22,
|
|
1615
|
+
transition: "background 120ms ease"
|
|
1616
|
+
}, children: [
|
|
1617
|
+
attachEnabled && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1624
1618
|
/* @__PURE__ */ jsx(
|
|
1625
1619
|
"input",
|
|
1626
1620
|
{
|
|
1627
|
-
ref:
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
if (e.
|
|
1634
|
-
|
|
1635
|
-
void send();
|
|
1636
|
-
}
|
|
1637
|
-
},
|
|
1638
|
-
placeholder: "Type a message\u2026",
|
|
1639
|
-
disabled: sending,
|
|
1640
|
-
style: {
|
|
1641
|
-
flex: 1,
|
|
1642
|
-
padding: "10px 14px",
|
|
1643
|
-
borderRadius: 12,
|
|
1644
|
-
border: `1px solid ${BORDER}`,
|
|
1645
|
-
background: SURFACE_MUTED,
|
|
1646
|
-
fontSize: 14,
|
|
1647
|
-
fontFamily: FONT_STACK,
|
|
1648
|
-
color: TEXT_BODY,
|
|
1649
|
-
outline: "none",
|
|
1650
|
-
transition: "box-shadow 120ms ease, border-color 120ms ease"
|
|
1621
|
+
ref: fileInputRef,
|
|
1622
|
+
type: "file",
|
|
1623
|
+
multiple: true,
|
|
1624
|
+
accept: acceptAttr,
|
|
1625
|
+
style: { display: "none" },
|
|
1626
|
+
onChange: (e) => {
|
|
1627
|
+
if (e.target.files) addFiles(e.target.files);
|
|
1628
|
+
e.target.value = "";
|
|
1651
1629
|
}
|
|
1652
1630
|
}
|
|
1653
1631
|
),
|
|
1654
1632
|
/* @__PURE__ */ jsx(
|
|
1655
1633
|
"button",
|
|
1656
1634
|
{
|
|
1657
|
-
className: "chatbotlite-
|
|
1658
|
-
onClick: () =>
|
|
1659
|
-
disabled: sending ||
|
|
1660
|
-
"aria-label": "
|
|
1635
|
+
className: "chatbotlite-icon-btn",
|
|
1636
|
+
onClick: () => fileInputRef.current?.click(),
|
|
1637
|
+
disabled: sending || files.length >= maxFiles,
|
|
1638
|
+
"aria-label": "Attach file",
|
|
1661
1639
|
style: {
|
|
1662
|
-
|
|
1663
|
-
height:
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
background: primary,
|
|
1667
|
-
color: onPrimary,
|
|
1640
|
+
width: 32,
|
|
1641
|
+
height: 32,
|
|
1642
|
+
borderRadius: "50%",
|
|
1643
|
+
background: "transparent",
|
|
1668
1644
|
border: "none",
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1645
|
+
cursor: sending || files.length >= maxFiles ? "default" : "pointer",
|
|
1646
|
+
opacity: sending || files.length >= maxFiles ? 0.35 : 0.7,
|
|
1647
|
+
fontSize: 18,
|
|
1648
|
+
lineHeight: 1,
|
|
1649
|
+
padding: 0,
|
|
1650
|
+
display: "flex",
|
|
1651
|
+
alignItems: "center",
|
|
1652
|
+
justifyContent: "center",
|
|
1653
|
+
flexShrink: 0,
|
|
1654
|
+
alignSelf: "center",
|
|
1655
|
+
transition: "opacity 120ms ease, background 120ms ease"
|
|
1675
1656
|
},
|
|
1676
|
-
children: "
|
|
1657
|
+
children: "\u{1F4CE}"
|
|
1677
1658
|
}
|
|
1678
1659
|
)
|
|
1679
|
-
] })
|
|
1680
|
-
|
|
1660
|
+
] }),
|
|
1661
|
+
voiceEnabled && speechSupported && /* @__PURE__ */ jsx(
|
|
1662
|
+
"button",
|
|
1663
|
+
{
|
|
1664
|
+
className: "chatbotlite-icon-btn",
|
|
1665
|
+
onClick: toggleVoice,
|
|
1666
|
+
disabled: sending,
|
|
1667
|
+
"aria-label": voiceListening ? "Stop recording" : "Start voice input",
|
|
1668
|
+
style: {
|
|
1669
|
+
width: 32,
|
|
1670
|
+
height: 32,
|
|
1671
|
+
borderRadius: "50%",
|
|
1672
|
+
background: voiceListening ? primary : "transparent",
|
|
1673
|
+
color: voiceListening ? onPrimary : "inherit",
|
|
1674
|
+
border: "none",
|
|
1675
|
+
cursor: sending ? "default" : "pointer",
|
|
1676
|
+
opacity: sending ? 0.35 : voiceListening ? 1 : 0.7,
|
|
1677
|
+
fontSize: 16,
|
|
1678
|
+
lineHeight: 1,
|
|
1679
|
+
padding: 0,
|
|
1680
|
+
display: "flex",
|
|
1681
|
+
alignItems: "center",
|
|
1682
|
+
justifyContent: "center",
|
|
1683
|
+
flexShrink: 0,
|
|
1684
|
+
alignSelf: "center",
|
|
1685
|
+
transition: "opacity 120ms ease, background 120ms ease, color 120ms ease"
|
|
1686
|
+
},
|
|
1687
|
+
children: "\u{1F399}\uFE0F"
|
|
1688
|
+
}
|
|
1689
|
+
),
|
|
1690
|
+
/* @__PURE__ */ jsx(
|
|
1691
|
+
"textarea",
|
|
1692
|
+
{
|
|
1693
|
+
ref: inputRef,
|
|
1694
|
+
className: "chatbotlite-input",
|
|
1695
|
+
rows: 1,
|
|
1696
|
+
value: input,
|
|
1697
|
+
onChange: (e) => {
|
|
1698
|
+
setInput(e.target.value);
|
|
1699
|
+
const el = e.currentTarget;
|
|
1700
|
+
el.style.height = "auto";
|
|
1701
|
+
el.style.height = Math.min(el.scrollHeight, 100) + "px";
|
|
1702
|
+
},
|
|
1703
|
+
onKeyDown: (e) => {
|
|
1704
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
1705
|
+
e.preventDefault();
|
|
1706
|
+
void send();
|
|
1707
|
+
}
|
|
1708
|
+
},
|
|
1709
|
+
placeholder: "Message",
|
|
1710
|
+
disabled: sending,
|
|
1711
|
+
style: {
|
|
1712
|
+
flex: 1,
|
|
1713
|
+
padding: "7px 4px",
|
|
1714
|
+
border: "none",
|
|
1715
|
+
background: "transparent",
|
|
1716
|
+
fontSize: 14.5,
|
|
1717
|
+
fontFamily: FONT_STACK,
|
|
1718
|
+
color: TEXT_BODY,
|
|
1719
|
+
outline: "none",
|
|
1720
|
+
resize: "none",
|
|
1721
|
+
lineHeight: 1.35,
|
|
1722
|
+
maxHeight: 100,
|
|
1723
|
+
minHeight: 20
|
|
1724
|
+
}
|
|
1725
|
+
}
|
|
1726
|
+
),
|
|
1727
|
+
/* @__PURE__ */ jsx(
|
|
1728
|
+
"button",
|
|
1729
|
+
{
|
|
1730
|
+
className: "chatbotlite-send",
|
|
1731
|
+
onClick: () => void send(),
|
|
1732
|
+
disabled: sending || !input.trim() && files.length === 0,
|
|
1733
|
+
"aria-label": "Send message",
|
|
1734
|
+
style: {
|
|
1735
|
+
width: 34,
|
|
1736
|
+
height: 34,
|
|
1737
|
+
borderRadius: "50%",
|
|
1738
|
+
background: primary,
|
|
1739
|
+
color: onPrimary,
|
|
1740
|
+
border: "none",
|
|
1741
|
+
fontSize: 14,
|
|
1742
|
+
fontWeight: 600,
|
|
1743
|
+
fontFamily: FONT_STACK,
|
|
1744
|
+
cursor: sending || !input.trim() && files.length === 0 ? "default" : "pointer",
|
|
1745
|
+
opacity: sending || !input.trim() && files.length === 0 ? 0.35 : 1,
|
|
1746
|
+
display: "flex",
|
|
1747
|
+
alignItems: "center",
|
|
1748
|
+
justifyContent: "center",
|
|
1749
|
+
flexShrink: 0,
|
|
1750
|
+
padding: 0,
|
|
1751
|
+
transition: "opacity 120ms ease, transform 80ms ease"
|
|
1752
|
+
},
|
|
1753
|
+
children: /* @__PURE__ */ jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
1754
|
+
/* @__PURE__ */ jsx("line", { x1: "12", y1: "19", x2: "12", y2: "5" }),
|
|
1755
|
+
/* @__PURE__ */ jsx("polyline", { points: "5 12 12 5 19 12" })
|
|
1756
|
+
] })
|
|
1757
|
+
}
|
|
1758
|
+
)
|
|
1759
|
+
] }) }),
|
|
1681
1760
|
showBranding && /* @__PURE__ */ jsxs(
|
|
1682
1761
|
"a",
|
|
1683
1762
|
{
|