@progress/kendo-angular-conversational-ui
Version:
Kendo UI for Angular Conversational UI components
1,016 lines (977 loc) • 47.6 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 { Component, ContentChild, ElementRef, EventEmitter, HostBinding, Input, isDevMode, Output, ViewChild, NgZone, Renderer2, ViewContainerRef } from '@angular/core';
import { AttachmentTemplateDirective } from './templates/attachment-template.directive';
import { L10N_PREFIX, LocalizationService } from '@progress/kendo-angular-l10n';
import { makeHandler } from './builtin-actions';
import { Subscription } from 'rxjs';
import { validatePackage } from '@progress/kendo-licensing';
import { packageMetadata } from '../package-metadata';
import { ChatMessageBoxTemplateDirective } from './templates/message-box.directive';
import { MessageBoxComponent } from './message-box.component';
import { MessageListComponent } from './message-list.component';
import { ScrollAnchorDirective } from './common/scroll-anchor.directive';
import { LocalizedMessagesDirective } from './l10n/localized-messages.directive';
import { isChanged, isPresent, processCssValue } from '@progress/kendo-angular-common';
import { ChatService } from './common/chat.service';
import { AppBarComponent } from "@progress/kendo-angular-navigation";
import { ChatHeaderTemplateDirective } from './templates/header-template.directive';
import { NgTemplateOutlet } from '@angular/common';
import { KENDO_BUTTON } from '@progress/kendo-angular-buttons';
import { pinIcon, xIcon } from '@progress/kendo-svg-icons';
import { IconWrapperComponent } from '@progress/kendo-angular-icons';
import { defaultModelFields } from './common/models/default-model-fields';
import { processMessages, SEND_BTN_DEFAULT_SETTINGS, FILE_ACTIONS, CONTEXT_MENU_ACTIONS, transformActions, MENU_ITEM_SELECTOR } from './common/utils';
import { ChatTimestampTemplateDirective } from './templates/timestamp-template.directive';
import { MessageReferenceComponent } from './message-reference-content.component';
import { ChatStatusTemplateDirective } from './templates/status-template.directive';
import { ChatSuggestionTemplateDirective } from './templates/suggestion-template.directive';
import { ContextMenuComponent } from '@progress/kendo-angular-menu';
import { NoDataTemplateDirective, MessageTemplateDirective, AuthorMessageContentTemplateDirective, ReceiverMessageContentTemplateDirective, ReceiverMessageTemplateDirective, AuthorMessageTemplateDirective, MessageContentTemplateDirective } from './chat.directives';
import { ChatUserStatusTemplateDirective } from './templates/user-status-template.directive';
import { SuggestionsScrollService } from './common/scroll.service';
import * as i0 from "@angular/core";
import * as i1 from "@progress/kendo-angular-l10n";
import * as i2 from "./common/chat.service";
import * as i3 from "@progress/kendo-angular-buttons";
/**
* Represents the [Kendo UI Chat component for Angular](slug:overview_convui).
*
* Provides a conversational UI for chat-based applications.
* Supports message templates, attachments, localization, and user actions.
*
* @example
* ```html
* <kendo-chat
* [messages]="messages"
* [authorId]="authorId"
* (sendMessage)="onSendMessage($event)"
* (executeAction)="onExecuteAction($event)">
* </kendo-chat>
* ```
*
* @remarks
* Supported children components are: {@link CustomMessagesComponent}, {@link HeroCardComponent}, {@link AttachmentTemplateDirective}, {@link ChatHeaderTemplateDirective}, {@link ChatMessageBoxTemplateDirective}, {@link MessageContentTemplateDirective}, {@link MessageTemplateDirective},{@link ChatStatusTemplateDirective}, {@link ChatSuggestionTemplateDirective}, {@link ChatTimestampTemplateDirective}, {@link ChatNoDataTemplateDirective}, {@link ChatUserStatusTemplateDirective}, {@link AuthorMessageContentTemplateDirective}, {@link ReceiverMessageContentTemplateDirective}, {@link ReceiverMessageTemplateDirective}, {@link AuthorMessageTemplateDirective}.
*/
export class ChatComponent {
localization;
zone;
renderer;
element;
chatService;
/**
* Sets the Chat messages.
* Accepts an array of `Message` objects, but can also accept custom data types.
* For more information, check [Data Binding](slug:databinding_chat) section in the documentation.
*/
messages;
/**
* Sets the ID that represents the local user.
*/
authorId;
/**
* Determines the type of input used in the message box.
* ([see example](slug:message_chat)).
* @default 'textarea'
*
* @hidden
*/
messageBoxType = 'textarea';
/**
* Sets the height of the Chat component.
* Accepts a string with CSS units (for example, `'400px'`, `'50%'`) or a number (interpreted as pixels).
* The minimum height is `600px`.
*/
height;
/**
* Sets the width of the Chat component.
* Accepts a string with CSS units (for example, `'400px'`, `'50%'`) or a number (interpreted as pixels).
* The minimum width is `320px`.
*/
width;
/**
* Sets the placeholder text for the message input box.
*/
placeholder;
/**
* Controls the width of the message between the predefined options.
*
* @default 'standard'
*/
messageWidthMode = 'standard';
/**
* Controls the visibility of timestamps in messages.
*
* @default 'focus'
*/
timestampVisibility = 'focus';
/**
* Controls the visibility of usernames in messages.
* When set to `true`, the username displays above each message bubble.
*
* @default true
*/
showUsername = true;
/**
* Controls the avatar visibility for the messages.
* When set to `true`, the user avatar displays next to each message bubble.
*
* @default true
*/
showAvatar = true;
/**
* Enables the expand or collapse functionality for messages.
*
* @default false
*/
allowMessageCollapse = false;
/**
* Sets the Speech to Text button settings.
*
* @default true
*/
enableSpeechToText = true;
/**
* Sets the File Select settings.
*
* @default true
*/
enableFileSelect = true;
/**
* Sets the actions of the message toolbar.
* These actions display in the message toolbar and let you perform specific operations on the message.
*
* @default []
*/
messageToolbarActions = [];
/**
* Sets the value of the Message Box.
*
* @default ''
*/
inputValue = '';
/**
* Sets the settings for the author's messages.
*/
authorMessageSettings;
/**
* Sets the settings for the receivers' messages.
*/
receiverMessageSettings;
/**
* Sets the default actions that display in the message context menu.
*
* @default [{ id: 'copy', label: 'Copy', icon: 'copy', svgIcon: copyIcon, disabled: false }, { id: 'reply', label: 'Reply', icon: 'undo', svgIcon: undoIcon, disabled: false }]
*/
defaultContextMenuActions = CONTEXT_MENU_ACTIONS;
/**
* Sets the actions that display in the message as a context menu.
* These actions display as menu items and let you perform specific operations on the message.
* The default actions are `copy` and `reply` and are defined by their `id`.
*/
set messageContextMenuActions(actions) {
this._messageContextMenuActions = this.mergeWithDefaultActions(actions, CONTEXT_MENU_ACTIONS);
}
get messageContextMenuActions() {
return this._messageContextMenuActions;
}
/**
* Sets the default actions that display in the file actions DropDownButton.
*
* @default [{ id: 'download', label: 'Download', icon: 'download', svgIcon: downloadIcon, disabled: false }]
*/
defaultFileActions = FILE_ACTIONS;
/**
* Sets the actions that display in the file as items of a DropDownButton.
* These actions display when you click the file DropDownButton and let you perform specific operations on the file.
* The default action is `download` and is defined by its `id`.
*
* @default [{ id: 'download', label: 'Download', icon: 'download', svgIcon: downloadIcon, disabled: false }]
*/
set fileActions(actions) {
this._fileActions = this.mergeWithDefaultActions(actions, FILE_ACTIONS);
}
get fileActions() {
return this._fileActions;
}
/**
* Sets the layout of the files in the message bubble.
*
* @default 'vertical'
*/
set messageFilesLayout(layout) {
this.chatService.messageFilesLayout = layout;
}
/**
* Sets the layout of the suggestions above the message input box.
*
* @default 'scroll'
*/
set suggestionsLayout(layoutMode) {
if (layoutMode) {
this.chatService.suggestionsLayout = layoutMode;
}
}
/**
* Sets the layout of the quick actions suggested below the messages.
*
* @default 'scroll'
*/
set quickActionsLayout(layoutMode) {
if (layoutMode) {
this.chatService.quickActionsLayout = layoutMode;
}
}
/**
* Sets the suggestions that display in the message input box.
* Suggestions display as a list of clickable items that let you quickly insert predefined text into the message input.
*
* @default []
*/
suggestions = [];
/**
* Sets the send button settings for the Chat component.
* Allows customization of the send button appearance, icons and disabled state.
*
* @default { fillMode: 'solid', rounded: 'full', size: 'medium', themeColor: 'primary', icon: 'paper-plane', svgIcon: paperPlaneIcon}
*/
sendButtonSettings = SEND_BTN_DEFAULT_SETTINGS;
/**
* Sets the names of the model fields from which the Chat reads its data.
* Lets you map custom data types to the expected `Message` format.
*/
set modelFields(value) {
this._modelFields = { ...defaultModelFields, ...value };
}
get modelFields() {
return this._modelFields;
}
/**
* Fires when the user sends a message by clicking the **Send** button or pressing **Enter**.
*
* The message is not automatically added to the `messages` array.
*/
sendMessage = new EventEmitter();
/**
* Fires when the user clicks a quick action button in the message toolbar.
*/
toolbarActionClick = new EventEmitter();
/**
* Fires when the user clicks an action in the message context menu.
*/
contextMenuActionClick = new EventEmitter();
/**
* Fires when the user clicks an action in the file context menu.
*/
fileActionClick = new EventEmitter();
/**
* Fires when the user clicks an action in the file context menu.
*/
download = new EventEmitter();
/**
* Fires when the user clicks a quick action button.
* The Chat internally handles [known actions](slug:api_conversational-ui_actiontype) such as `reply`, `openUrl`, and `call`.
*
* The event is preventable. Calling [`preventDefault`](https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault) suppresses the built-in action.
*/
executeAction = new EventEmitter();
/**
* Fires when the user clicks a suggestion in the message input box.
*/
suggestionExecute = new EventEmitter();
/**
* Fires when the user selects a file in the message input box.
*/
fileSelect = new EventEmitter();
/**
* Fires when the user removes a file from the message input box.
*/
fileRemove = new EventEmitter();
/**
* Fires when the user unpins the pinned message.
* This event triggers when the user clicks the delete button on the pinned message.
*/
unpin = new EventEmitter();
/**
* Fires when the user types in the message input box.
*/
inputValueChange = new EventEmitter();
get className() {
return 'k-chat';
}
get dirAttr() {
return this.direction;
}
set messagesContextMenu(contextMenu) {
this.chatService.messagesContextMenu = contextMenu;
}
attachmentTemplate;
chatHeaderTemplate;
chatNoDataTemplate;
authorMessageContentTemplate;
receiverMessageContentTemplate;
messageContentTemplate;
authorMessageTemplate;
receiverMessageTemplate;
messageTemplate;
timestampTemplate;
suggestionTemplate;
statusTemplate;
messageBoxTemplate;
userStatusTemplate;
messageBox;
/**
* @hidden
*/
messageList;
/**
* @hidden
* Returns processed messages when model fields are used, otherwise returns original messages.
*/
get processedMessages() {
if (!this.messages || this.messages.length === 0) {
return [];
}
if (this._modelFields && Object.keys(this._modelFields).some(key => this._modelFields[key] !== defaultModelFields[key])) {
if (this.messages !== this._lastMessagesReference || this._modelFields !== this._lastModelFields) {
this._cachedProcessedMessages = processMessages(this.messages, this._modelFields);
this._lastMessagesReference = this.messages;
this._lastModelFields = this._modelFields;
}
return this._cachedProcessedMessages;
}
return this.messages;
}
/**
* Gets the actions available in the message context menu.
*
* @hidden
*/
get contextMenuActions() {
const currentActions = this.chatService.calculatedContextMenuActions;
if (currentActions !== this._lastContextMenuActionsReference) {
this._cachedContextMenuActions = transformActions(currentActions);
this._lastContextMenuActionsReference = currentActions;
}
return this._cachedContextMenuActions;
}
/**
* @hidden
*/
get localizationText() {
return this.localization;
}
/**
* @hidden
*/
autoScroll = true;
/**
* @hidden
*/
pinIcon = pinIcon;
/**
* @hidden
*/
deleteIcon = xIcon;
/**
* @hidden
*/
pinnedMessage;
direction;
subs = new Subscription();
_modelFields = defaultModelFields;
_messageContextMenuActions = CONTEXT_MENU_ACTIONS;
_fileActions = FILE_ACTIONS;
_cachedProcessedMessages = [];
_lastMessagesReference = null;
_lastModelFields = null;
_cachedContextMenuActions = [];
_lastContextMenuActionsReference = null;
constructor(localization, zone, renderer, element, chatService) {
this.localization = localization;
this.zone = zone;
this.renderer = renderer;
this.element = element;
this.chatService = chatService;
validatePackage(packageMetadata);
this.direction = localization.rtl ? 'rtl' : 'ltr';
this.subs.add(localization.changes.subscribe(({ rtl }) => {
this.direction = rtl ? 'rtl' : 'ltr';
}));
}
/**
* @hidden
*/
ngOnInit() {
this.chatService.messageWidthMode = this.messageWidthMode;
this.chatService.timestampVisibility = this.timestampVisibility;
this.chatService.showUsername = this.showUsername;
this.chatService.showAvatar = this.showAvatar;
this.chatService.allowMessageCollapse = this.allowMessageCollapse;
this.chatService.enableSpeechToText = this.enableSpeechToText;
this.chatService.sendButtonSettings = this.sendButtonSettings;
this.chatService.enableFileSelect = this.enableFileSelect;
this.chatService.messageToolbarActions = this.messageToolbarActions;
this.chatService.messageContextMenuActions = this.messageContextMenuActions;
this.chatService.fileActions = this.fileActions;
this.chatService.authorMessageSettings = this.authorMessageSettings;
this.chatService.receiverMessageSettings = this.receiverMessageSettings;
this.chatService.messages = this.processedMessages || [];
this.chatService.chatElement = this.messageList;
this.subs.add(this.chatService.toolbarAction$.subscribe((actionEvent) => {
this.toolbarActionClick.emit(actionEvent);
}));
this.subs.add(this.chatService.contextMenuAction$.subscribe((actionEvent) => {
this.contextMenuActionClick.emit(actionEvent);
}));
this.subs.add(this.chatService.fileAction$.subscribe((actionEvent) => {
this.fileActionClick.emit(actionEvent);
}));
this.subs.add(this.chatService.fileDownload$.subscribe((actionEvent) => {
this.download.emit(actionEvent);
}));
this.subs.add(this.chatService.inputValueChange$.subscribe((value) => {
this.inputValueChange.emit(value);
}));
this.pinnedMessage = this.findLastPinnedMessage();
this.chatService.authorId = this.authorId;
}
/**
* @hidden
*/
ngOnChanges(changes) {
this.zone.runOutsideAngular(() => setTimeout(() => {
this.messageList.element.nativeElement.style.flex = '1 1 auto';
}));
if (isChanged('messages', changes, false)) {
this.pinnedMessage = this.findLastPinnedMessage();
this.chatService.messages = this.processedMessages;
}
if (isChanged('height', changes, false)) {
this.renderer.setStyle(this.element.nativeElement, 'height', `${processCssValue(this.height)}`);
}
if (isChanged('width', changes, false)) {
this.renderer.setStyle(this.element.nativeElement, 'width', `${processCssValue(this.width)}`);
}
this.updateChatServiceProperties([
'authorId',
'messageWidthMode',
'timestampVisibility',
'showUsername',
'showAvatar',
'allowMessageCollapse',
'enableSpeechToText',
'sendButtonSettings',
'enableFileSelect',
'messageToolbarActions',
'messageContextMenuActions',
'fileActions',
'authorMessageSettings',
'receiverMessageSettings'
], changes);
}
/**
* @hidden
*/
ngAfterViewInit() {
if (!isDevMode()) {
return;
}
if (!isPresent(this.authorId)) {
throw new Error('AuthorId must be set.');
}
}
/**
* @hidden
*/
ngOnDestroy() {
if (this.subs) {
this.subs.unsubscribe();
}
}
/**
* @hidden
*/
dispatchAction(e) {
this.executeAction.emit(e);
if (!e.isDefaultPrevented()) {
const handler = makeHandler(e.action);
handler(e.action, this);
if (!this.messageBoxTemplate) {
this.messageBox.messageBoxInput.focus();
}
}
}
/**
* @hidden
*/
textFor(key) {
return this.localization.get(key);
}
/**
* @hidden
*/
scrollToPinnedMessage() {
if (this.pinnedMessage) {
this.chatService.scrollToMessage(this.pinnedMessage?.id);
}
}
/**
* @hidden
*/
onContextMenuAction(action) {
if (action.id === 'reply') {
this.chatService.reply = this.chatService.activeMessage;
}
if (action.id === 'copy') {
navigator.clipboard.writeText(this.chatService.activeMessage.text);
}
this.chatService.emit('contextMenuAction', { action, message: this.chatService.activeMessage });
}
/**
* @hidden
*/
handleMenuClose(event) {
if (event) {
const originalEvent = event.originalEvent;
originalEvent && this.onActionButtonClick(originalEvent);
}
this.chatService.activeMessage = null;
this.chatService.emit('contextMenuVisibilityChange', false);
if (this.chatService.selectOnMenuClose) {
this.chatService.activeMessageElement.selected = true;
this.chatService.focusActiveMessageElement();
}
}
/**
* @hidden
*/
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;
}
}
findLastPinnedMessage() {
return [...this.processedMessages].reverse().find((message) => message.isPinned);
}
updateChatServiceProperties(propNames, changes) {
propNames.forEach(propName => {
if (isChanged(propName, changes, false)) {
this.chatService[propName] = this[propName];
}
});
}
mergeWithDefaultActions(actions, defaultActions) {
if (!actions || actions.length === 0) {
return [];
}
return actions.map(userAction => {
const defaultAction = defaultActions.find(action => action.id === userAction?.id);
if (defaultAction) {
return { ...defaultAction, ...userAction };
}
return userAction;
});
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ChatComponent, deps: [{ token: i1.LocalizationService }, { token: i0.NgZone }, { token: i0.Renderer2 }, { token: i0.ElementRef }, { token: i2.ChatService }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ChatComponent, isStandalone: true, selector: "kendo-chat", inputs: { messages: "messages", authorId: "authorId", messageBoxType: "messageBoxType", height: "height", width: "width", placeholder: "placeholder", messageWidthMode: "messageWidthMode", timestampVisibility: "timestampVisibility", showUsername: "showUsername", showAvatar: "showAvatar", allowMessageCollapse: "allowMessageCollapse", enableSpeechToText: "enableSpeechToText", enableFileSelect: "enableFileSelect", messageToolbarActions: "messageToolbarActions", inputValue: "inputValue", authorMessageSettings: "authorMessageSettings", receiverMessageSettings: "receiverMessageSettings", messageContextMenuActions: "messageContextMenuActions", fileActions: "fileActions", messageFilesLayout: "messageFilesLayout", suggestionsLayout: "suggestionsLayout", quickActionsLayout: "quickActionsLayout", suggestions: "suggestions", sendButtonSettings: "sendButtonSettings", modelFields: "modelFields" }, outputs: { sendMessage: "sendMessage", toolbarActionClick: "toolbarActionClick", contextMenuActionClick: "contextMenuActionClick", fileActionClick: "fileActionClick", download: "download", executeAction: "executeAction", suggestionExecute: "suggestionExecute", fileSelect: "fileSelect", fileRemove: "fileRemove", unpin: "unpin", inputValueChange: "inputValueChange" }, host: { properties: { "class": "this.className", "attr.dir": "this.dirAttr" } }, providers: [
LocalizationService,
ChatService,
SuggestionsScrollService,
{
provide: L10N_PREFIX,
useValue: 'kendo.chat'
}
], queries: [{ propertyName: "attachmentTemplate", first: true, predicate: AttachmentTemplateDirective, descendants: true }, { propertyName: "chatHeaderTemplate", first: true, predicate: ChatHeaderTemplateDirective, descendants: true }, { propertyName: "chatNoDataTemplate", first: true, predicate: NoDataTemplateDirective, descendants: true }, { propertyName: "authorMessageContentTemplate", first: true, predicate: AuthorMessageContentTemplateDirective, descendants: true }, { propertyName: "receiverMessageContentTemplate", first: true, predicate: ReceiverMessageContentTemplateDirective, descendants: true }, { propertyName: "messageContentTemplate", first: true, predicate: MessageContentTemplateDirective, descendants: true }, { propertyName: "authorMessageTemplate", first: true, predicate: AuthorMessageTemplateDirective, descendants: true }, { propertyName: "receiverMessageTemplate", first: true, predicate: ReceiverMessageTemplateDirective, descendants: true }, { propertyName: "messageTemplate", first: true, predicate: MessageTemplateDirective, descendants: true }, { propertyName: "timestampTemplate", first: true, predicate: ChatTimestampTemplateDirective, descendants: true }, { propertyName: "suggestionTemplate", first: true, predicate: ChatSuggestionTemplateDirective, descendants: true }, { propertyName: "statusTemplate", first: true, predicate: ChatStatusTemplateDirective, descendants: true }, { propertyName: "messageBoxTemplate", first: true, predicate: ChatMessageBoxTemplateDirective, descendants: true }, { propertyName: "userStatusTemplate", first: true, predicate: ChatUserStatusTemplateDirective, descendants: true }], viewQueries: [{ propertyName: "messagesContextMenu", first: true, predicate: ["messagesContextMenu"], descendants: true }, { propertyName: "messageBox", first: true, predicate: ["messageBox"], descendants: true }, { propertyName: "messageList", first: true, predicate: ["messageList"], descendants: true, read: ViewContainerRef, static: true }], usesOnChanges: true, ngImport: i0, template: `
<ng-container kendoChatLocalizedMessages
i18n-deletedMessageSenderText="kendo.chat.deletedMessageSenderText|The text that is displayed when the sender deletes a message"
deletedMessageSenderText="You removed this message."
i18n-deletedMessageReceiverText="kendo.chat.deletedMessageReceiverText|The text that is displayed when the receiver deletes a message"
deletedMessageReceiverText="This message was removed by its sender."
i18n-messagePlaceholder="kendo.chat.messagePlaceholder|The placholder text of the message text input"
messagePlaceholder="Type a message..."
i18n-send="kendo.chat.send|The text for the Send button"
send="Send..."
i18n-messageListLabel="kendo.chat.messageListLabel|The label text for the Message list"
messageListLabel="Message list"
i18n-messageBoxInputLabel="kendo.chat.messageBoxInputLabel|The label text for the Message input box"
messageBoxInputLabel="Message"
i18n-messageAttachmentLeftArrow="kendo.chat.messageAttachmentLeftArrow|The text for the left arrow of the message attachments"
messageAttachmentLeftArrow="Previous item"
i18n-messageAttachmentRightArrow="kendo.chat.messageAttachmentRightArrow|The text for the right arrow of the message attachments"
messageAttachmentRightArrow="Next item"
i18n-speechToTextButtonTitle="kendo.chat.speechToTextButtonTitle|Sets the Speech to Text button title."
speechToTextButtonTitle="Speech to Text"
i18n-fileSelectButtonTitle="kendo.chat.fileSelectButtonTitle|Sets the File Select button title."
fileSelectButtonTitle="Select files"
i18n-removeReplyTitle="kendo.chat.removeReplyTitle|Sets the title of the icon which removes the reply reference in the Message Box."
removeReplyTitle="Remove reply"
i18n-removeFileTitle="kendo.chat.removeFileTitle|Sets the title of the icon which removes a selected file in the Message Box."
removeFileTitle="Remove file"
i18n-expandTitle="kendo.chat.expandTitle|Sets the title of the icon which demonstrates that the message can be expanded."
expandTitle="Expand message"
i18n-collapseTitle="kendo.chat.collapseTitle|Sets the title of the icon which demonstrates that the message can be collapsed."
collapseTitle="Collapse message"
i18n-fileActionsTitle="kendo.chat.fileActionsTitle|Sets the title of the DropDownButton which opens the File actions."
fileActionsTitle="File actions"
i18n-downloadAllFilesText="kendo.chat.downloadAllFilesText|Sets the text that is displayed in the download section of the message."
downloadAllFilesText="Download all"
i18n-previousSuggestionsButtonTitle="kendo.chat.previousSuggestionsButtonTitle|The title of the button that scrolls to the previous suggestions"
previousSuggestionsButtonTitle="Scroll left"
i18n-nextSuggestionsButtonTitle="kendo.chat.nextSuggestionsButtonTitle|The title of the button that scrolls to the next suggestions"
nextSuggestionsButtonTitle="Scroll right"
>
</ng-container>
(chatHeaderTemplate) {
<kendo-appbar class="k-chat-header" positionMode="sticky" themeColor="inherit">
<ng-container *ngTemplateOutlet="chatHeaderTemplate.templateRef"></ng-container>
</kendo-appbar>
}
(pinnedMessage) {
<div class="k-message-reference k-message-reference-receiver k-message-pinned" (click)="scrollToPinnedMessage()">
<kendo-icon-wrapper
size="xlarge"
name="pin"
[svgIcon]="pinIcon"
>
</kendo-icon-wrapper>
<chat-message-reference-content [message]="pinnedMessage"></chat-message-reference-content>
<span class="k-spacer"></span>
<button kendoButton [svgIcon]="deleteIcon" (click)="unpin.emit(pinnedMessage)" fillMode="flat"></button>
</div>
}
<div
#messageList
class="k-message-list"
aria-live="polite"
role="log"
kendoChatScrollAnchor
[attr.aria-label]="textFor('messageListLabel')"
#anchor="scrollAnchor"
[(autoScroll)]="autoScroll"
>
(processedMessages && processedMessages.length === 0) {
<div class="k-message-list-content k-message-list-content-empty">
<ng-template
[ngTemplateOutlet]="chatNoDataTemplate?.templateRef">
</ng-template>
</div>
} {
<kendo-chat-message-list
[messages]="processedMessages"
[authorMessageContentTemplate]="authorMessageContentTemplate"
[receiverMessageContentTemplate]="receiverMessageContentTemplate"
[messageContentTemplate]="messageContentTemplate"
[authorMessageTemplate]="authorMessageTemplate"
[receiverMessageTemplate]="receiverMessageTemplate"
[messageTemplate]="messageTemplate"
[timestampTemplate]="timestampTemplate"
[statusTemplate]="statusTemplate"
[userStatusTemplate]="userStatusTemplate"
[localization]="localizationText"
[attachmentTemplate]="attachmentTemplate"
[authorId]="authorId"
(executeAction)="dispatchAction($event)"
(resize)="anchor.scrollToBottom()"
(navigate)="this.autoScroll = false"
>
</kendo-chat-message-list>
}
</div>
<kendo-message-box
#messageBox
[messageBoxTemplate]="messageBoxTemplate"
[suggestionTemplate]="suggestionTemplate"
[suggestions]="suggestions"
[placeholder]="placeholder"
[authorId]="authorId"
[autoScroll]="autoScroll"
[inputValue]="inputValue"
[localization]="localizationText"
(sendMessage)="sendMessage.emit($event)"
(executeSuggestion)="suggestionExecute.emit($event)"
(fileSelect)="fileSelect.emit($event)"
(fileRemove)="fileRemove.emit($event)"
>
</kendo-message-box>
<kendo-contextmenu
#messagesContextMenu
[items]="contextMenuActions"
[popupAlign]="{ horizontal: 'right', vertical: 'top' }"
[collision]="{ horizontal: 'flip', vertical: 'flip'}"
(popupClose)="handleMenuClose($event)"
(select)="onContextMenuAction($event.item.originalAction)"
></kendo-contextmenu>
`, isInline: true, dependencies: [{ kind: "directive", type: LocalizedMessagesDirective, selector: "[kendoChatLocalizedMessages]" }, { kind: "directive", type: ScrollAnchorDirective, selector: "[kendoChatScrollAnchor]", inputs: ["autoScroll"], outputs: ["autoScrollChange"], exportAs: ["scrollAnchor"] }, { kind: "component", type: MessageListComponent, selector: "kendo-chat-message-list", inputs: ["messages", "attachmentTemplate", "authorMessageContentTemplate", "receiverMessageContentTemplate", "messageContentTemplate", "authorMessageTemplate", "receiverMessageTemplate", "messageTemplate", "timestampTemplate", "statusTemplate", "userStatusTemplate", "localization", "authorId"], outputs: ["executeAction", "navigate", "resize"] }, { kind: "component", type: MessageBoxComponent, selector: "kendo-message-box", inputs: ["authorId", "autoScroll", "suggestions", "placeholder", "inputValue", "localization", "messageBoxTemplate", "suggestionTemplate"], outputs: ["sendMessage", "executeSuggestion", "fileSelect", "fileRemove"] }, { kind: "component", type: MessageReferenceComponent, selector: "chat-message-reference-content", inputs: ["message"] }, { kind: "component", type: AppBarComponent, selector: "kendo-appbar", inputs: ["position", "positionMode", "themeColor"], exportAs: ["kendoAppBar"] }, { 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: i3.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: ContextMenuComponent, selector: "kendo-contextmenu", inputs: ["showOn", "target", "filter", "alignToAnchor", "vertical", "popupAnimate", "popupAlign", "anchorAlign", "collision", "appendTo", "ariaLabel"], outputs: ["popupOpen", "popupClose", "select", "open", "close"], exportAs: ["kendoContextMenu"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ChatComponent, decorators: [{
type: Component,
args: [{
providers: [
LocalizationService,
ChatService,
SuggestionsScrollService,
{
provide: L10N_PREFIX,
useValue: 'kendo.chat'
}
],
selector: 'kendo-chat',
template: `
<ng-container kendoChatLocalizedMessages
i18n-deletedMessageSenderText="kendo.chat.deletedMessageSenderText|The text that is displayed when the sender deletes a message"
deletedMessageSenderText="You removed this message."
i18n-deletedMessageReceiverText="kendo.chat.deletedMessageReceiverText|The text that is displayed when the receiver deletes a message"
deletedMessageReceiverText="This message was removed by its sender."
i18n-messagePlaceholder="kendo.chat.messagePlaceholder|The placholder text of the message text input"
messagePlaceholder="Type a message..."
i18n-send="kendo.chat.send|The text for the Send button"
send="Send..."
i18n-messageListLabel="kendo.chat.messageListLabel|The label text for the Message list"
messageListLabel="Message list"
i18n-messageBoxInputLabel="kendo.chat.messageBoxInputLabel|The label text for the Message input box"
messageBoxInputLabel="Message"
i18n-messageAttachmentLeftArrow="kendo.chat.messageAttachmentLeftArrow|The text for the left arrow of the message attachments"
messageAttachmentLeftArrow="Previous item"
i18n-messageAttachmentRightArrow="kendo.chat.messageAttachmentRightArrow|The text for the right arrow of the message attachments"
messageAttachmentRightArrow="Next item"
i18n-speechToTextButtonTitle="kendo.chat.speechToTextButtonTitle|Sets the Speech to Text button title."
speechToTextButtonTitle="Speech to Text"
i18n-fileSelectButtonTitle="kendo.chat.fileSelectButtonTitle|Sets the File Select button title."
fileSelectButtonTitle="Select files"
i18n-removeReplyTitle="kendo.chat.removeReplyTitle|Sets the title of the icon which removes the reply reference in the Message Box."
removeReplyTitle="Remove reply"
i18n-removeFileTitle="kendo.chat.removeFileTitle|Sets the title of the icon which removes a selected file in the Message Box."
removeFileTitle="Remove file"
i18n-expandTitle="kendo.chat.expandTitle|Sets the title of the icon which demonstrates that the message can be expanded."
expandTitle="Expand message"
i18n-collapseTitle="kendo.chat.collapseTitle|Sets the title of the icon which demonstrates that the message can be collapsed."
collapseTitle="Collapse message"
i18n-fileActionsTitle="kendo.chat.fileActionsTitle|Sets the title of the DropDownButton which opens the File actions."
fileActionsTitle="File actions"
i18n-downloadAllFilesText="kendo.chat.downloadAllFilesText|Sets the text that is displayed in the download section of the message."
downloadAllFilesText="Download all"
i18n-previousSuggestionsButtonTitle="kendo.chat.previousSuggestionsButtonTitle|The title of the button that scrolls to the previous suggestions"
previousSuggestionsButtonTitle="Scroll left"
i18n-nextSuggestionsButtonTitle="kendo.chat.nextSuggestionsButtonTitle|The title of the button that scrolls to the next suggestions"
nextSuggestionsButtonTitle="Scroll right"
>
</ng-container>
(chatHeaderTemplate) {
<kendo-appbar class="k-chat-header" positionMode="sticky" themeColor="inherit">
<ng-container *ngTemplateOutlet="chatHeaderTemplate.templateRef"></ng-container>
</kendo-appbar>
}
(pinnedMessage) {
<div class="k-message-reference k-message-reference-receiver k-message-pinned" (click)="scrollToPinnedMessage()">
<kendo-icon-wrapper
size="xlarge"
name="pin"
[svgIcon]="pinIcon"
>
</kendo-icon-wrapper>
<chat-message-reference-content [message]="pinnedMessage"></chat-message-reference-content>
<span class="k-spacer"></span>
<button kendoButton [svgIcon]="deleteIcon" (click)="unpin.emit(pinnedMessage)" fillMode="flat"></button>
</div>
}
<div
#messageList
class="k-message-list"
aria-live="polite"
role="log"
kendoChatScrollAnchor
[attr.aria-label]="textFor('messageListLabel')"
#anchor="scrollAnchor"
[(autoScroll)]="autoScroll"
>
(processedMessages && processedMessages.length === 0) {
<div class="k-message-list-content k-message-list-content-empty">
<ng-template
[ngTemplateOutlet]="chatNoDataTemplate?.templateRef">
</ng-template>
</div>
} {
<kendo-chat-message-list
[messages]="processedMessages"
[authorMessageContentTemplate]="authorMessageContentTemplate"
[receiverMessageContentTemplate]="receiverMessageContentTemplate"
[messageContentTemplate]="messageContentTemplate"
[authorMessageTemplate]="authorMessageTemplate"
[receiverMessageTemplate]="receiverMessageTemplate"
[messageTemplate]="messageTemplate"
[timestampTemplate]="timestampTemplate"
[statusTemplate]="statusTemplate"
[userStatusTemplate]="userStatusTemplate"
[localization]="localizationText"
[attachmentTemplate]="attachmentTemplate"
[authorId]="authorId"
(executeAction)="dispatchAction($event)"
(resize)="anchor.scrollToBottom()"
(navigate)="this.autoScroll = false"
>
</kendo-chat-message-list>
}
</div>
<kendo-message-box
#messageBox
[messageBoxTemplate]="messageBoxTemplate"
[suggestionTemplate]="suggestionTemplate"
[suggestions]="suggestions"
[placeholder]="placeholder"
[authorId]="authorId"
[autoScroll]="autoScroll"
[inputValue]="inputValue"
[localization]="localizationText"
(sendMessage)="sendMessage.emit($event)"
(executeSuggestion)="suggestionExecute.emit($event)"
(fileSelect)="fileSelect.emit($event)"
(fileRemove)="fileRemove.emit($event)"
>
</kendo-message-box>
<kendo-contextmenu
#messagesContextMenu
[items]="contextMenuActions"
[popupAlign]="{ horizontal: 'right', vertical: 'top' }"
[collision]="{ horizontal: 'flip', vertical: 'flip'}"
(popupClose)="handleMenuClose($event)"
(select)="onContextMenuAction($event.item.originalAction)"
></kendo-contextmenu>
`,
standalone: true,
imports: [LocalizedMessagesDirective, ScrollAnchorDirective, MessageListComponent, MessageBoxComponent, MessageReferenceComponent, AppBarComponent, NgTemplateOutlet, IconWrapperComponent, KENDO_BUTTON, ContextMenuComponent]
}]
}], ctorParameters: () => [{ type: i1.LocalizationService }, { type: i0.NgZone }, { type: i0.Renderer2 }, { type: i0.ElementRef }, { type: i2.ChatService }], propDecorators: { messages: [{
type: Input
}], authorId: [{
type: Input
}], messageBoxType: [{
type: Input
}], height: [{
type: Input
}], width: [{
type: Input
}], placeholder: [{
type: Input
}], messageWidthMode: [{
type: Input
}], timestampVisibility: [{
type: Input
}], showUsername: [{
type: Input
}], showAvatar: [{
type: Input
}], allowMessageCollapse: [{
type: Input
}], enableSpeechToText: [{
type: Input
}], enableFileSelect: [{
type: Input
}], messageToolbarActions: [{
type: Input
}], inputValue: [{
type: Input
}], authorMessageSettings: [{
type: Input
}], receiverMessageSettings: [{
type: Input
}], messageContextMenuActions: [{
type: Input
}], fileActions: [{
type: Input
}], messageFilesLayout: [{
type: Input
}], suggestionsLayout: [{
type: Input
}], quickActionsLayout: [{
type: Input
}], suggestions: [{
type: Input
}], sendButtonSettings: [{
type: Input
}], modelFields: [{
type: Input
}], sendMessage: [{
type: Output
}], toolbarActionClick: [{
type: Output
}], contextMenuActionClick: [{
type: Output
}], fileActionClick: [{
type: Output
}], download: [{
type: Output
}], executeAction: [{
type: Output
}], suggestionExecute: [{
type: Output
}], fileSelect: [{
type: Output
}], fileRemove: [{
type: Output
}], unpin: [{
type: Output
}], inputValueChange: [{
type: Output
}], className: [{
type: HostBinding,
args: ['class']
}], dirAttr: [{
type: HostBinding,
args: ['attr.dir']
}], messagesContextMenu: [{
type: ViewChild,
args: ['messagesContextMenu']
}], attachmentTemplate: [{
type: ContentChild,
args: [AttachmentTemplateDirective]
}], chatHeaderTemplate: [{
type: ContentChild,
args: [ChatHeaderTemplateDirective]
}], chatNoDataTemplate: [{
type: ContentChild,
args: [NoDataTemplateDirective]
}], authorMessageContentTemplate: [{
type: ContentChild,
args: [AuthorMessageContentTemplateDirective]
}], receiverMessageContentTemplate: [{
type: ContentChild,
args: [ReceiverMessageContentTemplateDirective]
}], messageContentTemplate: [{
type: ContentChild,
args: [MessageContentTemplateDirective]
}], authorMessageTemplate: [{
type: ContentChild,
args: [AuthorMessageTemplateDirective]
}], receiverMessageTemplate: [{
type: ContentChild,
args: [ReceiverMessageTemplateDirective]
}], messageTemplate: [{
type: ContentChild,
args: [MessageTemplateDirective]
}], timestampTemplate: [{
type: ContentChild,
args: [ChatTimestampTemplateDirective]
}], suggestionTemplate: [{
type: ContentChild,
args: [ChatSuggestionTemplateDirective]
}], statusTemplate: [{
type: ContentChild,
args: [ChatStatusTemplateDirective]
}], messageBoxTemplate: [{
type: ContentChild,
args: [ChatMessageBoxTemplateDirective]
}], userStatusTemplate: [{
type: ContentChild,
args: [ChatUserStatusTemplateDirective]
}], messageBox: [{
type: ViewChild,
args: ['messageBox']
}], messageList: [{
type: ViewChild,
args: ['messageList', { static: true, read: ViewContainerRef }]
}] } });