@akropolys/kiku 1.6.8 → 1.6.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1157,6 +1157,7 @@ var ArrowUpIcon2 = () => /* @__PURE__ */ jsxs6("svg", { width: "18", height: "18
1157
1157
  /* @__PURE__ */ jsx7("path", { d: "m5 12 7-7 7 7" }),
1158
1158
  /* @__PURE__ */ jsx7("path", { d: "M12 19V5" })
1159
1159
  ] });
1160
+ var StopIcon = () => /* @__PURE__ */ jsx7("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx7("rect", { x: "5", y: "5", width: "14", height: "14", rx: "2" }) });
1160
1161
  var CloseIcon = () => /* @__PURE__ */ jsxs6("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
1161
1162
  /* @__PURE__ */ jsx7("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
1162
1163
  /* @__PURE__ */ jsx7("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
@@ -1167,7 +1168,6 @@ var HistoryIcon = () => /* @__PURE__ */ jsxs6("svg", { width: "16", height: "16"
1167
1168
  /* @__PURE__ */ jsx7("path", { d: "M3 3v5h5" }),
1168
1169
  /* @__PURE__ */ jsx7("path", { d: "M12 7v5l4 2" })
1169
1170
  ] });
1170
- var NewChatIcon = () => /* @__PURE__ */ jsx7("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx7("path", { d: "M12 5v14M5 12h14" }) });
1171
1171
  var BookmarkIcon = () => /* @__PURE__ */ jsx7("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx7("path", { d: "M19 21 12 16l-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z" }) });
1172
1172
  var TrashIcon = () => /* @__PURE__ */ jsxs6("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1173
1173
  /* @__PURE__ */ jsx7("path", { d: "M3 6h18" }),
@@ -1193,8 +1193,6 @@ var DEFAULT_CHIPS = [
1193
1193
  "Noise-cancelling headphones",
1194
1194
  "Best laptop for students"
1195
1195
  ];
1196
- var SESSIONS_KEY = "akropolys_chat_sessions";
1197
- var MAX_SESSIONS = 20;
1198
1196
  function parseAtKiku(raw) {
1199
1197
  const trimmed = raw.trim();
1200
1198
  if (!/^@kiku\b/i.test(trimmed)) return null;
@@ -1347,33 +1345,7 @@ function AtPickerMenu({ onSelect, onDismiss }) {
1347
1345
  }
1348
1346
  );
1349
1347
  }
1350
- function loadSessions() {
1351
- try {
1352
- if (typeof window === "undefined") return [];
1353
- const raw = localStorage.getItem(SESSIONS_KEY);
1354
- return raw ? JSON.parse(raw) : [];
1355
- } catch {
1356
- return [];
1357
- }
1358
- }
1359
- function saveSessions(sessions) {
1360
- try {
1361
- if (typeof window === "undefined") return;
1362
- localStorage.setItem(SESSIONS_KEY, JSON.stringify(sessions.slice(0, MAX_SESSIONS)));
1363
- } catch {
1364
- }
1365
- }
1366
- function relativeTime(ts) {
1367
- const diff = Date.now() - ts;
1368
- const mins = Math.floor(diff / 6e4);
1369
- if (mins < 1) return "just now";
1370
- if (mins < 60) return `${mins}m ago`;
1371
- const hrs = Math.floor(mins / 60);
1372
- if (hrs < 24) return `${hrs}h ago`;
1373
- const days = Math.floor(hrs / 24);
1374
- return `${days}d ago`;
1375
- }
1376
- function SourcesCarousel({ sources, defaultCurrency, onSelectSource, referencedIds = [] }) {
1348
+ function SourcesCarousel({ sources, defaultCurrency, onSelectSource, onImageClick, referencedIds = [] }) {
1377
1349
  const client = useAkropolysContext3();
1378
1350
  const isProperty = client?.vertical === "property";
1379
1351
  const railRef = useRef5(null);
@@ -1412,7 +1384,18 @@ function SourcesCarousel({ sources, defaultCurrency, onSelectSource, referencedI
1412
1384
  onClick: () => onSelectSource?.(src),
1413
1385
  children: [
1414
1386
  src.image ? /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-src-imgwrap", style: { position: "relative" }, children: [
1415
- /* @__PURE__ */ jsx7("img", { src: src.image, alt: src.name, loading: "lazy" }),
1387
+ /* @__PURE__ */ jsx7(
1388
+ "img",
1389
+ {
1390
+ src: src.image,
1391
+ alt: src.name,
1392
+ loading: "lazy",
1393
+ onClick: onImageClick ? (e) => {
1394
+ e.stopPropagation();
1395
+ onImageClick(src.image);
1396
+ } : void 0
1397
+ }
1398
+ ),
1416
1399
  isReferenced && /* @__PURE__ */ jsx7("div", { className: "hsk-cb-source-ref-badge", title: "Featured in response", children: /* @__PURE__ */ jsx7(SparkleIcon2, { size: 10 }) }),
1417
1400
  isProperty && /* @__PURE__ */ jsx7("div", { style: {
1418
1401
  position: "absolute",
@@ -1685,7 +1668,7 @@ function ChatModal({
1685
1668
  visionCategoryHint
1686
1669
  }) {
1687
1670
  const client = useAkropolysContext3();
1688
- const { messages, sources, loading, streaming, error, lastAction, lastIntent, send, reset, referencedIds } = useKiku2();
1671
+ const { messages, sources, loading, streaming, error, lastAction, lastIntent, send, stop, reset, referencedIds } = useKiku2();
1689
1672
  const [input, setInput] = useState5("");
1690
1673
  const [attachments, setAttachments] = useState5([]);
1691
1674
  const imageInputRef = useRef5(null);
@@ -1760,6 +1743,7 @@ function ChatModal({
1760
1743
  const activeTitle = title === "Shopping Assistant" && isProperty ? "Property Assistant" : title;
1761
1744
  const activePlaceholder = placeholder === "Ask me anything \u2014 gifts, budget, use case\u2026" && isProperty ? "Ask me anything \u2014 location, budget, bedrooms\u2026" : placeholder;
1762
1745
  const [selectedProduct, setSelectedProduct] = useState5(null);
1746
+ const [lightboxSrc, setLightboxSrc] = useState5(null);
1763
1747
  const bottomRef = useRef5(null);
1764
1748
  const textareaRef = useRef5(null);
1765
1749
  const [keyInput, setKeyInput] = useState5("");
@@ -1769,9 +1753,6 @@ function ChatModal({
1769
1753
  const [minting, setMinting] = useState5(false);
1770
1754
  const [showKikuPicker, setShowKikuPicker] = useState5(false);
1771
1755
  const [showAtPicker, setShowAtPicker] = useState5(false);
1772
- const [sessions, setSessions] = useState5(() => loadSessions());
1773
- const [sidebarOpen, setSidebarOpen] = useState5(false);
1774
- const [replayMessages, setReplayMessages] = useState5(null);
1775
1756
  useEffect3(() => {
1776
1757
  if (!lastAction) return;
1777
1758
  if (lastAction.type === "request_kiku_key") {
@@ -1828,9 +1809,15 @@ function ChatModal({
1828
1809
  }
1829
1810
  };
1830
1811
  const msgsContainerRef = useRef5(null);
1812
+ const messageRefs = useRef5([]);
1831
1813
  useEffect3(() => {
1832
1814
  const container = msgsContainerRef.current;
1833
1815
  if (!container) return;
1816
+ const lastMsg = messages[messages.length - 1];
1817
+ if (lastMsg?.role === "user") {
1818
+ messageRefs.current[messages.length - 1]?.scrollIntoView({ behavior: "smooth", block: "start" });
1819
+ return;
1820
+ }
1834
1821
  const distanceFromBottom = container.scrollHeight - container.scrollTop - container.clientHeight;
1835
1822
  if (distanceFromBottom < 120) {
1836
1823
  bottomRef.current?.scrollIntoView({ behavior: "smooth" });
@@ -1838,30 +1825,20 @@ function ChatModal({
1838
1825
  }, [messages, loading, selectedProduct]);
1839
1826
  useEffect3(() => {
1840
1827
  const h = (e) => {
1841
- if (e.key === "Escape") onClose();
1828
+ if (e.key !== "Escape") return;
1829
+ if (lightboxSrc) {
1830
+ setLightboxSrc(null);
1831
+ return;
1832
+ }
1833
+ onClose();
1842
1834
  };
1843
1835
  document.addEventListener("keydown", h);
1844
1836
  return () => document.removeEventListener("keydown", h);
1845
- }, []);
1846
- const saveCurrentSession = useCallback2(() => {
1847
- if (messages.length < 2) return;
1848
- const firstUser = messages.find((m) => m.role === "user");
1849
- const session = {
1850
- id: `session_${Date.now()}`,
1851
- title: firstUser ? firstUser.content.slice(0, 60) : "Chat session",
1852
- messages,
1853
- ts: Date.now()
1854
- };
1855
- const updated = [session, ...sessions].slice(0, MAX_SESSIONS);
1856
- setSessions(updated);
1857
- saveSessions(updated);
1858
- }, [messages, sessions]);
1837
+ }, [lightboxSrc, onClose]);
1859
1838
  const handleReset = useCallback2(() => {
1860
- saveCurrentSession();
1861
1839
  reset();
1862
- setReplayMessages(null);
1863
1840
  setKeyPhase("idle");
1864
- }, [reset, saveCurrentSession]);
1841
+ }, [reset]);
1865
1842
  const handleSourceClick = (src) => {
1866
1843
  setSelectedProduct(src);
1867
1844
  onSelectSource?.(src);
@@ -1874,7 +1851,6 @@ function ChatModal({
1874
1851
  const kiku = parseAtKiku(raw);
1875
1852
  const q = kiku ? kiku.cleanQuery : raw;
1876
1853
  const resolvedForcedIntent = forcedIntent ?? kiku?.intent;
1877
- setReplayMessages(null);
1878
1854
  setSelectedProduct(null);
1879
1855
  setShowKikuPicker(false);
1880
1856
  setShowAtPicker(false);
@@ -1899,7 +1875,6 @@ function ChatModal({
1899
1875
  const display = `@kiku capture${name ? " " + name : ""}`;
1900
1876
  const q = name || "capture current page";
1901
1877
  setInput("");
1902
- setReplayMessages(null);
1903
1878
  setSelectedProduct(null);
1904
1879
  const toSend = attachments;
1905
1880
  setAttachments([]);
@@ -1916,7 +1891,6 @@ function ChatModal({
1916
1891
  const names = products.map((p) => p.name).filter(Boolean).join(", ");
1917
1892
  const display = `@kiku capture all (${products.length} items)`;
1918
1893
  setInput("");
1919
- setReplayMessages(null);
1920
1894
  setSelectedProduct(null);
1921
1895
  setAttachments([]);
1922
1896
  send(names || "capture all", display, void 0, "capture_all", targets);
@@ -1924,7 +1898,6 @@ function ChatModal({
1924
1898
  const handleKikuViewHistory = useCallback2(() => {
1925
1899
  const display = "@kiku what have you saved?";
1926
1900
  setInput("");
1927
- setReplayMessages(null);
1928
1901
  setSelectedProduct(null);
1929
1902
  setAttachments([]);
1930
1903
  send("show my saved items", display, void 0, "view_history");
@@ -1932,7 +1905,6 @@ function ChatModal({
1932
1905
  const handleKikuDelete = useCallback2(() => {
1933
1906
  const display = "@kiku delete this";
1934
1907
  setInput("");
1935
- setReplayMessages(null);
1936
1908
  setSelectedProduct(null);
1937
1909
  setAttachments([]);
1938
1910
  send("delete this", display, void 0, "delete");
@@ -1978,17 +1950,7 @@ function ChatModal({
1978
1950
  return () => clearTimeout(timer);
1979
1951
  }, [voiceState]);
1980
1952
  const blurVal = typeof backdropBlur === "number" ? `${backdropBlur}px` : backdropBlur ?? "20px";
1981
- const displayMessages = replayMessages ?? messages;
1982
- const loadSession = (session) => {
1983
- setReplayMessages(session.messages);
1984
- setSidebarOpen(false);
1985
- };
1986
- const deleteSession = (id, e) => {
1987
- e.stopPropagation();
1988
- const updated = sessions.filter((s) => s.id !== id);
1989
- setSessions(updated);
1990
- saveSessions(updated);
1991
- };
1953
+ const displayMessages = messages;
1992
1954
  return /* @__PURE__ */ jsx7(
1993
1955
  "div",
1994
1956
  {
@@ -2001,326 +1963,298 @@ function ChatModal({
2001
1963
  ...backdropColor ? { background: backdropColor } : {},
2002
1964
  ...customStyles
2003
1965
  },
2004
- children: /* @__PURE__ */ jsxs6("div", { className: cn("hsk-cb-panel hsk-cb-panel--with-sidebar", classNames.panel), onClick: (e) => e.stopPropagation(), children: [
2005
- /* @__PURE__ */ jsxs6("div", { className: cn("hsk-cb-sidebar", sidebarOpen && "hsk-cb-sidebar--open"), children: [
2006
- /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-sidebar-header", children: [
2007
- /* @__PURE__ */ jsx7("span", { className: "hsk-cb-sidebar-title", children: "History" }),
2008
- /* @__PURE__ */ jsxs6(
2009
- "button",
2010
- {
2011
- className: "hsk-cb-sidebar-new",
2012
- onClick: handleReset,
2013
- title: "New chat",
2014
- children: [
2015
- /* @__PURE__ */ jsx7(NewChatIcon, {}),
2016
- /* @__PURE__ */ jsx7("span", { children: "New chat" })
2017
- ]
2018
- }
2019
- )
2020
- ] }),
2021
- /* @__PURE__ */ jsx7("div", { className: "hsk-cb-sidebar-list", children: sessions.length === 0 ? /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-sidebar-empty", children: [
2022
- /* @__PURE__ */ jsx7(HistoryIcon, {}),
2023
- /* @__PURE__ */ jsx7("span", { children: "No history yet" })
2024
- ] }) : sessions.map((session) => /* @__PURE__ */ jsxs6(
2025
- "div",
2026
- {
2027
- className: cn(
2028
- "hsk-cb-sidebar-session",
2029
- replayMessages === session.messages && "hsk-cb-sidebar-session--active"
2030
- ),
2031
- onClick: () => loadSession(session),
2032
- children: [
2033
- /* @__PURE__ */ jsx7("div", { className: "hsk-cb-sidebar-session-title", children: session.title }),
2034
- /* @__PURE__ */ jsx7("div", { className: "hsk-cb-sidebar-session-meta", children: relativeTime(session.ts) }),
2035
- /* @__PURE__ */ jsx7(
2036
- "button",
2037
- {
2038
- className: "hsk-cb-sidebar-session-del",
2039
- onClick: (e) => deleteSession(session.id, e),
2040
- title: "Delete",
2041
- children: "\xD7"
2042
- }
2043
- )
2044
- ]
2045
- },
2046
- session.id
2047
- )) })
2048
- ] }),
2049
- /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-main", children: [
2050
- /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-topbar", children: [
2051
- /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-topbar-left", children: [
2052
- /* @__PURE__ */ jsx7(
2053
- "button",
2054
- {
2055
- className: cn("hsk-cb-sidebar-toggle", sidebarOpen && "hsk-cb-sidebar-toggle--active"),
2056
- onClick: (e) => {
2057
- e.stopPropagation();
2058
- setSidebarOpen((v) => !v);
2059
- },
2060
- "aria-label": "Toggle history",
2061
- children: /* @__PURE__ */ jsx7(HistoryIcon, {})
2062
- }
2063
- ),
2064
- /* @__PURE__ */ jsx7("span", { className: "hsk-cb-topbar-icon", style: { display: "flex", alignItems: "center" }, children: /* @__PURE__ */ jsx7(SparkleIcon2, {}) }),
2065
- /* @__PURE__ */ jsx7("div", { children: /* @__PURE__ */ jsx7("div", { className: "hsk-cb-topbar-title", children: activeTitle }) })
1966
+ children: /* @__PURE__ */ jsxs6(
1967
+ "div",
1968
+ {
1969
+ className: cn("hsk-cb-panel", classNames.panel),
1970
+ onClick: (e) => {
1971
+ e.stopPropagation();
1972
+ const target = e.target;
1973
+ if (target.tagName === "IMG" && (target.classList.contains("hsk-markdown-img") || target.classList.contains("hsk-cb-user-img-thumb"))) {
1974
+ const src = target.src;
1975
+ if (src) setLightboxSrc(src);
1976
+ }
1977
+ },
1978
+ children: [
1979
+ lightboxSrc && /* @__PURE__ */ jsxs6("div", { className: "hsk-lightbox", onClick: () => setLightboxSrc(null), children: [
1980
+ /* @__PURE__ */ jsx7("button", { className: "hsk-lightbox-close", onClick: () => setLightboxSrc(null), "aria-label": "Close image", children: /* @__PURE__ */ jsx7(CloseIcon, {}) }),
1981
+ /* @__PURE__ */ jsx7("img", { src: lightboxSrc, alt: "", className: "hsk-lightbox-img", onClick: (e) => e.stopPropagation() })
2066
1982
  ] }),
2067
- /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-topbar-actions", children: [
2068
- replayMessages ? /* @__PURE__ */ jsx7("button", { className: "hsk-cb-topbar-btn", onClick: () => {
2069
- setReplayMessages(null);
2070
- }, children: "\u2190 Live chat" }) : messages.length > 0 && /* @__PURE__ */ jsx7("button", { className: "hsk-cb-topbar-btn", onClick: handleReset, children: "Clear chat" }),
2071
- /* @__PURE__ */ jsx7("button", { className: "hsk-cb-close", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ jsx7(CloseIcon, {}) })
2072
- ] })
2073
- ] }),
2074
- replayMessages && /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-replay-banner", children: [
2075
- /* @__PURE__ */ jsx7(HistoryIcon, {}),
2076
- /* @__PURE__ */ jsx7("span", { children: "You're viewing a past conversation." }),
2077
- /* @__PURE__ */ jsx7("button", { onClick: () => setReplayMessages(null), children: "Back to chat \u2192" })
2078
- ] }),
2079
- /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-msgs", ref: msgsContainerRef, children: [
2080
- displayMessages.length === 0 ? /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-empty", children: [
2081
- /* @__PURE__ */ jsx7("div", { className: "hsk-cb-empty-icon", style: { display: "flex", alignItems: "center" }, children: /* @__PURE__ */ jsx7(SparkleIcon2, {}) }),
2082
- /* @__PURE__ */ jsx7("div", { className: "hsk-cb-empty-title", children: "Find exactly what you need" }),
2083
- /* @__PURE__ */ jsx7("div", { className: "hsk-cb-chips", children: activeChips.map((chip) => /* @__PURE__ */ jsx7(
2084
- "button",
2085
- {
2086
- className: "hsk-cb-chip",
2087
- onClick: () => handleSend(chip),
2088
- children: chip
2089
- },
2090
- chip
2091
- )) })
2092
- ] }) : displayMessages.map((msg, idx) => {
2093
- const isLast = idx === displayMessages.length - 1 && !replayMessages;
2094
- const isUser = msg.role === "user";
2095
- const displayContent = !isUser && isLast && lastIntent === "compare" && sources.length >= 2 && !replayMessages ? stripMarkdownTables(msg.content) : msg.content;
2096
- return /* @__PURE__ */ jsx7("div", { className: "hsk-cb-msg-group", children: isUser ? /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-user-msg", children: [
2097
- msg.images && msg.images.length > 0 && /* @__PURE__ */ jsx7("div", { className: "hsk-cb-user-imgs", children: msg.images.map((img, i) => /* @__PURE__ */ jsx7("img", { src: img, alt: `attachment ${i + 1}`, className: "hsk-cb-user-img-thumb" }, i)) }),
2098
- msg.content && /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-user-bubble", children: [
2099
- /^@kiku\b/i.test(msg.content) && /* @__PURE__ */ jsx7("span", { className: "hsk-kiku-badge", children: "@kiku" }),
2100
- msg.content
1983
+ /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-main", children: [
1984
+ /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-topbar", children: [
1985
+ /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-topbar-left", children: [
1986
+ /* @__PURE__ */ jsx7("span", { className: "hsk-cb-topbar-icon", style: { display: "flex", alignItems: "center" }, children: /* @__PURE__ */ jsx7(SparkleIcon2, {}) }),
1987
+ /* @__PURE__ */ jsx7("div", { children: /* @__PURE__ */ jsx7("div", { className: "hsk-cb-topbar-title", children: activeTitle }) })
1988
+ ] }),
1989
+ /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-topbar-actions", children: [
1990
+ messages.length > 0 && /* @__PURE__ */ jsx7("button", { className: "hsk-cb-topbar-btn", onClick: handleReset, children: "Clear chat" }),
1991
+ /* @__PURE__ */ jsx7("button", { className: "hsk-cb-close", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ jsx7(CloseIcon, {}) })
2101
1992
  ] })
2102
- ] }) : /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-ai-msg", children: [
2103
- /* @__PURE__ */ jsx7("div", { className: "hsk-cb-ai-icon", style: { display: "flex", alignItems: "center" }, children: /* @__PURE__ */ jsx7(SparkleIcon2, {}) }),
2104
- /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-ai-body", children: [
2105
- (() => {
2106
- const { thinking, content, isComplete } = parseThinking(displayContent);
2107
- return /* @__PURE__ */ jsxs6(Fragment3, { children: [
2108
- thinking && /* @__PURE__ */ jsx7(ThinkingBlock, { text: thinking, isComplete }),
2109
- content && /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-ai-text", children: [
2110
- renderMarkdown(content),
2111
- isLast && streaming && /* @__PURE__ */ jsx7("span", { style: { display: "inline-block", width: "0.5em", height: "1.05em", marginLeft: "2px", verticalAlign: "text-bottom", background: "currentColor", opacity: 0.55, borderRadius: "1px" } })
2112
- ] })
2113
- ] });
2114
- })(),
2115
- isLast && lastIntent === "compare" && sources.length >= 2 && !replayMessages && /* @__PURE__ */ jsx7(ComparisonMatrix, { sources, defaultCurrency }),
2116
- isLast && referencedIds.length > 0 && lastIntent !== "compare" && lastAction?.type !== "request_kiku_key" && lastAction?.type !== "capture" && lastAction?.type !== "delete" && lastAction?.type !== "view_history" && /* @__PURE__ */ jsx7(
2117
- SourcesCarousel,
2118
- {
2119
- sources,
2120
- defaultCurrency,
2121
- onSelectSource: handleSourceClick,
2122
- referencedIds
2123
- }
2124
- ),
2125
- isLast && !loading && lastAction?.url && /* @__PURE__ */ jsx7("div", { className: "hsk-action-pills", children: /* @__PURE__ */ jsxs6("a", { className: "hsk-action-pill", href: lastAction.url, children: [
2126
- String(lastAction.type || "continue").replace(/_/g, " "),
2127
- " \u2192"
2128
- ] }) }),
2129
- isLast && !loading && !replayMessages && /* @__PURE__ */ jsx7(
2130
- SmartContextPills,
1993
+ ] }),
1994
+ /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-msgs", ref: msgsContainerRef, children: [
1995
+ displayMessages.length === 0 ? /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-empty", children: [
1996
+ /* @__PURE__ */ jsx7("div", { className: "hsk-cb-empty-icon", style: { display: "flex", alignItems: "center" }, children: /* @__PURE__ */ jsx7(SparkleIcon2, {}) }),
1997
+ /* @__PURE__ */ jsx7("div", { className: "hsk-cb-empty-title", children: "Find exactly what you need" }),
1998
+ /* @__PURE__ */ jsx7("div", { className: "hsk-cb-chips", children: activeChips.map((chip) => /* @__PURE__ */ jsx7(
1999
+ "button",
2131
2000
  {
2132
- intent: lastIntent,
2133
- sources: sources.filter((s) => s.id && referencedIds.includes(s.id)),
2134
- onSend: handleSend,
2135
- loading
2136
- }
2137
- )
2138
- ] })
2139
- ] }) }, idx);
2140
- }),
2141
- selectedProduct && loading && /* @__PURE__ */ jsxs6(
2142
- "div",
2143
- {
2144
- className: "hsk-cb-selected-product",
2145
- onClick: () => selectedProduct.url && window.open(selectedProduct.url, "_blank"),
2146
- children: [
2147
- selectedProduct.image && /* @__PURE__ */ jsx7("img", { className: "hsk-cb-selected-img", src: selectedProduct.image, alt: selectedProduct.name }),
2148
- /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-selected-info", children: [
2149
- /* @__PURE__ */ jsx7("div", { className: "hsk-cb-selected-name", children: selectedProduct.name }),
2150
- selectedProduct.price && /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-selected-price", children: [
2151
- selectedProduct.currency ?? defaultCurrency,
2152
- " ",
2153
- parseFloat(String(selectedProduct.price ?? "").replace(/[^0-9.]/g, "") || "0").toLocaleString()
2001
+ className: "hsk-cb-chip",
2002
+ onClick: () => handleSend(chip),
2003
+ children: chip
2004
+ },
2005
+ chip
2006
+ )) })
2007
+ ] }) : displayMessages.map((msg, idx) => {
2008
+ const isLast = idx === displayMessages.length - 1;
2009
+ const isUser = msg.role === "user";
2010
+ const displayContent = !isUser && isLast && lastIntent === "compare" && sources.length >= 2 ? stripMarkdownTables(msg.content) : msg.content;
2011
+ return /* @__PURE__ */ jsx7("div", { className: "hsk-cb-msg-group", ref: (el) => {
2012
+ messageRefs.current[idx] = el;
2013
+ }, children: isUser ? /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-user-msg", children: [
2014
+ msg.images && msg.images.length > 0 && /* @__PURE__ */ jsx7("div", { className: "hsk-cb-user-imgs", children: msg.images.map((img, i) => /* @__PURE__ */ jsx7("img", { src: img, alt: `attachment ${i + 1}`, className: "hsk-cb-user-img-thumb" }, i)) }),
2015
+ msg.content && /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-user-bubble", children: [
2016
+ /^@kiku\b/i.test(msg.content) && /* @__PURE__ */ jsx7("span", { className: "hsk-kiku-badge", children: "@kiku" }),
2017
+ msg.content
2154
2018
  ] })
2155
- ] })
2156
- ]
2157
- }
2158
- ),
2159
- loading && !streaming && /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-typing-row", style: { display: "flex", alignItems: "flex-start", gap: "10px" }, children: [
2160
- /* @__PURE__ */ jsx7("div", { className: "hsk-cb-ai-icon", style: { display: "flex", alignItems: "center", marginTop: "4px" }, children: /* @__PURE__ */ jsx7(SparkleIcon2, {}) }),
2161
- /* @__PURE__ */ jsxs6("div", { style: { display: "flex", flexDirection: "column", gap: "6px" }, children: [
2162
- /* @__PURE__ */ jsx7("style", { children: `
2019
+ ] }) : /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-ai-msg", children: [
2020
+ /* @__PURE__ */ jsx7("div", { className: "hsk-cb-ai-icon", style: { display: "flex", alignItems: "center" }, children: /* @__PURE__ */ jsx7(SparkleIcon2, {}) }),
2021
+ /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-ai-body", children: [
2022
+ (() => {
2023
+ const { thinking, content, isComplete } = parseThinking(displayContent);
2024
+ return /* @__PURE__ */ jsxs6(Fragment3, { children: [
2025
+ thinking && /* @__PURE__ */ jsx7(ThinkingBlock, { text: thinking, isComplete }),
2026
+ content && /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-ai-text", children: [
2027
+ renderMarkdown(content),
2028
+ isLast && streaming && /* @__PURE__ */ jsx7("span", { style: { display: "inline-block", width: "0.5em", height: "1.05em", marginLeft: "2px", verticalAlign: "text-bottom", background: "currentColor", opacity: 0.55, borderRadius: "1px" } })
2029
+ ] })
2030
+ ] });
2031
+ })(),
2032
+ isLast && lastIntent === "compare" && sources.length >= 2 && /* @__PURE__ */ jsx7(ComparisonMatrix, { sources, defaultCurrency }),
2033
+ (() => {
2034
+ const msgReferencedIds = isLast ? referencedIds : msg.referencedIds ?? [];
2035
+ const msgSources = isLast ? sources : msg.sources ?? [];
2036
+ const showCarousel = msgReferencedIds.length > 0 && (isLast ? lastIntent !== "compare" : msg.intent !== "compare") && lastAction?.type !== "request_kiku_key" && lastAction?.type !== "capture" && lastAction?.type !== "delete" && lastAction?.type !== "view_history";
2037
+ return showCarousel && /* @__PURE__ */ jsx7(
2038
+ SourcesCarousel,
2039
+ {
2040
+ sources: msgSources,
2041
+ defaultCurrency,
2042
+ onSelectSource: handleSourceClick,
2043
+ onImageClick: setLightboxSrc,
2044
+ referencedIds: msgReferencedIds
2045
+ }
2046
+ );
2047
+ })(),
2048
+ isLast && !loading && lastAction?.url && /* @__PURE__ */ jsx7("div", { className: "hsk-action-pills", children: /* @__PURE__ */ jsxs6("a", { className: "hsk-action-pill", href: lastAction.url, children: [
2049
+ String(lastAction.type || "continue").replace(/_/g, " "),
2050
+ " \u2192"
2051
+ ] }) }),
2052
+ isLast && !loading && /* @__PURE__ */ jsx7(
2053
+ SmartContextPills,
2054
+ {
2055
+ intent: lastIntent,
2056
+ sources: sources.filter((s) => s.id && referencedIds.includes(s.id)),
2057
+ onSend: handleSend,
2058
+ loading
2059
+ }
2060
+ )
2061
+ ] })
2062
+ ] }) }, idx);
2063
+ }),
2064
+ selectedProduct && loading && /* @__PURE__ */ jsxs6(
2065
+ "div",
2066
+ {
2067
+ className: "hsk-cb-selected-product",
2068
+ onClick: () => selectedProduct.url && window.open(selectedProduct.url, "_blank"),
2069
+ children: [
2070
+ selectedProduct.image && /* @__PURE__ */ jsx7("img", { className: "hsk-cb-selected-img", src: selectedProduct.image, alt: selectedProduct.name }),
2071
+ /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-selected-info", children: [
2072
+ /* @__PURE__ */ jsx7("div", { className: "hsk-cb-selected-name", children: selectedProduct.name }),
2073
+ selectedProduct.price && /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-selected-price", children: [
2074
+ selectedProduct.currency ?? defaultCurrency,
2075
+ " ",
2076
+ parseFloat(String(selectedProduct.price ?? "").replace(/[^0-9.]/g, "") || "0").toLocaleString()
2077
+ ] })
2078
+ ] })
2079
+ ]
2080
+ }
2081
+ ),
2082
+ loading && !streaming && /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-typing-row", style: { display: "flex", alignItems: "flex-start", gap: "10px" }, children: [
2083
+ /* @__PURE__ */ jsx7("div", { className: "hsk-cb-ai-icon", style: { display: "flex", alignItems: "center", marginTop: "4px" }, children: /* @__PURE__ */ jsx7(SparkleIcon2, {}) }),
2084
+ /* @__PURE__ */ jsxs6("div", { style: { display: "flex", flexDirection: "column", gap: "6px" }, children: [
2085
+ /* @__PURE__ */ jsx7("style", { children: `
2163
2086
  @keyframes hsk-pulse {
2164
2087
  0%, 100% { opacity: 0.6; }
2165
2088
  50% { opacity: 1; }
2166
2089
  }
2167
2090
  ` }),
2168
- /* @__PURE__ */ jsx7("div", { style: { fontSize: "0.85rem", color: "#6b7280", fontStyle: "italic", animation: "hsk-pulse 1.5s infinite ease-in-out" }, children: "Thinking\u2026" }),
2169
- /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-typing", style: { margin: 0, alignSelf: "flex-start" }, children: [
2170
- /* @__PURE__ */ jsx7("div", { className: "hsk-cb-dot" }),
2171
- /* @__PURE__ */ jsx7("div", { className: "hsk-cb-dot" }),
2172
- /* @__PURE__ */ jsx7("div", { className: "hsk-cb-dot" })
2173
- ] })
2174
- ] })
2175
- ] }),
2176
- error && /* @__PURE__ */ jsx7("div", { className: "hsk-cb-error", children: getFriendlyError(error) }),
2177
- !replayMessages && keyPhase === "prompt_key" && /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-ai-msg", children: [
2178
- /* @__PURE__ */ jsx7("div", { className: "hsk-cb-ai-icon", style: { display: "flex", alignItems: "center" }, children: /* @__PURE__ */ jsx7(SparkleIcon2, {}) }),
2179
- /* @__PURE__ */ jsx7("div", { className: "hsk-cb-ai-body", children: /* @__PURE__ */ jsx7("div", { className: "hsk-cb-ai-text", children: /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-phone-form", children: [
2180
- /* @__PURE__ */ jsx7("label", { className: "hsk-cb-phone-label", children: "Paste your kiku key \u2014 or create one" }),
2181
- /* @__PURE__ */ jsx7(
2182
- "input",
2091
+ /* @__PURE__ */ jsx7("div", { style: { fontSize: "0.85rem", color: "#6b7280", fontStyle: "italic", animation: "hsk-pulse 1.5s infinite ease-in-out" }, children: "Thinking\u2026" }),
2092
+ /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-typing", style: { margin: 0, alignSelf: "flex-start" }, children: [
2093
+ /* @__PURE__ */ jsx7("div", { className: "hsk-cb-dot" }),
2094
+ /* @__PURE__ */ jsx7("div", { className: "hsk-cb-dot" }),
2095
+ /* @__PURE__ */ jsx7("div", { className: "hsk-cb-dot" })
2096
+ ] })
2097
+ ] })
2098
+ ] }),
2099
+ error && /* @__PURE__ */ jsx7("div", { className: "hsk-cb-error", children: getFriendlyError(error) }),
2100
+ keyPhase === "prompt_key" && /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-ai-msg", children: [
2101
+ /* @__PURE__ */ jsx7("div", { className: "hsk-cb-ai-icon", style: { display: "flex", alignItems: "center" }, children: /* @__PURE__ */ jsx7(SparkleIcon2, {}) }),
2102
+ /* @__PURE__ */ jsx7("div", { className: "hsk-cb-ai-body", children: /* @__PURE__ */ jsx7("div", { className: "hsk-cb-ai-text", children: /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-phone-form", children: [
2103
+ /* @__PURE__ */ jsx7("label", { className: "hsk-cb-phone-label", children: "Paste your kiku key \u2014 or create one" }),
2104
+ /* @__PURE__ */ jsx7(
2105
+ "input",
2106
+ {
2107
+ type: "text",
2108
+ className: "hsk-cb-phone-input",
2109
+ placeholder: "kiku_\u2026",
2110
+ value: keyInput,
2111
+ onChange: (e) => setKeyInput(e.target.value),
2112
+ onKeyDown: (e) => e.key === "Enter" && handleUseExistingKey(),
2113
+ autoFocus: true
2114
+ }
2115
+ ),
2116
+ /* @__PURE__ */ jsxs6("div", { style: { display: "flex", gap: 8 }, children: [
2117
+ /* @__PURE__ */ jsx7("button", { className: "hsk-cb-phone-submit", onClick: handleUseExistingKey, disabled: !keyInput.trim(), children: "Use my key" }),
2118
+ /* @__PURE__ */ jsx7("button", { className: "hsk-cb-phone-submit", onClick: handleCreateKey, disabled: minting, children: minting ? "Creating\u2026" : "I'm new \u2014 create my key" })
2119
+ ] })
2120
+ ] }) }) })
2121
+ ] }),
2122
+ mintedKey && /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-ai-msg", children: [
2123
+ /* @__PURE__ */ jsx7("div", { className: "hsk-cb-ai-icon", style: { display: "flex", alignItems: "center" }, children: /* @__PURE__ */ jsx7(SparkleIcon2, {}) }),
2124
+ /* @__PURE__ */ jsx7("div", { className: "hsk-cb-ai-body", children: /* @__PURE__ */ jsx7("div", { className: "hsk-cb-ai-text", children: /* @__PURE__ */ jsxs6("div", { style: { padding: "10px 12px", border: "1px solid var(--hsk-border, #e5e5e5)", borderRadius: 8 }, children: [
2125
+ /* @__PURE__ */ jsx7("div", { style: { fontSize: 12, fontWeight: 600, marginBottom: 4 }, children: "\u{1F511} Your kiku key \u2014 shown only once" }),
2126
+ /* @__PURE__ */ jsx7("code", { style: { display: "block", fontSize: 14, fontWeight: 700, marginBottom: 6, wordBreak: "break-all" }, children: mintedKey }),
2127
+ /* @__PURE__ */ jsxs6("div", { style: { display: "flex", gap: 8, alignItems: "center" }, children: [
2128
+ /* @__PURE__ */ jsx7("button", { className: "hsk-cb-phone-submit", style: { padding: "4px 10px" }, onClick: () => {
2129
+ try {
2130
+ navigator.clipboard?.writeText(mintedKey);
2131
+ } catch {
2132
+ }
2133
+ }, children: "Copy" }),
2134
+ /* @__PURE__ */ jsxs6("span", { style: { fontSize: 11, opacity: 0.7 }, children: [
2135
+ "Disappears in ",
2136
+ keyCountdown,
2137
+ "s. Save it like a password \u2014 if lost, the memory it opens is lost with it."
2138
+ ] })
2139
+ ] })
2140
+ ] }) }) })
2141
+ ] }),
2142
+ /* @__PURE__ */ jsx7("div", { ref: bottomRef, style: { height: 1 } })
2143
+ ] }),
2144
+ /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-input-wrap", children: [
2145
+ showAtPicker && /* @__PURE__ */ jsx7(
2146
+ AtPickerMenu,
2183
2147
  {
2184
- type: "text",
2185
- className: "hsk-cb-phone-input",
2186
- placeholder: "kiku_\u2026",
2187
- value: keyInput,
2188
- onChange: (e) => setKeyInput(e.target.value),
2189
- onKeyDown: (e) => e.key === "Enter" && handleUseExistingKey(),
2190
- autoFocus: true
2148
+ onSelect: handleSelectExtension,
2149
+ onDismiss: () => setShowAtPicker(false)
2191
2150
  }
2192
2151
  ),
2193
- /* @__PURE__ */ jsxs6("div", { style: { display: "flex", gap: 8 }, children: [
2194
- /* @__PURE__ */ jsx7("button", { className: "hsk-cb-phone-submit", onClick: handleUseExistingKey, disabled: !keyInput.trim(), children: "Use my key" }),
2195
- /* @__PURE__ */ jsx7("button", { className: "hsk-cb-phone-submit", onClick: handleCreateKey, disabled: minting, children: minting ? "Creating\u2026" : "I'm new \u2014 create my key" })
2196
- ] })
2197
- ] }) }) })
2198
- ] }),
2199
- !replayMessages && mintedKey && /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-ai-msg", children: [
2200
- /* @__PURE__ */ jsx7("div", { className: "hsk-cb-ai-icon", style: { display: "flex", alignItems: "center" }, children: /* @__PURE__ */ jsx7(SparkleIcon2, {}) }),
2201
- /* @__PURE__ */ jsx7("div", { className: "hsk-cb-ai-body", children: /* @__PURE__ */ jsx7("div", { className: "hsk-cb-ai-text", children: /* @__PURE__ */ jsxs6("div", { style: { padding: "10px 12px", border: "1px solid var(--hsk-border, #e5e5e5)", borderRadius: 8 }, children: [
2202
- /* @__PURE__ */ jsx7("div", { style: { fontSize: 12, fontWeight: 600, marginBottom: 4 }, children: "\u{1F511} Your kiku key \u2014 shown only once" }),
2203
- /* @__PURE__ */ jsx7("code", { style: { display: "block", fontSize: 14, fontWeight: 700, marginBottom: 6, wordBreak: "break-all" }, children: mintedKey }),
2204
- /* @__PURE__ */ jsxs6("div", { style: { display: "flex", gap: 8, alignItems: "center" }, children: [
2205
- /* @__PURE__ */ jsx7("button", { className: "hsk-cb-phone-submit", style: { padding: "4px 10px" }, onClick: () => {
2206
- try {
2207
- navigator.clipboard?.writeText(mintedKey);
2208
- } catch {
2152
+ showKikuPicker && /* @__PURE__ */ jsx7(
2153
+ KikuPickerMenu,
2154
+ {
2155
+ sources,
2156
+ referencedIds,
2157
+ defaultCurrency,
2158
+ onCapture: handleKikuCapture,
2159
+ onCaptureAll: handleKikuCaptureAll,
2160
+ onViewHistory: handleKikuViewHistory,
2161
+ onDelete: handleKikuDelete,
2162
+ onDismiss: () => setShowKikuPicker(false)
2163
+ }
2164
+ ),
2165
+ attachments.length > 0 && /* @__PURE__ */ jsx7("div", { className: "hsk-cb-img-strip", children: attachments.map((att, i) => /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-img-thumb-wrap", children: [
2166
+ /* @__PURE__ */ jsx7("img", { src: att.data, alt: `attachment ${i + 1}`, className: "hsk-cb-img-thumb" }),
2167
+ /* @__PURE__ */ jsx7(
2168
+ "button",
2169
+ {
2170
+ className: "hsk-cb-img-thumb-remove",
2171
+ onClick: () => removeAttachment(i),
2172
+ "aria-label": "Remove image",
2173
+ children: "\xD7"
2174
+ }
2175
+ )
2176
+ ] }, i)) }),
2177
+ /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-input-box", children: [
2178
+ /* @__PURE__ */ jsx7(
2179
+ "input",
2180
+ {
2181
+ ref: imageInputRef,
2182
+ type: "file",
2183
+ accept: "image/*",
2184
+ multiple: true,
2185
+ style: { display: "none" },
2186
+ onChange: (e) => handleImageFiles(e.target.files)
2209
2187
  }
2210
- }, children: "Copy" }),
2211
- /* @__PURE__ */ jsxs6("span", { style: { fontSize: 11, opacity: 0.7 }, children: [
2212
- "Disappears in ",
2213
- keyCountdown,
2214
- "s. Save it like a password \u2014 if lost, the memory it opens is lost with it."
2215
- ] })
2216
- ] })
2217
- ] }) }) })
2218
- ] }),
2219
- /* @__PURE__ */ jsx7("div", { ref: bottomRef, style: { height: 1 } })
2220
- ] }),
2221
- !replayMessages && /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-input-wrap", children: [
2222
- showAtPicker && /* @__PURE__ */ jsx7(
2223
- AtPickerMenu,
2224
- {
2225
- onSelect: handleSelectExtension,
2226
- onDismiss: () => setShowAtPicker(false)
2227
- }
2228
- ),
2229
- showKikuPicker && /* @__PURE__ */ jsx7(
2230
- KikuPickerMenu,
2231
- {
2232
- sources,
2233
- referencedIds,
2234
- defaultCurrency,
2235
- onCapture: handleKikuCapture,
2236
- onCaptureAll: handleKikuCaptureAll,
2237
- onViewHistory: handleKikuViewHistory,
2238
- onDelete: handleKikuDelete,
2239
- onDismiss: () => setShowKikuPicker(false)
2240
- }
2241
- ),
2242
- attachments.length > 0 && /* @__PURE__ */ jsx7("div", { className: "hsk-cb-img-strip", children: attachments.map((att, i) => /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-img-thumb-wrap", children: [
2243
- /* @__PURE__ */ jsx7("img", { src: att.data, alt: `attachment ${i + 1}`, className: "hsk-cb-img-thumb" }),
2244
- /* @__PURE__ */ jsx7(
2245
- "button",
2246
- {
2247
- className: "hsk-cb-img-thumb-remove",
2248
- onClick: () => removeAttachment(i),
2249
- "aria-label": "Remove image",
2250
- children: "\xD7"
2251
- }
2252
- )
2253
- ] }, i)) }),
2254
- /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-input-box", children: [
2255
- /* @__PURE__ */ jsx7(
2256
- "input",
2257
- {
2258
- ref: imageInputRef,
2259
- type: "file",
2260
- accept: "image/*",
2261
- multiple: true,
2262
- style: { display: "none" },
2263
- onChange: (e) => handleImageFiles(e.target.files)
2264
- }
2265
- ),
2266
- enableVision && /* @__PURE__ */ jsx7(
2267
- "button",
2268
- {
2269
- className: "hsk-cb-attach-btn",
2270
- onClick: () => imageInputRef.current?.click(),
2271
- disabled: loading,
2272
- "aria-label": "Attach image",
2273
- title: "Attach image",
2274
- children: /* @__PURE__ */ jsx7(PaperclipIcon, {})
2275
- }
2276
- ),
2277
- /* @__PURE__ */ jsx7(
2278
- "textarea",
2279
- {
2280
- ref: textareaRef,
2281
- className: cn("hsk-cb-textarea", classNames.input),
2282
- value: input,
2283
- onChange: handleInput,
2284
- onKeyDown: handleKeyDown,
2285
- placeholder: voiceState === "listening" ? "\u{1F399}\uFE0F Listening\u2026 tap the mic to stop" : voiceState === "processing" ? "Got it \u2014 sending\u2026" : activePlaceholder,
2286
- rows: 1,
2287
- disabled: loading,
2288
- autoFocus: true
2289
- }
2290
- ),
2291
- hasSpeechAPI && enableVoice && /* @__PURE__ */ jsxs6(
2292
- "button",
2293
- {
2294
- className: cn(
2295
- "hsk-cb-mic-btn",
2296
- voiceState === "listening" && "hsk-cb-mic-btn--listening",
2297
- voiceState === "processing" && "hsk-cb-mic-btn--processing"
2298
2188
  ),
2299
- onClick: voiceState === "idle" ? startVoice : stopVoice,
2300
- disabled: loading,
2301
- "aria-label": voiceState === "idle" ? "Start voice input" : "Stop recording",
2302
- title: voiceState === "idle" ? "Voice input" : "Stop",
2303
- children: [
2304
- voiceState === "listening" ? /* @__PURE__ */ jsx7(MicOffIcon, {}) : /* @__PURE__ */ jsx7(MicIcon2, {}),
2305
- voiceState === "listening" && /* @__PURE__ */ jsx7("span", { className: "hsk-cb-mic-pulse" })
2306
- ]
2307
- }
2308
- ),
2309
- /* @__PURE__ */ jsx7(
2310
- "button",
2311
- {
2312
- className: cn("hsk-cb-send", classNames.sendButton),
2313
- onClick: () => handleSend(),
2314
- disabled: !input.trim() && attachments.length === 0 || loading,
2315
- "aria-label": "Send message",
2316
- children: /* @__PURE__ */ jsx7(ArrowUpIcon2, {})
2317
- }
2318
- )
2319
- ] }),
2320
- /* @__PURE__ */ jsx7("div", { className: "hsk-cb-hint", children: "Akropolys AI \xB7 searches the whole catalogue in real time" })
2321
- ] })
2322
- ] })
2323
- ] })
2189
+ enableVision && /* @__PURE__ */ jsx7(
2190
+ "button",
2191
+ {
2192
+ className: "hsk-cb-attach-btn",
2193
+ onClick: () => imageInputRef.current?.click(),
2194
+ disabled: loading,
2195
+ "aria-label": "Attach image",
2196
+ title: "Attach image",
2197
+ children: /* @__PURE__ */ jsx7(PaperclipIcon, {})
2198
+ }
2199
+ ),
2200
+ /* @__PURE__ */ jsx7(
2201
+ "textarea",
2202
+ {
2203
+ ref: textareaRef,
2204
+ className: cn("hsk-cb-textarea", classNames.input),
2205
+ value: input,
2206
+ onChange: handleInput,
2207
+ onKeyDown: handleKeyDown,
2208
+ placeholder: voiceState === "listening" ? "\u{1F399}\uFE0F Listening\u2026 tap the mic to stop" : voiceState === "processing" ? "Got it \u2014 sending\u2026" : activePlaceholder,
2209
+ rows: 1,
2210
+ disabled: loading,
2211
+ autoFocus: true
2212
+ }
2213
+ ),
2214
+ hasSpeechAPI && enableVoice && /* @__PURE__ */ jsxs6(
2215
+ "button",
2216
+ {
2217
+ className: cn(
2218
+ "hsk-cb-mic-btn",
2219
+ voiceState === "listening" && "hsk-cb-mic-btn--listening",
2220
+ voiceState === "processing" && "hsk-cb-mic-btn--processing"
2221
+ ),
2222
+ onClick: voiceState === "idle" ? startVoice : stopVoice,
2223
+ disabled: loading,
2224
+ "aria-label": voiceState === "idle" ? "Start voice input" : "Stop recording",
2225
+ title: voiceState === "idle" ? "Voice input" : "Stop",
2226
+ children: [
2227
+ voiceState === "listening" ? /* @__PURE__ */ jsx7(MicOffIcon, {}) : /* @__PURE__ */ jsx7(MicIcon2, {}),
2228
+ voiceState === "listening" && /* @__PURE__ */ jsx7("span", { className: "hsk-cb-mic-pulse" })
2229
+ ]
2230
+ }
2231
+ ),
2232
+ loading || streaming ? /* @__PURE__ */ jsx7(
2233
+ "button",
2234
+ {
2235
+ className: cn("hsk-cb-send", "hsk-cb-send--stop", classNames.sendButton),
2236
+ onClick: stop,
2237
+ "aria-label": "Stop generating",
2238
+ title: "Stop generating",
2239
+ children: /* @__PURE__ */ jsx7(StopIcon, {})
2240
+ }
2241
+ ) : /* @__PURE__ */ jsx7(
2242
+ "button",
2243
+ {
2244
+ className: cn("hsk-cb-send", classNames.sendButton),
2245
+ onClick: () => handleSend(),
2246
+ disabled: !input.trim() && attachments.length === 0,
2247
+ "aria-label": "Send message",
2248
+ children: /* @__PURE__ */ jsx7(ArrowUpIcon2, {})
2249
+ }
2250
+ )
2251
+ ] }),
2252
+ /* @__PURE__ */ jsx7("div", { className: "hsk-cb-hint", children: "Akropolys AI \xB7 searches the whole catalogue in real time" })
2253
+ ] })
2254
+ ] })
2255
+ ]
2256
+ }
2257
+ )
2324
2258
  }
2325
2259
  );
2326
2260
  }