@progress/kendo-angular-conversational-ui 24.0.0-develop.10 → 24.0.0-develop.12

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.
@@ -0,0 +1,18 @@
1
+ /**-----------------------------------------------------------------------------------------
2
+ * Copyright © 2026 Progress Software Corporation. All rights reserved.
3
+ * Licensed under commercial license. See LICENSE.md in the project root for more information
4
+ *-------------------------------------------------------------------------------------------*/
5
+ /**
6
+ * Arguments for the `loadMore` event of the Chat.
7
+ * Fires when the user scrolls near the edge of the rendered message window in endless scroll mode.
8
+ */
9
+ export interface ChatLoadMoreEvent {
10
+ /**
11
+ * The inclusive start index into the full messages array.
12
+ */
13
+ startIndex: number;
14
+ /**
15
+ * The exclusive end index into the full messages array.
16
+ */
17
+ endIndex: number;
18
+ }
@@ -0,0 +1,18 @@
1
+ /**-----------------------------------------------------------------------------------------
2
+ * Copyright © 2026 Progress Software Corporation. All rights reserved.
3
+ * Licensed under commercial license. See LICENSE.md in the project root for more information
4
+ *-------------------------------------------------------------------------------------------*/
5
+ /**
6
+ * Arguments for the `referencedMessageClick` event of the Chat.
7
+ * Fires when the user clicks a pinned message indicator or a reply preview.
8
+ */
9
+ export interface ChatReferencedMessageClickEvent {
10
+ /**
11
+ * The ID of the referenced message that was clicked.
12
+ */
13
+ id: string | number;
14
+ /**
15
+ * Specifies whether the click originated from a pinned message indicator or a reply preview.
16
+ */
17
+ type: 'pinned' | 'reply';
18
+ }
@@ -5,13 +5,17 @@
5
5
  export * from './action.interface';
6
6
  export * from './attachment.interface';
7
7
  export * from './chat-file-interface';
8
+ export * from './chat-load-more-event';
9
+ export * from './chat-referenced-message-click-event';
8
10
  export * from './chat-suggestion.interface';
9
11
  export * from './execute-action-event';
10
12
  export * from './message-action';
11
13
  export * from './message-width-mode';
12
14
  export * from './message.interface';
13
15
  export * from './message-settings.interface';
16
+ export * from './message-status.interface';
14
17
  export * from './post-message-event';
18
+ export * from './scroll-mode';
15
19
  export * from './user.interface';
16
20
  export * from './file-action';
17
21
  export * from './file-download-event.interface';
@@ -0,0 +1,12 @@
1
+ /**-----------------------------------------------------------------------------------------
2
+ * Copyright © 2026 Progress Software Corporation. All rights reserved.
3
+ * Licensed under commercial license. See LICENSE.md in the project root for more information
4
+ *-------------------------------------------------------------------------------------------*/
5
+ /**
6
+ * Defines the scroll behavior of the Chat message list.
7
+ *
8
+ * - `scrollable`—All messages are rendered with standard scroll behavior.
9
+ * - `endless`—The Chat starts by rendering the last `pageSize` messages
10
+ * and prepends older ones as the user scrolls up.
11
+ */
12
+ export type ScrollMode = 'scrollable' | 'endless';
@@ -7,19 +7,24 @@ import { SpeechToTextButtonSettings } from '@progress/kendo-angular-buttons';
7
7
  import { LocalizationService } from '@progress/kendo-angular-l10n';
8
8
  import { ContextMenuComponent, ContextMenuPopupEvent } from '@progress/kendo-angular-menu';
9
9
  import { SelectEvent } from '@progress/kendo-angular-upload';
10
+ import { LicenseMessage } from '@progress/kendo-licensing';
10
11
  import { SVGIcon } from '@progress/kendo-svg-icons';
11
12
  import { FileSelectButtonSettings } from '../promptbox/common/models';
12
13
  import { ExecuteActionEvent, FileAction, FileActionEvent, FileDownloadEvent, FilesLayoutMode, Message, MessageSettings, ResendMessageEvent, SendButtonSettings, SendMessageEvent } from './api';
13
14
  import { ChatFile } from './api/chat-file-interface';
15
+ import { ChatLoadMoreEvent } from './api/chat-load-more-event';
16
+ import { ChatReferencedMessageClickEvent } from './api/chat-referenced-message-click-event';
14
17
  import { ChatSuggestion } from './api/chat-suggestion.interface';
15
18
  import { MessageAction, MessageActionEvent } from './api/message-action';
16
19
  import { MessageBoxSettings, MessageBoxType } from './api/message-box';
17
20
  import { MessageWidthMode } from './api/message-width-mode';
21
+ import { ScrollMode } from './api/scroll-mode';
18
22
  import { QuickActionsLayoutMode, SuggestionsLayoutMode } from './api/suggestions-layout';
19
23
  import { TimestampVisibilityMode } from './api/timestamp-visibility';
20
24
  import { AuthorMessageContentTemplateDirective, AuthorMessageTemplateDirective, MessageContentTemplateDirective, MessageTemplateDirective, NoDataTemplateDirective, ReceiverMessageContentTemplateDirective, ReceiverMessageTemplateDirective } from './chat.directives';
21
25
  import { ChatService } from './common/chat.service';
22
26
  import { ConversationalUIModelFields } from './common/models/model-fields';
27
+ import { EndlessScrollState } from './common/endless-scroll-state';
23
28
  import { MessageBoxComponent } from './message-box.component';
24
29
  import { AttachmentTemplateDirective } from './templates/attachment-template.directive';
25
30
  import { ChatHeaderTemplateDirective } from './templates/header-template.directive';
@@ -225,6 +230,86 @@ export declare class ChatComponent implements OnInit, AfterViewInit, OnDestroy {
225
230
  */
226
231
  set sendButtonSettings(value: boolean | SendButtonSettings);
227
232
  get sendButtonSettings(): boolean | SendButtonSettings;
233
+ /**
234
+ * Controls the scrolling behavior of the message list.
235
+ *
236
+ * @default 'scrollable'
237
+ */
238
+ scrollMode: ScrollMode;
239
+ /**
240
+ * Sets the number of messages loaded per page in endless scroll mode.
241
+ * Ignored in `scrollable` mode.
242
+ *
243
+ * @default 50
244
+ */
245
+ pageSize: number;
246
+ /**
247
+ * Sets the minimum distance between a new receiver message and the top of the visible
248
+ * message area when auto-scrolling. Keeps older messages partially visible instead of
249
+ * scrolling them out of view.
250
+ *
251
+ * Accepts a percentage string relative to the visible area height (for example, `'30%'`)
252
+ * or a pixel value as a number. Negative values scroll the message fully to the bottom.
253
+ *
254
+ * Has no effect on author messages, which always scroll to the bottom.
255
+ *
256
+ * @default '20%'
257
+ */
258
+ autoScrollThreshold: number | string;
259
+ /**
260
+ * Sets the total number of messages in the conversation.
261
+ *
262
+ * When `messages.length` equals `total` (or `total` is not set), the Chat operates in
263
+ * **built-in mode** and manages rendering internally. When `messages.length < total`,
264
+ * the Chat operates in **remote mode** — the consumer manages data via
265
+ * [`loadMore`](slug:api_conversational-ui_chatcomponent#loadMore) events.
266
+ *
267
+ * Only relevant when [`scrollMode`](slug:api_conversational-ui_chatcomponent#scrollMode)
268
+ * is `'endless'`.
269
+ */
270
+ total: number;
271
+ /**
272
+ * Sets the index in the full conversation that `messages[0]` corresponds to.
273
+ *
274
+ * Only relevant in remote mode (`messages.length < total`). As the user scrolls up
275
+ * and the consumer prepends messages, `startIndex` decreases. The Chat uses this to
276
+ * compute the correct range for the next
277
+ * [`loadMore`](slug:api_conversational-ui_chatcomponent#loadMore) call.
278
+ *
279
+ * Ignored in built-in mode.
280
+ */
281
+ startIndex: number;
282
+ /**
283
+ * Sets the exclusive end index of the current batch in the full conversation.
284
+ *
285
+ * Only relevant in remote mode (`messages.length < total`). As the user scrolls down
286
+ * and the consumer appends messages, `endIndex` increases. The Chat uses this to know
287
+ * whether more messages exist below the current batch.
288
+ *
289
+ * Ignored in built-in mode.
290
+ */
291
+ endIndex: number;
292
+ /**
293
+ * Sets the full set of pinned messages in the conversation.
294
+ *
295
+ * Only needed in remote mode (`messages.length < total`). The Chat uses this to
296
+ * render the pinned message indicator when the pinned message is outside the current
297
+ * batch. In built-in mode, the Chat has all messages and can look them up directly.
298
+ *
299
+ * @default []
300
+ */
301
+ pinnedMessages: Message[];
302
+ /**
303
+ * Sets the reply targets that live outside the current batch.
304
+ *
305
+ * Only needed in remote mode (`messages.length < total`). The Chat uses this to
306
+ * render reply previews when the replied-to message is not in the current batch.
307
+ * The consumer resolves this after each data fetch by finding which `replyToId`
308
+ * targets are missing from the batch and fetching only those.
309
+ *
310
+ * @default []
311
+ */
312
+ repliedToMessages: Message[];
228
313
  /**
229
314
  * Sets the names of the model fields from which the Chat reads its data.
230
315
  * Lets you map custom data types to the expected `Message` format.
@@ -298,6 +383,14 @@ export declare class ChatComponent implements OnInit, AfterViewInit, OnDestroy {
298
383
  * Fires when the user types in the message input box.
299
384
  */
300
385
  inputValueChange: EventEmitter<string>;
386
+ /**
387
+ * Fires when the user scrolls near the edge of the rendered message window in endless scroll mode.
388
+ */
389
+ loadMore: EventEmitter<ChatLoadMoreEvent>;
390
+ /**
391
+ * Fires when the user clicks a referenced message (pinned indicator or reply preview).
392
+ */
393
+ referencedMessageClick: EventEmitter<ChatReferencedMessageClickEvent>;
301
394
  get className(): string;
302
395
  get dirAttr(): string;
303
396
  set messagesContextMenu(contextMenu: ContextMenuComponent);
@@ -328,6 +421,18 @@ export declare class ChatComponent implements OnInit, AfterViewInit, OnDestroy {
328
421
  * Returns processed messages when model fields are used, otherwise returns original messages.
329
422
  */
330
423
  get processedMessages(): Message[];
424
+ /**
425
+ * @hidden
426
+ * Returns `true` when the Chat is in remote endless scroll mode.
427
+ * Remote mode is active whenever the consumer provides a `total`.
428
+ */
429
+ get isRemoteMode(): boolean;
430
+ /**
431
+ * @hidden
432
+ * Returns the messages to render — sliced in endless mode, full in scrollable mode.
433
+ * In remote mode, returns processedMessages as-is (consumer already provides only the current batch).
434
+ */
435
+ get renderedMessages(): Message[];
331
436
  /**
332
437
  * @hidden
333
438
  */
@@ -362,6 +467,19 @@ export declare class ChatComponent implements OnInit, AfterViewInit, OnDestroy {
362
467
  * @hidden
363
468
  */
364
469
  scrollToBottomIcon: SVGIcon;
470
+ /**
471
+ * @hidden
472
+ */
473
+ endlessState: EndlessScrollState;
474
+ /**
475
+ * @hidden
476
+ */
477
+ showLicenseWatermark: boolean;
478
+ /**
479
+ * @hidden
480
+ */
481
+ licenseMessage?: LicenseMessage;
482
+ private anchor;
365
483
  private direction;
366
484
  private subs;
367
485
  private _modelFields;
@@ -372,6 +490,16 @@ export declare class ChatComponent implements OnInit, AfterViewInit, OnDestroy {
372
490
  private _lastModelFields;
373
491
  private _cachedContextMenuActions;
374
492
  private _lastContextMenuActionsReference;
493
+ private _previousMessagesLength;
494
+ private _pendingScrollAction;
495
+ private _scrollHandledBeforePaint;
496
+ private _lastNewMessageId;
497
+ private _cachedRenderedMessages;
498
+ private _renderedMessagesSource;
499
+ private _renderedMessagesStart;
500
+ private _renderedMessagesEnd;
501
+ private _pendingRemoteScrollToMessageId;
502
+ private _remoteScrollToBottom;
375
503
  constructor(localization: LocalizationService, zone: NgZone, renderer: Renderer2, element: ElementRef, chatService: ChatService);
376
504
  /**
377
505
  * @hidden
@@ -400,7 +528,23 @@ export declare class ChatComponent implements OnInit, AfterViewInit, OnDestroy {
400
528
  /**
401
529
  * @hidden
402
530
  */
403
- scrollToPinnedMessage(): void;
531
+ scrollToPinnedMessage(event?: MouseEvent): void;
532
+ /**
533
+ * @hidden
534
+ */
535
+ onNearTop(): void;
536
+ /**
537
+ * @hidden
538
+ */
539
+ onNearBottom(): void;
540
+ /**
541
+ * @hidden
542
+ */
543
+ onScrollToBottomClick(): void;
544
+ /**
545
+ * @hidden
546
+ */
547
+ handleReferencedMessageClick(messageId: string | number, type: 'pinned' | 'reply'): void;
404
548
  /**
405
549
  * @hidden
406
550
  */
@@ -413,9 +557,27 @@ export declare class ChatComponent implements OnInit, AfterViewInit, OnDestroy {
413
557
  * @hidden
414
558
  */
415
559
  onActionButtonClick(event: MouseEvent): void;
560
+ /**
561
+ * @hidden
562
+ */
563
+ onMessageListResize(): void;
564
+ /**
565
+ * Schedules the new-message scroll adjustment on zone.onStable so it runs
566
+ * after Angular renders the new DOM but before the browser paints,
567
+ * preventing a visible intermediate frame.
568
+ */
569
+ private scheduleNewMessageScroll;
570
+ private detectNewMessageScrollAction;
571
+ private getLastNewMessageElement;
416
572
  private findLastPinnedMessage;
573
+ private initEndlessScroll;
574
+ private handleMessagesChange;
575
+ private handleRemoteMessagesChange;
576
+ private handleRemoteReferencedMessageClick;
577
+ private handlePendingRemoteScroll;
417
578
  private updateChatServiceProperties;
579
+ private validateRemoteInputs;
418
580
  private mergeWithDefaultActions;
419
581
  static ɵfac: i0.ɵɵFactoryDeclaration<ChatComponent, never>;
420
- static ɵcmp: i0.ɵɵComponentDeclaration<ChatComponent, "kendo-chat", never, { "messages": { "alias": "messages"; "required": false; }; "authorId": { "alias": "authorId"; "required": false; }; "messageBoxType": { "alias": "messageBoxType"; "required": false; }; "height": { "alias": "height"; "required": false; }; "width": { "alias": "width"; "required": false; }; "placeholder": { "alias": "placeholder"; "required": false; }; "messageWidthMode": { "alias": "messageWidthMode"; "required": false; }; "timestampVisibility": { "alias": "timestampVisibility"; "required": false; }; "showUsername": { "alias": "showUsername"; "required": false; }; "showAvatar": { "alias": "showAvatar"; "required": false; }; "allowMessageCollapse": { "alias": "allowMessageCollapse"; "required": false; }; "speechToTextButton": { "alias": "speechToTextButton"; "required": false; }; "fileSelectButton": { "alias": "fileSelectButton"; "required": false; }; "messageBoxSettings": { "alias": "messageBoxSettings"; "required": false; }; "messageToolbarActions": { "alias": "messageToolbarActions"; "required": false; }; "inputValue": { "alias": "inputValue"; "required": false; }; "authorMessageSettings": { "alias": "authorMessageSettings"; "required": false; }; "receiverMessageSettings": { "alias": "receiverMessageSettings"; "required": false; }; "messageContextMenuActions": { "alias": "messageContextMenuActions"; "required": false; }; "fileActions": { "alias": "fileActions"; "required": false; }; "messageFilesLayout": { "alias": "messageFilesLayout"; "required": false; }; "suggestionsLayout": { "alias": "suggestionsLayout"; "required": false; }; "quickActionsLayout": { "alias": "quickActionsLayout"; "required": false; }; "suggestions": { "alias": "suggestions"; "required": false; }; "sendButton": { "alias": "sendButton"; "required": false; }; "sendButtonSettings": { "alias": "sendButtonSettings"; "required": false; }; "modelFields": { "alias": "modelFields"; "required": false; }; "scrollToBottomButton": { "alias": "scrollToBottomButton"; "required": false; }; "loading": { "alias": "loading"; "required": false; }; }, { "sendMessage": "sendMessage"; "resendMessage": "resendMessage"; "toolbarActionClick": "toolbarActionClick"; "contextMenuActionClick": "contextMenuActionClick"; "fileActionClick": "fileActionClick"; "download": "download"; "executeAction": "executeAction"; "suggestionExecute": "suggestionExecute"; "fileSelect": "fileSelect"; "fileRemove": "fileRemove"; "unpin": "unpin"; "inputValueChange": "inputValueChange"; }, ["attachmentTemplate", "chatHeaderTemplate", "chatNoDataTemplate", "authorMessageContentTemplate", "receiverMessageContentTemplate", "messageContentTemplate", "authorMessageTemplate", "receiverMessageTemplate", "messageTemplate", "timestampTemplate", "suggestionTemplate", "statusTemplate", "messageBoxTemplate", "messageBoxStartAffixTemplate", "messageBoxEndAffixTemplate", "messageBoxTopAffixTemplate", "userStatusTemplate"], never, true, never>;
582
+ static ɵcmp: i0.ɵɵComponentDeclaration<ChatComponent, "kendo-chat", never, { "messages": { "alias": "messages"; "required": false; }; "authorId": { "alias": "authorId"; "required": false; }; "messageBoxType": { "alias": "messageBoxType"; "required": false; }; "height": { "alias": "height"; "required": false; }; "width": { "alias": "width"; "required": false; }; "placeholder": { "alias": "placeholder"; "required": false; }; "messageWidthMode": { "alias": "messageWidthMode"; "required": false; }; "timestampVisibility": { "alias": "timestampVisibility"; "required": false; }; "showUsername": { "alias": "showUsername"; "required": false; }; "showAvatar": { "alias": "showAvatar"; "required": false; }; "allowMessageCollapse": { "alias": "allowMessageCollapse"; "required": false; }; "speechToTextButton": { "alias": "speechToTextButton"; "required": false; }; "fileSelectButton": { "alias": "fileSelectButton"; "required": false; }; "messageBoxSettings": { "alias": "messageBoxSettings"; "required": false; }; "messageToolbarActions": { "alias": "messageToolbarActions"; "required": false; }; "inputValue": { "alias": "inputValue"; "required": false; }; "authorMessageSettings": { "alias": "authorMessageSettings"; "required": false; }; "receiverMessageSettings": { "alias": "receiverMessageSettings"; "required": false; }; "messageContextMenuActions": { "alias": "messageContextMenuActions"; "required": false; }; "fileActions": { "alias": "fileActions"; "required": false; }; "messageFilesLayout": { "alias": "messageFilesLayout"; "required": false; }; "suggestionsLayout": { "alias": "suggestionsLayout"; "required": false; }; "quickActionsLayout": { "alias": "quickActionsLayout"; "required": false; }; "suggestions": { "alias": "suggestions"; "required": false; }; "sendButton": { "alias": "sendButton"; "required": false; }; "sendButtonSettings": { "alias": "sendButtonSettings"; "required": false; }; "scrollMode": { "alias": "scrollMode"; "required": false; }; "pageSize": { "alias": "pageSize"; "required": false; }; "autoScrollThreshold": { "alias": "autoScrollThreshold"; "required": false; }; "total": { "alias": "total"; "required": false; }; "startIndex": { "alias": "startIndex"; "required": false; }; "endIndex": { "alias": "endIndex"; "required": false; }; "pinnedMessages": { "alias": "pinnedMessages"; "required": false; }; "repliedToMessages": { "alias": "repliedToMessages"; "required": false; }; "modelFields": { "alias": "modelFields"; "required": false; }; "scrollToBottomButton": { "alias": "scrollToBottomButton"; "required": false; }; "loading": { "alias": "loading"; "required": false; }; }, { "sendMessage": "sendMessage"; "resendMessage": "resendMessage"; "toolbarActionClick": "toolbarActionClick"; "contextMenuActionClick": "contextMenuActionClick"; "fileActionClick": "fileActionClick"; "download": "download"; "executeAction": "executeAction"; "suggestionExecute": "suggestionExecute"; "fileSelect": "fileSelect"; "fileRemove": "fileRemove"; "unpin": "unpin"; "inputValueChange": "inputValueChange"; "loadMore": "loadMore"; "referencedMessageClick": "referencedMessageClick"; }, ["attachmentTemplate", "chatHeaderTemplate", "chatNoDataTemplate", "authorMessageContentTemplate", "receiverMessageContentTemplate", "messageContentTemplate", "authorMessageTemplate", "receiverMessageTemplate", "messageTemplate", "timestampTemplate", "suggestionTemplate", "statusTemplate", "messageBoxTemplate", "messageBoxStartAffixTemplate", "messageBoxEndAffixTemplate", "messageBoxTopAffixTemplate", "userStatusTemplate"], never, true, never>;
421
583
  }
@@ -2,7 +2,7 @@
2
2
  * Copyright © 2026 Progress Software Corporation. All rights reserved.
3
3
  * Licensed under commercial license. See LICENSE.md in the project root for more information
4
4
  *-------------------------------------------------------------------------------------------*/
5
- import { ViewContainerRef, ElementRef } from '@angular/core';
5
+ import { ViewContainerRef, ElementRef, NgZone } from '@angular/core';
6
6
  import { SpeechToTextButtonSettings } from '@progress/kendo-angular-buttons';
7
7
  import { MessageWidthMode } from '../api/message-width-mode';
8
8
  import { FileAction, FileActionEvent, FileDownloadEvent, FilesLayoutMode, Message, MessageAction, MessageActionEvent, MessageSettings, QuickActionsLayoutMode, ResendMessageEvent, SendButtonSettings, SuggestionsLayoutMode } from '../api';
@@ -15,15 +15,17 @@ import * as i0 from "@angular/core";
15
15
  * @hidden
16
16
  */
17
17
  export declare class ChatService {
18
+ private zone;
18
19
  authorId: string | number;
19
20
  messageWidthMode: MessageWidthMode;
20
- messageToolbarActions: MessageAction[];
21
21
  messageContextMenuActions: MessageAction[];
22
22
  calculatedContextMenuActions: MessageAction[];
23
23
  fileActions: FileAction[];
24
24
  toggleMessageState: boolean;
25
+ layoutChangeInProgress: boolean;
25
26
  reply: Message;
26
27
  messages: Message[];
28
+ repliedToMessages: Message[];
27
29
  chatElement: ViewContainerRef;
28
30
  messageElementsMap: Map<string | number, ElementRef>;
29
31
  messagesContextMenu: ContextMenuComponent;
@@ -41,6 +43,7 @@ export declare class ChatService {
41
43
  private _messageBoxSettings;
42
44
  private _suggestionsLayout;
43
45
  private _quickActionsLayout;
46
+ private _messageToolbarActions;
44
47
  _authorMessageSettings: MessageSettings;
45
48
  _receiverMessageSettings: MessageSettings;
46
49
  private _allowMessageCollapse;
@@ -58,6 +61,8 @@ export declare class ChatService {
58
61
  authorMessageSettingsChange$: import("rxjs").Observable<MessageSettings>;
59
62
  receiverMessageSettingsChange$: import("rxjs").Observable<MessageSettings>;
60
63
  allowMessageCollapseChange$: import("rxjs").Observable<boolean>;
64
+ messageToolbarActionsChange$: import("rxjs").Observable<MessageAction[]>;
65
+ constructor(zone: NgZone);
61
66
  set authorMessageSettings(settings: MessageSettings);
62
67
  get authorMessageSettings(): MessageSettings;
63
68
  set receiverMessageSettings(settings: MessageSettings);
@@ -74,6 +79,8 @@ export declare class ChatService {
74
79
  get suggestionsLayout(): SuggestionsLayoutMode;
75
80
  set quickActionsLayout(layoutMode: QuickActionsLayoutMode);
76
81
  get quickActionsLayout(): QuickActionsLayoutMode;
82
+ set messageToolbarActions(value: MessageAction[]);
83
+ get messageToolbarActions(): MessageAction[];
77
84
  set allowMessageCollapse(value: boolean);
78
85
  get allowMessageCollapse(): boolean;
79
86
  calculateContextMenuActions(isOwn: boolean): void;
@@ -81,9 +88,11 @@ export declare class ChatService {
81
88
  getMessageById(id: string | number): Message | undefined;
82
89
  registerMessageElement(messageId: string | number, elementRef: ElementRef): void;
83
90
  unregisterMessageElement(messageId: string | number): void;
84
- scrollToMessage(messageId: string | number): void;
91
+ scrollToMessage(messageId: string | number, behavior?: ScrollBehavior): void;
85
92
  focusActiveMessageElement(): void;
86
93
  isOwnMessage(message: Message): boolean;
94
+ private getScrollContainer;
95
+ private computeScrollTarget;
87
96
  private updateComponentSettings;
88
97
  static ɵfac: i0.ɵɵFactoryDeclaration<ChatService, never>;
89
98
  static ɵprov: i0.ɵɵInjectableDeclaration<ChatService>;
@@ -0,0 +1,36 @@
1
+ /**-----------------------------------------------------------------------------------------
2
+ * Copyright © 2026 Progress Software Corporation. All rights reserved.
3
+ * Licensed under commercial license. See LICENSE.md in the project root for more information
4
+ *-------------------------------------------------------------------------------------------*/
5
+ /**
6
+ * @hidden
7
+ *
8
+ * Tracks the rendered range for endless scroll mode.
9
+ * Pure logic — no Angular dependency.
10
+ */
11
+ export interface EndlessScrollRange {
12
+ start: number;
13
+ end: number;
14
+ }
15
+ /**
16
+ * @hidden
17
+ */
18
+ export declare class EndlessScrollState {
19
+ startIndex: number;
20
+ endIndex: number;
21
+ isLoading: boolean;
22
+ get isAtStart(): boolean;
23
+ get isAtEnd(): boolean;
24
+ private _total;
25
+ private _pageSize;
26
+ get pageSize(): number;
27
+ init(total: number, pageSize: number): EndlessScrollRange;
28
+ extendUp(): EndlessScrollRange | null;
29
+ extendDown(): EndlessScrollRange | null;
30
+ jumpTo(targetIndex: number): EndlessScrollRange;
31
+ jumpToEnd(): EndlessScrollRange;
32
+ updateTotal(total: number): void;
33
+ reset(): void;
34
+ contains(index: number): boolean;
35
+ syncFromInputs(start: number, end: number, total: number): void;
36
+ }
@@ -0,0 +1,11 @@
1
+ /**-----------------------------------------------------------------------------------------
2
+ * Copyright © 2026 Progress Software Corporation. All rights reserved.
3
+ * Licensed under commercial license. See LICENSE.md in the project root for more information
4
+ *-------------------------------------------------------------------------------------------*/
5
+ /**
6
+ * @hidden
7
+ * Scroll action scheduled after a new message is appended.
8
+ * `author` — the local user sent the message; scroll fully to the bottom.
9
+ * `receiver` — a remote message arrived while the user was near the bottom; scroll with threshold.
10
+ */
11
+ export type PendingScrollAction = 'author' | 'receiver';
@@ -13,13 +13,35 @@ export declare class ScrollAnchorDirective implements AfterViewInit, OnInit, OnD
13
13
  private renderer;
14
14
  private cdr;
15
15
  autoScroll: boolean;
16
+ autoScrollThreshold: number | string;
17
+ set endlessMode(value: boolean);
18
+ get endlessMode(): boolean;
19
+ rangeIsAtEnd: boolean;
16
20
  autoScrollChange: EventEmitter<boolean>;
21
+ nearTop: EventEmitter<void>;
22
+ nearBottom: EventEmitter<void>;
17
23
  overflowAnchor: string;
24
+ get scrollBehaviorStyle(): string;
18
25
  showScrollToBottomButton: boolean;
19
26
  showMessageBoxSeparator: boolean;
20
27
  private scrolling;
21
28
  private unsubscribe;
22
29
  private scrollUpdate;
30
+ private _previousScrollHeight;
31
+ private _previousScrollTop;
32
+ private _pendingScrollPreservation;
33
+ private _endlessMode;
34
+ private _nearTopLocked;
35
+ private _nearBottomLocked;
36
+ private _scrollingToMessage;
37
+ private _initialScrollDone;
38
+ private _subs;
39
+ private _streamingFollow;
40
+ private _thresholdScrollCap;
41
+ private _streamingPrevScrollTop;
42
+ private _streamingPrevHeight;
43
+ private _streamingPrevMsgCount;
44
+ private _mutationObserver;
23
45
  constructor(element: ElementRef, zone: NgZone, renderer: Renderer2, cdr: ChangeDetectorRef);
24
46
  ngOnInit(): void;
25
47
  ngAfterViewInit(): void;
@@ -27,9 +49,24 @@ export declare class ScrollAnchorDirective implements AfterViewInit, OnInit, OnD
27
49
  onScroll(): void;
28
50
  autoScrollToBottom(): void;
29
51
  scrollToBottom(): void;
52
+ scrollToBottomWithSettle(onComplete?: () => void): void;
53
+ scrollWithThreshold(messageEl: HTMLElement): void;
54
+ recordScrollHeight(): void;
55
+ preserveScrollPosition(): void;
30
56
  calculateMessageBoxSeparator(): void;
57
+ getDistanceFromBottom(): number;
58
+ setAriaLive(value: string): void;
59
+ lockForMessageScroll(): void;
60
+ unlockForMessageScroll(): void;
61
+ getAutoScrollThresholdPx(): number;
62
+ get isFollowingThreshold(): boolean;
63
+ private followStreamingContent;
64
+ private updateScrollToBottomButton;
65
+ private detectStreamingScrollUp;
66
+ private parseThreshold;
67
+ private getPinnedBarHeight;
31
68
  private setupScrollUpdate;
32
69
  private performScroll;
33
70
  static ɵfac: i0.ɵɵFactoryDeclaration<ScrollAnchorDirective, never>;
34
- static ɵdir: i0.ɵɵDirectiveDeclaration<ScrollAnchorDirective, "[kendoChatScrollAnchor]", ["scrollAnchor"], { "autoScroll": { "alias": "autoScroll"; "required": false; }; }, { "autoScrollChange": "autoScrollChange"; }, never, never, true, never>;
71
+ static ɵdir: i0.ɵɵDirectiveDeclaration<ScrollAnchorDirective, "[kendoChatScrollAnchor]", ["scrollAnchor"], { "autoScroll": { "alias": "autoScroll"; "required": false; }; "autoScrollThreshold": { "alias": "autoScrollThreshold"; "required": false; }; "endlessMode": { "alias": "endlessMode"; "required": false; }; "rangeIsAtEnd": { "alias": "rangeIsAtEnd"; "required": false; }; }, { "autoScrollChange": "autoScrollChange"; "nearTop": "nearTop"; "nearBottom": "nearBottom"; }, never, never, true, never>;
35
72
  }
@@ -7,6 +7,21 @@ import { ConversationalUIModelFields } from "./models/model-fields";
7
7
  import { FileSelectButtonSettings } from '../../promptbox/common/models';
8
8
  import { SpeechToTextButtonSettings } from "@progress/kendo-angular-buttons";
9
9
  import { MessageBoxSettings } from "../api/message-box";
10
+ import { NgZone } from "@angular/core";
11
+ /**
12
+ * @hidden
13
+ *
14
+ * Show the scroll-to-bottom button when the user is this many pixels from the bottom.
15
+ */
16
+ export declare const scrollButtonThreshold = 100;
17
+ /**
18
+ * @hidden
19
+ *
20
+ * Pins a scroll container to a computed target across layout shifts.
21
+ * Observers extend the idle window until layout has settled; the initial and
22
+ * final pins bracket the settle window so the viewport lands exactly on target.
23
+ */
24
+ export declare const settleScroll: (zone: NgZone, el: HTMLElement, computeTarget: () => number | null, onComplete: () => void, idleMs?: number, timeoutMs?: number) => void;
10
25
  /**
11
26
  * @hidden
12
27
  */
@@ -2,7 +2,7 @@
2
2
  * Copyright © 2026 Progress Software Corporation. All rights reserved.
3
3
  * Licensed under commercial license. See LICENSE.md in the project root for more information
4
4
  *-------------------------------------------------------------------------------------------*/
5
- import { ChangeDetectorRef, ElementRef, OnDestroy, OnInit } from '@angular/core';
5
+ import { ChangeDetectorRef, ElementRef, NgZone, OnDestroy, OnInit } from '@angular/core';
6
6
  import { Message } from './api/message.interface';
7
7
  import { MessageStatus } from './api/message-status.interface';
8
8
  import { ChatItem } from './chat-item';
@@ -31,6 +31,7 @@ export declare class MessageComponent extends ChatItem implements OnInit, OnDest
31
31
  chatService: ChatService;
32
32
  private localization;
33
33
  private cdr;
34
+ private zone;
34
35
  set message(value: Message);
35
36
  get message(): Message;
36
37
  tabbable: boolean;
@@ -71,7 +72,7 @@ export declare class MessageComponent extends ChatItem implements OnInit, OnDest
71
72
  get showToolbar(): boolean;
72
73
  private subs;
73
74
  private _message;
74
- constructor(element: ElementRef, intl: IntlService, chatService: ChatService, localization: LocalizationService, cdr: ChangeDetectorRef);
75
+ constructor(element: ElementRef, intl: IntlService, chatService: ChatService, localization: LocalizationService, cdr: ChangeDetectorRef, zone: NgZone);
75
76
  ngOnInit(): void;
76
77
  ngAfterViewInit(): void;
77
78
  ngOnDestroy(): void;
@@ -99,6 +100,7 @@ export declare class MessageComponent extends ChatItem implements OnInit, OnDest
99
100
  private getMessageSettings;
100
101
  private getToolbarActions;
101
102
  private getFileActions;
103
+ private updateExpandCollapseIconAfterStable;
102
104
  static ɵfac: i0.ɵɵFactoryDeclaration<MessageComponent, never>;
103
105
  static ɵcmp: i0.ɵɵComponentDeclaration<MessageComponent, "kendo-chat-message", never, { "message": { "alias": "message"; "required": false; }; "tabbable": { "alias": "tabbable"; "required": false; }; "authorMessageContentTemplate": { "alias": "authorMessageContentTemplate"; "required": false; }; "receiverMessageContentTemplate": { "alias": "receiverMessageContentTemplate"; "required": false; }; "messageContentTemplate": { "alias": "messageContentTemplate"; "required": false; }; "authorMessageTemplate": { "alias": "authorMessageTemplate"; "required": false; }; "receiverMessageTemplate": { "alias": "receiverMessageTemplate"; "required": false; }; "messageTemplate": { "alias": "messageTemplate"; "required": false; }; "statusTemplate": { "alias": "statusTemplate"; "required": false; }; "showMessageTime": { "alias": "showMessageTime"; "required": false; }; "authorId": { "alias": "authorId"; "required": false; }; }, {}, never, never, true, never>;
104
106
  }