@syncagent/react 0.1.7 → 0.1.8

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
@@ -107,30 +107,63 @@ import {
107
107
  useCallback as useCallback2
108
108
  } from "react";
109
109
  import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
110
- var GLOBAL_CSS = (accent) => `
110
+ function loadHistory(key) {
111
+ try {
112
+ const raw = localStorage.getItem(`sa_chat_${key}`);
113
+ if (!raw) return null;
114
+ const parsed = JSON.parse(raw);
115
+ if (parsed.timestamps) {
116
+ parsed.timestamps = parsed.timestamps.map((t) => t ? new Date(t) : null);
117
+ }
118
+ return parsed;
119
+ } catch {
120
+ return null;
121
+ }
122
+ }
123
+ function saveHistory(key, messages, timestamps) {
124
+ try {
125
+ localStorage.setItem(`sa_chat_${key}`, JSON.stringify({
126
+ messages,
127
+ timestamps: timestamps.map((t) => t?.toISOString() ?? null),
128
+ savedAt: (/* @__PURE__ */ new Date()).toISOString()
129
+ }));
130
+ } catch {
131
+ }
132
+ }
133
+ function clearHistory(key) {
134
+ try {
135
+ localStorage.removeItem(`sa_chat_${key}`);
136
+ } catch {
137
+ }
138
+ }
139
+ var CSS = (accent) => `
111
140
  @keyframes sa-bounce { 0%,80%,100%{transform:translateY(0);opacity:.35} 40%{transform:translateY(-5px);opacity:1} }
112
141
  @keyframes sa-fadein { from{opacity:0;transform:translateY(8px)} to{opacity:1;transform:translateY(0)} }
113
142
  @keyframes sa-cursor { 0%,100%{opacity:1} 50%{opacity:0} }
114
143
  @keyframes sa-pulse { 0%,100%{opacity:.6} 50%{opacity:1} }
144
+ @keyframes sa-shake { 0%,100%{transform:translateX(0)} 25%{transform:translateX(-4px)} 75%{transform:translateX(4px)} }
115
145
  .sa-msg { animation: sa-fadein .22s cubic-bezier(.16,1,.3,1) }
116
- .sa-fab { transition: transform .2s, box-shadow .2s }
117
146
  .sa-fab:hover { transform: scale(1.08) }
118
147
  .sa-fab:active { transform: scale(.96) }
119
148
  .sa-chip:hover { background: ${accent}22 !important; border-color: ${accent}88 !important }
120
149
  .sa-send:hover:not(:disabled) { filter: brightness(1.1); transform: scale(1.05) }
121
150
  .sa-send:active:not(:disabled) { transform: scale(.96) }
122
151
  .sa-send:disabled { opacity: .4; cursor: not-allowed }
123
- .sa-copy:hover { opacity: 1 !important; background: rgba(0,0,0,.06) !important }
152
+ .sa-act:hover { opacity: 1 !important; background: rgba(0,0,0,.06) !important }
153
+ .sa-react:hover { transform: scale(1.2) }
154
+ .sa-react.active { transform: scale(1.15) }
124
155
  .sa-scroll::-webkit-scrollbar { width: 4px }
125
156
  .sa-scroll::-webkit-scrollbar-track { background: transparent }
126
157
  .sa-scroll::-webkit-scrollbar-thumb { background: rgba(0,0,0,.12); border-radius: 4px }
127
158
  .sa-cursor { display:inline-block; width:2px; height:1em; background:currentColor; margin-left:1px; vertical-align:text-bottom; animation: sa-cursor .7s infinite }
159
+ .sa-resize { cursor: ns-resize; user-select: none }
160
+ .sa-resize:hover::after { opacity: 1 }
128
161
  .sa-md table { width:100%; border-collapse:collapse; font-size:12.5px; margin:10px 0 }
129
162
  .sa-md th { padding:7px 10px; text-align:left; font-weight:600; background:rgba(0,0,0,.04); border-bottom:2px solid rgba(0,0,0,.1); white-space:nowrap }
130
163
  .sa-md td { padding:6px 10px; border-bottom:1px solid rgba(0,0,0,.06); vertical-align:top }
131
164
  .sa-md tr:last-child td { border-bottom:none }
132
165
  .sa-md tr:hover td { background:rgba(0,0,0,.02) }
133
- .sa-md pre { background:#0f1117; color:#e2e8f0; padding:14px 16px; border-radius:10px; overflow-x:auto; font-size:12px; line-height:1.7; margin:10px 0; font-family:'Fira Code','Cascadia Code','JetBrains Mono',monospace; border:1px solid rgba(255,255,255,.06) }
166
+ .sa-md pre { background:#0f1117; color:#e2e8f0; padding:14px 16px; border-radius:10px; overflow-x:auto; font-size:12px; line-height:1.7; margin:10px 0; font-family:'Fira Code','Cascadia Code',monospace; border:1px solid rgba(255,255,255,.06) }
134
167
  .sa-md code { background:rgba(0,0,0,.07); padding:2px 6px; border-radius:4px; font-size:12px; font-family:monospace; color:#1e293b }
135
168
  .sa-md pre code { background:none; padding:0; color:inherit; font-size:inherit }
136
169
  .sa-md ul,.sa-md ol { margin:6px 0; padding-left:20px }
@@ -150,10 +183,10 @@ var GLOBAL_CSS = (accent) => `
150
183
  }
151
184
  `;
152
185
  function md(text) {
153
- let s = text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/```(\w*)\n?([\s\S]*?)```/g, (_, lang, code) => `<pre><code class="lang-${lang}">${code.trimEnd()}</code></pre>`).replace(/`([^`\n]+)`/g, "<code>$1</code>").replace(/^### (.+)$/gm, "<h3>$1</h3>").replace(/^## (.+)$/gm, "<h2>$1</h2>").replace(/^# (.+)$/gm, "<h1>$1</h1>").replace(/\*\*\*(.+?)\*\*\*/g, "<strong><em>$1</em></strong>").replace(/\*\*(.+?)\*\*/g, "<strong>$1</strong>").replace(/\*(.+?)\*/g, "<em>$1</em>").replace(/^> (.+)$/gm, "<blockquote>$1</blockquote>").replace(/^---$/gm, "<hr/>").replace(/\|(.+)\|\r?\n\|[-| :]+\|\r?\n((?:\|.+\|\r?\n?)+)/g, (_, hdr, body) => {
154
- const ths = hdr.split("|").filter((c) => c.trim()).map((c) => `<th>${c.trim()}</th>`).join("");
155
- const trs = body.trim().split("\n").map((row) => {
156
- const tds = row.split("|").filter((c) => c.trim()).map((c) => `<td>${c.trim()}</td>`).join("");
186
+ let s = text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/```(\w*)\n?([\s\S]*?)```/g, (_, l, c) => `<pre><code class="lang-${l}">${c.trimEnd()}</code></pre>`).replace(/`([^`\n]+)`/g, "<code>$1</code>").replace(/^### (.+)$/gm, "<h3>$1</h3>").replace(/^## (.+)$/gm, "<h2>$1</h2>").replace(/^# (.+)$/gm, "<h1>$1</h1>").replace(/\*\*\*(.+?)\*\*\*/g, "<strong><em>$1</em></strong>").replace(/\*\*(.+?)\*\*/g, "<strong>$1</strong>").replace(/\*(.+?)\*/g, "<em>$1</em>").replace(/^> (.+)$/gm, "<blockquote>$1</blockquote>").replace(/^---$/gm, "<hr/>").replace(/\|(.+)\|\r?\n\|[-| :]+\|\r?\n((?:\|.+\|\r?\n?)+)/g, (_, h, b) => {
187
+ const ths = h.split("|").filter((c) => c.trim()).map((c) => `<th>${c.trim()}</th>`).join("");
188
+ const trs = b.trim().split("\n").map((r) => {
189
+ const tds = r.split("|").filter((c) => c.trim()).map((c) => `<td>${c.trim()}</td>`).join("");
157
190
  return `<tr>${tds}</tr>`;
158
191
  }).join("");
159
192
  return `<div style="overflow-x:auto"><table><thead><tr>${ths}</tr></thead><tbody>${trs}</tbody></table></div>`;
@@ -161,109 +194,61 @@ function md(text) {
161
194
  return `<p>${s}</p>`;
162
195
  }
163
196
  function Dots({ color }) {
164
- return /* @__PURE__ */ jsx2("span", { style: { display: "inline-flex", gap: 4, alignItems: "center", padding: "4px 2px" }, children: [0, 1, 2].map((i) => /* @__PURE__ */ jsx2("span", { style: {
165
- width: 7,
166
- height: 7,
167
- borderRadius: "50%",
168
- background: color,
169
- display: "inline-block",
170
- animation: "sa-bounce 1.3s infinite",
171
- animationDelay: `${i * 0.18}s`
172
- } }, i)) });
197
+ return /* @__PURE__ */ jsx2("span", { style: { display: "inline-flex", gap: 4, alignItems: "center", padding: "4px 2px" }, children: [0, 1, 2].map((i) => /* @__PURE__ */ jsx2("span", { style: { width: 7, height: 7, borderRadius: "50%", background: color, display: "inline-block", animation: "sa-bounce 1.3s infinite", animationDelay: `${i * 0.18}s` } }, i)) });
173
198
  }
174
- function Copy({ text }) {
199
+ function CopyBtn({ text }) {
175
200
  const [ok, setOk] = useState2(false);
176
- return /* @__PURE__ */ jsx2("button", { className: "sa-copy", onClick: () => {
201
+ return /* @__PURE__ */ jsx2("button", { className: "sa-act", onClick: () => {
177
202
  navigator.clipboard?.writeText(text).then(() => {
178
203
  setOk(true);
179
204
  setTimeout(() => setOk(false), 1600);
180
205
  });
181
- }, title: "Copy response", style: {
182
- background: "none",
183
- border: "none",
184
- cursor: "pointer",
185
- padding: "3px 7px",
186
- borderRadius: 5,
187
- fontSize: 11,
188
- color: "#94a3b8",
189
- opacity: 0.65,
190
- transition: "all .15s",
191
- display: "flex",
192
- alignItems: "center",
193
- gap: 3
194
- }, children: ok ? /* @__PURE__ */ jsxs(Fragment, { children: [
206
+ }, style: { background: "none", border: "none", cursor: "pointer", padding: "3px 7px", borderRadius: 5, fontSize: 11, color: "#94a3b8", opacity: 0.65, transition: "all .15s", display: "flex", alignItems: "center", gap: 3 }, children: ok ? /* @__PURE__ */ jsxs(Fragment, { children: [
195
207
  /* @__PURE__ */ jsx2("svg", { width: "11", height: "11", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx2("path", { d: "M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z" }) }),
196
- " Copied"
208
+ "Copied"
197
209
  ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
198
210
  /* @__PURE__ */ jsx2("svg", { width: "11", height: "11", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx2("path", { d: "M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z" }) }),
199
- " Copy"
211
+ "Copy"
200
212
  ] }) });
201
213
  }
202
- function Bubble({ role, content, streaming, accent, time }) {
214
+ function ReactionBtns({ idx, reactions, onReact, accent }) {
215
+ const cur = reactions[idx];
216
+ return /* @__PURE__ */ jsx2("div", { style: { display: "flex", gap: 2 }, children: ["up", "down"].map((r) => /* @__PURE__ */ jsx2("button", { className: `sa-react${cur === r ? " active" : ""}`, onClick: () => onReact(idx, r), title: r === "up" ? "Helpful" : "Not helpful", style: {
217
+ background: cur === r ? r === "up" ? `${accent}18` : "#fef2f2" : "none",
218
+ border: cur === r ? `1px solid ${r === "up" ? accent + "44" : "#fecaca"}` : "none",
219
+ cursor: "pointer",
220
+ padding: "3px 6px",
221
+ borderRadius: 5,
222
+ fontSize: 13,
223
+ transition: "all .15s",
224
+ opacity: cur && cur !== r ? 0.3 : 0.7
225
+ }, children: r === "up" ? "\u{1F44D}" : "\u{1F44E}" }, r)) });
226
+ }
227
+ function Bubble({ role, content, streaming, accent, time, idx, reactions, onReact, onRetry, hasError }) {
203
228
  const isUser = role === "user";
204
229
  const t = time.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
205
- return /* @__PURE__ */ jsxs("div", { className: "sa-msg", style: {
206
- display: "flex",
207
- flexDirection: "column",
208
- alignItems: isUser ? "flex-end" : "flex-start",
209
- gap: 4,
210
- maxWidth: "90%",
211
- alignSelf: isUser ? "flex-end" : "flex-start"
212
- }, children: [
213
- /* @__PURE__ */ jsxs("div", { style: {
214
- display: "flex",
215
- alignItems: "center",
216
- gap: 6,
217
- flexDirection: isUser ? "row-reverse" : "row"
218
- }, children: [
219
- /* @__PURE__ */ jsx2("div", { style: {
220
- width: 26,
221
- height: 26,
222
- borderRadius: "50%",
223
- flexShrink: 0,
224
- background: isUser ? `linear-gradient(135deg,${accent},${adj(accent, -25)})` : "linear-gradient(135deg,#6366f1,#8b5cf6)",
225
- display: "flex",
226
- alignItems: "center",
227
- justifyContent: "center",
228
- fontSize: 11,
229
- color: "white",
230
- fontWeight: 700,
231
- boxShadow: isUser ? `0 2px 8px ${accent}44` : "0 2px 8px #6366f144"
232
- }, children: isUser ? "U" : "\u2726" }),
230
+ return /* @__PURE__ */ jsxs("div", { className: "sa-msg", style: { display: "flex", flexDirection: "column", alignItems: isUser ? "flex-end" : "flex-start", gap: 4, maxWidth: "90%", alignSelf: isUser ? "flex-end" : "flex-start" }, children: [
231
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 6, flexDirection: isUser ? "row-reverse" : "row" }, children: [
232
+ /* @__PURE__ */ jsx2("div", { style: { width: 26, height: 26, borderRadius: "50%", flexShrink: 0, background: isUser ? `linear-gradient(135deg,${accent},${adj(accent, -25)})` : "linear-gradient(135deg,#6366f1,#8b5cf6)", display: "flex", alignItems: "center", justifyContent: "center", fontSize: 11, color: "white", fontWeight: 700, boxShadow: isUser ? `0 2px 8px ${accent}44` : "0 2px 8px #6366f144" }, children: isUser ? "U" : "\u2726" }),
233
233
  /* @__PURE__ */ jsx2("span", { style: { fontSize: 11.5, fontWeight: 600, color: isUser ? "#475569" : "#6366f1" }, children: isUser ? "You" : "SyncAgent" }),
234
234
  /* @__PURE__ */ jsx2("span", { style: { fontSize: 10, color: "#cbd5e1" }, children: t })
235
235
  ] }),
236
- /* @__PURE__ */ jsxs("div", { style: {
237
- padding: isUser ? "10px 14px" : "12px 16px",
238
- borderRadius: isUser ? "18px 4px 18px 18px" : "4px 18px 18px 18px",
239
- background: isUser ? `linear-gradient(135deg,${accent},${adj(accent, -20)})` : "#ffffff",
240
- color: isUser ? "white" : "#1e293b",
241
- fontSize: 13.5,
242
- lineHeight: 1.65,
243
- wordBreak: "break-word",
244
- border: isUser ? "none" : "1px solid #e8edf3",
245
- boxShadow: isUser ? `0 4px 16px ${accent}33` : "0 2px 12px rgba(0,0,0,0.07)",
246
- maxWidth: "100%"
247
- }, children: [
236
+ /* @__PURE__ */ jsxs("div", { style: { padding: isUser ? "10px 14px" : "12px 16px", borderRadius: isUser ? "18px 4px 18px 18px" : "4px 18px 18px 18px", background: isUser ? `linear-gradient(135deg,${accent},${adj(accent, -20)})` : "#ffffff", color: isUser ? "white" : "#1e293b", fontSize: 13.5, lineHeight: 1.65, wordBreak: "break-word", border: isUser ? "none" : "1px solid #e8edf3", boxShadow: isUser ? `0 4px 16px ${accent}33` : "0 2px 12px rgba(0,0,0,0.07)", maxWidth: "100%", animation: hasError ? "sa-shake .3s ease" : "none" }, children: [
248
237
  streaming && !content ? /* @__PURE__ */ jsx2(Dots, { color: accent }) : isUser ? /* @__PURE__ */ jsx2("span", { style: { whiteSpace: "pre-wrap" }, children: content }) : /* @__PURE__ */ jsx2("div", { className: "sa-md", dangerouslySetInnerHTML: { __html: md(content) } }),
249
238
  streaming && content && /* @__PURE__ */ jsx2("span", { className: "sa-cursor", style: { color: accent } })
250
239
  ] }),
251
- !isUser && content && !streaming && /* @__PURE__ */ jsx2("div", { style: { paddingLeft: 32, display: "flex", gap: 2 }, children: /* @__PURE__ */ jsx2(Copy, { text: content }) })
240
+ !isUser && content && !streaming && /* @__PURE__ */ jsxs("div", { style: { paddingLeft: 32, display: "flex", gap: 2, alignItems: "center" }, children: [
241
+ /* @__PURE__ */ jsx2(CopyBtn, { text: content }),
242
+ /* @__PURE__ */ jsx2(ReactionBtns, { idx, reactions, onReact, accent }),
243
+ onRetry && /* @__PURE__ */ jsxs("button", { className: "sa-act", onClick: onRetry, style: { background: "none", border: "none", cursor: "pointer", padding: "3px 7px", borderRadius: 5, fontSize: 11, color: "#94a3b8", opacity: 0.65, transition: "all .15s", display: "flex", alignItems: "center", gap: 3 }, children: [
244
+ /* @__PURE__ */ jsx2("svg", { width: "11", height: "11", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx2("path", { d: "M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z" }) }),
245
+ "Retry"
246
+ ] })
247
+ ] })
252
248
  ] });
253
249
  }
254
250
  function Chips({ items, onPick, accent }) {
255
- return /* @__PURE__ */ jsx2("div", { style: { display: "flex", flexWrap: "wrap", gap: 6, padding: "0 14px 10px" }, children: items.map((s) => /* @__PURE__ */ jsx2("button", { className: "sa-chip", onClick: () => onPick(s), style: {
256
- padding: "5px 13px",
257
- borderRadius: 20,
258
- fontSize: 12,
259
- cursor: "pointer",
260
- border: `1px solid ${accent}33`,
261
- background: `${accent}0a`,
262
- color: accent,
263
- fontWeight: 500,
264
- transition: "all .15s",
265
- whiteSpace: "nowrap"
266
- }, children: s }, s)) });
251
+ return /* @__PURE__ */ jsx2("div", { style: { display: "flex", flexWrap: "wrap", gap: 6, padding: "0 14px 10px" }, children: items.map((s) => /* @__PURE__ */ jsx2("button", { className: "sa-chip", onClick: () => onPick(s), style: { padding: "5px 13px", borderRadius: 20, fontSize: 12, cursor: "pointer", border: `1px solid ${accent}33`, background: `${accent}0a`, color: accent, fontWeight: 500, transition: "all .15s", whiteSpace: "nowrap" }, children: s }, s)) });
267
252
  }
268
253
  function ChatInner({
269
254
  mode = "floating",
@@ -276,29 +261,52 @@ function ChatInner({
276
261
  accentColor = "#10b981",
277
262
  className,
278
263
  style: customStyle,
279
- suggestions = ["Show all records", "Count total entries", "Show recent activity"]
264
+ suggestions = ["Show all records", "Count total entries", "Show recent activity"],
265
+ persistKey,
266
+ onReaction
280
267
  }) {
281
268
  const { messages, isLoading, error, status, sendMessage, stop, reset } = useSyncAgent();
282
269
  const [open, setOpen] = useState2(defaultOpen);
283
270
  const [input, setInput] = useState2("");
284
- const [ts] = useState2(() => /* @__PURE__ */ new Map());
271
+ const [ts, setTs] = useState2([]);
272
+ const [reactions, setReactions] = useState2({});
273
+ const [panelH, setPanelH] = useState2(600);
274
+ const [lastUserMsg, setLastUserMsg] = useState2("");
285
275
  const endRef = useRef2(null);
286
276
  const inputRef = useRef2(null);
287
- const prevLen = useRef2(0);
288
- if (messages.length > prevLen.current) {
289
- for (let i = prevLen.current; i < messages.length; i++)
290
- if (!ts.has(i)) ts.set(i, /* @__PURE__ */ new Date());
291
- prevLen.current = messages.length;
292
- }
277
+ const resizeRef = useRef2(null);
278
+ const STORAGE_KEY = persistKey || "default";
279
+ const loaded = useRef2(false);
280
+ useEffect(() => {
281
+ if (loaded.current || !persistKey) return;
282
+ loaded.current = true;
283
+ const saved = loadHistory(STORAGE_KEY);
284
+ if (saved?.messages?.length) {
285
+ }
286
+ }, []);
287
+ useEffect(() => {
288
+ if (!persistKey || messages.length === 0) return;
289
+ saveHistory(STORAGE_KEY, messages, ts);
290
+ }, [messages, ts, persistKey]);
291
+ useEffect(() => {
292
+ if (messages.length > ts.length) {
293
+ setTs((prev) => {
294
+ const next = [...prev];
295
+ while (next.length < messages.length) next.push(/* @__PURE__ */ new Date());
296
+ return next;
297
+ });
298
+ }
299
+ }, [messages.length]);
293
300
  useEffect(() => {
294
301
  endRef.current?.scrollIntoView({ behavior: "smooth" });
295
302
  }, [messages, isLoading]);
296
303
  useEffect(() => {
297
304
  if (open) setTimeout(() => inputRef.current?.focus(), 120);
298
305
  }, [open]);
299
- const send = useCallback2(() => {
300
- const t = input.trim();
306
+ const send = useCallback2((text) => {
307
+ const t = (text || input).trim();
301
308
  if (!t || isLoading) return;
309
+ setLastUserMsg(t);
302
310
  setInput("");
303
311
  sendMessage(t);
304
312
  }, [input, isLoading, sendMessage]);
@@ -308,13 +316,40 @@ function ChatInner({
308
316
  send();
309
317
  }
310
318
  };
319
+ const handleReact = useCallback2((idx, r) => {
320
+ setReactions((prev) => ({ ...prev, [idx]: prev[idx] === r ? void 0 : r }));
321
+ onReaction?.(idx, r, messages[idx]?.content || "");
322
+ }, [messages, onReaction]);
323
+ const newConversation = useCallback2(() => {
324
+ if (persistKey) clearHistory(STORAGE_KEY);
325
+ setTs([]);
326
+ setReactions({});
327
+ setLastUserMsg("");
328
+ reset();
329
+ }, [reset, persistKey]);
330
+ const onResizeStart = useCallback2((e) => {
331
+ e.preventDefault();
332
+ resizeRef.current = { startY: e.clientY, startH: panelH };
333
+ const onMove = (ev) => {
334
+ if (!resizeRef.current) return;
335
+ const delta = resizeRef.current.startY - ev.clientY;
336
+ setPanelH(Math.min(Math.max(resizeRef.current.startH + delta, 320), window.innerHeight - 120));
337
+ };
338
+ const onUp = () => {
339
+ resizeRef.current = null;
340
+ window.removeEventListener("mousemove", onMove);
341
+ window.removeEventListener("mouseup", onUp);
342
+ };
343
+ window.addEventListener("mousemove", onMove);
344
+ window.addEventListener("mouseup", onUp);
345
+ }, [panelH]);
311
346
  const noMsgs = messages.length === 0;
312
347
  const panel = /* @__PURE__ */ jsxs("div", { className: `sa-panel ${className || ""}`, style: {
313
- height: mode === "inline" ? "100%" : 600,
348
+ height: mode === "inline" ? "100%" : panelH,
314
349
  maxHeight: mode === "inline" ? "none" : "calc(100vh - 110px)",
315
350
  background: "#f8fafc",
316
351
  borderRadius: mode === "inline" ? 14 : 20,
317
- boxShadow: mode === "inline" ? "0 2px 20px rgba(0,0,0,.08)" : "0 24px 64px rgba(0,0,0,.18), 0 4px 24px rgba(0,0,0,.08)",
352
+ boxShadow: mode === "inline" ? "0 2px 20px rgba(0,0,0,.08)" : "0 24px 64px rgba(0,0,0,.18),0 4px 24px rgba(0,0,0,.08)",
318
353
  display: "flex",
319
354
  flexDirection: "column",
320
355
  overflow: "hidden",
@@ -322,29 +357,20 @@ function ChatInner({
322
357
  border: "1px solid rgba(0,0,0,.07)",
323
358
  ...customStyle
324
359
  }, children: [
325
- /* @__PURE__ */ jsx2("style", { children: GLOBAL_CSS(accentColor) }),
326
- /* @__PURE__ */ jsxs("div", { style: {
327
- padding: "13px 16px",
328
- background: `linear-gradient(135deg,${accentColor},${adj(accentColor, -28)})`,
360
+ /* @__PURE__ */ jsx2("style", { children: CSS(accentColor) }),
361
+ mode === "floating" && /* @__PURE__ */ jsx2("div", { className: "sa-resize", onMouseDown: onResizeStart, style: {
362
+ height: 6,
363
+ flexShrink: 0,
364
+ cursor: "ns-resize",
365
+ background: "transparent",
366
+ position: "relative",
329
367
  display: "flex",
330
368
  alignItems: "center",
331
- justifyContent: "space-between",
332
- flexShrink: 0,
333
- boxShadow: "0 2px 12px rgba(0,0,0,.12)"
334
- }, children: [
369
+ justifyContent: "center"
370
+ }, children: /* @__PURE__ */ jsx2("div", { style: { width: 32, height: 3, borderRadius: 2, background: "rgba(0,0,0,.12)" } }) }),
371
+ /* @__PURE__ */ jsxs("div", { style: { padding: "11px 16px", background: `linear-gradient(135deg,${accentColor},${adj(accentColor, -28)})`, display: "flex", alignItems: "center", justifyContent: "space-between", flexShrink: 0, boxShadow: "0 2px 12px rgba(0,0,0,.12)" }, children: [
335
372
  /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 10 }, children: [
336
- /* @__PURE__ */ jsx2("div", { style: {
337
- width: 36,
338
- height: 36,
339
- borderRadius: "50%",
340
- background: "rgba(255,255,255,.18)",
341
- backdropFilter: "blur(8px)",
342
- display: "flex",
343
- alignItems: "center",
344
- justifyContent: "center",
345
- fontSize: 17,
346
- boxShadow: "0 2px 8px rgba(0,0,0,.15)"
347
- }, children: "\u2726" }),
373
+ /* @__PURE__ */ jsx2("div", { style: { width: 36, height: 36, borderRadius: "50%", background: "rgba(255,255,255,.18)", backdropFilter: "blur(8px)", display: "flex", alignItems: "center", justifyContent: "center", fontSize: 17, boxShadow: "0 2px 8px rgba(0,0,0,.15)" }, children: "\u2726" }),
348
374
  /* @__PURE__ */ jsxs("div", { children: [
349
375
  /* @__PURE__ */ jsx2("div", { style: { color: "white", fontWeight: 700, fontSize: 14, lineHeight: 1.2, letterSpacing: "-0.01em" }, children: title }),
350
376
  /* @__PURE__ */ jsx2("div", { style: { color: "rgba(255,255,255,.72)", fontSize: 11, marginTop: 1 }, children: isLoading ? /* @__PURE__ */ jsxs("span", { style: { animation: "sa-pulse 1.2s infinite" }, children: [
@@ -354,87 +380,41 @@ function ChatInner({
354
380
  ] })
355
381
  ] }),
356
382
  /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 4 }, children: [
357
- messages.length > 0 && /* @__PURE__ */ jsx2("button", { onClick: reset, style: {
358
- background: "rgba(255,255,255,.15)",
359
- border: "none",
360
- color: "white",
361
- cursor: "pointer",
362
- borderRadius: 7,
363
- padding: "4px 9px",
364
- fontSize: 11,
365
- fontWeight: 500,
366
- backdropFilter: "blur(4px)"
367
- }, children: "Clear" }),
368
- mode === "floating" && /* @__PURE__ */ jsx2("button", { onClick: () => setOpen(false), style: {
369
- background: "rgba(255,255,255,.15)",
370
- border: "none",
371
- color: "white",
372
- cursor: "pointer",
373
- borderRadius: 7,
374
- padding: "4px 9px",
375
- fontSize: 18,
376
- lineHeight: 1,
377
- backdropFilter: "blur(4px)"
378
- }, children: "\xD7" })
383
+ messages.length > 0 && /* @__PURE__ */ jsxs("button", { onClick: newConversation, title: "New conversation", style: { background: "rgba(255,255,255,.15)", border: "none", color: "white", cursor: "pointer", borderRadius: 7, padding: "4px 9px", fontSize: 11, fontWeight: 500, backdropFilter: "blur(4px)", display: "flex", alignItems: "center", gap: 4 }, children: [
384
+ /* @__PURE__ */ jsx2("svg", { width: "11", height: "11", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx2("path", { d: "M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z" }) }),
385
+ "New"
386
+ ] }),
387
+ mode === "floating" && /* @__PURE__ */ jsx2("button", { onClick: () => setOpen(false), style: { background: "rgba(255,255,255,.15)", border: "none", color: "white", cursor: "pointer", borderRadius: 7, padding: "4px 9px", fontSize: 18, lineHeight: 1, backdropFilter: "blur(4px)" }, children: "\xD7" })
379
388
  ] })
380
389
  ] }),
381
- /* @__PURE__ */ jsxs("div", { className: "sa-scroll", style: {
382
- flex: 1,
383
- overflowY: "auto",
384
- padding: "16px 14px 8px",
385
- display: "flex",
386
- flexDirection: "column",
387
- gap: 16,
388
- background: "#f8fafc"
389
- }, children: [
390
- noMsgs && /* @__PURE__ */ jsxs("div", { style: {
391
- flex: 1,
392
- display: "flex",
393
- flexDirection: "column",
394
- alignItems: "center",
395
- justifyContent: "center",
396
- padding: "32px 20px",
397
- textAlign: "center"
398
- }, children: [
399
- /* @__PURE__ */ jsx2("div", { style: {
400
- width: 56,
401
- height: 56,
402
- borderRadius: "50%",
403
- marginBottom: 14,
404
- background: `linear-gradient(135deg,${accentColor}18,${accentColor}35)`,
405
- display: "flex",
406
- alignItems: "center",
407
- justifyContent: "center",
408
- fontSize: 24,
409
- boxShadow: `0 4px 20px ${accentColor}22`
410
- }, children: "\u2726" }),
390
+ /* @__PURE__ */ jsxs("div", { className: "sa-scroll", style: { flex: 1, overflowY: "auto", padding: "16px 14px 8px", display: "flex", flexDirection: "column", gap: 16, background: "#f8fafc" }, children: [
391
+ noMsgs && /* @__PURE__ */ jsxs("div", { style: { flex: 1, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", padding: "32px 20px", textAlign: "center" }, children: [
392
+ /* @__PURE__ */ jsx2("div", { style: { width: 56, height: 56, borderRadius: "50%", marginBottom: 14, background: `linear-gradient(135deg,${accentColor}18,${accentColor}35)`, display: "flex", alignItems: "center", justifyContent: "center", fontSize: 24, boxShadow: `0 4px 20px ${accentColor}22` }, children: "\u2726" }),
411
393
  /* @__PURE__ */ jsx2("p", { style: { fontSize: 14, color: "#64748b", lineHeight: 1.65, maxWidth: 260, margin: 0 }, children: welcomeMessage })
412
394
  ] }),
413
395
  messages.map((msg, i) => /* @__PURE__ */ jsx2(
414
396
  Bubble,
415
397
  {
398
+ idx: i,
416
399
  role: msg.role,
417
400
  content: msg.content,
418
401
  streaming: isLoading && i === messages.length - 1 && msg.role === "assistant",
419
402
  accent: accentColor,
420
- time: ts.get(i) ?? /* @__PURE__ */ new Date()
403
+ time: ts[i] ?? /* @__PURE__ */ new Date(),
404
+ reactions,
405
+ onReact: handleReact,
406
+ onRetry: !isLoading && i === messages.length - 1 && msg.role === "assistant" && !!error ? () => send(lastUserMsg) : void 0,
407
+ hasError: !!error && i === messages.length - 1 && msg.role === "assistant"
421
408
  },
422
409
  i
423
410
  )),
424
- error && /* @__PURE__ */ jsxs("div", { style: {
425
- padding: "10px 14px",
426
- borderRadius: 10,
427
- fontSize: 13,
428
- background: "#fef2f2",
429
- color: "#dc2626",
430
- border: "1px solid #fecaca",
431
- alignSelf: "flex-start",
432
- display: "flex",
433
- alignItems: "center",
434
- gap: 6
435
- }, children: [
411
+ error && /* @__PURE__ */ jsxs("div", { style: { padding: "10px 14px", borderRadius: 10, fontSize: 13, background: "#fef2f2", color: "#dc2626", border: "1px solid #fecaca", alignSelf: "flex-start", display: "flex", alignItems: "center", gap: 8 }, children: [
436
412
  /* @__PURE__ */ jsx2("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx2("path", { d: "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z" }) }),
437
- error.message
413
+ /* @__PURE__ */ jsx2("span", { children: error.message }),
414
+ lastUserMsg && /* @__PURE__ */ jsxs("button", { onClick: () => send(lastUserMsg), style: { marginLeft: 4, padding: "3px 10px", borderRadius: 6, border: "1px solid #fecaca", background: "white", color: "#dc2626", cursor: "pointer", fontSize: 11, fontWeight: 600, display: "flex", alignItems: "center", gap: 3 }, children: [
415
+ /* @__PURE__ */ jsx2("svg", { width: "10", height: "10", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx2("path", { d: "M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z" }) }),
416
+ "Retry"
417
+ ] })
438
418
  ] }),
439
419
  /* @__PURE__ */ jsx2("div", { ref: endRef })
440
420
  ] }),
@@ -442,23 +422,8 @@ function ChatInner({
442
422
  setInput(s);
443
423
  inputRef.current?.focus();
444
424
  }, accent: accentColor }),
445
- isLoading && status && status.step !== "done" && /* @__PURE__ */ jsxs("div", { style: {
446
- padding: "7px 14px",
447
- borderTop: "1px solid #f0f4f8",
448
- background: "#fafbfc",
449
- display: "flex",
450
- alignItems: "center",
451
- gap: 8,
452
- flexShrink: 0
453
- }, children: [
454
- /* @__PURE__ */ jsx2("div", { style: { display: "flex", gap: 3 }, children: [0, 1, 2].map((i) => /* @__PURE__ */ jsx2("div", { style: {
455
- width: 5,
456
- height: 5,
457
- borderRadius: "50%",
458
- background: accentColor,
459
- animation: "sa-bounce 1.2s infinite",
460
- animationDelay: `${i * 0.15}s`
461
- } }, i)) }),
425
+ isLoading && status && status.step !== "done" && /* @__PURE__ */ jsxs("div", { style: { padding: "7px 14px", borderTop: "1px solid #f0f4f8", background: "#fafbfc", display: "flex", alignItems: "center", gap: 8, flexShrink: 0 }, children: [
426
+ /* @__PURE__ */ jsx2("div", { style: { display: "flex", gap: 3 }, children: [0, 1, 2].map((i) => /* @__PURE__ */ jsx2("div", { style: { width: 5, height: 5, borderRadius: "50%", background: accentColor, animation: "sa-bounce 1.2s infinite", animationDelay: `${i * 0.15}s` } }, i)) }),
462
427
  /* @__PURE__ */ jsxs("span", { style: { fontSize: 11.5, color: "#64748b", fontWeight: 500 }, children: [
463
428
  status.step === "connecting" && "\u{1F50C} ",
464
429
  status.step === "schema" && "\u{1F4CB} ",
@@ -468,22 +433,8 @@ function ChatInner({
468
433
  status.label
469
434
  ] })
470
435
  ] }),
471
- /* @__PURE__ */ jsxs("div", { style: {
472
- padding: "10px 12px 12px",
473
- borderTop: "1px solid #e8edf3",
474
- background: "#ffffff",
475
- flexShrink: 0
476
- }, children: [
477
- /* @__PURE__ */ jsxs("div", { style: {
478
- display: "flex",
479
- gap: 8,
480
- alignItems: "flex-end",
481
- background: "#f1f5f9",
482
- borderRadius: 14,
483
- border: "1.5px solid #e2e8f0",
484
- padding: "8px 8px 8px 14px",
485
- transition: "border-color .15s, box-shadow .15s"
486
- }, children: [
436
+ /* @__PURE__ */ jsxs("div", { style: { padding: "10px 12px 12px", borderTop: "1px solid #e8edf3", background: "#ffffff", flexShrink: 0 }, children: [
437
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 8, alignItems: "flex-end", background: "#f1f5f9", borderRadius: 14, border: "1.5px solid #e2e8f0", padding: "8px 8px 8px 14px", transition: "border-color .15s,box-shadow .15s" }, children: [
487
438
  /* @__PURE__ */ jsx2(
488
439
  "textarea",
489
440
  {
@@ -512,53 +463,15 @@ function ChatInner({
512
463
  placeholder,
513
464
  disabled: isLoading,
514
465
  rows: 1,
515
- style: {
516
- flex: 1,
517
- background: "none",
518
- border: "none",
519
- resize: "none",
520
- fontSize: 13.5,
521
- lineHeight: 1.55,
522
- color: "#1e293b",
523
- fontFamily: "inherit",
524
- padding: 0,
525
- maxHeight: 130,
526
- outline: "none"
527
- }
466
+ style: { flex: 1, background: "none", border: "none", resize: "none", fontSize: 13.5, lineHeight: 1.55, color: "#1e293b", fontFamily: "inherit", padding: 0, maxHeight: 130, outline: "none" }
528
467
  }
529
468
  ),
530
469
  /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 5, alignItems: "flex-end", flexShrink: 0 }, children: [
531
- isLoading && /* @__PURE__ */ jsxs("button", { onClick: stop, style: {
532
- background: "#fef2f2",
533
- border: "1px solid #fecaca",
534
- color: "#dc2626",
535
- borderRadius: 9,
536
- padding: "6px 11px",
537
- cursor: "pointer",
538
- fontSize: 11.5,
539
- fontWeight: 600,
540
- display: "flex",
541
- alignItems: "center",
542
- gap: 4
543
- }, children: [
470
+ isLoading && /* @__PURE__ */ jsxs("button", { onClick: stop, style: { background: "#fef2f2", border: "1px solid #fecaca", color: "#dc2626", borderRadius: 9, padding: "6px 11px", cursor: "pointer", fontSize: 11.5, fontWeight: 600, display: "flex", alignItems: "center", gap: 4 }, children: [
544
471
  /* @__PURE__ */ jsx2("svg", { width: "10", height: "10", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx2("rect", { x: "4", y: "4", width: "16", height: "16" }) }),
545
472
  "Stop"
546
473
  ] }),
547
- /* @__PURE__ */ jsx2("button", { className: "sa-send", onClick: send, disabled: isLoading || !input.trim(), style: {
548
- width: 36,
549
- height: 36,
550
- borderRadius: 10,
551
- border: "none",
552
- background: input.trim() && !isLoading ? `linear-gradient(135deg,${accentColor},${adj(accentColor, -20)})` : "#e2e8f0",
553
- color: input.trim() && !isLoading ? "white" : "#94a3b8",
554
- cursor: "pointer",
555
- display: "flex",
556
- alignItems: "center",
557
- justifyContent: "center",
558
- transition: "all .15s",
559
- flexShrink: 0,
560
- boxShadow: input.trim() && !isLoading ? `0 3px 12px ${accentColor}44` : "none"
561
- }, children: /* @__PURE__ */ jsx2("svg", { width: "15", height: "15", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx2("path", { d: "M2.01 21L23 12 2.01 3 2 10l15 2-15 2z" }) }) })
474
+ /* @__PURE__ */ jsx2("button", { className: "sa-send", onClick: () => send(), disabled: isLoading || !input.trim(), style: { width: 36, height: 36, borderRadius: 10, border: "none", background: input.trim() && !isLoading ? `linear-gradient(135deg,${accentColor},${adj(accentColor, -20)})` : "#e2e8f0", color: input.trim() && !isLoading ? "white" : "#94a3b8", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center", transition: "all .15s", flexShrink: 0, boxShadow: input.trim() && !isLoading ? `0 3px 12px ${accentColor}44` : "none" }, children: /* @__PURE__ */ jsx2("svg", { width: "15", height: "15", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx2("path", { d: "M2.01 21L23 12 2.01 3 2 10l15 2-15 2z" }) }) })
562
475
  ] })
563
476
  ] }),
564
477
  /* @__PURE__ */ jsxs("div", { style: { textAlign: "center", marginTop: 7, fontSize: 10, color: "#c4cdd8", letterSpacing: ".01em" }, children: [
@@ -572,51 +485,10 @@ function ChatInner({
572
485
  if (mode === "inline") return panel;
573
486
  const left = position === "bottom-left";
574
487
  return /* @__PURE__ */ jsxs(Fragment, { children: [
575
- /* @__PURE__ */ jsx2("div", { className: "sa-panel-float", style: {
576
- position: "fixed",
577
- bottom: 84,
578
- zIndex: 99998,
579
- ...left ? { left: 16 } : { right: 16 },
580
- width: 430,
581
- maxWidth: "calc(100vw - 32px)",
582
- transition: "opacity .28s cubic-bezier(.16,1,.3,1), transform .28s cubic-bezier(.16,1,.3,1)",
583
- opacity: open ? 1 : 0,
584
- transform: open ? "translateY(0) scale(1)" : "translateY(20px) scale(.95)",
585
- pointerEvents: open ? "auto" : "none"
586
- }, children: panel }),
587
- /* @__PURE__ */ jsxs("button", { className: "sa-fab", onClick: () => setOpen((o) => !o), style: {
588
- position: "fixed",
589
- bottom: 16,
590
- zIndex: 99999,
591
- ...left ? { left: 16 } : { right: 16 },
592
- width: 58,
593
- height: 58,
594
- borderRadius: "50%",
595
- border: "none",
596
- background: `linear-gradient(135deg,${accentColor},${adj(accentColor, -28)})`,
597
- cursor: "pointer",
598
- boxShadow: `0 6px 24px ${accentColor}55, 0 2px 8px rgba(0,0,0,.18)`,
599
- display: "flex",
600
- alignItems: "center",
601
- justifyContent: "center"
602
- }, children: [
603
- /* @__PURE__ */ jsx2("div", { style: {
604
- transition: "transform .3s cubic-bezier(.16,1,.3,1), opacity .2s",
605
- transform: open ? "rotate(90deg) scale(.9)" : "rotate(0) scale(1)",
606
- opacity: open ? 0.85 : 1,
607
- display: "flex"
608
- }, children: open ? /* @__PURE__ */ jsx2("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "white", children: /* @__PURE__ */ jsx2("path", { d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" }) }) : /* @__PURE__ */ jsx2("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "white", children: /* @__PURE__ */ jsx2("path", { d: "M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z" }) }) }),
609
- !open && messages.length > 0 && /* @__PURE__ */ jsx2("div", { style: {
610
- position: "absolute",
611
- top: 3,
612
- right: 3,
613
- width: 13,
614
- height: 13,
615
- borderRadius: "50%",
616
- background: "#ef4444",
617
- border: "2.5px solid white",
618
- animation: "sa-pulse 2s infinite"
619
- } })
488
+ /* @__PURE__ */ jsx2("div", { className: "sa-panel-float", style: { position: "fixed", bottom: 84, zIndex: 99998, ...left ? { left: 16 } : { right: 16 }, width: 430, maxWidth: "calc(100vw - 32px)", transition: "opacity .28s cubic-bezier(.16,1,.3,1),transform .28s cubic-bezier(.16,1,.3,1)", opacity: open ? 1 : 0, transform: open ? "translateY(0) scale(1)" : "translateY(20px) scale(.95)", pointerEvents: open ? "auto" : "none" }, children: panel }),
489
+ /* @__PURE__ */ jsxs("button", { className: "sa-fab", onClick: () => setOpen((o) => !o), style: { position: "fixed", bottom: 16, zIndex: 99999, ...left ? { left: 16 } : { right: 16 }, width: 58, height: 58, borderRadius: "50%", border: "none", background: `linear-gradient(135deg,${accentColor},${adj(accentColor, -28)})`, cursor: "pointer", boxShadow: `0 6px 24px ${accentColor}55,0 2px 8px rgba(0,0,0,.18)`, display: "flex", alignItems: "center", justifyContent: "center", transition: "transform .2s,box-shadow .2s" }, children: [
490
+ /* @__PURE__ */ jsx2("div", { style: { transition: "transform .3s cubic-bezier(.16,1,.3,1),opacity .2s", transform: open ? "rotate(90deg) scale(.9)" : "rotate(0) scale(1)", opacity: open ? 0.85 : 1, display: "flex" }, children: open ? /* @__PURE__ */ jsx2("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "white", children: /* @__PURE__ */ jsx2("path", { d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" }) }) : /* @__PURE__ */ jsx2("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "white", children: /* @__PURE__ */ jsx2("path", { d: "M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z" }) }) }),
491
+ !open && messages.length > 0 && /* @__PURE__ */ jsx2("div", { style: { position: "absolute", top: 3, right: 3, width: 13, height: 13, borderRadius: "50%", background: "#ef4444", border: "2.5px solid white", animation: "sa-pulse 2s infinite" } })
620
492
  ] })
621
493
  ] });
622
494
  }