@progress/kendo-angular-conversational-ui 21.0.0-develop.8 → 21.0.0-develop.9

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 (62) hide show
  1. package/chat/api/files-layout.d.ts +12 -0
  2. package/chat/api/index.d.ts +3 -1
  3. package/chat/api/message-settings.interface.d.ts +33 -0
  4. package/chat/api/message.interface.d.ts +5 -1
  5. package/chat/api/suggestions-layout.d.ts +20 -0
  6. package/chat/chat.component.d.ts +92 -34
  7. package/chat/chat.directives.d.ts +18 -0
  8. package/chat/chat.module.d.ts +15 -8
  9. package/chat/common/chat.service.d.ts +32 -3
  10. package/chat/common/models/model-fields.d.ts +0 -6
  11. package/chat/common/scroll-button.component.d.ts +32 -0
  12. package/chat/common/scroll.service.d.ts +39 -0
  13. package/chat/common/utils.d.ts +13 -1
  14. package/chat/l10n/messages.d.ts +9 -1
  15. package/chat/message-list.component.d.ts +20 -3
  16. package/chat/message.component.d.ts +40 -16
  17. package/chat/suggested-actions.component.d.ts +30 -5
  18. package/chat/templates/author-message-content-template.directive.d.ts +28 -0
  19. package/chat/templates/author-message-template.directive.d.ts +28 -0
  20. package/chat/templates/message-content-template.directive.d.ts +28 -0
  21. package/chat/templates/message-template.directive.d.ts +1 -1
  22. package/chat/templates/no-data-template.directive.d.ts +27 -0
  23. package/chat/templates/receiver-message-content-template.directive.d.ts +28 -0
  24. package/chat/templates/receiver-message-template.directive.d.ts +28 -0
  25. package/chat/templates/user-status-template.directive.d.ts +27 -0
  26. package/conversational-ui.module.d.ts +18 -11
  27. package/directives.d.ts +9 -2
  28. package/esm2022/chat/api/index.mjs +3 -1
  29. package/{chat/api/message-toolbar-visibility.d.ts → esm2022/chat/api/message-settings.interface.mjs} +1 -4
  30. package/esm2022/chat/api/suggestions-layout.mjs +5 -0
  31. package/esm2022/chat/builtin-actions.mjs +2 -0
  32. package/esm2022/chat/chat-file.component.mjs +2 -2
  33. package/esm2022/chat/chat.component.mjs +265 -71
  34. package/esm2022/chat/chat.directives.mjs +18 -0
  35. package/esm2022/chat/chat.module.mjs +16 -9
  36. package/esm2022/chat/common/chat.service.mjs +83 -4
  37. package/esm2022/chat/common/models/default-model-fields.mjs +0 -1
  38. package/esm2022/chat/common/scroll-button.component.mjs +81 -0
  39. package/esm2022/chat/common/scroll.service.mjs +110 -0
  40. package/esm2022/chat/common/utils.mjs +22 -3
  41. package/esm2022/chat/l10n/messages.mjs +13 -1
  42. package/esm2022/chat/message-attachments.component.mjs +2 -2
  43. package/esm2022/chat/message-box.component.mjs +5 -2
  44. package/esm2022/chat/message-list.component.mjs +165 -19
  45. package/esm2022/chat/message.component.mjs +487 -326
  46. package/esm2022/chat/suggested-actions.component.mjs +298 -80
  47. package/esm2022/chat/templates/author-message-content-template.directive.mjs +39 -0
  48. package/esm2022/chat/templates/author-message-template.directive.mjs +39 -0
  49. package/esm2022/chat/templates/message-content-template.directive.mjs +39 -0
  50. package/esm2022/chat/templates/message-template.directive.mjs +1 -1
  51. package/esm2022/chat/templates/no-data-template.directive.mjs +38 -0
  52. package/esm2022/chat/templates/receiver-message-content-template.directive.mjs +39 -0
  53. package/esm2022/chat/templates/receiver-message-template.directive.mjs +39 -0
  54. package/esm2022/chat/templates/user-status-template.directive.mjs +38 -0
  55. package/esm2022/conversational-ui.module.mjs +19 -12
  56. package/esm2022/directives.mjs +15 -1
  57. package/esm2022/index.mjs +7 -0
  58. package/esm2022/package-metadata.mjs +2 -2
  59. package/fesm2022/progress-kendo-angular-conversational-ui.mjs +1771 -547
  60. package/index.d.ts +7 -0
  61. package/package.json +14 -14
  62. /package/esm2022/chat/api/{message-toolbar-visibility.mjs → files-layout.mjs} +0 -0
@@ -0,0 +1,18 @@
1
+ /**-----------------------------------------------------------------------------------------
2
+ * Copyright © 2025 Progress Software Corporation. All rights reserved.
3
+ * Licensed under commercial license. See LICENSE.md in the project root for more information
4
+ *-------------------------------------------------------------------------------------------*/
5
+ export { ChatComponent } from './chat.component';
6
+ export { AttachmentTemplateDirective } from './templates/attachment-template.directive';
7
+ export { MessageContentTemplateDirective } from './templates/message-content-template.directive';
8
+ export { MessageTemplateDirective } from './templates/message-template.directive';
9
+ export { ChatUserStatusTemplateDirective } from './templates/user-status-template.directive';
10
+ export { ChatMessageBoxTemplateDirective } from './templates/message-box.directive';
11
+ export { ChatHeaderTemplateDirective } from './templates/header-template.directive';
12
+ export { NoDataTemplateDirective } from './templates/no-data-template.directive';
13
+ export { ChatTimestampTemplateDirective } from './templates/timestamp-template.directive';
14
+ export { ChatStatusTemplateDirective } from './templates/status-template.directive';
15
+ export { AuthorMessageContentTemplateDirective } from './templates/author-message-content-template.directive';
16
+ export { ReceiverMessageContentTemplateDirective } from './templates/receiver-message-content-template.directive';
17
+ export { ReceiverMessageTemplateDirective } from './templates/receiver-message-template.directive';
18
+ export { AuthorMessageTemplateDirective } from './templates/author-message-template.directive';
@@ -10,13 +10,20 @@ import * as i0 from "@angular/core";
10
10
  import * as i1 from "./chat.component";
11
11
  import * as i2 from "./l10n/custom-messages.component";
12
12
  import * as i3 from "./templates/attachment-template.directive";
13
- import * as i4 from "./templates/message-template.directive";
14
- import * as i5 from "./cards/hero-card.component";
15
- import * as i6 from "./templates/message-box.directive";
16
- import * as i7 from "./templates/header-template.directive";
17
- import * as i8 from "./templates/timestamp-template.directive";
18
- import * as i9 from "./templates/status-template.directive";
19
- import * as i10 from "./templates/suggestion-template.directive";
13
+ import * as i4 from "./templates/author-message-content-template.directive";
14
+ import * as i5 from "./templates/receiver-message-content-template.directive";
15
+ import * as i6 from "./templates/message-content-template.directive";
16
+ import * as i7 from "./templates/author-message-template.directive";
17
+ import * as i8 from "./templates/receiver-message-template.directive";
18
+ import * as i9 from "./templates/message-template.directive";
19
+ import * as i10 from "./cards/hero-card.component";
20
+ import * as i11 from "./templates/message-box.directive";
21
+ import * as i12 from "./templates/header-template.directive";
22
+ import * as i13 from "./templates/no-data-template.directive";
23
+ import * as i14 from "./templates/timestamp-template.directive";
24
+ import * as i15 from "./templates/status-template.directive";
25
+ import * as i16 from "./templates/suggestion-template.directive";
26
+ import * as i17 from "./templates/user-status-template.directive";
20
27
  // IMPORTANT: NgModule export kept for backwards compatibility
21
28
  /**
22
29
  * Represents the [`NgModule`](link:site.data.urls.angular['ngmodules']) for the Chat component.
@@ -41,8 +48,8 @@ import * as i10 from "./templates/suggestion-template.directive";
41
48
  */
42
49
  export class ChatModule {
43
50
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ChatModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
44
- static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.14", ngImport: i0, type: ChatModule, imports: [i1.ChatComponent, i2.CustomMessagesComponent, i3.AttachmentTemplateDirective, i4.MessageTemplateDirective, i5.HeroCardComponent, i6.ChatMessageBoxTemplateDirective, i7.ChatHeaderTemplateDirective, i8.ChatTimestampTemplateDirective, i9.ChatStatusTemplateDirective, i10.ChatSuggestionTemplateDirective], exports: [i1.ChatComponent, i2.CustomMessagesComponent, i3.AttachmentTemplateDirective, i4.MessageTemplateDirective, i5.HeroCardComponent, i6.ChatMessageBoxTemplateDirective, i7.ChatHeaderTemplateDirective, i8.ChatTimestampTemplateDirective, i9.ChatStatusTemplateDirective, i10.ChatSuggestionTemplateDirective] });
45
- static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ChatModule, providers: [IconsService, ResizeBatchService], imports: [i1.ChatComponent, i5.HeroCardComponent] });
51
+ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.14", ngImport: i0, type: ChatModule, imports: [i1.ChatComponent, i2.CustomMessagesComponent, i3.AttachmentTemplateDirective, i4.AuthorMessageContentTemplateDirective, i5.ReceiverMessageContentTemplateDirective, i6.MessageContentTemplateDirective, i7.AuthorMessageTemplateDirective, i8.ReceiverMessageTemplateDirective, i9.MessageTemplateDirective, i10.HeroCardComponent, i11.ChatMessageBoxTemplateDirective, i12.ChatHeaderTemplateDirective, i13.NoDataTemplateDirective, i14.ChatTimestampTemplateDirective, i15.ChatStatusTemplateDirective, i16.ChatSuggestionTemplateDirective, i17.ChatUserStatusTemplateDirective], exports: [i1.ChatComponent, i2.CustomMessagesComponent, i3.AttachmentTemplateDirective, i4.AuthorMessageContentTemplateDirective, i5.ReceiverMessageContentTemplateDirective, i6.MessageContentTemplateDirective, i7.AuthorMessageTemplateDirective, i8.ReceiverMessageTemplateDirective, i9.MessageTemplateDirective, i10.HeroCardComponent, i11.ChatMessageBoxTemplateDirective, i12.ChatHeaderTemplateDirective, i13.NoDataTemplateDirective, i14.ChatTimestampTemplateDirective, i15.ChatStatusTemplateDirective, i16.ChatSuggestionTemplateDirective, i17.ChatUserStatusTemplateDirective] });
52
+ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ChatModule, providers: [IconsService, ResizeBatchService], imports: [i1.ChatComponent, i10.HeroCardComponent] });
46
53
  }
47
54
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ChatModule, decorators: [{
48
55
  type: NgModule,
@@ -4,7 +4,7 @@
4
4
  *-------------------------------------------------------------------------------------------*/
5
5
  import { Injectable } from '@angular/core';
6
6
  import { Subject } from 'rxjs';
7
- import { STB_DEFAULT_SETTINGS, SEND_BTN_DEFAULT_SETTINGS, FILESELECT_DEFAULT_SETTINGS } from './utils';
7
+ import { STB_DEFAULT_SETTINGS, SEND_BTN_DEFAULT_SETTINGS, FILESELECT_DEFAULT_SETTINGS, SUGGESTIONS_LAYOUT_DEFAULT_SETTINGS } from './utils';
8
8
  import * as i0 from "@angular/core";
9
9
  /**
10
10
  * @hidden
@@ -12,26 +12,42 @@ import * as i0 from "@angular/core";
12
12
  export class ChatService {
13
13
  authorId;
14
14
  messageWidthMode;
15
- allowMessageCollapse;
16
15
  messageToolbarActions = [];
17
16
  messageContextMenuActions = [];
17
+ calculatedContextMenuActions = [];
18
18
  fileActions = [];
19
- messageToolbarVisibility = 'hidden';
20
19
  toggleMessageState = false;
21
20
  reply;
22
21
  messages = [];
23
22
  chatElement;
24
23
  messageElementsMap = new Map();
24
+ messagesContextMenu;
25
+ activeMessage;
26
+ activeMessageElement;
27
+ selectOnMenuClose = false;
28
+ active = false;
29
+ messageFilesLayout = 'vertical';
25
30
  _enableSpeechToText = STB_DEFAULT_SETTINGS;
26
31
  _enableFileSelect = FILESELECT_DEFAULT_SETTINGS;
27
32
  _sendButtonSettings = SEND_BTN_DEFAULT_SETTINGS;
33
+ _suggestionsLayout = SUGGESTIONS_LAYOUT_DEFAULT_SETTINGS;
34
+ _quickActionsLayout = SUGGESTIONS_LAYOUT_DEFAULT_SETTINGS;
35
+ _authorMessageSettings;
36
+ _receiverMessageSettings;
37
+ _allowMessageCollapse;
28
38
  subjects = {
29
39
  toolbarAction: new Subject(),
30
40
  contextMenuAction: new Subject(),
31
41
  fileAction: new Subject(),
32
42
  fileDownload: new Subject(),
33
43
  replyReferenceClick: new Subject(),
34
- inputValueChange: new Subject()
44
+ inputValueChange: new Subject(),
45
+ contextMenuVisibilityChange: new Subject(),
46
+ suggestionsLayoutChange: new Subject(),
47
+ quickActionsLayoutChange: new Subject(),
48
+ authorMessageSettingsChange: new Subject(),
49
+ receiverMessageSettingsChange: new Subject(),
50
+ allowMessageCollapseChange: new Subject(),
35
51
  };
36
52
  toolbarAction$ = this.subjects.toolbarAction.asObservable();
37
53
  contextMenuAction$ = this.subjects.contextMenuAction.asObservable();
@@ -39,6 +55,32 @@ export class ChatService {
39
55
  fileDownload$ = this.subjects.fileDownload.asObservable();
40
56
  replyReferenceClick$ = this.subjects.replyReferenceClick.asObservable();
41
57
  inputValueChange$ = this.subjects.inputValueChange.asObservable();
58
+ contextMenuVisibilityChange$ = this.subjects.contextMenuVisibilityChange.asObservable();
59
+ suggestionsLayoutChange$ = this.subjects.suggestionsLayoutChange.asObservable();
60
+ quickActionsLayoutChange$ = this.subjects.quickActionsLayoutChange.asObservable();
61
+ authorMessageSettingsChange$ = this.subjects.authorMessageSettingsChange.asObservable();
62
+ receiverMessageSettingsChange$ = this.subjects.receiverMessageSettingsChange.asObservable();
63
+ allowMessageCollapseChange$ = this.subjects.allowMessageCollapseChange.asObservable();
64
+ set authorMessageSettings(settings) {
65
+ const previousSettings = this._authorMessageSettings;
66
+ if (JSON.stringify(previousSettings) !== JSON.stringify(settings)) {
67
+ this.updateComponentSettings('_authorMessageSettings', settings, null);
68
+ this.emit('authorMessageSettingsChange', this._authorMessageSettings);
69
+ }
70
+ }
71
+ get authorMessageSettings() {
72
+ return this._authorMessageSettings;
73
+ }
74
+ set receiverMessageSettings(settings) {
75
+ const previousSettings = this._receiverMessageSettings;
76
+ if (JSON.stringify(previousSettings) !== JSON.stringify(settings)) {
77
+ this.updateComponentSettings('_receiverMessageSettings', settings, null);
78
+ this.emit('receiverMessageSettingsChange', this._receiverMessageSettings);
79
+ }
80
+ }
81
+ get receiverMessageSettings() {
82
+ return this._receiverMessageSettings;
83
+ }
42
84
  set enableSpeechToText(settings) {
43
85
  this.updateComponentSettings('_enableSpeechToText', settings, STB_DEFAULT_SETTINGS);
44
86
  }
@@ -57,6 +99,38 @@ export class ChatService {
57
99
  get sendButtonSettings() {
58
100
  return this._sendButtonSettings;
59
101
  }
102
+ set suggestionsLayout(layoutMode) {
103
+ this._suggestionsLayout = layoutMode;
104
+ this.emit('suggestionsLayoutChange', this._suggestionsLayout);
105
+ }
106
+ get suggestionsLayout() {
107
+ return this._suggestionsLayout;
108
+ }
109
+ set quickActionsLayout(layoutMode) {
110
+ this._quickActionsLayout = layoutMode;
111
+ this.emit('quickActionsLayoutChange', this._quickActionsLayout);
112
+ }
113
+ get quickActionsLayout() {
114
+ return this._quickActionsLayout;
115
+ }
116
+ set allowMessageCollapse(value) {
117
+ const previousValue = this._allowMessageCollapse;
118
+ if (previousValue !== value) {
119
+ this._allowMessageCollapse = value;
120
+ this.emit('allowMessageCollapseChange', this._allowMessageCollapse);
121
+ }
122
+ }
123
+ get allowMessageCollapse() {
124
+ return this._allowMessageCollapse;
125
+ }
126
+ calculateContextMenuActions(isOwn) {
127
+ const settings = isOwn ? this.authorMessageSettings : this.receiverMessageSettings;
128
+ if (settings?.messageContextMenuActions) {
129
+ this.calculatedContextMenuActions = settings.messageContextMenuActions;
130
+ return;
131
+ }
132
+ this.calculatedContextMenuActions = this.messageContextMenuActions || [];
133
+ }
60
134
  emit(subjectKey, value) {
61
135
  (this.subjects[subjectKey]).next(value);
62
136
  }
@@ -78,6 +152,11 @@ export class ChatService {
78
152
  elementRef.nativeElement.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
79
153
  }
80
154
  }
155
+ focusActiveMessageElement() {
156
+ if (this.activeMessageElement) {
157
+ this.activeMessageElement.element?.nativeElement?.focus();
158
+ }
159
+ }
81
160
  updateComponentSettings(property, settings, defaultSettings) {
82
161
  if (settings === true) {
83
162
  this[property] = defaultSettings;
@@ -19,7 +19,6 @@ export const defaultModelFields = {
19
19
  attachmentLayoutField: 'attachmentLayout',
20
20
  suggestedActionsField: 'suggestedActions',
21
21
  isPinnedField: 'isPinned',
22
- pinnedByField: 'pinnedBy',
23
22
  replyToIdField: 'replyToId',
24
23
  isDeletedField: 'isDeleted',
25
24
  typingField: 'typing'
@@ -0,0 +1,81 @@
1
+ /**-----------------------------------------------------------------------------------------
2
+ * Copyright © 2025 Progress Software Corporation. All rights reserved.
3
+ * Licensed under commercial license. See LICENSE.md in the project root for more information
4
+ *-------------------------------------------------------------------------------------------*/
5
+ import { Component, ElementRef, HostBinding, Input, Renderer2, NgZone, Output, EventEmitter, } from '@angular/core';
6
+ import { Subscription } from 'rxjs';
7
+ import { chevronLeftIcon, chevronRightIcon } from '@progress/kendo-svg-icons';
8
+ import { LocalizationService } from '@progress/kendo-angular-l10n';
9
+ import { IconWrapperComponent } from '@progress/kendo-angular-icons';
10
+ import * as i0 from "@angular/core";
11
+ import * as i1 from "@progress/kendo-angular-l10n";
12
+ const DIRECTION_CLASSES = {
13
+ left: 'chevron-left',
14
+ right: 'chevron-right',
15
+ };
16
+ /**
17
+ * @hidden
18
+ */
19
+ export class ChatScrollableButtonComponent {
20
+ host;
21
+ renderer;
22
+ ngZone;
23
+ localization;
24
+ role = 'button';
25
+ prev = false;
26
+ onClick = new EventEmitter();
27
+ get scrollButtonIconClass() {
28
+ const defaultPrevIcon = !this.localization.rtl ? DIRECTION_CLASSES.left : DIRECTION_CLASSES.right;
29
+ const defaultNextIcon = !this.localization.rtl ? DIRECTION_CLASSES.right : DIRECTION_CLASSES.left;
30
+ return this.prev ? defaultPrevIcon : defaultNextIcon;
31
+ }
32
+ get scrollButtonSVGIcon() {
33
+ const defaultPrevSVGIcon = !this.localization.rtl ? this.chevronLeftIcon : this.chevronRightIcon;
34
+ const defaultNextSVGIcon = !this.localization.rtl ? this.chevronRightIcon : this.chevronLeftIcon;
35
+ return this.prev ? defaultPrevSVGIcon : defaultNextSVGIcon;
36
+ }
37
+ chevronLeftIcon = chevronLeftIcon;
38
+ chevronRightIcon = chevronRightIcon;
39
+ subs = new Subscription();
40
+ constructor(host, renderer, ngZone, localization) {
41
+ this.host = host;
42
+ this.renderer = renderer;
43
+ this.ngZone = ngZone;
44
+ this.localization = localization;
45
+ }
46
+ ngAfterViewInit() {
47
+ this.ngZone.runOutsideAngular(() => {
48
+ this.subs.add(this.renderer.listen(this.host.nativeElement, 'click', () => this.clickHandler()));
49
+ });
50
+ }
51
+ ngOnDestroy() {
52
+ this.subs.unsubscribe();
53
+ }
54
+ clickHandler() {
55
+ const buttonType = this.prev ? 'prev' : 'next';
56
+ this.onClick.emit(buttonType);
57
+ }
58
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ChatScrollableButtonComponent, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.NgZone }, { token: i1.LocalizationService }], target: i0.ɵɵFactoryTarget.Component });
59
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: ChatScrollableButtonComponent, isStandalone: true, selector: "[kendoChatScrollableButton]", inputs: { prev: "prev" }, outputs: { onClick: "onClick" }, host: { properties: { "attr.role": "this.role" } }, ngImport: i0, template: `
60
+ <kendo-icon-wrapper [name]="scrollButtonIconClass" [svgIcon]="scrollButtonSVGIcon" innerCssClass="k-button-icon"> </kendo-icon-wrapper>
61
+ `, isInline: true, dependencies: [{ kind: "component", type: IconWrapperComponent, selector: "kendo-icon-wrapper", inputs: ["name", "svgIcon", "innerCssClass", "customFontClass", "size"], exportAs: ["kendoIconWrapper"] }] });
62
+ }
63
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ChatScrollableButtonComponent, decorators: [{
64
+ type: Component,
65
+ args: [{
66
+ template: `
67
+ <kendo-icon-wrapper [name]="scrollButtonIconClass" [svgIcon]="scrollButtonSVGIcon" innerCssClass="k-button-icon"> </kendo-icon-wrapper>
68
+ `,
69
+ // eslint-disable-next-line @angular-eslint/component-selector
70
+ selector: '[kendoChatScrollableButton]',
71
+ standalone: true,
72
+ imports: [IconWrapperComponent],
73
+ }]
74
+ }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i0.NgZone }, { type: i1.LocalizationService }], propDecorators: { role: [{
75
+ type: HostBinding,
76
+ args: ['attr.role']
77
+ }], prev: [{
78
+ type: Input
79
+ }], onClick: [{
80
+ type: Output
81
+ }] } });
@@ -0,0 +1,110 @@
1
+ /**-----------------------------------------------------------------------------------------
2
+ * Copyright © 2025 Progress Software Corporation. All rights reserved.
3
+ * Licensed under commercial license. See LICENSE.md in the project root for more information
4
+ *-------------------------------------------------------------------------------------------*/
5
+ import { Injectable, NgZone } from '@angular/core';
6
+ import { isDocumentAvailable } from '@progress/kendo-angular-common';
7
+ import { Subject } from 'rxjs';
8
+ import { LocalizationService } from '@progress/kendo-angular-l10n';
9
+ import * as i0 from "@angular/core";
10
+ import * as i1 from "@progress/kendo-angular-l10n";
11
+ const DEFAULT_SCROLL_BEHAVIOR = 'smooth';
12
+ const DEFAULT_SCROLL_SPEED = 100;
13
+ /**
14
+ * @hidden
15
+ */
16
+ export class SuggestionsScrollService {
17
+ ngZone;
18
+ localization;
19
+ owner;
20
+ position = 0;
21
+ scrollButtonActiveStateChange = new Subject();
22
+ get scrollElement() {
23
+ return this.owner.suggestionsContainer?.nativeElement;
24
+ }
25
+ get scrollContainerOverflowSize() {
26
+ if (!isDocumentAvailable()) {
27
+ return 0;
28
+ }
29
+ if (!this.scrollElement) {
30
+ return 0;
31
+ }
32
+ const overflowSize = Math.floor(this.scrollElement.scrollWidth - this.scrollElement.offsetWidth);
33
+ return overflowSize < 0 ? 0 : overflowSize;
34
+ }
35
+ get suggestionsOverflow() {
36
+ return this.scrollContainerOverflowSize > 0;
37
+ }
38
+ constructor(ngZone, localization) {
39
+ this.ngZone = ngZone;
40
+ this.localization = localization;
41
+ }
42
+ toggleScrollButtonsState() {
43
+ const suggestedActions = this.owner;
44
+ if (!suggestedActions?.hasScrollButtons) {
45
+ return;
46
+ }
47
+ const currentPrevButtonActive = !this.isDisabled('prev');
48
+ const currentNextButtonActive = !this.isDisabled('next');
49
+ const defaultOffset = 1;
50
+ const rtlDelta = this.localization.rtl ? -1 : 1;
51
+ const calculatedPrevButtonActive = (this.position * rtlDelta) > 0 && this.scrollContainerOverflowSize > 0;
52
+ const calculatedNextButtonActive = (this.position * rtlDelta) < this.scrollContainerOverflowSize - defaultOffset && this.scrollContainerOverflowSize > 0;
53
+ if (calculatedPrevButtonActive !== currentPrevButtonActive) {
54
+ this.ngZone.run(() => this.toggleButtonActiveState('prev', calculatedPrevButtonActive));
55
+ }
56
+ if (calculatedNextButtonActive !== currentNextButtonActive) {
57
+ this.ngZone.run(() => this.toggleButtonActiveState('next', calculatedNextButtonActive));
58
+ }
59
+ }
60
+ onScroll(e) {
61
+ this.position = e.target.scrollLeft;
62
+ this.toggleScrollButtonsState();
63
+ }
64
+ scrollSuggestions(direction) {
65
+ this.calculateListPosition(direction, DEFAULT_SCROLL_SPEED);
66
+ if (this.scrollElement) {
67
+ this.scrollElement.scrollTo({ left: this.position, behavior: DEFAULT_SCROLL_BEHAVIOR });
68
+ }
69
+ this.toggleScrollButtonsState();
70
+ }
71
+ updateScrollPosition(element) {
72
+ this.position = element.scrollLeft;
73
+ }
74
+ calculateListPosition(direction, scrollSpeed) {
75
+ if (direction === 'prev') {
76
+ if (!this.localization.rtl) {
77
+ this.position = this.position - scrollSpeed <= 0 ? 0 : this.position - scrollSpeed;
78
+ }
79
+ else {
80
+ this.position = this.position + scrollSpeed >= 0 ? 0 : this.position + scrollSpeed;
81
+ }
82
+ }
83
+ else if (direction === 'next' && this.position < this.scrollContainerOverflowSize) {
84
+ if (this.position + scrollSpeed > this.scrollContainerOverflowSize) {
85
+ if (this.localization.rtl) {
86
+ this.position = -this.scrollContainerOverflowSize;
87
+ }
88
+ else {
89
+ this.position = this.scrollContainerOverflowSize;
90
+ }
91
+ return;
92
+ }
93
+ if (this.localization.rtl) {
94
+ this.position -= scrollSpeed;
95
+ }
96
+ else {
97
+ this.position += scrollSpeed;
98
+ }
99
+ }
100
+ }
101
+ toggleButtonActiveState(buttonType, active) {
102
+ this.scrollButtonActiveStateChange.next({ buttonType, active });
103
+ }
104
+ isDisabled = (buttonType) => this.owner[`${buttonType}ScrollButton`]?.nativeElement.classList.contains('k-disabled');
105
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SuggestionsScrollService, deps: [{ token: i0.NgZone }, { token: i1.LocalizationService }], target: i0.ɵɵFactoryTarget.Injectable });
106
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SuggestionsScrollService });
107
+ }
108
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SuggestionsScrollService, decorators: [{
109
+ type: Injectable
110
+ }], ctorParameters: () => [{ type: i0.NgZone }, { type: i1.LocalizationService }] });
@@ -67,6 +67,10 @@ export const FILESELECT_DEFAULT_SETTINGS = {
67
67
  multiple: true,
68
68
  disabled: false
69
69
  };
70
+ /**
71
+ * @hidden
72
+ */
73
+ export const SUGGESTIONS_LAYOUT_DEFAULT_SETTINGS = 'scroll';
70
74
  /**
71
75
  * @hidden
72
76
  */
@@ -119,14 +123,16 @@ export const parseMessage = (message, fields) => {
119
123
  id: authorId,
120
124
  ...(authorName && { name: authorName }),
121
125
  ...(authorImageUrl && { avatarUrl: authorImageUrl }),
122
- ...(authorImageAltText && { avatarAltText: authorImageAltText })
126
+ ...(authorImageAltText && { avatarAltText: authorImageAltText }),
123
127
  };
124
128
  }
129
+ const timestampValue = getter(modelFields.timestampField)(message);
130
+ const timestamp = timestampValue instanceof Date ? timestampValue : new Date(timestampValue);
125
131
  return {
126
132
  id: getter(modelFields.idField)(message),
127
133
  text: getter(modelFields.textField)(message),
128
134
  author: author,
129
- timestamp: new Date(getter(modelFields.timestampField)(message)),
135
+ timestamp: timestamp,
130
136
  status: getter(modelFields.statusField)(message),
131
137
  files: getter(modelFields.filesField)(message),
132
138
  attachments: getter(modelFields.attachmentsField)(message),
@@ -135,6 +141,19 @@ export const parseMessage = (message, fields) => {
135
141
  isPinned: getter(modelFields.isPinnedField)(message),
136
142
  replyToId: getter(modelFields.replyToIdField)(message),
137
143
  isDeleted: getter(modelFields.isDeletedField)(message),
138
- typing: getter(modelFields.typingField)(message)
144
+ typing: getter(modelFields.typingField)(message),
145
+ dataItem: message
139
146
  };
140
147
  };
148
+ /**
149
+ * @hidden
150
+ */
151
+ export const transformActions = (actions) => {
152
+ return actions.map(action => ({
153
+ text: action.label,
154
+ icon: action.icon,
155
+ svgIcon: action.svgIcon,
156
+ disabled: action.disabled,
157
+ originalAction: action
158
+ }));
159
+ };
@@ -74,8 +74,16 @@ export class Messages extends ComponentMessages {
74
74
  * Sets the title of the DropDownButton that opens the File actions.
75
75
  */
76
76
  fileActionsTitle;
77
+ /**
78
+ * Sets the title of the button that shows the **Scroll right** when the suggestions list is scrollable with buttons.
79
+ */
80
+ nextSuggestionsButtonTitle;
81
+ /**
82
+ * Sets the title of the button that shows the **Scroll left** when the suggestions list is scrollable with buttons.
83
+ */
84
+ previousSuggestionsButtonTitle;
77
85
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: Messages, deps: null, target: i0.ɵɵFactoryTarget.Directive });
78
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.14", type: Messages, selector: "kendoConversationalUIMessages", inputs: { deletedMessageSenderText: "deletedMessageSenderText", deletedMessageReceiverText: "deletedMessageReceiverText", downloadAllFilesText: "downloadAllFilesText", messagePlaceholder: "messagePlaceholder", send: "send", messageListLabel: "messageListLabel", messageBoxInputLabel: "messageBoxInputLabel", messageAttachmentLeftArrow: "messageAttachmentLeftArrow", messageAttachmentRightArrow: "messageAttachmentRightArrow", speechToTextButtonTitle: "speechToTextButtonTitle", fileSelectButtonTitle: "fileSelectButtonTitle", removeReplyTitle: "removeReplyTitle", removeFileTitle: "removeFileTitle", expandTitle: "expandTitle", collapseTitle: "collapseTitle", fileActionsTitle: "fileActionsTitle" }, usesInheritance: true, ngImport: i0 });
86
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.14", type: Messages, selector: "kendoConversationalUIMessages", inputs: { deletedMessageSenderText: "deletedMessageSenderText", deletedMessageReceiverText: "deletedMessageReceiverText", downloadAllFilesText: "downloadAllFilesText", messagePlaceholder: "messagePlaceholder", send: "send", messageListLabel: "messageListLabel", messageBoxInputLabel: "messageBoxInputLabel", messageAttachmentLeftArrow: "messageAttachmentLeftArrow", messageAttachmentRightArrow: "messageAttachmentRightArrow", speechToTextButtonTitle: "speechToTextButtonTitle", fileSelectButtonTitle: "fileSelectButtonTitle", removeReplyTitle: "removeReplyTitle", removeFileTitle: "removeFileTitle", expandTitle: "expandTitle", collapseTitle: "collapseTitle", fileActionsTitle: "fileActionsTitle", nextSuggestionsButtonTitle: "nextSuggestionsButtonTitle", previousSuggestionsButtonTitle: "previousSuggestionsButtonTitle" }, usesInheritance: true, ngImport: i0 });
79
87
  }
80
88
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: Messages, decorators: [{
81
89
  type: Directive,
@@ -115,4 +123,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
115
123
  type: Input
116
124
  }], fileActionsTitle: [{
117
125
  type: Input
126
+ }], nextSuggestionsButtonTitle: [{
127
+ type: Input
128
+ }], previousSuggestionsButtonTitle: [{
129
+ type: Input
118
130
  }] } });
@@ -46,10 +46,10 @@ export class MessageAttachmentsComponent extends ChatItem {
46
46
  scrollSubscription;
47
47
  direction;
48
48
  get showLeftArrow() {
49
- return this.carousel && this.direction === 'rtl' ? this.scrollPosition > -1 : this.scrollPosition > 0;
49
+ return this.carousel && (this.direction === 'rtl' ? this.scrollPosition > -1 : this.scrollPosition > 0);
50
50
  }
51
51
  get showRightArrow() {
52
- return this.carousel && this.direction === 'rtl' ? this.scrollPosition < 0 : this.scrollPosition < 1;
52
+ return this.carousel && (this.direction === 'rtl' ? this.scrollPosition < 0 : this.scrollPosition < 1);
53
53
  }
54
54
  carouselKeyHandlers = {
55
55
  [Keys.ArrowLeft]: (e) => this.navigateTo(e, this.direction === 'rtl' ? 1 : -1),
@@ -5,7 +5,7 @@
5
5
  import { ChangeDetectorRef, Component, ElementRef, EventEmitter, HostBinding, Input, Output, Renderer2, ViewChild } from '@angular/core';
6
6
  import { NgIf, NgFor, NgTemplateOutlet } from '@angular/common';
7
7
  import { LocalizationService } from '@progress/kendo-angular-l10n';
8
- import { closest, isPresent, Keys } from '@progress/kendo-angular-common';
8
+ import { closest, guid, isPresent, Keys } from '@progress/kendo-angular-common';
9
9
  import { paperPlaneIcon, paperclipIcon, fileIcon, xIcon } from '@progress/kendo-svg-icons';
10
10
  import { ButtonComponent, SpeechToTextButtonComponent } from '@progress/kendo-angular-buttons';
11
11
  import { SendMessageEvent } from './api/post-message-event';
@@ -84,6 +84,7 @@ export class MessageBoxComponent {
84
84
  return;
85
85
  }
86
86
  const message = {
87
+ id: guid(),
87
88
  text: this.inputValue,
88
89
  timestamp: new Date(),
89
90
  author: { id: this.authorId },
@@ -221,6 +222,7 @@ export class MessageBoxComponent {
221
222
  *ngIf="suggestions?.length > 0"
222
223
  #suggestedActions
223
224
  [suggestions]="suggestions"
225
+ type="suggestion"
224
226
  [suggestionTemplate]="suggestionTemplate"
225
227
  [tabbable]="true"
226
228
  (dispatchSuggestion)="dispatchSuggestion($event)"
@@ -321,7 +323,7 @@ export class MessageBoxComponent {
321
323
  [showFileList]="false"
322
324
  (select)="handleFileSelect($event)"
323
325
  ></kendo-fileselect>
324
- `, isInline: true, dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: TextAreaComponent, selector: "kendo-textarea", inputs: ["focusableId", "flow", "inputAttributes", "adornmentsOrientation", "rows", "cols", "maxlength", "maxResizableRows", "tabindex", "tabIndex", "resizable", "size", "rounded", "fillMode", "showPrefixSeparator", "showSuffixSeparator"], outputs: ["focus", "blur", "valueChange"], exportAs: ["kendoTextArea"] }, { kind: "component", type: MessageReferenceComponent, selector: "chat-message-reference-content", inputs: ["message"] }, { kind: "component", type: TextAreaSuffixComponent, selector: "kendo-textarea-suffix", inputs: ["flow", "orientation"], exportAs: ["kendoTextAreaSuffix"] }, { kind: "component", type: TextAreaPrefixComponent, selector: "kendo-textarea-prefix", inputs: ["flow", "orientation"], exportAs: ["kendoTextAreaPrefix"] }, { kind: "component", type: SpeechToTextButtonComponent, selector: "button[kendoSpeechToTextButton]", inputs: ["disabled", "size", "rounded", "fillMode", "themeColor", "integrationMode", "lang", "continuous", "interimResults", "maxAlternatives"], outputs: ["start", "end", "result", "error", "click"], exportAs: ["kendoSpeechToTextButton"] }, { kind: "component", type: InputSpacerComponent, selector: "kendo-input-spacer, kendo-textbox-spacer", inputs: ["width"] }, { kind: "component", type: FileSelectComponent, selector: "kendo-fileselect", inputs: ["name"], outputs: ["valueChange"], exportAs: ["kendoFileSelect"] }, { kind: "component", type: SuggestedActionsComponent, selector: "kendo-chat-suggested-actions", inputs: ["actions", "suggestions", "tabbable", "suggestionTemplate"], outputs: ["dispatchAction", "dispatchSuggestion"] }, { kind: "component", type: ChatFileComponent, selector: "li[chatFile]", inputs: ["chatFile", "removable", "fileActions"], outputs: ["remove", "actionClick", "actionsToggle", "actionButtonClick"] }] });
326
+ `, isInline: true, dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: TextAreaComponent, selector: "kendo-textarea", inputs: ["focusableId", "flow", "inputAttributes", "adornmentsOrientation", "rows", "cols", "maxlength", "maxResizableRows", "tabindex", "tabIndex", "resizable", "size", "rounded", "fillMode", "showPrefixSeparator", "showSuffixSeparator"], outputs: ["focus", "blur", "valueChange"], exportAs: ["kendoTextArea"] }, { kind: "component", type: MessageReferenceComponent, selector: "chat-message-reference-content", inputs: ["message"] }, { kind: "component", type: TextAreaSuffixComponent, selector: "kendo-textarea-suffix", inputs: ["flow", "orientation"], exportAs: ["kendoTextAreaSuffix"] }, { kind: "component", type: TextAreaPrefixComponent, selector: "kendo-textarea-prefix", inputs: ["flow", "orientation"], exportAs: ["kendoTextAreaPrefix"] }, { kind: "component", type: SpeechToTextButtonComponent, selector: "button[kendoSpeechToTextButton]", inputs: ["disabled", "size", "rounded", "fillMode", "themeColor", "integrationMode", "lang", "continuous", "interimResults", "maxAlternatives"], outputs: ["start", "end", "result", "error", "click"], exportAs: ["kendoSpeechToTextButton"] }, { kind: "component", type: InputSpacerComponent, selector: "kendo-input-spacer, kendo-textbox-spacer", inputs: ["width"] }, { kind: "component", type: FileSelectComponent, selector: "kendo-fileselect", inputs: ["name"], outputs: ["valueChange"], exportAs: ["kendoFileSelect"] }, { kind: "component", type: SuggestedActionsComponent, selector: "kendo-chat-suggested-actions", inputs: ["actions", "suggestions", "tabbable", "type", "suggestionTemplate"], outputs: ["dispatchAction", "dispatchSuggestion"] }, { kind: "component", type: ChatFileComponent, selector: "li[chatFile]", inputs: ["chatFile", "removable", "fileActions"], outputs: ["remove", "actionClick", "actionsToggle", "actionButtonClick"] }] });
325
327
  }
326
328
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: MessageBoxComponent, decorators: [{
327
329
  type: Component,
@@ -332,6 +334,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
332
334
  *ngIf="suggestions?.length > 0"
333
335
  #suggestedActions
334
336
  [suggestions]="suggestions"
337
+ type="suggestion"
335
338
  [suggestionTemplate]="suggestionTemplate"
336
339
  [tabbable]="true"
337
340
  (dispatchSuggestion)="dispatchSuggestion($event)"