chatbotlite 0.5.1 → 0.6.0

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.
@@ -3,6 +3,18 @@ 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;
@@ -1009,26 +1021,82 @@ function RequestPayment(props) {
1009
1021
  ] })
1010
1022
  ] });
1011
1023
  }
1012
- var BOLT = "\u26A1";
1013
1024
  var DEFAULT_PRIMARY = "#0f172a";
1014
1025
  var DEFAULT_ON_PRIMARY = "#ffffff";
1015
- var SURFACE = "#ffffff";
1016
- var CHAT_BG = "#f5f1eb";
1017
- var BUBBLE_BOT = "#ffffff";
1018
- var INPUT_BG = "#f1f3f5";
1019
- var BORDER = "#e5e7eb";
1020
- var BORDER_LIGHT = "rgba(15,23,42,0.06)";
1021
- var TEXT_BODY = "#0f172a";
1022
- var TEXT_MUTED = "#64748b";
1023
- var TEXT_FAINT = "#94a3b8";
1024
- var FONT_STACK = `-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif`;
1026
+ 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" }) });
1027
+ 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: [
1028
+ /* @__PURE__ */ jsx("rect", { x: "9", y: "3", width: "6", height: "12", rx: "3" }),
1029
+ /* @__PURE__ */ jsx("path", { d: "M5 11a7 7 0 0 0 14 0M12 19v3" })
1030
+ ] });
1031
+ 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" }) });
1032
+ var SURFACE = "var(--cbl-bg)";
1033
+ var CHAT_BG = "var(--cbl-bg-chat)";
1034
+ var BUBBLE_BOT = "var(--cbl-bg-elevated)";
1035
+ var INPUT_BG = "var(--cbl-bg-sunken)";
1036
+ var BORDER = "var(--cbl-border)";
1037
+ var BORDER_LIGHT = "var(--cbl-border-light)";
1038
+ var TEXT_BODY = "var(--cbl-text)";
1039
+ var TEXT_MUTED = "var(--cbl-text-muted)";
1040
+ var TEXT_FAINT = "var(--cbl-text-faint)";
1041
+ var FONT_STACK = "var(--cbl-font)";
1025
1042
  var STYLE_TAG_ID = "chatbotlite-widget-styles";
1043
+ var TOKENS = `
1044
+ :where(.chatbotlite-root) {
1045
+ --cbl-bg: #FFFFFF;
1046
+ --cbl-bg-elevated: #FFFFFF;
1047
+ --cbl-bg-chat: #F7F8FA;
1048
+ --cbl-bg-sunken: #F1F3F5;
1049
+ --cbl-border: #E5E7EB;
1050
+ --cbl-border-strong: #D1D5DB;
1051
+ --cbl-border-light: rgba(15,23,42,0.06);
1052
+ --cbl-text: #0F172A;
1053
+ --cbl-text-muted: #64748B;
1054
+ --cbl-text-faint: #94A3B8;
1055
+ --cbl-success: #10B981;
1056
+ --cbl-danger: #EF4444;
1057
+ --cbl-font: -apple-system, BlinkMacSystemFont, "Inter", "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", system-ui, sans-serif;
1058
+ --cbl-ease-out: cubic-bezier(0.16, 1, 0.3, 1);
1059
+ --cbl-ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
1060
+ --cbl-ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
1061
+ --cbl-shadow-1: 0 1px 2px rgba(15,23,42,0.04);
1062
+ --cbl-shadow-2: 0 4px 12px rgba(15,23,42,0.06), 0 1px 2px rgba(15,23,42,0.04);
1063
+ --cbl-shadow-3: 0 10px 32px rgba(15,23,42,0.10), 0 2px 6px rgba(15,23,42,0.04);
1064
+ --cbl-shadow-4: 0 20px 48px rgba(15,23,42,0.18), 0 4px 12px rgba(15,23,42,0.08);
1065
+ }
1066
+ @media (prefers-color-scheme: dark) {
1067
+ :where(.chatbotlite-root[data-color-scheme="auto"]),
1068
+ :where(.chatbotlite-root[data-color-scheme="dark"]) {
1069
+ --cbl-bg: #16181D;
1070
+ --cbl-bg-elevated: #1F2228;
1071
+ --cbl-bg-chat: #0B0D10;
1072
+ --cbl-bg-sunken: #1F2228;
1073
+ --cbl-border: #24272E;
1074
+ --cbl-border-strong: #2E323A;
1075
+ --cbl-border-light: rgba(255,255,255,0.06);
1076
+ --cbl-text: #ECEDEE;
1077
+ --cbl-text-muted: #9BA1A6;
1078
+ --cbl-text-faint: #6B7177;
1079
+ }
1080
+ }
1081
+ :where(.chatbotlite-root[data-color-scheme="light"]) {
1082
+ --cbl-bg: #FFFFFF;
1083
+ --cbl-bg-elevated: #FFFFFF;
1084
+ --cbl-bg-chat: #F7F8FA;
1085
+ --cbl-bg-sunken: #F1F3F5;
1086
+ --cbl-border: #E5E7EB;
1087
+ --cbl-border-strong: #D1D5DB;
1088
+ --cbl-border-light: rgba(15,23,42,0.06);
1089
+ --cbl-text: #0F172A;
1090
+ --cbl-text-muted: #64748B;
1091
+ --cbl-text-faint: #94A3B8;
1092
+ }
1093
+ `;
1026
1094
  var KEYFRAMES = `
1027
1095
  @keyframes chatbotlite-pop { 0% { opacity: 0; transform: scale(0.6); } 100% { opacity: 1; transform: scale(1); } }
1028
1096
  @keyframes chatbotlite-slide { 0% { opacity: 0; transform: translateY(16px) scale(0.98); } 100% { opacity: 1; transform: translateY(0) scale(1); } }
1029
1097
  @keyframes chatbotlite-fade-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: translateY(0); } }
1030
1098
  @keyframes chatbotlite-dot { 0%, 60%, 100% { transform: translateY(0); opacity: 0.4; } 30% { transform: translateY(-4px); opacity: 1; } }
1031
- @keyframes chatbotlite-cursor { 0%, 50% { opacity: 1; } 51%, 100% { opacity: 0; } }
1099
+ @keyframes chatbotlite-cursor { 0%, 50% { opacity: 1; } 51%, 100% { opacity: 0.2; } }
1032
1100
  @keyframes chatbotlite-pulse { 0%, 100% { box-shadow: 0 12px 28px -8px rgba(15,23,42,0.32), 0 4px 8px -2px rgba(15,23,42,0.12); } 50% { box-shadow: 0 14px 32px -8px rgba(15,23,42,0.36), 0 6px 12px -2px rgba(15,23,42,0.16); } }
1033
1101
  .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; }
1034
1102
  .chatbotlite-launcher:hover { transform: translateY(-2px) scale(1.04); }
@@ -1038,10 +1106,12 @@ var KEYFRAMES = `
1038
1106
  .chatbotlite-send { transition: transform 120ms ease, opacity 120ms ease, box-shadow 120ms ease; }
1039
1107
  .chatbotlite-send:not(:disabled):hover { transform: translateY(-1px); }
1040
1108
  .chatbotlite-send:not(:disabled):active { transform: translateY(0); }
1041
- .chatbotlite-input:focus { box-shadow: 0 0 0 3px rgba(15,23,42,0.06); }
1109
+ .chatbotlite-input:focus { box-shadow: none; outline: none; }
1110
+ .chatbotlite-composer { transition: background 120ms ease, box-shadow 120ms ease; }
1111
+ .chatbotlite-composer:focus-within { background: ${SURFACE}; box-shadow: 0 0 0 1px ${BORDER}, 0 1px 2px rgba(15,23,42,0.04); }
1042
1112
  .chatbotlite-msg { animation: chatbotlite-fade-in 220ms cubic-bezier(0.4, 0, 0.2, 1); }
1043
1113
  .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; }
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; }
1114
+ .chatbotlite-cursor { display: inline-block; width: 0.5ch; vertical-align: text-bottom; margin-left: 1px; font-size: inherit; line-height: inherit; animation: chatbotlite-cursor 1s ease-in-out infinite; }
1045
1115
  .chatbotlite-icon-btn:hover:not(:disabled) { background: rgba(15,23,42,0.06) !important; opacity: 1 !important; }
1046
1116
  .chatbotlite-icon-btn:active:not(:disabled) { transform: scale(0.92); }
1047
1117
  .chatbotlite-dot:nth-child(2) { animation-delay: 0.15s; }
@@ -1053,7 +1123,7 @@ function ensureStyles() {
1053
1123
  if (document.getElementById(STYLE_TAG_ID)) return;
1054
1124
  const style = document.createElement("style");
1055
1125
  style.id = STYLE_TAG_ID;
1056
- style.textContent = KEYFRAMES;
1126
+ style.textContent = TOKENS + KEYFRAMES;
1057
1127
  document.head.appendChild(style);
1058
1128
  }
1059
1129
  function ChatWidget(props) {
@@ -1069,7 +1139,8 @@ function ChatWidget(props) {
1069
1139
  const resolvedTitle = title ?? "Chat";
1070
1140
  const resolvedGreeting = greeting ?? "Hi! How can we help?";
1071
1141
  const primary = themeOverrides?.primary ?? DEFAULT_PRIMARY;
1072
- const onPrimary = themeOverrides?.onPrimary ?? DEFAULT_ON_PRIMARY;
1142
+ const primaryIsLight = luminance(primary) > 0.65;
1143
+ const onPrimary = themeOverrides?.onPrimary ?? (primaryIsLight ? "#0f172a" : DEFAULT_ON_PRIMARY);
1073
1144
  const attachCfg = props.attach;
1074
1145
  const attachEnabled = attachCfg?.enabled === true;
1075
1146
  const acceptAttr = attachCfg?.accept?.join(",");
@@ -1205,7 +1276,12 @@ function ChatWidget(props) {
1205
1276
  body = JSON.stringify({ message: text, transcript: history, enabledTools });
1206
1277
  }
1207
1278
  const res = await fetch(props.endpoint, { method: "POST", headers, body });
1208
- if (!res.ok) throw new Error(`Endpoint ${res.status}: ${await res.text().catch(() => "")}`);
1279
+ if (!res.ok) {
1280
+ const raw = await res.text().catch(() => "");
1281
+ const looksLikeHtml = /^\s*<(!doctype|html|head|body)/i.test(raw);
1282
+ const snippet = looksLikeHtml ? "" : raw.slice(0, 120).replace(/\s+/g, " ").trim();
1283
+ throw new Error(`Server returned ${res.status}${snippet ? ` \u2014 ${snippet}` : ""}`);
1284
+ }
1209
1285
  const contentType = res.headers.get("Content-Type") ?? "";
1210
1286
  if (contentType.includes("text/event-stream") && res.body) {
1211
1287
  const reader = res.body.getReader();
@@ -1307,10 +1383,13 @@ function ChatWidget(props) {
1307
1383
  !open && /* @__PURE__ */ jsx(
1308
1384
  "button",
1309
1385
  {
1310
- className: "chatbotlite-launcher",
1386
+ className: "chatbotlite-root chatbotlite-launcher",
1387
+ "data-color-scheme": "auto",
1311
1388
  onClick: () => setOpen(true),
1312
1389
  "aria-label": "Open chat",
1313
1390
  style: {
1391
+ ["--cbl-primary"]: primary,
1392
+ ["--cbl-on-primary"]: onPrimary,
1314
1393
  position: "fixed",
1315
1394
  bottom: 20,
1316
1395
  ...launcherPos,
@@ -1330,15 +1409,24 @@ function ChatWidget(props) {
1330
1409
  alignItems: "center",
1331
1410
  justifyContent: "center"
1332
1411
  },
1333
- children: /* @__PURE__ */ jsx("span", { style: { filter: "drop-shadow(0 1px 2px rgba(0,0,0,0.2))" }, children: BOLT })
1412
+ children: props.launcherIcon ? props.launcherIcon.startsWith("http") || props.launcherIcon.startsWith("/") ? /* @__PURE__ */ jsx("img", { src: props.launcherIcon, alt: "", style: { width: 28, height: 28, objectFit: "contain" } }) : /* @__PURE__ */ jsx("span", { style: { filter: "drop-shadow(0 1px 2px rgba(0,0,0,0.2))" }, children: props.launcherIcon }) : /* @__PURE__ */ jsxs("svg", { width: "26", height: "26", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
1413
+ /* @__PURE__ */ jsx("path", { d: "M21 12a8 8 0 0 1-13.6 5.8L3 19l1.2-4.4A8 8 0 1 1 21 12z" }),
1414
+ /* @__PURE__ */ jsx("circle", { cx: "9", cy: "12", r: "1", fill: "currentColor", stroke: "none" }),
1415
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "1", fill: "currentColor", stroke: "none" }),
1416
+ /* @__PURE__ */ jsx("circle", { cx: "15", cy: "12", r: "1", fill: "currentColor", stroke: "none" })
1417
+ ] })
1334
1418
  }
1335
1419
  ),
1336
1420
  open && /* @__PURE__ */ jsxs(
1337
1421
  "div",
1338
1422
  {
1423
+ className: "chatbotlite-root",
1424
+ "data-color-scheme": "auto",
1339
1425
  role: "dialog",
1340
1426
  "aria-label": "Chat",
1341
1427
  style: {
1428
+ ["--cbl-primary"]: primary,
1429
+ ["--cbl-on-primary"]: onPrimary,
1342
1430
  position: "fixed",
1343
1431
  bottom: 20,
1344
1432
  ...panelPos,
@@ -1368,24 +1456,39 @@ function ChatWidget(props) {
1368
1456
  gap: 12,
1369
1457
  borderBottom: `1px solid ${BORDER_LIGHT}`
1370
1458
  }, children: [
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,
1459
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: props.avatar ? 10 : 0, minWidth: 0 }, children: [
1460
+ props.avatar === true && /* @__PURE__ */ jsx("div", { style: {
1461
+ width: 32,
1462
+ height: 32,
1375
1463
  borderRadius: "50%",
1376
1464
  background: primary,
1377
1465
  color: onPrimary,
1378
1466
  display: "flex",
1379
1467
  alignItems: "center",
1380
1468
  justifyContent: "center",
1381
- fontSize: 16,
1469
+ fontSize: 14,
1382
1470
  fontWeight: 600,
1383
1471
  flexShrink: 0,
1384
1472
  letterSpacing: "-0.02em"
1385
1473
  }, children: resolvedTitle.charAt(0).toUpperCase() }),
1474
+ typeof props.avatar === "string" && /* @__PURE__ */ jsx(
1475
+ "img",
1476
+ {
1477
+ src: props.avatar,
1478
+ alt: "",
1479
+ style: {
1480
+ width: 32,
1481
+ height: 32,
1482
+ borderRadius: "50%",
1483
+ objectFit: "cover",
1484
+ flexShrink: 0,
1485
+ border: `1px solid ${BORDER}`
1486
+ }
1487
+ }
1488
+ ),
1386
1489
  /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", lineHeight: 1.2, minWidth: 0 }, children: [
1387
1490
  /* @__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") })
1491
+ (subtitle || sending) && /* @__PURE__ */ jsx("span", { style: { fontSize: 12, color: TEXT_MUTED, marginTop: 2, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: subtitle ?? (sending ? "typing\u2026" : "") })
1389
1492
  ] })
1390
1493
  ] }),
1391
1494
  /* @__PURE__ */ jsx(
@@ -1434,22 +1537,30 @@ function ChatWidget(props) {
1434
1537
  className: "chatbotlite-msg",
1435
1538
  style: {
1436
1539
  alignSelf: m.role === "user" ? "flex-end" : "flex-start",
1437
- maxWidth: "78%",
1438
- padding: "8px 12px",
1439
- borderRadius: 18,
1540
+ maxWidth: "82%",
1541
+ padding: "9px 13px",
1542
+ borderRadius: m.role === "user" ? "18px 18px 4px 18px" : "18px 18px 18px 4px",
1440
1543
  background: m.role === "user" ? primary : BUBBLE_BOT,
1441
1544
  color: m.role === "user" ? onPrimary : TEXT_BODY,
1442
- border: "none",
1443
- fontSize: 14.5,
1444
- lineHeight: 1.4,
1545
+ border: m.role === "user" ? "none" : `1px solid ${BORDER}`,
1546
+ fontSize: 14,
1547
+ lineHeight: 1.5,
1445
1548
  letterSpacing: "-0.005em",
1446
1549
  whiteSpace: "pre-wrap",
1447
1550
  wordBreak: "break-word",
1448
- boxShadow: m.role === "user" ? "none" : "0 1px 0.5px rgba(15,23,42,0.05)"
1551
+ boxShadow: m.role === "user" ? "0 1px 2px rgba(15,23,42,0.12)" : "0 1px 2px rgba(15,23,42,0.04)"
1449
1552
  },
1450
1553
  children: [
1451
1554
  m.content,
1452
- sending && m.role === "assistant" && m === messages[messages.length - 1] && /* @__PURE__ */ jsx("span", { className: "chatbotlite-cursor", "aria-hidden": "true" })
1555
+ sending && m.role === "assistant" && m === messages[messages.length - 1] && /* @__PURE__ */ jsx(
1556
+ "span",
1557
+ {
1558
+ className: "chatbotlite-cursor",
1559
+ style: { color: primary },
1560
+ "aria-hidden": "true",
1561
+ children: "\u258D"
1562
+ }
1563
+ )
1453
1564
  ]
1454
1565
  }
1455
1566
  ),
@@ -1549,10 +1660,11 @@ function ChatWidget(props) {
1549
1660
  className: "chatbotlite-msg",
1550
1661
  style: {
1551
1662
  alignSelf: "flex-start",
1552
- padding: "10px 14px",
1553
- borderRadius: 18,
1663
+ padding: "12px 14px",
1664
+ borderRadius: "18px 18px 18px 4px",
1554
1665
  background: BUBBLE_BOT,
1555
- boxShadow: "0 1px 0.5px rgba(15,23,42,0.05)"
1666
+ border: `1px solid ${BORDER}`,
1667
+ boxShadow: "0 1px 2px rgba(15,23,42,0.04)"
1556
1668
  },
1557
1669
  children: [
1558
1670
  /* @__PURE__ */ jsx("span", { className: "chatbotlite-dot" }),
@@ -1585,9 +1697,9 @@ function ChatWidget(props) {
1585
1697
  maxWidth: 200
1586
1698
  },
1587
1699
  children: [
1588
- /* @__PURE__ */ jsxs("span", { style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: [
1589
- "\u{1F4CE} ",
1590
- f.name
1700
+ /* @__PURE__ */ jsxs("span", { style: { display: "inline-flex", alignItems: "center", gap: 6, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", color: TEXT_MUTED }, children: [
1701
+ /* @__PURE__ */ jsx(IconPaperclip, { size: 12 }),
1702
+ /* @__PURE__ */ jsx("span", { style: { overflow: "hidden", textOverflow: "ellipsis", color: TEXT_BODY }, children: f.name })
1591
1703
  ] }),
1592
1704
  /* @__PURE__ */ jsx(
1593
1705
  "button",
@@ -1605,159 +1717,169 @@ function ChatWidget(props) {
1605
1717
  /* @__PURE__ */ jsx("div", { style: {
1606
1718
  padding: "10px 12px 12px",
1607
1719
  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: [
1618
- /* @__PURE__ */ jsx(
1619
- "input",
1620
- {
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 = "";
1720
+ }, children: /* @__PURE__ */ jsxs(
1721
+ "div",
1722
+ {
1723
+ className: "chatbotlite-composer",
1724
+ style: {
1725
+ display: "flex",
1726
+ alignItems: "center",
1727
+ gap: 4,
1728
+ padding: "4px 4px 4px 8px",
1729
+ background: INPUT_BG,
1730
+ borderRadius: 999
1731
+ },
1732
+ children: [
1733
+ attachEnabled && /* @__PURE__ */ jsxs(Fragment, { children: [
1734
+ /* @__PURE__ */ jsx(
1735
+ "input",
1736
+ {
1737
+ ref: fileInputRef,
1738
+ type: "file",
1739
+ multiple: true,
1740
+ accept: acceptAttr,
1741
+ style: { display: "none" },
1742
+ onChange: (e) => {
1743
+ if (e.target.files) addFiles(e.target.files);
1744
+ e.target.value = "";
1745
+ }
1746
+ }
1747
+ ),
1748
+ /* @__PURE__ */ jsx(
1749
+ "button",
1750
+ {
1751
+ className: "chatbotlite-icon-btn",
1752
+ onClick: () => fileInputRef.current?.click(),
1753
+ disabled: sending || files.length >= maxFiles,
1754
+ "aria-label": "Attach file",
1755
+ style: {
1756
+ width: 32,
1757
+ height: 32,
1758
+ borderRadius: "50%",
1759
+ background: "transparent",
1760
+ border: "none",
1761
+ cursor: sending || files.length >= maxFiles ? "default" : "pointer",
1762
+ opacity: sending || files.length >= maxFiles ? 0.35 : 0.75,
1763
+ color: TEXT_MUTED,
1764
+ lineHeight: 1,
1765
+ padding: 0,
1766
+ display: "flex",
1767
+ alignItems: "center",
1768
+ justifyContent: "center",
1769
+ flexShrink: 0,
1770
+ alignSelf: "center",
1771
+ transition: "opacity 120ms ease, background 120ms ease"
1772
+ },
1773
+ children: /* @__PURE__ */ jsx(IconPaperclip, { size: 18 })
1774
+ }
1775
+ )
1776
+ ] }),
1777
+ voiceEnabled && speechSupported && /* @__PURE__ */ jsx(
1778
+ "button",
1779
+ {
1780
+ className: "chatbotlite-icon-btn",
1781
+ onClick: toggleVoice,
1782
+ disabled: sending,
1783
+ "aria-label": voiceListening ? "Stop recording" : "Start voice input",
1784
+ style: {
1785
+ width: 32,
1786
+ height: 32,
1787
+ borderRadius: "50%",
1788
+ background: voiceListening ? primary : "transparent",
1789
+ color: voiceListening ? onPrimary : "inherit",
1790
+ border: "none",
1791
+ cursor: sending ? "default" : "pointer",
1792
+ opacity: sending ? 0.35 : voiceListening ? 1 : 0.75,
1793
+ lineHeight: 1,
1794
+ padding: 0,
1795
+ display: "flex",
1796
+ alignItems: "center",
1797
+ justifyContent: "center",
1798
+ flexShrink: 0,
1799
+ alignSelf: "center",
1800
+ transition: "opacity 120ms ease, background 120ms ease, color 120ms ease"
1801
+ },
1802
+ children: /* @__PURE__ */ jsx(IconMic, { size: 16 })
1629
1803
  }
1630
- }
1631
- ),
1632
- /* @__PURE__ */ jsx(
1633
- "button",
1634
- {
1635
- className: "chatbotlite-icon-btn",
1636
- onClick: () => fileInputRef.current?.click(),
1637
- disabled: sending || files.length >= maxFiles,
1638
- "aria-label": "Attach file",
1639
- style: {
1640
- width: 32,
1641
- height: 32,
1642
- borderRadius: "50%",
1643
- background: "transparent",
1644
- border: "none",
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"
1656
- },
1657
- children: "\u{1F4CE}"
1658
- }
1659
- )
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();
1804
+ ),
1805
+ /* @__PURE__ */ jsx(
1806
+ "textarea",
1807
+ {
1808
+ ref: inputRef,
1809
+ className: "chatbotlite-input",
1810
+ rows: 1,
1811
+ value: input,
1812
+ onChange: (e) => {
1813
+ setInput(e.target.value);
1814
+ const el = e.currentTarget;
1815
+ el.style.height = "20px";
1816
+ if (el.scrollHeight > 28) {
1817
+ el.style.height = Math.min(el.scrollHeight, 100) + "px";
1818
+ }
1819
+ },
1820
+ onKeyDown: (e) => {
1821
+ if (e.key === "Enter" && !e.shiftKey) {
1822
+ e.preventDefault();
1823
+ void send();
1824
+ }
1825
+ },
1826
+ placeholder: "Message",
1827
+ disabled: sending,
1828
+ style: {
1829
+ flex: 1,
1830
+ padding: "4px 6px",
1831
+ margin: 0,
1832
+ border: "none",
1833
+ background: "transparent",
1834
+ fontSize: 14,
1835
+ fontFamily: FONT_STACK,
1836
+ color: TEXT_BODY,
1837
+ outline: "none",
1838
+ resize: "none",
1839
+ lineHeight: 1.4,
1840
+ height: 20,
1841
+ maxHeight: 100,
1842
+ boxSizing: "content-box",
1843
+ overflow: "hidden"
1844
+ }
1707
1845
  }
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
- ] }) }),
1760
- showBranding && /* @__PURE__ */ jsxs(
1846
+ ),
1847
+ /* @__PURE__ */ jsx(
1848
+ "button",
1849
+ {
1850
+ className: "chatbotlite-send",
1851
+ onClick: () => void send(),
1852
+ disabled: sending || !input.trim() && files.length === 0,
1853
+ "aria-label": "Send message",
1854
+ style: {
1855
+ width: 34,
1856
+ height: 34,
1857
+ borderRadius: "50%",
1858
+ background: primary,
1859
+ color: onPrimary,
1860
+ border: "none",
1861
+ fontSize: 14,
1862
+ fontWeight: 600,
1863
+ fontFamily: FONT_STACK,
1864
+ cursor: sending || !input.trim() && files.length === 0 ? "default" : "pointer",
1865
+ opacity: sending || !input.trim() && files.length === 0 ? 0.35 : 1,
1866
+ display: "flex",
1867
+ alignItems: "center",
1868
+ justifyContent: "center",
1869
+ flexShrink: 0,
1870
+ padding: 0,
1871
+ transition: "opacity 120ms ease, transform 80ms ease"
1872
+ },
1873
+ 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: [
1874
+ /* @__PURE__ */ jsx("line", { x1: "12", y1: "19", x2: "12", y2: "5" }),
1875
+ /* @__PURE__ */ jsx("polyline", { points: "5 12 12 5 19 12" })
1876
+ ] })
1877
+ }
1878
+ )
1879
+ ]
1880
+ }
1881
+ ) }),
1882
+ showBranding && /* @__PURE__ */ jsx(
1761
1883
  "a",
1762
1884
  {
1763
1885
  className: "chatbotlite-brand",
@@ -1776,10 +1898,10 @@ function ChatWidget(props) {
1776
1898
  letterSpacing: "0.01em",
1777
1899
  transition: "color 120ms ease"
1778
1900
  },
1779
- children: [
1780
- BOLT,
1781
- " Powered by chatbotlite"
1782
- ]
1901
+ children: /* @__PURE__ */ jsxs("span", { style: { display: "inline-flex", alignItems: "center", gap: 5 }, children: [
1902
+ /* @__PURE__ */ jsx(IconBolt, { size: 11 }),
1903
+ "Powered by chatbotlite"
1904
+ ] })
1783
1905
  }
1784
1906
  )
1785
1907
  ]