chatbotlite 0.5.2 → 0.6.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.
@@ -95,6 +95,19 @@ interface ChatWidgetDirectProps extends ChatWidgetCommonProps {
95
95
  knowledge: Knowledge;
96
96
  /** Provider chain + API keys. */
97
97
  providers: ProviderConfig;
98
+ /**
99
+ * Append per-vertical behaviour tweaks to the default system prompt
100
+ * (tone, escalation rules, "don't quote price too early", etc.).
101
+ * Only used in direct (client-side) mode — in endpoint mode the server
102
+ * controls the prompt.
103
+ */
104
+ extraInstructions?: string;
105
+ /**
106
+ * Power-user hook to modify our default scaffolding inline.
107
+ * Receives the assembled default prompt, returns a transformed string.
108
+ * Direct mode only.
109
+ */
110
+ systemPromptTransform?: (defaultPrompt: string) => string;
98
111
  endpoint?: never;
99
112
  }
100
113
  interface ChatWidgetEndpointProps extends ChatWidgetCommonProps {
@@ -95,6 +95,19 @@ interface ChatWidgetDirectProps extends ChatWidgetCommonProps {
95
95
  knowledge: Knowledge;
96
96
  /** Provider chain + API keys. */
97
97
  providers: ProviderConfig;
98
+ /**
99
+ * Append per-vertical behaviour tweaks to the default system prompt
100
+ * (tone, escalation rules, "don't quote price too early", etc.).
101
+ * Only used in direct (client-side) mode — in endpoint mode the server
102
+ * controls the prompt.
103
+ */
104
+ extraInstructions?: string;
105
+ /**
106
+ * Power-user hook to modify our default scaffolding inline.
107
+ * Receives the assembled default prompt, returns a transformed string.
108
+ * Direct mode only.
109
+ */
110
+ systemPromptTransform?: (defaultPrompt: string) => string;
98
111
  endpoint?: never;
99
112
  }
100
113
  interface ChatWidgetEndpointProps extends ChatWidgetCommonProps {
@@ -1,8 +1,20 @@
1
- import { useState, useRef, useEffect, useMemo } from 'react';
1
+ import { useState, useEffect, useRef, useMemo } from 'react';
2
2
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
3
3
 
4
4
  // src/react/ChatWidget.tsx
5
5
 
6
+ // src/react/color.ts
7
+ function luminance(hex) {
8
+ const m = hex.replace("#", "");
9
+ const norm = m.length === 3 ? m.split("").map((c) => c + c).join("") : m;
10
+ if (norm.length !== 6 || !/^[0-9a-fA-F]{6}$/.test(norm)) return 0;
11
+ const r = parseInt(norm.slice(0, 2), 16) / 255;
12
+ const g = parseInt(norm.slice(2, 4), 16) / 255;
13
+ const b = parseInt(norm.slice(4, 6), 16) / 255;
14
+ const toLinear = (c) => c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
15
+ return 0.2126 * toLinear(r) + 0.7152 * toLinear(g) + 0.0722 * toLinear(b);
16
+ }
17
+
6
18
  // src/core/tools.ts
7
19
  var MARKER_RE = /\[SKILL:(\w+)((?:\s+\w+=(?:"[^"]*"|[\w./@*+,:-]+))*)\s*\]/g;
8
20
  var ARG_RE = /(\w+)=("([^"]*)"|([\w./@*+,:-]+))/g;
@@ -55,9 +67,11 @@ function buildToolsPromptAddendum(enabledTools) {
55
67
  }
56
68
 
57
69
  // src/core/prompts.ts
58
- function buildSystemPrompt(knowledge, enabledTools = []) {
59
- const toolsAddendum = buildToolsPromptAddendum(enabledTools);
60
- return [
70
+ function buildSystemPrompt(knowledge, optionsOrEnabledTools = []) {
71
+ const opts = Array.isArray(optionsOrEnabledTools) ? { enabledTools: optionsOrEnabledTools } : optionsOrEnabledTools;
72
+ const toolsAddendum = buildToolsPromptAddendum(opts.enabledTools ?? []);
73
+ const extras = opts.extraInstructions?.trim();
74
+ const parts = [
61
75
  "You are an AI assistant on a business website. Use ONLY the knowledge below to answer.",
62
76
  "",
63
77
  "## Business knowledge",
@@ -69,9 +83,16 @@ function buildSystemPrompt(knowledge, enabledTools = []) {
69
83
  "- For anything not covered in the knowledge above, say the owner will follow up \u2014 do NOT guess.",
70
84
  '- 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."',
71
85
  `- If wrong number or asked to stop, say: "Sorry about that. We won't text again."`,
72
- "- Match the caller's language automatically.",
73
- toolsAddendum
74
- ].filter(Boolean).join("\n");
86
+ "- Match the caller's language automatically."
87
+ ];
88
+ if (extras) {
89
+ parts.push("", "## Additional instructions", extras);
90
+ }
91
+ if (toolsAddendum) {
92
+ parts.push(toolsAddendum);
93
+ }
94
+ const defaultPrompt = parts.join("\n");
95
+ return opts.systemPromptTransform ? opts.systemPromptTransform(defaultPrompt) : defaultPrompt;
75
96
  }
76
97
 
77
98
  // src/core/guards.ts
@@ -195,6 +216,8 @@ var ChatBot = class {
195
216
  cachedSystemPrompt;
196
217
  guards;
197
218
  knowledge;
219
+ extraInstructions;
220
+ systemPromptTransform;
198
221
  constructor(init) {
199
222
  if (!init.knowledge || typeof init.knowledge !== "string" || init.knowledge.trim().length === 0) {
200
223
  throw new Error("chatbotlite: knowledge is required (a non-empty markdown string).");
@@ -204,14 +227,23 @@ var ChatBot = class {
204
227
  this.steps = resolveChain(init.providers);
205
228
  this.fetcher = init.options?.fetch ?? globalThis.fetch.bind(globalThis);
206
229
  this.timeoutMs = init.options?.timeoutMs ?? 3e4;
207
- this.cachedSystemPrompt = buildSystemPrompt(init.knowledge);
230
+ this.extraInstructions = init.extraInstructions;
231
+ this.systemPromptTransform = init.systemPromptTransform;
232
+ this.cachedSystemPrompt = buildSystemPrompt(init.knowledge, {
233
+ extraInstructions: this.extraInstructions,
234
+ systemPromptTransform: this.systemPromptTransform
235
+ });
208
236
  this.guards = init.guards ?? {};
209
237
  }
210
238
  /** Build system prompt for given opts — uses cached if no enabledTools, else rebuilds. */
211
239
  resolveSystemPrompt(opts) {
212
240
  if (opts.systemPrompt) return opts.systemPrompt;
213
241
  if (opts.enabledTools && opts.enabledTools.length > 0) {
214
- return buildSystemPrompt(this.knowledge, opts.enabledTools);
242
+ return buildSystemPrompt(this.knowledge, {
243
+ enabledTools: opts.enabledTools,
244
+ extraInstructions: this.extraInstructions,
245
+ systemPromptTransform: this.systemPromptTransform
246
+ });
215
247
  }
216
248
  return this.cachedSystemPrompt;
217
249
  }
@@ -881,7 +913,7 @@ function RequestPayment(props) {
881
913
  surface,
882
914
  textBody,
883
915
  textMuted,
884
- showInterac = true,
916
+ showInterac = false,
885
917
  stripeLink,
886
918
  onPick,
887
919
  submitting = false,
@@ -997,8 +1029,12 @@ function RequestPayment(props) {
997
1029
  display: "flex",
998
1030
  alignItems: "center",
999
1031
  justifyContent: "center",
1000
- flexShrink: 0
1001
- }, children: /* @__PURE__ */ jsx("span", { style: { color: "#635BFF", fontSize: 14, fontWeight: 700 }, children: "\u{1F4B3}" }) }),
1032
+ flexShrink: 0,
1033
+ color: "#635BFF"
1034
+ }, children: /* @__PURE__ */ jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1.75, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
1035
+ /* @__PURE__ */ jsx("rect", { x: "2", y: "5", width: "20", height: "14", rx: "2.5" }),
1036
+ /* @__PURE__ */ jsx("line", { x1: "2", y1: "10", x2: "22", y2: "10" })
1037
+ ] }) }),
1002
1038
  /* @__PURE__ */ jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [
1003
1039
  /* @__PURE__ */ jsx("p", { style: { margin: 0, fontSize: 13, fontWeight: 600, color: textBody }, children: "Pay by card" }),
1004
1040
  /* @__PURE__ */ jsx("p", { style: { margin: "2px 0 0", fontSize: 11, color: textMuted }, children: "Visa \xB7 Mastercard \xB7 Amex" })
@@ -1009,30 +1045,76 @@ function RequestPayment(props) {
1009
1045
  ] })
1010
1046
  ] });
1011
1047
  }
1012
- var BOLT = "\u26A1";
1013
1048
  var DEFAULT_PRIMARY = "#0f172a";
1014
1049
  var DEFAULT_ON_PRIMARY = "#ffffff";
1015
- function luminance(hex) {
1016
- const m = hex.replace("#", "");
1017
- const norm = m.length === 3 ? m.split("").map((c) => c + c).join("") : m;
1018
- if (norm.length !== 6) return 0;
1019
- const r = parseInt(norm.slice(0, 2), 16) / 255;
1020
- const g = parseInt(norm.slice(2, 4), 16) / 255;
1021
- const b = parseInt(norm.slice(4, 6), 16) / 255;
1022
- const toLinear = (c) => c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
1023
- return 0.2126 * toLinear(r) + 0.7152 * toLinear(g) + 0.0722 * toLinear(b);
1024
- }
1025
- var SURFACE = "#ffffff";
1026
- var CHAT_BG = "#f5f1eb";
1027
- var BUBBLE_BOT = "#ffffff";
1028
- var INPUT_BG = "#f1f3f5";
1029
- var BORDER = "#e5e7eb";
1030
- var BORDER_LIGHT = "rgba(15,23,42,0.06)";
1031
- var TEXT_BODY = "#0f172a";
1032
- var TEXT_MUTED = "#64748b";
1033
- var TEXT_FAINT = "#94a3b8";
1034
- var FONT_STACK = `-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif`;
1050
+ var IconPaperclip = ({ size = 18 }) => /* @__PURE__ */ jsx("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1.75, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48" }) });
1051
+ var IconMic = ({ size = 16 }) => /* @__PURE__ */ jsxs("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1.75, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
1052
+ /* @__PURE__ */ jsx("rect", { x: "9", y: "3", width: "6", height: "12", rx: "3" }),
1053
+ /* @__PURE__ */ jsx("path", { d: "M5 11a7 7 0 0 0 14 0M12 19v3" })
1054
+ ] });
1055
+ var IconBolt = ({ size = 11 }) => /* @__PURE__ */ jsx("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": "true", style: { verticalAlign: "-1px" }, children: /* @__PURE__ */ jsx("path", { d: "M13 2L4 14h7l-1 8 9-12h-7l1-8z" }) });
1056
+ var SURFACE = "var(--cbl-bg)";
1057
+ var CHAT_BG = "var(--cbl-bg-chat)";
1058
+ var BUBBLE_BOT = "var(--cbl-bg-elevated)";
1059
+ var INPUT_BG = "var(--cbl-bg-sunken)";
1060
+ var BORDER = "var(--cbl-border)";
1061
+ var BORDER_LIGHT = "var(--cbl-border-light)";
1062
+ var TEXT_BODY = "var(--cbl-text)";
1063
+ var TEXT_MUTED = "var(--cbl-text-muted)";
1064
+ var TEXT_FAINT = "var(--cbl-text-faint)";
1065
+ var FONT_STACK = "var(--cbl-font)";
1035
1066
  var STYLE_TAG_ID = "chatbotlite-widget-styles";
1067
+ var TOKENS = `
1068
+ :where(.chatbotlite-root) {
1069
+ --cbl-bg: #FFFFFF;
1070
+ --cbl-bg-elevated: #FFFFFF;
1071
+ --cbl-bg-chat: #F7F8FA;
1072
+ --cbl-bg-sunken: #F1F3F5;
1073
+ --cbl-border: #E5E7EB;
1074
+ --cbl-border-strong: #D1D5DB;
1075
+ --cbl-border-light: rgba(15,23,42,0.06);
1076
+ --cbl-text: #0F172A;
1077
+ --cbl-text-muted: #64748B;
1078
+ --cbl-text-faint: #94A3B8;
1079
+ --cbl-success: #10B981;
1080
+ --cbl-danger: #EF4444;
1081
+ --cbl-font: -apple-system, BlinkMacSystemFont, "Inter", "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", system-ui, sans-serif;
1082
+ --cbl-ease-out: cubic-bezier(0.16, 1, 0.3, 1);
1083
+ --cbl-ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
1084
+ --cbl-ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
1085
+ --cbl-shadow-1: 0 1px 2px rgba(15,23,42,0.04);
1086
+ --cbl-shadow-2: 0 4px 12px rgba(15,23,42,0.06), 0 1px 2px rgba(15,23,42,0.04);
1087
+ --cbl-shadow-3: 0 10px 32px rgba(15,23,42,0.10), 0 2px 6px rgba(15,23,42,0.04);
1088
+ --cbl-shadow-4: 0 20px 48px rgba(15,23,42,0.18), 0 4px 12px rgba(15,23,42,0.08);
1089
+ }
1090
+ @media (prefers-color-scheme: dark) {
1091
+ :where(.chatbotlite-root[data-color-scheme="auto"]),
1092
+ :where(.chatbotlite-root[data-color-scheme="dark"]) {
1093
+ --cbl-bg: #16181D;
1094
+ --cbl-bg-elevated: #1F2228;
1095
+ --cbl-bg-chat: #0B0D10;
1096
+ --cbl-bg-sunken: #1F2228;
1097
+ --cbl-border: #24272E;
1098
+ --cbl-border-strong: #2E323A;
1099
+ --cbl-border-light: rgba(255,255,255,0.06);
1100
+ --cbl-text: #ECEDEE;
1101
+ --cbl-text-muted: #9BA1A6;
1102
+ --cbl-text-faint: #6B7177;
1103
+ }
1104
+ }
1105
+ :where(.chatbotlite-root[data-color-scheme="light"]) {
1106
+ --cbl-bg: #FFFFFF;
1107
+ --cbl-bg-elevated: #FFFFFF;
1108
+ --cbl-bg-chat: #F7F8FA;
1109
+ --cbl-bg-sunken: #F1F3F5;
1110
+ --cbl-border: #E5E7EB;
1111
+ --cbl-border-strong: #D1D5DB;
1112
+ --cbl-border-light: rgba(15,23,42,0.06);
1113
+ --cbl-text: #0F172A;
1114
+ --cbl-text-muted: #64748B;
1115
+ --cbl-text-faint: #94A3B8;
1116
+ }
1117
+ `;
1036
1118
  var KEYFRAMES = `
1037
1119
  @keyframes chatbotlite-pop { 0% { opacity: 0; transform: scale(0.6); } 100% { opacity: 1; transform: scale(1); } }
1038
1120
  @keyframes chatbotlite-slide { 0% { opacity: 0; transform: translateY(16px) scale(0.98); } 100% { opacity: 1; transform: translateY(0) scale(1); } }
@@ -1065,7 +1147,7 @@ function ensureStyles() {
1065
1147
  if (document.getElementById(STYLE_TAG_ID)) return;
1066
1148
  const style = document.createElement("style");
1067
1149
  style.id = STYLE_TAG_ID;
1068
- style.textContent = KEYFRAMES;
1150
+ style.textContent = TOKENS + KEYFRAMES;
1069
1151
  document.head.appendChild(style);
1070
1152
  }
1071
1153
  function ChatWidget(props) {
@@ -1093,6 +1175,33 @@ function ChatWidget(props) {
1093
1175
  const voiceLang = voiceCfg?.lang ?? "en-US";
1094
1176
  const speechSupported = typeof window !== "undefined" && (Boolean(window.SpeechRecognition) || Boolean(window.webkitSpeechRecognition));
1095
1177
  const [open, setOpen] = useState(false);
1178
+ const [expanded, setExpanded] = useState(() => {
1179
+ if (typeof window === "undefined") return false;
1180
+ try {
1181
+ return window.localStorage.getItem("cbl-panel-size") === "expanded";
1182
+ } catch {
1183
+ return false;
1184
+ }
1185
+ });
1186
+ const [isMobile, setIsMobile] = useState(
1187
+ () => typeof window === "undefined" ? false : window.innerWidth < 640
1188
+ );
1189
+ useEffect(() => {
1190
+ if (typeof window === "undefined") return;
1191
+ const onResize = () => setIsMobile(window.innerWidth < 640);
1192
+ window.addEventListener("resize", onResize);
1193
+ return () => window.removeEventListener("resize", onResize);
1194
+ }, []);
1195
+ function toggleExpanded() {
1196
+ setExpanded((prev) => {
1197
+ const next = !prev;
1198
+ try {
1199
+ window.localStorage.setItem("cbl-panel-size", next ? "expanded" : "compact");
1200
+ } catch {
1201
+ }
1202
+ return next;
1203
+ });
1204
+ }
1096
1205
  const [messages, setMessages] = useState([
1097
1206
  { id: "g0", role: "assistant", content: resolvedGreeting, ts: Date.now() }
1098
1207
  ]);
@@ -1185,11 +1294,17 @@ function ChatWidget(props) {
1185
1294
  useEffect(() => {
1186
1295
  ensureStyles();
1187
1296
  }, []);
1297
+ const directProps = isEndpointMode ? null : props;
1188
1298
  const bot = useMemo(() => {
1189
- if (isEndpointMode) return null;
1190
- if (!props.knowledge || !props.providers) return null;
1191
- return new ChatBot({ knowledge: props.knowledge, providers: props.providers });
1192
- }, [isEndpointMode, props.knowledge, props.providers]);
1299
+ if (!directProps) return null;
1300
+ if (!directProps.knowledge || !directProps.providers) return null;
1301
+ return new ChatBot({
1302
+ knowledge: directProps.knowledge,
1303
+ providers: directProps.providers,
1304
+ ...directProps.extraInstructions ? { extraInstructions: directProps.extraInstructions } : {},
1305
+ ...directProps.systemPromptTransform ? { systemPromptTransform: directProps.systemPromptTransform } : {}
1306
+ });
1307
+ }, [directProps]);
1193
1308
  useEffect(() => {
1194
1309
  if (scrollRef.current) {
1195
1310
  scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
@@ -1218,7 +1333,12 @@ function ChatWidget(props) {
1218
1333
  body = JSON.stringify({ message: text, transcript: history, enabledTools });
1219
1334
  }
1220
1335
  const res = await fetch(props.endpoint, { method: "POST", headers, body });
1221
- if (!res.ok) throw new Error(`Endpoint ${res.status}: ${await res.text().catch(() => "")}`);
1336
+ if (!res.ok) {
1337
+ const raw = await res.text().catch(() => "");
1338
+ const looksLikeHtml = /^\s*<(!doctype|html|head|body)/i.test(raw);
1339
+ const snippet = looksLikeHtml ? "" : raw.slice(0, 120).replace(/\s+/g, " ").trim();
1340
+ throw new Error(`Server returned ${res.status}${snippet ? ` \u2014 ${snippet}` : ""}`);
1341
+ }
1222
1342
  const contentType = res.headers.get("Content-Type") ?? "";
1223
1343
  if (contentType.includes("text/event-stream") && res.body) {
1224
1344
  const reader = res.body.getReader();
@@ -1320,10 +1440,13 @@ function ChatWidget(props) {
1320
1440
  !open && /* @__PURE__ */ jsx(
1321
1441
  "button",
1322
1442
  {
1323
- className: "chatbotlite-launcher",
1443
+ className: "chatbotlite-root chatbotlite-launcher",
1444
+ "data-color-scheme": "auto",
1324
1445
  onClick: () => setOpen(true),
1325
1446
  "aria-label": "Open chat",
1326
1447
  style: {
1448
+ ["--cbl-primary"]: primary,
1449
+ ["--cbl-on-primary"]: onPrimary,
1327
1450
  position: "fixed",
1328
1451
  bottom: 20,
1329
1452
  ...launcherPos,
@@ -1354,16 +1477,20 @@ function ChatWidget(props) {
1354
1477
  open && /* @__PURE__ */ jsxs(
1355
1478
  "div",
1356
1479
  {
1480
+ className: "chatbotlite-root",
1481
+ "data-color-scheme": "auto",
1357
1482
  role: "dialog",
1358
1483
  "aria-label": "Chat",
1359
1484
  style: {
1485
+ ["--cbl-primary"]: primary,
1486
+ ["--cbl-on-primary"]: onPrimary,
1360
1487
  position: "fixed",
1361
- bottom: 20,
1362
- ...panelPos,
1363
- width: 380,
1364
- maxWidth: "calc(100vw - 40px)",
1365
- height: 580,
1366
- maxHeight: "calc(100vh - 40px)",
1488
+ bottom: isMobile ? 0 : 20,
1489
+ ...isMobile ? { left: 0, right: 0 } : panelPos,
1490
+ width: isMobile ? "100vw" : expanded ? 720 : 380,
1491
+ maxWidth: isMobile ? "100vw" : "calc(100vw - 40px)",
1492
+ height: isMobile ? "100vh" : expanded ? 800 : 580,
1493
+ maxHeight: isMobile ? "100vh" : "calc(100vh - 40px)",
1367
1494
  background: SURFACE,
1368
1495
  color: TEXT_BODY,
1369
1496
  borderRadius: 20,
@@ -1421,30 +1548,63 @@ function ChatWidget(props) {
1421
1548
  (subtitle || sending) && /* @__PURE__ */ jsx("span", { style: { fontSize: 12, color: TEXT_MUTED, marginTop: 2, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: subtitle ?? (sending ? "typing\u2026" : "") })
1422
1549
  ] })
1423
1550
  ] }),
1424
- /* @__PURE__ */ jsx(
1425
- "button",
1426
- {
1427
- className: "chatbotlite-close",
1428
- onClick: () => setOpen(false),
1429
- "aria-label": "Close chat",
1430
- style: {
1431
- background: "transparent",
1432
- border: "none",
1433
- color: TEXT_MUTED,
1434
- width: 32,
1435
- height: 32,
1436
- borderRadius: 10,
1437
- fontSize: 22,
1438
- lineHeight: 1,
1439
- cursor: "pointer",
1440
- display: "flex",
1441
- alignItems: "center",
1442
- justifyContent: "center",
1443
- flexShrink: 0
1444
- },
1445
- children: "\xD7"
1446
- }
1447
- )
1551
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 2, flexShrink: 0 }, children: [
1552
+ !isMobile && /* @__PURE__ */ jsx(
1553
+ "button",
1554
+ {
1555
+ className: "chatbotlite-resize",
1556
+ onClick: toggleExpanded,
1557
+ "aria-label": expanded ? "Compact view" : "Expand view",
1558
+ title: expanded ? "Compact view" : "Expand view",
1559
+ style: {
1560
+ background: "transparent",
1561
+ border: "none",
1562
+ color: TEXT_MUTED,
1563
+ width: 32,
1564
+ height: 32,
1565
+ borderRadius: 10,
1566
+ cursor: "pointer",
1567
+ display: "flex",
1568
+ alignItems: "center",
1569
+ justifyContent: "center"
1570
+ },
1571
+ children: expanded ? /* @__PURE__ */ jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1.75, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
1572
+ /* @__PURE__ */ jsx("polyline", { points: "9 4 4 4 4 9" }),
1573
+ /* @__PURE__ */ jsx("polyline", { points: "15 4 20 4 20 9" }),
1574
+ /* @__PURE__ */ jsx("polyline", { points: "4 15 4 20 9 20" }),
1575
+ /* @__PURE__ */ jsx("polyline", { points: "20 15 20 20 15 20" })
1576
+ ] }) : /* @__PURE__ */ jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1.75, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
1577
+ /* @__PURE__ */ jsx("polyline", { points: "3 9 3 3 9 3" }),
1578
+ /* @__PURE__ */ jsx("polyline", { points: "21 9 21 3 15 3" }),
1579
+ /* @__PURE__ */ jsx("polyline", { points: "3 15 3 21 9 21" }),
1580
+ /* @__PURE__ */ jsx("polyline", { points: "21 15 21 21 15 21" })
1581
+ ] })
1582
+ }
1583
+ ),
1584
+ /* @__PURE__ */ jsx(
1585
+ "button",
1586
+ {
1587
+ className: "chatbotlite-close",
1588
+ onClick: () => setOpen(false),
1589
+ "aria-label": "Close chat",
1590
+ style: {
1591
+ background: "transparent",
1592
+ border: "none",
1593
+ color: TEXT_MUTED,
1594
+ width: 32,
1595
+ height: 32,
1596
+ borderRadius: 10,
1597
+ fontSize: 22,
1598
+ lineHeight: 1,
1599
+ cursor: "pointer",
1600
+ display: "flex",
1601
+ alignItems: "center",
1602
+ justifyContent: "center"
1603
+ },
1604
+ children: "\xD7"
1605
+ }
1606
+ )
1607
+ ] })
1448
1608
  ] }),
1449
1609
  /* @__PURE__ */ jsxs(
1450
1610
  "div",
@@ -1627,9 +1787,9 @@ function ChatWidget(props) {
1627
1787
  maxWidth: 200
1628
1788
  },
1629
1789
  children: [
1630
- /* @__PURE__ */ jsxs("span", { style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: [
1631
- "\u{1F4CE} ",
1632
- f.name
1790
+ /* @__PURE__ */ jsxs("span", { style: { display: "inline-flex", alignItems: "center", gap: 6, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", color: TEXT_MUTED }, children: [
1791
+ /* @__PURE__ */ jsx(IconPaperclip, { size: 12 }),
1792
+ /* @__PURE__ */ jsx("span", { style: { overflow: "hidden", textOverflow: "ellipsis", color: TEXT_BODY }, children: f.name })
1633
1793
  ] }),
1634
1794
  /* @__PURE__ */ jsx(
1635
1795
  "button",
@@ -1689,8 +1849,8 @@ function ChatWidget(props) {
1689
1849
  background: "transparent",
1690
1850
  border: "none",
1691
1851
  cursor: sending || files.length >= maxFiles ? "default" : "pointer",
1692
- opacity: sending || files.length >= maxFiles ? 0.35 : 0.7,
1693
- fontSize: 18,
1852
+ opacity: sending || files.length >= maxFiles ? 0.35 : 0.75,
1853
+ color: TEXT_MUTED,
1694
1854
  lineHeight: 1,
1695
1855
  padding: 0,
1696
1856
  display: "flex",
@@ -1700,7 +1860,7 @@ function ChatWidget(props) {
1700
1860
  alignSelf: "center",
1701
1861
  transition: "opacity 120ms ease, background 120ms ease"
1702
1862
  },
1703
- children: "\u{1F4CE}"
1863
+ children: /* @__PURE__ */ jsx(IconPaperclip, { size: 18 })
1704
1864
  }
1705
1865
  )
1706
1866
  ] }),
@@ -1719,8 +1879,7 @@ function ChatWidget(props) {
1719
1879
  color: voiceListening ? onPrimary : "inherit",
1720
1880
  border: "none",
1721
1881
  cursor: sending ? "default" : "pointer",
1722
- opacity: sending ? 0.35 : voiceListening ? 1 : 0.7,
1723
- fontSize: 16,
1882
+ opacity: sending ? 0.35 : voiceListening ? 1 : 0.75,
1724
1883
  lineHeight: 1,
1725
1884
  padding: 0,
1726
1885
  display: "flex",
@@ -1730,7 +1889,7 @@ function ChatWidget(props) {
1730
1889
  alignSelf: "center",
1731
1890
  transition: "opacity 120ms ease, background 120ms ease, color 120ms ease"
1732
1891
  },
1733
- children: "\u{1F399}\uFE0F"
1892
+ children: /* @__PURE__ */ jsx(IconMic, { size: 16 })
1734
1893
  }
1735
1894
  ),
1736
1895
  /* @__PURE__ */ jsx(
@@ -1810,7 +1969,7 @@ function ChatWidget(props) {
1810
1969
  ]
1811
1970
  }
1812
1971
  ) }),
1813
- showBranding && /* @__PURE__ */ jsxs(
1972
+ showBranding && /* @__PURE__ */ jsx(
1814
1973
  "a",
1815
1974
  {
1816
1975
  className: "chatbotlite-brand",
@@ -1829,10 +1988,10 @@ function ChatWidget(props) {
1829
1988
  letterSpacing: "0.01em",
1830
1989
  transition: "color 120ms ease"
1831
1990
  },
1832
- children: [
1833
- BOLT,
1834
- " Powered by chatbotlite"
1835
- ]
1991
+ children: /* @__PURE__ */ jsxs("span", { style: { display: "inline-flex", alignItems: "center", gap: 5 }, children: [
1992
+ /* @__PURE__ */ jsx(IconBolt, { size: 11 }),
1993
+ "Powered by chatbotlite"
1994
+ ] })
1836
1995
  }
1837
1996
  )
1838
1997
  ]