@progress/kendo-angular-conversational-ui 20.0.0-develop.4 → 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
@@ -4,24 +4,28 @@
4
4
  *-------------------------------------------------------------------------------------------*/
5
5
  /* eslint-disable @typescript-eslint/no-unused-vars */
6
6
  /* eslint-disable @typescript-eslint/no-explicit-any */
7
- import { Component, ElementRef, EventEmitter, HostBinding, Input, Output, QueryList, Renderer2, ViewChildren } from '@angular/core';
8
- import { NgFor, NgSwitch, NgSwitchCase, NgIf } from '@angular/common';
7
+ import { ChangeDetectorRef, Component, ElementRef, EventEmitter, HostBinding, Input, Output, QueryList, Renderer2, ViewChildren } from '@angular/core';
8
+ import { NgFor, NgSwitch, NgSwitchCase, NgIf, NgTemplateOutlet } from '@angular/common';
9
9
  import { ExecuteActionEvent } from './api';
10
10
  import { Keys, normalizeNumpadKeys, ResizeSensorComponent } from '@progress/kendo-angular-common';
11
11
  import { IntlService } from '@progress/kendo-angular-intl';
12
12
  import { LocalizationService } from '@progress/kendo-angular-l10n';
13
- import { closest } from './common/utils';
13
+ import { closest, DOWNLOAD_ALL_SELECTOR, FILE_ACTION_BTN_SELECTOR } from './common/utils';
14
14
  import { ChatItem } from './chat-item';
15
15
  import { chatView, isAuthor } from './chat-view';
16
- import { AttachmentTemplateDirective } from './attachment-template.directive';
17
- import { MessageTemplateDirective } from './message-template.directive';
16
+ import { AttachmentTemplateDirective } from './templates/attachment-template.directive';
17
+ import { MessageTemplateDirective } from './templates/message-template.directive';
18
+ import { ChatTimestampTemplateDirective } from './templates/timestamp-template.directive';
18
19
  import { Subscription } from 'rxjs';
19
20
  import { SuggestedActionsComponent } from './suggested-actions.component';
20
21
  import { MessageComponent } from './message.component';
21
22
  import { MessageAttachmentsComponent } from './message-attachments.component';
22
23
  import { AttachmentComponent } from './attachment.component';
24
+ import { ChatService } from './common/chat.service';
25
+ import { ChatStatusTemplateDirective } from './templates/status-template.directive';
23
26
  import * as i0 from "@angular/core";
24
27
  import * as i1 from "@progress/kendo-angular-intl";
28
+ import * as i2 from "./common/chat.service";
25
29
  /**
26
30
  * @hidden
27
31
  */
@@ -29,6 +33,8 @@ export class MessageListComponent {
29
33
  element;
30
34
  intl;
31
35
  renderer;
36
+ chatService;
37
+ cdr;
32
38
  set messages(value) {
33
39
  const data = value || [];
34
40
  this.view = chatView(data);
@@ -39,8 +45,10 @@ export class MessageListComponent {
39
45
  }
40
46
  attachmentTemplate;
41
47
  messageTemplate;
48
+ timestampTemplate;
49
+ statusTemplate;
42
50
  localization;
43
- user;
51
+ authorId;
44
52
  executeAction = new EventEmitter();
45
53
  navigate = new EventEmitter();
46
54
  resize = new EventEmitter();
@@ -57,15 +65,20 @@ export class MessageListComponent {
57
65
  [Keys.ArrowDown]: (e) => this.navigateTo(e, 1),
58
66
  [Keys.Tab]: (e) => this.onTabKeyDown(e),
59
67
  };
60
- constructor(element, intl, renderer) {
68
+ constructor(element, intl, renderer, chatService, cdr) {
61
69
  this.element = element;
62
70
  this.intl = intl;
63
71
  this.renderer = renderer;
72
+ this.chatService = chatService;
73
+ this.cdr = cdr;
64
74
  }
65
75
  ngOnInit() {
66
76
  const elRef = this.element.nativeElement;
67
77
  this.subs.add(this.renderer.listen(elRef, 'keydown', event => this.onKeydown(event)));
68
78
  this.subs.add(this.renderer.listen(elRef, 'focusout', event => this.onBlur(event)));
79
+ this.subs.add(this.chatService.replyReferenceClick$.subscribe((messageId) => {
80
+ this.scrollToAndSelectMessage(messageId);
81
+ }));
69
82
  }
70
83
  ngAfterViewInit() {
71
84
  this.selectedItem = this.items.last;
@@ -76,6 +89,9 @@ export class MessageListComponent {
76
89
  onResize() {
77
90
  this.resize.emit();
78
91
  }
92
+ onClick(message, event) {
93
+ this.select(message, event);
94
+ }
79
95
  formatTimeStamp(date) {
80
96
  return this.intl.formatDate(date, { date: 'full' });
81
97
  }
@@ -90,12 +106,13 @@ export class MessageListComponent {
90
106
  onBlur(args) {
91
107
  const next = args.relatedTarget || document.activeElement;
92
108
  const outside = !closest(next, (node) => node === this.element.nativeElement);
93
- if (outside) {
109
+ const isActionClick = closest(next, (node) => node?.classList?.contains('k-context-menu-popup')) || closest(next, (node) => node?.classList?.contains('k-menu-popup'));
110
+ if (outside && !isActionClick) {
94
111
  this.select(null);
95
112
  }
96
113
  }
97
114
  isOwnMessage(msg) {
98
- return isAuthor(this.user, msg);
115
+ return isAuthor(this.authorId, msg);
99
116
  }
100
117
  dispatchAction(action, message) {
101
118
  const args = new ExecuteActionEvent(action, message);
@@ -104,21 +121,38 @@ export class MessageListComponent {
104
121
  trackGroup(_index, item) {
105
122
  return item.trackBy;
106
123
  }
107
- select(item) {
108
- const prevItem = this.selectedItem;
109
- if (prevItem) {
110
- prevItem.selected = false;
124
+ select(item, event) {
125
+ if (event) {
126
+ const target = event.target;
127
+ if (target.classList.contains('k-suggestion') || target.closest(DOWNLOAD_ALL_SELECTOR) || target.closest(FILE_ACTION_BTN_SELECTOR)) {
128
+ return;
129
+ }
111
130
  }
112
- if (item) {
113
- item.selected = true;
114
- this.selectedItem = item;
131
+ if (!this.chatService.toggleMessageState) {
132
+ const prevItem = this.selectedItem;
133
+ if (prevItem) {
134
+ prevItem.selected = false;
135
+ }
136
+ if (item) {
137
+ item.selected = true;
138
+ this.selectedItem = item;
139
+ }
140
+ this.cdr.detectChanges();
115
141
  }
142
+ this.chatService.toggleMessageState = false;
116
143
  }
117
144
  last(items) {
118
145
  if (!items || items.length === 0) {
119
146
  return;
120
147
  }
121
- return items[items.length - 1];
148
+ const messageGroups = items.filter((item) => item.type === 'message-group');
149
+ const lastMessageGroup = messageGroups[messageGroups.length - 1].messages;
150
+ return lastMessageGroup[lastMessageGroup.length - 1];
151
+ }
152
+ handleMenuClose(state) {
153
+ if (!state) {
154
+ this.select(null);
155
+ }
122
156
  }
123
157
  onHomeOrEndKeyDown(key) {
124
158
  const items = this.items.toArray();
@@ -157,29 +191,42 @@ export class MessageListComponent {
157
191
  e.preventDefault();
158
192
  }
159
193
  }
160
- /**
161
- * @hidden
162
- */
194
+ scrollToAndSelectMessage(messageId) {
195
+ this.chatService.scrollToMessage(messageId);
196
+ const message = this.chatService.getMessageById(messageId);
197
+ const chatItem = this.items.find(item => item instanceof MessageComponent &&
198
+ item.message === message);
199
+ if (chatItem) {
200
+ this.select(chatItem);
201
+ }
202
+ }
163
203
  textFor(key) {
164
204
  return this.localization.get(key);
165
205
  }
166
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: MessageListComponent, deps: [{ token: i0.ElementRef }, { token: i1.IntlService }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Component });
167
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: MessageListComponent, isStandalone: true, selector: "kendo-chat-message-list", inputs: { messages: "messages", attachmentTemplate: "attachmentTemplate", messageTemplate: "messageTemplate", localization: "localization", user: "user" }, outputs: { executeAction: "executeAction", navigate: "navigate", resize: "resize" }, host: { properties: { "class.k-message-list-content": "this.cssClass" } }, viewQueries: [{ propertyName: "items", predicate: ChatItem, descendants: true }], ngImport: i0, template: `
206
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: MessageListComponent, deps: [{ token: i0.ElementRef }, { token: i1.IntlService }, { token: i0.Renderer2 }, { token: i2.ChatService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
207
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: MessageListComponent, isStandalone: true, selector: "kendo-chat-message-list", inputs: { messages: "messages", attachmentTemplate: "attachmentTemplate", messageTemplate: "messageTemplate", timestampTemplate: "timestampTemplate", statusTemplate: "statusTemplate", localization: "localization", authorId: "authorId" }, outputs: { executeAction: "executeAction", navigate: "navigate", resize: "resize" }, host: { properties: { "class.k-message-list-content": "this.cssClass" } }, viewQueries: [{ propertyName: "items", predicate: ChatItem, descendants: true }], ngImport: i0, template: `
168
208
  <ng-container *ngFor="let group of view; last as lastGroup; trackBy: trackGroup">
169
209
  <ng-container [ngSwitch]="group.type">
170
210
  <div
171
211
  *ngSwitchCase="'date-marker'"
172
212
  class="k-timestamp"
173
213
  >
174
- {{ formatTimeStamp(group.timestamp) }}
214
+ <ng-container
215
+ *ngIf="timestampTemplate?.templateRef"
216
+ [ngTemplateOutlet]="timestampTemplate.templateRef"
217
+ [ngTemplateOutletContext]="{ $implicit: group.timestamp }"
218
+ >
219
+ </ng-container>
220
+ <ng-container *ngIf="!timestampTemplate?.templateRef">{{ formatTimeStamp(group.timestamp) }}</ng-container>
175
221
  </div>
176
222
  <div
177
223
  *ngSwitchCase="'message-group'"
178
224
  class="k-message-group"
179
- [class.k-alt]="isOwnMessage(group.messages[0])"
225
+ [class.k-message-group-sender]="isOwnMessage(group.messages[0])"
226
+ [class.k-message-group-receiver]="!isOwnMessage(group.messages[0])"
180
227
  [class.k-no-avatar]="!group.author.avatarUrl"
228
+ [class.k-message-group-full-width]="chatService.messageWidthMode === 'full'"
181
229
  >
182
- <p *ngIf="group.author.name" class="k-author">{{ group.author.name }}</p>
183
230
  <div
184
231
  *ngIf="group.author.avatarUrl"
185
232
  class="k-avatar k-avatar-md k-avatar-solid k-avatar-solid-primary k-rounded-full"
@@ -187,40 +234,46 @@ export class MessageListComponent {
187
234
  <span class="k-avatar-image">
188
235
  <img
189
236
  [attr.src]="group.author.avatarUrl"
190
- [alt]="textFor('messageAvatarAlt')"
237
+ [alt]="group.author.avatarAltText"
191
238
  />
192
239
  </span>
193
240
  </div>
194
- <ng-container
195
- *ngFor="let msg of group.messages; first as firstMessage; last as lastMessage"
196
- >
197
- <div
198
- *ngIf="msg.user?.avatarUrl"
199
- class="k-avatar k-avatar-md k-avatar-solid k-avatar-solid-primary k-rounded-full"
241
+ <div class="k-message-group-content">
242
+ <p *ngIf="group.author.name" class="k-message-author">{{ group.author.name }}</p>
243
+ <ng-container
244
+ *ngFor="let msg of group.messages; first as firstMessage; last as lastMessage"
200
245
  >
201
- <span class="k-avatar-image">
202
- <img [src]="msg.user?.avatarUrl">
203
- </span>
204
- </div>
205
- <kendo-chat-message #message
206
- [message]="msg"
207
- [tabbable]="lastGroup && lastMessage"
208
- [template]="messageTemplate"
209
- (click)="select(message)"
210
- (focus)="select(message)"
211
- [class.k-only]="group.messages.length === 1"
212
- [class.k-first]="group.messages.length > 1 && firstMessage"
213
- [class.k-last]="group.messages.length > 1 && lastMessage"
214
- >
215
- </kendo-chat-message>
246
+ <div
247
+ *ngIf="msg.user?.avatarUrl"
248
+ class="k-avatar k-avatar-md k-avatar-solid k-avatar-solid-primary k-rounded-full"
249
+ >
250
+ <span class="k-avatar-image">
251
+ <img [src]="msg.user?.avatarUrl">
252
+ </span>
253
+ </div>
254
+ <kendo-chat-message #message
255
+ [message]="msg"
256
+ [tabbable]="lastGroup && lastMessage"
257
+ [template]="messageTemplate"
258
+ [statusTemplate]="statusTemplate"
259
+ [authorId]="authorId"
260
+ (click)="onClick(message, $event)"
261
+ (mouseenter)="message.hovered = true"
262
+ (mouseleave)="message.hovered = false"
263
+ (contextMenuVisibilityChange)="handleMenuClose($event)"
264
+ [class.k-first]="group.messages.length > 1 && firstMessage"
265
+ [class.k-last]="group.messages.length > 1 && lastMessage"
266
+ >
267
+ </kendo-chat-message>
216
268
 
217
- <kendo-chat-attachment
218
- *ngIf="msg.attachments && msg.attachments.length === 1"
219
- [attachment]="msg.attachments[0]"
220
- [template]="attachmentTemplate"
221
- >
222
- </kendo-chat-attachment>
223
- </ng-container>
269
+ <kendo-chat-attachment
270
+ *ngIf="msg.attachments && msg.attachments.length === 1"
271
+ [attachment]="msg.attachments[0]"
272
+ [template]="attachmentTemplate"
273
+ >
274
+ </kendo-chat-attachment>
275
+ </ng-container>
276
+ </div>
224
277
  </div>
225
278
 
226
279
  <kendo-chat-message-attachments #attachments
@@ -239,16 +292,16 @@ export class MessageListComponent {
239
292
  *ngSwitchCase="'action-group'"
240
293
  [actions]="group.actions"
241
294
  [tabbable]="lastGroup"
242
- (dispatch)="dispatchAction($event, last(group.messages))"
243
- (click)="select(actions)"
244
- (focus)="select(actions)"
295
+ (dispatchAction)="dispatchAction($event, last(view))"
296
+ (click)="select(actions, $event)"
297
+ (focus)="select(actions, $event)"
245
298
  >
246
299
  </kendo-chat-suggested-actions>
247
300
  </ng-container>
248
301
  </ng-container>
249
302
  <kendo-resize-sensor (resize)="onResize()">
250
303
  </kendo-resize-sensor>
251
- `, isInline: true, dependencies: [{ kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: MessageComponent, selector: "kendo-chat-message", inputs: ["message", "tabbable", "template"] }, { kind: "component", type: AttachmentComponent, selector: "kendo-chat-attachment", inputs: ["attachment", "template"] }, { kind: "component", type: MessageAttachmentsComponent, selector: "kendo-chat-message-attachments", inputs: ["attachments", "layout", "tabbable", "template", "localization"] }, { kind: "component", type: SuggestedActionsComponent, selector: "kendo-chat-suggested-actions", inputs: ["actions", "tabbable"], outputs: ["dispatch"] }, { kind: "component", type: ResizeSensorComponent, selector: "kendo-resize-sensor", inputs: ["rateLimit"], outputs: ["resize"] }] });
304
+ `, isInline: true, dependencies: [{ kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: MessageComponent, selector: "kendo-chat-message", inputs: ["message", "tabbable", "template", "statusTemplate", "showMessageTime", "authorId"], outputs: ["contextMenuVisibilityChange"] }, { kind: "component", type: AttachmentComponent, selector: "kendo-chat-attachment", inputs: ["attachment", "template"] }, { kind: "component", type: MessageAttachmentsComponent, selector: "kendo-chat-message-attachments", inputs: ["attachments", "layout", "tabbable", "template", "localization"] }, { kind: "component", type: SuggestedActionsComponent, selector: "kendo-chat-suggested-actions", inputs: ["actions", "suggestions", "tabbable", "suggestionTemplate"], outputs: ["dispatchAction", "dispatchSuggestion"] }, { kind: "component", type: ResizeSensorComponent, selector: "kendo-resize-sensor", inputs: ["rateLimit"], outputs: ["resize"] }] });
252
305
  }
253
306
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: MessageListComponent, decorators: [{
254
307
  type: Component,
@@ -261,15 +314,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
261
314
  *ngSwitchCase="'date-marker'"
262
315
  class="k-timestamp"
263
316
  >
264
- {{ formatTimeStamp(group.timestamp) }}
317
+ <ng-container
318
+ *ngIf="timestampTemplate?.templateRef"
319
+ [ngTemplateOutlet]="timestampTemplate.templateRef"
320
+ [ngTemplateOutletContext]="{ $implicit: group.timestamp }"
321
+ >
322
+ </ng-container>
323
+ <ng-container *ngIf="!timestampTemplate?.templateRef">{{ formatTimeStamp(group.timestamp) }}</ng-container>
265
324
  </div>
266
325
  <div
267
326
  *ngSwitchCase="'message-group'"
268
327
  class="k-message-group"
269
- [class.k-alt]="isOwnMessage(group.messages[0])"
328
+ [class.k-message-group-sender]="isOwnMessage(group.messages[0])"
329
+ [class.k-message-group-receiver]="!isOwnMessage(group.messages[0])"
270
330
  [class.k-no-avatar]="!group.author.avatarUrl"
331
+ [class.k-message-group-full-width]="chatService.messageWidthMode === 'full'"
271
332
  >
272
- <p *ngIf="group.author.name" class="k-author">{{ group.author.name }}</p>
273
333
  <div
274
334
  *ngIf="group.author.avatarUrl"
275
335
  class="k-avatar k-avatar-md k-avatar-solid k-avatar-solid-primary k-rounded-full"
@@ -277,40 +337,46 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
277
337
  <span class="k-avatar-image">
278
338
  <img
279
339
  [attr.src]="group.author.avatarUrl"
280
- [alt]="textFor('messageAvatarAlt')"
340
+ [alt]="group.author.avatarAltText"
281
341
  />
282
342
  </span>
283
343
  </div>
284
- <ng-container
285
- *ngFor="let msg of group.messages; first as firstMessage; last as lastMessage"
286
- >
287
- <div
288
- *ngIf="msg.user?.avatarUrl"
289
- class="k-avatar k-avatar-md k-avatar-solid k-avatar-solid-primary k-rounded-full"
290
- >
291
- <span class="k-avatar-image">
292
- <img [src]="msg.user?.avatarUrl">
293
- </span>
294
- </div>
295
- <kendo-chat-message #message
296
- [message]="msg"
297
- [tabbable]="lastGroup && lastMessage"
298
- [template]="messageTemplate"
299
- (click)="select(message)"
300
- (focus)="select(message)"
301
- [class.k-only]="group.messages.length === 1"
302
- [class.k-first]="group.messages.length > 1 && firstMessage"
303
- [class.k-last]="group.messages.length > 1 && lastMessage"
344
+ <div class="k-message-group-content">
345
+ <p *ngIf="group.author.name" class="k-message-author">{{ group.author.name }}</p>
346
+ <ng-container
347
+ *ngFor="let msg of group.messages; first as firstMessage; last as lastMessage"
304
348
  >
305
- </kendo-chat-message>
349
+ <div
350
+ *ngIf="msg.user?.avatarUrl"
351
+ class="k-avatar k-avatar-md k-avatar-solid k-avatar-solid-primary k-rounded-full"
352
+ >
353
+ <span class="k-avatar-image">
354
+ <img [src]="msg.user?.avatarUrl">
355
+ </span>
356
+ </div>
357
+ <kendo-chat-message #message
358
+ [message]="msg"
359
+ [tabbable]="lastGroup && lastMessage"
360
+ [template]="messageTemplate"
361
+ [statusTemplate]="statusTemplate"
362
+ [authorId]="authorId"
363
+ (click)="onClick(message, $event)"
364
+ (mouseenter)="message.hovered = true"
365
+ (mouseleave)="message.hovered = false"
366
+ (contextMenuVisibilityChange)="handleMenuClose($event)"
367
+ [class.k-first]="group.messages.length > 1 && firstMessage"
368
+ [class.k-last]="group.messages.length > 1 && lastMessage"
369
+ >
370
+ </kendo-chat-message>
306
371
 
307
- <kendo-chat-attachment
308
- *ngIf="msg.attachments && msg.attachments.length === 1"
309
- [attachment]="msg.attachments[0]"
310
- [template]="attachmentTemplate"
311
- >
312
- </kendo-chat-attachment>
313
- </ng-container>
372
+ <kendo-chat-attachment
373
+ *ngIf="msg.attachments && msg.attachments.length === 1"
374
+ [attachment]="msg.attachments[0]"
375
+ [template]="attachmentTemplate"
376
+ >
377
+ </kendo-chat-attachment>
378
+ </ng-container>
379
+ </div>
314
380
  </div>
315
381
 
316
382
  <kendo-chat-message-attachments #attachments
@@ -329,9 +395,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
329
395
  *ngSwitchCase="'action-group'"
330
396
  [actions]="group.actions"
331
397
  [tabbable]="lastGroup"
332
- (dispatch)="dispatchAction($event, last(group.messages))"
333
- (click)="select(actions)"
334
- (focus)="select(actions)"
398
+ (dispatchAction)="dispatchAction($event, last(view))"
399
+ (click)="select(actions, $event)"
400
+ (focus)="select(actions, $event)"
335
401
  >
336
402
  </kendo-chat-suggested-actions>
337
403
  </ng-container>
@@ -340,17 +406,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
340
406
  </kendo-resize-sensor>
341
407
  `,
342
408
  standalone: true,
343
- imports: [NgFor, NgSwitch, NgSwitchCase, NgIf, MessageComponent, AttachmentComponent, MessageAttachmentsComponent, SuggestedActionsComponent, ResizeSensorComponent]
409
+ imports: [NgFor, NgSwitch, NgSwitchCase, NgIf, NgTemplateOutlet, MessageComponent, AttachmentComponent, MessageAttachmentsComponent, SuggestedActionsComponent, ResizeSensorComponent]
344
410
  }]
345
- }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i1.IntlService }, { type: i0.Renderer2 }]; }, propDecorators: { messages: [{
411
+ }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i1.IntlService }, { type: i0.Renderer2 }, { type: i2.ChatService }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { messages: [{
346
412
  type: Input
347
413
  }], attachmentTemplate: [{
348
414
  type: Input
349
415
  }], messageTemplate: [{
350
416
  type: Input
417
+ }], timestampTemplate: [{
418
+ type: Input
419
+ }], statusTemplate: [{
420
+ type: Input
351
421
  }], localization: [{
352
422
  type: Input
353
- }], user: [{
423
+ }], authorId: [{
354
424
  type: Input
355
425
  }], executeAction: [{
356
426
  type: Output
@@ -0,0 +1,75 @@
1
+ /**-----------------------------------------------------------------------------------------
2
+ * Copyright © 2025 Progress Software Corporation. All rights reserved.
3
+ * Licensed under commercial license. See LICENSE.md in the project root for more information
4
+ *-------------------------------------------------------------------------------------------*/
5
+ /* eslint-disable @typescript-eslint/no-empty-function */
6
+ import { Component, forwardRef, Input, HostBinding } from '@angular/core';
7
+ import { ChatItem } from './chat-item';
8
+ import { NgIf } from '@angular/common';
9
+ import { ChatFileComponent } from './chat-file.component';
10
+ import { ChatService } from './common/chat.service';
11
+ import { LocalizationService } from '@progress/kendo-angular-l10n';
12
+ import { isAuthor } from './chat-view';
13
+ import * as i0 from "@angular/core";
14
+ import * as i1 from "@progress/kendo-angular-l10n";
15
+ import * as i2 from "./common/chat.service";
16
+ /**
17
+ * @hidden
18
+ */
19
+ export class MessageReferenceComponent extends ChatItem {
20
+ localization;
21
+ chatService;
22
+ hostClass = true;
23
+ message;
24
+ constructor(localization, chatService) {
25
+ super();
26
+ this.localization = localization;
27
+ this.chatService = chatService;
28
+ }
29
+ isOwnMessage(msg) {
30
+ return isAuthor(this.chatService.authorId, msg);
31
+ }
32
+ textFor(key) {
33
+ return this.localization.get(key);
34
+ }
35
+ focus() { }
36
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: MessageReferenceComponent, deps: [{ token: i1.LocalizationService }, { token: i2.ChatService }], target: i0.ɵɵFactoryTarget.Component });
37
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: MessageReferenceComponent, isStandalone: true, selector: "chat-message-reference-content", inputs: { message: "message" }, host: { properties: { "class.k-message-reference-content": "this.hostClass" } }, providers: [{
38
+ provide: ChatItem,
39
+ useExisting: forwardRef(() => MessageReferenceComponent)
40
+ }], usesInheritance: true, ngImport: i0, template: `
41
+ <ng-container *ngIf="message.text && !message.isDeleted">{{message.text}}</ng-container>
42
+ <ng-container *ngIf="!message.text && !message.isDeleted && message.files && message.files.length > 0">
43
+ <li class="k-chat-file" [chatFile]="message.files[0]">
44
+ </li>
45
+ </ng-container>
46
+ <ng-container *ngIf="message.isDeleted && isOwnMessage(message)">{{ textFor('deletedMessageSenderText') }}</ng-container>
47
+ <ng-container *ngIf="message.isDeleted && !isOwnMessage(message)">{{ textFor('deletedMessageReceiverText') }}</ng-container>
48
+ `, isInline: true, dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: ChatFileComponent, selector: "li[chatFile]", inputs: ["chatFile", "removable", "fileActions"], outputs: ["remove", "actionClick", "actionsToggle", "actionButtonClick"] }] });
49
+ }
50
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: MessageReferenceComponent, decorators: [{
51
+ type: Component,
52
+ args: [{
53
+ selector: 'chat-message-reference-content',
54
+ providers: [{
55
+ provide: ChatItem,
56
+ useExisting: forwardRef(() => MessageReferenceComponent)
57
+ }],
58
+ template: `
59
+ <ng-container *ngIf="message.text && !message.isDeleted">{{message.text}}</ng-container>
60
+ <ng-container *ngIf="!message.text && !message.isDeleted && message.files && message.files.length > 0">
61
+ <li class="k-chat-file" [chatFile]="message.files[0]">
62
+ </li>
63
+ </ng-container>
64
+ <ng-container *ngIf="message.isDeleted && isOwnMessage(message)">{{ textFor('deletedMessageSenderText') }}</ng-container>
65
+ <ng-container *ngIf="message.isDeleted && !isOwnMessage(message)">{{ textFor('deletedMessageReceiverText') }}</ng-container>
66
+ `,
67
+ standalone: true,
68
+ imports: [NgIf, ChatFileComponent]
69
+ }]
70
+ }], ctorParameters: function () { return [{ type: i1.LocalizationService }, { type: i2.ChatService }]; }, propDecorators: { hostClass: [{
71
+ type: HostBinding,
72
+ args: ['class.k-message-reference-content']
73
+ }], message: [{
74
+ type: Input
75
+ }] } });