@progress/kendo-angular-conversational-ui
Version:
Kendo UI for Angular Conversational UI components
741 lines (738 loc) • 33.7 kB
JavaScript
/**-----------------------------------------------------------------------------------------
* Copyright © 2025 Progress Software Corporation. All rights reserved.
* Licensed under commercial license. See LICENSE.md in the project root for more information
*-------------------------------------------------------------------------------------------*/
import { ChangeDetectorRef, Component, ElementRef, forwardRef, HostBinding, HostListener, Input } from '@angular/core';
import { ChatItem } from './chat-item';
import { MessageContentTemplateDirective } from './templates/message-content-template.directive';
import { IntlService } from '@progress/kendo-angular-intl';
import { KENDO_BUTTONS } from '@progress/kendo-angular-buttons';
import { NgClass, NgTemplateOutlet } from '@angular/common';
import { IconWrapperComponent } from '@progress/kendo-angular-icons';
import { ToolBarButtonComponent, ToolBarComponent } from '@progress/kendo-angular-toolbar';
import { chevronDownIcon, chevronUpIcon, downloadIcon } from '@progress/kendo-svg-icons';
import { ChatService } from './common/chat.service';
import { LocalizationService } from '@progress/kendo-angular-l10n';
import { URL_REGEX, FILE_ACTION_BTN_SELECTOR, DOWNLOAD_ALL_SELECTOR, MENU_ITEM_SELECTOR, transformActions } from './common/utils';
import { isAuthor } from './chat-view';
import { ChatFileComponent } from './chat-file.component';
import { MessageReferenceComponent } from './message-reference-content.component';
import { ChatStatusTemplateDirective } from './templates/status-template.directive';
import { isPresent, Keys, normalizeKeys } from '@progress/kendo-angular-common';
import { MessageTemplateDirective } from './templates/message-template.directive';
import { AuthorMessageContentTemplateDirective } from './templates/author-message-content-template.directive';
import { ReceiverMessageContentTemplateDirective } from './templates/receiver-message-content-template.directive';
import { ReceiverMessageTemplateDirective } from './templates/receiver-message-template.directive';
import { AuthorMessageTemplateDirective } from './templates/author-message-template.directive';
import { Subscription } from 'rxjs';
import * as i0 from "@angular/core";
import * as i1 from "@progress/kendo-angular-intl";
import * as i2 from "./common/chat.service";
import * as i3 from "@progress/kendo-angular-l10n";
import * as i4 from "@progress/kendo-angular-buttons";
// eslint-disable no-forward-ref
/**
* @hidden
*/
export class MessageComponent extends ChatItem {
element;
intl;
chatService;
localization;
cdr;
set message(value) {
this._message = value;
}
get message() {
return this._message;
}
tabbable;
authorMessageContentTemplate;
receiverMessageContentTemplate;
messageContentTemplate;
authorMessageTemplate;
receiverMessageTemplate;
messageTemplate;
statusTemplate;
showMessageTime = true;
authorId;
cssClass = true;
get removedClass() {
return this.message.isDeleted;
}
onKeyDown(event) {
if (this.message.isDeleted) {
return;
}
if (!this.chatService.allowMessageCollapse) {
return;
}
this.onExpandableKeydown(event);
}
selected;
get tabIndex() {
return this.tabbable ? '0' : '-1';
}
expandIcon = chevronDownIcon;
collapseIcon = chevronUpIcon;
downloadIcon = downloadIcon;
isMessageExpanded = false;
showExpandCollapseIcon = false;
fileActions = [];
toolbarActions = [];
parts = [];
get useCustomBubbleTemplate() {
return !!(this.getActiveBubbleTemplate());
}
get useCustomContentTemplate() {
return !!(this.getActiveContentTemplate());
}
get hasMessageContent() {
return !!(this.message?.text || this.message?.files?.length > 0);
}
get hasFiles() {
return this.message?.files?.length > 0;
}
get hasMultipleFiles() {
return this.message?.files?.length > 1;
}
get isActiveMessage() {
return this.chatService.active && this.message?.id === this.chatService.activeMessage?.id;
}
get isMessageExpandable() {
const isOwn = this.isOwnMessage(this.message);
const messageSettings = isOwn
? this.chatService.authorMessageSettings
: this.chatService.receiverMessageSettings;
if (isPresent(messageSettings?.allowMessageCollapse)) {
return messageSettings.allowMessageCollapse;
}
return this.chatService.allowMessageCollapse || false;
}
get showToolbar() {
if (this.message?.isDeleted) {
return false;
}
const hasComponentActions = this.chatService.messageToolbarActions?.length > 0;
const hasMessageActions = this.toolbarActions?.length > 0;
return hasComponentActions || hasMessageActions;
}
subs = new Subscription();
_message;
constructor(element, intl, chatService, localization, cdr) {
super();
this.element = element;
this.intl = intl;
this.chatService = chatService;
this.localization = localization;
this.cdr = cdr;
}
ngOnInit() {
this.fileActions = this.getFileActions();
this.toolbarActions = this.getToolbarActions();
const settingsChange$ = this.isOwnMessage(this.message)
? this.chatService.authorMessageSettingsChange$
: this.chatService.receiverMessageSettingsChange$;
this.subs.add(settingsChange$.subscribe(() => {
this.fileActions = this.getFileActions();
this.toolbarActions = this.getToolbarActions();
setTimeout(() => {
this.showExpandCollapseIcon = this.calculateExpandCollapseIconVisibility();
});
}));
this.subs.add(this.chatService.allowMessageCollapseChange$.subscribe(() => {
setTimeout(() => {
this.showExpandCollapseIcon = this.calculateExpandCollapseIconVisibility();
});
}));
if (this.message.id) {
this.chatService.registerMessageElement(this.message.id, this.element);
}
this.parts = this.getFormattedTextParts(this.message.text);
}
ngAfterViewInit() {
this.showExpandCollapseIcon = this.calculateExpandCollapseIconVisibility();
this.cdr.detectChanges();
}
ngOnDestroy() {
if (this.message.id) {
this.chatService.unregisterMessageElement(this.message.id);
}
this.subs.unsubscribe();
}
calculateExpandCollapseIconVisibility() {
if (this.isMessageExpanded) {
return true;
}
const bubbleContent = this.element.nativeElement.querySelector('.k-bubble-content');
if (!bubbleContent) {
return false;
}
const hasVerticalOverflow = bubbleContent.scrollHeight > bubbleContent.clientHeight;
const hasHorizontalOverflow = bubbleContent.scrollWidth > bubbleContent.clientWidth;
if (this.useCustomContentTemplate) {
return hasVerticalOverflow || hasHorizontalOverflow;
}
const messageText = this.element.nativeElement.querySelector('.k-chat-bubble-text');
const hasTextOverflow = messageText?.scrollWidth > messageText?.clientWidth;
return hasTextOverflow || hasVerticalOverflow || hasHorizontalOverflow;
}
getActiveBubbleTemplate() {
const isOwn = this.isOwnMessage(this.message);
if (isOwn && this.authorMessageTemplate) {
return this.authorMessageTemplate;
}
if (!isOwn && this.receiverMessageTemplate) {
return this.receiverMessageTemplate;
}
if (this.messageTemplate) {
return this.messageTemplate;
}
return null;
}
getActiveContentTemplate() {
const isOwn = this.isOwnMessage(this.message);
if (isOwn && this.authorMessageContentTemplate) {
return this.authorMessageContentTemplate;
}
if (!isOwn && this.receiverMessageContentTemplate) {
return this.receiverMessageContentTemplate;
}
if (this.messageContentTemplate) {
return this.messageContentTemplate;
}
return null;
}
getDeletedMessageText() {
const isOwn = this.isOwnMessage(this.message);
return isOwn ? this.textFor('deletedMessageSenderText') : this.textFor('deletedMessageReceiverText');
}
textFor(key) {
return this.localization.get(key);
}
formatTimeStamp(date) {
return this.intl.formatDate(date, { datetime: 'short' });
}
focus() {
this.element.nativeElement.focus();
}
onDownloadAll() {
this.chatService.emit('fileDownload', { files: this.message.files, message: this.message });
}
toggleMessageState(event) {
event.stopImmediatePropagation();
this.isMessageExpanded = !this.isMessageExpanded;
this.chatService.toggleMessageState = false;
}
onExpandableKeydown(event) {
const key = normalizeKeys(event);
const isFileActionButton = event.target.closest(FILE_ACTION_BTN_SELECTOR) || event.target.closest(DOWNLOAD_ALL_SELECTOR);
if (!isFileActionButton && (key === Keys.Enter || key === Keys.Space)) {
event.preventDefault();
this.chatService.toggleMessageState = true;
this.toggleMessageState(event);
}
}
onToolbarAction(event, action, message) {
event.stopImmediatePropagation();
this.chatService.emit('toolbarAction', { action, message });
}
onFileAction(action, file) {
if (action.originalAction.id === 'download') {
this.chatService.emit('fileDownload', { files: [file], message: this.message });
}
this.chatService.emit('fileAction', { action: action.originalAction, file });
}
getMessageById(id) {
return this.chatService.getMessageById(id);
}
onReplyReferenceClick(event, replyToId) {
event.stopPropagation();
this.chatService.emit('replyReferenceClick', replyToId);
}
handleMenuClose(event) {
if (event) {
const originalEvent = event.originalEvent;
if (originalEvent) {
this.onActionButtonClick(originalEvent);
}
}
this.chatService.active = false;
this.chatService.emit('contextMenuVisibilityChange', false);
if (this.chatService.selectOnMenuClose) {
this.selected = true;
this.focus();
}
}
onActionButtonClick(event) {
const clickOutsideMessage = event instanceof MouseEvent && !event.target?.closest('.k-chat-bubble');
const menuItemClick = event instanceof MouseEvent && event.target?.closest(MENU_ITEM_SELECTOR);
if (clickOutsideMessage && !menuItemClick) {
this.chatService.selectOnMenuClose = false;
}
}
handleMenuOpen() {
this.chatService.selectOnMenuClose = this.selected;
this.chatService.emit('contextMenuVisibilityChange', true);
}
onActionPopupChange(expanded) {
if (expanded) {
this.chatService.active = true;
this.handleMenuOpen();
}
else {
this.handleMenuClose();
}
}
isOwnMessage(msg) {
return isAuthor(this.authorId, msg);
}
getFormattedTextParts(text) {
if (!text) {
return [];
}
const parts = [];
const urlMatches = Array.from(text.matchAll(URL_REGEX));
let lastIndex = 0;
for (const match of urlMatches) {
const url = match[1];
const matchStart = match.index;
if (!isPresent(matchStart)) {
continue;
}
if (matchStart > lastIndex) {
parts.push({ type: 'text', content: text.substring(lastIndex, matchStart) });
}
parts.push({ type: 'link', content: url, href: url });
lastIndex = matchStart + match[0].length;
}
if (lastIndex < text.length) {
parts.push({ type: 'text', content: text.substring(lastIndex) });
}
return parts;
}
getMessageSettings() {
return this.isOwnMessage(this.message)
? this.chatService.authorMessageSettings
: this.chatService.receiverMessageSettings;
}
getToolbarActions() {
const messageSettings = this.getMessageSettings();
return messageSettings?.messageToolbarActions?.length
? messageSettings.messageToolbarActions
: this.chatService.messageToolbarActions || [];
}
getFileActions() {
const messageSettings = this.getMessageSettings();
const actions = messageSettings?.fileActions?.length
? messageSettings.fileActions
: this.chatService.fileActions || [];
return transformActions(actions);
}
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 });
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: [
{
provide: ChatItem,
useExisting: forwardRef(() => MessageComponent)
}
], usesInheritance: true, ngImport: i0, template: `
(useCustomBubbleTemplate) {
<ng-container *ngTemplateOutlet="getActiveBubbleTemplate()?.templateRef; context: { $implicit: message };"></ng-container>
}
(!useCustomBubbleTemplate) {
(chatService.timestampVisibility === 'focus' && message.timestamp) {
<time
[attr.aria-hidden]="!selected"
class="k-message-time"
>
{{ formatTimeStamp(message.timestamp) }}
</time>
}
(message.typing) {
<div class="k-chat-bubble k-bubble">
<div class="k-typing-indicator" [attr.tabindex]="'-1'">
<span></span>
<span></span>
<span></span>
</div>
</div>
}
(!message.typing) {
(useCustomContentTemplate) {
<div
class="k-chat-bubble k-bubble"
[attr.tabindex]="0"
[ngClass]="{
'k-bubble-expandable': isMessageExpandable,
'k-expanded': isMessageExpanded,
'k-selected': selected,
'k-focus': selected,
'k-active': isActiveMessage
}"
>
<div class="k-bubble-content">
<ng-container *ngTemplateOutlet="getActiveContentTemplate()?.templateRef; context: { $implicit: message };"></ng-container>
</div>
(isMessageExpandable && showExpandCollapseIcon) {
<span
class="k-bubble-expandable-indicator"
[attr.tabindex]="'0'"
[attr.role]="'button'"
[attr.title]="isMessageExpanded ? textFor('collapseTitle') : textFor('expandTitle')"
(mousedown)="chatService.toggleMessageState = true"
(click)="toggleMessageState($event)"
>
<kendo-icon-wrapper
[name]="isMessageExpanded ? 'chevron-up' : 'chevron-down'"
[svgIcon]="isMessageExpanded ? collapseIcon : expandIcon"
>
</kendo-icon-wrapper>
</span>
}
</div>
}
(!useCustomContentTemplate && hasMessageContent) {
<div
class="k-chat-bubble k-bubble"
[attr.tabindex]="0"
[ngClass]="{
'k-bubble-expandable': isMessageExpandable,
'k-expanded': isMessageExpanded,
'k-selected': selected,
'k-focus': selected,
'k-active': isActiveMessage
}"
>
<div class="k-bubble-content">
(message.text || message.isDeleted) {
(message.replyToId && !message.isDeleted) {
<div
class="k-message-reference k-message-reference-receiver"
(click)="onReplyReferenceClick($event, message.replyToId)"
>
<chat-message-reference-content [message]="getMessageById(message.replyToId)"></chat-message-reference-content>
</div>
}
(message.isDeleted) {
<span class="k-chat-bubble-text">
{{ getDeletedMessageText() }}
</span>
}
(!message.isDeleted && parts.length > 0) {
<span class="k-chat-bubble-text">
(part of parts; track part) {
(part.type === 'text') {{{part.content}}}
(part.type === 'link') {<a [href]="part.href" target="_blank">{{part.content}}</a>}
}
</span>
}
}
(hasFiles && !message.isDeleted) {
<ul
class="k-chat-file-wrapper"
[ngClass]="{
'k-chat-files-wrap': chatService.messageFilesLayout === 'wrap',
'k-chat-files-horizontal': chatService.messageFilesLayout === 'horizontal'
}"
>
(file of message.files; track file) {
<li
class="k-chat-file"
[chatFile]="file"
[fileActions]="fileActions"
(actionClick)="onFileAction($event, file)"
(actionsToggle)="onActionPopupChange($event)"
(actionButtonClick)="onActionButtonClick($event)"
></li>
}
</ul>
}
(hasMultipleFiles && !message.isDeleted) {
<div class="k-chat-download-button-wrapper">
<button
kendoButton
class="k-chat-download-button"
fillMode="flat"
icon="download"
[svgIcon]="downloadIcon"
[attr.title]="textFor('downloadAllFilesText')"
(click)="onDownloadAll()"
>{{ textFor('downloadAllFilesText') }}</button>
</div>
}
</div>
(isMessageExpandable && showExpandCollapseIcon) {
<span
class="k-bubble-expandable-indicator"
[attr.tabindex]="'0'"
[attr.role]="'button'"
[attr.title]="isMessageExpanded ? textFor('collapseTitle') : textFor('expandTitle')"
(mousedown)="chatService.toggleMessageState = true"
(click)="toggleMessageState($event)"
>
<kendo-icon-wrapper
[name]="isMessageExpanded ? 'chevron-up' : 'chevron-down'"
[svgIcon]="isMessageExpanded ? collapseIcon : expandIcon"
>
</kendo-icon-wrapper>
</span>
}
</div>
}
}
(message.status) {
<span class="k-message-status">
(statusTemplate?.templateRef) {
<ng-template
[ngTemplateOutlet]="statusTemplate.templateRef"
[ngTemplateOutletContext]="{ $implicit: message.status, message }"
>
</ng-template>
}
(!statusTemplate?.templateRef) {
{{ message.status }}
}
</span>
}
}
(showToolbar) {
<kendo-toolbar class="k-chat-message-toolbar" fillMode="flat">
(action of toolbarActions; track action) {
<kendo-toolbar-button
fillMode="flat"
[icon]="action.icon"
[svgIcon]="action.svgIcon"
[disabled]="action.disabled"
[title]="action.label"
(click)="onToolbarAction($event, action, message)"
>
</kendo-toolbar-button>
}
</kendo-toolbar>
}
`, 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"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: MessageComponent, decorators: [{
type: Component,
args: [{
selector: 'kendo-chat-message',
providers: [
{
provide: ChatItem,
useExisting: forwardRef(() => MessageComponent)
}
],
template: `
(useCustomBubbleTemplate) {
<ng-container *ngTemplateOutlet="getActiveBubbleTemplate()?.templateRef; context: { $implicit: message };"></ng-container>
}
(!useCustomBubbleTemplate) {
(chatService.timestampVisibility === 'focus' && message.timestamp) {
<time
[attr.aria-hidden]="!selected"
class="k-message-time"
>
{{ formatTimeStamp(message.timestamp) }}
</time>
}
(message.typing) {
<div class="k-chat-bubble k-bubble">
<div class="k-typing-indicator" [attr.tabindex]="'-1'">
<span></span>
<span></span>
<span></span>
</div>
</div>
}
(!message.typing) {
(useCustomContentTemplate) {
<div
class="k-chat-bubble k-bubble"
[attr.tabindex]="0"
[ngClass]="{
'k-bubble-expandable': isMessageExpandable,
'k-expanded': isMessageExpanded,
'k-selected': selected,
'k-focus': selected,
'k-active': isActiveMessage
}"
>
<div class="k-bubble-content">
<ng-container *ngTemplateOutlet="getActiveContentTemplate()?.templateRef; context: { $implicit: message };"></ng-container>
</div>
(isMessageExpandable && showExpandCollapseIcon) {
<span
class="k-bubble-expandable-indicator"
[attr.tabindex]="'0'"
[attr.role]="'button'"
[attr.title]="isMessageExpanded ? textFor('collapseTitle') : textFor('expandTitle')"
(mousedown)="chatService.toggleMessageState = true"
(click)="toggleMessageState($event)"
>
<kendo-icon-wrapper
[name]="isMessageExpanded ? 'chevron-up' : 'chevron-down'"
[svgIcon]="isMessageExpanded ? collapseIcon : expandIcon"
>
</kendo-icon-wrapper>
</span>
}
</div>
}
(!useCustomContentTemplate && hasMessageContent) {
<div
class="k-chat-bubble k-bubble"
[attr.tabindex]="0"
[ngClass]="{
'k-bubble-expandable': isMessageExpandable,
'k-expanded': isMessageExpanded,
'k-selected': selected,
'k-focus': selected,
'k-active': isActiveMessage
}"
>
<div class="k-bubble-content">
(message.text || message.isDeleted) {
(message.replyToId && !message.isDeleted) {
<div
class="k-message-reference k-message-reference-receiver"
(click)="onReplyReferenceClick($event, message.replyToId)"
>
<chat-message-reference-content [message]="getMessageById(message.replyToId)"></chat-message-reference-content>
</div>
}
(message.isDeleted) {
<span class="k-chat-bubble-text">
{{ getDeletedMessageText() }}
</span>
}
(!message.isDeleted && parts.length > 0) {
<span class="k-chat-bubble-text">
(part of parts; track part) {
(part.type === 'text') {{{part.content}}}
(part.type === 'link') {<a [href]="part.href" target="_blank">{{part.content}}</a>}
}
</span>
}
}
(hasFiles && !message.isDeleted) {
<ul
class="k-chat-file-wrapper"
[ngClass]="{
'k-chat-files-wrap': chatService.messageFilesLayout === 'wrap',
'k-chat-files-horizontal': chatService.messageFilesLayout === 'horizontal'
}"
>
(file of message.files; track file) {
<li
class="k-chat-file"
[chatFile]="file"
[fileActions]="fileActions"
(actionClick)="onFileAction($event, file)"
(actionsToggle)="onActionPopupChange($event)"
(actionButtonClick)="onActionButtonClick($event)"
></li>
}
</ul>
}
(hasMultipleFiles && !message.isDeleted) {
<div class="k-chat-download-button-wrapper">
<button
kendoButton
class="k-chat-download-button"
fillMode="flat"
icon="download"
[svgIcon]="downloadIcon"
[attr.title]="textFor('downloadAllFilesText')"
(click)="onDownloadAll()"
>{{ textFor('downloadAllFilesText') }}</button>
</div>
}
</div>
(isMessageExpandable && showExpandCollapseIcon) {
<span
class="k-bubble-expandable-indicator"
[attr.tabindex]="'0'"
[attr.role]="'button'"
[attr.title]="isMessageExpanded ? textFor('collapseTitle') : textFor('expandTitle')"
(mousedown)="chatService.toggleMessageState = true"
(click)="toggleMessageState($event)"
>
<kendo-icon-wrapper
[name]="isMessageExpanded ? 'chevron-up' : 'chevron-down'"
[svgIcon]="isMessageExpanded ? collapseIcon : expandIcon"
>
</kendo-icon-wrapper>
</span>
}
</div>
}
}
(message.status) {
<span class="k-message-status">
(statusTemplate?.templateRef) {
<ng-template
[ngTemplateOutlet]="statusTemplate.templateRef"
[ngTemplateOutletContext]="{ $implicit: message.status, message }"
>
</ng-template>
}
(!statusTemplate?.templateRef) {
{{ message.status }}
}
</span>
}
}
(showToolbar) {
<kendo-toolbar class="k-chat-message-toolbar" fillMode="flat">
(action of toolbarActions; track action) {
<kendo-toolbar-button
fillMode="flat"
[icon]="action.icon"
[svgIcon]="action.svgIcon"
[disabled]="action.disabled"
[title]="action.label"
(click)="onToolbarAction($event, action, message)"
>
</kendo-toolbar-button>
}
</kendo-toolbar>
}
`,
standalone: true,
imports: [NgClass, NgTemplateOutlet, IconWrapperComponent, KENDO_BUTTONS, ChatFileComponent, ToolBarComponent, ToolBarButtonComponent, MessageReferenceComponent],
}]
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: i1.IntlService }, { type: i2.ChatService }, { type: i3.LocalizationService }, { type: i0.ChangeDetectorRef }], propDecorators: { message: [{
type: Input
}], tabbable: [{
type: Input
}], authorMessageContentTemplate: [{
type: Input
}], receiverMessageContentTemplate: [{
type: Input
}], messageContentTemplate: [{
type: Input
}], authorMessageTemplate: [{
type: Input
}], receiverMessageTemplate: [{
type: Input
}], messageTemplate: [{
type: Input
}], statusTemplate: [{
type: Input
}], showMessageTime: [{
type: Input
}], authorId: [{
type: Input
}], cssClass: [{
type: HostBinding,
args: ['class.k-message']
}], removedClass: [{
type: HostBinding,
args: ['class.k-message-removed']
}], onKeyDown: [{
type: HostListener,
args: ['keydown', ['$event']]
}], tabIndex: [{
type: HostBinding,
args: ['attr.tabIndex']
}] } });