stream-chat-angular 4.67.0 → 4.68.0

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.
@@ -3,7 +3,7 @@ import * as i0 from '@angular/core';
3
3
  import { Injectable, Component, Input, EventEmitter, Output, ViewChild, InjectionToken, Directive, HostBinding, Inject, ChangeDetectionStrategy, NgModule } from '@angular/core';
4
4
  import { BehaviorSubject, ReplaySubject, combineLatest, Subject, timer } from 'rxjs';
5
5
  import { StreamChat } from 'stream-chat';
6
- import { take, shareReplay, map, first, filter, tap, distinctUntilChanged, debounceTime } from 'rxjs/operators';
6
+ import { take, shareReplay, map, first, filter, tap, distinctUntilChanged, debounceTime, throttleTime } from 'rxjs/operators';
7
7
  import { v4 } from 'uuid';
8
8
  import * as i9 from '@ngx-translate/core';
9
9
  import { TranslateModule } from '@ngx-translate/core';
@@ -20,7 +20,7 @@ import transliterate from '@stream-io/transliterate';
20
20
  import * as i8$1 from 'angular-mentions';
21
21
  import { MentionModule } from 'angular-mentions';
22
22
 
23
- const version = '4.67.0';
23
+ const version = '4.68.0';
24
24
 
25
25
  /**
26
26
  * The `NotificationService` can be used to add or remove notifications. By default the [`NotificationList`](../components/NotificationListComponent.mdx) component displays the currently active notifications.
@@ -436,6 +436,23 @@ class ChannelService {
436
436
  .asObservable()
437
437
  .pipe(shareReplay(1));
438
438
  }
439
+ /**
440
+ * internal
441
+ */
442
+ removeOldMessageFromMessageList() {
443
+ const channel = this.activeChannelSubject.getValue();
444
+ const channelMessages = channel === null || channel === void 0 ? void 0 : channel.state.latestMessages;
445
+ const targetLength = Math.ceil(ChannelService.MAX_MESSAGE_COUNT_IN_MESSAGE_LIST / 2);
446
+ if (!channel ||
447
+ !channelMessages ||
448
+ channelMessages !== (channel === null || channel === void 0 ? void 0 : channel.state.latestMessages) ||
449
+ channelMessages.length <= targetLength) {
450
+ return;
451
+ }
452
+ const messages = channelMessages;
453
+ messages.splice(0, messages.length - targetLength);
454
+ this.activeChannelMessagesSubject.next(messages);
455
+ }
439
456
  /**
440
457
  * If set to false, read events won't be sent as new messages are received. If set to true active channel (if any) will immediately be marked as read.
441
458
  */
@@ -1005,6 +1022,12 @@ class ChannelService {
1005
1022
  }
1006
1023
  });
1007
1024
  }
1025
+ /**
1026
+ * Clears the currently selected message to jump
1027
+ */
1028
+ clearMessageJump() {
1029
+ this.jumpToMessageSubject.next({ id: undefined, parentId: undefined });
1030
+ }
1008
1031
  /**
1009
1032
  * Pins the given message in the channel
1010
1033
  * @param message
@@ -1798,7 +1821,11 @@ class ChannelService {
1798
1821
  }
1799
1822
  }
1800
1823
  /**
1801
- * internal
1824
+ * @internal
1825
+ */
1826
+ ChannelService.MAX_MESSAGE_COUNT_IN_MESSAGE_LIST = 250;
1827
+ /**
1828
+ * @internal
1802
1829
  */
1803
1830
  ChannelService.MAX_MESSAGE_REACTIONS_TO_FETCH = 1200;
1804
1831
  ChannelService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: ChannelService, deps: [{ token: ChatClientService }, { token: i0.NgZone }, { token: NotificationService }], target: i0.ɵɵFactoryTarget.Injectable });
@@ -6432,6 +6459,10 @@ class MessageListComponent {
6432
6459
  * You can turn on and off the loading indicator that signals to users that more messages are being loaded to the message list
6433
6460
  */
6434
6461
  this.displayLoadingIndicator = true;
6462
+ /**
6463
+ * @internal
6464
+ */
6465
+ this.limitNumberOfMessagesInList = true;
6435
6466
  this.emptyMainMessageListTemplate = null;
6436
6467
  this.emptyThreadMessageListTemplate = null;
6437
6468
  this.enabledMessageActions = [];
@@ -6447,6 +6478,8 @@ class MessageListComponent {
6447
6478
  this.isLatestMessageInList = true;
6448
6479
  this.parsedDates = new Map();
6449
6480
  this.isViewInited = false;
6481
+ this.isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
6482
+ this.forceRepaintSubject = new Subject();
6450
6483
  this.messageNotificationJumpClicked = () => {
6451
6484
  this.jumpToFirstUnreadMessage();
6452
6485
  this.isUnreadNotificationVisible = false;
@@ -6461,6 +6494,9 @@ class MessageListComponent {
6461
6494
  return `str-chat-angular__main-panel-inner str-chat-angular__message-list-host str-chat__main-panel-inner ${this.isEmpty ? 'str-chat-angular__message-list-host--empty' : ''}`;
6462
6495
  }
6463
6496
  ngOnInit() {
6497
+ this.subscriptions.push(this.forceRepaintSubject.pipe(throttleTime(1000)).subscribe(() => {
6498
+ this.forceRepaint();
6499
+ }));
6464
6500
  this.subscriptions.push(this.channelService.activeChannel$.subscribe((channel) => {
6465
6501
  var _a, _b, _c, _d, _e, _f, _g;
6466
6502
  (_b = (_a = this.chatClientService.chatClient) === null || _a === void 0 ? void 0 : _a.logger) === null || _b === void 0 ? void 0 : _b.call(_a, 'info', `${(channel === null || channel === void 0 ? void 0 : channel.cid) || 'undefined'} selected`, { tags: `message list ${this.mode}` });
@@ -6473,6 +6509,9 @@ class MessageListComponent {
6473
6509
  this.isUnreadNotificationVisible = false;
6474
6510
  (_e = (_d = (_c = this.chatClientService) === null || _c === void 0 ? void 0 : _c.chatClient) === null || _d === void 0 ? void 0 : _d.logger) === null || _e === void 0 ? void 0 : _e.call(_d, 'info', `new channel is different from prev channel, reseting scroll state`, { tags: `message list ${this.mode}` });
6475
6511
  this.parsedDates = new Map();
6512
+ if (this.messageRemoveTimeout) {
6513
+ clearTimeout(this.messageRemoveTimeout);
6514
+ }
6476
6515
  this.resetScrollState();
6477
6516
  this.channelId = channel === null || channel === void 0 ? void 0 : channel.id;
6478
6517
  if (this.isViewInited) {
@@ -6621,6 +6660,9 @@ class MessageListComponent {
6621
6660
  .subscribe((config) => {
6622
6661
  var _a, _b;
6623
6662
  let messageId = undefined;
6663
+ if (this.messageRemoveTimeout) {
6664
+ clearTimeout(this.messageRemoveTimeout);
6665
+ }
6624
6666
  if (this.mode === 'main') {
6625
6667
  messageId = config.parentId || config.id;
6626
6668
  }
@@ -6647,6 +6689,7 @@ class MessageListComponent {
6647
6689
  }
6648
6690
  }
6649
6691
  }
6692
+ this.channelService.clearMessageJump();
6650
6693
  }));
6651
6694
  this.subscriptions.push(this.customTemplatesService.emptyMainMessageListPlaceholder$.subscribe((template) => {
6652
6695
  const isChanged = this.emptyMainMessageListTemplate !== template;
@@ -6730,7 +6773,7 @@ class MessageListComponent {
6730
6773
  }
6731
6774
  }
6732
6775
  ngOnDestroy() {
6733
- var _a;
6776
+ var _a, _b;
6734
6777
  this.subscriptions.forEach((s) => s.unsubscribe());
6735
6778
  (_a = this.newMessageSubscription) === null || _a === void 0 ? void 0 : _a.unsubscribe();
6736
6779
  if (this.scrollEndTimeout) {
@@ -6742,6 +6785,10 @@ class MessageListComponent {
6742
6785
  if (this.jumpToLatestButtonVisibilityTimeout) {
6743
6786
  clearTimeout(this.jumpToLatestButtonVisibilityTimeout);
6744
6787
  }
6788
+ if (this.messageRemoveTimeout) {
6789
+ clearTimeout(this.messageRemoveTimeout);
6790
+ }
6791
+ (_b = this.removeOldMessagesSubscription) === null || _b === void 0 ? void 0 : _b.unsubscribe();
6745
6792
  }
6746
6793
  trackByMessageId(index, item) {
6747
6794
  return item.id;
@@ -6756,7 +6803,9 @@ class MessageListComponent {
6756
6803
  scrollToBottom() {
6757
6804
  this.scrollContainer.nativeElement.scrollTop =
6758
6805
  this.scrollContainer.nativeElement.scrollHeight + 0.1;
6759
- this.forceRepaint();
6806
+ if (this.isSafari) {
6807
+ this.forceRepaintSubject.next();
6808
+ }
6760
6809
  }
6761
6810
  scrollToTop() {
6762
6811
  this.scrollContainer.nativeElement.scrollTop = 0;
@@ -6799,7 +6848,7 @@ class MessageListComponent {
6799
6848
  }
6800
6849
  if (this.shouldLoadMoreMessages(scrollPosition)) {
6801
6850
  this.ngZone.run(() => {
6802
- var _a, _b;
6851
+ var _a, _b, _c;
6803
6852
  this.containerHeight = this.scrollContainer.nativeElement.scrollHeight;
6804
6853
  let direction;
6805
6854
  if (this.direction === 'top-to-bottom') {
@@ -6814,6 +6863,9 @@ class MessageListComponent {
6814
6863
  if (result) {
6815
6864
  (_b = (_a = this.chatClientService.chatClient) === null || _a === void 0 ? void 0 : _a.logger) === null || _b === void 0 ? void 0 : _b.call(_a, 'info', `Displaying loading indicator`, { tags: `message list ${this.mode}` });
6816
6865
  this.isLoading = true;
6866
+ (_c = result.catch) === null || _c === void 0 ? void 0 : _c.call(result, () => {
6867
+ this.isLoading = false;
6868
+ });
6817
6869
  }
6818
6870
  this.cdRef.detectChanges();
6819
6871
  });
@@ -6882,16 +6934,20 @@ class MessageListComponent {
6882
6934
  position = 'top';
6883
6935
  }
6884
6936
  else if (Math.ceil(this.scrollContainer.nativeElement.scrollTop) +
6885
- this.scrollContainer.nativeElement.clientHeight >=
6937
+ this.scrollContainer.nativeElement.clientHeight +
6938
+ 1 >=
6886
6939
  this.scrollContainer.nativeElement.scrollHeight) {
6887
6940
  position = 'bottom';
6888
6941
  }
6889
6942
  return position;
6890
6943
  }
6891
6944
  shouldLoadMoreMessages(scrollPosition) {
6892
- return scrollPosition !== 'middle' && !this.highlightedMessageId;
6945
+ return (scrollPosition !== 'middle' &&
6946
+ !this.highlightedMessageId &&
6947
+ !this.isLoading);
6893
6948
  }
6894
6949
  setMessages$() {
6950
+ var _a;
6895
6951
  this.messages$ = (this.mode === 'main'
6896
6952
  ? this.channelService.activeChannelMessages$
6897
6953
  : this.channelService.activeThreadMessages$).pipe(tap((messages) => {
@@ -6955,7 +7011,40 @@ class MessageListComponent {
6955
7011
  lastReadMessageId: this.lastReadMessageId,
6956
7012
  }));
6957
7013
  this.isNextMessageOnSeparateDate = messages.map((m, i) => this.checkIfOnSeparateDates(m, messages[i + 1]));
6958
- }));
7014
+ }), shareReplay(1));
7015
+ (_a = this.removeOldMessagesSubscription) === null || _a === void 0 ? void 0 : _a.unsubscribe();
7016
+ this.removeOldMessagesSubscription = combineLatest([
7017
+ this.channelService.jumpToMessage$,
7018
+ this.messages$,
7019
+ ]).subscribe(([jumpToMessage, messages]) => {
7020
+ if (this.limitNumberOfMessagesInList &&
7021
+ this.mode === 'main' &&
7022
+ messages.length >
7023
+ ChannelService.MAX_MESSAGE_COUNT_IN_MESSAGE_LIST * 0.5 &&
7024
+ !this.isUserScrolled &&
7025
+ !(jumpToMessage === null || jumpToMessage === void 0 ? void 0 : jumpToMessage.id) &&
7026
+ this.isLatestMessageInList) {
7027
+ if (this.messageRemoveTimeout) {
7028
+ clearTimeout(this.messageRemoveTimeout);
7029
+ }
7030
+ if (messages.length >= ChannelService.MAX_MESSAGE_COUNT_IN_MESSAGE_LIST) {
7031
+ this.channelService.removeOldMessageFromMessageList();
7032
+ }
7033
+ else {
7034
+ this.messageRemoveTimeout = setTimeout(() => {
7035
+ if (this.limitNumberOfMessagesInList &&
7036
+ this.mode === 'main' &&
7037
+ messages.length >
7038
+ ChannelService.MAX_MESSAGE_COUNT_IN_MESSAGE_LIST * 0.5 &&
7039
+ !this.isUserScrolled &&
7040
+ !this.highlightedMessageId &&
7041
+ this.isLatestMessageInList) {
7042
+ this.channelService.removeOldMessageFromMessageList();
7043
+ }
7044
+ }, 1500);
7045
+ }
7046
+ }
7047
+ });
6959
7048
  }
6960
7049
  resetScrollState() {
6961
7050
  this.isEmpty = true;
@@ -7038,7 +7127,7 @@ class MessageListComponent {
7038
7127
  }
7039
7128
  }
7040
7129
  MessageListComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: MessageListComponent, deps: [{ token: ChannelService }, { token: ChatClientService }, { token: CustomTemplatesService }, { token: DateParserService }, { token: i0.NgZone }, { token: i0.ChangeDetectorRef }, { token: MessageActionsService }], target: i0.ɵɵFactoryTarget.Component });
7041
- MessageListComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: MessageListComponent, selector: "stream-message-list", inputs: { mode: "mode", direction: "direction", messageOptionsTrigger: "messageOptionsTrigger", hideJumpToLatestButtonDuringScroll: "hideJumpToLatestButtonDuringScroll", customMessageActions: "customMessageActions", displayDateSeparator: "displayDateSeparator", displayUnreadSeparator: "displayUnreadSeparator", dateSeparatorTextPos: "dateSeparatorTextPos", openMessageListAt: "openMessageListAt", hideUnreadCountForNotificationAndIndicator: "hideUnreadCountForNotificationAndIndicator", displayLoadingIndicator: "displayLoadingIndicator" }, host: { properties: { "class": "this.class" } }, viewQueries: [{ propertyName: "scrollContainer", first: true, predicate: ["scrollContainer"], descendants: true }, { propertyName: "parentMessageElement", first: true, predicate: ["parentMessageElement"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<ng-container\n *ngIf=\"\n lastReadMessageId &&\n isUnreadNotificationVisible &&\n openMessageListAt === 'last-message' &&\n displayUnreadSeparator\n \"\n>\n <ng-container\n *ngTemplateOutlet=\"\n customnewMessagesNotificationTemplate ||\n defaultUnreadMessagesNotification;\n context: {\n unreadCount: unreadCount,\n onDismiss: messageNotificationDismissClicked,\n onJump: messageNotificationJumpClicked\n }\n \"\n ></ng-container>\n</ng-container>\n<ng-template\n #defaultUnreadMessagesNotification\n let-unreadCount=\"unreadCount\"\n let-onDismiss=\"onDismiss\"\n let-onJump=\"onJump\"\n>\n <div\n class=\"str-chat__unread-messages-notification\"\n data-testid=\"unread-messages-notification\"\n >\n <button\n data-testid=\"unread-messages-notification-jump-to-message\"\n (click)=\"onJump()\"\n >\n <ng-container\n *ngIf=\"\n unreadCount > 0 && !hideUnreadCountForNotificationAndIndicator;\n else noUnreadCount\n \"\n >\n {{\n (unreadCount === 1\n ? \"streamChat.\\{\\{count\\}\\} unread message\"\n : \"streamChat.\\{\\{count\\}\\} unread messages\"\n ) | translate: { count: unreadCount }\n }}\n </ng-container>\n <ng-template #noUnreadCount>\n {{ \"streamChat.Unread messages\" | translate }}\n </ng-template>\n </button>\n <button\n data-testid=\"unread-messages-notification-dismiss\"\n (click)=\"onDismiss()\"\n >\n <stream-icon-placeholder icon=\"close\"></stream-icon-placeholder>\n </button>\n </div>\n</ng-template>\n<div #scrollContainer data-testid=\"scroll-container\" class=\"str-chat__list\">\n <ng-container *ngIf=\"mode === 'main' && isEmpty && emptyListTemplate\">\n <ng-container *ngTemplateOutlet=\"emptyListTemplate\"></ng-container>\n </ng-container>\n <div class=\"str-chat__reverse-infinite-scroll str-chat__message-list-scroll\">\n <ul\n class=\"str-chat__ul\"\n [class.str-chat__message-options-in-bubble]=\"\n messageOptionsTrigger === 'message-bubble'\n \"\n >\n <li\n #parentMessageElement\n *ngIf=\"mode === 'thread' && parentMessage\"\n data-testid=\"parent-message\"\n class=\"str-chat__parent-message-li\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n messageTemplateContainer;\n context: { message: parentMessage, index: 'parent' }\n \"\n ></ng-container>\n <div data-testid=\"reply-count\" class=\"str-chat__thread-start\">\n {{parentMessage?.reply_count === 1 ? ('streamChat.1 reply' | translate) : ('streamChat.{{ replyCount }}\n replies' | translate:replyCountParam)}}\n </div>\n </li>\n <ng-container *ngIf=\"mode === 'thread' && isEmpty && emptyListTemplate\">\n <ng-container *ngTemplateOutlet=\"emptyListTemplate\"></ng-container>\n </ng-container>\n <stream-loading-indicator\n data-testid=\"top-loading-indicator\"\n *ngIf=\"\n isLoading && direction === 'bottom-to-top' && displayLoadingIndicator\n \"\n ></stream-loading-indicator>\n <ng-container *ngIf=\"messages$ | async as messages\">\n <ng-container\n *ngFor=\"\n let message of messages;\n let i = index;\n let isFirst = first;\n let isLast = last;\n trackBy: trackByMessageId\n \"\n >\n <ng-container *ngIf=\"isFirst\">\n <ng-container\n *ngTemplateOutlet=\"\n dateSeparator;\n context: {\n date: message.created_at,\n parsedDate: parseDate(message.created_at)\n }\n \"\n ></ng-container>\n </ng-container>\n <li\n tabindex=\"0\"\n data-testclass=\"message\"\n class=\"str-chat__li str-chat__li--{{ groupStyles[i] }}\"\n id=\"{{ message.id }}\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n messageTemplateContainer;\n context: { message: message, index: i }\n \"\n ></ng-container>\n </li>\n <ng-container\n *ngIf=\"\n (lastReadMessageId === message?.id &&\n direction === 'bottom-to-top') ||\n (direction === 'top-to-bottom' &&\n lastReadMessageId === messages[i + 1]?.id)\n \"\n >\n <li\n *ngIf=\"displayUnreadSeparator\"\n id=\"stream-chat-new-message-indicator\"\n data-testid=\"new-messages-indicator\"\n class=\"str-chat__li str-chat__unread-messages-separator-wrapper\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n customnewMessagesIndicatorTemplate ||\n defaultNewMessagesIndicator;\n context: { unreadCount: unreadCount }\n \"\n ></ng-container>\n </li>\n </ng-container>\n <ng-container *ngIf=\"isNextMessageOnSeparateDate[i]\">\n <ng-container\n *ngTemplateOutlet=\"\n dateSeparator;\n context: {\n date: messages[i + 1].created_at,\n parsedDate: parseDate(messages[i + 1].created_at)\n }\n \"\n ></ng-container>\n </ng-container>\n </ng-container>\n </ng-container>\n <stream-loading-indicator\n data-testid=\"bottom-loading-indicator\"\n *ngIf=\"\n isLoading && direction === 'top-to-bottom' && displayLoadingIndicator\n \"\n ></stream-loading-indicator>\n </ul>\n <ng-template #defaultTypingIndicator let-usersTyping$=\"usersTyping$\">\n <!-- eslint-disable-next-line @angular-eslint/template/no-any -->\n <ng-container *ngIf=\"$any(usersTyping$ | async) as users\">\n <div\n *ngIf=\"users.length > 0\"\n data-testid=\"typing-indicator\"\n class=\"str-chat__typing-indicator str-chat__typing-indicator--typing\"\n >\n <div class=\"str-chat__typing-indicator__dots\">\n <span class=\"str-chat__typing-indicator__dot\"></span>\n <span class=\"str-chat__typing-indicator__dot\"></span>\n <span class=\"str-chat__typing-indicator__dot\"></span>\n </div>\n <div\n data-testid=\"typing-users\"\n class=\"str-chat__typing-indicator__users\"\n >\n {{\n users.length === 1\n ? (\"streamChat.user is typing\"\n | translate: { user: getTypingIndicatorText(users) })\n : (\"streamChat.users are typing\"\n | translate: { users: getTypingIndicatorText(users) })\n }}\n </div>\n </div>\n </ng-container>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n typingIndicatorTemplate || defaultTypingIndicator;\n context: getTypingIndicatorContext()\n \"\n ></ng-container>\n </div>\n</div>\n<div class=\"str-chat__jump-to-latest-message\">\n <button\n data-testid=\"scroll-to-latest\"\n *ngIf=\"isUserScrolled && isJumpToLatestButtonVisible\"\n class=\"\n str-chat__message-notification-scroll-to-latest\n str-chat__message-notification-scroll-to-latest-right\n str-chat__circle-fab\n \"\n (keyup.enter)=\"jumpToLatestMessage()\"\n (click)=\"jumpToLatestMessage()\"\n >\n <stream-icon\n class=\"str-chat__jump-to-latest-icon str-chat__circle-fab-icon\"\n [icon]=\"direction === 'bottom-to-top' ? 'arrow-down' : 'arrow-up'\"\n ></stream-icon>\n <div\n *ngIf=\"newMessageCountWhileBeingScrolled > 0\"\n class=\"\n str-chat__message-notification\n str-chat__message-notification-scroll-to-latest-unread-count\n str-chat__jump-to-latest-unread-count\n \"\n >\n {{ newMessageCountWhileBeingScrolled }}\n </div>\n </button>\n</div>\n\n<ng-template #messageTemplateContainer let-message=\"message\" let-index=\"index\">\n <ng-template\n #defaultMessageTemplate\n let-messageInput=\"message\"\n let-isLastSentMessage=\"isLastSentMessage\"\n let-enabledMessageActions=\"enabledMessageActions\"\n let-mode=\"mode\"\n let-isHighlighted=\"isHighlighted\"\n let-customActions=\"customActions\"\n >\n <stream-message\n [message]=\"messageInput\"\n [isLastSentMessage]=\"isLastSentMessage\"\n [enabledMessageActions]=\"enabledMessageActions\"\n [mode]=\"mode\"\n [isHighlighted]=\"isHighlighted\"\n [customActions]=\"customActions\"\n ></stream-message>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n messageTemplate || defaultMessageTemplate;\n context: {\n message: message,\n isLastSentMessage: !!(\n lastSentMessageId && message?.id === lastSentMessageId\n ),\n enabledMessageActions: enabledMessageActions,\n mode: mode,\n isHighlighted: message?.id === highlightedMessageId,\n customActions: customMessageActions\n }\n \"\n ></ng-container>\n</ng-template>\n\n<ng-template #dateSeparator let-date=\"date\" let-parsedDate=\"parsedDate\">\n <ng-container *ngIf=\"displayDateSeparator\">\n <ng-container\n *ngTemplateOutlet=\"\n customDateSeparatorTemplate || defaultDateSeparator;\n context: {\n date: date,\n parsedDate: parsedDate\n }\n \"\n ></ng-container>\n </ng-container>\n\n <ng-template\n #defaultDateSeparator\n let-date=\"date\"\n let-parsedDate=\"parsedDate\"\n >\n <div data-testid=\"date-separator\" class=\"str-chat__date-separator\">\n <hr\n *ngIf=\"\n dateSeparatorTextPos === 'right' || dateSeparatorTextPos === 'center'\n \"\n class=\"str-chat__date-separator-line\"\n />\n <div class=\"str-chat__date-separator-date\">\n {{ parsedDate }}\n </div>\n <hr\n *ngIf=\"\n dateSeparatorTextPos === 'left' || dateSeparatorTextPos === 'center'\n \"\n class=\"str-chat__date-separator-line\"\n />\n </div>\n </ng-template>\n</ng-template>\n\n<ng-template #defaultNewMessagesIndicator let-unreadCount=\"unreadCount\">\n <div class=\"str-chat__unread-messages-separator\">\n <ng-container\n *ngIf=\"\n unreadCount > 0 && !hideUnreadCountForNotificationAndIndicator;\n else noUnreadCount\n \"\n >\n {{\n (unreadCount === 1\n ? \"streamChat.\\{\\{count\\}\\} unread message\"\n : \"streamChat.\\{\\{count\\}\\} unread messages\"\n ) | translate: { count: unreadCount }\n }}\n </ng-container>\n <ng-template #noUnreadCount>\n {{ \"streamChat.Unread messages\" | translate }}\n </ng-template>\n </div>\n</ng-template>\n", components: [{ type: IconPlaceholderComponent, selector: "stream-icon-placeholder", inputs: ["icon", "size"] }, { type: LoadingIndicatorComponent, selector: "stream-loading-indicator", inputs: ["size", "color"] }, { type: IconComponent, selector: "stream-icon", inputs: ["icon", "size"] }, { type: MessageComponent, selector: "stream-message", inputs: ["message", "enabledMessageActions", "isLastSentMessage", "mode", "isHighlighted", "customActions"] }], directives: [{ type: i8.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i8.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i8.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], pipes: { "translate": i9.TranslatePipe, "async": i8.AsyncPipe }, changeDetection: i0.ChangeDetectionStrategy.OnPush });
7130
+ MessageListComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: MessageListComponent, selector: "stream-message-list", inputs: { mode: "mode", direction: "direction", messageOptionsTrigger: "messageOptionsTrigger", hideJumpToLatestButtonDuringScroll: "hideJumpToLatestButtonDuringScroll", customMessageActions: "customMessageActions", displayDateSeparator: "displayDateSeparator", displayUnreadSeparator: "displayUnreadSeparator", dateSeparatorTextPos: "dateSeparatorTextPos", openMessageListAt: "openMessageListAt", hideUnreadCountForNotificationAndIndicator: "hideUnreadCountForNotificationAndIndicator", displayLoadingIndicator: "displayLoadingIndicator", limitNumberOfMessagesInList: "limitNumberOfMessagesInList" }, host: { properties: { "class": "this.class" } }, viewQueries: [{ propertyName: "scrollContainer", first: true, predicate: ["scrollContainer"], descendants: true }, { propertyName: "parentMessageElement", first: true, predicate: ["parentMessageElement"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<ng-container\n *ngIf=\"\n lastReadMessageId &&\n isUnreadNotificationVisible &&\n openMessageListAt === 'last-message' &&\n displayUnreadSeparator\n \"\n>\n <ng-container\n *ngTemplateOutlet=\"\n customnewMessagesNotificationTemplate ||\n defaultUnreadMessagesNotification;\n context: {\n unreadCount: unreadCount,\n onDismiss: messageNotificationDismissClicked,\n onJump: messageNotificationJumpClicked\n }\n \"\n ></ng-container>\n</ng-container>\n<ng-template\n #defaultUnreadMessagesNotification\n let-unreadCount=\"unreadCount\"\n let-onDismiss=\"onDismiss\"\n let-onJump=\"onJump\"\n>\n <div\n class=\"str-chat__unread-messages-notification\"\n data-testid=\"unread-messages-notification\"\n >\n <button\n data-testid=\"unread-messages-notification-jump-to-message\"\n (click)=\"onJump()\"\n >\n <ng-container\n *ngIf=\"\n unreadCount > 0 && !hideUnreadCountForNotificationAndIndicator;\n else noUnreadCount\n \"\n >\n {{\n (unreadCount === 1\n ? \"streamChat.\\{\\{count\\}\\} unread message\"\n : \"streamChat.\\{\\{count\\}\\} unread messages\"\n ) | translate: { count: unreadCount }\n }}\n </ng-container>\n <ng-template #noUnreadCount>\n {{ \"streamChat.Unread messages\" | translate }}\n </ng-template>\n </button>\n <button\n data-testid=\"unread-messages-notification-dismiss\"\n (click)=\"onDismiss()\"\n >\n <stream-icon-placeholder icon=\"close\"></stream-icon-placeholder>\n </button>\n </div>\n</ng-template>\n<div #scrollContainer data-testid=\"scroll-container\" class=\"str-chat__list\">\n <ng-container *ngIf=\"mode === 'main' && isEmpty && emptyListTemplate\">\n <ng-container *ngTemplateOutlet=\"emptyListTemplate\"></ng-container>\n </ng-container>\n <div class=\"str-chat__reverse-infinite-scroll str-chat__message-list-scroll\">\n <ul\n class=\"str-chat__ul\"\n [class.str-chat__message-options-in-bubble]=\"\n messageOptionsTrigger === 'message-bubble'\n \"\n >\n <li\n #parentMessageElement\n *ngIf=\"mode === 'thread' && parentMessage\"\n data-testid=\"parent-message\"\n class=\"str-chat__parent-message-li\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n messageTemplateContainer;\n context: { message: parentMessage, index: 'parent' }\n \"\n ></ng-container>\n <div data-testid=\"reply-count\" class=\"str-chat__thread-start\">\n {{parentMessage?.reply_count === 1 ? ('streamChat.1 reply' | translate) : ('streamChat.{{ replyCount }}\n replies' | translate:replyCountParam)}}\n </div>\n </li>\n <ng-container *ngIf=\"mode === 'thread' && isEmpty && emptyListTemplate\">\n <ng-container *ngTemplateOutlet=\"emptyListTemplate\"></ng-container>\n </ng-container>\n <stream-loading-indicator\n data-testid=\"top-loading-indicator\"\n *ngIf=\"\n isLoading && direction === 'bottom-to-top' && displayLoadingIndicator\n \"\n ></stream-loading-indicator>\n <ng-container *ngIf=\"messages$ | async as messages\">\n <ng-container\n *ngFor=\"\n let message of messages;\n let i = index;\n let isFirst = first;\n let isLast = last;\n trackBy: trackByMessageId\n \"\n >\n <ng-container *ngIf=\"isFirst\">\n <ng-container\n *ngTemplateOutlet=\"\n dateSeparator;\n context: {\n date: message.created_at,\n parsedDate: parseDate(message.created_at)\n }\n \"\n ></ng-container>\n </ng-container>\n <li\n tabindex=\"0\"\n data-testclass=\"message\"\n class=\"str-chat__li str-chat__li--{{ groupStyles[i] }}\"\n id=\"{{ message.id }}\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n messageTemplateContainer;\n context: { message: message, index: i }\n \"\n ></ng-container>\n </li>\n <ng-container\n *ngIf=\"\n (lastReadMessageId === message?.id &&\n direction === 'bottom-to-top') ||\n (direction === 'top-to-bottom' &&\n lastReadMessageId === messages[i + 1]?.id)\n \"\n >\n <li\n *ngIf=\"displayUnreadSeparator\"\n id=\"stream-chat-new-message-indicator\"\n data-testid=\"new-messages-indicator\"\n class=\"str-chat__li str-chat__unread-messages-separator-wrapper\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n customnewMessagesIndicatorTemplate ||\n defaultNewMessagesIndicator;\n context: { unreadCount: unreadCount }\n \"\n ></ng-container>\n </li>\n </ng-container>\n <ng-container *ngIf=\"isNextMessageOnSeparateDate[i]\">\n <ng-container\n *ngTemplateOutlet=\"\n dateSeparator;\n context: {\n date: messages[i + 1].created_at,\n parsedDate: parseDate(messages[i + 1].created_at)\n }\n \"\n ></ng-container>\n </ng-container>\n </ng-container>\n </ng-container>\n <stream-loading-indicator\n data-testid=\"bottom-loading-indicator\"\n *ngIf=\"\n isLoading && direction === 'top-to-bottom' && displayLoadingIndicator\n \"\n ></stream-loading-indicator>\n </ul>\n <ng-template #defaultTypingIndicator let-usersTyping$=\"usersTyping$\">\n <!-- eslint-disable-next-line @angular-eslint/template/no-any -->\n <ng-container *ngIf=\"$any(usersTyping$ | async) as users\">\n <div\n *ngIf=\"users.length > 0\"\n data-testid=\"typing-indicator\"\n class=\"str-chat__typing-indicator str-chat__typing-indicator--typing\"\n >\n <div class=\"str-chat__typing-indicator__dots\">\n <span class=\"str-chat__typing-indicator__dot\"></span>\n <span class=\"str-chat__typing-indicator__dot\"></span>\n <span class=\"str-chat__typing-indicator__dot\"></span>\n </div>\n <div\n data-testid=\"typing-users\"\n class=\"str-chat__typing-indicator__users\"\n >\n {{\n users.length === 1\n ? (\"streamChat.user is typing\"\n | translate: { user: getTypingIndicatorText(users) })\n : (\"streamChat.users are typing\"\n | translate: { users: getTypingIndicatorText(users) })\n }}\n </div>\n </div>\n </ng-container>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n typingIndicatorTemplate || defaultTypingIndicator;\n context: getTypingIndicatorContext()\n \"\n ></ng-container>\n </div>\n</div>\n<div class=\"str-chat__jump-to-latest-message\">\n <button\n data-testid=\"scroll-to-latest\"\n *ngIf=\"isUserScrolled && isJumpToLatestButtonVisible\"\n class=\"\n str-chat__message-notification-scroll-to-latest\n str-chat__message-notification-scroll-to-latest-right\n str-chat__circle-fab\n \"\n (keyup.enter)=\"jumpToLatestMessage()\"\n (click)=\"jumpToLatestMessage()\"\n >\n <stream-icon\n class=\"str-chat__jump-to-latest-icon str-chat__circle-fab-icon\"\n [icon]=\"direction === 'bottom-to-top' ? 'arrow-down' : 'arrow-up'\"\n ></stream-icon>\n <div\n *ngIf=\"newMessageCountWhileBeingScrolled > 0\"\n class=\"\n str-chat__message-notification\n str-chat__message-notification-scroll-to-latest-unread-count\n str-chat__jump-to-latest-unread-count\n \"\n >\n {{ newMessageCountWhileBeingScrolled }}\n </div>\n </button>\n</div>\n\n<ng-template #messageTemplateContainer let-message=\"message\" let-index=\"index\">\n <ng-template\n #defaultMessageTemplate\n let-messageInput=\"message\"\n let-isLastSentMessage=\"isLastSentMessage\"\n let-enabledMessageActions=\"enabledMessageActions\"\n let-mode=\"mode\"\n let-isHighlighted=\"isHighlighted\"\n let-customActions=\"customActions\"\n >\n <stream-message\n [message]=\"messageInput\"\n [isLastSentMessage]=\"isLastSentMessage\"\n [enabledMessageActions]=\"enabledMessageActions\"\n [mode]=\"mode\"\n [isHighlighted]=\"isHighlighted\"\n [customActions]=\"customActions\"\n ></stream-message>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n messageTemplate || defaultMessageTemplate;\n context: {\n message: message,\n isLastSentMessage: !!(\n lastSentMessageId && message?.id === lastSentMessageId\n ),\n enabledMessageActions: enabledMessageActions,\n mode: mode,\n isHighlighted: message?.id === highlightedMessageId,\n customActions: customMessageActions\n }\n \"\n ></ng-container>\n</ng-template>\n\n<ng-template #dateSeparator let-date=\"date\" let-parsedDate=\"parsedDate\">\n <ng-container *ngIf=\"displayDateSeparator\">\n <ng-container\n *ngTemplateOutlet=\"\n customDateSeparatorTemplate || defaultDateSeparator;\n context: {\n date: date,\n parsedDate: parsedDate\n }\n \"\n ></ng-container>\n </ng-container>\n\n <ng-template\n #defaultDateSeparator\n let-date=\"date\"\n let-parsedDate=\"parsedDate\"\n >\n <div data-testid=\"date-separator\" class=\"str-chat__date-separator\">\n <hr\n *ngIf=\"\n dateSeparatorTextPos === 'right' || dateSeparatorTextPos === 'center'\n \"\n class=\"str-chat__date-separator-line\"\n />\n <div class=\"str-chat__date-separator-date\">\n {{ parsedDate }}\n </div>\n <hr\n *ngIf=\"\n dateSeparatorTextPos === 'left' || dateSeparatorTextPos === 'center'\n \"\n class=\"str-chat__date-separator-line\"\n />\n </div>\n </ng-template>\n</ng-template>\n\n<ng-template #defaultNewMessagesIndicator let-unreadCount=\"unreadCount\">\n <div class=\"str-chat__unread-messages-separator\">\n <ng-container\n *ngIf=\"\n unreadCount > 0 && !hideUnreadCountForNotificationAndIndicator;\n else noUnreadCount\n \"\n >\n {{\n (unreadCount === 1\n ? \"streamChat.\\{\\{count\\}\\} unread message\"\n : \"streamChat.\\{\\{count\\}\\} unread messages\"\n ) | translate: { count: unreadCount }\n }}\n </ng-container>\n <ng-template #noUnreadCount>\n {{ \"streamChat.Unread messages\" | translate }}\n </ng-template>\n </div>\n</ng-template>\n", components: [{ type: IconPlaceholderComponent, selector: "stream-icon-placeholder", inputs: ["icon", "size"] }, { type: LoadingIndicatorComponent, selector: "stream-loading-indicator", inputs: ["size", "color"] }, { type: IconComponent, selector: "stream-icon", inputs: ["icon", "size"] }, { type: MessageComponent, selector: "stream-message", inputs: ["message", "enabledMessageActions", "isLastSentMessage", "mode", "isHighlighted", "customActions"] }], directives: [{ type: i8.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i8.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i8.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], pipes: { "translate": i9.TranslatePipe, "async": i8.AsyncPipe }, changeDetection: i0.ChangeDetectionStrategy.OnPush });
7042
7131
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: MessageListComponent, decorators: [{
7043
7132
  type: Component,
7044
7133
  args: [{
@@ -7069,6 +7158,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImpor
7069
7158
  type: Input
7070
7159
  }], displayLoadingIndicator: [{
7071
7160
  type: Input
7161
+ }], limitNumberOfMessagesInList: [{
7162
+ type: Input
7072
7163
  }], scrollContainer: [{
7073
7164
  type: ViewChild,
7074
7165
  args: ['scrollContainer']