@salla.sa/ui-ai-kit-core 1.1.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/ai-card.cjs.entry.js +2 -2
- package/dist/cjs/ai-chat-container.cjs.entry.js +84 -57
- package/dist/cjs/ai-chat-header.cjs.entry.js +29 -19
- package/dist/cjs/ai-chat-message.cjs.entry.js +1456 -21
- package/dist/cjs/ai-conversation-list.cjs.entry.js +80 -0
- package/dist/cjs/ai-conversation-summary.cjs.entry.js +33 -0
- package/dist/cjs/ai-icon.cjs.entry.js +2 -2
- package/dist/cjs/ai-link.cjs.entry.js +4 -4
- package/dist/cjs/ai-loading.cjs.entry.js +35 -22
- package/dist/cjs/ai-message-input.cjs.entry.js +48 -15
- package/dist/cjs/ai-rating.cjs.entry.js +2 -2
- package/dist/cjs/ai-route-decision.cjs.entry.js +48 -0
- package/dist/cjs/ai-suggestion.cjs.entry.js +4 -4
- package/dist/cjs/ai-voice-input.cjs.entry.js +75 -21
- package/dist/cjs/{icon-registry-dmfLA-Dj.js → icon-registry-BKb9-2Nt.js} +24 -0
- package/dist/cjs/{index-DLJcLHFH.js → index-BkNg07SW.js} +1 -1
- package/dist/cjs/loader.cjs.js +2 -2
- package/dist/cjs/ui-ai-kit.cjs.js +2 -2
- package/dist/collection/collection-manifest.json +3 -0
- package/dist/collection/components/ai-card/ai-card.css +5 -8
- package/dist/collection/components/ai-chat-container/ai-chat-container.css +17 -14
- package/dist/collection/components/ai-chat-container/ai-chat-container.js +125 -53
- package/dist/collection/components/ai-chat-header/ai-chat-header.css +50 -17
- package/dist/collection/components/ai-chat-header/ai-chat-header.js +53 -18
- package/dist/collection/components/ai-chat-message/ai-chat-message.css +47 -38
- package/dist/collection/components/ai-chat-message/ai-chat-message.js +68 -18
- package/dist/collection/components/ai-conversation-list/ai-conversation-list.css +196 -0
- package/dist/collection/components/ai-conversation-list/ai-conversation-list.js +176 -0
- package/dist/collection/components/ai-conversation-summary/ai-conversation-summary.css +103 -0
- package/dist/collection/components/ai-conversation-summary/ai-conversation-summary.js +118 -0
- package/dist/collection/components/ai-icon/ai-icon.js +1 -1
- package/dist/collection/components/ai-link/ai-link.css +3 -7
- package/dist/collection/components/ai-link/ai-link.js +1 -1
- package/dist/collection/components/ai-loading/ai-loading.css +149 -20
- package/dist/collection/components/ai-loading/ai-loading.js +100 -23
- package/dist/collection/components/ai-message-input/ai-message-input.css +41 -37
- package/dist/collection/components/ai-message-input/ai-message-input.js +100 -19
- package/dist/collection/components/ai-rating/ai-rating.css +8 -14
- package/dist/collection/components/ai-route-decision/ai-route-decision.css +132 -0
- package/dist/collection/components/ai-route-decision/ai-route-decision.js +195 -0
- package/dist/collection/components/ai-suggestion/ai-suggestion.css +5 -11
- package/dist/collection/components/ai-suggestion/ai-suggestion.js +2 -2
- package/dist/collection/components/ai-voice-input/ai-voice-input.css +27 -22
- package/dist/collection/components/ai-voice-input/ai-voice-input.js +116 -20
- package/dist/collection/utils/icon-registry.js +24 -0
- package/dist/components/ai-card.js +1 -1
- package/dist/components/ai-chat-container.js +1 -1
- package/dist/components/ai-chat-header.js +1 -1
- package/dist/components/ai-chat-message.js +2 -1
- package/dist/components/ai-conversation-list.d.ts +11 -0
- package/dist/components/ai-conversation-list.js +1 -0
- package/dist/components/ai-conversation-summary.d.ts +11 -0
- package/dist/components/ai-conversation-summary.js +1 -0
- package/dist/components/ai-icon.js +1 -1
- package/dist/components/ai-link.js +1 -1
- package/dist/components/ai-loading.js +1 -1
- package/dist/components/ai-message-input.js +1 -1
- package/dist/components/ai-rating.js +1 -1
- package/dist/components/ai-route-decision.d.ts +11 -0
- package/dist/components/ai-route-decision.js +1 -0
- package/dist/components/ai-suggestion.js +1 -1
- package/dist/components/ai-voice-input.js +1 -1
- package/dist/components/index.js +1 -1
- package/dist/components/p-CX1Yp79q.js +1 -0
- package/dist/components/p-DnO4dikr.js +1 -0
- package/dist/components/{p-CY6emva2.js → p-Dr2tAPV7.js} +1 -1
- package/dist/{ui-ai-kit/p-DYv5ef4M.js → components/p-SJZ6Ujn9.js} +1 -1
- package/dist/esm/ai-card.entry.js +2 -2
- package/dist/esm/ai-chat-container.entry.js +84 -57
- package/dist/esm/ai-chat-header.entry.js +29 -19
- package/dist/esm/ai-chat-message.entry.js +1456 -21
- package/dist/esm/ai-conversation-list.entry.js +78 -0
- package/dist/esm/ai-conversation-summary.entry.js +31 -0
- package/dist/esm/ai-icon.entry.js +2 -2
- package/dist/esm/ai-link.entry.js +4 -4
- package/dist/esm/ai-loading.entry.js +35 -22
- package/dist/esm/ai-message-input.entry.js +48 -15
- package/dist/esm/ai-rating.entry.js +2 -2
- package/dist/esm/ai-route-decision.entry.js +46 -0
- package/dist/esm/ai-suggestion.entry.js +4 -4
- package/dist/esm/ai-voice-input.entry.js +75 -21
- package/dist/esm/{icon-registry-DYv5ef4M.js → icon-registry-SJZ6Ujn9.js} +24 -0
- package/dist/esm/{index-7hrZ8FOQ.js → index-B0yIzgh4.js} +1 -1
- package/dist/esm/loader.js +3 -3
- package/dist/esm/ui-ai-kit.js +3 -3
- package/dist/types/components/ai-chat-container/ai-chat-container.d.ts +11 -1
- package/dist/types/components/ai-chat-header/ai-chat-header.d.ts +7 -2
- package/dist/types/components/ai-conversation-list/ai-conversation-list.d.ts +24 -0
- package/dist/types/components/ai-conversation-summary/ai-conversation-summary.d.ts +12 -0
- package/dist/types/components/ai-loading/ai-loading.d.ts +12 -6
- package/dist/types/components/ai-message-input/ai-message-input.d.ts +17 -3
- package/dist/types/components/ai-route-decision/ai-route-decision.d.ts +21 -0
- package/dist/types/components/ai-voice-input/ai-voice-input.d.ts +7 -0
- package/dist/types/components.d.ts +335 -11
- package/dist/types/index.d.ts +2 -0
- package/dist/types/utils/icon-registry.d.ts +1 -1
- package/dist/ui-ai-kit/p-2955439f.entry.js +1 -0
- package/dist/ui-ai-kit/p-5c9e9822.entry.js +1 -0
- package/dist/ui-ai-kit/p-5caf1c38.entry.js +1 -0
- package/dist/ui-ai-kit/p-74c5c83f.entry.js +1 -0
- package/dist/ui-ai-kit/p-76195745.entry.js +1 -0
- package/dist/ui-ai-kit/p-79c78d8e.entry.js +1 -0
- package/dist/ui-ai-kit/p-87e9739b.entry.js +1 -0
- package/dist/ui-ai-kit/p-9c4c6c01.entry.js +1 -0
- package/dist/ui-ai-kit/p-B0yIzgh4.js +2 -0
- package/dist/{components/p-DYv5ef4M.js → ui-ai-kit/p-SJZ6Ujn9.js} +1 -1
- package/dist/ui-ai-kit/p-a099fcfb.entry.js +1 -0
- package/dist/ui-ai-kit/p-b28af13a.entry.js +1 -0
- package/dist/ui-ai-kit/p-d1bb1ad0.entry.js +1 -0
- package/dist/ui-ai-kit/p-eb0c7e7a.entry.js +1 -0
- package/dist/ui-ai-kit/{p-455daa17.entry.js → p-eec6f083.entry.js} +1 -1
- package/dist/ui-ai-kit/p-ef07638f.entry.js +2 -0
- package/dist/ui-ai-kit/ui-ai-kit.css +1 -1
- package/dist/ui-ai-kit/ui-ai-kit.esm.js +1 -1
- package/package.json +5 -13
- package/dist/collection/components/ai-card/ai-card.stories.js +0 -52
- package/dist/collection/components/ai-chat-container/ai-chat-container.stories.js +0 -160
- package/dist/collection/components/ai-chat-header/ai-chat-header.stories.js +0 -138
- package/dist/collection/components/ai-chat-message/ai-chat-message.stories.js +0 -164
- package/dist/collection/components/ai-link/ai-link.stories.js +0 -79
- package/dist/collection/components/ai-loading/ai-loading.stories.js +0 -145
- package/dist/collection/components/ai-message-input/ai-message-input.stories.js +0 -125
- package/dist/collection/components/ai-rating/ai-rating.stories.js +0 -78
- package/dist/collection/components/ai-suggestion/ai-suggestion.stories.js +0 -62
- package/dist/collection/components/ai-voice-input/ai-voice-input.stories.js +0 -118
- package/dist/components/p-CWjXxYJI.js +0 -1
- package/dist/types/components/ai-card/ai-card.stories.d.ts +0 -7
- package/dist/types/components/ai-chat-container/ai-chat-container.stories.d.ts +0 -7
- package/dist/types/components/ai-chat-header/ai-chat-header.stories.d.ts +0 -8
- package/dist/types/components/ai-chat-message/ai-chat-message.stories.d.ts +0 -10
- package/dist/types/components/ai-link/ai-link.stories.d.ts +0 -8
- package/dist/types/components/ai-loading/ai-loading.stories.d.ts +0 -10
- package/dist/types/components/ai-message-input/ai-message-input.stories.d.ts +0 -13
- package/dist/types/components/ai-rating/ai-rating.stories.d.ts +0 -8
- package/dist/types/components/ai-suggestion/ai-suggestion.stories.d.ts +0 -8
- package/dist/types/components/ai-voice-input/ai-voice-input.stories.d.ts +0 -9
- package/dist/ui-ai-kit/p-11facfad.entry.js +0 -1
- package/dist/ui-ai-kit/p-128a2ed4.entry.js +0 -1
- package/dist/ui-ai-kit/p-227bdb8f.entry.js +0 -1
- package/dist/ui-ai-kit/p-56163e8c.entry.js +0 -1
- package/dist/ui-ai-kit/p-6d21d0fd.entry.js +0 -1
- package/dist/ui-ai-kit/p-6ddcd77b.entry.js +0 -1
- package/dist/ui-ai-kit/p-7hrZ8FOQ.js +0 -2
- package/dist/ui-ai-kit/p-8e90143e.entry.js +0 -1
- package/dist/ui-ai-kit/p-9938c277.entry.js +0 -1
- package/dist/ui-ai-kit/p-dc5b4a7f.entry.js +0 -1
- package/dist/ui-ai-kit/p-fb1702de.entry.js +0 -1
|
@@ -13,32 +13,89 @@ export class ChatContainer {
|
|
|
13
13
|
showWatermark = false;
|
|
14
14
|
/** Height of the panel when position='float' */
|
|
15
15
|
floatHeight = '600px';
|
|
16
|
+
/** Color theme for the panel */
|
|
17
|
+
theme = 'light';
|
|
16
18
|
isMobile = false;
|
|
19
|
+
floatLeft = '24px';
|
|
20
|
+
floatTop = '24px';
|
|
17
21
|
containerRef;
|
|
22
|
+
messagesAreaRef;
|
|
18
23
|
dragState = null;
|
|
19
|
-
|
|
24
|
+
// Named arrow so we can reliably add/remove it without leaking
|
|
25
|
+
dragListener = (e) => {
|
|
26
|
+
const container = this.containerRef;
|
|
27
|
+
if (!container)
|
|
28
|
+
return;
|
|
29
|
+
const { clientX, clientY } = e.detail;
|
|
30
|
+
const rect = container.getBoundingClientRect();
|
|
31
|
+
this.dragState = {
|
|
32
|
+
startX: clientX,
|
|
33
|
+
startY: clientY,
|
|
34
|
+
initLeft: rect.left,
|
|
35
|
+
initTop: rect.top,
|
|
36
|
+
};
|
|
37
|
+
// Capture current rendered position into state so subsequent re-renders don't jump
|
|
38
|
+
this.floatLeft = `${rect.left}px`;
|
|
39
|
+
this.floatTop = `${rect.top}px`;
|
|
40
|
+
const onMove = (me) => {
|
|
41
|
+
if (!this.dragState)
|
|
42
|
+
return;
|
|
43
|
+
const dx = me.clientX - this.dragState.startX;
|
|
44
|
+
const dy = me.clientY - this.dragState.startY;
|
|
45
|
+
let newLeft = this.dragState.initLeft + dx;
|
|
46
|
+
let newTop = this.dragState.initTop + dy;
|
|
47
|
+
const vw = window.innerWidth;
|
|
48
|
+
const vh = window.innerHeight;
|
|
49
|
+
const w = container.offsetWidth;
|
|
50
|
+
const h = container.offsetHeight;
|
|
51
|
+
newLeft = Math.max(0, Math.min(newLeft, vw - w));
|
|
52
|
+
newTop = Math.max(0, Math.min(newTop, vh - h));
|
|
53
|
+
this.floatLeft = `${newLeft}px`;
|
|
54
|
+
this.floatTop = `${newTop}px`;
|
|
55
|
+
};
|
|
56
|
+
const onUp = () => {
|
|
57
|
+
this.dragState = null;
|
|
58
|
+
document.removeEventListener('pointermove', onMove);
|
|
59
|
+
document.removeEventListener('pointerup', onUp);
|
|
60
|
+
};
|
|
61
|
+
document.addEventListener('pointermove', onMove);
|
|
62
|
+
document.addEventListener('pointerup', onUp);
|
|
63
|
+
};
|
|
64
|
+
constructor() {
|
|
65
|
+
// Bind so window.removeEventListener can match the reference
|
|
66
|
+
this.checkMobile = this.checkMobile.bind(this);
|
|
67
|
+
}
|
|
20
68
|
componentWillLoad() {
|
|
21
69
|
this.checkMobile();
|
|
22
70
|
}
|
|
23
71
|
componentDidLoad() {
|
|
24
72
|
if (typeof window !== 'undefined') {
|
|
25
|
-
this.
|
|
26
|
-
this.checkMobile();
|
|
27
|
-
});
|
|
28
|
-
this.resizeObserver.observe(document.body);
|
|
73
|
+
window.addEventListener('resize', this.checkMobile);
|
|
29
74
|
if (this.position === 'float') {
|
|
30
75
|
this.setupDrag();
|
|
31
76
|
}
|
|
32
77
|
}
|
|
33
78
|
}
|
|
79
|
+
isOpenChanged(newVal) {
|
|
80
|
+
if (newVal && this.autoScroll && this.messagesAreaRef) {
|
|
81
|
+
requestAnimationFrame(() => {
|
|
82
|
+
this.messagesAreaRef.scrollTop = this.messagesAreaRef.scrollHeight;
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
34
86
|
positionChanged(newVal) {
|
|
35
87
|
if (newVal === 'float') {
|
|
36
88
|
this.setupDrag();
|
|
37
89
|
}
|
|
38
90
|
}
|
|
39
91
|
disconnectedCallback() {
|
|
40
|
-
|
|
41
|
-
|
|
92
|
+
window.removeEventListener('resize', this.checkMobile);
|
|
93
|
+
this.el.removeEventListener('headerDragStart', this.dragListener);
|
|
94
|
+
}
|
|
95
|
+
/** Programmatically scroll the messages area to the bottom */
|
|
96
|
+
async scrollToBottom() {
|
|
97
|
+
if (this.messagesAreaRef) {
|
|
98
|
+
this.messagesAreaRef.scrollTop = this.messagesAreaRef.scrollHeight;
|
|
42
99
|
}
|
|
43
100
|
}
|
|
44
101
|
checkMobile() {
|
|
@@ -47,50 +104,9 @@ export class ChatContainer {
|
|
|
47
104
|
}
|
|
48
105
|
}
|
|
49
106
|
setupDrag() {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
// Listen on the host element so composed events from ai-chat-header's shadow DOM
|
|
54
|
-
// are received. (composedPath() hides cross-shadow-root elements from shadow listeners.)
|
|
55
|
-
this.el.addEventListener('headerDragStart', (e) => {
|
|
56
|
-
const { clientX, clientY } = e.detail;
|
|
57
|
-
const rect = container.getBoundingClientRect();
|
|
58
|
-
this.dragState = {
|
|
59
|
-
startX: clientX,
|
|
60
|
-
startY: clientY,
|
|
61
|
-
initLeft: rect.left,
|
|
62
|
-
initTop: rect.top,
|
|
63
|
-
};
|
|
64
|
-
// Switch from bottom/right anchoring to top/left so we can move freely
|
|
65
|
-
container.style.right = 'auto';
|
|
66
|
-
container.style.bottom = 'auto';
|
|
67
|
-
container.style.left = `${rect.left}px`;
|
|
68
|
-
container.style.top = `${rect.top}px`;
|
|
69
|
-
const onMove = (me) => {
|
|
70
|
-
if (!this.dragState)
|
|
71
|
-
return;
|
|
72
|
-
const dx = me.clientX - this.dragState.startX;
|
|
73
|
-
const dy = me.clientY - this.dragState.startY;
|
|
74
|
-
let newLeft = this.dragState.initLeft + dx;
|
|
75
|
-
let newTop = this.dragState.initTop + dy;
|
|
76
|
-
// Clamp to viewport edges
|
|
77
|
-
const vw = window.innerWidth;
|
|
78
|
-
const vh = window.innerHeight;
|
|
79
|
-
const w = container.offsetWidth;
|
|
80
|
-
const h = container.offsetHeight;
|
|
81
|
-
newLeft = Math.max(0, Math.min(newLeft, vw - w));
|
|
82
|
-
newTop = Math.max(0, Math.min(newTop, vh - h));
|
|
83
|
-
container.style.left = `${newLeft}px`;
|
|
84
|
-
container.style.top = `${newTop}px`;
|
|
85
|
-
};
|
|
86
|
-
const onUp = () => {
|
|
87
|
-
this.dragState = null;
|
|
88
|
-
document.removeEventListener('pointermove', onMove);
|
|
89
|
-
document.removeEventListener('pointerup', onUp);
|
|
90
|
-
};
|
|
91
|
-
document.addEventListener('pointermove', onMove);
|
|
92
|
-
document.addEventListener('pointerup', onUp);
|
|
93
|
-
});
|
|
107
|
+
// Remove any existing listener before adding to prevent accumulation
|
|
108
|
+
this.el.removeEventListener('headerDragStart', this.dragListener);
|
|
109
|
+
this.el.addEventListener('headerDragStart', this.dragListener);
|
|
94
110
|
}
|
|
95
111
|
getContainerClasses() {
|
|
96
112
|
const classes = ['chat-container', this.position];
|
|
@@ -110,14 +126,24 @@ export class ChatContainer {
|
|
|
110
126
|
if (this.position === 'float') {
|
|
111
127
|
style.width = this.width;
|
|
112
128
|
style.height = this.floatHeight;
|
|
129
|
+
style.left = this.floatLeft;
|
|
130
|
+
style.top = this.floatTop;
|
|
113
131
|
}
|
|
114
132
|
else {
|
|
115
133
|
style.width = this.width;
|
|
116
134
|
}
|
|
117
135
|
return style;
|
|
118
136
|
}
|
|
137
|
+
isDark() {
|
|
138
|
+
if (this.theme === 'dark')
|
|
139
|
+
return true;
|
|
140
|
+
if (this.theme === 'auto' && typeof window !== 'undefined') {
|
|
141
|
+
return window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
142
|
+
}
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
119
145
|
render() {
|
|
120
|
-
return (h(Host, { key: '
|
|
146
|
+
return (h(Host, { key: 'dd656127f6974b6eef12f64c78c072f2c1f92a6a', class: { dark: this.isDark() } }, h("div", { key: '0eb43bc5c8b80e5576146f01998e5279eb860162', class: this.getContainerClasses(), style: this.getContainerStyle(), ref: el => (this.containerRef = el) }, this.showWatermark && (h("div", { key: '363046f0e73ab7aa0209d5f41562031fb34d6c2d', class: "watermark" }, h("ai-icon", { key: '1f3c26ba6a145f8532f6e1a40ea344249e8e5b43', name: "watermark", size: 133 }))), h("slot", { key: '3ec10548660ff721c094be36a15a152fdf6dac78', name: "header" }), h("div", { key: '9babb87041287ac400322b910aa64f7a7b1743a5', class: "messages-area", ref: el => (this.messagesAreaRef = el) }, h("slot", { key: '937c0c0bd675e5a619d46883e7c1f890754aae4b' })), h("slot", { key: '0982b8bc96537c6cecca757926d5849ba386bd69', name: "footer" }))));
|
|
121
147
|
}
|
|
122
148
|
static get is() { return "ai-chat-container"; }
|
|
123
149
|
static get encapsulation() { return "shadow"; }
|
|
@@ -252,17 +278,63 @@ export class ChatContainer {
|
|
|
252
278
|
"reflect": false,
|
|
253
279
|
"attribute": "float-height",
|
|
254
280
|
"defaultValue": "'600px'"
|
|
281
|
+
},
|
|
282
|
+
"theme": {
|
|
283
|
+
"type": "string",
|
|
284
|
+
"mutable": false,
|
|
285
|
+
"complexType": {
|
|
286
|
+
"original": "'light' | 'dark' | 'auto'",
|
|
287
|
+
"resolved": "\"auto\" | \"dark\" | \"light\"",
|
|
288
|
+
"references": {}
|
|
289
|
+
},
|
|
290
|
+
"required": false,
|
|
291
|
+
"optional": false,
|
|
292
|
+
"docs": {
|
|
293
|
+
"tags": [],
|
|
294
|
+
"text": "Color theme for the panel"
|
|
295
|
+
},
|
|
296
|
+
"getter": false,
|
|
297
|
+
"setter": false,
|
|
298
|
+
"reflect": false,
|
|
299
|
+
"attribute": "theme",
|
|
300
|
+
"defaultValue": "'light'"
|
|
255
301
|
}
|
|
256
302
|
};
|
|
257
303
|
}
|
|
258
304
|
static get states() {
|
|
259
305
|
return {
|
|
260
|
-
"isMobile": {}
|
|
306
|
+
"isMobile": {},
|
|
307
|
+
"floatLeft": {},
|
|
308
|
+
"floatTop": {}
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
static get methods() {
|
|
312
|
+
return {
|
|
313
|
+
"scrollToBottom": {
|
|
314
|
+
"complexType": {
|
|
315
|
+
"signature": "() => Promise<void>",
|
|
316
|
+
"parameters": [],
|
|
317
|
+
"references": {
|
|
318
|
+
"Promise": {
|
|
319
|
+
"location": "global",
|
|
320
|
+
"id": "global::Promise"
|
|
321
|
+
}
|
|
322
|
+
},
|
|
323
|
+
"return": "Promise<void>"
|
|
324
|
+
},
|
|
325
|
+
"docs": {
|
|
326
|
+
"text": "Programmatically scroll the messages area to the bottom",
|
|
327
|
+
"tags": []
|
|
328
|
+
}
|
|
329
|
+
}
|
|
261
330
|
};
|
|
262
331
|
}
|
|
263
332
|
static get elementRef() { return "el"; }
|
|
264
333
|
static get watchers() {
|
|
265
334
|
return [{
|
|
335
|
+
"propName": "isOpen",
|
|
336
|
+
"methodName": "isOpenChanged"
|
|
337
|
+
}, {
|
|
266
338
|
"propName": "position",
|
|
267
339
|
"methodName": "positionChanged"
|
|
268
340
|
}];
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
:host {
|
|
2
2
|
display: block;
|
|
3
|
-
font-family: var(--ai-font-family, "PingARLT", sans-serif);
|
|
4
3
|
}
|
|
5
4
|
|
|
6
5
|
/* ── Container ──────────────────────────────────────────────────── */
|
|
@@ -9,16 +8,12 @@
|
|
|
9
8
|
align-items: center;
|
|
10
9
|
gap: 8px;
|
|
11
10
|
padding: 16px;
|
|
12
|
-
background: var(--ai-bg-card
|
|
13
|
-
border-bottom: 1px solid var(--ai-border-light
|
|
11
|
+
background: var(--ai-bg-card);
|
|
12
|
+
border-bottom: 1px solid var(--ai-border-light);
|
|
14
13
|
width: 100%;
|
|
15
14
|
box-sizing: border-box;
|
|
16
15
|
}
|
|
17
16
|
|
|
18
|
-
.header-container {
|
|
19
|
-
direction: rtl;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
17
|
/* ── Action & Back Buttons ──────────────────────────────────────── */
|
|
23
18
|
.drag-btn {
|
|
24
19
|
cursor: grab;
|
|
@@ -37,7 +32,7 @@
|
|
|
37
32
|
display: flex;
|
|
38
33
|
align-items: center;
|
|
39
34
|
justify-content: center;
|
|
40
|
-
background: var(--ai-bg-card
|
|
35
|
+
background: var(--ai-bg-card);
|
|
41
36
|
border: none;
|
|
42
37
|
border-radius: 8px;
|
|
43
38
|
cursor: pointer;
|
|
@@ -48,7 +43,7 @@
|
|
|
48
43
|
|
|
49
44
|
.action-btn:hover,
|
|
50
45
|
.back-btn:hover {
|
|
51
|
-
background: var(--ai-bg-surface
|
|
46
|
+
background: var(--ai-bg-surface);
|
|
52
47
|
}
|
|
53
48
|
|
|
54
49
|
.action-btn:focus-visible,
|
|
@@ -59,7 +54,7 @@
|
|
|
59
54
|
|
|
60
55
|
.action-btn:active,
|
|
61
56
|
.back-btn:active {
|
|
62
|
-
background: var(--ai-bg-surface
|
|
57
|
+
background: var(--ai-bg-surface);
|
|
63
58
|
}
|
|
64
59
|
|
|
65
60
|
/* ── Actions Group ──────────────────────────────────────────────── */
|
|
@@ -110,7 +105,7 @@
|
|
|
110
105
|
.title {
|
|
111
106
|
font-size: 16px;
|
|
112
107
|
font-weight: 700;
|
|
113
|
-
color: var(--ai-text-primary
|
|
108
|
+
color: var(--ai-text-primary);
|
|
114
109
|
white-space: nowrap;
|
|
115
110
|
line-height: normal;
|
|
116
111
|
min-width: 0;
|
|
@@ -130,15 +125,30 @@
|
|
|
130
125
|
width: 40px;
|
|
131
126
|
height: 40px;
|
|
132
127
|
border-radius: 9999px;
|
|
133
|
-
border: 1px solid var(--ai-border-default
|
|
128
|
+
border: 1px solid var(--ai-border-default);
|
|
134
129
|
object-fit: cover;
|
|
135
130
|
display: block;
|
|
136
131
|
}
|
|
137
132
|
|
|
133
|
+
.avatar-fallback {
|
|
134
|
+
width: 40px;
|
|
135
|
+
height: 40px;
|
|
136
|
+
border-radius: 9999px;
|
|
137
|
+
border: 1px solid var(--ai-border-default);
|
|
138
|
+
background: var(--ai-bg-surface);
|
|
139
|
+
color: var(--ai-text-primary);
|
|
140
|
+
font-size: 16px;
|
|
141
|
+
font-weight: 600;
|
|
142
|
+
display: flex;
|
|
143
|
+
align-items: center;
|
|
144
|
+
justify-content: center;
|
|
145
|
+
flex-shrink: 0;
|
|
146
|
+
}
|
|
147
|
+
|
|
138
148
|
.online-dot {
|
|
139
149
|
position: absolute;
|
|
140
150
|
bottom: 0;
|
|
141
|
-
|
|
151
|
+
inset-inline-end: 0;
|
|
142
152
|
width: 10px;
|
|
143
153
|
height: 10px;
|
|
144
154
|
display: inline-flex;
|
|
@@ -147,20 +157,36 @@
|
|
|
147
157
|
color: var(--ai-bg-card); /* used as stroke to match card bg in both themes */
|
|
148
158
|
}
|
|
149
159
|
|
|
160
|
+
/* Status indicator color variants */
|
|
161
|
+
.online-dot.status-online {
|
|
162
|
+
color: #22c55e; /* green */
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.online-dot.status-offline {
|
|
166
|
+
color: #9ca3af; /* gray */
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.online-dot.status-busy {
|
|
170
|
+
color: #ef4444; /* red */
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.online-dot.status-away {
|
|
174
|
+
color: #f59e0b; /* amber */
|
|
175
|
+
}
|
|
176
|
+
|
|
150
177
|
/* ── Text Block (human mode) ────────────────────────────────────── */
|
|
151
178
|
.text-block {
|
|
152
179
|
display: flex;
|
|
153
180
|
flex-direction: column;
|
|
154
|
-
align-items: flex-
|
|
181
|
+
align-items: flex-start;
|
|
155
182
|
gap: 0;
|
|
156
183
|
flex-shrink: 0;
|
|
157
184
|
}
|
|
158
185
|
|
|
159
|
-
|
|
160
186
|
.agent-name {
|
|
161
187
|
font-size: 14px;
|
|
162
188
|
font-weight: 500;
|
|
163
|
-
color: var(--ai-text-primary
|
|
189
|
+
color: var(--ai-text-primary);
|
|
164
190
|
line-height: 20px;
|
|
165
191
|
white-space: nowrap;
|
|
166
192
|
}
|
|
@@ -168,7 +194,7 @@
|
|
|
168
194
|
.agent-status {
|
|
169
195
|
font-size: 14px;
|
|
170
196
|
font-weight: 400;
|
|
171
|
-
color: var(--ai-text-secondary
|
|
197
|
+
color: var(--ai-text-secondary);
|
|
172
198
|
line-height: 20px;
|
|
173
199
|
white-space: nowrap;
|
|
174
200
|
}
|
|
@@ -184,3 +210,10 @@
|
|
|
184
210
|
.icon-wrap svg {
|
|
185
211
|
display: block;
|
|
186
212
|
}
|
|
213
|
+
|
|
214
|
+
/* ── Directional icon flip (back-btn arrow points right in RTL = "back";
|
|
215
|
+
in LTR it must flip to point left) ──────────────────────────────────── */
|
|
216
|
+
:host-context([dir='ltr']) .back-btn .icon-wrap,
|
|
217
|
+
:host([dir='ltr']) .back-btn .icon-wrap {
|
|
218
|
+
transform: scaleX(-1);
|
|
219
|
+
}
|
|
@@ -14,14 +14,17 @@ export class AiChatHeader {
|
|
|
14
14
|
/** Human mode: show the back button */
|
|
15
15
|
showBack = true;
|
|
16
16
|
isDraggable = false;
|
|
17
|
+
/** Human mode: status indicator variant */
|
|
18
|
+
statusIndicator = 'online';
|
|
19
|
+
avatarError = false;
|
|
17
20
|
/** Cancel / close button */
|
|
18
21
|
closeClick;
|
|
19
22
|
/** Pencil-edit button (agent mode) */
|
|
20
23
|
editClick;
|
|
21
24
|
/** Title / chevron click → open conversation list (agent mode) */
|
|
22
25
|
dropdownClick;
|
|
23
|
-
/**
|
|
24
|
-
|
|
26
|
+
/** More options button */
|
|
27
|
+
positionClick;
|
|
25
28
|
/** Back-arrow button (human mode) */
|
|
26
29
|
backClick;
|
|
27
30
|
/**
|
|
@@ -36,28 +39,35 @@ export class AiChatHeader {
|
|
|
36
39
|
const svg = `<svg width="${width}" height="${height}" viewBox="${icon.viewBox}" fill="none" xmlns="http://www.w3.org/2000/svg">${icon.content}</svg>`;
|
|
37
40
|
return h("span", { class: "icon-wrap", innerHTML: svg });
|
|
38
41
|
}
|
|
42
|
+
renderAvatar() {
|
|
43
|
+
const fallbackLetter = this.agentName ? this.agentName.charAt(0) : '?';
|
|
44
|
+
if (!this.agentAvatar || this.avatarError) {
|
|
45
|
+
return h("div", { class: "avatar-fallback" }, fallbackLetter);
|
|
46
|
+
}
|
|
47
|
+
return (h("img", { class: "avatar", src: this.agentAvatar, alt: this.agentName, onError: () => { this.avatarError = true; } }));
|
|
48
|
+
}
|
|
49
|
+
renderDragBtn() {
|
|
50
|
+
return this.isDraggable && (h("button", { class: "action-btn drag-btn", "aria-label": "\u0633\u062D\u0628 / Drag", onPointerDown: (e) => {
|
|
51
|
+
e.preventDefault();
|
|
52
|
+
this.headerDragStart.emit({ clientX: e.clientX, clientY: e.clientY });
|
|
53
|
+
} }, this.renderIcon('drag', 11, 15)));
|
|
54
|
+
}
|
|
39
55
|
renderAgentMode() {
|
|
40
56
|
return [
|
|
41
|
-
this.
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
} }, this.renderIcon('drag', 11, 15))),
|
|
45
|
-
h("div", { class: "content agent" }, h("span", { class: "title" }, this.conversation), h("button", { class: "dropdown-trigger", onClick: () => this.dropdownClick.emit() }, this.renderIcon('chevron-down', 24, 24))),
|
|
46
|
-
h("div", { class: "actions" }, h("button", { class: "action-btn", onClick: () => this.editClick.emit() }, this.renderIcon('pencil-edit', 22, 22)), h("button", { class: "action-btn", onClick: () => this.moreClick.emit() }, this.renderIcon('hand', 22, 22)), h("button", { class: "action-btn", onClick: () => this.closeClick.emit() }, this.renderIcon('cancel', 22, 22))),
|
|
57
|
+
this.renderDragBtn(),
|
|
58
|
+
h("div", { class: "content agent dropdown-trigger", role: "button", onClick: () => this.dropdownClick.emit(), "aria-haspopup": "listbox", "aria-expanded": false, "aria-label": `${this.conversation}, افتح قائمة المحادثات` }, h("span", { class: "title" }, this.conversation), h("span", { class: "dropdown-chevron" }, this.renderIcon('chevron-down', 24, 24))),
|
|
59
|
+
h("div", { class: "actions" }, h("button", { class: "action-btn", "aria-label": "\u062A\u0639\u062F\u064A\u0644 / Edit", onClick: () => this.editClick.emit() }, this.renderIcon('pencil-edit', 22, 22)), h("button", { class: "action-btn", "aria-label": "\u0627\u0644\u0639\u0631\u0636 / Position", onClick: () => this.positionClick.emit() }, this.renderIcon('hand', 22, 22)), h("button", { class: "action-btn", "aria-label": "\u0625\u063A\u0644\u0627\u0642 / Close", onClick: () => this.closeClick.emit() }, this.renderIcon('cancel', 22, 22))),
|
|
47
60
|
];
|
|
48
61
|
}
|
|
49
62
|
renderHumanMode() {
|
|
50
63
|
return [
|
|
51
|
-
this.
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
} }, this.renderIcon('drag', 11, 15))),
|
|
55
|
-
h("div", { class: "content human" }, this.showBack && (h("button", { class: "back-btn", onClick: () => this.backClick.emit() }, this.renderIcon('arrow-right', 24, 24))), h("div", { class: "avatar-wrapper" }, h("img", { class: "avatar", src: this.agentAvatar, alt: this.agentName }), h("span", { class: "online-dot" }, this.renderIcon('online-dot', 10, 10))), h("div", { class: "text-block" }, h("span", { class: "agent-name" }, this.agentName), h("span", { class: "agent-status" }, this.agentStatus))),
|
|
56
|
-
h("div", { class: "actions" }, h("button", { class: "action-btn", onClick: () => this.moreClick.emit() }, this.renderIcon('hand', 22, 22)), h("button", { class: "action-btn", onClick: () => this.closeClick.emit() }, this.renderIcon('cancel', 22, 22))),
|
|
64
|
+
this.renderDragBtn(),
|
|
65
|
+
h("div", { class: "content human" }, this.showBack && (h("button", { class: "back-btn", "aria-label": "\u0631\u062C\u0648\u0639 / Back", onClick: () => this.backClick.emit() }, this.renderIcon('arrow-right', 24, 24))), h("div", { class: "avatar-wrapper" }, this.renderAvatar(), h("span", { class: `online-dot status-${this.statusIndicator}` }, this.renderIcon('online-dot', 10, 10))), h("div", { class: "text-block" }, h("span", { class: "agent-name" }, this.agentName), this.agentStatus && h("span", { class: "agent-status" }, this.agentStatus))),
|
|
66
|
+
h("div", { class: "actions" }, h("button", { class: "action-btn", "aria-label": "\u0627\u0644\u0639\u0631\u0636 / Position", onClick: () => this.positionClick.emit() }, this.renderIcon('hand', 22, 22)), h("button", { class: "action-btn", "aria-label": "\u0625\u063A\u0644\u0627\u0642 / Close", onClick: () => this.closeClick.emit() }, this.renderIcon('cancel', 22, 22))),
|
|
57
67
|
];
|
|
58
68
|
}
|
|
59
69
|
render() {
|
|
60
|
-
return (h(Host, { key: '
|
|
70
|
+
return (h(Host, { key: 'f96f4d5c533747b2843706c165866769b834fb98' }, h("div", { key: '8643a8cb214cbe40f0ee1a0b64c483829b5de6c9', class: "header-container" }, this.mode === 'agent' ? this.renderAgentMode() : this.renderHumanMode())));
|
|
61
71
|
}
|
|
62
72
|
static get is() { return "ai-chat-header"; }
|
|
63
73
|
static get encapsulation() { return "shadow"; }
|
|
@@ -212,9 +222,34 @@ export class AiChatHeader {
|
|
|
212
222
|
"reflect": false,
|
|
213
223
|
"attribute": "is-draggable",
|
|
214
224
|
"defaultValue": "false"
|
|
225
|
+
},
|
|
226
|
+
"statusIndicator": {
|
|
227
|
+
"type": "string",
|
|
228
|
+
"mutable": false,
|
|
229
|
+
"complexType": {
|
|
230
|
+
"original": "'online' | 'offline' | 'busy' | 'away'",
|
|
231
|
+
"resolved": "\"away\" | \"busy\" | \"offline\" | \"online\"",
|
|
232
|
+
"references": {}
|
|
233
|
+
},
|
|
234
|
+
"required": false,
|
|
235
|
+
"optional": false,
|
|
236
|
+
"docs": {
|
|
237
|
+
"tags": [],
|
|
238
|
+
"text": "Human mode: status indicator variant"
|
|
239
|
+
},
|
|
240
|
+
"getter": false,
|
|
241
|
+
"setter": false,
|
|
242
|
+
"reflect": false,
|
|
243
|
+
"attribute": "status-indicator",
|
|
244
|
+
"defaultValue": "'online'"
|
|
215
245
|
}
|
|
216
246
|
};
|
|
217
247
|
}
|
|
248
|
+
static get states() {
|
|
249
|
+
return {
|
|
250
|
+
"avatarError": {}
|
|
251
|
+
};
|
|
252
|
+
}
|
|
218
253
|
static get events() {
|
|
219
254
|
return [{
|
|
220
255
|
"method": "closeClick",
|
|
@@ -262,14 +297,14 @@ export class AiChatHeader {
|
|
|
262
297
|
"references": {}
|
|
263
298
|
}
|
|
264
299
|
}, {
|
|
265
|
-
"method": "
|
|
266
|
-
"name": "
|
|
300
|
+
"method": "positionClick",
|
|
301
|
+
"name": "positionClick",
|
|
267
302
|
"bubbles": true,
|
|
268
303
|
"cancelable": true,
|
|
269
304
|
"composed": true,
|
|
270
305
|
"docs": {
|
|
271
306
|
"tags": [],
|
|
272
|
-
"text": "
|
|
307
|
+
"text": "More options button"
|
|
273
308
|
},
|
|
274
309
|
"complexType": {
|
|
275
310
|
"original": "void",
|