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