igniteui-webcomponents 6.2.0 → 6.3.0-alpha.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/components/chat/chat-input.d.ts +70 -0
- package/components/chat/chat-input.js +266 -0
- package/components/chat/chat-input.js.map +1 -0
- package/components/chat/chat-message-list.d.ts +111 -0
- package/components/chat/chat-message-list.js +178 -0
- package/components/chat/chat-message-list.js.map +1 -0
- package/components/chat/chat-message.d.ts +57 -0
- package/components/chat/chat-message.js +59 -0
- package/components/chat/chat-message.js.map +1 -0
- package/components/chat/chat-state.d.ts +155 -0
- package/components/chat/chat-state.js +167 -0
- package/components/chat/chat-state.js.map +1 -0
- package/components/chat/chat.d.ts +164 -0
- package/components/chat/chat.js +168 -0
- package/components/chat/chat.js.map +1 -0
- package/components/chat/markdown-util.d.ts +2 -0
- package/components/chat/markdown-util.js +22 -0
- package/components/chat/markdown-util.js.map +1 -0
- package/components/chat/message-attachments.d.ts +45 -0
- package/components/chat/message-attachments.js +127 -0
- package/components/chat/message-attachments.js.map +1 -0
- package/components/chat/themes/chat.base.css.d.ts +1 -0
- package/components/chat/themes/chat.base.css.js +3 -0
- package/components/chat/themes/chat.base.css.js.map +1 -0
- package/components/chat/themes/dark/chat.bootstrap.css.d.ts +1 -0
- package/components/chat/themes/dark/chat.bootstrap.css.js +3 -0
- package/components/chat/themes/dark/chat.bootstrap.css.js.map +1 -0
- package/components/chat/themes/dark/chat.fluent.css.d.ts +1 -0
- package/components/chat/themes/dark/chat.fluent.css.js +3 -0
- package/components/chat/themes/dark/chat.fluent.css.js.map +1 -0
- package/components/chat/themes/dark/chat.indigo.css.d.ts +1 -0
- package/components/chat/themes/dark/chat.indigo.css.js +3 -0
- package/components/chat/themes/dark/chat.indigo.css.js.map +1 -0
- package/components/chat/themes/dark/chat.material.css.d.ts +1 -0
- package/components/chat/themes/dark/chat.material.css.js +3 -0
- package/components/chat/themes/dark/chat.material.css.js.map +1 -0
- package/components/chat/themes/input.base.css.d.ts +1 -0
- package/components/chat/themes/input.base.css.js +3 -0
- package/components/chat/themes/input.base.css.js.map +1 -0
- package/components/chat/themes/input.d.ts +2 -0
- package/components/chat/themes/input.js +35 -0
- package/components/chat/themes/input.js.map +1 -0
- package/components/chat/themes/light/chat.bootstrap.css.d.ts +1 -0
- package/components/chat/themes/light/chat.bootstrap.css.js +3 -0
- package/components/chat/themes/light/chat.bootstrap.css.js.map +1 -0
- package/components/chat/themes/light/chat.fluent.css.d.ts +1 -0
- package/components/chat/themes/light/chat.fluent.css.js +3 -0
- package/components/chat/themes/light/chat.fluent.css.js.map +1 -0
- package/components/chat/themes/light/chat.indigo.css.d.ts +1 -0
- package/components/chat/themes/light/chat.indigo.css.js +3 -0
- package/components/chat/themes/light/chat.indigo.css.js.map +1 -0
- package/components/chat/themes/light/chat.material.css.d.ts +1 -0
- package/components/chat/themes/light/chat.material.css.js +3 -0
- package/components/chat/themes/light/chat.material.css.js.map +1 -0
- package/components/chat/themes/light/chat.shared.css.d.ts +1 -0
- package/components/chat/themes/light/chat.shared.css.js +3 -0
- package/components/chat/themes/light/chat.shared.css.js.map +1 -0
- package/components/chat/themes/message-attachments.base.css.d.ts +1 -0
- package/components/chat/themes/message-attachments.base.css.js +3 -0
- package/components/chat/themes/message-attachments.base.css.js.map +1 -0
- package/components/chat/themes/message-list.base.css.d.ts +1 -0
- package/components/chat/themes/message-list.base.css.js +3 -0
- package/components/chat/themes/message-list.base.css.js.map +1 -0
- package/components/chat/themes/message.base.css.d.ts +1 -0
- package/components/chat/themes/message.base.css.js +3 -0
- package/components/chat/themes/message.base.css.js.map +1 -0
- package/components/chat/themes/shared/chat-message.common.css.d.ts +1 -0
- package/components/chat/themes/shared/chat-message.common.css.js +3 -0
- package/components/chat/themes/shared/chat-message.common.css.js.map +1 -0
- package/components/chat/themes/shared/chat.common.css.d.ts +1 -0
- package/components/chat/themes/shared/chat.common.css.js +3 -0
- package/components/chat/themes/shared/chat.common.css.js.map +1 -0
- package/components/chat/themes/shared/input/input.bootstrap.css.d.ts +1 -0
- package/components/chat/themes/shared/input/input.bootstrap.css.js +3 -0
- package/components/chat/themes/shared/input/input.bootstrap.css.js.map +1 -0
- package/components/chat/themes/shared/input/input.common.css.d.ts +1 -0
- package/components/chat/themes/shared/input/input.common.css.js +3 -0
- package/components/chat/themes/shared/input/input.common.css.js.map +1 -0
- package/components/chat/themes/shared/input/input.fluent.css.d.ts +1 -0
- package/components/chat/themes/shared/input/input.fluent.css.js +3 -0
- package/components/chat/themes/shared/input/input.fluent.css.js.map +1 -0
- package/components/chat/themes/shared/input/input.indigo.css.d.ts +1 -0
- package/components/chat/themes/shared/input/input.indigo.css.js +3 -0
- package/components/chat/themes/shared/input/input.indigo.css.js.map +1 -0
- package/components/chat/themes/shared/input/input.material.css.d.ts +1 -0
- package/components/chat/themes/shared/input/input.material.css.js +3 -0
- package/components/chat/themes/shared/input/input.material.css.js.map +1 -0
- package/components/chat/themes/shared/message-attachments.common.css.d.ts +1 -0
- package/components/chat/themes/shared/message-attachments.common.css.js +3 -0
- package/components/chat/themes/shared/message-attachments.common.css.js.map +1 -0
- package/components/chat/themes/shared/message-list.common.css.d.ts +1 -0
- package/components/chat/themes/shared/message-list.common.css.js +3 -0
- package/components/chat/themes/shared/message-list.common.css.js.map +1 -0
- package/components/chat/themes/themes.d.ts +2 -0
- package/components/chat/themes/themes.js +46 -0
- package/components/chat/themes/themes.js.map +1 -0
- package/components/chat/types.d.ts +190 -0
- package/components/chat/types.js +8 -0
- package/components/chat/types.js.map +1 -0
- package/components/checkbox/themes/dark/switch/switch.bootstrap.css.js +1 -1
- package/components/checkbox/themes/dark/switch/switch.bootstrap.css.js.map +1 -1
- package/components/checkbox/themes/dark/switch/switch.fluent.css.js +1 -1
- package/components/checkbox/themes/dark/switch/switch.fluent.css.js.map +1 -1
- package/components/checkbox/themes/dark/switch/switch.indigo.css.js +1 -1
- package/components/checkbox/themes/dark/switch/switch.indigo.css.js.map +1 -1
- package/components/checkbox/themes/dark/switch/switch.material.css.js +1 -1
- package/components/checkbox/themes/dark/switch/switch.material.css.js.map +1 -1
- package/components/checkbox/themes/light/switch/switch.bootstrap.css.js +1 -1
- package/components/checkbox/themes/light/switch/switch.bootstrap.css.js.map +1 -1
- package/components/checkbox/themes/light/switch/switch.fluent.css.js +1 -1
- package/components/checkbox/themes/light/switch/switch.fluent.css.js.map +1 -1
- package/components/checkbox/themes/light/switch/switch.indigo.css.js +1 -1
- package/components/checkbox/themes/light/switch/switch.indigo.css.js.map +1 -1
- package/components/checkbox/themes/light/switch/switch.material.css.js +1 -1
- package/components/checkbox/themes/light/switch/switch.material.css.js.map +1 -1
- package/components/common/context.d.ts +5 -1
- package/components/common/context.js +2 -1
- package/components/common/context.js.map +1 -1
- package/components/common/definitions/defineAllComponents.js +2 -0
- package/components/common/definitions/defineAllComponents.js.map +1 -1
- package/custom-elements.json +15692 -13967
- package/igniteui-webcomponents.css-data.json +1 -1
- package/igniteui-webcomponents.html-data.json +1 -1
- package/index.d.ts +3 -0
- package/index.js +1 -0
- package/index.js.map +1 -1
- package/package.json +1 -1
- package/web-types.json +2 -2
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { LitElement, type TemplateResult } from 'lit';
|
|
2
|
+
/**
|
|
3
|
+
* A web component that provides the input area for the `igc-chat` interface.
|
|
4
|
+
*
|
|
5
|
+
* It supports:
|
|
6
|
+
* - Text input with automatic resizing
|
|
7
|
+
* - Sending messages on Enter key (with Shift+Enter for newlines)
|
|
8
|
+
* - File attachments via file picker or drag-and-drop
|
|
9
|
+
* - Customizable templates for send button, attachments, and text input
|
|
10
|
+
* - Emits various chat-related events (typing, input focus/blur, attachment drop, etc.)
|
|
11
|
+
*
|
|
12
|
+
* @element igc-chat-input
|
|
13
|
+
*
|
|
14
|
+
* @slot - Default unnamed slot for rendering inside the component
|
|
15
|
+
* @fires igcTypingChange - Fired when the user starts/stops typing
|
|
16
|
+
* @fires igcInputFocus - Fired when the input area receives focus
|
|
17
|
+
* @fires igcInputBlur - Fired when the input area loses focus
|
|
18
|
+
* @fires igcAttachmentDrag - Fired when dragging a file over the input
|
|
19
|
+
* @fires igcAttachmentDrop - Fired when a file is dropped into the input
|
|
20
|
+
* @fires igcChange - Fired when file input changes (delegated from `<igc-file-input>`)
|
|
21
|
+
*
|
|
22
|
+
* @csspart input-container - Container for the input section
|
|
23
|
+
* @csspart input-wrapper - Wrapper around the text input
|
|
24
|
+
* @csspart text-input - The `<igc-textarea>` component
|
|
25
|
+
* @csspart buttons-container - Container for file upload/send buttons
|
|
26
|
+
* @csspart send-button - The send icon button
|
|
27
|
+
* @csspart attachments - Container for rendering attachments
|
|
28
|
+
* @csspart attachment-wrapper - Wrapper for individual attachment
|
|
29
|
+
* @csspart attachment-name - Display name of an attachment
|
|
30
|
+
*/
|
|
31
|
+
export default class IgcChatInputComponent extends LitElement {
|
|
32
|
+
static readonly tagName = "igc-chat-input";
|
|
33
|
+
static styles: import("lit").CSSResult[];
|
|
34
|
+
private _chatState?;
|
|
35
|
+
static register(): void;
|
|
36
|
+
private textInputElement;
|
|
37
|
+
private fileInputElement;
|
|
38
|
+
protected acceptedFilesChange(): void;
|
|
39
|
+
private inputValue;
|
|
40
|
+
private inputPlaceholder;
|
|
41
|
+
private containerPart;
|
|
42
|
+
constructor();
|
|
43
|
+
get defaultAttachmentsArea(): TemplateResult;
|
|
44
|
+
get defaultTextArea(): TemplateResult;
|
|
45
|
+
get defaultFileUploadButton(): TemplateResult;
|
|
46
|
+
get defaultSendButton(): TemplateResult;
|
|
47
|
+
protected renderDefaultFileUploadTemplate(): Generator<TemplateResult<1>, void, unknown>;
|
|
48
|
+
protected firstUpdated(): void;
|
|
49
|
+
protected updated(): void;
|
|
50
|
+
private handleInput;
|
|
51
|
+
private handleKeyDown;
|
|
52
|
+
private handleFocus;
|
|
53
|
+
private handleBlur;
|
|
54
|
+
private setupDragAndDrop;
|
|
55
|
+
private handleDragEnter;
|
|
56
|
+
private handleDragOver;
|
|
57
|
+
private handleDragLeave;
|
|
58
|
+
private handleDrop;
|
|
59
|
+
private sendMessage;
|
|
60
|
+
private handleFileUpload;
|
|
61
|
+
private removeAttachment;
|
|
62
|
+
private renderActionsArea;
|
|
63
|
+
private renderAttachmentsArea;
|
|
64
|
+
protected render(): TemplateResult<1>;
|
|
65
|
+
}
|
|
66
|
+
declare global {
|
|
67
|
+
interface HTMLElementTagNameMap {
|
|
68
|
+
'igc-chat-input': IgcChatInputComponent;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { consume } from '@lit/context';
|
|
8
|
+
import { html, LitElement, nothing } from 'lit';
|
|
9
|
+
import { query, state } from 'lit/decorators.js';
|
|
10
|
+
import { addThemingController } from '../../theming/theming-controller.js';
|
|
11
|
+
import IgcIconButtonComponent from '../button/icon-button.js';
|
|
12
|
+
import IgcChipComponent from '../chip/chip.js';
|
|
13
|
+
import { chatContext } from '../common/context.js';
|
|
14
|
+
import { watch } from '../common/decorators/watch.js';
|
|
15
|
+
import { registerComponent } from '../common/definitions/register.js';
|
|
16
|
+
import IgcFileInputComponent from '../file-input/file-input.js';
|
|
17
|
+
import IgcIconComponent from '../icon/icon.js';
|
|
18
|
+
import { registerIconFromText } from '../icon/icon.registry.js';
|
|
19
|
+
import IgcTextareaComponent from '../textarea/textarea.js';
|
|
20
|
+
import { styles } from './themes/input.base.css.js';
|
|
21
|
+
import { all } from './themes/input.js';
|
|
22
|
+
import { styles as shared } from './themes/shared/input/input.common.css.js';
|
|
23
|
+
import { attachmentIcon, sendButtonIcon } from './types.js';
|
|
24
|
+
class IgcChatInputComponent extends LitElement {
|
|
25
|
+
static register() {
|
|
26
|
+
registerComponent(IgcChatInputComponent, IgcTextareaComponent, IgcIconButtonComponent, IgcChipComponent, IgcFileInputComponent, IgcIconComponent);
|
|
27
|
+
}
|
|
28
|
+
acceptedFilesChange() {
|
|
29
|
+
this._chatState?.updateAcceptedTypesCache();
|
|
30
|
+
}
|
|
31
|
+
constructor() {
|
|
32
|
+
super();
|
|
33
|
+
this.inputValue = '';
|
|
34
|
+
this.inputPlaceholder = '';
|
|
35
|
+
this.containerPart = 'input-container';
|
|
36
|
+
addThemingController(this, all);
|
|
37
|
+
registerIconFromText('attachment', attachmentIcon, 'material');
|
|
38
|
+
registerIconFromText('send-message', sendButtonIcon, 'material');
|
|
39
|
+
}
|
|
40
|
+
get defaultAttachmentsArea() {
|
|
41
|
+
return html `${this._chatState?.inputAttachments?.map((attachment, index) => html `
|
|
42
|
+
<div part="attachment-wrapper" role="listitem">
|
|
43
|
+
<igc-chip removable @igcRemove=${() => this.removeAttachment(index)}>
|
|
44
|
+
<span part="attachment-name">${attachment.name}</span>
|
|
45
|
+
</igc-chip>
|
|
46
|
+
</div>
|
|
47
|
+
`)} `;
|
|
48
|
+
}
|
|
49
|
+
get defaultTextArea() {
|
|
50
|
+
return html ` <igc-textarea
|
|
51
|
+
part="text-input"
|
|
52
|
+
.placeholder=${this.inputPlaceholder}
|
|
53
|
+
resize="auto"
|
|
54
|
+
rows="1"
|
|
55
|
+
.value=${this.inputValue}
|
|
56
|
+
@input=${this.handleInput}
|
|
57
|
+
@keydown=${this.handleKeyDown}
|
|
58
|
+
@focus=${this.handleFocus}
|
|
59
|
+
@blur=${this.handleBlur}
|
|
60
|
+
></igc-textarea>`;
|
|
61
|
+
}
|
|
62
|
+
get defaultFileUploadButton() {
|
|
63
|
+
return html `
|
|
64
|
+
<igc-file-input
|
|
65
|
+
multiple
|
|
66
|
+
.accept=${this._chatState?.options?.acceptedFiles}
|
|
67
|
+
@igcChange=${this.handleFileUpload}
|
|
68
|
+
>
|
|
69
|
+
<igc-icon
|
|
70
|
+
slot="file-selector-text"
|
|
71
|
+
name="attachment"
|
|
72
|
+
collection="material"
|
|
73
|
+
></igc-icon>
|
|
74
|
+
</igc-file-input>
|
|
75
|
+
`;
|
|
76
|
+
}
|
|
77
|
+
get defaultSendButton() {
|
|
78
|
+
return html ` <igc-icon-button
|
|
79
|
+
aria-label="Send message"
|
|
80
|
+
name="send-message"
|
|
81
|
+
collection="material"
|
|
82
|
+
variant="contained"
|
|
83
|
+
part="send-button"
|
|
84
|
+
?disabled=${!this.inputValue.trim() &&
|
|
85
|
+
this._chatState?.inputAttachments.length === 0}
|
|
86
|
+
@click=${this.sendMessage}
|
|
87
|
+
></igc-icon-button>`;
|
|
88
|
+
}
|
|
89
|
+
*renderDefaultFileUploadTemplate() {
|
|
90
|
+
yield html `${this._chatState?.options?.disableAttachments
|
|
91
|
+
? nothing
|
|
92
|
+
: this.defaultFileUploadButton}`;
|
|
93
|
+
}
|
|
94
|
+
firstUpdated() {
|
|
95
|
+
this.setupDragAndDrop();
|
|
96
|
+
if (this._chatState) {
|
|
97
|
+
this._chatState.updateAcceptedTypesCache();
|
|
98
|
+
this._chatState.textArea = this.textInputElement;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
updated() {
|
|
102
|
+
this.inputValue = this._chatState?.inputValue || '';
|
|
103
|
+
this.inputPlaceholder = this._chatState?.options?.inputPlaceholder || '';
|
|
104
|
+
}
|
|
105
|
+
handleInput(e) {
|
|
106
|
+
const target = e.target;
|
|
107
|
+
this.inputValue = target.value;
|
|
108
|
+
this._chatState?.handleInputChange(this.inputValue);
|
|
109
|
+
}
|
|
110
|
+
handleKeyDown(e) {
|
|
111
|
+
if (e.key === 'Enter' && !e.shiftKey) {
|
|
112
|
+
e.preventDefault();
|
|
113
|
+
this.sendMessage();
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
this._chatState?.emitEvent('igcTypingChange', {
|
|
117
|
+
detail: { isTyping: true },
|
|
118
|
+
});
|
|
119
|
+
setTimeout(() => {
|
|
120
|
+
this._chatState?.emitEvent('igcTypingChange', {
|
|
121
|
+
detail: { isTyping: false },
|
|
122
|
+
});
|
|
123
|
+
}, 3000);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
handleFocus() {
|
|
127
|
+
this._chatState?.emitEvent('igcInputFocus');
|
|
128
|
+
}
|
|
129
|
+
handleBlur() {
|
|
130
|
+
this._chatState?.emitEvent('igcInputBlur');
|
|
131
|
+
}
|
|
132
|
+
setupDragAndDrop() {
|
|
133
|
+
const container = this.shadowRoot?.querySelector(`div[part='input-container']`);
|
|
134
|
+
if (container) {
|
|
135
|
+
container.addEventListener('dragenter', this.handleDragEnter.bind(this));
|
|
136
|
+
container.addEventListener('dragover', this.handleDragOver.bind(this));
|
|
137
|
+
container.addEventListener('dragleave', this.handleDragLeave.bind(this));
|
|
138
|
+
container.addEventListener('drop', this.handleDrop.bind(this));
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
handleDragEnter(e) {
|
|
142
|
+
e.preventDefault();
|
|
143
|
+
e.stopPropagation();
|
|
144
|
+
const files = Array.from(e.dataTransfer?.items || []).filter((item) => item.kind === 'file');
|
|
145
|
+
const hasValidFiles = files.some((item) => this._chatState?.isFileTypeAccepted(item.getAsFile(), item.type));
|
|
146
|
+
this.containerPart = `input-container ${hasValidFiles ? ' dragging' : ''}`;
|
|
147
|
+
this._chatState?.emitEvent('igcAttachmentDrag');
|
|
148
|
+
}
|
|
149
|
+
handleDragOver(e) {
|
|
150
|
+
e.preventDefault();
|
|
151
|
+
e.stopPropagation();
|
|
152
|
+
}
|
|
153
|
+
handleDragLeave(e) {
|
|
154
|
+
e.preventDefault();
|
|
155
|
+
e.stopPropagation();
|
|
156
|
+
const rect = e.currentTarget.getBoundingClientRect();
|
|
157
|
+
const x = e.clientX;
|
|
158
|
+
const y = e.clientY;
|
|
159
|
+
if (x <= rect.left ||
|
|
160
|
+
x >= rect.right ||
|
|
161
|
+
y <= rect.top ||
|
|
162
|
+
y >= rect.bottom) {
|
|
163
|
+
this.containerPart = 'input-container';
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
handleDrop(e) {
|
|
167
|
+
e.preventDefault();
|
|
168
|
+
e.stopPropagation();
|
|
169
|
+
this.containerPart = 'input-container';
|
|
170
|
+
const files = Array.from(e.dataTransfer?.files || []);
|
|
171
|
+
if (files.length === 0)
|
|
172
|
+
return;
|
|
173
|
+
const validFiles = files.filter((file) => this._chatState?.isFileTypeAccepted(file));
|
|
174
|
+
this._chatState?.emitEvent('igcAttachmentDrop');
|
|
175
|
+
this._chatState?.attachFiles(validFiles);
|
|
176
|
+
this.requestUpdate();
|
|
177
|
+
}
|
|
178
|
+
sendMessage() {
|
|
179
|
+
if (!this.inputValue.trim() &&
|
|
180
|
+
this._chatState?.inputAttachments.length === 0)
|
|
181
|
+
return;
|
|
182
|
+
this._chatState?.addMessage({
|
|
183
|
+
text: this.inputValue,
|
|
184
|
+
attachments: this._chatState?.inputAttachments,
|
|
185
|
+
});
|
|
186
|
+
this.inputValue = '';
|
|
187
|
+
if (this.textInputElement) {
|
|
188
|
+
this.textInputElement.style.height = 'auto';
|
|
189
|
+
}
|
|
190
|
+
this.updateComplete.then(() => {
|
|
191
|
+
this.textInputElement?.focus();
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
handleFileUpload(e) {
|
|
195
|
+
const input = e.target.input;
|
|
196
|
+
if (!input.files || input.files.length === 0)
|
|
197
|
+
return;
|
|
198
|
+
const files = Array.from(input.files);
|
|
199
|
+
this._chatState?.attachFiles(files);
|
|
200
|
+
this.requestUpdate();
|
|
201
|
+
if (this.fileInputElement) {
|
|
202
|
+
this.fileInputElement.value = '';
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
removeAttachment(index) {
|
|
206
|
+
this._chatState?.removeAttachment(index);
|
|
207
|
+
this.requestUpdate();
|
|
208
|
+
}
|
|
209
|
+
renderActionsArea() {
|
|
210
|
+
return html `<div part="buttons-container">
|
|
211
|
+
${this._chatState?.options?.templates?.textAreaActionsTemplate
|
|
212
|
+
? this._chatState?.options?.templates?.textAreaActionsTemplate
|
|
213
|
+
: html `
|
|
214
|
+
${this.renderDefaultFileUploadTemplate()} ${this.defaultSendButton}
|
|
215
|
+
`}
|
|
216
|
+
</div>`;
|
|
217
|
+
}
|
|
218
|
+
renderAttachmentsArea() {
|
|
219
|
+
return html `<div part="attachments" role="list" aria-label="Attachments">
|
|
220
|
+
${this._chatState?.options?.templates?.textAreaAttachmentsTemplate
|
|
221
|
+
? this._chatState.options.templates.textAreaAttachmentsTemplate(this._chatState?.inputAttachments)
|
|
222
|
+
: this.defaultAttachmentsArea}
|
|
223
|
+
</div>`;
|
|
224
|
+
}
|
|
225
|
+
render() {
|
|
226
|
+
return html `
|
|
227
|
+
<div part="${this.containerPart}">
|
|
228
|
+
${this._chatState?.inputAttachments &&
|
|
229
|
+
this._chatState?.inputAttachments.length > 0
|
|
230
|
+
? this.renderAttachmentsArea()
|
|
231
|
+
: nothing}
|
|
232
|
+
<div part="input-wrapper">
|
|
233
|
+
${this._chatState?.options?.templates?.textInputTemplate
|
|
234
|
+
? this._chatState.options.templates.textInputTemplate(this._chatState?.inputValue)
|
|
235
|
+
: this.defaultTextArea}
|
|
236
|
+
</div>
|
|
237
|
+
${this.renderActionsArea()}
|
|
238
|
+
</div>
|
|
239
|
+
`;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
IgcChatInputComponent.tagName = 'igc-chat-input';
|
|
243
|
+
IgcChatInputComponent.styles = [styles, shared];
|
|
244
|
+
export default IgcChatInputComponent;
|
|
245
|
+
__decorate([
|
|
246
|
+
consume({ context: chatContext, subscribe: true })
|
|
247
|
+
], IgcChatInputComponent.prototype, "_chatState", void 0);
|
|
248
|
+
__decorate([
|
|
249
|
+
query(IgcTextareaComponent.tagName)
|
|
250
|
+
], IgcChatInputComponent.prototype, "textInputElement", void 0);
|
|
251
|
+
__decorate([
|
|
252
|
+
query(IgcFileInputComponent.tagName)
|
|
253
|
+
], IgcChatInputComponent.prototype, "fileInputElement", void 0);
|
|
254
|
+
__decorate([
|
|
255
|
+
watch('acceptedFiles', { waitUntilFirstUpdate: true })
|
|
256
|
+
], IgcChatInputComponent.prototype, "acceptedFilesChange", null);
|
|
257
|
+
__decorate([
|
|
258
|
+
state()
|
|
259
|
+
], IgcChatInputComponent.prototype, "inputValue", void 0);
|
|
260
|
+
__decorate([
|
|
261
|
+
state()
|
|
262
|
+
], IgcChatInputComponent.prototype, "inputPlaceholder", void 0);
|
|
263
|
+
__decorate([
|
|
264
|
+
state()
|
|
265
|
+
], IgcChatInputComponent.prototype, "containerPart", void 0);
|
|
266
|
+
//# sourceMappingURL=chat-input.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-input.js","sourceRoot":"","sources":["../../../src/components/chat/chat-input.ts"],"names":[],"mappings":"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","sourcesContent":["import { consume } from '@lit/context';\nimport { html, LitElement, nothing, type TemplateResult } from 'lit';\nimport { query, state } from 'lit/decorators.js';\nimport { addThemingController } from '../../theming/theming-controller.js';\nimport IgcIconButtonComponent from '../button/icon-button.js';\nimport IgcChipComponent from '../chip/chip.js';\nimport { chatContext } from '../common/context.js';\nimport { watch } from '../common/decorators/watch.js';\nimport { registerComponent } from '../common/definitions/register.js';\nimport IgcFileInputComponent from '../file-input/file-input.js';\nimport IgcIconComponent from '../icon/icon.js';\nimport { registerIconFromText } from '../icon/icon.registry.js';\nimport IgcTextareaComponent from '../textarea/textarea.js';\nimport type { ChatState } from './chat-state.js';\nimport { styles } from './themes/input.base.css.js';\nimport { all } from './themes/input.js';\nimport { styles as shared } from './themes/shared/input/input.common.css.js';\nimport { attachmentIcon, sendButtonIcon } from './types.js';\n\n/**\n * A web component that provides the input area for the `igc-chat` interface.\n *\n * It supports:\n * - Text input with automatic resizing\n * - Sending messages on Enter key (with Shift+Enter for newlines)\n * - File attachments via file picker or drag-and-drop\n * - Customizable templates for send button, attachments, and text input\n * - Emits various chat-related events (typing, input focus/blur, attachment drop, etc.)\n *\n * @element igc-chat-input\n *\n * @slot - Default unnamed slot for rendering inside the component\n * @fires igcTypingChange - Fired when the user starts/stops typing\n * @fires igcInputFocus - Fired when the input area receives focus\n * @fires igcInputBlur - Fired when the input area loses focus\n * @fires igcAttachmentDrag - Fired when dragging a file over the input\n * @fires igcAttachmentDrop - Fired when a file is dropped into the input\n * @fires igcChange - Fired when file input changes (delegated from `<igc-file-input>`)\n *\n * @csspart input-container - Container for the input section\n * @csspart input-wrapper - Wrapper around the text input\n * @csspart text-input - The `<igc-textarea>` component\n * @csspart buttons-container - Container for file upload/send buttons\n * @csspart send-button - The send icon button\n * @csspart attachments - Container for rendering attachments\n * @csspart attachment-wrapper - Wrapper for individual attachment\n * @csspart attachment-name - Display name of an attachment\n */\nexport default class IgcChatInputComponent extends LitElement {\n public static readonly tagName = 'igc-chat-input';\n\n public static override styles = [styles, shared];\n\n @consume({ context: chatContext, subscribe: true })\n private _chatState?: ChatState;\n\n /* blazorSuppress */\n public static register() {\n registerComponent(\n IgcChatInputComponent,\n IgcTextareaComponent,\n IgcIconButtonComponent,\n IgcChipComponent,\n IgcFileInputComponent,\n IgcIconComponent\n );\n }\n\n @query(IgcTextareaComponent.tagName)\n private textInputElement!: IgcTextareaComponent;\n\n @query(IgcFileInputComponent.tagName)\n private fileInputElement!: IgcFileInputComponent;\n\n @watch('acceptedFiles', { waitUntilFirstUpdate: true })\n protected acceptedFilesChange(): void {\n this._chatState?.updateAcceptedTypesCache();\n }\n\n @state()\n private inputValue = '';\n\n @state()\n private inputPlaceholder = '';\n\n @state()\n private containerPart = 'input-container';\n\n constructor() {\n super();\n addThemingController(this, all);\n registerIconFromText('attachment', attachmentIcon, 'material');\n registerIconFromText('send-message', sendButtonIcon, 'material');\n }\n\n public get defaultAttachmentsArea(): TemplateResult {\n return html`${this._chatState?.inputAttachments?.map(\n (attachment, index) => html`\n <div part=\"attachment-wrapper\" role=\"listitem\">\n <igc-chip removable @igcRemove=${() => this.removeAttachment(index)}>\n <span part=\"attachment-name\">${attachment.name}</span>\n </igc-chip>\n </div>\n `\n )} `;\n }\n\n public get defaultTextArea(): TemplateResult {\n return html` <igc-textarea\n part=\"text-input\"\n .placeholder=${this.inputPlaceholder}\n resize=\"auto\"\n rows=\"1\"\n .value=${this.inputValue}\n @input=${this.handleInput}\n @keydown=${this.handleKeyDown}\n @focus=${this.handleFocus}\n @blur=${this.handleBlur}\n ></igc-textarea>`;\n }\n\n public get defaultFileUploadButton(): TemplateResult {\n return html`\n <igc-file-input\n multiple\n .accept=${this._chatState?.options?.acceptedFiles}\n @igcChange=${this.handleFileUpload}\n >\n <igc-icon\n slot=\"file-selector-text\"\n name=\"attachment\"\n collection=\"material\"\n ></igc-icon>\n </igc-file-input>\n `;\n }\n\n public get defaultSendButton(): TemplateResult {\n return html` <igc-icon-button\n aria-label=\"Send message\"\n name=\"send-message\"\n collection=\"material\"\n variant=\"contained\"\n part=\"send-button\"\n ?disabled=${!this.inputValue.trim() &&\n this._chatState?.inputAttachments.length === 0}\n @click=${this.sendMessage}\n ></igc-icon-button>`;\n }\n\n protected *renderDefaultFileUploadTemplate() {\n yield html`${this._chatState?.options?.disableAttachments\n ? nothing\n : this.defaultFileUploadButton}`;\n }\n\n protected override firstUpdated() {\n this.setupDragAndDrop();\n if (this._chatState) {\n this._chatState.updateAcceptedTypesCache();\n this._chatState.textArea = this.textInputElement;\n }\n }\n\n protected override updated() {\n this.inputValue = this._chatState?.inputValue || '';\n this.inputPlaceholder = this._chatState?.options?.inputPlaceholder || '';\n }\n\n private handleInput(e: Event) {\n const target = e.target as HTMLTextAreaElement;\n this.inputValue = target.value;\n this._chatState?.handleInputChange(this.inputValue);\n // this.adjustTextareaHeight();\n }\n\n private handleKeyDown(e: KeyboardEvent) {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n this.sendMessage();\n } else {\n this._chatState?.emitEvent('igcTypingChange', {\n detail: { isTyping: true },\n });\n\n // wait 3 seconds and dispatch a stop-typing event\n setTimeout(() => {\n this._chatState?.emitEvent('igcTypingChange', {\n detail: { isTyping: false },\n });\n }, 3000);\n }\n }\n\n private handleFocus() {\n this._chatState?.emitEvent('igcInputFocus');\n }\n\n private handleBlur() {\n this._chatState?.emitEvent('igcInputBlur');\n }\n\n private setupDragAndDrop() {\n const container = this.shadowRoot?.querySelector(\n `div[part='input-container']`\n ) as HTMLElement;\n if (container) {\n container.addEventListener('dragenter', this.handleDragEnter.bind(this));\n container.addEventListener('dragover', this.handleDragOver.bind(this));\n container.addEventListener('dragleave', this.handleDragLeave.bind(this));\n container.addEventListener('drop', this.handleDrop.bind(this));\n }\n }\n\n private handleDragEnter(e: DragEvent) {\n e.preventDefault();\n e.stopPropagation();\n\n const files = Array.from(e.dataTransfer?.items || []).filter(\n (item) => item.kind === 'file'\n );\n const hasValidFiles = files.some((item) =>\n this._chatState?.isFileTypeAccepted(item.getAsFile() as File, item.type)\n );\n\n this.containerPart = `input-container ${hasValidFiles ? ' dragging' : ''}`;\n\n this._chatState?.emitEvent('igcAttachmentDrag');\n }\n\n private handleDragOver(e: DragEvent) {\n e.preventDefault();\n e.stopPropagation();\n }\n\n private handleDragLeave(e: DragEvent) {\n e.preventDefault();\n e.stopPropagation();\n\n // Check if we're actually leaving the container\n const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();\n const x = e.clientX;\n const y = e.clientY;\n\n if (\n x <= rect.left ||\n x >= rect.right ||\n y <= rect.top ||\n y >= rect.bottom\n ) {\n this.containerPart = 'input-container';\n }\n }\n\n private handleDrop(e: DragEvent) {\n e.preventDefault();\n e.stopPropagation();\n this.containerPart = 'input-container';\n\n const files = Array.from(e.dataTransfer?.files || []);\n if (files.length === 0) return;\n\n const validFiles = files.filter((file) =>\n this._chatState?.isFileTypeAccepted(file)\n );\n\n this._chatState?.emitEvent('igcAttachmentDrop');\n\n this._chatState?.attachFiles(validFiles);\n this.requestUpdate();\n }\n\n // private adjustTextareaHeight() {\n // const textarea = this.textInputElement;\n // if (!textarea) return;\n\n // textarea.style.height = 'auto';\n // const newHeight = Math.min(textarea.scrollHeight, 120);\n // textarea.style.height = `${newHeight}px`;\n // }\n\n private sendMessage() {\n if (\n !this.inputValue.trim() &&\n this._chatState?.inputAttachments.length === 0\n )\n return;\n\n this._chatState?.addMessage({\n text: this.inputValue,\n attachments: this._chatState?.inputAttachments,\n });\n this.inputValue = '';\n\n if (this.textInputElement) {\n this.textInputElement.style.height = 'auto';\n }\n\n this.updateComplete.then(() => {\n this.textInputElement?.focus();\n });\n }\n\n private handleFileUpload(e: Event) {\n const input = (e.target as any).input as HTMLInputElement;\n if (!input.files || input.files.length === 0) return;\n\n const files = Array.from(input.files);\n this._chatState?.attachFiles(files);\n this.requestUpdate();\n\n if (this.fileInputElement) {\n this.fileInputElement.value = '';\n }\n }\n\n private removeAttachment(index: number) {\n this._chatState?.removeAttachment(index);\n this.requestUpdate();\n }\n\n private renderActionsArea() {\n return html`<div part=\"buttons-container\">\n ${this._chatState?.options?.templates?.textAreaActionsTemplate\n ? this._chatState?.options?.templates?.textAreaActionsTemplate\n : html`\n ${this.renderDefaultFileUploadTemplate()} ${this.defaultSendButton}\n `}\n </div>`;\n }\n\n private renderAttachmentsArea() {\n return html`<div part=\"attachments\" role=\"list\" aria-label=\"Attachments\">\n ${this._chatState?.options?.templates?.textAreaAttachmentsTemplate\n ? this._chatState.options.templates.textAreaAttachmentsTemplate(\n this._chatState?.inputAttachments\n )\n : this.defaultAttachmentsArea}\n </div>`;\n }\n\n protected override render() {\n return html`\n <div part=\"${this.containerPart}\">\n ${this._chatState?.inputAttachments &&\n this._chatState?.inputAttachments.length > 0\n ? this.renderAttachmentsArea()\n : nothing}\n <div part=\"input-wrapper\">\n ${this._chatState?.options?.templates?.textInputTemplate\n ? this._chatState.options.templates.textInputTemplate(\n this._chatState?.inputValue\n )\n : this.defaultTextArea}\n </div>\n ${this.renderActionsArea()}\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'igc-chat-input': IgcChatInputComponent;\n }\n}\n"]}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { LitElement } from 'lit';
|
|
2
|
+
/**
|
|
3
|
+
* A chat message list component that displays a list of chat messages grouped by date.
|
|
4
|
+
*
|
|
5
|
+
* @element igc-chat-message-list
|
|
6
|
+
*
|
|
7
|
+
* This component:
|
|
8
|
+
* - Renders messages using the `<igc-chat-message>` component.
|
|
9
|
+
* - Supports keyboard navigation between messages (Home, End, ArrowUp, ArrowDown).
|
|
10
|
+
* - Manages focus highlighting on active messages.
|
|
11
|
+
* - Automatically scrolls to the bottom when new messages arrive, unless auto-scroll is disabled.
|
|
12
|
+
* - Displays a typing indicator if the chat state option `isComposing` is true.
|
|
13
|
+
*
|
|
14
|
+
* Accessibility:
|
|
15
|
+
* - Uses ARIA roles and properties for grouping and active descendant management.
|
|
16
|
+
* - Message items have role="option" for assistive technologies.
|
|
17
|
+
*
|
|
18
|
+
*/
|
|
19
|
+
export default class IgcChatMessageListComponent extends LitElement {
|
|
20
|
+
/** Tag name of the custom element. */
|
|
21
|
+
static readonly tagName = "igc-chat-message-list";
|
|
22
|
+
/** Styles applied to the component */
|
|
23
|
+
static styles: import("lit").CSSResult[];
|
|
24
|
+
/**
|
|
25
|
+
* Consumed chat state context providing messages, options, and user data.
|
|
26
|
+
* @private
|
|
27
|
+
*/
|
|
28
|
+
private _chatState?;
|
|
29
|
+
/**
|
|
30
|
+
* Currently active message id used for focus and keyboard navigation.
|
|
31
|
+
* @private
|
|
32
|
+
*/
|
|
33
|
+
private _activeMessageId;
|
|
34
|
+
/**
|
|
35
|
+
* Registers this component and its dependencies.
|
|
36
|
+
* Used internally for component setup.
|
|
37
|
+
*/
|
|
38
|
+
static register(): void;
|
|
39
|
+
constructor();
|
|
40
|
+
/**
|
|
41
|
+
* Formats a date to a human-readable label.
|
|
42
|
+
* Returns 'Today', 'Yesterday', or localized date string.
|
|
43
|
+
* @param date - Date object to format
|
|
44
|
+
* @returns formatted string
|
|
45
|
+
* @private
|
|
46
|
+
*/
|
|
47
|
+
private formatDate;
|
|
48
|
+
/**
|
|
49
|
+
* Groups messages by their date labels.
|
|
50
|
+
* @param messages - Array of messages to group
|
|
51
|
+
* @returns Array of groups with date label and messages
|
|
52
|
+
* @private
|
|
53
|
+
*/
|
|
54
|
+
private groupMessagesByDate;
|
|
55
|
+
/**
|
|
56
|
+
* Scrolls the container to the bottom, typically called after new messages are rendered.
|
|
57
|
+
* @private
|
|
58
|
+
*/
|
|
59
|
+
private scrollToBottom;
|
|
60
|
+
/**
|
|
61
|
+
* Scrolls the view to a specific message by id.
|
|
62
|
+
* @param messageId - The id of the message to scroll to
|
|
63
|
+
* @private
|
|
64
|
+
*/
|
|
65
|
+
private scrollToMessage;
|
|
66
|
+
/**
|
|
67
|
+
* Handles focus entering the message list container.
|
|
68
|
+
* Sets the active message to the last message for keyboard navigation.
|
|
69
|
+
* @private
|
|
70
|
+
*/
|
|
71
|
+
private handleFocusIn;
|
|
72
|
+
/**
|
|
73
|
+
* Handles focus leaving the message list container.
|
|
74
|
+
* Clears the active message.
|
|
75
|
+
* @private
|
|
76
|
+
*/
|
|
77
|
+
private handleFocusOut;
|
|
78
|
+
/**
|
|
79
|
+
* Handles keyboard navigation within the message list.
|
|
80
|
+
* Supports Home, End, ArrowUp, ArrowDown keys to move active message focus.
|
|
81
|
+
* @param e KeyboardEvent from user input
|
|
82
|
+
* @private
|
|
83
|
+
*/
|
|
84
|
+
private navigateToMessage;
|
|
85
|
+
/**
|
|
86
|
+
* Lifecycle: called when the component updates.
|
|
87
|
+
* Scrolls to bottom unless auto-scroll is disabled.
|
|
88
|
+
*/
|
|
89
|
+
protected updated(): void;
|
|
90
|
+
/**
|
|
91
|
+
* Lifecycle: called after first render.
|
|
92
|
+
* Scrolls to bottom unless auto-scroll is disabled.
|
|
93
|
+
*/
|
|
94
|
+
protected firstUpdated(): void;
|
|
95
|
+
/**
|
|
96
|
+
* Renders the typing indicator template if composing.
|
|
97
|
+
* @protected
|
|
98
|
+
*/
|
|
99
|
+
protected renderLoadingTemplate(): Generator<import("lit-html").TemplateResult<1>, void, unknown>;
|
|
100
|
+
/**
|
|
101
|
+
* Main render method.
|
|
102
|
+
* Groups messages by date and renders each message.
|
|
103
|
+
* Shows the typing indicator if applicable.
|
|
104
|
+
*/
|
|
105
|
+
protected render(): import("lit-html").TemplateResult<1>;
|
|
106
|
+
}
|
|
107
|
+
declare global {
|
|
108
|
+
interface HTMLElementTagNameMap {
|
|
109
|
+
'igc-chat-message-list': IgcChatMessageListComponent;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { consume } from '@lit/context';
|
|
8
|
+
import { html, LitElement, nothing } from 'lit';
|
|
9
|
+
import { state } from 'lit/decorators.js';
|
|
10
|
+
import { repeat } from 'lit/directives/repeat.js';
|
|
11
|
+
import { chatContext } from '../common/context.js';
|
|
12
|
+
import { addKeybindings, arrowDown, arrowUp, endKey, homeKey, } from '../common/controllers/key-bindings.js';
|
|
13
|
+
import { registerComponent } from '../common/definitions/register.js';
|
|
14
|
+
import IgcChatMessageComponent from './chat-message.js';
|
|
15
|
+
import { styles } from './themes/message-list.base.css.js';
|
|
16
|
+
import { styles as shared } from './themes/shared/message-list.common.css.js';
|
|
17
|
+
class IgcChatMessageListComponent extends LitElement {
|
|
18
|
+
static register() {
|
|
19
|
+
registerComponent(IgcChatMessageListComponent, IgcChatMessageComponent);
|
|
20
|
+
}
|
|
21
|
+
constructor() {
|
|
22
|
+
super();
|
|
23
|
+
this._activeMessageId = '';
|
|
24
|
+
addKeybindings(this)
|
|
25
|
+
.set(homeKey, this.navigateToMessage)
|
|
26
|
+
.set(endKey, this.navigateToMessage)
|
|
27
|
+
.set(arrowUp, this.navigateToMessage)
|
|
28
|
+
.set(arrowDown, this.navigateToMessage);
|
|
29
|
+
}
|
|
30
|
+
formatDate(date) {
|
|
31
|
+
const today = new Date();
|
|
32
|
+
const yesterday = new Date(today);
|
|
33
|
+
yesterday.setDate(yesterday.getDate() - 1);
|
|
34
|
+
if (date.toDateString() === today.toDateString()) {
|
|
35
|
+
return 'Today';
|
|
36
|
+
}
|
|
37
|
+
if (date.toDateString() === yesterday.toDateString()) {
|
|
38
|
+
return 'Yesterday';
|
|
39
|
+
}
|
|
40
|
+
return date.toLocaleDateString('en-US', {
|
|
41
|
+
weekday: 'long',
|
|
42
|
+
month: 'short',
|
|
43
|
+
day: 'numeric',
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
groupMessagesByDate(messages) {
|
|
47
|
+
const grouped = {};
|
|
48
|
+
messages.forEach((message) => {
|
|
49
|
+
const dateStr = this.formatDate(message.timestamp);
|
|
50
|
+
if (!grouped[dateStr]) {
|
|
51
|
+
grouped[dateStr] = [];
|
|
52
|
+
}
|
|
53
|
+
grouped[dateStr].push(message);
|
|
54
|
+
});
|
|
55
|
+
return Object.keys(grouped).map((date) => ({
|
|
56
|
+
date,
|
|
57
|
+
messages: grouped[date],
|
|
58
|
+
}));
|
|
59
|
+
}
|
|
60
|
+
scrollToBottom() {
|
|
61
|
+
requestAnimationFrame(() => {
|
|
62
|
+
const container = this.shadowRoot?.host;
|
|
63
|
+
if (container) {
|
|
64
|
+
container.scrollTop = container.scrollHeight;
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
scrollToMessage(messageId) {
|
|
69
|
+
const messageElement = this.shadowRoot?.querySelector(`#message-${messageId}`);
|
|
70
|
+
messageElement?.scrollIntoView();
|
|
71
|
+
}
|
|
72
|
+
handleFocusIn() {
|
|
73
|
+
if (!this._chatState?.messages || this._chatState.messages.length === 0) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const lastMessage = this._chatState.sortedMessagesIds?.pop() ?? '';
|
|
77
|
+
this._activeMessageId = lastMessage !== '' ? `message-${lastMessage}` : '';
|
|
78
|
+
}
|
|
79
|
+
handleFocusOut() {
|
|
80
|
+
this._activeMessageId = '';
|
|
81
|
+
}
|
|
82
|
+
navigateToMessage(e) {
|
|
83
|
+
if (!this._chatState?.messages || this._chatState.messages.length === 0) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const currentIndex = this._chatState?.sortedMessagesIds.findIndex((id) => `message-${id}` === this._activeMessageId);
|
|
87
|
+
let activeMessageId = '';
|
|
88
|
+
const key = e.key.toLowerCase();
|
|
89
|
+
switch (key) {
|
|
90
|
+
case 'home':
|
|
91
|
+
activeMessageId = this._chatState.sortedMessagesIds[0];
|
|
92
|
+
break;
|
|
93
|
+
case 'end':
|
|
94
|
+
activeMessageId =
|
|
95
|
+
this._chatState.sortedMessagesIds[this._chatState.sortedMessagesIds.length - 1];
|
|
96
|
+
break;
|
|
97
|
+
case 'arrowup':
|
|
98
|
+
if (currentIndex > 0) {
|
|
99
|
+
activeMessageId = this._chatState.sortedMessagesIds[currentIndex - 1];
|
|
100
|
+
}
|
|
101
|
+
break;
|
|
102
|
+
case 'arrowdown':
|
|
103
|
+
if (currentIndex < this._chatState?.messages.length - 1) {
|
|
104
|
+
activeMessageId = this._chatState.sortedMessagesIds[currentIndex + 1];
|
|
105
|
+
}
|
|
106
|
+
break;
|
|
107
|
+
default:
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
this._activeMessageId = `message-${activeMessageId}`;
|
|
111
|
+
this.scrollToMessage(activeMessageId);
|
|
112
|
+
}
|
|
113
|
+
updated() {
|
|
114
|
+
if (!this._chatState?.options?.disableAutoScroll) {
|
|
115
|
+
this.scrollToBottom();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
firstUpdated() {
|
|
119
|
+
if (!this._chatState?.options?.disableAutoScroll) {
|
|
120
|
+
this.scrollToBottom();
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
*renderLoadingTemplate() {
|
|
124
|
+
yield html `${this._chatState?.options?.templates?.composingIndicatorTemplate
|
|
125
|
+
? this._chatState.options.templates.composingIndicatorTemplate
|
|
126
|
+
: html `<div part="typing-indicator">
|
|
127
|
+
<div part="typing-dot"></div>
|
|
128
|
+
<div part="typing-dot"></div>
|
|
129
|
+
<div part="typing-dot"></div>
|
|
130
|
+
</div>`}`;
|
|
131
|
+
}
|
|
132
|
+
render() {
|
|
133
|
+
const groupedMessages = this.groupMessagesByDate(this._chatState?.messages ?? []);
|
|
134
|
+
return html `
|
|
135
|
+
<div
|
|
136
|
+
part="message-container"
|
|
137
|
+
aria-activedescendant=${this._activeMessageId}
|
|
138
|
+
role="group"
|
|
139
|
+
aria-label="Message list"
|
|
140
|
+
tabindex="0"
|
|
141
|
+
@focusin=${this.handleFocusIn}
|
|
142
|
+
@focusout=${this.handleFocusOut}
|
|
143
|
+
></div>
|
|
144
|
+
<div part="message-list">
|
|
145
|
+
${repeat(groupedMessages, (group) => group.date, (group) => html `
|
|
146
|
+
${repeat(group.messages, (message) => message.id, (message) => {
|
|
147
|
+
const messageId = `message-${message.id}`;
|
|
148
|
+
return html `
|
|
149
|
+
<igc-chat-message
|
|
150
|
+
id=${messageId}
|
|
151
|
+
role="option"
|
|
152
|
+
part="message-item ${this._activeMessageId === messageId
|
|
153
|
+
? 'active'
|
|
154
|
+
: ''}"
|
|
155
|
+
.message=${message}
|
|
156
|
+
>
|
|
157
|
+
</igc-chat-message>
|
|
158
|
+
`;
|
|
159
|
+
})}
|
|
160
|
+
`)}
|
|
161
|
+
${this._chatState?.options?.isComposing
|
|
162
|
+
? this.renderLoadingTemplate()
|
|
163
|
+
: nothing}
|
|
164
|
+
</div>
|
|
165
|
+
</div>
|
|
166
|
+
`;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
IgcChatMessageListComponent.tagName = 'igc-chat-message-list';
|
|
170
|
+
IgcChatMessageListComponent.styles = [styles, shared];
|
|
171
|
+
export default IgcChatMessageListComponent;
|
|
172
|
+
__decorate([
|
|
173
|
+
consume({ context: chatContext, subscribe: true })
|
|
174
|
+
], IgcChatMessageListComponent.prototype, "_chatState", void 0);
|
|
175
|
+
__decorate([
|
|
176
|
+
state()
|
|
177
|
+
], IgcChatMessageListComponent.prototype, "_activeMessageId", void 0);
|
|
178
|
+
//# sourceMappingURL=chat-message-list.js.map
|