@progress/kendo-angular-conversational-ui 21.1.1-develop.2 → 21.2.0-develop.10

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 (27) hide show
  1. package/chat/chat.component.d.ts +2 -0
  2. package/chat/message-list.component.d.ts +2 -2
  3. package/codemods/utils.js +805 -394
  4. package/codemods/v20/chat-user.js +9 -12
  5. package/codemods/v21/chat-messagetoolbarvisibility.js +9 -13
  6. package/codemods/v21/chat-pinnedbyfield.js +1 -2
  7. package/esm2022/ai-prompt/aiprompt.component.mjs +155 -139
  8. package/esm2022/ai-prompt/common/output-card.component.mjs +81 -83
  9. package/esm2022/ai-prompt/common/toolbar-focusable.directive.mjs +2 -2
  10. package/esm2022/ai-prompt/views/output-view.component.mjs +27 -29
  11. package/esm2022/ai-prompt/views/prompt-view.component.mjs +150 -135
  12. package/esm2022/chat/attachment.component.mjs +53 -37
  13. package/esm2022/chat/cards/hero-card.component.mjs +48 -35
  14. package/esm2022/chat/chat-file.component.mjs +32 -29
  15. package/esm2022/chat/chat-view.mjs +2 -2
  16. package/esm2022/chat/chat.component.mjs +259 -242
  17. package/esm2022/chat/message-attachments.component.mjs +60 -55
  18. package/esm2022/chat/message-box.component.mjs +203 -183
  19. package/esm2022/chat/message-list.component.mjs +249 -209
  20. package/esm2022/chat/message-reference-content.component.mjs +30 -19
  21. package/esm2022/chat/message.component.mjs +301 -281
  22. package/esm2022/chat/suggested-actions.component.mjs +142 -134
  23. package/esm2022/inline-ai-prompt/inlineaiprompt-content.component.mjs +205 -179
  24. package/esm2022/package-metadata.mjs +2 -2
  25. package/fesm2022/progress-kendo-angular-conversational-ui.mjs +1988 -1777
  26. package/package.json +14 -14
  27. package/codemods/template-transformer/index.js +0 -93
@@ -7,7 +7,7 @@ import { ChatItem } from './chat-item';
7
7
  import { MessageContentTemplateDirective } from './templates/message-content-template.directive';
8
8
  import { IntlService } from '@progress/kendo-angular-intl';
9
9
  import { KENDO_BUTTONS } from '@progress/kendo-angular-buttons';
10
- import { NgClass, NgFor, NgIf, NgTemplateOutlet } from '@angular/common';
10
+ import { NgClass, NgTemplateOutlet } from '@angular/common';
11
11
  import { IconWrapperComponent } from '@progress/kendo-angular-icons';
12
12
  import { ToolBarButtonComponent, ToolBarComponent } from '@progress/kendo-angular-toolbar';
13
13
  import { chevronDownIcon, chevronUpIcon, downloadIcon } from '@progress/kendo-svg-icons';
@@ -18,7 +18,7 @@ import { isAuthor } from './chat-view';
18
18
  import { ChatFileComponent } from './chat-file.component';
19
19
  import { MessageReferenceComponent } from './message-reference-content.component';
20
20
  import { ChatStatusTemplateDirective } from './templates/status-template.directive';
21
- import { isPresent, Keys, normalizeNumpadKeys } from '@progress/kendo-angular-common';
21
+ import { isPresent, Keys, normalizeKeys } from '@progress/kendo-angular-common';
22
22
  import { MessageTemplateDirective } from './templates/message-template.directive';
23
23
  import { AuthorMessageContentTemplateDirective } from './templates/author-message-content-template.directive';
24
24
  import { ReceiverMessageContentTemplateDirective } from './templates/receiver-message-content-template.directive';
@@ -225,7 +225,7 @@ export class MessageComponent extends ChatItem {
225
225
  this.chatService.toggleMessageState = false;
226
226
  }
227
227
  onExpandableKeydown(event) {
228
- const key = normalizeNumpadKeys(event);
228
+ const key = normalizeKeys(event);
229
229
  const isFileActionButton = event.target.closest(FILE_ACTION_BTN_SELECTOR) || event.target.closest(DOWNLOAD_ALL_SELECTOR);
230
230
  if (!isFileActionButton && (key === Keys.Enter || key === Keys.Space)) {
231
231
  event.preventDefault();
@@ -330,178 +330,188 @@ export class MessageComponent extends ChatItem {
330
330
  return transformActions(actions);
331
331
  }
332
332
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: MessageComponent, deps: [{ token: i0.ElementRef }, { token: i1.IntlService }, { token: i2.ChatService }, { token: i3.LocalizationService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
333
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: MessageComponent, isStandalone: true, selector: "kendo-chat-message", inputs: { message: "message", tabbable: "tabbable", authorMessageContentTemplate: "authorMessageContentTemplate", receiverMessageContentTemplate: "receiverMessageContentTemplate", messageContentTemplate: "messageContentTemplate", authorMessageTemplate: "authorMessageTemplate", receiverMessageTemplate: "receiverMessageTemplate", messageTemplate: "messageTemplate", statusTemplate: "statusTemplate", showMessageTime: "showMessageTime", authorId: "authorId" }, host: { listeners: { "keydown": "onKeyDown($event)" }, properties: { "class.k-message": "this.cssClass", "class.k-message-removed": "this.removedClass", "attr.tabIndex": "this.tabIndex" } }, providers: [
333
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: MessageComponent, isStandalone: true, selector: "kendo-chat-message", inputs: { message: "message", tabbable: "tabbable", authorMessageContentTemplate: "authorMessageContentTemplate", receiverMessageContentTemplate: "receiverMessageContentTemplate", messageContentTemplate: "messageContentTemplate", authorMessageTemplate: "authorMessageTemplate", receiverMessageTemplate: "receiverMessageTemplate", messageTemplate: "messageTemplate", statusTemplate: "statusTemplate", showMessageTime: "showMessageTime", authorId: "authorId" }, host: { listeners: { "keydown": "onKeyDown($event)" }, properties: { "class.k-message": "this.cssClass", "class.k-message-removed": "this.removedClass", "attr.tabIndex": "this.tabIndex" } }, providers: [
334
334
  {
335
335
  provide: ChatItem,
336
336
  useExisting: forwardRef(() => MessageComponent)
337
337
  }
338
338
  ], usesInheritance: true, ngImport: i0, template: `
339
- <ng-container *ngIf="useCustomBubbleTemplate">
340
- <ng-container *ngTemplateOutlet="getActiveBubbleTemplate()?.templateRef; context: { $implicit: message };"></ng-container>
341
- </ng-container>
339
+ @if (useCustomBubbleTemplate) {
340
+ <ng-container *ngTemplateOutlet="getActiveBubbleTemplate()?.templateRef; context: { $implicit: message };"></ng-container>
341
+ }
342
342
 
343
- <ng-container *ngIf="!useCustomBubbleTemplate">
343
+ @if (!useCustomBubbleTemplate) {
344
+ @if (chatService.timestampVisibility === 'focus' && message.timestamp) {
344
345
  <time
345
- [attr.aria-hidden]="!selected"
346
- class="k-message-time"
347
- *ngIf="chatService.timestampVisibility === 'focus' && message.timestamp"
348
- >
349
- {{ formatTimeStamp(message.timestamp) }}
346
+ [attr.aria-hidden]="!selected"
347
+ class="k-message-time"
348
+ >
349
+ {{ formatTimeStamp(message.timestamp) }}
350
350
  </time>
351
-
352
- <ng-container *ngIf="message.typing">
353
- <div class="k-chat-bubble k-bubble">
354
- <div class="k-typing-indicator" [attr.tabindex]="'-1'">
355
- <span></span>
356
- <span></span>
357
- <span></span>
358
- </div>
359
- </div>
360
- </ng-container>
361
-
362
- <ng-container *ngIf="!message.typing">
363
- <div
364
- class="k-chat-bubble k-bubble"
365
- *ngIf="useCustomContentTemplate"
366
- [attr.tabindex]="0"
351
+ }
352
+ @if (message.typing) {
353
+ <div class="k-chat-bubble k-bubble">
354
+ <div class="k-typing-indicator" [attr.tabindex]="'-1'">
355
+ <span></span>
356
+ <span></span>
357
+ <span></span>
358
+ </div>
359
+ </div>
360
+ }
361
+ @if (!message.typing) {
362
+ @if (useCustomContentTemplate) {
363
+ <div
364
+ class="k-chat-bubble k-bubble"
365
+ [attr.tabindex]="0"
367
366
  [ngClass]="{
368
- 'k-bubble-expandable': isMessageExpandable,
367
+ 'k-bubble-expandable': isMessageExpandable,
369
368
  'k-expanded': isMessageExpanded,
370
- 'k-selected': selected,
369
+ 'k-selected': selected,
371
370
  'k-focus': selected,
372
371
  'k-active': isActiveMessage
373
372
  }"
374
373
  >
375
- <div class="k-bubble-content">
376
- <ng-container *ngTemplateOutlet="getActiveContentTemplate()?.templateRef; context: { $implicit: message };"></ng-container>
377
- </div>
378
- <span
379
- class="k-bubble-expandable-indicator"
380
- *ngIf="isMessageExpandable && showExpandCollapseIcon"
381
- [attr.tabindex]="'0'"
382
- [attr.role]="'button'"
383
- [attr.title]="isMessageExpanded ? textFor('collapseTitle') : textFor('expandTitle')"
384
- (mousedown)="chatService.toggleMessageState = true"
385
- (click)="toggleMessageState($event)"
386
- >
387
- <kendo-icon-wrapper
388
- [name]="isMessageExpanded ? 'chevron-up' : 'chevron-down'"
389
- [svgIcon]="isMessageExpanded ? collapseIcon : expandIcon"
390
- >
391
- </kendo-icon-wrapper>
392
- </span>
374
+ <div class="k-bubble-content">
375
+ <ng-container *ngTemplateOutlet="getActiveContentTemplate()?.templateRef; context: { $implicit: message };"></ng-container>
393
376
  </div>
394
-
395
- <div
396
- class="k-chat-bubble k-bubble"
397
- *ngIf="!useCustomContentTemplate && hasMessageContent"
398
- [attr.tabindex]="0"
377
+ @if (isMessageExpandable && showExpandCollapseIcon) {
378
+ <span
379
+ class="k-bubble-expandable-indicator"
380
+ [attr.tabindex]="'0'"
381
+ [attr.role]="'button'"
382
+ [attr.title]="isMessageExpanded ? textFor('collapseTitle') : textFor('expandTitle')"
383
+ (mousedown)="chatService.toggleMessageState = true"
384
+ (click)="toggleMessageState($event)"
385
+ >
386
+ <kendo-icon-wrapper
387
+ [name]="isMessageExpanded ? 'chevron-up' : 'chevron-down'"
388
+ [svgIcon]="isMessageExpanded ? collapseIcon : expandIcon"
389
+ >
390
+ </kendo-icon-wrapper>
391
+ </span>
392
+ }
393
+ </div>
394
+ }
395
+ @if (!useCustomContentTemplate && hasMessageContent) {
396
+ <div
397
+ class="k-chat-bubble k-bubble"
398
+ [attr.tabindex]="0"
399
399
  [ngClass]="{
400
- 'k-bubble-expandable': isMessageExpandable,
401
- 'k-expanded': isMessageExpanded,
402
- 'k-selected': selected,
400
+ 'k-bubble-expandable': isMessageExpandable,
401
+ 'k-expanded': isMessageExpanded,
402
+ 'k-selected': selected,
403
403
  'k-focus': selected,
404
404
  'k-active': isActiveMessage
405
405
  }"
406
406
  >
407
- <div class="k-bubble-content">
408
- <ng-container *ngIf="message.text || message.isDeleted">
409
- <div
410
- class="k-message-reference k-message-reference-receiver"
411
- *ngIf="message.replyToId && !message.isDeleted"
412
- (click)="onReplyReferenceClick($event, message.replyToId)"
413
- >
414
- <chat-message-reference-content [message]="getMessageById(message.replyToId)"></chat-message-reference-content>
415
- </div>
416
-
417
- <span class="k-chat-bubble-text" *ngIf="message.isDeleted">
418
- {{ getDeletedMessageText() }}
419
- </span>
420
-
421
- <span class="k-chat-bubble-text" *ngIf="!message.isDeleted && parts.length > 0">
422
- <ng-container *ngFor="let part of parts">
423
- <ng-container *ngIf="part.type === 'text'">{{part.content}}</ng-container>
424
- <a *ngIf="part.type === 'link'" [href]="part.href" target="_blank">{{part.content}}</a>
425
- </ng-container>
426
- </span>
427
- </ng-container>
428
-
429
- <ul
430
- class="k-chat-file-wrapper"
431
- *ngIf="hasFiles && !message.isDeleted"
407
+ <div class="k-bubble-content">
408
+ @if (message.text || message.isDeleted) {
409
+ @if (message.replyToId && !message.isDeleted) {
410
+ <div
411
+ class="k-message-reference k-message-reference-receiver"
412
+ (click)="onReplyReferenceClick($event, message.replyToId)"
413
+ >
414
+ <chat-message-reference-content [message]="getMessageById(message.replyToId)"></chat-message-reference-content>
415
+ </div>
416
+ }
417
+ @if (message.isDeleted) {
418
+ <span class="k-chat-bubble-text">
419
+ {{ getDeletedMessageText() }}
420
+ </span>
421
+ }
422
+ @if (!message.isDeleted && parts.length > 0) {
423
+ <span class="k-chat-bubble-text">
424
+ @for (part of parts; track part) {
425
+ @if (part.type === 'text') {{{part.content}}}
426
+ @if (part.type === 'link') {<a [href]="part.href" target="_blank">{{part.content}}</a>}
427
+ }
428
+ </span>
429
+ }
430
+ }
431
+ @if (hasFiles && !message.isDeleted) {
432
+ <ul
433
+ class="k-chat-file-wrapper"
432
434
  [ngClass]="{
433
- 'k-chat-files-wrap': chatService.messageFilesLayout === 'wrap',
435
+ 'k-chat-files-wrap': chatService.messageFilesLayout === 'wrap',
434
436
  'k-chat-files-horizontal': chatService.messageFilesLayout === 'horizontal'
435
437
  }"
436
- >
437
- <li
438
- *ngFor="let file of message.files"
439
- class="k-chat-file"
440
- [chatFile]="file"
441
- [fileActions]="fileActions"
442
- (actionClick)="onFileAction($event, file)"
443
- (actionsToggle)="onActionPopupChange($event)"
444
- (actionButtonClick)="onActionButtonClick($event)"
445
- ></li>
446
- </ul>
447
-
448
- <div class="k-chat-download-button-wrapper" *ngIf="hasMultipleFiles && !message.isDeleted">
449
- <button
450
- kendoButton
451
- class="k-chat-download-button"
452
- fillMode="flat"
453
- icon="download"
454
- [svgIcon]="downloadIcon"
455
- [attr.title]="textFor('downloadAllFilesText')"
456
- (click)="onDownloadAll()"
457
- >{{ textFor('downloadAllFilesText') }}</button>
458
- </div>
438
+ >
439
+ @for (file of message.files; track file) {
440
+ <li
441
+ class="k-chat-file"
442
+ [chatFile]="file"
443
+ [fileActions]="fileActions"
444
+ (actionClick)="onFileAction($event, file)"
445
+ (actionsToggle)="onActionPopupChange($event)"
446
+ (actionButtonClick)="onActionButtonClick($event)"
447
+ ></li>
448
+ }
449
+ </ul>
450
+ }
451
+ @if (hasMultipleFiles && !message.isDeleted) {
452
+ <div class="k-chat-download-button-wrapper">
453
+ <button
454
+ kendoButton
455
+ class="k-chat-download-button"
456
+ fillMode="flat"
457
+ icon="download"
458
+ [svgIcon]="downloadIcon"
459
+ [attr.title]="textFor('downloadAllFilesText')"
460
+ (click)="onDownloadAll()"
461
+ >{{ textFor('downloadAllFilesText') }}</button>
459
462
  </div>
460
-
461
- <span
462
- class="k-bubble-expandable-indicator"
463
- *ngIf="isMessageExpandable && showExpandCollapseIcon"
464
- [attr.tabindex]="'0'"
465
- [attr.role]="'button'"
466
- [attr.title]="isMessageExpanded ? textFor('collapseTitle') : textFor('expandTitle')"
467
- (mousedown)="chatService.toggleMessageState = true"
468
- (click)="toggleMessageState($event)"
469
- >
470
- <kendo-icon-wrapper
471
- [name]="isMessageExpanded ? 'chevron-up' : 'chevron-down'"
472
- [svgIcon]="isMessageExpanded ? collapseIcon : expandIcon"
473
- >
474
- </kendo-icon-wrapper>
475
- </span>
463
+ }
476
464
  </div>
477
- </ng-container>
478
-
479
- <span class="k-message-status" *ngIf="message.status">
480
- <ng-container *ngIf="statusTemplate?.templateRef">
481
- <ng-template
482
- [ngTemplateOutlet]="statusTemplate.templateRef"
483
- [ngTemplateOutletContext]="{ $implicit: message.status, message }"
465
+ @if (isMessageExpandable && showExpandCollapseIcon) {
466
+ <span
467
+ class="k-bubble-expandable-indicator"
468
+ [attr.tabindex]="'0'"
469
+ [attr.role]="'button'"
470
+ [attr.title]="isMessageExpanded ? textFor('collapseTitle') : textFor('expandTitle')"
471
+ (mousedown)="chatService.toggleMessageState = true"
472
+ (click)="toggleMessageState($event)"
484
473
  >
485
- </ng-template>
486
- </ng-container>
487
- <ng-container *ngIf="!statusTemplate?.templateRef">
488
- {{ message.status }}
489
- </ng-container>
474
+ <kendo-icon-wrapper
475
+ [name]="isMessageExpanded ? 'chevron-up' : 'chevron-down'"
476
+ [svgIcon]="isMessageExpanded ? collapseIcon : expandIcon"
477
+ >
478
+ </kendo-icon-wrapper>
479
+ </span>
480
+ }
481
+ </div>
482
+ }
483
+ }
484
+ @if (message.status) {
485
+ <span class="k-message-status">
486
+ @if (statusTemplate?.templateRef) {
487
+ <ng-template
488
+ [ngTemplateOutlet]="statusTemplate.templateRef"
489
+ [ngTemplateOutletContext]="{ $implicit: message.status, message }"
490
+ >
491
+ </ng-template>
492
+ }
493
+ @if (!statusTemplate?.templateRef) {
494
+ {{ message.status }}
495
+ }
490
496
  </span>
491
- </ng-container>
492
- <kendo-toolbar *ngIf="showToolbar" class="k-chat-message-toolbar" fillMode="flat">
493
- <kendo-toolbar-button
494
- *ngFor="let action of toolbarActions"
497
+ }
498
+ }
499
+ @if (showToolbar) {
500
+ <kendo-toolbar class="k-chat-message-toolbar" fillMode="flat">
501
+ @for (action of toolbarActions; track action) {
502
+ <kendo-toolbar-button
495
503
  fillMode="flat"
496
504
  [icon]="action.icon"
497
505
  [svgIcon]="action.svgIcon"
498
506
  [disabled]="action.disabled"
499
507
  [title]="action.label"
500
508
  (click)="onToolbarAction($event, action, message)"
501
- >
502
- </kendo-toolbar-button>
503
- </kendo-toolbar>
504
- `, isInline: true, dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: IconWrapperComponent, selector: "kendo-icon-wrapper", inputs: ["name", "svgIcon", "innerCssClass", "customFontClass", "size"], exportAs: ["kendoIconWrapper"] }, { kind: "component", type: i4.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: "component", type: ChatFileComponent, selector: "li[chatFile]", inputs: ["chatFile", "removable", "fileActions"], outputs: ["remove", "actionClick", "actionsToggle", "actionButtonClick"] }, { kind: "component", type: ToolBarComponent, selector: "kendo-toolbar", inputs: ["overflow", "resizable", "popupSettings", "fillMode", "tabindex", "size", "tabIndex", "showIcon", "showText"], outputs: ["open", "close"], exportAs: ["kendoToolBar"] }, { kind: "component", type: ToolBarButtonComponent, selector: "kendo-toolbar-button", inputs: ["showText", "showIcon", "text", "style", "className", "title", "disabled", "toggleable", "look", "togglable", "selected", "fillMode", "rounded", "themeColor", "icon", "iconClass", "svgIcon", "imageUrl"], outputs: ["click", "pointerdown", "selectedChange"], exportAs: ["kendoToolBarButton"] }, { kind: "component", type: MessageReferenceComponent, selector: "chat-message-reference-content", inputs: ["message"] }] });
509
+ >
510
+ </kendo-toolbar-button>
511
+ }
512
+ </kendo-toolbar>
513
+ }
514
+ `, isInline: true, dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: IconWrapperComponent, selector: "kendo-icon-wrapper", inputs: ["name", "svgIcon", "innerCssClass", "customFontClass", "size"], exportAs: ["kendoIconWrapper"] }, { kind: "component", type: i4.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: "component", type: ChatFileComponent, selector: "li[chatFile]", inputs: ["chatFile", "removable", "fileActions"], outputs: ["remove", "actionClick", "actionsToggle", "actionButtonClick"] }, { kind: "component", type: ToolBarComponent, selector: "kendo-toolbar", inputs: ["overflow", "resizable", "popupSettings", "fillMode", "tabindex", "size", "tabIndex", "showIcon", "showText"], outputs: ["open", "close"], exportAs: ["kendoToolBar"] }, { kind: "component", type: ToolBarButtonComponent, selector: "kendo-toolbar-button", inputs: ["showText", "showIcon", "text", "style", "className", "title", "disabled", "toggleable", "look", "togglable", "selected", "fillMode", "rounded", "themeColor", "icon", "iconClass", "svgIcon", "imageUrl"], outputs: ["click", "pointerdown", "selectedChange"], exportAs: ["kendoToolBarButton"] }, { kind: "component", type: MessageReferenceComponent, selector: "chat-message-reference-content", inputs: ["message"] }] });
505
515
  }
506
516
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: MessageComponent, decorators: [{
507
517
  type: Component,
@@ -514,174 +524,184 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
514
524
  }
515
525
  ],
516
526
  template: `
517
- <ng-container *ngIf="useCustomBubbleTemplate">
518
- <ng-container *ngTemplateOutlet="getActiveBubbleTemplate()?.templateRef; context: { $implicit: message };"></ng-container>
519
- </ng-container>
527
+ @if (useCustomBubbleTemplate) {
528
+ <ng-container *ngTemplateOutlet="getActiveBubbleTemplate()?.templateRef; context: { $implicit: message };"></ng-container>
529
+ }
520
530
 
521
- <ng-container *ngIf="!useCustomBubbleTemplate">
531
+ @if (!useCustomBubbleTemplate) {
532
+ @if (chatService.timestampVisibility === 'focus' && message.timestamp) {
522
533
  <time
523
- [attr.aria-hidden]="!selected"
524
- class="k-message-time"
525
- *ngIf="chatService.timestampVisibility === 'focus' && message.timestamp"
526
- >
527
- {{ formatTimeStamp(message.timestamp) }}
534
+ [attr.aria-hidden]="!selected"
535
+ class="k-message-time"
536
+ >
537
+ {{ formatTimeStamp(message.timestamp) }}
528
538
  </time>
529
-
530
- <ng-container *ngIf="message.typing">
531
- <div class="k-chat-bubble k-bubble">
532
- <div class="k-typing-indicator" [attr.tabindex]="'-1'">
533
- <span></span>
534
- <span></span>
535
- <span></span>
536
- </div>
537
- </div>
538
- </ng-container>
539
-
540
- <ng-container *ngIf="!message.typing">
541
- <div
542
- class="k-chat-bubble k-bubble"
543
- *ngIf="useCustomContentTemplate"
544
- [attr.tabindex]="0"
539
+ }
540
+ @if (message.typing) {
541
+ <div class="k-chat-bubble k-bubble">
542
+ <div class="k-typing-indicator" [attr.tabindex]="'-1'">
543
+ <span></span>
544
+ <span></span>
545
+ <span></span>
546
+ </div>
547
+ </div>
548
+ }
549
+ @if (!message.typing) {
550
+ @if (useCustomContentTemplate) {
551
+ <div
552
+ class="k-chat-bubble k-bubble"
553
+ [attr.tabindex]="0"
545
554
  [ngClass]="{
546
- 'k-bubble-expandable': isMessageExpandable,
555
+ 'k-bubble-expandable': isMessageExpandable,
547
556
  'k-expanded': isMessageExpanded,
548
- 'k-selected': selected,
557
+ 'k-selected': selected,
549
558
  'k-focus': selected,
550
559
  'k-active': isActiveMessage
551
560
  }"
552
561
  >
553
- <div class="k-bubble-content">
554
- <ng-container *ngTemplateOutlet="getActiveContentTemplate()?.templateRef; context: { $implicit: message };"></ng-container>
555
- </div>
556
- <span
557
- class="k-bubble-expandable-indicator"
558
- *ngIf="isMessageExpandable && showExpandCollapseIcon"
559
- [attr.tabindex]="'0'"
560
- [attr.role]="'button'"
561
- [attr.title]="isMessageExpanded ? textFor('collapseTitle') : textFor('expandTitle')"
562
- (mousedown)="chatService.toggleMessageState = true"
563
- (click)="toggleMessageState($event)"
564
- >
565
- <kendo-icon-wrapper
566
- [name]="isMessageExpanded ? 'chevron-up' : 'chevron-down'"
567
- [svgIcon]="isMessageExpanded ? collapseIcon : expandIcon"
568
- >
569
- </kendo-icon-wrapper>
570
- </span>
562
+ <div class="k-bubble-content">
563
+ <ng-container *ngTemplateOutlet="getActiveContentTemplate()?.templateRef; context: { $implicit: message };"></ng-container>
571
564
  </div>
572
-
573
- <div
574
- class="k-chat-bubble k-bubble"
575
- *ngIf="!useCustomContentTemplate && hasMessageContent"
576
- [attr.tabindex]="0"
565
+ @if (isMessageExpandable && showExpandCollapseIcon) {
566
+ <span
567
+ class="k-bubble-expandable-indicator"
568
+ [attr.tabindex]="'0'"
569
+ [attr.role]="'button'"
570
+ [attr.title]="isMessageExpanded ? textFor('collapseTitle') : textFor('expandTitle')"
571
+ (mousedown)="chatService.toggleMessageState = true"
572
+ (click)="toggleMessageState($event)"
573
+ >
574
+ <kendo-icon-wrapper
575
+ [name]="isMessageExpanded ? 'chevron-up' : 'chevron-down'"
576
+ [svgIcon]="isMessageExpanded ? collapseIcon : expandIcon"
577
+ >
578
+ </kendo-icon-wrapper>
579
+ </span>
580
+ }
581
+ </div>
582
+ }
583
+ @if (!useCustomContentTemplate && hasMessageContent) {
584
+ <div
585
+ class="k-chat-bubble k-bubble"
586
+ [attr.tabindex]="0"
577
587
  [ngClass]="{
578
- 'k-bubble-expandable': isMessageExpandable,
579
- 'k-expanded': isMessageExpanded,
580
- 'k-selected': selected,
588
+ 'k-bubble-expandable': isMessageExpandable,
589
+ 'k-expanded': isMessageExpanded,
590
+ 'k-selected': selected,
581
591
  'k-focus': selected,
582
592
  'k-active': isActiveMessage
583
593
  }"
584
594
  >
585
- <div class="k-bubble-content">
586
- <ng-container *ngIf="message.text || message.isDeleted">
587
- <div
588
- class="k-message-reference k-message-reference-receiver"
589
- *ngIf="message.replyToId && !message.isDeleted"
590
- (click)="onReplyReferenceClick($event, message.replyToId)"
591
- >
592
- <chat-message-reference-content [message]="getMessageById(message.replyToId)"></chat-message-reference-content>
593
- </div>
594
-
595
- <span class="k-chat-bubble-text" *ngIf="message.isDeleted">
596
- {{ getDeletedMessageText() }}
597
- </span>
598
-
599
- <span class="k-chat-bubble-text" *ngIf="!message.isDeleted && parts.length > 0">
600
- <ng-container *ngFor="let part of parts">
601
- <ng-container *ngIf="part.type === 'text'">{{part.content}}</ng-container>
602
- <a *ngIf="part.type === 'link'" [href]="part.href" target="_blank">{{part.content}}</a>
603
- </ng-container>
604
- </span>
605
- </ng-container>
606
-
607
- <ul
608
- class="k-chat-file-wrapper"
609
- *ngIf="hasFiles && !message.isDeleted"
595
+ <div class="k-bubble-content">
596
+ @if (message.text || message.isDeleted) {
597
+ @if (message.replyToId && !message.isDeleted) {
598
+ <div
599
+ class="k-message-reference k-message-reference-receiver"
600
+ (click)="onReplyReferenceClick($event, message.replyToId)"
601
+ >
602
+ <chat-message-reference-content [message]="getMessageById(message.replyToId)"></chat-message-reference-content>
603
+ </div>
604
+ }
605
+ @if (message.isDeleted) {
606
+ <span class="k-chat-bubble-text">
607
+ {{ getDeletedMessageText() }}
608
+ </span>
609
+ }
610
+ @if (!message.isDeleted && parts.length > 0) {
611
+ <span class="k-chat-bubble-text">
612
+ @for (part of parts; track part) {
613
+ @if (part.type === 'text') {{{part.content}}}
614
+ @if (part.type === 'link') {<a [href]="part.href" target="_blank">{{part.content}}</a>}
615
+ }
616
+ </span>
617
+ }
618
+ }
619
+ @if (hasFiles && !message.isDeleted) {
620
+ <ul
621
+ class="k-chat-file-wrapper"
610
622
  [ngClass]="{
611
- 'k-chat-files-wrap': chatService.messageFilesLayout === 'wrap',
623
+ 'k-chat-files-wrap': chatService.messageFilesLayout === 'wrap',
612
624
  'k-chat-files-horizontal': chatService.messageFilesLayout === 'horizontal'
613
625
  }"
614
- >
615
- <li
616
- *ngFor="let file of message.files"
617
- class="k-chat-file"
618
- [chatFile]="file"
619
- [fileActions]="fileActions"
620
- (actionClick)="onFileAction($event, file)"
621
- (actionsToggle)="onActionPopupChange($event)"
622
- (actionButtonClick)="onActionButtonClick($event)"
623
- ></li>
624
- </ul>
625
-
626
- <div class="k-chat-download-button-wrapper" *ngIf="hasMultipleFiles && !message.isDeleted">
627
- <button
628
- kendoButton
629
- class="k-chat-download-button"
630
- fillMode="flat"
631
- icon="download"
632
- [svgIcon]="downloadIcon"
633
- [attr.title]="textFor('downloadAllFilesText')"
634
- (click)="onDownloadAll()"
635
- >{{ textFor('downloadAllFilesText') }}</button>
636
- </div>
626
+ >
627
+ @for (file of message.files; track file) {
628
+ <li
629
+ class="k-chat-file"
630
+ [chatFile]="file"
631
+ [fileActions]="fileActions"
632
+ (actionClick)="onFileAction($event, file)"
633
+ (actionsToggle)="onActionPopupChange($event)"
634
+ (actionButtonClick)="onActionButtonClick($event)"
635
+ ></li>
636
+ }
637
+ </ul>
638
+ }
639
+ @if (hasMultipleFiles && !message.isDeleted) {
640
+ <div class="k-chat-download-button-wrapper">
641
+ <button
642
+ kendoButton
643
+ class="k-chat-download-button"
644
+ fillMode="flat"
645
+ icon="download"
646
+ [svgIcon]="downloadIcon"
647
+ [attr.title]="textFor('downloadAllFilesText')"
648
+ (click)="onDownloadAll()"
649
+ >{{ textFor('downloadAllFilesText') }}</button>
637
650
  </div>
638
-
639
- <span
640
- class="k-bubble-expandable-indicator"
641
- *ngIf="isMessageExpandable && showExpandCollapseIcon"
642
- [attr.tabindex]="'0'"
643
- [attr.role]="'button'"
644
- [attr.title]="isMessageExpanded ? textFor('collapseTitle') : textFor('expandTitle')"
645
- (mousedown)="chatService.toggleMessageState = true"
646
- (click)="toggleMessageState($event)"
647
- >
648
- <kendo-icon-wrapper
649
- [name]="isMessageExpanded ? 'chevron-up' : 'chevron-down'"
650
- [svgIcon]="isMessageExpanded ? collapseIcon : expandIcon"
651
- >
652
- </kendo-icon-wrapper>
653
- </span>
651
+ }
654
652
  </div>
655
- </ng-container>
656
-
657
- <span class="k-message-status" *ngIf="message.status">
658
- <ng-container *ngIf="statusTemplate?.templateRef">
659
- <ng-template
660
- [ngTemplateOutlet]="statusTemplate.templateRef"
661
- [ngTemplateOutletContext]="{ $implicit: message.status, message }"
653
+ @if (isMessageExpandable && showExpandCollapseIcon) {
654
+ <span
655
+ class="k-bubble-expandable-indicator"
656
+ [attr.tabindex]="'0'"
657
+ [attr.role]="'button'"
658
+ [attr.title]="isMessageExpanded ? textFor('collapseTitle') : textFor('expandTitle')"
659
+ (mousedown)="chatService.toggleMessageState = true"
660
+ (click)="toggleMessageState($event)"
662
661
  >
663
- </ng-template>
664
- </ng-container>
665
- <ng-container *ngIf="!statusTemplate?.templateRef">
666
- {{ message.status }}
667
- </ng-container>
662
+ <kendo-icon-wrapper
663
+ [name]="isMessageExpanded ? 'chevron-up' : 'chevron-down'"
664
+ [svgIcon]="isMessageExpanded ? collapseIcon : expandIcon"
665
+ >
666
+ </kendo-icon-wrapper>
667
+ </span>
668
+ }
669
+ </div>
670
+ }
671
+ }
672
+ @if (message.status) {
673
+ <span class="k-message-status">
674
+ @if (statusTemplate?.templateRef) {
675
+ <ng-template
676
+ [ngTemplateOutlet]="statusTemplate.templateRef"
677
+ [ngTemplateOutletContext]="{ $implicit: message.status, message }"
678
+ >
679
+ </ng-template>
680
+ }
681
+ @if (!statusTemplate?.templateRef) {
682
+ {{ message.status }}
683
+ }
668
684
  </span>
669
- </ng-container>
670
- <kendo-toolbar *ngIf="showToolbar" class="k-chat-message-toolbar" fillMode="flat">
671
- <kendo-toolbar-button
672
- *ngFor="let action of toolbarActions"
685
+ }
686
+ }
687
+ @if (showToolbar) {
688
+ <kendo-toolbar class="k-chat-message-toolbar" fillMode="flat">
689
+ @for (action of toolbarActions; track action) {
690
+ <kendo-toolbar-button
673
691
  fillMode="flat"
674
692
  [icon]="action.icon"
675
693
  [svgIcon]="action.svgIcon"
676
694
  [disabled]="action.disabled"
677
695
  [title]="action.label"
678
696
  (click)="onToolbarAction($event, action, message)"
679
- >
680
- </kendo-toolbar-button>
681
- </kendo-toolbar>
682
- `,
697
+ >
698
+ </kendo-toolbar-button>
699
+ }
700
+ </kendo-toolbar>
701
+ }
702
+ `,
683
703
  standalone: true,
684
- imports: [NgIf, NgClass, NgFor, NgTemplateOutlet, IconWrapperComponent, KENDO_BUTTONS, ChatFileComponent, ToolBarComponent, ToolBarButtonComponent, MessageReferenceComponent],
704
+ imports: [NgClass, NgTemplateOutlet, IconWrapperComponent, KENDO_BUTTONS, ChatFileComponent, ToolBarComponent, ToolBarButtonComponent, MessageReferenceComponent],
685
705
  }]
686
706
  }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i1.IntlService }, { type: i2.ChatService }, { type: i3.LocalizationService }, { type: i0.ChangeDetectorRef }], propDecorators: { message: [{
687
707
  type: Input