@salla.sa/ui-ai-kit-core 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/cjs/ai-card.cjs.entry.js +25 -0
- package/dist/cjs/ai-chat-container.cjs.entry.js +138 -0
- package/dist/cjs/ai-chat-header.cjs.entry.js +79 -0
- package/dist/cjs/ai-chat-message.cjs.entry.js +164 -0
- package/dist/cjs/ai-icon.cjs.entry.js +25 -0
- package/dist/cjs/ai-link.cjs.entry.js +34 -0
- package/dist/cjs/ai-loading.cjs.entry.js +77 -0
- package/dist/cjs/ai-message-input.cjs.entry.js +65 -0
- package/dist/cjs/ai-rating.cjs.entry.js +57 -0
- package/dist/cjs/ai-suggestion.cjs.entry.js +31 -0
- package/dist/cjs/ai-voice-input.cjs.entry.js +233 -0
- package/dist/cjs/icon-registry-dmfLA-Dj.js +82 -0
- package/dist/cjs/index-DLJcLHFH.js +1622 -0
- package/dist/cjs/index.cjs.js +7 -0
- package/dist/cjs/loader.cjs.js +12 -0
- package/dist/cjs/ui-ai-kit.cjs.js +24 -0
- package/dist/collection/collection-manifest.json +23 -0
- package/dist/collection/components/ai-card/ai-card.css +40 -0
- package/dist/collection/components/ai-card/ai-card.js +70 -0
- package/dist/collection/components/ai-card/ai-card.stories.js +52 -0
- package/dist/collection/components/ai-chat-container/ai-chat-container.css +137 -0
- package/dist/collection/components/ai-chat-container/ai-chat-container.js +270 -0
- package/dist/collection/components/ai-chat-container/ai-chat-container.stories.js +160 -0
- package/dist/collection/components/ai-chat-header/ai-chat-header.css +186 -0
- package/dist/collection/components/ai-chat-header/ai-chat-header.js +311 -0
- package/dist/collection/components/ai-chat-header/ai-chat-header.stories.js +138 -0
- package/dist/collection/components/ai-chat-message/ai-chat-message.css +304 -0
- package/dist/collection/components/ai-chat-message/ai-chat-message.js +379 -0
- package/dist/collection/components/ai-chat-message/ai-chat-message.stories.js +164 -0
- package/dist/collection/components/ai-icon/ai-icon.css +9 -0
- package/dist/collection/components/ai-icon/ai-icon.js +76 -0
- package/dist/collection/components/ai-link/ai-link.css +62 -0
- package/dist/collection/components/ai-link/ai-link.js +119 -0
- package/dist/collection/components/ai-link/ai-link.stories.js +79 -0
- package/dist/collection/components/ai-loading/ai-loading.css +202 -0
- package/dist/collection/components/ai-loading/ai-loading.js +244 -0
- package/dist/collection/components/ai-loading/ai-loading.stories.js +145 -0
- package/dist/collection/components/ai-message-input/ai-message-input.css +175 -0
- package/dist/collection/components/ai-message-input/ai-message-input.js +192 -0
- package/dist/collection/components/ai-message-input/ai-message-input.stories.js +125 -0
- package/dist/collection/components/ai-rating/ai-rating.css +145 -0
- package/dist/collection/components/ai-rating/ai-rating.js +176 -0
- package/dist/collection/components/ai-rating/ai-rating.stories.js +78 -0
- package/dist/collection/components/ai-suggestion/ai-suggestion.css +69 -0
- package/dist/collection/components/ai-suggestion/ai-suggestion.js +93 -0
- package/dist/collection/components/ai-suggestion/ai-suggestion.stories.js +62 -0
- package/dist/collection/components/ai-voice-input/ai-voice-input.css +136 -0
- package/dist/collection/components/ai-voice-input/ai-voice-input.js +341 -0
- package/dist/collection/components/ai-voice-input/ai-voice-input.stories.js +118 -0
- package/dist/collection/index.js +10 -0
- package/dist/collection/utils/icon-registry.js +78 -0
- package/dist/collection/utils/utils.js +3 -0
- package/dist/components/ai-card.d.ts +11 -0
- package/dist/components/ai-card.js +1 -0
- package/dist/components/ai-chat-container.d.ts +11 -0
- package/dist/components/ai-chat-container.js +1 -0
- package/dist/components/ai-chat-header.d.ts +11 -0
- package/dist/components/ai-chat-header.js +1 -0
- package/dist/components/ai-chat-message.d.ts +11 -0
- package/dist/components/ai-chat-message.js +1 -0
- package/dist/components/ai-icon.d.ts +11 -0
- package/dist/components/ai-icon.js +1 -0
- package/dist/components/ai-link.d.ts +11 -0
- package/dist/components/ai-link.js +1 -0
- package/dist/components/ai-loading.d.ts +11 -0
- package/dist/components/ai-loading.js +1 -0
- package/dist/components/ai-message-input.d.ts +11 -0
- package/dist/components/ai-message-input.js +1 -0
- package/dist/components/ai-rating.d.ts +11 -0
- package/dist/components/ai-rating.js +1 -0
- package/dist/components/ai-suggestion.d.ts +11 -0
- package/dist/components/ai-suggestion.js +1 -0
- package/dist/components/ai-voice-input.d.ts +11 -0
- package/dist/components/ai-voice-input.js +1 -0
- package/dist/components/index.d.ts +35 -0
- package/dist/components/index.js +1 -0
- package/dist/components/p-CWjXxYJI.js +1 -0
- package/dist/components/p-CY6emva2.js +1 -0
- package/dist/components/p-DYv5ef4M.js +1 -0
- package/dist/esm/ai-card.entry.js +23 -0
- package/dist/esm/ai-chat-container.entry.js +136 -0
- package/dist/esm/ai-chat-header.entry.js +77 -0
- package/dist/esm/ai-chat-message.entry.js +162 -0
- package/dist/esm/ai-icon.entry.js +23 -0
- package/dist/esm/ai-link.entry.js +32 -0
- package/dist/esm/ai-loading.entry.js +75 -0
- package/dist/esm/ai-message-input.entry.js +63 -0
- package/dist/esm/ai-rating.entry.js +55 -0
- package/dist/esm/ai-suggestion.entry.js +29 -0
- package/dist/esm/ai-voice-input.entry.js +231 -0
- package/dist/esm/icon-registry-DYv5ef4M.js +80 -0
- package/dist/esm/index-7hrZ8FOQ.js +1612 -0
- package/dist/esm/index.js +5 -0
- package/dist/esm/loader.js +10 -0
- package/dist/esm/ui-ai-kit.js +20 -0
- package/dist/index.cjs.js +1 -0
- package/dist/index.js +1 -0
- package/dist/types/components/ai-card/ai-card.d.ts +7 -0
- package/dist/types/components/ai-card/ai-card.stories.d.ts +7 -0
- package/dist/types/components/ai-chat-container/ai-chat-container.d.ts +28 -0
- package/dist/types/components/ai-chat-container/ai-chat-container.stories.d.ts +7 -0
- package/dist/types/components/ai-chat-header/ai-chat-header.d.ts +38 -0
- package/dist/types/components/ai-chat-header/ai-chat-header.stories.d.ts +8 -0
- package/dist/types/components/ai-chat-message/ai-chat-message.d.ts +27 -0
- package/dist/types/components/ai-chat-message/ai-chat-message.stories.d.ts +10 -0
- package/dist/types/components/ai-icon/ai-icon.d.ts +8 -0
- package/dist/types/components/ai-link/ai-link.d.ts +12 -0
- package/dist/types/components/ai-link/ai-link.stories.d.ts +8 -0
- package/dist/types/components/ai-loading/ai-loading.d.ts +33 -0
- package/dist/types/components/ai-loading/ai-loading.stories.d.ts +10 -0
- package/dist/types/components/ai-message-input/ai-message-input.d.ts +22 -0
- package/dist/types/components/ai-message-input/ai-message-input.stories.d.ts +13 -0
- package/dist/types/components/ai-rating/ai-rating.d.ts +17 -0
- package/dist/types/components/ai-rating/ai-rating.stories.d.ts +8 -0
- package/dist/types/components/ai-suggestion/ai-suggestion.d.ts +10 -0
- package/dist/types/components/ai-suggestion/ai-suggestion.stories.d.ts +8 -0
- package/dist/types/components/ai-voice-input/ai-voice-input.d.ts +43 -0
- package/dist/types/components/ai-voice-input/ai-voice-input.stories.d.ts +9 -0
- package/dist/types/components.d.ts +860 -0
- package/dist/types/index.d.ts +11 -0
- package/dist/types/stencil-public-runtime.d.ts +1860 -0
- package/dist/types/utils/icon-registry.d.ts +5 -0
- package/dist/types/utils/utils.d.ts +1 -0
- package/dist/ui-ai-kit/index.esm.js +1 -0
- package/dist/ui-ai-kit/p-11facfad.entry.js +1 -0
- package/dist/ui-ai-kit/p-128a2ed4.entry.js +1 -0
- package/dist/ui-ai-kit/p-227bdb8f.entry.js +1 -0
- package/dist/ui-ai-kit/p-455daa17.entry.js +1 -0
- package/dist/ui-ai-kit/p-56163e8c.entry.js +1 -0
- package/dist/ui-ai-kit/p-6d21d0fd.entry.js +1 -0
- package/dist/ui-ai-kit/p-6ddcd77b.entry.js +1 -0
- package/dist/ui-ai-kit/p-7hrZ8FOQ.js +2 -0
- package/dist/ui-ai-kit/p-8e90143e.entry.js +1 -0
- package/dist/ui-ai-kit/p-9938c277.entry.js +1 -0
- package/dist/ui-ai-kit/p-DYv5ef4M.js +1 -0
- package/dist/ui-ai-kit/p-dc5b4a7f.entry.js +1 -0
- package/dist/ui-ai-kit/p-fb1702de.entry.js +1 -0
- package/dist/ui-ai-kit/ui-ai-kit.css +1 -0
- package/dist/ui-ai-kit/ui-ai-kit.esm.js +1 -0
- package/loader/cdn.js +1 -0
- package/loader/index.cjs.js +1 -0
- package/loader/index.d.ts +24 -0
- package/loader/index.es2017.js +1 -0
- package/loader/index.js +2 -0
- package/package.json +77 -0
- package/readme.md +111 -0
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { Host, h } from "@stencil/core";
|
|
2
|
+
export class MessageInput {
|
|
3
|
+
el;
|
|
4
|
+
/** Placeholder text for the textarea */
|
|
5
|
+
placeholder = 'ايش في بالك؟';
|
|
6
|
+
/** Whether the input is disabled */
|
|
7
|
+
disabled = false;
|
|
8
|
+
/** Whether to show the voice recording button */
|
|
9
|
+
showVoiceButton = true;
|
|
10
|
+
inputValue = '';
|
|
11
|
+
textareaRef;
|
|
12
|
+
/** Event emitted when a message is sent */
|
|
13
|
+
sendMessage;
|
|
14
|
+
/** Event emitted when the voice button is clicked — caller controls rendering the voice recorder */
|
|
15
|
+
voiceButtonClick;
|
|
16
|
+
/** Set the textarea value programmatically (e.g. after speech-to-text transcription) */
|
|
17
|
+
async setInputValue(value) {
|
|
18
|
+
this.inputValue = value;
|
|
19
|
+
if (this.textareaRef) {
|
|
20
|
+
this.textareaRef.style.height = 'auto';
|
|
21
|
+
this.textareaRef.style.height = `${this.textareaRef.scrollHeight}px`;
|
|
22
|
+
this.textareaRef.focus();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
handleSendMessage = () => {
|
|
26
|
+
if (!this.inputValue.trim() || this.disabled)
|
|
27
|
+
return;
|
|
28
|
+
this.sendMessage.emit(this.inputValue.trim());
|
|
29
|
+
this.inputValue = '';
|
|
30
|
+
if (this.textareaRef) {
|
|
31
|
+
this.textareaRef.style.height = 'auto';
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
handleKeyPress = (e) => {
|
|
35
|
+
if (e.key === 'Enter' && !e.shiftKey) {
|
|
36
|
+
e.preventDefault();
|
|
37
|
+
this.handleSendMessage();
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
handleInputChange = (e) => {
|
|
41
|
+
const target = e.target;
|
|
42
|
+
this.inputValue = target.value;
|
|
43
|
+
if (this.textareaRef) {
|
|
44
|
+
this.textareaRef.style.height = 'auto';
|
|
45
|
+
this.textareaRef.style.height = `${this.textareaRef.scrollHeight}px`;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
render() {
|
|
49
|
+
const canSend = !!this.inputValue.trim() && !this.disabled;
|
|
50
|
+
return (h(Host, { key: '97dfe627b89657d36e4f7281a8bdb708cc913374' }, h("div", { key: 'a3efb2a0b95ec3a86cc5f575d0fdb2bb6dd2eb6c', part: "wrapper", class: "wrapper" }, h("div", { key: '5986fa2946a44757c143999a72b25ea3b6e7c336', part: "glow", class: "glow", "aria-hidden": "true" }), h("div", { key: 'd5b9d346495de00e8b0e0900ef3e766756844626', part: "container", class: "input-container" }, h("div", { key: '8313695b2e4d7557a5362e9b9d2a5c5803a4ec0c', class: "input-row" }, h("div", { key: '9c184f8097e28527b5d18fccf92010fb36b14a9c', class: "actions" }, h("button", { key: '39ad3feb24a53fd5a08e8a8388f7bcee71413a91', part: "send-button", class: `send-button${canSend ? ' active' : ''}`, onClick: this.handleSendMessage, disabled: !canSend, type: "button", "aria-label": "Send message" }, h("ai-icon", { key: '1fe555709288d33551696312fb3329b1c656d063', name: "send", size: 16 })), this.showVoiceButton && !this.inputValue && (h("button", { key: 'a7bcc3b9ca5f5e59c32a34ab33c2fbbd607bb298', part: "voice-button", class: "voice-button", onClick: () => this.voiceButtonClick.emit(), disabled: this.disabled, type: "button", "aria-label": "Record voice" }, h("ai-icon", { key: '98fea04c79e841e4a2b8ee50a480bb554212b055', name: "mic", size: 16 })))), h("textarea", { key: '798af74ca2298a31f37459dfa1c176182d740839', part: "textarea", ref: el => (this.textareaRef = el), value: this.inputValue, onInput: this.handleInputChange, onKeyPress: this.handleKeyPress, disabled: this.disabled, placeholder: this.placeholder, rows: 1, class: "textarea" }))))));
|
|
51
|
+
}
|
|
52
|
+
static get is() { return "ai-message-input"; }
|
|
53
|
+
static get encapsulation() { return "shadow"; }
|
|
54
|
+
static get originalStyleUrls() {
|
|
55
|
+
return {
|
|
56
|
+
"$": ["ai-message-input.css"]
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
static get styleUrls() {
|
|
60
|
+
return {
|
|
61
|
+
"$": ["ai-message-input.css"]
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
static get properties() {
|
|
65
|
+
return {
|
|
66
|
+
"placeholder": {
|
|
67
|
+
"type": "string",
|
|
68
|
+
"mutable": false,
|
|
69
|
+
"complexType": {
|
|
70
|
+
"original": "string",
|
|
71
|
+
"resolved": "string",
|
|
72
|
+
"references": {}
|
|
73
|
+
},
|
|
74
|
+
"required": false,
|
|
75
|
+
"optional": false,
|
|
76
|
+
"docs": {
|
|
77
|
+
"tags": [],
|
|
78
|
+
"text": "Placeholder text for the textarea"
|
|
79
|
+
},
|
|
80
|
+
"getter": false,
|
|
81
|
+
"setter": false,
|
|
82
|
+
"reflect": false,
|
|
83
|
+
"attribute": "placeholder",
|
|
84
|
+
"defaultValue": "'\u0627\u064A\u0634 \u0641\u064A \u0628\u0627\u0644\u0643\u061F'"
|
|
85
|
+
},
|
|
86
|
+
"disabled": {
|
|
87
|
+
"type": "boolean",
|
|
88
|
+
"mutable": false,
|
|
89
|
+
"complexType": {
|
|
90
|
+
"original": "boolean",
|
|
91
|
+
"resolved": "boolean",
|
|
92
|
+
"references": {}
|
|
93
|
+
},
|
|
94
|
+
"required": false,
|
|
95
|
+
"optional": false,
|
|
96
|
+
"docs": {
|
|
97
|
+
"tags": [],
|
|
98
|
+
"text": "Whether the input is disabled"
|
|
99
|
+
},
|
|
100
|
+
"getter": false,
|
|
101
|
+
"setter": false,
|
|
102
|
+
"reflect": false,
|
|
103
|
+
"attribute": "disabled",
|
|
104
|
+
"defaultValue": "false"
|
|
105
|
+
},
|
|
106
|
+
"showVoiceButton": {
|
|
107
|
+
"type": "boolean",
|
|
108
|
+
"mutable": false,
|
|
109
|
+
"complexType": {
|
|
110
|
+
"original": "boolean",
|
|
111
|
+
"resolved": "boolean",
|
|
112
|
+
"references": {}
|
|
113
|
+
},
|
|
114
|
+
"required": false,
|
|
115
|
+
"optional": false,
|
|
116
|
+
"docs": {
|
|
117
|
+
"tags": [],
|
|
118
|
+
"text": "Whether to show the voice recording button"
|
|
119
|
+
},
|
|
120
|
+
"getter": false,
|
|
121
|
+
"setter": false,
|
|
122
|
+
"reflect": false,
|
|
123
|
+
"attribute": "show-voice-button",
|
|
124
|
+
"defaultValue": "true"
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
static get states() {
|
|
129
|
+
return {
|
|
130
|
+
"inputValue": {}
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
static get events() {
|
|
134
|
+
return [{
|
|
135
|
+
"method": "sendMessage",
|
|
136
|
+
"name": "sendMessage",
|
|
137
|
+
"bubbles": true,
|
|
138
|
+
"cancelable": true,
|
|
139
|
+
"composed": true,
|
|
140
|
+
"docs": {
|
|
141
|
+
"tags": [],
|
|
142
|
+
"text": "Event emitted when a message is sent"
|
|
143
|
+
},
|
|
144
|
+
"complexType": {
|
|
145
|
+
"original": "string",
|
|
146
|
+
"resolved": "string",
|
|
147
|
+
"references": {}
|
|
148
|
+
}
|
|
149
|
+
}, {
|
|
150
|
+
"method": "voiceButtonClick",
|
|
151
|
+
"name": "voiceButtonClick",
|
|
152
|
+
"bubbles": true,
|
|
153
|
+
"cancelable": true,
|
|
154
|
+
"composed": true,
|
|
155
|
+
"docs": {
|
|
156
|
+
"tags": [],
|
|
157
|
+
"text": "Event emitted when the voice button is clicked \u2014 caller controls rendering the voice recorder"
|
|
158
|
+
},
|
|
159
|
+
"complexType": {
|
|
160
|
+
"original": "void",
|
|
161
|
+
"resolved": "void",
|
|
162
|
+
"references": {}
|
|
163
|
+
}
|
|
164
|
+
}];
|
|
165
|
+
}
|
|
166
|
+
static get methods() {
|
|
167
|
+
return {
|
|
168
|
+
"setInputValue": {
|
|
169
|
+
"complexType": {
|
|
170
|
+
"signature": "(value: string) => Promise<void>",
|
|
171
|
+
"parameters": [{
|
|
172
|
+
"name": "value",
|
|
173
|
+
"type": "string",
|
|
174
|
+
"docs": ""
|
|
175
|
+
}],
|
|
176
|
+
"references": {
|
|
177
|
+
"Promise": {
|
|
178
|
+
"location": "global",
|
|
179
|
+
"id": "global::Promise"
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
"return": "Promise<void>"
|
|
183
|
+
},
|
|
184
|
+
"docs": {
|
|
185
|
+
"text": "Set the textarea value programmatically (e.g. after speech-to-text transcription)",
|
|
186
|
+
"tags": []
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
static get elementRef() { return "el"; }
|
|
192
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { html } from "lit";
|
|
2
|
+
const meta = {
|
|
3
|
+
title: 'Chat/Message Input',
|
|
4
|
+
component: 'ai-message-input',
|
|
5
|
+
tags: ['autodocs'],
|
|
6
|
+
argTypes: {
|
|
7
|
+
placeholder: {
|
|
8
|
+
control: 'text',
|
|
9
|
+
description: 'Placeholder text for the textarea',
|
|
10
|
+
},
|
|
11
|
+
disabled: {
|
|
12
|
+
control: 'boolean',
|
|
13
|
+
description: 'Whether the input is disabled',
|
|
14
|
+
},
|
|
15
|
+
showVoiceButton: {
|
|
16
|
+
control: 'boolean',
|
|
17
|
+
description: 'Show the mic button — emits voiceButtonClick when pressed so the caller can render ai-voice-input',
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
parameters: {
|
|
21
|
+
docs: {
|
|
22
|
+
description: {
|
|
23
|
+
component: `
|
|
24
|
+
A pill-shaped chat input component.
|
|
25
|
+
|
|
26
|
+
## Events
|
|
27
|
+
- \`sendMessage\` — emitted with the trimmed message string when the user sends
|
|
28
|
+
- \`voiceButtonClick\` — emitted when the mic button is pressed; the caller is responsible for showing \`ai-voice-input\`
|
|
29
|
+
|
|
30
|
+
## Methods
|
|
31
|
+
- \`setInputValue(text: string)\` — populates the textarea programmatically (e.g. after speech-to-text transcription)
|
|
32
|
+
`,
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
export default meta;
|
|
38
|
+
export const Default = {
|
|
39
|
+
render: args => html `
|
|
40
|
+
<ai-message-input
|
|
41
|
+
placeholder=${args.placeholder || 'ايش في بالك؟'}
|
|
42
|
+
?disabled=${args.disabled}
|
|
43
|
+
?show-voice-button=${args.showVoiceButton !== false}
|
|
44
|
+
@sendMessage=${(e) => console.log('sendMessage:', e.detail)}
|
|
45
|
+
@voiceButtonClick=${() => console.log('voiceButtonClick')}
|
|
46
|
+
></ai-message-input>
|
|
47
|
+
`,
|
|
48
|
+
args: {
|
|
49
|
+
placeholder: 'ايش في بالك؟',
|
|
50
|
+
disabled: false,
|
|
51
|
+
showVoiceButton: true,
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
export const Disabled = {
|
|
55
|
+
render: () => html `<ai-message-input placeholder="ايش في بالك؟" disabled></ai-message-input>`,
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Demonstrates the full voice toggle pattern:
|
|
59
|
+
* clicking the mic button hides the message input and shows ai-voice-input.
|
|
60
|
+
* After recording (or cancel) the voice input is hidden and message input is restored.
|
|
61
|
+
* When audio is recorded, setInputValue() pre-fills the textarea for review.
|
|
62
|
+
*/
|
|
63
|
+
export const WithVoiceToggle = {
|
|
64
|
+
render: () => html `
|
|
65
|
+
<div id="voice-toggle-demo" style="max-width: 600px;">
|
|
66
|
+
<ai-message-input
|
|
67
|
+
id="msg-input"
|
|
68
|
+
placeholder="اكتب رسالة أو اضغط على الميكروفون"
|
|
69
|
+
@sendMessage=${(e) => {
|
|
70
|
+
const log = document.getElementById('toggle-log');
|
|
71
|
+
if (log)
|
|
72
|
+
log.innerHTML += `<div style="color:#10b981;">✓ Message sent: "${e.detail}"</div>`;
|
|
73
|
+
}}
|
|
74
|
+
@voiceButtonClick=${() => {
|
|
75
|
+
const msg = document.getElementById('msg-input');
|
|
76
|
+
const voice = document.getElementById('voice-recorder');
|
|
77
|
+
if (msg)
|
|
78
|
+
msg.style.display = 'none';
|
|
79
|
+
if (voice) {
|
|
80
|
+
voice.style.display = 'block';
|
|
81
|
+
voice.autoStart = true;
|
|
82
|
+
}
|
|
83
|
+
}}
|
|
84
|
+
></ai-message-input>
|
|
85
|
+
|
|
86
|
+
<ai-voice-input
|
|
87
|
+
id="voice-recorder"
|
|
88
|
+
auto-start
|
|
89
|
+
style="display:none;"
|
|
90
|
+
@audioRecorded=${(e) => {
|
|
91
|
+
const msg = document.getElementById('msg-input');
|
|
92
|
+
const voice = document.getElementById('voice-recorder');
|
|
93
|
+
if (voice)
|
|
94
|
+
voice.style.display = 'none';
|
|
95
|
+
if (msg) {
|
|
96
|
+
msg.style.display = 'block';
|
|
97
|
+
// In a real app: send e.detail.blob to Whisper, then call setInputValue()
|
|
98
|
+
msg.setInputValue(`[Audio ${e.detail.duration}s — paste transcription here]`);
|
|
99
|
+
}
|
|
100
|
+
const log = document.getElementById('toggle-log');
|
|
101
|
+
if (log)
|
|
102
|
+
log.innerHTML += `<div style="color:#8b5cf6;">🎤 Audio recorded (${e.detail.duration}s, ${(e.detail.blob.size / 1024).toFixed(1)} KB)</div>`;
|
|
103
|
+
}}
|
|
104
|
+
@recordingCancel=${() => {
|
|
105
|
+
const msg = document.getElementById('msg-input');
|
|
106
|
+
const voice = document.getElementById('voice-recorder');
|
|
107
|
+
if (voice)
|
|
108
|
+
voice.style.display = 'none';
|
|
109
|
+
if (msg)
|
|
110
|
+
msg.style.display = 'block';
|
|
111
|
+
const log = document.getElementById('toggle-log');
|
|
112
|
+
if (log)
|
|
113
|
+
log.innerHTML += `<div style="color:#737373;">✕ Recording cancelled</div>`;
|
|
114
|
+
}}
|
|
115
|
+
></ai-voice-input>
|
|
116
|
+
|
|
117
|
+
<div
|
|
118
|
+
id="toggle-log"
|
|
119
|
+
style="margin-top:1rem;padding:1rem;background:#f5f5f5;border-radius:8px;font-family:monospace;font-size:13px;min-height:80px;max-height:200px;overflow-y:auto;"
|
|
120
|
+
>
|
|
121
|
+
<div style="color:#666;font-weight:bold;margin-bottom:4px;">Event log:</div>
|
|
122
|
+
</div>
|
|
123
|
+
</div>
|
|
124
|
+
`,
|
|
125
|
+
};
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/* ─── Custom Properties ──────────────────────────────────────────────────── */
|
|
2
|
+
:host {
|
|
3
|
+
--ai-rating-question-color: var(--ai-text-primary, #333333);
|
|
4
|
+
--ai-rating-subtitle-color: var(--ai-text-secondary, #737373);
|
|
5
|
+
--ai-rating-question-size: 16px;
|
|
6
|
+
--ai-rating-subtitle-size: 14px;
|
|
7
|
+
--ai-rating-gap: 8px;
|
|
8
|
+
--ai-rating-emoji-size: 24px;
|
|
9
|
+
--ai-rating-btn-padding: 6px;
|
|
10
|
+
--ai-rating-btn-border: 1px solid var(--ai-border-light, #f4f4f4);
|
|
11
|
+
--ai-rating-btn-radius: 9999px;
|
|
12
|
+
|
|
13
|
+
/* hover */
|
|
14
|
+
--ai-rating-btn-bg-hover: var(--ai-bg-surface, #f9fafb);
|
|
15
|
+
--ai-rating-btn-border-hover: 1px solid var(--ai-border-default);
|
|
16
|
+
|
|
17
|
+
/* selected — matches Figma warning palette */
|
|
18
|
+
--ai-rating-btn-bg-active: var(--ai-warning-bg, #fff9eb);
|
|
19
|
+
--ai-rating-btn-border-active: 1px solid var(--ai-warning-border, #ffaf44);
|
|
20
|
+
--ai-rating-btn-shadow-active: 0px 4px 6px -1px rgba(18, 18, 23, 0.08),
|
|
21
|
+
0px 2px 4px -1px rgba(18, 18, 23, 0.06);
|
|
22
|
+
|
|
23
|
+
/* selected label */
|
|
24
|
+
--ai-rating-label-color: var(--ai-text-primary, #333333);
|
|
25
|
+
--ai-rating-label-size: 16px;
|
|
26
|
+
|
|
27
|
+
display: block;
|
|
28
|
+
direction: rtl;
|
|
29
|
+
font-family: var(--ai-font-family, "PingARLT", sans-serif);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/* ─── Wrapper ────────────────────────────────────────────────────────────── */
|
|
33
|
+
.rating {
|
|
34
|
+
display: flex;
|
|
35
|
+
flex-direction: column;
|
|
36
|
+
align-items: center;
|
|
37
|
+
gap: var(--ai-rating-gap);
|
|
38
|
+
width: 100%;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/* ─── Text block ─────────────────────────────────────────────────────────── */
|
|
42
|
+
.rating__text {
|
|
43
|
+
display: flex;
|
|
44
|
+
flex-direction: column;
|
|
45
|
+
align-items: center;
|
|
46
|
+
gap: 2px;
|
|
47
|
+
width: 100%;
|
|
48
|
+
text-align: center;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.rating__question {
|
|
52
|
+
margin: 0;
|
|
53
|
+
font-size: var(--ai-rating-question-size);
|
|
54
|
+
font-weight: 500;
|
|
55
|
+
line-height: 24px;
|
|
56
|
+
color: var(--ai-rating-question-color);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.rating__subtitle {
|
|
60
|
+
margin: 0;
|
|
61
|
+
font-size: var(--ai-rating-subtitle-size);
|
|
62
|
+
font-weight: 400;
|
|
63
|
+
line-height: 20px;
|
|
64
|
+
color: var(--ai-rating-subtitle-color);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* ─── Emoji row ──────────────────────────────────────────────────────────── */
|
|
68
|
+
.rating__icons {
|
|
69
|
+
display: flex;
|
|
70
|
+
align-items: center;
|
|
71
|
+
justify-content: center;
|
|
72
|
+
gap: 10px;
|
|
73
|
+
width: 100%;
|
|
74
|
+
flex-wrap: wrap;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/* ─── Emoji button ───────────────────────────────────────────────────────── */
|
|
78
|
+
.emoji-btn {
|
|
79
|
+
display: inline-flex;
|
|
80
|
+
align-items: center;
|
|
81
|
+
justify-content: center;
|
|
82
|
+
padding: var(--ai-rating-btn-padding);
|
|
83
|
+
border: var(--ai-rating-btn-border);
|
|
84
|
+
border-radius: var(--ai-rating-btn-radius);
|
|
85
|
+
background: transparent;
|
|
86
|
+
cursor: pointer;
|
|
87
|
+
transition: background 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease;
|
|
88
|
+
outline: none;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.emoji-btn:focus-visible {
|
|
92
|
+
outline: 2px solid var(--ai-warning-border);
|
|
93
|
+
outline-offset: 2px;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.emoji-btn:hover:not(:disabled),
|
|
97
|
+
.emoji-btn--hovered {
|
|
98
|
+
background: var(--ai-rating-btn-bg-hover);
|
|
99
|
+
border: var(--ai-rating-btn-border-hover);
|
|
100
|
+
transform: scale(1.1);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/* ─── Selected state ─────────────────────────────────────────────────────── */
|
|
104
|
+
.emoji-btn--active {
|
|
105
|
+
background: var(--ai-rating-btn-bg-active) !important;
|
|
106
|
+
border: var(--ai-rating-btn-border-active) !important;
|
|
107
|
+
box-shadow: var(--ai-rating-btn-shadow-active);
|
|
108
|
+
transform: scale(1.18) !important;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/* ─── Disabled ───────────────────────────────────────────────────────────── */
|
|
112
|
+
.emoji-btn--disabled {
|
|
113
|
+
opacity: 0.45;
|
|
114
|
+
cursor: not-allowed;
|
|
115
|
+
pointer-events: none;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/* ─── Emoji icon ─────────────────────────────────────────────────────────── */
|
|
119
|
+
.emoji-btn__icon {
|
|
120
|
+
font-size: var(--ai-rating-emoji-size);
|
|
121
|
+
line-height: 1;
|
|
122
|
+
display: inline-flex;
|
|
123
|
+
align-items: center;
|
|
124
|
+
justify-content: center;
|
|
125
|
+
width: var(--ai-rating-emoji-size);
|
|
126
|
+
height: var(--ai-rating-emoji-size);
|
|
127
|
+
pointer-events: none;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/* ─── Selected label ─────────────────────────────────────────────────────── */
|
|
131
|
+
.rating__selected-label {
|
|
132
|
+
margin: 0;
|
|
133
|
+
font-size: var(--ai-rating-label-size);
|
|
134
|
+
font-weight: 500;
|
|
135
|
+
line-height: 24px;
|
|
136
|
+
color: var(--ai-rating-label-color);
|
|
137
|
+
text-align: center;
|
|
138
|
+
width: 100%;
|
|
139
|
+
animation: fadeIn 0.15s ease;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
@keyframes fadeIn {
|
|
143
|
+
from { opacity: 0; transform: translateY(4px); }
|
|
144
|
+
to { opacity: 1; transform: translateY(0); }
|
|
145
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { Host, h } from "@stencil/core";
|
|
2
|
+
const EMOJI_OPTIONS = [
|
|
3
|
+
{ value: 1, emoji: '😠', label: 'سيئ جداً' },
|
|
4
|
+
{ value: 2, emoji: '☹️', label: 'سيئ' },
|
|
5
|
+
{ value: 3, emoji: '😐', label: 'مقبول' },
|
|
6
|
+
{ value: 4, emoji: '🙂', label: 'جيد' },
|
|
7
|
+
{ value: 5, emoji: '😍', label: 'ممتاز' },
|
|
8
|
+
];
|
|
9
|
+
export class AiRating {
|
|
10
|
+
/** Main question label */
|
|
11
|
+
question = 'كيف كانت تجربتك؟';
|
|
12
|
+
/** Sub-label below the question */
|
|
13
|
+
subtitle = 'رأيك يساعدنا نحسن الخدمة';
|
|
14
|
+
/** Currently selected rating value (1–5) */
|
|
15
|
+
value = null;
|
|
16
|
+
/** Disable interaction */
|
|
17
|
+
disabled = false;
|
|
18
|
+
hovered = null;
|
|
19
|
+
ratingChange;
|
|
20
|
+
select(val) {
|
|
21
|
+
if (this.disabled)
|
|
22
|
+
return;
|
|
23
|
+
this.value = this.value === val ? null : val;
|
|
24
|
+
if (this.value !== null)
|
|
25
|
+
this.ratingChange.emit(this.value);
|
|
26
|
+
}
|
|
27
|
+
get selectedLabel() {
|
|
28
|
+
if (this.value === null)
|
|
29
|
+
return null;
|
|
30
|
+
return EMOJI_OPTIONS.find(o => o.value === this.value)?.label ?? null;
|
|
31
|
+
}
|
|
32
|
+
render() {
|
|
33
|
+
const label = this.selectedLabel;
|
|
34
|
+
return (h(Host, { key: 'e540c94762552fbf2bc8a60f37a9059e1f9b6610' }, h("div", { key: '0e5ff97267ee692a19e6e1ba5d6f32b456d6401e', class: "rating" }, h("div", { key: '00c30cb515c0d51d7c1f9e8393f15b1d0475ffc7', class: "rating__text" }, h("p", { key: '2a390c9465eed30fac0d8f8291f6a7c2dab35a47', class: "rating__question" }, this.question), h("p", { key: '09a1010df00e31aa05946e6a1cf1fc23d9fa77a0', class: "rating__subtitle" }, this.subtitle)), h("div", { key: '777a46e4157d1c1bc3691bdd0783a7023f7e3d8d', class: "rating__icons", role: "group", "aria-label": this.question }, EMOJI_OPTIONS.map(opt => {
|
|
35
|
+
const isActive = this.value === opt.value;
|
|
36
|
+
const isHovered = this.hovered === opt.value;
|
|
37
|
+
return (h("button", { key: opt.value, class: {
|
|
38
|
+
'emoji-btn': true,
|
|
39
|
+
'emoji-btn--active': isActive,
|
|
40
|
+
'emoji-btn--hovered': isHovered && !isActive,
|
|
41
|
+
'emoji-btn--disabled': this.disabled,
|
|
42
|
+
}, "aria-label": opt.label, "aria-pressed": isActive ? 'true' : 'false', disabled: this.disabled, onClick: () => this.select(opt.value), onMouseEnter: () => (this.hovered = opt.value), onMouseLeave: () => (this.hovered = null) }, h("span", { class: "emoji-btn__icon", "aria-hidden": "true" }, opt.emoji)));
|
|
43
|
+
})), label && h("p", { key: 'bba5b2ff2bcdd371cb3aefc761a5d7653bbf8630', class: "rating__selected-label" }, label))));
|
|
44
|
+
}
|
|
45
|
+
static get is() { return "ai-rating"; }
|
|
46
|
+
static get encapsulation() { return "shadow"; }
|
|
47
|
+
static get originalStyleUrls() {
|
|
48
|
+
return {
|
|
49
|
+
"$": ["ai-rating.css"]
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
static get styleUrls() {
|
|
53
|
+
return {
|
|
54
|
+
"$": ["ai-rating.css"]
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
static get properties() {
|
|
58
|
+
return {
|
|
59
|
+
"question": {
|
|
60
|
+
"type": "string",
|
|
61
|
+
"mutable": false,
|
|
62
|
+
"complexType": {
|
|
63
|
+
"original": "string",
|
|
64
|
+
"resolved": "string",
|
|
65
|
+
"references": {}
|
|
66
|
+
},
|
|
67
|
+
"required": false,
|
|
68
|
+
"optional": false,
|
|
69
|
+
"docs": {
|
|
70
|
+
"tags": [],
|
|
71
|
+
"text": "Main question label"
|
|
72
|
+
},
|
|
73
|
+
"getter": false,
|
|
74
|
+
"setter": false,
|
|
75
|
+
"reflect": false,
|
|
76
|
+
"attribute": "question",
|
|
77
|
+
"defaultValue": "'\u0643\u064A\u0641 \u0643\u0627\u0646\u062A \u062A\u062C\u0631\u0628\u062A\u0643\u061F'"
|
|
78
|
+
},
|
|
79
|
+
"subtitle": {
|
|
80
|
+
"type": "string",
|
|
81
|
+
"mutable": false,
|
|
82
|
+
"complexType": {
|
|
83
|
+
"original": "string",
|
|
84
|
+
"resolved": "string",
|
|
85
|
+
"references": {}
|
|
86
|
+
},
|
|
87
|
+
"required": false,
|
|
88
|
+
"optional": false,
|
|
89
|
+
"docs": {
|
|
90
|
+
"tags": [],
|
|
91
|
+
"text": "Sub-label below the question"
|
|
92
|
+
},
|
|
93
|
+
"getter": false,
|
|
94
|
+
"setter": false,
|
|
95
|
+
"reflect": false,
|
|
96
|
+
"attribute": "subtitle",
|
|
97
|
+
"defaultValue": "'\u0631\u0623\u064A\u0643 \u064A\u0633\u0627\u0639\u062F\u0646\u0627 \u0646\u062D\u0633\u0646 \u0627\u0644\u062E\u062F\u0645\u0629'"
|
|
98
|
+
},
|
|
99
|
+
"value": {
|
|
100
|
+
"type": "number",
|
|
101
|
+
"mutable": true,
|
|
102
|
+
"complexType": {
|
|
103
|
+
"original": "RatingValue | null",
|
|
104
|
+
"resolved": "1 | 2 | 3 | 4 | 5",
|
|
105
|
+
"references": {
|
|
106
|
+
"RatingValue": {
|
|
107
|
+
"location": "local",
|
|
108
|
+
"path": "/home/ahmed/Desktop/Salla/Dev/multi-agent/ui-ai-kit/packages/core/src/components/ai-rating/ai-rating.tsx",
|
|
109
|
+
"id": "src/components/ai-rating/ai-rating.tsx::RatingValue"
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
"required": false,
|
|
114
|
+
"optional": false,
|
|
115
|
+
"docs": {
|
|
116
|
+
"tags": [],
|
|
117
|
+
"text": "Currently selected rating value (1\u20135)"
|
|
118
|
+
},
|
|
119
|
+
"getter": false,
|
|
120
|
+
"setter": false,
|
|
121
|
+
"reflect": false,
|
|
122
|
+
"attribute": "value",
|
|
123
|
+
"defaultValue": "null"
|
|
124
|
+
},
|
|
125
|
+
"disabled": {
|
|
126
|
+
"type": "boolean",
|
|
127
|
+
"mutable": false,
|
|
128
|
+
"complexType": {
|
|
129
|
+
"original": "boolean",
|
|
130
|
+
"resolved": "boolean",
|
|
131
|
+
"references": {}
|
|
132
|
+
},
|
|
133
|
+
"required": false,
|
|
134
|
+
"optional": false,
|
|
135
|
+
"docs": {
|
|
136
|
+
"tags": [],
|
|
137
|
+
"text": "Disable interaction"
|
|
138
|
+
},
|
|
139
|
+
"getter": false,
|
|
140
|
+
"setter": false,
|
|
141
|
+
"reflect": false,
|
|
142
|
+
"attribute": "disabled",
|
|
143
|
+
"defaultValue": "false"
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
static get states() {
|
|
148
|
+
return {
|
|
149
|
+
"hovered": {}
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
static get events() {
|
|
153
|
+
return [{
|
|
154
|
+
"method": "ratingChange",
|
|
155
|
+
"name": "ratingChange",
|
|
156
|
+
"bubbles": true,
|
|
157
|
+
"cancelable": true,
|
|
158
|
+
"composed": true,
|
|
159
|
+
"docs": {
|
|
160
|
+
"tags": [],
|
|
161
|
+
"text": ""
|
|
162
|
+
},
|
|
163
|
+
"complexType": {
|
|
164
|
+
"original": "RatingValue",
|
|
165
|
+
"resolved": "1 | 2 | 3 | 4 | 5",
|
|
166
|
+
"references": {
|
|
167
|
+
"RatingValue": {
|
|
168
|
+
"location": "local",
|
|
169
|
+
"path": "/home/ahmed/Desktop/Salla/Dev/multi-agent/ui-ai-kit/packages/core/src/components/ai-rating/ai-rating.tsx",
|
|
170
|
+
"id": "src/components/ai-rating/ai-rating.tsx::RatingValue"
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}];
|
|
175
|
+
}
|
|
176
|
+
}
|