@progress/kendo-angular-conversational-ui 20.0.0-develop.3 → 20.0.0-develop.5

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.
Files changed (86) hide show
  1. package/chat/api/action.interface.d.ts +1 -1
  2. package/chat/api/attachment.interface.d.ts +1 -1
  3. package/chat/api/chat-file-interface.d.ts +41 -0
  4. package/chat/api/chat-suggestion.interface.d.ts +25 -0
  5. package/chat/api/file-action.d.ts +42 -0
  6. package/chat/api/file-download-event.interface.d.ts +21 -0
  7. package/chat/api/index.d.ts +8 -0
  8. package/chat/api/message-action.d.ts +42 -0
  9. package/{esm2022/chat/chat.directives.mjs → chat/api/message-toolbar-visibility.d.ts} +4 -4
  10. package/chat/api/message-width-mode.d.ts +10 -0
  11. package/chat/api/message.interface.d.ts +30 -12
  12. package/chat/api/send-button-settings.d.ts +15 -0
  13. package/chat/api/user.interface.d.ts +4 -0
  14. package/chat/attachment.component.d.ts +1 -1
  15. package/chat/cards/hero-card.component.d.ts +1 -1
  16. package/chat/chat-file.component.d.ts +34 -0
  17. package/chat/chat-item.d.ts +1 -0
  18. package/chat/chat-view.d.ts +1 -1
  19. package/chat/chat.component.d.ts +218 -19
  20. package/chat/chat.module.d.ts +8 -4
  21. package/chat/common/chat.service.d.ts +51 -0
  22. package/chat/{chat.directives.d.ts → common/models/default-model-fields.d.ts} +5 -4
  23. package/chat/common/models/message-box-options.d.ts +1 -1
  24. package/chat/common/models/model-fields.d.ts +111 -0
  25. package/chat/common/utils.d.ts +50 -0
  26. package/chat/l10n/messages.d.ts +40 -3
  27. package/chat/message-attachments.component.d.ts +1 -4
  28. package/chat/message-box.component.d.ts +54 -25
  29. package/chat/message-list.component.d.ts +18 -11
  30. package/chat/message-reference-content.component.d.ts +24 -0
  31. package/chat/message.component.d.ts +54 -6
  32. package/chat/suggested-actions.component.d.ts +17 -4
  33. package/chat/templates/header-template.directive.d.ts +24 -0
  34. package/chat/{message-box.directive.d.ts → templates/message-box.directive.d.ts} +1 -1
  35. package/chat/templates/status-template.directive.d.ts +24 -0
  36. package/chat/templates/suggestion-template.directive.d.ts +24 -0
  37. package/chat/templates/timestamp-template.directive.d.ts +28 -0
  38. package/codemods/template-transformer/index.js +94 -0
  39. package/codemods/utils.js +609 -0
  40. package/codemods/v20/chat-user.js +50 -0
  41. package/conversational-ui.module.d.ts +11 -7
  42. package/directives.d.ts +9 -5
  43. package/esm2022/chat/api/chat-file-interface.mjs +5 -0
  44. package/esm2022/chat/api/chat-suggestion.interface.mjs +5 -0
  45. package/esm2022/chat/api/file-action.mjs +5 -0
  46. package/esm2022/chat/api/file-download-event.interface.mjs +5 -0
  47. package/esm2022/chat/api/index.mjs +8 -0
  48. package/esm2022/chat/api/message-action.mjs +5 -0
  49. package/esm2022/chat/api/message-toolbar-visibility.mjs +5 -0
  50. package/esm2022/chat/api/message-width-mode.mjs +5 -0
  51. package/esm2022/chat/api/send-button-settings.mjs +5 -0
  52. package/esm2022/chat/attachment.component.mjs +1 -1
  53. package/esm2022/chat/builtin-actions.mjs +1 -1
  54. package/esm2022/chat/cards/hero-card.component.mjs +1 -1
  55. package/esm2022/chat/chat-file.component.mjs +141 -0
  56. package/esm2022/chat/chat-item.mjs +1 -0
  57. package/esm2022/chat/chat-view.mjs +2 -2
  58. package/esm2022/chat/chat.component.mjs +518 -57
  59. package/esm2022/chat/chat.module.mjs +8 -4
  60. package/esm2022/chat/common/chat.service.mjs +97 -0
  61. package/esm2022/chat/common/models/default-model-fields.mjs +26 -0
  62. package/esm2022/chat/common/models/model-fields.mjs +5 -0
  63. package/esm2022/chat/common/utils.mjs +127 -0
  64. package/esm2022/chat/l10n/messages.mjs +60 -5
  65. package/esm2022/chat/message-attachments.component.mjs +1 -4
  66. package/esm2022/chat/message-box.component.mjs +360 -111
  67. package/esm2022/chat/message-list.component.mjs +166 -96
  68. package/esm2022/chat/message-reference-content.component.mjs +75 -0
  69. package/esm2022/chat/message.component.mjs +448 -35
  70. package/esm2022/chat/suggested-actions.component.mjs +151 -41
  71. package/esm2022/chat/templates/header-template.directive.mjs +33 -0
  72. package/esm2022/chat/{message-box.directive.mjs → templates/message-box.directive.mjs} +1 -1
  73. package/esm2022/chat/templates/status-template.directive.mjs +33 -0
  74. package/esm2022/chat/templates/suggestion-template.directive.mjs +33 -0
  75. package/esm2022/chat/templates/timestamp-template.directive.mjs +39 -0
  76. package/esm2022/conversational-ui.module.mjs +12 -8
  77. package/esm2022/directives.mjs +12 -4
  78. package/esm2022/index.mjs +9 -3
  79. package/esm2022/package-metadata.mjs +2 -2
  80. package/fesm2022/progress-kendo-angular-conversational-ui.mjs +4986 -3125
  81. package/index.d.ts +10 -3
  82. package/package.json +29 -12
  83. /package/chat/{attachment-template.directive.d.ts → templates/attachment-template.directive.d.ts} +0 -0
  84. /package/chat/{message-template.directive.d.ts → templates/message-template.directive.d.ts} +0 -0
  85. /package/esm2022/chat/{attachment-template.directive.mjs → templates/attachment-template.directive.mjs} +0 -0
  86. /package/esm2022/chat/{message-template.directive.mjs → templates/message-template.directive.mjs} +0 -0
@@ -2,62 +2,104 @@
2
2
  * Copyright © 2025 Progress Software Corporation. All rights reserved.
3
3
  * Licensed under commercial license. See LICENSE.md in the project root for more information
4
4
  *-------------------------------------------------------------------------------------------*/
5
- import { Component, EventEmitter, HostBinding, Input, Output, ViewChild } from '@angular/core';
6
- import { NgIf, NgTemplateOutlet } from '@angular/common';
5
+ import { ChangeDetectorRef, Component, ElementRef, EventEmitter, HostBinding, Input, Output, Renderer2, ViewChild } from '@angular/core';
6
+ import { NgIf, NgFor, NgTemplateOutlet } from '@angular/common';
7
7
  import { LocalizationService } from '@progress/kendo-angular-l10n';
8
- import { Keys } from '@progress/kendo-angular-common';
9
- import { paperPlaneIcon } from '@progress/kendo-svg-icons';
10
- import { ButtonComponent } from '@progress/kendo-angular-buttons';
8
+ import { closest, isPresent, Keys } from '@progress/kendo-angular-common';
9
+ import { paperPlaneIcon, paperclipIcon, fileIcon, xIcon } from '@progress/kendo-svg-icons';
10
+ import { ButtonComponent, SpeechToTextButtonComponent } from '@progress/kendo-angular-buttons';
11
11
  import { SendMessageEvent } from './api/post-message-event';
12
- import { ChatMessageBoxTemplateDirective } from './message-box.directive';
13
- import { InputSeparatorComponent, TextAreaComponent, TextAreaSuffixComponent, TextBoxComponent, TextBoxSuffixTemplateDirective } from '@progress/kendo-angular-inputs';
12
+ import { ChatMessageBoxTemplateDirective } from './templates/message-box.directive';
13
+ import { InputSpacerComponent, TextAreaComponent, TextAreaPrefixComponent, TextAreaSuffixComponent } from '@progress/kendo-angular-inputs';
14
+ import { FileSelectComponent } from '@progress/kendo-angular-upload';
15
+ import { FormsModule } from '@angular/forms';
16
+ import { ChatService } from './common/chat.service';
17
+ import { SuggestedActionsComponent } from "./suggested-actions.component";
18
+ import { Subscription } from 'rxjs';
19
+ import { ChatFileComponent } from './chat-file.component';
20
+ import { MessageReferenceComponent } from './message-reference-content.component';
21
+ import { ChatSuggestionTemplateDirective } from './templates/suggestion-template.directive';
14
22
  import * as i0 from "@angular/core";
23
+ import * as i1 from "./common/chat.service";
15
24
  /**
16
25
  * @hidden
17
26
  */
18
27
  export class MessageBoxComponent {
28
+ chatService;
29
+ cdr;
30
+ element;
31
+ renderer;
19
32
  borderColor = 'inherit';
33
+ messageBoxWrapperClass = true;
20
34
  messageBoxInput;
21
- user;
35
+ fileSelectComponent;
36
+ suggestedActionsComponent;
37
+ authorId;
22
38
  autoScroll;
23
- type;
39
+ suggestions;
40
+ placeholder;
41
+ inputValue = '';
24
42
  localization;
25
43
  messageBoxTemplate;
44
+ suggestionTemplate;
26
45
  sendMessage = new EventEmitter();
27
- /**
28
- * @hidden
29
- */
46
+ executeSuggestion = new EventEmitter();
47
+ fileSelect = new EventEmitter();
48
+ fileRemove = new EventEmitter();
49
+ files = [];
30
50
  sendIcon = paperPlaneIcon;
31
- /**
32
- * @hidden
33
- */
51
+ attachmentIcon = paperclipIcon;
52
+ deleteIcon = xIcon;
53
+ fileIcon = fileIcon;
54
+ isListening = false;
55
+ get reply() {
56
+ return this.chatService.reply;
57
+ }
58
+ selectedItem;
59
+ subs = new Subscription();
60
+ constructor(chatService, cdr, element, renderer) {
61
+ this.chatService = chatService;
62
+ this.cdr = cdr;
63
+ this.element = element;
64
+ this.renderer = renderer;
65
+ }
66
+ ngOnInit() {
67
+ const elRef = this.element.nativeElement;
68
+ this.subs.add(this.renderer.listen(elRef, 'focusout', event => this.onBlur(event)));
69
+ this.subs.add(this.chatService.contextMenuAction$.subscribe((action) => {
70
+ action.action.id === 'reply' && this.messageBoxInput.focus();
71
+ }));
72
+ }
73
+ ngOnDestroy() {
74
+ if (this.subs) {
75
+ this.subs.unsubscribe();
76
+ }
77
+ }
34
78
  sendClick() {
35
- const input = this.messageBoxInput;
36
- const value = input.value;
37
- if (!value) {
79
+ const hasMessage = this.inputValue?.trim() || this.files?.length;
80
+ const isCustomDisabled = isPresent(this.sendButtonSettings?.disabled);
81
+ if (!hasMessage && !isCustomDisabled) {
38
82
  return;
39
83
  }
40
84
  const message = {
41
- author: this.user,
42
- text: value,
43
- timestamp: new Date()
85
+ text: this.inputValue,
86
+ timestamp: new Date(),
87
+ author: { id: this.authorId },
88
+ ...(this.files && this.files.length > 0 && { files: this.files }),
89
+ ...(this.reply && { replyToId: this.reply.id })
44
90
  };
45
91
  this.sendMessage.emit(new SendMessageEvent(message));
46
- input.value = null;
47
- input.focus();
92
+ this.inputValue = '';
93
+ this.files = [];
94
+ this.chatService.reply = null;
95
+ this.messageBoxInput.focus();
48
96
  this.autoScroll = true;
49
97
  }
50
- /**
51
- * @hidden
52
- */
53
98
  inputKeydown(e) {
54
99
  if (e.code === Keys.Enter || e.code === Keys.NumpadEnter) {
55
100
  this.sendClick();
56
101
  }
57
102
  }
58
- /**
59
- * @hidden
60
- */
61
103
  textAreaKeydown(e) {
62
104
  const isEnter = e.code === Keys.Enter || e.code === Keys.NumpadEnter;
63
105
  if (!isEnter) {
@@ -70,66 +112,197 @@ export class MessageBoxComponent {
70
112
  this.sendClick();
71
113
  }
72
114
  if (newLine) {
73
- this.messageBoxInput.value += `\r\n`;
115
+ this.inputValue += `\r\n`;
116
+ }
117
+ }
118
+ handleSpeechResult(event) {
119
+ if (event.alternatives && event.alternatives.length > 0) {
120
+ if (!isPresent(this.inputValue)) {
121
+ this.inputValue = '';
122
+ }
123
+ const appendedValue = event.alternatives[0].transcript + ' ';
124
+ if (!appendedValue.trim()) {
125
+ return;
126
+ }
127
+ this.inputValue += appendedValue;
128
+ this.chatService.emit('inputValueChange', this.inputValue);
74
129
  }
75
130
  }
76
- /**
77
- * @hidden
78
- */
79
131
  textFor(key) {
80
132
  return this.localization.get(key);
81
133
  }
82
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: MessageBoxComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
83
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: MessageBoxComponent, isStandalone: true, selector: "kendo-message-box", inputs: { user: "user", autoScroll: "autoScroll", type: "type", localization: "localization", messageBoxTemplate: "messageBoxTemplate" }, outputs: { sendMessage: "sendMessage" }, host: { properties: { "style.border-color": "this.borderColor" } }, viewQueries: [{ propertyName: "messageBoxInput", first: true, predicate: ["messageBoxInput"], descendants: true }], ngImport: i0, template: `
84
- <ng-container *ngIf="!messageBoxTemplate">
85
- <kendo-textbox
86
- *ngIf="type === 'textbox'"
87
- #messageBoxInput
88
- class="k-message-box"
89
- [inputAttributes]="{
90
- 'aria-label': textFor('messageBoxInputLabel')
91
- }"
92
- [placeholder]="textFor('messagePlaceholder')"
93
- (keydown)="inputKeydown($event)"
94
- >
95
- <ng-template kendoTextBoxSuffixTemplate>
96
- <kendo-textbox-separator></kendo-textbox-separator>
97
- <button
98
- kendoButton
99
- fillMode="flat"
100
- class="k-chat-send"
101
- icon="paper-plane"
102
- [svgIcon]="sendIcon"
103
- [tabindex]="0"
104
- [attr.title]="textFor('send')"
105
- (click)="sendClick()"
106
- >
107
- </button>
108
- </ng-template>
109
- </kendo-textbox>
134
+ removeReply() {
135
+ this.chatService.reply = null;
136
+ }
137
+ onReplyReferenceClick(event) {
138
+ event.stopPropagation();
139
+ this.chatService.emit('replyReferenceClick', this.chatService.reply?.id);
140
+ }
141
+ handleFileSelect(event) {
142
+ const processedFiles = event.files.map(currentFile => {
143
+ return {
144
+ id: currentFile.uid,
145
+ name: currentFile.name,
146
+ extension: currentFile.extension,
147
+ size: currentFile.size,
148
+ type: currentFile.rawFile.type,
149
+ rawFile: currentFile.rawFile
150
+ };
151
+ });
152
+ this.files = [...this.files, ...processedFiles];
153
+ this.fileSelect.emit(event);
154
+ }
155
+ selectFiles() {
156
+ if (this.fileSelectComponent?.fileSelectInput) {
157
+ this.fileSelectComponent.fileSelectInput.nativeElement.click();
158
+ }
159
+ }
160
+ removeFile(index) {
161
+ this.files = this.files.filter((_, i) => i !== index);
162
+ const removedFile = this.files[index];
163
+ this.fileRemove.emit(removedFile);
164
+ }
165
+ get speechToTextButtonSettings() {
166
+ return this.chatService.enableSpeechToText;
167
+ }
168
+ get sendButtonSettings() {
169
+ return this.chatService.sendButtonSettings;
170
+ }
171
+ get enableFileSelect() {
172
+ return this.chatService.enableFileSelect;
173
+ }
174
+ get isDisabledSendButton() {
175
+ if (isPresent(this.sendButtonSettings?.disabled)) {
176
+ return this.sendButtonSettings.disabled;
177
+ }
178
+ const isEmptyInput = !this.inputValue?.length || !this.inputValue?.trim();
179
+ const hasFiles = this.files?.length > 0;
180
+ return (isEmptyInput && !hasFiles) || this.isListening;
181
+ }
182
+ select(item, event) {
183
+ if (event) {
184
+ const target = event.target;
185
+ if (!target.classList.contains('k-suggestion')) {
186
+ return;
187
+ }
188
+ }
189
+ if (!this.chatService.toggleMessageState) {
190
+ const prevItem = this.selectedItem;
191
+ if (prevItem) {
192
+ prevItem.selected = false;
193
+ }
194
+ if (item) {
195
+ item.selected = true;
196
+ this.selectedItem = item;
197
+ }
198
+ this.cdr.detectChanges();
199
+ }
200
+ this.chatService.toggleMessageState = false;
201
+ }
202
+ onBlur(args) {
203
+ const next = args.relatedTarget || document.activeElement;
204
+ const outside = !closest(next, (node) => node === this.element.nativeElement);
205
+ if (outside) {
206
+ this.select(null);
207
+ }
208
+ }
209
+ onInputValueChange(value) {
210
+ this.inputValue = value;
211
+ this.chatService.emit('inputValueChange', value);
212
+ }
213
+ dispatchSuggestion(suggestion) {
214
+ this.executeSuggestion.emit(suggestion);
215
+ }
216
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: MessageBoxComponent, deps: [{ token: i1.ChatService }, { token: i0.ChangeDetectorRef }, { token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Component });
217
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: MessageBoxComponent, isStandalone: true, selector: "kendo-message-box", inputs: { authorId: "authorId", autoScroll: "autoScroll", suggestions: "suggestions", placeholder: "placeholder", inputValue: "inputValue", localization: "localization", messageBoxTemplate: "messageBoxTemplate", suggestionTemplate: "suggestionTemplate" }, outputs: { sendMessage: "sendMessage", executeSuggestion: "executeSuggestion", fileSelect: "fileSelect", fileRemove: "fileRemove" }, host: { properties: { "style.border-color": "this.borderColor", "class.k-message-box-wrapper": "this.messageBoxWrapperClass" } }, viewQueries: [{ propertyName: "messageBoxInput", first: true, predicate: ["messageBoxInput"], descendants: true }, { propertyName: "fileSelectComponent", first: true, predicate: ["fileSelect"], descendants: true }, { propertyName: "suggestedActionsComponent", first: true, predicate: SuggestedActionsComponent, descendants: true }], ngImport: i0, template: `
218
+ <kendo-chat-suggested-actions
219
+ *ngIf="suggestions?.length > 0"
220
+ #suggestedActions
221
+ [suggestions]="suggestions"
222
+ [suggestionTemplate]="suggestionTemplate"
223
+ [tabbable]="true"
224
+ (dispatchSuggestion)="dispatchSuggestion($event)"
225
+ (click)="select(suggestedActions, $event)"
226
+ (focus)="select(suggestedActions, $event)"
227
+ ></kendo-chat-suggested-actions>
110
228
 
229
+ <ng-container *ngIf="!messageBoxTemplate?.templateRef">
111
230
  <kendo-textarea
112
- *ngIf="type === 'textarea'"
113
231
  #messageBoxInput
114
- class="k-message-box !k-align-items-end"
232
+ class="k-message-box"
115
233
  resizable="none"
116
234
  [rows]="3"
117
235
  [inputAttributes]="{
118
236
  'aria-label': textFor('messageBoxInputLabel')
119
237
  }"
120
- [placeholder]="textFor('messagePlaceholder')"
121
- [showSuffixSeparator]="true"
238
+ [placeholder]="placeholder || textFor('messagePlaceholder')"
239
+ [showSuffixSeparator]="false"
122
240
  (keydown)="textAreaKeydown($event)"
241
+ [value]="inputValue"
242
+ (valueChange)="onInputValueChange($event)"
123
243
  >
244
+ <kendo-textarea-prefix *ngIf="reply || (files && files.length > 0)">
245
+ <div class="k-message-reference k-message-reference-sender" *ngIf="reply" (click)="onReplyReferenceClick($event)">
246
+ <chat-message-reference-content [message]="reply"></chat-message-reference-content>
247
+ <span class="k-spacer"></span>
248
+ <button
249
+ kendoButton
250
+ [attr.title]="textFor('removeReplyTitle')"
251
+ [svgIcon]="deleteIcon"
252
+ (click)="removeReply()"
253
+ fillMode="flat"
254
+ ></button>
255
+ </div>
256
+ <ul class="k-chat-file-wrapper">
257
+ <li class="k-chat-file"
258
+ *ngFor="let file of files; let i = index"
259
+ [chatFile]="file"
260
+ [removable]="true"
261
+ (remove)="removeFile(i)"
262
+ ></li>
263
+ </ul>
264
+ </kendo-textarea-prefix>
265
+
124
266
  <kendo-textarea-suffix>
267
+ <button *ngIf="speechToTextButtonSettings"
268
+ kendoSpeechToTextButton
269
+ [attr.title]="textFor('speechToTextButtonTitle')"
270
+ [continuous]="speechToTextButtonSettings?.continuous"
271
+ [disabled]="speechToTextButtonSettings?.disabled"
272
+ [fillMode]="speechToTextButtonSettings?.fillMode ?? 'clear'"
273
+ [integrationMode]="speechToTextButtonSettings?.integrationMode ?? 'webSpeech'"
274
+ [interimResults]="speechToTextButtonSettings?.interimResults"
275
+ [lang]="speechToTextButtonSettings?.lang"
276
+ [maxAlternatives]="speechToTextButtonSettings?.maxAlternatives"
277
+ [rounded]="speechToTextButtonSettings?.rounded"
278
+ [size]="speechToTextButtonSettings?.size"
279
+ [themeColor]="speechToTextButtonSettings?.themeColor"
280
+ (result)="handleSpeechResult($event)"
281
+ (start)="isListening = true"
282
+ (end)="isListening = false"
283
+ ></button>
125
284
  <button
126
285
  kendoButton
127
- fillMode="flat"
128
- class="k-chat-send"
129
- icon="paper-plane"
130
- [svgIcon]="sendIcon"
286
+ *ngIf="enableFileSelect"
287
+ [attr.title]="textFor('fileSelectButtonTitle')"
288
+ [svgIcon]="attachmentIcon"
289
+ icon="attachment"
290
+ fillMode="clear"
291
+ (click)="selectFiles()"
292
+ ></button>
293
+ <kendo-input-spacer></kendo-input-spacer>
294
+ <button
295
+ kendoButton
296
+ [fillMode]="sendButtonSettings?.fillMode"
297
+ [themeColor]="sendButtonSettings?.themeColor"
298
+ [rounded]="sendButtonSettings?.rounded"
299
+ [class]="sendButtonSettings?.buttonClass || 'k-chat-send'"
300
+ [icon]="sendButtonSettings?.icon"
301
+ [svgIcon]="sendButtonSettings?.svgIcon"
131
302
  [tabindex]="0"
132
303
  [attr.title]="textFor('send')"
304
+ [class.k-disabled]="isDisabledSendButton"
305
+ [attr.aria-disabled]="isDisabledSendButton"
133
306
  (click)="sendClick()"
134
307
  >
135
308
  </button>
@@ -137,63 +310,110 @@ export class MessageBoxComponent {
137
310
  </kendo-textarea>
138
311
  </ng-container>
139
312
 
140
- <ng-template *ngIf="messageBoxTemplate" [ngTemplateOutlet]="messageBoxTemplate?.templateRef"></ng-template>
141
- `, isInline: true, dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: TextBoxComponent, selector: "kendo-textbox", inputs: ["focusableId", "title", "type", "disabled", "readonly", "tabindex", "value", "selectOnFocus", "showSuccessIcon", "showErrorIcon", "clearButton", "successIcon", "successSvgIcon", "errorIcon", "errorSvgIcon", "clearButtonIcon", "clearButtonSvgIcon", "size", "rounded", "fillMode", "tabIndex", "placeholder", "maxlength", "inputAttributes"], outputs: ["valueChange", "inputFocus", "inputBlur", "focus", "blur"], exportAs: ["kendoTextBox"] }, { kind: "component", type: TextAreaComponent, selector: "kendo-textarea", inputs: ["focusableId", "flow", "inputAttributes", "adornmentsOrientation", "rows", "cols", "maxlength", "maxResizableRows", "tabindex", "tabIndex", "resizable", "size", "rounded", "fillMode", "showPrefixSeparator", "showSuffixSeparator"], outputs: ["focus", "blur", "valueChange"], exportAs: ["kendoTextArea"] }, { kind: "component", type: InputSeparatorComponent, selector: "kendo-input-separator, kendo-textbox-separator", inputs: ["orientation"] }, { kind: "directive", type: TextBoxSuffixTemplateDirective, selector: "[kendoTextBoxSuffixTemplate]", inputs: ["showSeparator"] }, { kind: "component", type: TextAreaSuffixComponent, selector: "kendo-textarea-suffix", inputs: ["flow", "orientation"], exportAs: ["kendoTextAreaSuffix"] }] });
313
+ <ng-template *ngIf="messageBoxTemplate?.templateRef" [ngTemplateOutlet]="messageBoxTemplate?.templateRef"></ng-template>
314
+
315
+ <kendo-fileselect
316
+ #fileSelect
317
+ class="k-hidden"
318
+ [multiple]="true"
319
+ [showFileList]="false"
320
+ (select)="handleFileSelect($event)"
321
+ ></kendo-fileselect>
322
+ `, isInline: true, dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: TextAreaComponent, selector: "kendo-textarea", inputs: ["focusableId", "flow", "inputAttributes", "adornmentsOrientation", "rows", "cols", "maxlength", "maxResizableRows", "tabindex", "tabIndex", "resizable", "size", "rounded", "fillMode", "showPrefixSeparator", "showSuffixSeparator"], outputs: ["focus", "blur", "valueChange"], exportAs: ["kendoTextArea"] }, { kind: "component", type: MessageReferenceComponent, selector: "chat-message-reference-content", inputs: ["message"] }, { kind: "component", type: TextAreaSuffixComponent, selector: "kendo-textarea-suffix", inputs: ["flow", "orientation"], exportAs: ["kendoTextAreaSuffix"] }, { kind: "component", type: TextAreaPrefixComponent, selector: "kendo-textarea-prefix", inputs: ["flow", "orientation"], exportAs: ["kendoTextAreaPrefix"] }, { kind: "component", type: SpeechToTextButtonComponent, selector: "button[kendoSpeechToTextButton]", inputs: ["disabled", "size", "rounded", "fillMode", "themeColor", "integrationMode", "lang", "continuous", "interimResults", "maxAlternatives"], outputs: ["start", "end", "result", "error", "click"], exportAs: ["kendoSpeechToTextButton"] }, { kind: "component", type: InputSpacerComponent, selector: "kendo-input-spacer, kendo-textbox-spacer", inputs: ["width"] }, { kind: "component", type: FileSelectComponent, selector: "kendo-fileselect", inputs: ["name"], outputs: ["valueChange"], exportAs: ["kendoFileSelect"] }, { kind: "component", type: SuggestedActionsComponent, selector: "kendo-chat-suggested-actions", inputs: ["actions", "suggestions", "tabbable", "suggestionTemplate"], outputs: ["dispatchAction", "dispatchSuggestion"] }, { kind: "component", type: ChatFileComponent, selector: "li[chatFile]", inputs: ["chatFile", "removable", "fileActions"], outputs: ["remove", "actionClick", "actionsToggle", "actionButtonClick"] }] });
142
323
  }
143
324
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: MessageBoxComponent, decorators: [{
144
325
  type: Component,
145
326
  args: [{
146
327
  selector: 'kendo-message-box',
147
328
  template: `
148
- <ng-container *ngIf="!messageBoxTemplate">
149
- <kendo-textbox
150
- *ngIf="type === 'textbox'"
151
- #messageBoxInput
152
- class="k-message-box"
153
- [inputAttributes]="{
154
- 'aria-label': textFor('messageBoxInputLabel')
155
- }"
156
- [placeholder]="textFor('messagePlaceholder')"
157
- (keydown)="inputKeydown($event)"
158
- >
159
- <ng-template kendoTextBoxSuffixTemplate>
160
- <kendo-textbox-separator></kendo-textbox-separator>
161
- <button
162
- kendoButton
163
- fillMode="flat"
164
- class="k-chat-send"
165
- icon="paper-plane"
166
- [svgIcon]="sendIcon"
167
- [tabindex]="0"
168
- [attr.title]="textFor('send')"
169
- (click)="sendClick()"
170
- >
171
- </button>
172
- </ng-template>
173
- </kendo-textbox>
329
+ <kendo-chat-suggested-actions
330
+ *ngIf="suggestions?.length > 0"
331
+ #suggestedActions
332
+ [suggestions]="suggestions"
333
+ [suggestionTemplate]="suggestionTemplate"
334
+ [tabbable]="true"
335
+ (dispatchSuggestion)="dispatchSuggestion($event)"
336
+ (click)="select(suggestedActions, $event)"
337
+ (focus)="select(suggestedActions, $event)"
338
+ ></kendo-chat-suggested-actions>
174
339
 
340
+ <ng-container *ngIf="!messageBoxTemplate?.templateRef">
175
341
  <kendo-textarea
176
- *ngIf="type === 'textarea'"
177
342
  #messageBoxInput
178
- class="k-message-box !k-align-items-end"
343
+ class="k-message-box"
179
344
  resizable="none"
180
345
  [rows]="3"
181
346
  [inputAttributes]="{
182
347
  'aria-label': textFor('messageBoxInputLabel')
183
348
  }"
184
- [placeholder]="textFor('messagePlaceholder')"
185
- [showSuffixSeparator]="true"
349
+ [placeholder]="placeholder || textFor('messagePlaceholder')"
350
+ [showSuffixSeparator]="false"
186
351
  (keydown)="textAreaKeydown($event)"
352
+ [value]="inputValue"
353
+ (valueChange)="onInputValueChange($event)"
187
354
  >
355
+ <kendo-textarea-prefix *ngIf="reply || (files && files.length > 0)">
356
+ <div class="k-message-reference k-message-reference-sender" *ngIf="reply" (click)="onReplyReferenceClick($event)">
357
+ <chat-message-reference-content [message]="reply"></chat-message-reference-content>
358
+ <span class="k-spacer"></span>
359
+ <button
360
+ kendoButton
361
+ [attr.title]="textFor('removeReplyTitle')"
362
+ [svgIcon]="deleteIcon"
363
+ (click)="removeReply()"
364
+ fillMode="flat"
365
+ ></button>
366
+ </div>
367
+ <ul class="k-chat-file-wrapper">
368
+ <li class="k-chat-file"
369
+ *ngFor="let file of files; let i = index"
370
+ [chatFile]="file"
371
+ [removable]="true"
372
+ (remove)="removeFile(i)"
373
+ ></li>
374
+ </ul>
375
+ </kendo-textarea-prefix>
376
+
188
377
  <kendo-textarea-suffix>
378
+ <button *ngIf="speechToTextButtonSettings"
379
+ kendoSpeechToTextButton
380
+ [attr.title]="textFor('speechToTextButtonTitle')"
381
+ [continuous]="speechToTextButtonSettings?.continuous"
382
+ [disabled]="speechToTextButtonSettings?.disabled"
383
+ [fillMode]="speechToTextButtonSettings?.fillMode ?? 'clear'"
384
+ [integrationMode]="speechToTextButtonSettings?.integrationMode ?? 'webSpeech'"
385
+ [interimResults]="speechToTextButtonSettings?.interimResults"
386
+ [lang]="speechToTextButtonSettings?.lang"
387
+ [maxAlternatives]="speechToTextButtonSettings?.maxAlternatives"
388
+ [rounded]="speechToTextButtonSettings?.rounded"
389
+ [size]="speechToTextButtonSettings?.size"
390
+ [themeColor]="speechToTextButtonSettings?.themeColor"
391
+ (result)="handleSpeechResult($event)"
392
+ (start)="isListening = true"
393
+ (end)="isListening = false"
394
+ ></button>
189
395
  <button
190
396
  kendoButton
191
- fillMode="flat"
192
- class="k-chat-send"
193
- icon="paper-plane"
194
- [svgIcon]="sendIcon"
397
+ *ngIf="enableFileSelect"
398
+ [attr.title]="textFor('fileSelectButtonTitle')"
399
+ [svgIcon]="attachmentIcon"
400
+ icon="attachment"
401
+ fillMode="clear"
402
+ (click)="selectFiles()"
403
+ ></button>
404
+ <kendo-input-spacer></kendo-input-spacer>
405
+ <button
406
+ kendoButton
407
+ [fillMode]="sendButtonSettings?.fillMode"
408
+ [themeColor]="sendButtonSettings?.themeColor"
409
+ [rounded]="sendButtonSettings?.rounded"
410
+ [class]="sendButtonSettings?.buttonClass || 'k-chat-send'"
411
+ [icon]="sendButtonSettings?.icon"
412
+ [svgIcon]="sendButtonSettings?.svgIcon"
195
413
  [tabindex]="0"
196
414
  [attr.title]="textFor('send')"
415
+ [class.k-disabled]="isDisabledSendButton"
416
+ [attr.aria-disabled]="isDisabledSendButton"
197
417
  (click)="sendClick()"
198
418
  >
199
419
  </button>
@@ -201,27 +421,56 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
201
421
  </kendo-textarea>
202
422
  </ng-container>
203
423
 
204
- <ng-template *ngIf="messageBoxTemplate" [ngTemplateOutlet]="messageBoxTemplate?.templateRef"></ng-template>
424
+ <ng-template *ngIf="messageBoxTemplate?.templateRef" [ngTemplateOutlet]="messageBoxTemplate?.templateRef"></ng-template>
425
+
426
+ <kendo-fileselect
427
+ #fileSelect
428
+ class="k-hidden"
429
+ [multiple]="true"
430
+ [showFileList]="false"
431
+ (select)="handleFileSelect($event)"
432
+ ></kendo-fileselect>
205
433
  `,
206
434
  standalone: true,
207
- imports: [NgIf, ButtonComponent, NgTemplateOutlet, TextBoxComponent, TextAreaComponent, InputSeparatorComponent, TextBoxSuffixTemplateDirective, TextAreaSuffixComponent]
435
+ imports: [NgIf, NgFor, ButtonComponent, FormsModule, NgTemplateOutlet, TextAreaComponent, MessageReferenceComponent, TextAreaSuffixComponent, TextAreaPrefixComponent, SpeechToTextButtonComponent, InputSpacerComponent, FileSelectComponent, SuggestedActionsComponent, ChatFileComponent]
208
436
  }]
209
- }], propDecorators: { borderColor: [{
437
+ }], ctorParameters: function () { return [{ type: i1.ChatService }, { type: i0.ChangeDetectorRef }, { type: i0.ElementRef }, { type: i0.Renderer2 }]; }, propDecorators: { borderColor: [{
210
438
  type: HostBinding,
211
439
  args: ['style.border-color']
440
+ }], messageBoxWrapperClass: [{
441
+ type: HostBinding,
442
+ args: ['class.k-message-box-wrapper']
212
443
  }], messageBoxInput: [{
213
444
  type: ViewChild,
214
- args: ['messageBoxInput', { static: false }]
215
- }], user: [{
445
+ args: ['messageBoxInput']
446
+ }], fileSelectComponent: [{
447
+ type: ViewChild,
448
+ args: ['fileSelect']
449
+ }], suggestedActionsComponent: [{
450
+ type: ViewChild,
451
+ args: [SuggestedActionsComponent]
452
+ }], authorId: [{
216
453
  type: Input
217
454
  }], autoScroll: [{
218
455
  type: Input
219
- }], type: [{
456
+ }], suggestions: [{
457
+ type: Input
458
+ }], placeholder: [{
459
+ type: Input
460
+ }], inputValue: [{
220
461
  type: Input
221
462
  }], localization: [{
222
463
  type: Input
223
464
  }], messageBoxTemplate: [{
224
465
  type: Input
466
+ }], suggestionTemplate: [{
467
+ type: Input
225
468
  }], sendMessage: [{
226
469
  type: Output
470
+ }], executeSuggestion: [{
471
+ type: Output
472
+ }], fileSelect: [{
473
+ type: Output
474
+ }], fileRemove: [{
475
+ type: Output
227
476
  }] } });