@mnexium/chat-react 1.0.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.
package/dist/index.js ADDED
@@ -0,0 +1,615 @@
1
+ "use client";
2
+ "use strict";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/index.ts
22
+ var index_exports = {};
23
+ __export(index_exports, {
24
+ MnexiumChat: () => MnexiumChat,
25
+ default: () => MnexiumChat
26
+ });
27
+ module.exports = __toCommonJS(index_exports);
28
+
29
+ // src/client/MnexiumChat.tsx
30
+ var import_react = require("react");
31
+ var import_jsx_runtime = require("react/jsx-runtime");
32
+ var themes = {
33
+ dark: {
34
+ bg: "#1a1a1a",
35
+ bgSecondary: "#2a2a2a",
36
+ border: "#333",
37
+ text: "#fff",
38
+ textSecondary: "#e5e5e5",
39
+ textMuted: "#888",
40
+ inputBg: "#2a2a2a",
41
+ inputBorder: "#444",
42
+ codeBg: "#374151",
43
+ codeBlockBg: "#1f2937"
44
+ },
45
+ light: {
46
+ bg: "#ffffff",
47
+ bgSecondary: "#f3f4f6",
48
+ border: "#e5e7eb",
49
+ text: "#111827",
50
+ textSecondary: "#374151",
51
+ textMuted: "#6b7280",
52
+ inputBg: "#f9fafb",
53
+ inputBorder: "#d1d5db",
54
+ codeBg: "#e5e7eb",
55
+ codeBlockBg: "#f3f4f6"
56
+ }
57
+ };
58
+ function generateId() {
59
+ return Math.random().toString(36).substring(2, 15);
60
+ }
61
+ function renderMarkdown(text, themeColors) {
62
+ if (!text) return null;
63
+ const lines = text.split("\n");
64
+ const elements = [];
65
+ let inCodeBlock = false;
66
+ let codeContent = [];
67
+ const processInline = (line) => {
68
+ const parts = [];
69
+ let remaining = line;
70
+ let key = 0;
71
+ while (remaining.length > 0) {
72
+ const codeMatch = remaining.match(/`([^`]+)`/);
73
+ const boldMatch = remaining.match(/\*\*([^*]+)\*\*/);
74
+ const italicMatch = remaining.match(/\*([^*]+)\*/);
75
+ const matches = [
76
+ codeMatch ? { type: "code", match: codeMatch, index: codeMatch.index } : null,
77
+ boldMatch ? { type: "bold", match: boldMatch, index: boldMatch.index } : null,
78
+ italicMatch ? { type: "italic", match: italicMatch, index: italicMatch.index } : null
79
+ ].filter(Boolean).sort((a, b) => a.index - b.index);
80
+ if (matches.length === 0) {
81
+ parts.push(remaining);
82
+ break;
83
+ }
84
+ const first = matches[0];
85
+ if (first.index > 0) {
86
+ parts.push(remaining.substring(0, first.index));
87
+ }
88
+ if (first.type === "code") {
89
+ parts.push(
90
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { style: { backgroundColor: themeColors.codeBg, padding: "2px 6px", borderRadius: "4px", fontSize: "13px" }, children: first.match[1] }, key++)
91
+ );
92
+ } else if (first.type === "bold") {
93
+ parts.push(/* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: first.match[1] }, key++));
94
+ } else if (first.type === "italic") {
95
+ parts.push(/* @__PURE__ */ (0, import_jsx_runtime.jsx)("em", { children: first.match[1] }, key++));
96
+ }
97
+ remaining = remaining.substring(first.index + first.match[0].length);
98
+ }
99
+ return parts.length === 1 ? parts[0] : parts;
100
+ };
101
+ for (let i = 0; i < lines.length; i++) {
102
+ const line = lines[i];
103
+ if (line.startsWith("```")) {
104
+ if (!inCodeBlock) {
105
+ inCodeBlock = true;
106
+ codeContent = [];
107
+ } else {
108
+ elements.push(
109
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("pre", { style: { backgroundColor: themeColors.codeBlockBg, padding: "12px", borderRadius: "8px", overflow: "auto", fontSize: "13px", margin: "8px 0" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: codeContent.join("\n") }) }, i)
110
+ );
111
+ inCodeBlock = false;
112
+ }
113
+ continue;
114
+ }
115
+ if (inCodeBlock) {
116
+ codeContent.push(line);
117
+ continue;
118
+ }
119
+ if (line.startsWith("### ")) {
120
+ elements.push(/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h4", { style: { margin: "12px 0 8px", fontSize: "14px", fontWeight: 600 }, children: processInline(line.slice(4)) }, i));
121
+ } else if (line.startsWith("## ")) {
122
+ elements.push(/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { style: { margin: "12px 0 8px", fontSize: "15px", fontWeight: 600 }, children: processInline(line.slice(3)) }, i));
123
+ } else if (line.startsWith("# ")) {
124
+ elements.push(/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { style: { margin: "12px 0 8px", fontSize: "16px", fontWeight: 600 }, children: processInline(line.slice(2)) }, i));
125
+ } else if (line.startsWith("- ") || line.startsWith("* ")) {
126
+ elements.push(/* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { style: { marginLeft: "16px", listStyleType: "disc" }, children: processInline(line.slice(2)) }, i));
127
+ } else if (/^\d+\.\s/.test(line)) {
128
+ const content = line.replace(/^\d+\.\s/, "");
129
+ elements.push(/* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { style: { marginLeft: "16px", listStyleType: "decimal" }, children: processInline(content) }, i));
130
+ } else if (line.trim() === "") {
131
+ elements.push(/* @__PURE__ */ (0, import_jsx_runtime.jsx)("br", {}, i));
132
+ } else {
133
+ elements.push(/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { margin: "4px 0" }, children: processInline(line) }, i));
134
+ }
135
+ }
136
+ if (inCodeBlock && codeContent.length > 0) {
137
+ elements.push(
138
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("pre", { style: { backgroundColor: themeColors.codeBlockBg, padding: "12px", borderRadius: "8px", overflow: "auto", fontSize: "13px", margin: "8px 0" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: codeContent.join("\n") }) }, "final-code")
139
+ );
140
+ }
141
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: elements });
142
+ }
143
+ function MnexiumChat({
144
+ endpoint = "/api/mnx",
145
+ placeholder = "Type a message...",
146
+ title = "Ask AI",
147
+ buttonLabel = "Ask AI",
148
+ position = "bottom-right",
149
+ primaryColor = "#facc15",
150
+ defaultOpen = false,
151
+ logo,
152
+ theme = "dark",
153
+ welcomeIcon = "\u{1F44B}",
154
+ welcomeMessage = "How can I help you today?",
155
+ history = false,
156
+ eagerInit = true
157
+ }) {
158
+ const t = themes[theme];
159
+ const [isOpen, setIsOpen] = (0, import_react.useState)(defaultOpen);
160
+ const [messages, setMessages] = (0, import_react.useState)([]);
161
+ const [input, setInput] = (0, import_react.useState)("");
162
+ const [isLoading, setIsLoading] = (0, import_react.useState)(false);
163
+ const [isStreaming, setIsStreaming] = (0, import_react.useState)(false);
164
+ const [isInitialized, setIsInitialized] = (0, import_react.useState)(false);
165
+ const [error, setError] = (0, import_react.useState)(null);
166
+ const messagesEndRef = (0, import_react.useRef)(null);
167
+ const inputRef = (0, import_react.useRef)(null);
168
+ const scrollToBottom = (0, import_react.useCallback)(() => {
169
+ messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
170
+ }, []);
171
+ (0, import_react.useEffect)(() => {
172
+ scrollToBottom();
173
+ }, [messages, scrollToBottom]);
174
+ (0, import_react.useEffect)(() => {
175
+ if (isOpen && inputRef.current) {
176
+ inputRef.current.focus();
177
+ }
178
+ }, [isOpen]);
179
+ (0, import_react.useEffect)(() => {
180
+ if (!eagerInit && !isOpen) return;
181
+ const bootstrap = async () => {
182
+ if (isInitialized) return;
183
+ try {
184
+ const res = await fetch(`${endpoint}/bootstrap`);
185
+ if (!res.ok) throw new Error("Failed to bootstrap");
186
+ const data = await res.json();
187
+ if (history && data.chat_id) {
188
+ try {
189
+ const historyRes = await fetch(`${endpoint}/conversations/${data.chat_id}`);
190
+ if (historyRes.ok) {
191
+ const historyData = await historyRes.json();
192
+ if (historyData.messages && Array.isArray(historyData.messages)) {
193
+ setMessages(historyData.messages.map((m) => ({
194
+ id: generateId(),
195
+ role: m.role,
196
+ content: m.content,
197
+ timestamp: /* @__PURE__ */ new Date()
198
+ })));
199
+ }
200
+ }
201
+ } catch {
202
+ }
203
+ }
204
+ setIsInitialized(true);
205
+ } catch (err) {
206
+ setError("Failed to initialize chat");
207
+ console.error("Bootstrap error:", err);
208
+ }
209
+ };
210
+ bootstrap();
211
+ }, [endpoint, isOpen, isInitialized, history, eagerInit]);
212
+ const sendMessage = async () => {
213
+ if (!input.trim() || isLoading || isStreaming) return;
214
+ const userMessage = {
215
+ id: generateId(),
216
+ role: "user",
217
+ content: input.trim(),
218
+ timestamp: /* @__PURE__ */ new Date()
219
+ };
220
+ setMessages((prev) => [...prev, userMessage]);
221
+ setInput("");
222
+ setIsLoading(true);
223
+ setError(null);
224
+ const assistantMessageId = generateId();
225
+ try {
226
+ const res = await fetch(`${endpoint}/chat`, {
227
+ method: "POST",
228
+ headers: { "Content-Type": "application/json" },
229
+ body: JSON.stringify({ message: userMessage.content })
230
+ });
231
+ if (!res.ok) throw new Error("Failed to send message");
232
+ if (!res.body) throw new Error("No response body");
233
+ setIsLoading(false);
234
+ setIsStreaming(true);
235
+ const assistantMessage = {
236
+ id: assistantMessageId,
237
+ role: "assistant",
238
+ content: "",
239
+ timestamp: /* @__PURE__ */ new Date()
240
+ };
241
+ setMessages((prev) => [...prev, assistantMessage]);
242
+ const reader = res.body.getReader();
243
+ const decoder = new TextDecoder();
244
+ let buffer = "";
245
+ while (true) {
246
+ const { done, value } = await reader.read();
247
+ if (done) break;
248
+ buffer += decoder.decode(value, { stream: true });
249
+ const lines = buffer.split("\n");
250
+ buffer = lines.pop() || "";
251
+ for (const line of lines) {
252
+ if (line.startsWith("data: ")) {
253
+ const data = line.slice(6);
254
+ if (data === "[DONE]") continue;
255
+ try {
256
+ const parsed = JSON.parse(data);
257
+ const content = parsed.choices?.[0]?.delta?.content;
258
+ if (content) {
259
+ setMessages(
260
+ (prev) => prev.map(
261
+ (m) => m.id === assistantMessageId ? { ...m, content: m.content + content } : m
262
+ )
263
+ );
264
+ }
265
+ } catch {
266
+ }
267
+ }
268
+ }
269
+ }
270
+ if (buffer.startsWith("data: ")) {
271
+ const data = buffer.slice(6);
272
+ if (data !== "[DONE]") {
273
+ try {
274
+ const parsed = JSON.parse(data);
275
+ const content = parsed.choices?.[0]?.delta?.content;
276
+ if (content) {
277
+ setMessages(
278
+ (prev) => prev.map(
279
+ (m) => m.id === assistantMessageId ? { ...m, content: m.content + content } : m
280
+ )
281
+ );
282
+ }
283
+ } catch {
284
+ }
285
+ }
286
+ }
287
+ } catch (err) {
288
+ setError("Failed to send message");
289
+ console.error("Chat error:", err);
290
+ setMessages((prev) => prev.filter((m) => m.id !== assistantMessageId));
291
+ } finally {
292
+ setIsLoading(false);
293
+ setIsStreaming(false);
294
+ requestAnimationFrame(() => {
295
+ inputRef.current?.focus();
296
+ });
297
+ }
298
+ };
299
+ const handleKeyDown = (e) => {
300
+ if (e.key === "Enter" && !e.shiftKey) {
301
+ e.preventDefault();
302
+ sendMessage();
303
+ }
304
+ };
305
+ const startNewChat = async () => {
306
+ try {
307
+ const res = await fetch(`${endpoint}/new-chat`, { method: "POST" });
308
+ if (res.ok) {
309
+ setMessages([]);
310
+ }
311
+ } catch {
312
+ setMessages([]);
313
+ }
314
+ };
315
+ const positionStyles = position === "bottom-right" ? { right: "20px", bottom: "20px" } : { left: "20px", bottom: "20px" };
316
+ const chatPositionStyles = position === "bottom-right" ? { right: "0", bottom: "60px" } : { left: "0", bottom: "60px" };
317
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
318
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: `
319
+ @keyframes mnx-typing {
320
+ 0%, 80%, 100% { transform: scale(0.8); opacity: 0.5; }
321
+ 40% { transform: scale(1); opacity: 1; }
322
+ }
323
+ @keyframes mnx-fade-in {
324
+ from { opacity: 0; transform: translateY(10px) scale(0.95); }
325
+ to { opacity: 1; transform: translateY(0) scale(1); }
326
+ }
327
+ @keyframes mnx-fade-out {
328
+ from { opacity: 1; transform: translateY(0) scale(1); }
329
+ to { opacity: 0; transform: translateY(10px) scale(0.95); }
330
+ }
331
+ @keyframes mnx-pulse {
332
+ 0% { box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); }
333
+ 50% { box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4); }
334
+ 100% { box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); }
335
+ }
336
+ .mnx-typing-dot:nth-child(1) { animation-delay: 0s; }
337
+ .mnx-typing-dot:nth-child(2) { animation-delay: 0.2s; }
338
+ .mnx-typing-dot:nth-child(3) { animation-delay: 0.4s; }
339
+ .mnx-btn-icon {
340
+ transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
341
+ }
342
+ .mnx-btn-icon.open {
343
+ transform: rotate(45deg);
344
+ }
345
+ ` }),
346
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: {
347
+ position: "fixed",
348
+ zIndex: 9999,
349
+ fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
350
+ ...positionStyles
351
+ }, children: [
352
+ isOpen && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: {
353
+ position: "absolute",
354
+ ...chatPositionStyles,
355
+ width: "380px",
356
+ height: "500px",
357
+ backgroundColor: theme === "dark" ? "rgba(26, 26, 26, 0.9)" : "rgba(255, 255, 255, 0.9)",
358
+ backdropFilter: "blur(8px) saturate(180%)",
359
+ WebkitBackdropFilter: "blur(16px) saturate(180%)",
360
+ borderRadius: "16px",
361
+ border: `1px solid ${primaryColor}33`,
362
+ boxShadow: theme === "dark" ? "0 25px 50px -12px rgba(0, 0, 0, 0.5)" : "0 25px 50px -12px rgba(0, 0, 0, 0.15)",
363
+ display: "flex",
364
+ flexDirection: "column",
365
+ overflow: "hidden",
366
+ animation: "mnx-fade-in 0.2s ease-out",
367
+ transform: "translateZ(0)",
368
+ isolation: "isolate"
369
+ }, children: [
370
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: {
371
+ display: "flex",
372
+ alignItems: "center",
373
+ justifyContent: "space-between",
374
+ padding: "8px 8px",
375
+ borderBottom: `1px solid ${t.border}`,
376
+ backgroundColor: theme === "dark" ? "rgba(26, 26, 26, 0.7)" : "rgba(255, 255, 255, 0.7)"
377
+ }, children: [
378
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "10px" }, children: [
379
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: {
380
+ width: "32px",
381
+ height: "32px",
382
+ backgroundColor: primaryColor,
383
+ borderRadius: "8px",
384
+ display: "flex",
385
+ alignItems: "center",
386
+ justifyContent: "center",
387
+ overflow: "hidden"
388
+ }, children: logo ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", { src: logo, alt: "", style: { width: "100%", height: "100%", objectFit: "cover" } }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "#000", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
389
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 2L2 7l10 5 10-5-10-5z" }),
390
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M2 17l10 5 10-5" }),
391
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M2 12l10 5 10-5" })
392
+ ] }) }),
393
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { color: t.text, fontWeight: 600, fontSize: "15px" }, children: title })
394
+ ] }),
395
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "4px" }, children: [
396
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
397
+ "button",
398
+ {
399
+ onClick: startNewChat,
400
+ style: {
401
+ background: "none",
402
+ border: "none",
403
+ color: t.textMuted,
404
+ cursor: "pointer",
405
+ padding: "6px",
406
+ borderRadius: "6px",
407
+ display: "flex",
408
+ alignItems: "center",
409
+ justifyContent: "center"
410
+ },
411
+ title: "New chat",
412
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
413
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "12", y1: "5", x2: "12", y2: "19" }),
414
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "5", y1: "12", x2: "19", y2: "12" })
415
+ ] })
416
+ }
417
+ ),
418
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
419
+ "button",
420
+ {
421
+ onClick: () => setIsOpen(false),
422
+ style: {
423
+ background: "none",
424
+ border: "none",
425
+ color: t.textMuted,
426
+ cursor: "pointer",
427
+ padding: "4px",
428
+ display: "flex",
429
+ alignItems: "center",
430
+ justifyContent: "center"
431
+ },
432
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
433
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
434
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
435
+ ] })
436
+ }
437
+ )
438
+ ] })
439
+ ] }),
440
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: {
441
+ flex: 1,
442
+ overflowY: "auto",
443
+ padding: "8px 8px",
444
+ display: "flex",
445
+ flexDirection: "column",
446
+ gap: "12px"
447
+ }, children: [
448
+ !isInitialized && !error && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", height: "100%", color: t.textMuted }, children: "Initializing..." }),
449
+ error && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", height: "100%", color: "#ef4444" }, children: error }),
450
+ isInitialized && messages.length === 0 && !error && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", height: "100%", color: t.textMuted, textAlign: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
451
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: "24px", marginBottom: "8px" }, children: welcomeIcon }),
452
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: welcomeMessage })
453
+ ] }) }),
454
+ messages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
455
+ "div",
456
+ {
457
+ style: {
458
+ maxWidth: "85%",
459
+ padding: "10px 14px",
460
+ borderRadius: "12px",
461
+ fontSize: "14px",
462
+ lineHeight: 1.5,
463
+ wordBreak: "break-word",
464
+ ...message.role === "user" ? {
465
+ alignSelf: "flex-end",
466
+ backgroundColor: `${primaryColor}cc`,
467
+ color: "#000",
468
+ borderBottomRightRadius: "4px"
469
+ } : {
470
+ alignSelf: "flex-start",
471
+ backgroundColor: theme === "dark" ? "rgba(42, 42, 42, 0.7)" : "rgba(243, 244, 246, 0.7)",
472
+ color: t.textSecondary,
473
+ borderBottomLeftRadius: "4px"
474
+ }
475
+ },
476
+ children: message.role === "assistant" ? renderMarkdown(message.content, { codeBg: t.codeBg, codeBlockBg: t.codeBlockBg }) : message.content
477
+ },
478
+ message.id
479
+ )),
480
+ isLoading && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: {
481
+ display: "flex",
482
+ gap: "4px",
483
+ padding: "10px 14px",
484
+ alignSelf: "flex-start",
485
+ backgroundColor: theme === "dark" ? "rgba(42, 42, 42, 0.7)" : "rgba(243, 244, 246, 0.7)",
486
+ borderRadius: "12px",
487
+ borderBottomLeftRadius: "4px"
488
+ }, children: [
489
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "mnx-typing-dot", style: { width: "6px", height: "6px", backgroundColor: t.textMuted, borderRadius: "50%", animation: "mnx-typing 1.4s infinite ease-in-out" } }),
490
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "mnx-typing-dot", style: { width: "6px", height: "6px", backgroundColor: t.textMuted, borderRadius: "50%", animation: "mnx-typing 1.4s infinite ease-in-out" } }),
491
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "mnx-typing-dot", style: { width: "6px", height: "6px", backgroundColor: t.textMuted, borderRadius: "50%", animation: "mnx-typing 1.4s infinite ease-in-out" } })
492
+ ] }),
493
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ref: messagesEndRef })
494
+ ] }),
495
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: {
496
+ display: "flex",
497
+ gap: "8px",
498
+ padding: "8px 8px",
499
+ borderTop: `1px solid ${t.border}`,
500
+ backgroundColor: theme === "dark" ? "rgba(26, 26, 26, 0.5)" : "rgba(255, 255, 255, 0.5)"
501
+ }, children: [
502
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
503
+ "input",
504
+ {
505
+ ref: inputRef,
506
+ type: "text",
507
+ value: input,
508
+ onChange: (e) => setInput(e.target.value),
509
+ onKeyDown: handleKeyDown,
510
+ placeholder,
511
+ disabled: !isInitialized || isLoading || isStreaming,
512
+ style: {
513
+ flex: 1,
514
+ padding: "10px 14px",
515
+ backgroundColor: theme === "dark" ? "rgba(42, 42, 42, 0.6)" : "rgba(249, 250, 251, 0.6)",
516
+ border: "none",
517
+ borderRadius: "8px",
518
+ fontSize: "14px",
519
+ color: t.text,
520
+ outline: "none",
521
+ transition: "box-shadow 0.15s ease"
522
+ },
523
+ onFocus: (e) => {
524
+ e.currentTarget.style.boxShadow = `0 0 0 2px ${primaryColor}`;
525
+ },
526
+ onBlur: (e) => {
527
+ e.currentTarget.style.boxShadow = "none";
528
+ }
529
+ }
530
+ ),
531
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
532
+ "button",
533
+ {
534
+ onClick: sendMessage,
535
+ disabled: !isInitialized || !input.trim() || isLoading || isStreaming,
536
+ style: {
537
+ padding: "10px 16px",
538
+ backgroundColor: !isInitialized || !input.trim() || isLoading || isStreaming ? t.inputBorder : primaryColor,
539
+ color: "#000",
540
+ border: "none",
541
+ borderRadius: "8px",
542
+ fontSize: "14px",
543
+ fontWeight: 500,
544
+ cursor: !isInitialized || !input.trim() || isLoading || isStreaming ? "not-allowed" : "pointer",
545
+ display: "flex",
546
+ alignItems: "center",
547
+ justifyContent: "center"
548
+ },
549
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
550
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "22", y1: "2", x2: "11", y2: "13" }),
551
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("polygon", { points: "22 2 15 22 11 13 2 9 22 2" })
552
+ ] })
553
+ }
554
+ )
555
+ ] })
556
+ ] }),
557
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
558
+ "button",
559
+ {
560
+ onClick: () => setIsOpen(!isOpen),
561
+ style: {
562
+ display: "flex",
563
+ alignItems: "center",
564
+ gap: "8px",
565
+ padding: "12px 16px",
566
+ backgroundColor: primaryColor,
567
+ color: "#000",
568
+ border: "none",
569
+ borderRadius: "12px",
570
+ fontSize: "14px",
571
+ fontWeight: 600,
572
+ cursor: "pointer",
573
+ boxShadow: "0 4px 12px rgba(0, 0, 0, 0.3)",
574
+ transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)"
575
+ },
576
+ onMouseEnter: (e) => {
577
+ e.currentTarget.style.transform = "scale(1.05)";
578
+ e.currentTarget.style.boxShadow = "0 6px 20px rgba(0, 0, 0, 0.4)";
579
+ },
580
+ onMouseLeave: (e) => {
581
+ e.currentTarget.style.transform = "scale(1)";
582
+ e.currentTarget.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
583
+ },
584
+ children: [
585
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
586
+ "span",
587
+ {
588
+ className: `mnx-btn-icon ${isOpen ? "open" : ""}`,
589
+ style: { display: "flex", alignItems: "center", justifyContent: "center" },
590
+ children: isOpen ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { width: "28", height: "28", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
591
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
592
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
593
+ ] }) : logo ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", { src: logo, alt: "", style: { height: "28px", width: "auto", objectFit: "contain" } }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { width: "28", height: "28", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
594
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 2L2 7l10 5 10-5-10-5z" }),
595
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M2 17l10 5 10-5" }),
596
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M2 12l10 5 10-5" })
597
+ ] })
598
+ }
599
+ ),
600
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: {
601
+ transition: "opacity 0.2s, width 0.3s",
602
+ overflow: "hidden",
603
+ whiteSpace: "nowrap"
604
+ }, children: isOpen ? "Close" : buttonLabel })
605
+ ]
606
+ }
607
+ )
608
+ ] })
609
+ ] });
610
+ }
611
+ // Annotate the CommonJS export names for ESM import in node:
612
+ 0 && (module.exports = {
613
+ MnexiumChat
614
+ });
615
+ //# sourceMappingURL=index.js.map