@a.izzuddin/ai-chat 0.1.2 → 0.2.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/custom-elements.json +66 -28
- package/dist/index.d.mts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +123 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +123 -4
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/custom-elements.json
CHANGED
|
@@ -72,34 +72,6 @@
|
|
|
72
72
|
"declarations": [],
|
|
73
73
|
"exports": []
|
|
74
74
|
},
|
|
75
|
-
{
|
|
76
|
-
"kind": "javascript-module",
|
|
77
|
-
"path": "lib/utils.ts",
|
|
78
|
-
"declarations": [
|
|
79
|
-
{
|
|
80
|
-
"kind": "function",
|
|
81
|
-
"name": "cn",
|
|
82
|
-
"parameters": [
|
|
83
|
-
{
|
|
84
|
-
"name": "inputs",
|
|
85
|
-
"type": {
|
|
86
|
-
"text": "ClassValue[]"
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
]
|
|
90
|
-
}
|
|
91
|
-
],
|
|
92
|
-
"exports": [
|
|
93
|
-
{
|
|
94
|
-
"kind": "js",
|
|
95
|
-
"name": "cn",
|
|
96
|
-
"declaration": {
|
|
97
|
-
"name": "cn",
|
|
98
|
-
"module": "lib/utils.ts"
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
]
|
|
102
|
-
},
|
|
103
75
|
{
|
|
104
76
|
"kind": "javascript-module",
|
|
105
77
|
"path": "examples/angular.component.ts",
|
|
@@ -190,6 +162,34 @@
|
|
|
190
162
|
}
|
|
191
163
|
]
|
|
192
164
|
},
|
|
165
|
+
{
|
|
166
|
+
"kind": "javascript-module",
|
|
167
|
+
"path": "lib/utils.ts",
|
|
168
|
+
"declarations": [
|
|
169
|
+
{
|
|
170
|
+
"kind": "function",
|
|
171
|
+
"name": "cn",
|
|
172
|
+
"parameters": [
|
|
173
|
+
{
|
|
174
|
+
"name": "inputs",
|
|
175
|
+
"type": {
|
|
176
|
+
"text": "ClassValue[]"
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
]
|
|
180
|
+
}
|
|
181
|
+
],
|
|
182
|
+
"exports": [
|
|
183
|
+
{
|
|
184
|
+
"kind": "js",
|
|
185
|
+
"name": "cn",
|
|
186
|
+
"declaration": {
|
|
187
|
+
"name": "cn",
|
|
188
|
+
"module": "lib/utils.ts"
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
]
|
|
192
|
+
},
|
|
193
193
|
{
|
|
194
194
|
"kind": "javascript-module",
|
|
195
195
|
"path": "src/index.ts",
|
|
@@ -528,6 +528,17 @@
|
|
|
528
528
|
"default": "'light'",
|
|
529
529
|
"attribute": "theme"
|
|
530
530
|
},
|
|
531
|
+
{
|
|
532
|
+
"kind": "field",
|
|
533
|
+
"name": "mode",
|
|
534
|
+
"privacy": "public",
|
|
535
|
+
"type": {
|
|
536
|
+
"text": "'fullscreen' | 'widget'"
|
|
537
|
+
},
|
|
538
|
+
"default": "'fullscreen'",
|
|
539
|
+
"attribute": "mode",
|
|
540
|
+
"reflects": true
|
|
541
|
+
},
|
|
531
542
|
{
|
|
532
543
|
"kind": "field",
|
|
533
544
|
"name": "initialMessages",
|
|
@@ -565,6 +576,15 @@
|
|
|
565
576
|
"privacy": "private",
|
|
566
577
|
"default": "false"
|
|
567
578
|
},
|
|
579
|
+
{
|
|
580
|
+
"kind": "field",
|
|
581
|
+
"name": "isOpen",
|
|
582
|
+
"type": {
|
|
583
|
+
"text": "boolean"
|
|
584
|
+
},
|
|
585
|
+
"privacy": "private",
|
|
586
|
+
"default": "false"
|
|
587
|
+
},
|
|
568
588
|
{
|
|
569
589
|
"kind": "field",
|
|
570
590
|
"name": "messagesEndRef",
|
|
@@ -573,6 +593,11 @@
|
|
|
573
593
|
},
|
|
574
594
|
"privacy": "private"
|
|
575
595
|
},
|
|
596
|
+
{
|
|
597
|
+
"kind": "method",
|
|
598
|
+
"name": "toggleWidget",
|
|
599
|
+
"privacy": "private"
|
|
600
|
+
},
|
|
576
601
|
{
|
|
577
602
|
"kind": "method",
|
|
578
603
|
"name": "scrollToBottom",
|
|
@@ -603,6 +628,11 @@
|
|
|
603
628
|
}
|
|
604
629
|
}
|
|
605
630
|
]
|
|
631
|
+
},
|
|
632
|
+
{
|
|
633
|
+
"kind": "method",
|
|
634
|
+
"name": "renderChatUI",
|
|
635
|
+
"privacy": "private"
|
|
606
636
|
}
|
|
607
637
|
],
|
|
608
638
|
"events": [
|
|
@@ -661,6 +691,14 @@
|
|
|
661
691
|
"default": "'light'",
|
|
662
692
|
"fieldName": "theme"
|
|
663
693
|
},
|
|
694
|
+
{
|
|
695
|
+
"name": "mode",
|
|
696
|
+
"type": {
|
|
697
|
+
"text": "'fullscreen' | 'widget'"
|
|
698
|
+
},
|
|
699
|
+
"default": "'fullscreen'",
|
|
700
|
+
"fieldName": "mode"
|
|
701
|
+
},
|
|
664
702
|
{
|
|
665
703
|
"name": "initialMessages",
|
|
666
704
|
"type": {
|
package/dist/index.d.mts
CHANGED
|
@@ -29,10 +29,12 @@ declare class AIChat extends LitElement {
|
|
|
29
29
|
sessionId: string;
|
|
30
30
|
chatTitle: string;
|
|
31
31
|
theme: 'light' | 'dark';
|
|
32
|
+
mode: 'fullscreen' | 'widget';
|
|
32
33
|
initialMessages: Message[];
|
|
33
34
|
private messages;
|
|
34
35
|
private input;
|
|
35
36
|
private isLoading;
|
|
37
|
+
private isOpen;
|
|
36
38
|
private messagesEndRef?;
|
|
37
39
|
static properties: {
|
|
38
40
|
apiUrl: {
|
|
@@ -50,16 +52,22 @@ declare class AIChat extends LitElement {
|
|
|
50
52
|
theme: {
|
|
51
53
|
type: StringConstructor;
|
|
52
54
|
};
|
|
55
|
+
mode: {
|
|
56
|
+
type: StringConstructor;
|
|
57
|
+
reflect: boolean;
|
|
58
|
+
};
|
|
53
59
|
initialMessages: {
|
|
54
60
|
type: ArrayConstructor;
|
|
55
61
|
};
|
|
56
62
|
};
|
|
57
63
|
constructor();
|
|
64
|
+
private toggleWidget;
|
|
58
65
|
connectedCallback(): void;
|
|
59
66
|
updated(changedProperties: PropertyValues): void;
|
|
60
67
|
private scrollToBottom;
|
|
61
68
|
private handleInput;
|
|
62
69
|
private handleSubmit;
|
|
70
|
+
private renderChatUI;
|
|
63
71
|
render(): lit_html.TemplateResult<1>;
|
|
64
72
|
}
|
|
65
73
|
declare global {
|
package/dist/index.d.ts
CHANGED
|
@@ -29,10 +29,12 @@ declare class AIChat extends LitElement {
|
|
|
29
29
|
sessionId: string;
|
|
30
30
|
chatTitle: string;
|
|
31
31
|
theme: 'light' | 'dark';
|
|
32
|
+
mode: 'fullscreen' | 'widget';
|
|
32
33
|
initialMessages: Message[];
|
|
33
34
|
private messages;
|
|
34
35
|
private input;
|
|
35
36
|
private isLoading;
|
|
37
|
+
private isOpen;
|
|
36
38
|
private messagesEndRef?;
|
|
37
39
|
static properties: {
|
|
38
40
|
apiUrl: {
|
|
@@ -50,16 +52,22 @@ declare class AIChat extends LitElement {
|
|
|
50
52
|
theme: {
|
|
51
53
|
type: StringConstructor;
|
|
52
54
|
};
|
|
55
|
+
mode: {
|
|
56
|
+
type: StringConstructor;
|
|
57
|
+
reflect: boolean;
|
|
58
|
+
};
|
|
53
59
|
initialMessages: {
|
|
54
60
|
type: ArrayConstructor;
|
|
55
61
|
};
|
|
56
62
|
};
|
|
57
63
|
constructor();
|
|
64
|
+
private toggleWidget;
|
|
58
65
|
connectedCallback(): void;
|
|
59
66
|
updated(changedProperties: PropertyValues): void;
|
|
60
67
|
private scrollToBottom;
|
|
61
68
|
private handleInput;
|
|
62
69
|
private handleSubmit;
|
|
70
|
+
private renderChatUI;
|
|
63
71
|
render(): lit_html.TemplateResult<1>;
|
|
64
72
|
}
|
|
65
73
|
declare global {
|
package/dist/index.js
CHANGED
|
@@ -22,10 +22,15 @@ exports.AIChat = class AIChat extends lit.LitElement {
|
|
|
22
22
|
this.sessionId = "default-session";
|
|
23
23
|
this.chatTitle = "My AI Agent";
|
|
24
24
|
this.theme = "light";
|
|
25
|
+
this.mode = "fullscreen";
|
|
25
26
|
this.initialMessages = [];
|
|
26
27
|
this.messages = [];
|
|
27
28
|
this.input = "";
|
|
28
29
|
this.isLoading = false;
|
|
30
|
+
this.isOpen = false;
|
|
31
|
+
}
|
|
32
|
+
toggleWidget() {
|
|
33
|
+
this.isOpen = !this.isOpen;
|
|
29
34
|
}
|
|
30
35
|
connectedCallback() {
|
|
31
36
|
super.connectedCallback();
|
|
@@ -108,7 +113,7 @@ Please check your API endpoint configuration.`
|
|
|
108
113
|
this.isLoading = false;
|
|
109
114
|
}
|
|
110
115
|
}
|
|
111
|
-
|
|
116
|
+
renderChatUI() {
|
|
112
117
|
return lit.html`
|
|
113
118
|
<!-- Header -->
|
|
114
119
|
<div class="header">
|
|
@@ -184,22 +189,132 @@ Please check your API endpoint configuration.`
|
|
|
184
189
|
</div>
|
|
185
190
|
`;
|
|
186
191
|
}
|
|
192
|
+
render() {
|
|
193
|
+
if (this.mode === "widget") {
|
|
194
|
+
return lit.html`
|
|
195
|
+
<div class="widget-container">
|
|
196
|
+
<!-- Chat Window -->
|
|
197
|
+
<div class=${classMap_js.classMap({ "widget-window": true, "open": this.isOpen })}>
|
|
198
|
+
${this.renderChatUI()}
|
|
199
|
+
</div>
|
|
200
|
+
|
|
201
|
+
<!-- Toggle Button -->
|
|
202
|
+
<button
|
|
203
|
+
class="widget-button"
|
|
204
|
+
@click=${this.toggleWidget}
|
|
205
|
+
aria-label=${this.isOpen ? "Close chat" : "Open chat"}
|
|
206
|
+
>
|
|
207
|
+
${this.isOpen ? lit.html`
|
|
208
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
209
|
+
<line x1="18" y1="6" x2="6" y2="18"></line>
|
|
210
|
+
<line x1="6" y1="6" x2="18" y2="18"></line>
|
|
211
|
+
</svg>
|
|
212
|
+
` : lit.html`
|
|
213
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
214
|
+
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path>
|
|
215
|
+
</svg>
|
|
216
|
+
`}
|
|
217
|
+
</button>
|
|
218
|
+
</div>
|
|
219
|
+
`;
|
|
220
|
+
}
|
|
221
|
+
return this.renderChatUI();
|
|
222
|
+
}
|
|
187
223
|
};
|
|
188
224
|
exports.AIChat.styles = lit.css`
|
|
189
225
|
:host {
|
|
226
|
+
font-family: system-ui, -apple-system, sans-serif;
|
|
227
|
+
color: #09090b;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/* Fullscreen mode (default) */
|
|
231
|
+
:host([mode="fullscreen"]) {
|
|
190
232
|
display: flex;
|
|
191
233
|
flex-direction: column;
|
|
192
234
|
height: 100vh;
|
|
193
|
-
font-family: system-ui, -apple-system, sans-serif;
|
|
194
235
|
background: #fafafa;
|
|
195
|
-
color: #09090b;
|
|
196
236
|
}
|
|
197
237
|
|
|
198
|
-
:host([theme="dark"]) {
|
|
238
|
+
:host([mode="fullscreen"][theme="dark"]) {
|
|
199
239
|
background: #000;
|
|
200
240
|
color: #fafafa;
|
|
201
241
|
}
|
|
202
242
|
|
|
243
|
+
/* Widget mode */
|
|
244
|
+
:host([mode="widget"]) {
|
|
245
|
+
position: fixed;
|
|
246
|
+
bottom: 20px;
|
|
247
|
+
right: 20px;
|
|
248
|
+
z-index: 9999;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.widget-container {
|
|
252
|
+
position: relative;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
.widget-button {
|
|
256
|
+
width: 60px;
|
|
257
|
+
height: 60px;
|
|
258
|
+
border-radius: 50%;
|
|
259
|
+
background: #2563eb;
|
|
260
|
+
border: none;
|
|
261
|
+
cursor: pointer;
|
|
262
|
+
display: flex;
|
|
263
|
+
align-items: center;
|
|
264
|
+
justify-content: center;
|
|
265
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
266
|
+
transition: transform 0.2s, box-shadow 0.2s;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
.widget-button:hover {
|
|
270
|
+
transform: scale(1.05);
|
|
271
|
+
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.widget-button svg {
|
|
275
|
+
width: 28px;
|
|
276
|
+
height: 28px;
|
|
277
|
+
color: white;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
.widget-window {
|
|
281
|
+
position: absolute;
|
|
282
|
+
bottom: 80px;
|
|
283
|
+
right: 0;
|
|
284
|
+
width: 380px;
|
|
285
|
+
height: 600px;
|
|
286
|
+
background: #fff;
|
|
287
|
+
border-radius: 12px;
|
|
288
|
+
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12);
|
|
289
|
+
display: flex;
|
|
290
|
+
flex-direction: column;
|
|
291
|
+
overflow: hidden;
|
|
292
|
+
opacity: 0;
|
|
293
|
+
transform: scale(0.9) translateY(20px);
|
|
294
|
+
pointer-events: none;
|
|
295
|
+
transition: opacity 0.2s, transform 0.2s;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
.widget-window.open {
|
|
299
|
+
opacity: 1;
|
|
300
|
+
transform: scale(1) translateY(0);
|
|
301
|
+
pointer-events: all;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
:host([theme="dark"]) .widget-window {
|
|
305
|
+
background: #18181b;
|
|
306
|
+
color: #fafafa;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
@media (max-width: 480px) {
|
|
310
|
+
.widget-window {
|
|
311
|
+
width: calc(100vw - 40px);
|
|
312
|
+
height: calc(100vh - 100px);
|
|
313
|
+
bottom: 80px;
|
|
314
|
+
right: 0;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
203
318
|
.header {
|
|
204
319
|
border-bottom: 1px solid #e4e4e7;
|
|
205
320
|
background: #fff;
|
|
@@ -404,6 +519,7 @@ exports.AIChat.properties = {
|
|
|
404
519
|
sessionId: { type: String, attribute: "session-id" },
|
|
405
520
|
chatTitle: { type: String, attribute: "title" },
|
|
406
521
|
theme: { type: String },
|
|
522
|
+
mode: { type: String, reflect: true },
|
|
407
523
|
initialMessages: { type: Array }
|
|
408
524
|
};
|
|
409
525
|
__decorateClass([
|
|
@@ -415,6 +531,9 @@ __decorateClass([
|
|
|
415
531
|
__decorateClass([
|
|
416
532
|
decorators_js.state()
|
|
417
533
|
], exports.AIChat.prototype, "isLoading", 2);
|
|
534
|
+
__decorateClass([
|
|
535
|
+
decorators_js.state()
|
|
536
|
+
], exports.AIChat.prototype, "isOpen", 2);
|
|
418
537
|
exports.AIChat = __decorateClass([
|
|
419
538
|
decorators_js.customElement("ai-chat")
|
|
420
539
|
], exports.AIChat);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/ai-chat.ts"],"names":["AIChat","LitElement","html","repeat","classMap","css","state","customElement"],"mappings":"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","file":"index.js","sourcesContent":["import { LitElement, html, css, PropertyValues } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { repeat } from 'lit/directives/repeat.js';\nimport { classMap } from 'lit/directives/class-map.js';\n\nexport interface Message {\n id: string;\n role: 'user' | 'assistant';\n content: string;\n}\n\n/**\n * AI Chat Web Component\n *\n * @fires message-sent - Fired when user sends a message\n * @fires response-received - Fired when AI responds\n * @fires error - Fired when an error occurs\n *\n * @example\n * ```html\n * <ai-chat\n * api-url=\"https://api.example.com\"\n * session-id=\"user-123\"\n * title=\"My AI Assistant\">\n * </ai-chat>\n * ```\n */\n@customElement('ai-chat')\nexport class AIChat extends LitElement {\n static styles = css`\n :host {\n display: flex;\n flex-direction: column;\n height: 100vh;\n font-family: system-ui, -apple-system, sans-serif;\n background: #fafafa;\n color: #09090b;\n }\n\n :host([theme=\"dark\"]) {\n background: #000;\n color: #fafafa;\n }\n\n .header {\n border-bottom: 1px solid #e4e4e7;\n background: #fff;\n padding: 1rem;\n }\n\n :host([theme=\"dark\"]) .header {\n border-bottom-color: #27272a;\n background: #18181b;\n }\n\n .header-content {\n max-width: 56rem;\n margin: 0 auto;\n }\n\n .title {\n font-size: 1.25rem;\n font-weight: 600;\n margin: 0;\n }\n\n .messages-area {\n flex: 1;\n overflow-y: auto;\n padding: 1.5rem 1rem;\n }\n\n .messages-container {\n max-width: 56rem;\n margin: 0 auto;\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n }\n\n .empty-state {\n text-align: center;\n color: #71717a;\n margin-top: 5rem;\n }\n\n :host([theme=\"dark\"]) .empty-state {\n color: #a1a1aa;\n }\n\n .empty-state p {\n font-size: 1.5rem;\n font-weight: 500;\n margin: 0;\n }\n\n .message {\n display: flex;\n gap: 1rem;\n }\n\n .message.user {\n flex-direction: row-reverse;\n }\n\n .avatar {\n width: 2.5rem;\n height: 2.5rem;\n border-radius: 9999px;\n background: #e4e4e7;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n font-weight: 500;\n font-size: 0.875rem;\n }\n\n :host([theme=\"dark\"]) .avatar {\n background: #3f3f46;\n }\n\n .message-content {\n max-width: 36rem;\n padding: 0.75rem 1rem;\n border-radius: 1rem;\n }\n\n .message.user .message-content {\n background: #2563eb;\n color: #fff;\n }\n\n .message.assistant .message-content {\n background: #fff;\n border: 1px solid #e4e4e7;\n color: #09090b;\n }\n\n :host([theme=\"dark\"]) .message.assistant .message-content {\n background: #27272a;\n border-color: #3f3f46;\n color: #fafafa;\n }\n\n .message-text {\n white-space: pre-wrap;\n margin: 0;\n }\n\n .loading {\n display: flex;\n gap: 1rem;\n }\n\n .spinner {\n display: inline-block;\n width: 1.25rem;\n height: 1.25rem;\n border: 2px solid #e4e4e7;\n border-top-color: #71717a;\n border-radius: 50%;\n animation: spin 1s linear infinite;\n }\n\n @keyframes spin {\n to { transform: rotate(360deg); }\n }\n\n .input-area {\n border-top: 1px solid #e4e4e7;\n background: #fff;\n padding: 1rem;\n }\n\n :host([theme=\"dark\"]) .input-area {\n border-top-color: #27272a;\n background: #000;\n }\n\n .input-form {\n max-width: 56rem;\n margin: 0 auto;\n display: flex;\n gap: 0.75rem;\n }\n\n .input-field {\n flex: 1;\n height: 3rem;\n padding: 0 1rem;\n border: 1px solid #e4e4e7;\n border-radius: 0.5rem;\n font-size: 1rem;\n font-family: inherit;\n background: #fff;\n color: #09090b;\n }\n\n :host([theme=\"dark\"]) .input-field {\n border-color: #3f3f46;\n background: #18181b;\n color: #fafafa;\n }\n\n .input-field:focus {\n outline: 2px solid #2563eb;\n outline-offset: 2px;\n }\n\n .input-field:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .send-button {\n width: 3rem;\n height: 3rem;\n border-radius: 9999px;\n border: none;\n background: #2563eb;\n color: #fff;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: background 0.2s;\n }\n\n .send-button:hover:not(:disabled) {\n background: #1d4ed8;\n }\n\n .send-button:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .send-icon {\n width: 1.25rem;\n height: 1.25rem;\n }\n `;\n\n declare apiUrl: string;\n declare sessionId: string;\n declare chatTitle: string;\n declare theme: 'light' | 'dark';\n declare initialMessages: Message[];\n\n @state()\n private declare messages: Message[];\n\n @state()\n private declare input: string;\n\n @state()\n private declare isLoading: boolean;\n\n private messagesEndRef?: HTMLDivElement;\n\n static override properties = {\n apiUrl: { type: String, attribute: 'api-url' },\n sessionId: { type: String, attribute: 'session-id' },\n chatTitle: { type: String, attribute: 'title' },\n theme: { type: String },\n initialMessages: { type: Array },\n };\n\n constructor() {\n super();\n this.apiUrl = '';\n this.sessionId = 'default-session';\n this.chatTitle = 'My AI Agent';\n this.theme = 'light';\n this.initialMessages = [];\n this.messages = [];\n this.input = '';\n this.isLoading = false;\n }\n\n connectedCallback() {\n super.connectedCallback();\n if (this.initialMessages && this.initialMessages.length > 0) {\n this.messages = [...this.initialMessages];\n }\n }\n\n updated(changedProperties: PropertyValues) {\n super.updated(changedProperties);\n if (changedProperties.has('messages')) {\n this.scrollToBottom();\n }\n }\n\n private scrollToBottom() {\n requestAnimationFrame(() => {\n this.messagesEndRef?.scrollIntoView({ behavior: 'smooth' });\n });\n }\n\n private handleInput(e: Event) {\n this.input = (e.target as HTMLInputElement).value;\n }\n\n private async handleSubmit(e: Event) {\n e.preventDefault();\n\n if (!this.input.trim() || this.isLoading || !this.apiUrl) return;\n\n const userMessage: Message = {\n id: Date.now().toString(),\n role: 'user',\n content: this.input.trim(),\n };\n\n this.messages = [...this.messages, userMessage];\n const questionText = this.input.trim();\n this.input = '';\n this.isLoading = true;\n\n // Dispatch message-sent event\n this.dispatchEvent(new CustomEvent('message-sent', {\n detail: userMessage,\n bubbles: true,\n composed: true,\n }));\n\n try {\n const response = await fetch(`${this.apiUrl}/ask`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n session_id: this.sessionId,\n question: questionText,\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Backend error: ${response.status} ${errorText}`);\n }\n\n const data = await response.json();\n\n const assistantMessage: Message = {\n id: (Date.now() + 1).toString(),\n role: 'assistant',\n content: data.response || 'No response from agent',\n };\n\n this.messages = [...this.messages, assistantMessage];\n\n // Dispatch response-received event\n this.dispatchEvent(new CustomEvent('response-received', {\n detail: assistantMessage,\n bubbles: true,\n composed: true,\n }));\n } catch (err: any) {\n console.error('Backend connection failed:', err);\n\n const errorMessage: Message = {\n id: (Date.now() + 1).toString(),\n role: 'assistant',\n content: `Error: ${err.message}\\n\\nPlease check your API endpoint configuration.`,\n };\n\n this.messages = [...this.messages, errorMessage];\n\n // Dispatch error event\n this.dispatchEvent(new CustomEvent('error', {\n detail: err,\n bubbles: true,\n composed: true,\n }));\n } finally {\n this.isLoading = false;\n }\n }\n\n render() {\n return html`\n <!-- Header -->\n <div class=\"header\">\n <div class=\"header-content\">\n <h1 class=\"title\">${this.chatTitle}</h1>\n </div>\n </div>\n\n <!-- Messages Area -->\n <div class=\"messages-area\">\n <div class=\"messages-container\">\n ${this.messages.length === 0 ? html`\n <div class=\"empty-state\">\n <p>How can I help you today?</p>\n </div>\n ` : ''}\n\n ${repeat(this.messages, (msg) => msg.id, (msg) => html`\n <div class=${classMap({\n message: true,\n user: msg.role === 'user',\n assistant: msg.role === 'assistant'\n })}>\n <div class=\"avatar\">\n ${msg.role === 'user' ? 'U' : 'AI'}\n </div>\n <div class=\"message-content\">\n <p class=\"message-text\">${msg.content}</p>\n </div>\n </div>\n `)}\n\n ${this.isLoading ? html`\n <div class=\"loading\">\n <div class=\"avatar\">AI</div>\n <div class=\"message-content\">\n <div class=\"spinner\"></div>\n </div>\n </div>\n ` : ''}\n\n <div ${(el: Element) => this.messagesEndRef = el as HTMLDivElement}></div>\n </div>\n </div>\n\n <!-- Input Area -->\n <div class=\"input-area\">\n <form class=\"input-form\" @submit=${this.handleSubmit}>\n <input\n type=\"text\"\n class=\"input-field\"\n placeholder=\"Type your message...\"\n .value=${this.input}\n @input=${this.handleInput}\n ?disabled=${this.isLoading}\n />\n <button\n type=\"submit\"\n class=\"send-button\"\n ?disabled=${this.isLoading || !this.input.trim()}\n aria-label=\"Send message\"\n >\n ${this.isLoading ? html`\n <div class=\"spinner\" style=\"border-color: #fff; border-top-color: transparent;\"></div>\n ` : html`\n <svg class=\"send-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\"></line>\n <polygon points=\"22 2 15 22 11 13 2 9 22 2\"></polygon>\n </svg>\n `}\n </button>\n </form>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'ai-chat': AIChat;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/components/ai-chat.ts"],"names":["AIChat","LitElement","html","repeat","classMap","css","state","customElement"],"mappings":"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","file":"index.js","sourcesContent":["import { LitElement, html, css, PropertyValues } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { repeat } from 'lit/directives/repeat.js';\nimport { classMap } from 'lit/directives/class-map.js';\n\nexport interface Message {\n id: string;\n role: 'user' | 'assistant';\n content: string;\n}\n\n/**\n * AI Chat Web Component\n *\n * @fires message-sent - Fired when user sends a message\n * @fires response-received - Fired when AI responds\n * @fires error - Fired when an error occurs\n *\n * @example\n * ```html\n * <ai-chat\n * api-url=\"https://api.example.com\"\n * session-id=\"user-123\"\n * title=\"My AI Assistant\">\n * </ai-chat>\n * ```\n */\n@customElement('ai-chat')\nexport class AIChat extends LitElement {\n static styles = css`\n :host {\n font-family: system-ui, -apple-system, sans-serif;\n color: #09090b;\n }\n\n /* Fullscreen mode (default) */\n :host([mode=\"fullscreen\"]) {\n display: flex;\n flex-direction: column;\n height: 100vh;\n background: #fafafa;\n }\n\n :host([mode=\"fullscreen\"][theme=\"dark\"]) {\n background: #000;\n color: #fafafa;\n }\n\n /* Widget mode */\n :host([mode=\"widget\"]) {\n position: fixed;\n bottom: 20px;\n right: 20px;\n z-index: 9999;\n }\n\n .widget-container {\n position: relative;\n }\n\n .widget-button {\n width: 60px;\n height: 60px;\n border-radius: 50%;\n background: #2563eb;\n border: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n transition: transform 0.2s, box-shadow 0.2s;\n }\n\n .widget-button:hover {\n transform: scale(1.05);\n box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2);\n }\n\n .widget-button svg {\n width: 28px;\n height: 28px;\n color: white;\n }\n\n .widget-window {\n position: absolute;\n bottom: 80px;\n right: 0;\n width: 380px;\n height: 600px;\n background: #fff;\n border-radius: 12px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n opacity: 0;\n transform: scale(0.9) translateY(20px);\n pointer-events: none;\n transition: opacity 0.2s, transform 0.2s;\n }\n\n .widget-window.open {\n opacity: 1;\n transform: scale(1) translateY(0);\n pointer-events: all;\n }\n\n :host([theme=\"dark\"]) .widget-window {\n background: #18181b;\n color: #fafafa;\n }\n\n @media (max-width: 480px) {\n .widget-window {\n width: calc(100vw - 40px);\n height: calc(100vh - 100px);\n bottom: 80px;\n right: 0;\n }\n }\n\n .header {\n border-bottom: 1px solid #e4e4e7;\n background: #fff;\n padding: 1rem;\n }\n\n :host([theme=\"dark\"]) .header {\n border-bottom-color: #27272a;\n background: #18181b;\n }\n\n .header-content {\n max-width: 56rem;\n margin: 0 auto;\n }\n\n .title {\n font-size: 1.25rem;\n font-weight: 600;\n margin: 0;\n }\n\n .messages-area {\n flex: 1;\n overflow-y: auto;\n padding: 1.5rem 1rem;\n }\n\n .messages-container {\n max-width: 56rem;\n margin: 0 auto;\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n }\n\n .empty-state {\n text-align: center;\n color: #71717a;\n margin-top: 5rem;\n }\n\n :host([theme=\"dark\"]) .empty-state {\n color: #a1a1aa;\n }\n\n .empty-state p {\n font-size: 1.5rem;\n font-weight: 500;\n margin: 0;\n }\n\n .message {\n display: flex;\n gap: 1rem;\n }\n\n .message.user {\n flex-direction: row-reverse;\n }\n\n .avatar {\n width: 2.5rem;\n height: 2.5rem;\n border-radius: 9999px;\n background: #e4e4e7;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n font-weight: 500;\n font-size: 0.875rem;\n }\n\n :host([theme=\"dark\"]) .avatar {\n background: #3f3f46;\n }\n\n .message-content {\n max-width: 36rem;\n padding: 0.75rem 1rem;\n border-radius: 1rem;\n }\n\n .message.user .message-content {\n background: #2563eb;\n color: #fff;\n }\n\n .message.assistant .message-content {\n background: #fff;\n border: 1px solid #e4e4e7;\n color: #09090b;\n }\n\n :host([theme=\"dark\"]) .message.assistant .message-content {\n background: #27272a;\n border-color: #3f3f46;\n color: #fafafa;\n }\n\n .message-text {\n white-space: pre-wrap;\n margin: 0;\n }\n\n .loading {\n display: flex;\n gap: 1rem;\n }\n\n .spinner {\n display: inline-block;\n width: 1.25rem;\n height: 1.25rem;\n border: 2px solid #e4e4e7;\n border-top-color: #71717a;\n border-radius: 50%;\n animation: spin 1s linear infinite;\n }\n\n @keyframes spin {\n to { transform: rotate(360deg); }\n }\n\n .input-area {\n border-top: 1px solid #e4e4e7;\n background: #fff;\n padding: 1rem;\n }\n\n :host([theme=\"dark\"]) .input-area {\n border-top-color: #27272a;\n background: #000;\n }\n\n .input-form {\n max-width: 56rem;\n margin: 0 auto;\n display: flex;\n gap: 0.75rem;\n }\n\n .input-field {\n flex: 1;\n height: 3rem;\n padding: 0 1rem;\n border: 1px solid #e4e4e7;\n border-radius: 0.5rem;\n font-size: 1rem;\n font-family: inherit;\n background: #fff;\n color: #09090b;\n }\n\n :host([theme=\"dark\"]) .input-field {\n border-color: #3f3f46;\n background: #18181b;\n color: #fafafa;\n }\n\n .input-field:focus {\n outline: 2px solid #2563eb;\n outline-offset: 2px;\n }\n\n .input-field:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .send-button {\n width: 3rem;\n height: 3rem;\n border-radius: 9999px;\n border: none;\n background: #2563eb;\n color: #fff;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: background 0.2s;\n }\n\n .send-button:hover:not(:disabled) {\n background: #1d4ed8;\n }\n\n .send-button:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .send-icon {\n width: 1.25rem;\n height: 1.25rem;\n }\n `;\n\n declare apiUrl: string;\n declare sessionId: string;\n declare chatTitle: string;\n declare theme: 'light' | 'dark';\n declare mode: 'fullscreen' | 'widget';\n declare initialMessages: Message[];\n\n @state()\n private declare messages: Message[];\n\n @state()\n private declare input: string;\n\n @state()\n private declare isLoading: boolean;\n\n @state()\n private declare isOpen: boolean;\n\n private messagesEndRef?: HTMLDivElement;\n\n static override properties = {\n apiUrl: { type: String, attribute: 'api-url' },\n sessionId: { type: String, attribute: 'session-id' },\n chatTitle: { type: String, attribute: 'title' },\n theme: { type: String },\n mode: { type: String, reflect: true },\n initialMessages: { type: Array },\n };\n\n constructor() {\n super();\n this.apiUrl = '';\n this.sessionId = 'default-session';\n this.chatTitle = 'My AI Agent';\n this.theme = 'light';\n this.mode = 'fullscreen';\n this.initialMessages = [];\n this.messages = [];\n this.input = '';\n this.isLoading = false;\n this.isOpen = false;\n }\n\n private toggleWidget() {\n this.isOpen = !this.isOpen;\n }\n\n connectedCallback() {\n super.connectedCallback();\n if (this.initialMessages && this.initialMessages.length > 0) {\n this.messages = [...this.initialMessages];\n }\n }\n\n updated(changedProperties: PropertyValues) {\n super.updated(changedProperties);\n if (changedProperties.has('messages')) {\n this.scrollToBottom();\n }\n }\n\n private scrollToBottom() {\n requestAnimationFrame(() => {\n this.messagesEndRef?.scrollIntoView({ behavior: 'smooth' });\n });\n }\n\n private handleInput(e: Event) {\n this.input = (e.target as HTMLInputElement).value;\n }\n\n private async handleSubmit(e: Event) {\n e.preventDefault();\n\n if (!this.input.trim() || this.isLoading || !this.apiUrl) return;\n\n const userMessage: Message = {\n id: Date.now().toString(),\n role: 'user',\n content: this.input.trim(),\n };\n\n this.messages = [...this.messages, userMessage];\n const questionText = this.input.trim();\n this.input = '';\n this.isLoading = true;\n\n // Dispatch message-sent event\n this.dispatchEvent(new CustomEvent('message-sent', {\n detail: userMessage,\n bubbles: true,\n composed: true,\n }));\n\n try {\n const response = await fetch(`${this.apiUrl}/ask`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n session_id: this.sessionId,\n question: questionText,\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Backend error: ${response.status} ${errorText}`);\n }\n\n const data = await response.json();\n\n const assistantMessage: Message = {\n id: (Date.now() + 1).toString(),\n role: 'assistant',\n content: data.response || 'No response from agent',\n };\n\n this.messages = [...this.messages, assistantMessage];\n\n // Dispatch response-received event\n this.dispatchEvent(new CustomEvent('response-received', {\n detail: assistantMessage,\n bubbles: true,\n composed: true,\n }));\n } catch (err: any) {\n console.error('Backend connection failed:', err);\n\n const errorMessage: Message = {\n id: (Date.now() + 1).toString(),\n role: 'assistant',\n content: `Error: ${err.message}\\n\\nPlease check your API endpoint configuration.`,\n };\n\n this.messages = [...this.messages, errorMessage];\n\n // Dispatch error event\n this.dispatchEvent(new CustomEvent('error', {\n detail: err,\n bubbles: true,\n composed: true,\n }));\n } finally {\n this.isLoading = false;\n }\n }\n\n private renderChatUI() {\n return html`\n <!-- Header -->\n <div class=\"header\">\n <div class=\"header-content\">\n <h1 class=\"title\">${this.chatTitle}</h1>\n </div>\n </div>\n\n <!-- Messages Area -->\n <div class=\"messages-area\">\n <div class=\"messages-container\">\n ${this.messages.length === 0 ? html`\n <div class=\"empty-state\">\n <p>How can I help you today?</p>\n </div>\n ` : ''}\n\n ${repeat(this.messages, (msg) => msg.id, (msg) => html`\n <div class=${classMap({\n message: true,\n user: msg.role === 'user',\n assistant: msg.role === 'assistant'\n })}>\n <div class=\"avatar\">\n ${msg.role === 'user' ? 'U' : 'AI'}\n </div>\n <div class=\"message-content\">\n <p class=\"message-text\">${msg.content}</p>\n </div>\n </div>\n `)}\n\n ${this.isLoading ? html`\n <div class=\"loading\">\n <div class=\"avatar\">AI</div>\n <div class=\"message-content\">\n <div class=\"spinner\"></div>\n </div>\n </div>\n ` : ''}\n\n <div ${(el: Element) => this.messagesEndRef = el as HTMLDivElement}></div>\n </div>\n </div>\n\n <!-- Input Area -->\n <div class=\"input-area\">\n <form class=\"input-form\" @submit=${this.handleSubmit}>\n <input\n type=\"text\"\n class=\"input-field\"\n placeholder=\"Type your message...\"\n .value=${this.input}\n @input=${this.handleInput}\n ?disabled=${this.isLoading}\n />\n <button\n type=\"submit\"\n class=\"send-button\"\n ?disabled=${this.isLoading || !this.input.trim()}\n aria-label=\"Send message\"\n >\n ${this.isLoading ? html`\n <div class=\"spinner\" style=\"border-color: #fff; border-top-color: transparent;\"></div>\n ` : html`\n <svg class=\"send-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\"></line>\n <polygon points=\"22 2 15 22 11 13 2 9 22 2\"></polygon>\n </svg>\n `}\n </button>\n </form>\n </div>\n `;\n }\n\n render() {\n if (this.mode === 'widget') {\n return html`\n <div class=\"widget-container\">\n <!-- Chat Window -->\n <div class=${classMap({ 'widget-window': true, 'open': this.isOpen })}>\n ${this.renderChatUI()}\n </div>\n\n <!-- Toggle Button -->\n <button\n class=\"widget-button\"\n @click=${this.toggleWidget}\n aria-label=${this.isOpen ? 'Close chat' : 'Open chat'}\n >\n ${this.isOpen ? html`\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\n </svg>\n ` : html`\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"></path>\n </svg>\n `}\n </button>\n </div>\n `;\n }\n\n // Fullscreen mode\n return this.renderChatUI();\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'ai-chat': AIChat;\n }\n}\n"]}
|
package/dist/index.mjs
CHANGED
|
@@ -20,10 +20,15 @@ var AIChat = class extends LitElement {
|
|
|
20
20
|
this.sessionId = "default-session";
|
|
21
21
|
this.chatTitle = "My AI Agent";
|
|
22
22
|
this.theme = "light";
|
|
23
|
+
this.mode = "fullscreen";
|
|
23
24
|
this.initialMessages = [];
|
|
24
25
|
this.messages = [];
|
|
25
26
|
this.input = "";
|
|
26
27
|
this.isLoading = false;
|
|
28
|
+
this.isOpen = false;
|
|
29
|
+
}
|
|
30
|
+
toggleWidget() {
|
|
31
|
+
this.isOpen = !this.isOpen;
|
|
27
32
|
}
|
|
28
33
|
connectedCallback() {
|
|
29
34
|
super.connectedCallback();
|
|
@@ -106,7 +111,7 @@ Please check your API endpoint configuration.`
|
|
|
106
111
|
this.isLoading = false;
|
|
107
112
|
}
|
|
108
113
|
}
|
|
109
|
-
|
|
114
|
+
renderChatUI() {
|
|
110
115
|
return html`
|
|
111
116
|
<!-- Header -->
|
|
112
117
|
<div class="header">
|
|
@@ -182,22 +187,132 @@ Please check your API endpoint configuration.`
|
|
|
182
187
|
</div>
|
|
183
188
|
`;
|
|
184
189
|
}
|
|
190
|
+
render() {
|
|
191
|
+
if (this.mode === "widget") {
|
|
192
|
+
return html`
|
|
193
|
+
<div class="widget-container">
|
|
194
|
+
<!-- Chat Window -->
|
|
195
|
+
<div class=${classMap({ "widget-window": true, "open": this.isOpen })}>
|
|
196
|
+
${this.renderChatUI()}
|
|
197
|
+
</div>
|
|
198
|
+
|
|
199
|
+
<!-- Toggle Button -->
|
|
200
|
+
<button
|
|
201
|
+
class="widget-button"
|
|
202
|
+
@click=${this.toggleWidget}
|
|
203
|
+
aria-label=${this.isOpen ? "Close chat" : "Open chat"}
|
|
204
|
+
>
|
|
205
|
+
${this.isOpen ? html`
|
|
206
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
207
|
+
<line x1="18" y1="6" x2="6" y2="18"></line>
|
|
208
|
+
<line x1="6" y1="6" x2="18" y2="18"></line>
|
|
209
|
+
</svg>
|
|
210
|
+
` : html`
|
|
211
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
212
|
+
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path>
|
|
213
|
+
</svg>
|
|
214
|
+
`}
|
|
215
|
+
</button>
|
|
216
|
+
</div>
|
|
217
|
+
`;
|
|
218
|
+
}
|
|
219
|
+
return this.renderChatUI();
|
|
220
|
+
}
|
|
185
221
|
};
|
|
186
222
|
AIChat.styles = css`
|
|
187
223
|
:host {
|
|
224
|
+
font-family: system-ui, -apple-system, sans-serif;
|
|
225
|
+
color: #09090b;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/* Fullscreen mode (default) */
|
|
229
|
+
:host([mode="fullscreen"]) {
|
|
188
230
|
display: flex;
|
|
189
231
|
flex-direction: column;
|
|
190
232
|
height: 100vh;
|
|
191
|
-
font-family: system-ui, -apple-system, sans-serif;
|
|
192
233
|
background: #fafafa;
|
|
193
|
-
color: #09090b;
|
|
194
234
|
}
|
|
195
235
|
|
|
196
|
-
:host([theme="dark"]) {
|
|
236
|
+
:host([mode="fullscreen"][theme="dark"]) {
|
|
197
237
|
background: #000;
|
|
198
238
|
color: #fafafa;
|
|
199
239
|
}
|
|
200
240
|
|
|
241
|
+
/* Widget mode */
|
|
242
|
+
:host([mode="widget"]) {
|
|
243
|
+
position: fixed;
|
|
244
|
+
bottom: 20px;
|
|
245
|
+
right: 20px;
|
|
246
|
+
z-index: 9999;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
.widget-container {
|
|
250
|
+
position: relative;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
.widget-button {
|
|
254
|
+
width: 60px;
|
|
255
|
+
height: 60px;
|
|
256
|
+
border-radius: 50%;
|
|
257
|
+
background: #2563eb;
|
|
258
|
+
border: none;
|
|
259
|
+
cursor: pointer;
|
|
260
|
+
display: flex;
|
|
261
|
+
align-items: center;
|
|
262
|
+
justify-content: center;
|
|
263
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
264
|
+
transition: transform 0.2s, box-shadow 0.2s;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
.widget-button:hover {
|
|
268
|
+
transform: scale(1.05);
|
|
269
|
+
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
.widget-button svg {
|
|
273
|
+
width: 28px;
|
|
274
|
+
height: 28px;
|
|
275
|
+
color: white;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
.widget-window {
|
|
279
|
+
position: absolute;
|
|
280
|
+
bottom: 80px;
|
|
281
|
+
right: 0;
|
|
282
|
+
width: 380px;
|
|
283
|
+
height: 600px;
|
|
284
|
+
background: #fff;
|
|
285
|
+
border-radius: 12px;
|
|
286
|
+
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12);
|
|
287
|
+
display: flex;
|
|
288
|
+
flex-direction: column;
|
|
289
|
+
overflow: hidden;
|
|
290
|
+
opacity: 0;
|
|
291
|
+
transform: scale(0.9) translateY(20px);
|
|
292
|
+
pointer-events: none;
|
|
293
|
+
transition: opacity 0.2s, transform 0.2s;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
.widget-window.open {
|
|
297
|
+
opacity: 1;
|
|
298
|
+
transform: scale(1) translateY(0);
|
|
299
|
+
pointer-events: all;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
:host([theme="dark"]) .widget-window {
|
|
303
|
+
background: #18181b;
|
|
304
|
+
color: #fafafa;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
@media (max-width: 480px) {
|
|
308
|
+
.widget-window {
|
|
309
|
+
width: calc(100vw - 40px);
|
|
310
|
+
height: calc(100vh - 100px);
|
|
311
|
+
bottom: 80px;
|
|
312
|
+
right: 0;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
201
316
|
.header {
|
|
202
317
|
border-bottom: 1px solid #e4e4e7;
|
|
203
318
|
background: #fff;
|
|
@@ -402,6 +517,7 @@ AIChat.properties = {
|
|
|
402
517
|
sessionId: { type: String, attribute: "session-id" },
|
|
403
518
|
chatTitle: { type: String, attribute: "title" },
|
|
404
519
|
theme: { type: String },
|
|
520
|
+
mode: { type: String, reflect: true },
|
|
405
521
|
initialMessages: { type: Array }
|
|
406
522
|
};
|
|
407
523
|
__decorateClass([
|
|
@@ -413,6 +529,9 @@ __decorateClass([
|
|
|
413
529
|
__decorateClass([
|
|
414
530
|
state()
|
|
415
531
|
], AIChat.prototype, "isLoading", 2);
|
|
532
|
+
__decorateClass([
|
|
533
|
+
state()
|
|
534
|
+
], AIChat.prototype, "isOpen", 2);
|
|
416
535
|
AIChat = __decorateClass([
|
|
417
536
|
customElement("ai-chat")
|
|
418
537
|
], AIChat);
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/ai-chat.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["import { LitElement, html, css, PropertyValues } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { repeat } from 'lit/directives/repeat.js';\nimport { classMap } from 'lit/directives/class-map.js';\n\nexport interface Message {\n id: string;\n role: 'user' | 'assistant';\n content: string;\n}\n\n/**\n * AI Chat Web Component\n *\n * @fires message-sent - Fired when user sends a message\n * @fires response-received - Fired when AI responds\n * @fires error - Fired when an error occurs\n *\n * @example\n * ```html\n * <ai-chat\n * api-url=\"https://api.example.com\"\n * session-id=\"user-123\"\n * title=\"My AI Assistant\">\n * </ai-chat>\n * ```\n */\n@customElement('ai-chat')\nexport class AIChat extends LitElement {\n static styles = css`\n :host {\n display: flex;\n flex-direction: column;\n height: 100vh;\n font-family: system-ui, -apple-system, sans-serif;\n background: #fafafa;\n color: #09090b;\n }\n\n :host([theme=\"dark\"]) {\n background: #000;\n color: #fafafa;\n }\n\n .header {\n border-bottom: 1px solid #e4e4e7;\n background: #fff;\n padding: 1rem;\n }\n\n :host([theme=\"dark\"]) .header {\n border-bottom-color: #27272a;\n background: #18181b;\n }\n\n .header-content {\n max-width: 56rem;\n margin: 0 auto;\n }\n\n .title {\n font-size: 1.25rem;\n font-weight: 600;\n margin: 0;\n }\n\n .messages-area {\n flex: 1;\n overflow-y: auto;\n padding: 1.5rem 1rem;\n }\n\n .messages-container {\n max-width: 56rem;\n margin: 0 auto;\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n }\n\n .empty-state {\n text-align: center;\n color: #71717a;\n margin-top: 5rem;\n }\n\n :host([theme=\"dark\"]) .empty-state {\n color: #a1a1aa;\n }\n\n .empty-state p {\n font-size: 1.5rem;\n font-weight: 500;\n margin: 0;\n }\n\n .message {\n display: flex;\n gap: 1rem;\n }\n\n .message.user {\n flex-direction: row-reverse;\n }\n\n .avatar {\n width: 2.5rem;\n height: 2.5rem;\n border-radius: 9999px;\n background: #e4e4e7;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n font-weight: 500;\n font-size: 0.875rem;\n }\n\n :host([theme=\"dark\"]) .avatar {\n background: #3f3f46;\n }\n\n .message-content {\n max-width: 36rem;\n padding: 0.75rem 1rem;\n border-radius: 1rem;\n }\n\n .message.user .message-content {\n background: #2563eb;\n color: #fff;\n }\n\n .message.assistant .message-content {\n background: #fff;\n border: 1px solid #e4e4e7;\n color: #09090b;\n }\n\n :host([theme=\"dark\"]) .message.assistant .message-content {\n background: #27272a;\n border-color: #3f3f46;\n color: #fafafa;\n }\n\n .message-text {\n white-space: pre-wrap;\n margin: 0;\n }\n\n .loading {\n display: flex;\n gap: 1rem;\n }\n\n .spinner {\n display: inline-block;\n width: 1.25rem;\n height: 1.25rem;\n border: 2px solid #e4e4e7;\n border-top-color: #71717a;\n border-radius: 50%;\n animation: spin 1s linear infinite;\n }\n\n @keyframes spin {\n to { transform: rotate(360deg); }\n }\n\n .input-area {\n border-top: 1px solid #e4e4e7;\n background: #fff;\n padding: 1rem;\n }\n\n :host([theme=\"dark\"]) .input-area {\n border-top-color: #27272a;\n background: #000;\n }\n\n .input-form {\n max-width: 56rem;\n margin: 0 auto;\n display: flex;\n gap: 0.75rem;\n }\n\n .input-field {\n flex: 1;\n height: 3rem;\n padding: 0 1rem;\n border: 1px solid #e4e4e7;\n border-radius: 0.5rem;\n font-size: 1rem;\n font-family: inherit;\n background: #fff;\n color: #09090b;\n }\n\n :host([theme=\"dark\"]) .input-field {\n border-color: #3f3f46;\n background: #18181b;\n color: #fafafa;\n }\n\n .input-field:focus {\n outline: 2px solid #2563eb;\n outline-offset: 2px;\n }\n\n .input-field:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .send-button {\n width: 3rem;\n height: 3rem;\n border-radius: 9999px;\n border: none;\n background: #2563eb;\n color: #fff;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: background 0.2s;\n }\n\n .send-button:hover:not(:disabled) {\n background: #1d4ed8;\n }\n\n .send-button:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .send-icon {\n width: 1.25rem;\n height: 1.25rem;\n }\n `;\n\n declare apiUrl: string;\n declare sessionId: string;\n declare chatTitle: string;\n declare theme: 'light' | 'dark';\n declare initialMessages: Message[];\n\n @state()\n private declare messages: Message[];\n\n @state()\n private declare input: string;\n\n @state()\n private declare isLoading: boolean;\n\n private messagesEndRef?: HTMLDivElement;\n\n static override properties = {\n apiUrl: { type: String, attribute: 'api-url' },\n sessionId: { type: String, attribute: 'session-id' },\n chatTitle: { type: String, attribute: 'title' },\n theme: { type: String },\n initialMessages: { type: Array },\n };\n\n constructor() {\n super();\n this.apiUrl = '';\n this.sessionId = 'default-session';\n this.chatTitle = 'My AI Agent';\n this.theme = 'light';\n this.initialMessages = [];\n this.messages = [];\n this.input = '';\n this.isLoading = false;\n }\n\n connectedCallback() {\n super.connectedCallback();\n if (this.initialMessages && this.initialMessages.length > 0) {\n this.messages = [...this.initialMessages];\n }\n }\n\n updated(changedProperties: PropertyValues) {\n super.updated(changedProperties);\n if (changedProperties.has('messages')) {\n this.scrollToBottom();\n }\n }\n\n private scrollToBottom() {\n requestAnimationFrame(() => {\n this.messagesEndRef?.scrollIntoView({ behavior: 'smooth' });\n });\n }\n\n private handleInput(e: Event) {\n this.input = (e.target as HTMLInputElement).value;\n }\n\n private async handleSubmit(e: Event) {\n e.preventDefault();\n\n if (!this.input.trim() || this.isLoading || !this.apiUrl) return;\n\n const userMessage: Message = {\n id: Date.now().toString(),\n role: 'user',\n content: this.input.trim(),\n };\n\n this.messages = [...this.messages, userMessage];\n const questionText = this.input.trim();\n this.input = '';\n this.isLoading = true;\n\n // Dispatch message-sent event\n this.dispatchEvent(new CustomEvent('message-sent', {\n detail: userMessage,\n bubbles: true,\n composed: true,\n }));\n\n try {\n const response = await fetch(`${this.apiUrl}/ask`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n session_id: this.sessionId,\n question: questionText,\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Backend error: ${response.status} ${errorText}`);\n }\n\n const data = await response.json();\n\n const assistantMessage: Message = {\n id: (Date.now() + 1).toString(),\n role: 'assistant',\n content: data.response || 'No response from agent',\n };\n\n this.messages = [...this.messages, assistantMessage];\n\n // Dispatch response-received event\n this.dispatchEvent(new CustomEvent('response-received', {\n detail: assistantMessage,\n bubbles: true,\n composed: true,\n }));\n } catch (err: any) {\n console.error('Backend connection failed:', err);\n\n const errorMessage: Message = {\n id: (Date.now() + 1).toString(),\n role: 'assistant',\n content: `Error: ${err.message}\\n\\nPlease check your API endpoint configuration.`,\n };\n\n this.messages = [...this.messages, errorMessage];\n\n // Dispatch error event\n this.dispatchEvent(new CustomEvent('error', {\n detail: err,\n bubbles: true,\n composed: true,\n }));\n } finally {\n this.isLoading = false;\n }\n }\n\n render() {\n return html`\n <!-- Header -->\n <div class=\"header\">\n <div class=\"header-content\">\n <h1 class=\"title\">${this.chatTitle}</h1>\n </div>\n </div>\n\n <!-- Messages Area -->\n <div class=\"messages-area\">\n <div class=\"messages-container\">\n ${this.messages.length === 0 ? html`\n <div class=\"empty-state\">\n <p>How can I help you today?</p>\n </div>\n ` : ''}\n\n ${repeat(this.messages, (msg) => msg.id, (msg) => html`\n <div class=${classMap({\n message: true,\n user: msg.role === 'user',\n assistant: msg.role === 'assistant'\n })}>\n <div class=\"avatar\">\n ${msg.role === 'user' ? 'U' : 'AI'}\n </div>\n <div class=\"message-content\">\n <p class=\"message-text\">${msg.content}</p>\n </div>\n </div>\n `)}\n\n ${this.isLoading ? html`\n <div class=\"loading\">\n <div class=\"avatar\">AI</div>\n <div class=\"message-content\">\n <div class=\"spinner\"></div>\n </div>\n </div>\n ` : ''}\n\n <div ${(el: Element) => this.messagesEndRef = el as HTMLDivElement}></div>\n </div>\n </div>\n\n <!-- Input Area -->\n <div class=\"input-area\">\n <form class=\"input-form\" @submit=${this.handleSubmit}>\n <input\n type=\"text\"\n class=\"input-field\"\n placeholder=\"Type your message...\"\n .value=${this.input}\n @input=${this.handleInput}\n ?disabled=${this.isLoading}\n />\n <button\n type=\"submit\"\n class=\"send-button\"\n ?disabled=${this.isLoading || !this.input.trim()}\n aria-label=\"Send message\"\n >\n ${this.isLoading ? html`\n <div class=\"spinner\" style=\"border-color: #fff; border-top-color: transparent;\"></div>\n ` : html`\n <svg class=\"send-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\"></line>\n <polygon points=\"22 2 15 22 11 13 2 9 22 2\"></polygon>\n </svg>\n `}\n </button>\n </form>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'ai-chat': AIChat;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/components/ai-chat.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["import { LitElement, html, css, PropertyValues } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { repeat } from 'lit/directives/repeat.js';\nimport { classMap } from 'lit/directives/class-map.js';\n\nexport interface Message {\n id: string;\n role: 'user' | 'assistant';\n content: string;\n}\n\n/**\n * AI Chat Web Component\n *\n * @fires message-sent - Fired when user sends a message\n * @fires response-received - Fired when AI responds\n * @fires error - Fired when an error occurs\n *\n * @example\n * ```html\n * <ai-chat\n * api-url=\"https://api.example.com\"\n * session-id=\"user-123\"\n * title=\"My AI Assistant\">\n * </ai-chat>\n * ```\n */\n@customElement('ai-chat')\nexport class AIChat extends LitElement {\n static styles = css`\n :host {\n font-family: system-ui, -apple-system, sans-serif;\n color: #09090b;\n }\n\n /* Fullscreen mode (default) */\n :host([mode=\"fullscreen\"]) {\n display: flex;\n flex-direction: column;\n height: 100vh;\n background: #fafafa;\n }\n\n :host([mode=\"fullscreen\"][theme=\"dark\"]) {\n background: #000;\n color: #fafafa;\n }\n\n /* Widget mode */\n :host([mode=\"widget\"]) {\n position: fixed;\n bottom: 20px;\n right: 20px;\n z-index: 9999;\n }\n\n .widget-container {\n position: relative;\n }\n\n .widget-button {\n width: 60px;\n height: 60px;\n border-radius: 50%;\n background: #2563eb;\n border: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n transition: transform 0.2s, box-shadow 0.2s;\n }\n\n .widget-button:hover {\n transform: scale(1.05);\n box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2);\n }\n\n .widget-button svg {\n width: 28px;\n height: 28px;\n color: white;\n }\n\n .widget-window {\n position: absolute;\n bottom: 80px;\n right: 0;\n width: 380px;\n height: 600px;\n background: #fff;\n border-radius: 12px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n opacity: 0;\n transform: scale(0.9) translateY(20px);\n pointer-events: none;\n transition: opacity 0.2s, transform 0.2s;\n }\n\n .widget-window.open {\n opacity: 1;\n transform: scale(1) translateY(0);\n pointer-events: all;\n }\n\n :host([theme=\"dark\"]) .widget-window {\n background: #18181b;\n color: #fafafa;\n }\n\n @media (max-width: 480px) {\n .widget-window {\n width: calc(100vw - 40px);\n height: calc(100vh - 100px);\n bottom: 80px;\n right: 0;\n }\n }\n\n .header {\n border-bottom: 1px solid #e4e4e7;\n background: #fff;\n padding: 1rem;\n }\n\n :host([theme=\"dark\"]) .header {\n border-bottom-color: #27272a;\n background: #18181b;\n }\n\n .header-content {\n max-width: 56rem;\n margin: 0 auto;\n }\n\n .title {\n font-size: 1.25rem;\n font-weight: 600;\n margin: 0;\n }\n\n .messages-area {\n flex: 1;\n overflow-y: auto;\n padding: 1.5rem 1rem;\n }\n\n .messages-container {\n max-width: 56rem;\n margin: 0 auto;\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n }\n\n .empty-state {\n text-align: center;\n color: #71717a;\n margin-top: 5rem;\n }\n\n :host([theme=\"dark\"]) .empty-state {\n color: #a1a1aa;\n }\n\n .empty-state p {\n font-size: 1.5rem;\n font-weight: 500;\n margin: 0;\n }\n\n .message {\n display: flex;\n gap: 1rem;\n }\n\n .message.user {\n flex-direction: row-reverse;\n }\n\n .avatar {\n width: 2.5rem;\n height: 2.5rem;\n border-radius: 9999px;\n background: #e4e4e7;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n font-weight: 500;\n font-size: 0.875rem;\n }\n\n :host([theme=\"dark\"]) .avatar {\n background: #3f3f46;\n }\n\n .message-content {\n max-width: 36rem;\n padding: 0.75rem 1rem;\n border-radius: 1rem;\n }\n\n .message.user .message-content {\n background: #2563eb;\n color: #fff;\n }\n\n .message.assistant .message-content {\n background: #fff;\n border: 1px solid #e4e4e7;\n color: #09090b;\n }\n\n :host([theme=\"dark\"]) .message.assistant .message-content {\n background: #27272a;\n border-color: #3f3f46;\n color: #fafafa;\n }\n\n .message-text {\n white-space: pre-wrap;\n margin: 0;\n }\n\n .loading {\n display: flex;\n gap: 1rem;\n }\n\n .spinner {\n display: inline-block;\n width: 1.25rem;\n height: 1.25rem;\n border: 2px solid #e4e4e7;\n border-top-color: #71717a;\n border-radius: 50%;\n animation: spin 1s linear infinite;\n }\n\n @keyframes spin {\n to { transform: rotate(360deg); }\n }\n\n .input-area {\n border-top: 1px solid #e4e4e7;\n background: #fff;\n padding: 1rem;\n }\n\n :host([theme=\"dark\"]) .input-area {\n border-top-color: #27272a;\n background: #000;\n }\n\n .input-form {\n max-width: 56rem;\n margin: 0 auto;\n display: flex;\n gap: 0.75rem;\n }\n\n .input-field {\n flex: 1;\n height: 3rem;\n padding: 0 1rem;\n border: 1px solid #e4e4e7;\n border-radius: 0.5rem;\n font-size: 1rem;\n font-family: inherit;\n background: #fff;\n color: #09090b;\n }\n\n :host([theme=\"dark\"]) .input-field {\n border-color: #3f3f46;\n background: #18181b;\n color: #fafafa;\n }\n\n .input-field:focus {\n outline: 2px solid #2563eb;\n outline-offset: 2px;\n }\n\n .input-field:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .send-button {\n width: 3rem;\n height: 3rem;\n border-radius: 9999px;\n border: none;\n background: #2563eb;\n color: #fff;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: background 0.2s;\n }\n\n .send-button:hover:not(:disabled) {\n background: #1d4ed8;\n }\n\n .send-button:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .send-icon {\n width: 1.25rem;\n height: 1.25rem;\n }\n `;\n\n declare apiUrl: string;\n declare sessionId: string;\n declare chatTitle: string;\n declare theme: 'light' | 'dark';\n declare mode: 'fullscreen' | 'widget';\n declare initialMessages: Message[];\n\n @state()\n private declare messages: Message[];\n\n @state()\n private declare input: string;\n\n @state()\n private declare isLoading: boolean;\n\n @state()\n private declare isOpen: boolean;\n\n private messagesEndRef?: HTMLDivElement;\n\n static override properties = {\n apiUrl: { type: String, attribute: 'api-url' },\n sessionId: { type: String, attribute: 'session-id' },\n chatTitle: { type: String, attribute: 'title' },\n theme: { type: String },\n mode: { type: String, reflect: true },\n initialMessages: { type: Array },\n };\n\n constructor() {\n super();\n this.apiUrl = '';\n this.sessionId = 'default-session';\n this.chatTitle = 'My AI Agent';\n this.theme = 'light';\n this.mode = 'fullscreen';\n this.initialMessages = [];\n this.messages = [];\n this.input = '';\n this.isLoading = false;\n this.isOpen = false;\n }\n\n private toggleWidget() {\n this.isOpen = !this.isOpen;\n }\n\n connectedCallback() {\n super.connectedCallback();\n if (this.initialMessages && this.initialMessages.length > 0) {\n this.messages = [...this.initialMessages];\n }\n }\n\n updated(changedProperties: PropertyValues) {\n super.updated(changedProperties);\n if (changedProperties.has('messages')) {\n this.scrollToBottom();\n }\n }\n\n private scrollToBottom() {\n requestAnimationFrame(() => {\n this.messagesEndRef?.scrollIntoView({ behavior: 'smooth' });\n });\n }\n\n private handleInput(e: Event) {\n this.input = (e.target as HTMLInputElement).value;\n }\n\n private async handleSubmit(e: Event) {\n e.preventDefault();\n\n if (!this.input.trim() || this.isLoading || !this.apiUrl) return;\n\n const userMessage: Message = {\n id: Date.now().toString(),\n role: 'user',\n content: this.input.trim(),\n };\n\n this.messages = [...this.messages, userMessage];\n const questionText = this.input.trim();\n this.input = '';\n this.isLoading = true;\n\n // Dispatch message-sent event\n this.dispatchEvent(new CustomEvent('message-sent', {\n detail: userMessage,\n bubbles: true,\n composed: true,\n }));\n\n try {\n const response = await fetch(`${this.apiUrl}/ask`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n session_id: this.sessionId,\n question: questionText,\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Backend error: ${response.status} ${errorText}`);\n }\n\n const data = await response.json();\n\n const assistantMessage: Message = {\n id: (Date.now() + 1).toString(),\n role: 'assistant',\n content: data.response || 'No response from agent',\n };\n\n this.messages = [...this.messages, assistantMessage];\n\n // Dispatch response-received event\n this.dispatchEvent(new CustomEvent('response-received', {\n detail: assistantMessage,\n bubbles: true,\n composed: true,\n }));\n } catch (err: any) {\n console.error('Backend connection failed:', err);\n\n const errorMessage: Message = {\n id: (Date.now() + 1).toString(),\n role: 'assistant',\n content: `Error: ${err.message}\\n\\nPlease check your API endpoint configuration.`,\n };\n\n this.messages = [...this.messages, errorMessage];\n\n // Dispatch error event\n this.dispatchEvent(new CustomEvent('error', {\n detail: err,\n bubbles: true,\n composed: true,\n }));\n } finally {\n this.isLoading = false;\n }\n }\n\n private renderChatUI() {\n return html`\n <!-- Header -->\n <div class=\"header\">\n <div class=\"header-content\">\n <h1 class=\"title\">${this.chatTitle}</h1>\n </div>\n </div>\n\n <!-- Messages Area -->\n <div class=\"messages-area\">\n <div class=\"messages-container\">\n ${this.messages.length === 0 ? html`\n <div class=\"empty-state\">\n <p>How can I help you today?</p>\n </div>\n ` : ''}\n\n ${repeat(this.messages, (msg) => msg.id, (msg) => html`\n <div class=${classMap({\n message: true,\n user: msg.role === 'user',\n assistant: msg.role === 'assistant'\n })}>\n <div class=\"avatar\">\n ${msg.role === 'user' ? 'U' : 'AI'}\n </div>\n <div class=\"message-content\">\n <p class=\"message-text\">${msg.content}</p>\n </div>\n </div>\n `)}\n\n ${this.isLoading ? html`\n <div class=\"loading\">\n <div class=\"avatar\">AI</div>\n <div class=\"message-content\">\n <div class=\"spinner\"></div>\n </div>\n </div>\n ` : ''}\n\n <div ${(el: Element) => this.messagesEndRef = el as HTMLDivElement}></div>\n </div>\n </div>\n\n <!-- Input Area -->\n <div class=\"input-area\">\n <form class=\"input-form\" @submit=${this.handleSubmit}>\n <input\n type=\"text\"\n class=\"input-field\"\n placeholder=\"Type your message...\"\n .value=${this.input}\n @input=${this.handleInput}\n ?disabled=${this.isLoading}\n />\n <button\n type=\"submit\"\n class=\"send-button\"\n ?disabled=${this.isLoading || !this.input.trim()}\n aria-label=\"Send message\"\n >\n ${this.isLoading ? html`\n <div class=\"spinner\" style=\"border-color: #fff; border-top-color: transparent;\"></div>\n ` : html`\n <svg class=\"send-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\"></line>\n <polygon points=\"22 2 15 22 11 13 2 9 22 2\"></polygon>\n </svg>\n `}\n </button>\n </form>\n </div>\n `;\n }\n\n render() {\n if (this.mode === 'widget') {\n return html`\n <div class=\"widget-container\">\n <!-- Chat Window -->\n <div class=${classMap({ 'widget-window': true, 'open': this.isOpen })}>\n ${this.renderChatUI()}\n </div>\n\n <!-- Toggle Button -->\n <button\n class=\"widget-button\"\n @click=${this.toggleWidget}\n aria-label=${this.isOpen ? 'Close chat' : 'Open chat'}\n >\n ${this.isOpen ? html`\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\n </svg>\n ` : html`\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"></path>\n </svg>\n `}\n </button>\n </div>\n `;\n }\n\n // Fullscreen mode\n return this.renderChatUI();\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'ai-chat': AIChat;\n }\n}\n"]}
|
package/package.json
CHANGED