@aikaara/chat-sdk 0.2.0 → 0.3.3

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/ui.mjs CHANGED
@@ -1,1012 +1,18 @@
1
- import { a as p, D as u, e as d, f as g, g as m, h as f, i as x, j as k, k as c, l as v } from "./AikaaraChatClient-C4lWcRsS.mjs";
2
- class y {
3
- client;
4
- panel;
5
- bubble;
6
- header;
7
- messageList;
8
- input;
9
- errorBanner;
10
- isOpen = !1;
11
- constructor(e, t) {
12
- this.client = new p(e), this.bubble = t.querySelector("aikaara-chat-bubble"), this.panel = t.querySelector(".aikaara-panel"), this.header = t.querySelector("aikaara-chat-header"), this.messageList = t.querySelector("aikaara-message-list"), this.input = t.querySelector("aikaara-chat-input"), this.errorBanner = t.querySelector("aikaara-error-banner"), e.welcomeMessage && this.messageList.setWelcomeMessage(e.welcomeMessage), e.showTimestamps !== void 0 && this.messageList.setShowTimestamps(e.showTimestamps), this.wireEvents();
13
- }
14
- async connect() {
15
- try {
16
- await this.client.connect(), this.messageList.renderMessages(this.client.messages);
17
- } catch {
18
- this.errorBanner.show("Failed to connect. Retrying...", 5e3);
19
- }
20
- }
21
- async disconnect() {
22
- await this.client.disconnect();
23
- }
24
- wireEvents() {
25
- this.bubble.addEventListener("toggle", () => {
26
- this.togglePanel();
27
- }), this.header.addEventListener("header-close", () => {
28
- this.togglePanel(!1);
29
- }), this.input.addEventListener("send", ((e) => {
30
- this.handleSend(e.detail.content);
31
- })), this.client.on("message:sent", (e) => {
32
- this.messageList.addMessage(e);
33
- }), this.client.on("stream:start", () => {
34
- this.messageList.removeTypingIndicator();
35
- const e = this.client.messages[this.client.messages.length - 1];
36
- e && this.messageList.addMessage(e);
37
- }), this.client.on("stream:update", ({ content: e }) => {
38
- this.messageList.updateStreamingContent(e);
39
- }), this.client.on("stream:end", () => {
40
- this.messageList.finalizeStreaming();
41
- }), this.client.on("typing:start", () => {
42
- const e = this.client.messages, t = e[e.length - 1];
43
- (!t || t.status !== "streaming") && this.messageList.showTypingIndicator();
44
- }), this.client.on("typing:stop", () => {
45
- this.messageList.removeTypingIndicator();
46
- }), this.client.on("connection:state", (e) => {
47
- this.header.setStatus(e), e === "connected" ? (this.errorBanner.hide(), this.input.disabled = !1) : e === "reconnecting" ? (this.errorBanner.show("Connection lost. Reconnecting..."), this.input.disabled = !0) : e === "disconnected" && (this.input.disabled = !0);
48
- }), this.client.on("error", (e) => {
49
- this.errorBanner.show(e.message, 5e3);
50
- });
51
- }
52
- async handleSend(e) {
53
- try {
54
- await this.client.sendMessage(e);
55
- } catch {
56
- this.errorBanner.show("Failed to send message", 3e3);
57
- }
58
- }
59
- sendUserEvent(e, t, a) {
60
- this.client.sendUserEvent(e, t, a);
61
- }
62
- getClient() {
63
- return this.client;
64
- }
65
- togglePanel(e) {
66
- this.isOpen = e !== void 0 ? e : !this.isOpen, this.isOpen ? (this.panel.removeAttribute("hidden"), requestAnimationFrame(() => {
67
- this.panel.classList.remove("entering"), this.panel.classList.add("visible"), this.input.focus();
68
- })) : (this.panel.classList.remove("visible"), this.panel.classList.add("entering"), setTimeout(() => {
69
- this.panel.setAttribute("hidden", "");
70
- }, 200));
71
- }
72
- }
73
- class w extends HTMLElement {
74
- shadow;
75
- controller = null;
76
- _config = {};
77
- static get observedAttributes() {
78
- return [
79
- "base-url",
80
- "ws-url",
81
- "user-token",
82
- "api-key",
83
- "title",
84
- "subtitle",
85
- "theme",
86
- "primary-color",
87
- "position",
88
- "width",
89
- "height",
90
- "placeholder",
91
- "welcome-message",
92
- "avatar-url"
93
- ];
94
- }
95
- constructor() {
96
- super(), this.shadow = this.attachShadow({ mode: "open" });
97
- }
98
- connectedCallback() {
99
- this.render(), this.initController();
100
- }
101
- disconnectedCallback() {
102
- this.controller?.disconnect();
103
- }
104
- attributeChangedCallback(e, t, a) {
105
- t !== a && this.controller && (this.render(), this.initController());
106
- }
107
- configure(e) {
108
- this._config = { ...this._config, ...e };
109
- }
110
- getConfig() {
111
- return {
112
- baseUrl: this.getAttribute("base-url") || this._config.baseUrl || "",
113
- wsUrl: this.getAttribute("ws-url") || this._config.wsUrl,
114
- userToken: this.getAttribute("user-token") || this._config.userToken || "",
115
- apiKey: this.getAttribute("api-key") || this._config.apiKey,
116
- title: this.getAttribute("title") || this._config.title || "Chat",
117
- subtitle: this.getAttribute("subtitle") || this._config.subtitle,
118
- theme: this.getAttribute("theme") || this._config.theme || v,
119
- primaryColor: this.getAttribute("primary-color") || this._config.primaryColor || c,
120
- position: this.getAttribute("position") || this._config.position || k,
121
- width: Number(this.getAttribute("width")) || this._config.width || x,
122
- height: Number(this.getAttribute("height")) || this._config.height || f,
123
- fontFamily: this._config.fontFamily || m,
124
- borderRadius: this._config.borderRadius ?? g,
125
- placeholder: this.getAttribute("placeholder") || this._config.placeholder || d,
126
- welcomeMessage: this.getAttribute("welcome-message") || this._config.welcomeMessage,
127
- avatarUrl: this.getAttribute("avatar-url") || this._config.avatarUrl,
128
- showTimestamps: this._config.showTimestamps ?? !0,
129
- persistConversation: this._config.persistConversation ?? !0,
130
- showBubble: this._config.showBubble ?? !0,
131
- offset: this._config.offset || u,
132
- conversationId: this._config.conversationId,
133
- systemPromptId: this._config.systemPromptId,
134
- channel: this._config.channel,
135
- extUid: this._config.extUid,
136
- onMessage: this._config.onMessage,
137
- onStatusChange: this._config.onStatusChange,
138
- onError: this._config.onError,
139
- onStreamUpdate: this._config.onStreamUpdate,
140
- onConnectionStateChange: this._config.onConnectionStateChange
141
- };
142
- }
143
- render() {
144
- const e = this.getConfig();
145
- this.shadow.innerHTML = `
146
- <style>
147
- :host {
148
- --aikaara-primary: ${e.primaryColor};
149
- --aikaara-primary-hover: ${this.darkenColor(e.primaryColor || c)};
150
- --aikaara-bg: #ffffff;
151
- --aikaara-bg-secondary: #f9fafb;
152
- --aikaara-text: #1f2937;
153
- --aikaara-text-secondary: #6b7280;
154
- --aikaara-border: #e5e7eb;
155
- --aikaara-radius: ${e.borderRadius}px;
156
- --aikaara-font: ${e.fontFamily};
157
- --aikaara-panel-width: ${e.width}px;
158
- --aikaara-panel-height: ${e.height}px;
159
- --aikaara-bubble-size: 60px;
160
- --aikaara-offset-x: ${e.offset?.x ?? 20}px;
161
- --aikaara-offset-y: ${e.offset?.y ?? 20}px;
162
- font-family: var(--aikaara-font);
163
- position: fixed;
164
- z-index: 9999;
165
- bottom: var(--aikaara-offset-y);
166
- ${e.position === "bottom-left" ? "left" : "right"}: var(--aikaara-offset-x);
167
- }
168
-
169
- .aikaara-panel {
170
- width: var(--aikaara-panel-width);
171
- height: var(--aikaara-panel-height);
172
- max-height: calc(100vh - 100px);
173
- background: var(--aikaara-bg);
174
- border-radius: var(--aikaara-radius);
175
- box-shadow: 0 4px 24px rgba(0, 0, 0, 0.12);
176
- border: 1px solid var(--aikaara-border);
177
- display: flex;
178
- flex-direction: column;
179
- overflow: hidden;
180
- position: absolute;
181
- bottom: calc(var(--aikaara-bubble-size) + 16px);
182
- ${e.position === "bottom-left" ? "left" : "right"}: 0;
183
- transition: opacity 200ms ease, transform 200ms ease;
184
- }
185
-
186
- .aikaara-panel[hidden] {
187
- display: none;
188
- }
189
-
190
- .aikaara-panel.entering {
191
- opacity: 0;
192
- transform: translateY(8px) scale(0.98);
193
- }
194
-
195
- .aikaara-panel.visible {
196
- opacity: 1;
197
- transform: translateY(0) scale(1);
198
- }
199
-
200
- aikaara-chat-header,
201
- aikaara-message-list,
202
- aikaara-chat-input,
203
- aikaara-error-banner {
204
- display: block;
205
- }
206
-
207
- aikaara-message-list {
208
- flex: 1;
209
- overflow: scroll;
210
- min-height: 0;
211
- }
212
-
213
- aikaara-chat-input {
214
- flex-shrink: 0;
215
- }
216
-
217
- aikaara-chat-header {
218
- flex-shrink: 0;
219
- }
220
- </style>
221
-
222
- <aikaara-chat-bubble></aikaara-chat-bubble>
223
-
224
- <div class="aikaara-panel entering" hidden role="dialog" aria-label="Chat">
225
- <aikaara-chat-header
226
- title="${e.title || "Chat"}"
227
- ${e.subtitle ? `subtitle="${e.subtitle}"` : ""}
228
- ${e.avatarUrl ? `avatar-url="${e.avatarUrl}"` : ""}
229
- ></aikaara-chat-header>
230
- <aikaara-message-list></aikaara-message-list>
231
- <aikaara-chat-input placeholder="${e.placeholder || d}"></aikaara-chat-input>
232
- <aikaara-error-banner></aikaara-error-banner>
233
- </div>
234
- `;
235
- }
236
- async initController() {
237
- const e = this.getConfig();
238
- !e.baseUrl || !e.userToken || (this.controller?.disconnect(), this.controller = new y(e, this.shadow), await this.controller.connect());
239
- }
240
- sendUserEvent(e, t, a) {
241
- this.controller?.sendUserEvent(e, t, a);
242
- }
243
- getClient() {
244
- return this.controller?.getClient() ?? null;
245
- }
246
- darkenColor(e) {
247
- try {
248
- const t = parseInt(e.replace("#", ""), 16), a = Math.max(0, (t >> 16) - 20), s = Math.max(0, (t >> 8 & 255) - 20), n = Math.max(0, (t & 255) - 20);
249
- return `#${(a << 16 | s << 8 | n).toString(16).padStart(6, "0")}`;
250
- } catch {
251
- return e;
252
- }
253
- }
254
- }
255
- class T extends HTMLElement {
256
- shadow;
257
- constructor() {
258
- super(), this.shadow = this.attachShadow({ mode: "open" });
259
- }
260
- connectedCallback() {
261
- this.render(), this.shadow.querySelector(".bubble")?.addEventListener("click", () => {
262
- this.dispatchEvent(new CustomEvent("toggle", { bubbles: !0, composed: !0 }));
263
- });
264
- }
265
- render() {
266
- this.shadow.innerHTML = `
267
- <style>
268
- .bubble {
269
- width: var(--aikaara-bubble-size, 60px);
270
- height: var(--aikaara-bubble-size, 60px);
271
- border-radius: 50%;
272
- background: var(--aikaara-primary, #6366f1);
273
- color: #ffffff;
274
- border: none;
275
- cursor: pointer;
276
- display: flex;
277
- align-items: center;
278
- justify-content: center;
279
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
280
- transition: transform 200ms ease, box-shadow 200ms ease;
281
- }
282
- .bubble:hover {
283
- transform: scale(1.05);
284
- box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2);
285
- }
286
- .bubble svg {
287
- width: 28px;
288
- height: 28px;
289
- }
290
- .bubble-text {
291
- font-family: var(--aikaara-font, system-ui, sans-serif);
292
- font-size: 12px;
293
- font-weight: 500;
294
- }
295
- </style>
296
- <button class="bubble" aria-label="Open chat">
297
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
298
- <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>
299
- </svg>
300
- </button>
301
- `;
302
- }
303
- setIcon(e) {
304
- const t = this.shadow.querySelector(".bubble");
305
- t && (t.innerHTML = e);
306
- }
307
- }
308
- class C extends HTMLElement {
309
- shadow;
310
- static get observedAttributes() {
311
- return ["title", "subtitle", "avatar-url", "status"];
312
- }
313
- constructor() {
314
- super(), this.shadow = this.attachShadow({ mode: "open" });
315
- }
316
- connectedCallback() {
317
- this.render(), this.bindClose();
318
- }
319
- attributeChangedCallback() {
320
- this.render(), this.bindClose();
321
- }
322
- bindClose() {
323
- this.shadow.querySelector(".close-btn")?.addEventListener("click", () => {
324
- this.dispatchEvent(new CustomEvent("header-close", { bubbles: !0, composed: !0 }));
325
- });
326
- }
327
- render() {
328
- const e = this.getAttribute("title") || "Chat", t = this.getAttribute("subtitle") || "", a = this.getAttribute("avatar-url"), s = this.getAttribute("status") || "connected", n = s === "connected" ? "#10b981" : s === "connecting" || s === "reconnecting" ? "#f59e0b" : "#ef4444";
329
- this.shadow.innerHTML = `
330
- <style>
331
- .header {
332
- display: flex;
333
- align-items: center;
334
- gap: 12px;
335
- padding: 14px 16px;
336
- background: var(--aikaara-primary, #6366f1);
337
- color: #ffffff;
338
- flex-shrink: 0;
339
- }
340
- .avatar {
341
- width: 36px;
342
- height: 36px;
343
- border-radius: 50%;
344
- background: rgba(255,255,255,0.2);
345
- display: flex;
346
- align-items: center;
347
- justify-content: center;
348
- flex-shrink: 0;
349
- overflow: hidden;
350
- }
351
- .avatar img {
352
- width: 100%;
353
- height: 100%;
354
- object-fit: cover;
355
- }
356
- .avatar svg {
357
- width: 20px;
358
- height: 20px;
359
- }
360
- .info {
361
- flex: 1;
362
- min-width: 0;
363
- }
364
- .title {
365
- font-size: 15px;
366
- font-weight: 600;
367
- line-height: 1.2;
368
- display: flex;
369
- align-items: center;
370
- gap: 6px;
371
- }
372
- .status-dot {
373
- width: 8px;
374
- height: 8px;
375
- border-radius: 50%;
376
- flex-shrink: 0;
377
- }
378
- .subtitle {
379
- font-size: 12px;
380
- opacity: 0.85;
381
- white-space: nowrap;
382
- overflow: hidden;
383
- text-overflow: ellipsis;
384
- }
385
- .close-btn {
386
- background: none;
387
- border: none;
388
- color: #ffffff;
389
- cursor: pointer;
390
- padding: 4px;
391
- border-radius: 4px;
392
- display: flex;
393
- align-items: center;
394
- justify-content: center;
395
- opacity: 0.8;
396
- transition: opacity 200ms;
397
- }
398
- .close-btn:hover {
399
- opacity: 1;
400
- }
401
- .close-btn svg {
402
- width: 20px;
403
- height: 20px;
404
- }
405
- </style>
406
- <div class="header">
407
- <div class="avatar">
408
- ${a ? `<img src="${a}" alt="Avatar" />` : '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>'}
409
- </div>
410
- <div class="info">
411
- <div class="title">
412
- ${e}
413
- <span class="status-dot" style="background:${n}"></span>
414
- </div>
415
- ${t ? `<div class="subtitle">${t}</div>` : ""}
416
- </div>
417
- <button class="close-btn" aria-label="Close chat">
418
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
419
- <line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/>
420
- </svg>
421
- </button>
422
- </div>
423
- `;
424
- }
425
- setStatus(e) {
426
- this.setAttribute("status", e);
427
- }
428
- }
429
- function o(i) {
430
- let e = L(i);
431
- return e = e.replace(/```(\w*)\n([\s\S]*?)```/g, (t, a, s) => `<pre><code>${s.trim()}</code></pre>`), e = e.replace(/`([^`]+)`/g, "<code>$1</code>"), e = e.replace(/\*\*(.+?)\*\*/g, "<strong>$1</strong>"), e = e.replace(/\*(.+?)\*/g, "<em>$1</em>"), e = e.replace(
432
- /\[([^\]]+)\]\((https?:\/\/[^\s)]+)\)/g,
433
- '<a href="$2" target="_blank" rel="noopener noreferrer">$1</a>'
434
- ), e = e.replace(/\n/g, "<br>"), e;
435
- }
436
- function L(i) {
437
- const e = {
438
- "&": "&amp;",
439
- "<": "&lt;",
440
- ">": "&gt;",
441
- '"': "&quot;",
442
- "'": "&#039;"
443
- };
444
- return i.replace(/[&<>"']/g, (t) => e[t]);
445
- }
446
- const A = /* @__PURE__ */ new Set([
447
- "p",
448
- "br",
449
- "strong",
450
- "em",
451
- "code",
452
- "pre",
453
- "a",
454
- "ul",
455
- "ol",
456
- "li",
457
- "blockquote",
458
- "h1",
459
- "h2",
460
- "h3",
461
- "h4",
462
- "h5",
463
- "h6",
464
- "span",
465
- "div"
466
- ]), E = {
467
- a: /* @__PURE__ */ new Set(["href", "target", "rel"]),
468
- code: /* @__PURE__ */ new Set(["class"]),
469
- pre: /* @__PURE__ */ new Set(["class"]),
470
- span: /* @__PURE__ */ new Set(["class"]),
471
- div: /* @__PURE__ */ new Set(["class"])
472
- };
473
- function l(i) {
474
- const e = document.createElement("template");
475
- return e.innerHTML = i, h(e.content), e.innerHTML;
476
- }
477
- function h(i) {
478
- const e = Array.from(i.childNodes);
479
- for (const t of e)
480
- if (t.nodeType === Node.ELEMENT_NODE) {
481
- const a = t, s = a.tagName.toLowerCase();
482
- if (!A.has(s)) {
483
- const r = document.createTextNode(a.textContent || "");
484
- i.replaceChild(r, t);
485
- continue;
486
- }
487
- const n = E[s] || /* @__PURE__ */ new Set(), b = Array.from(a.attributes);
488
- for (const r of b)
489
- n.has(r.name) || a.removeAttribute(r.name);
490
- if (a.hasAttribute("href")) {
491
- const r = a.getAttribute("href") || "";
492
- !r.startsWith("http://") && !r.startsWith("https://") && !r.startsWith("/") && a.removeAttribute("href");
493
- }
494
- h(t);
495
- }
496
- }
497
- class S extends HTMLElement {
498
- shadow;
499
- container;
500
- welcomeMessage = "";
501
- showTimestamps = !0;
502
- constructor() {
503
- super(), this.shadow = this.attachShadow({ mode: "open" });
504
- }
505
- connectedCallback() {
506
- this.shadow.innerHTML = `
507
- <style>
508
- :host {
509
- display: flex;
510
- flex-direction: column;
511
- min-height: 0;
512
- }
513
- .message-list {
514
- flex: 1;
515
- overflow-y: auto;
516
- padding: 16px;
517
- display: flex;
518
- flex-direction: column;
519
- gap: 8px;
520
- scroll-behavior: smooth;
521
- }
522
- .message-list::-webkit-scrollbar { width: 6px; }
523
- .message-list::-webkit-scrollbar-track { background: transparent; }
524
- .message-list::-webkit-scrollbar-thumb { background: var(--aikaara-border, #e5e7eb); border-radius: 3px; }
525
- .message-wrap { display: flex; flex-direction: column; }
526
- .message-wrap.user { align-items: flex-end; }
527
- .message-wrap.assistant { align-items: flex-start; }
528
- .bubble {
529
- max-width: 85%;
530
- padding: 10px 14px;
531
- border-radius: var(--aikaara-radius, 12px);
532
- font-size: 14px;
533
- line-height: 1.5;
534
- word-wrap: break-word;
535
- overflow-wrap: break-word;
536
- }
537
- .bubble.user {
538
- background: var(--aikaara-primary, #6366f1);
539
- color: #ffffff;
540
- border-bottom-right-radius: 4px;
541
- }
542
- .bubble.assistant {
543
- background: var(--aikaara-bg-secondary, #f9fafb);
544
- color: var(--aikaara-text, #1f2937);
545
- border-bottom-left-radius: 4px;
546
- }
547
- .bubble pre {
548
- background: rgba(0,0,0,0.06);
549
- padding: 8px 12px;
550
- border-radius: 6px;
551
- overflow-x: auto;
552
- font-size: 13px;
553
- margin: 8px 0;
554
- }
555
- .bubble code {
556
- font-family: 'SF Mono', 'Fira Code', monospace;
557
- font-size: 13px;
558
- }
559
- .bubble.assistant code:not(pre code) {
560
- background: rgba(0,0,0,0.06);
561
- padding: 2px 4px;
562
- border-radius: 3px;
563
- }
564
- .bubble a { color: inherit; text-decoration: underline; }
565
- .timestamp {
566
- font-size: 11px;
567
- color: var(--aikaara-text-secondary, #6b7280);
568
- margin-top: 2px;
569
- padding: 0 4px;
570
- }
571
- .welcome {
572
- text-align: center;
573
- color: var(--aikaara-text-secondary, #6b7280);
574
- font-size: 14px;
575
- padding: 24px 16px;
576
- }
577
- .streaming-cursor::after {
578
- content: '\\25CF';
579
- animation: blink 1s infinite;
580
- margin-left: 2px;
581
- font-size: 10px;
582
- vertical-align: middle;
583
- }
584
- @keyframes blink {
585
- 0%, 100% { opacity: 1; }
586
- 50% { opacity: 0; }
587
- }
588
- .typing-indicator {
589
- display: flex;
590
- align-items: center;
591
- gap: 4px;
592
- padding: 10px 14px;
593
- align-self: flex-start;
594
- background: var(--aikaara-bg-secondary, #f9fafb);
595
- border-radius: var(--aikaara-radius, 12px);
596
- border-bottom-left-radius: 4px;
597
- }
598
- .typing-indicator .dot {
599
- width: 6px;
600
- height: 6px;
601
- border-radius: 50%;
602
- background: var(--aikaara-text-secondary, #6b7280);
603
- animation: typing-bounce 1.4s infinite ease-in-out;
604
- }
605
- .typing-indicator .dot:nth-child(1) { animation-delay: 0ms; }
606
- .typing-indicator .dot:nth-child(2) { animation-delay: 200ms; }
607
- .typing-indicator .dot:nth-child(3) { animation-delay: 400ms; }
608
- @keyframes typing-bounce {
609
- 0%, 60%, 100% { transform: translateY(0); opacity: 0.4; }
610
- 30% { transform: translateY(-4px); opacity: 1; }
611
- }
612
- </style>
613
- <div class="message-list"></div>
614
- `, this.container = this.shadow.querySelector(".message-list"), this.welcomeMessage && this.renderMessages([]);
615
- }
616
- setWelcomeMessage(e) {
617
- this.welcomeMessage = e;
618
- }
619
- setShowTimestamps(e) {
620
- this.showTimestamps = e;
621
- }
622
- renderMessages(e) {
623
- if (this.container) {
624
- if (this.container.innerHTML = "", e.length === 0 && this.welcomeMessage) {
625
- this.container.innerHTML = `<div class="welcome">${l(o(this.welcomeMessage))}</div>`;
626
- return;
627
- }
628
- for (const t of e)
629
- this.appendMessageElement(t);
630
- this.scrollToBottom();
631
- }
632
- }
633
- addMessage(e) {
634
- const t = this.container.querySelector(".welcome");
635
- t && t.remove(), this.appendMessageElement(e), this.scrollToBottom();
636
- }
637
- updateStreamingContent(e) {
638
- const t = this.container.querySelector('[data-streaming="true"] .bubble');
639
- t && (t.innerHTML = l(o(e)), t.classList.add("streaming-cursor"), this.scrollToBottom());
640
- }
641
- finalizeStreaming() {
642
- const e = this.container.querySelector('[data-streaming="true"]');
643
- e && (e.removeAttribute("data-streaming"), e.querySelector(".bubble")?.classList.remove("streaming-cursor"));
644
- }
645
- showTypingIndicator() {
646
- this.removeTypingIndicator();
647
- const e = document.createElement("div");
648
- e.classList.add("typing-indicator"), e.setAttribute("data-typing", "true"), e.innerHTML = '<span class="dot"></span><span class="dot"></span><span class="dot"></span>', this.container.appendChild(e), this.scrollToBottom();
649
- }
650
- removeTypingIndicator() {
651
- this.container.querySelector('[data-typing="true"]')?.remove();
652
- }
653
- appendMessageElement(e) {
654
- const t = document.createElement("div");
655
- t.classList.add("message-wrap", e.role), e.status === "streaming" && t.setAttribute("data-streaming", "true");
656
- const a = document.createElement("div");
657
- if (a.classList.add("bubble", e.role), e.role === "user" ? a.textContent = e.content : (a.innerHTML = l(o(e.content || "")), e.status === "streaming" && a.classList.add("streaming-cursor")), t.appendChild(a), this.showTimestamps && e.createdAt) {
658
- const s = document.createElement("div");
659
- s.classList.add("timestamp"), s.textContent = this.formatTime(e.createdAt), t.appendChild(s);
660
- }
661
- this.container.appendChild(t);
662
- }
663
- scrollToBottom() {
664
- requestAnimationFrame(() => {
665
- this.container.scrollTop = this.container.scrollHeight;
666
- });
667
- }
668
- formatTime(e) {
669
- try {
670
- return new Date(e).toLocaleTimeString(void 0, { hour: "2-digit", minute: "2-digit" });
671
- } catch {
672
- return "";
673
- }
674
- }
675
- }
676
- class M extends HTMLElement {
677
- shadow;
678
- static get observedAttributes() {
679
- return ["role", "content", "timestamp"];
680
- }
681
- constructor() {
682
- super(), this.shadow = this.attachShadow({ mode: "open" });
683
- }
684
- connectedCallback() {
685
- this.render();
686
- }
687
- attributeChangedCallback() {
688
- this.render();
689
- }
690
- render() {
691
- const e = this.getAttribute("role") || "user", t = this.getAttribute("content") || "", a = this.getAttribute("timestamp") || "", s = e === "user" ? document.createTextNode(t).textContent || "" : l(o(t));
692
- this.shadow.innerHTML = `
693
- <style>
694
- :host { display: flex; flex-direction: column; }
695
- :host([role="user"]) { align-items: flex-end; }
696
- :host([role="assistant"]) { align-items: flex-start; }
697
- .bubble {
698
- max-width: 85%;
699
- padding: 10px 14px;
700
- border-radius: var(--aikaara-radius, 12px);
701
- font-size: 14px;
702
- line-height: 1.5;
703
- word-wrap: break-word;
704
- }
705
- .bubble.user {
706
- background: var(--aikaara-primary, #6366f1);
707
- color: #fff;
708
- border-bottom-right-radius: 4px;
709
- }
710
- .bubble.assistant {
711
- background: var(--aikaara-bg-secondary, #f9fafb);
712
- color: var(--aikaara-text, #1f2937);
713
- border-bottom-left-radius: 4px;
714
- }
715
- .timestamp {
716
- font-size: 11px;
717
- color: var(--aikaara-text-secondary, #6b7280);
718
- margin-top: 2px;
719
- padding: 0 4px;
720
- }
721
- </style>
722
- <div class="bubble ${e}">${s}</div>
723
- ${a ? `<div class="timestamp">${a}</div>` : ""}
724
- `;
725
- }
726
- }
727
- class _ extends HTMLElement {
728
- shadow;
729
- textarea;
730
- sendBtn;
731
- _disabled = !1;
732
- constructor() {
733
- super(), this.shadow = this.attachShadow({ mode: "open" });
734
- }
735
- connectedCallback() {
736
- const e = this.getAttribute("placeholder") || "Type a message...";
737
- this.shadow.innerHTML = `
738
- <style>
739
- .input-container {
740
- display: flex;
741
- align-items: flex-end;
742
- gap: 8px;
743
- padding: 12px 16px;
744
- border-top: 1px solid var(--aikaara-border, #e5e7eb);
745
- background: var(--aikaara-bg, #ffffff);
746
- }
747
- textarea {
748
- flex: 1;
749
- resize: none;
750
- border: 1px solid var(--aikaara-border, #e5e7eb);
751
- border-radius: 8px;
752
- padding: 10px 12px;
753
- font-family: var(--aikaara-font, system-ui, sans-serif);
754
- font-size: 14px;
755
- color: var(--aikaara-text, #1f2937);
756
- background: var(--aikaara-bg, #ffffff);
757
- outline: none;
758
- min-height: 40px;
759
- max-height: 120px;
760
- line-height: 1.4;
761
- transition: border-color 200ms ease;
762
- }
763
- textarea:focus {
764
- border-color: var(--aikaara-primary, #6366f1);
765
- }
766
- textarea::placeholder {
767
- color: var(--aikaara-text-secondary, #6b7280);
768
- }
769
- .send-btn {
770
- width: 40px;
771
- height: 40px;
772
- border: none;
773
- border-radius: 50%;
774
- background: var(--aikaara-primary, #6366f1);
775
- color: #ffffff;
776
- cursor: pointer;
777
- display: flex;
778
- align-items: center;
779
- justify-content: center;
780
- flex-shrink: 0;
781
- transition: background 200ms, opacity 200ms;
782
- }
783
- .send-btn:hover { background: var(--aikaara-primary-hover, #4f46e5); }
784
- .send-btn:disabled { opacity: 0.5; cursor: not-allowed; }
785
- .send-btn svg { width: 18px; height: 18px; }
786
- </style>
787
- <div class="input-container">
788
- <textarea rows="1" placeholder="${e}"></textarea>
789
- <button class="send-btn" aria-label="Send message" disabled>
790
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
791
- <line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/>
792
- </svg>
793
- </button>
794
- </div>
795
- `, this.textarea = this.shadow.querySelector("textarea"), this.sendBtn = this.shadow.querySelector(".send-btn"), this.textarea.addEventListener("input", () => {
796
- this.autoGrow(), this.sendBtn.disabled = this._disabled || !this.textarea.value.trim();
797
- }), this.textarea.addEventListener("keydown", (t) => {
798
- t.key === "Enter" && !t.shiftKey && (t.preventDefault(), this.handleSend());
799
- }), this.sendBtn.addEventListener("click", () => this.handleSend());
800
- }
801
- set disabled(e) {
802
- this._disabled = e, this.textarea && (this.textarea.disabled = e), this.sendBtn && (this.sendBtn.disabled = e || !this.textarea?.value.trim());
803
- }
804
- get disabled() {
805
- return this._disabled;
806
- }
807
- focus() {
808
- this.textarea?.focus();
809
- }
810
- clear() {
811
- this.textarea && (this.textarea.value = "", this.textarea.style.height = "auto", this.sendBtn.disabled = !0);
812
- }
813
- handleSend() {
814
- const e = this.textarea.value.trim();
815
- !e || this._disabled || (this.dispatchEvent(new CustomEvent("send", {
816
- detail: { content: e },
817
- bubbles: !0,
818
- composed: !0
819
- })), this.clear(), this.textarea.focus());
820
- }
821
- autoGrow() {
822
- this.textarea.style.height = "auto", this.textarea.style.height = Math.min(this.textarea.scrollHeight, 120) + "px";
823
- }
824
- }
825
- class H extends HTMLElement {
826
- shadow;
827
- constructor() {
828
- super(), this.shadow = this.attachShadow({ mode: "open" });
829
- }
830
- connectedCallback() {
831
- this.shadow.innerHTML = `
832
- <style>
833
- :host { display: none; }
834
- :host([visible]) { display: block; }
835
- .typing {
836
- display: flex;
837
- align-items: center;
838
- gap: 4px;
839
- padding: 10px 14px;
840
- background: var(--aikaara-bg-secondary, #f9fafb);
841
- border-radius: var(--aikaara-radius, 12px);
842
- border-bottom-left-radius: 4px;
843
- width: fit-content;
844
- }
845
- .dot {
846
- width: 6px;
847
- height: 6px;
848
- border-radius: 50%;
849
- background: var(--aikaara-text-secondary, #6b7280);
850
- animation: bounce 1.4s infinite ease-in-out;
851
- }
852
- .dot:nth-child(1) { animation-delay: 0ms; }
853
- .dot:nth-child(2) { animation-delay: 200ms; }
854
- .dot:nth-child(3) { animation-delay: 400ms; }
855
- @keyframes bounce {
856
- 0%, 60%, 100% { transform: translateY(0); opacity: 0.4; }
857
- 30% { transform: translateY(-4px); opacity: 1; }
858
- }
859
- </style>
860
- <div class="typing">
861
- <span class="dot"></span>
862
- <span class="dot"></span>
863
- <span class="dot"></span>
864
- </div>
865
- `;
866
- }
867
- show() {
868
- this.setAttribute("visible", "");
869
- }
870
- hide() {
871
- this.removeAttribute("visible");
872
- }
873
- }
874
- class $ extends HTMLElement {
875
- shadow;
876
- bubble;
877
- constructor() {
878
- super(), this.shadow = this.attachShadow({ mode: "open" });
879
- }
880
- connectedCallback() {
881
- this.shadow.innerHTML = `
882
- <style>
883
- :host {
884
- display: flex;
885
- flex-direction: column;
886
- align-items: flex-start;
887
- }
888
- .bubble {
889
- max-width: 85%;
890
- padding: 10px 14px;
891
- border-radius: var(--aikaara-radius, 12px);
892
- border-bottom-left-radius: 4px;
893
- background: var(--aikaara-bg-secondary, #f9fafb);
894
- color: var(--aikaara-text, #1f2937);
895
- font-size: 14px;
896
- line-height: 1.5;
897
- word-wrap: break-word;
898
- min-height: 20px;
899
- }
900
- .bubble pre {
901
- background: rgba(0,0,0,0.06);
902
- padding: 8px 12px;
903
- border-radius: 6px;
904
- overflow-x: auto;
905
- font-size: 13px;
906
- margin: 8px 0;
907
- }
908
- .bubble code {
909
- font-family: 'SF Mono', 'Fira Code', monospace;
910
- font-size: 13px;
911
- }
912
- .bubble code:not(pre code) {
913
- background: rgba(0,0,0,0.06);
914
- padding: 2px 4px;
915
- border-radius: 3px;
916
- }
917
- .cursor::after {
918
- content: '\\25CF';
919
- animation: blink 1s infinite;
920
- margin-left: 2px;
921
- font-size: 10px;
922
- vertical-align: middle;
923
- }
924
- @keyframes blink {
925
- 0%, 100% { opacity: 1; }
926
- 50% { opacity: 0; }
927
- }
928
- </style>
929
- <div class="bubble cursor"></div>
930
- `, this.bubble = this.shadow.querySelector(".bubble");
931
- }
932
- updateContent(e) {
933
- this.bubble && (this.bubble.innerHTML = l(o(e)), this.bubble.classList.add("cursor"));
934
- }
935
- finalize() {
936
- this.bubble?.classList.remove("cursor");
937
- }
938
- }
939
- class z extends HTMLElement {
940
- shadow;
941
- container;
942
- dismissTimer = null;
943
- constructor() {
944
- super(), this.shadow = this.attachShadow({ mode: "open" });
945
- }
946
- connectedCallback() {
947
- this.shadow.innerHTML = `
948
- <style>
949
- .banner {
950
- display: none;
951
- padding: 8px 16px;
952
- background: #fef2f2;
953
- color: #dc2626;
954
- font-size: 13px;
955
- text-align: center;
956
- border-top: 1px solid #fecaca;
957
- }
958
- .banner.visible {
959
- display: block;
960
- }
961
- .dismiss {
962
- background: none;
963
- border: none;
964
- color: #dc2626;
965
- cursor: pointer;
966
- font-size: 12px;
967
- text-decoration: underline;
968
- margin-left: 8px;
969
- }
970
- </style>
971
- <div class="banner">
972
- <span class="message"></span>
973
- <button class="dismiss">Dismiss</button>
974
- </div>
975
- `, this.container = this.shadow.querySelector(".banner"), this.shadow.querySelector(".dismiss")?.addEventListener("click", () => this.hide());
976
- }
977
- show(e, t) {
978
- const a = this.container.querySelector(".message");
979
- a && (a.textContent = e), this.container.classList.add("visible"), this.dismissTimer && clearTimeout(this.dismissTimer), t && (this.dismissTimer = setTimeout(() => this.hide(), t));
980
- }
981
- hide() {
982
- this.container.classList.remove("visible"), this.dismissTimer && (clearTimeout(this.dismissTimer), this.dismissTimer = null);
983
- }
984
- }
985
- function B() {
986
- const i = [
987
- ["aikaara-chat-widget", w],
988
- ["aikaara-chat-bubble", T],
989
- ["aikaara-chat-header", C],
990
- ["aikaara-message-list", S],
991
- ["aikaara-message-bubble", M],
992
- ["aikaara-chat-input", _],
993
- ["aikaara-typing-indicator", H],
994
- ["aikaara-streaming-message", $],
995
- ["aikaara-error-banner", z]
996
- ];
997
- for (const [e, t] of i)
998
- customElements.get(e) || customElements.define(e, t);
999
- }
1000
- B();
1
+ import { a as i, c as s, d as e, e as t, f as A, g as k, h as n, s as o, t as g, i as d, u as l, v as m, w as p, j as b, r as h } from "./ui-BMGa0gZH.mjs";
1001
2
  export {
1002
- T as AikaaraChatBubble,
1003
- C as AikaaraChatHeader,
1004
- _ as AikaaraChatInput,
1005
- w as AikaaraChatWidget,
1006
- z as AikaaraErrorBanner,
1007
- M as AikaaraMessageBubble,
1008
- S as AikaaraMessageList,
1009
- $ as AikaaraStreamingMessage,
1010
- H as AikaaraTypingIndicator,
1011
- B as registerComponents
3
+ i as AikaaraChatBubble,
4
+ s as AikaaraChatHeader,
5
+ e as AikaaraChatInput,
6
+ t as AikaaraChatWidget,
7
+ A as AikaaraErrorBanner,
8
+ k as AikaaraMessageBubble,
9
+ n as AikaaraMessageList,
10
+ o as AikaaraModalAction,
11
+ g as AikaaraOptionList,
12
+ d as AikaaraStreamingMessage,
13
+ l as AikaaraSubmitAction,
14
+ m as AikaaraSystemPill,
15
+ p as AikaaraTemplateRenderer,
16
+ b as AikaaraTypingIndicator,
17
+ h as registerComponents
1012
18
  };