stream-chat-angular 2.21.0 → 3.0.0-beta.11

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 (127) hide show
  1. package/README.md +44 -12
  2. package/assets/version.d.ts +1 -1
  3. package/bundles/stream-chat-angular.umd.js +796 -566
  4. package/bundles/stream-chat-angular.umd.js.map +1 -1
  5. package/esm2015/assets/version.js +2 -2
  6. package/esm2015/lib/attachment-list/attachment-list.component.js +27 -15
  7. package/esm2015/lib/attachment-preview-list/attachment-preview-list.component.js +28 -22
  8. package/esm2015/lib/attachment.service.js +11 -5
  9. package/esm2015/lib/avatar-placeholder/avatar-placeholder.component.js +41 -0
  10. package/esm2015/lib/channel-header/channel-header.component.js +26 -12
  11. package/esm2015/lib/channel-list/channel-list.component.js +23 -13
  12. package/esm2015/lib/channel-preview/channel-preview.component.js +3 -3
  13. package/esm2015/lib/channel.service.js +40 -64
  14. package/esm2015/lib/chat-client.service.js +5 -4
  15. package/esm2015/lib/custom-templates.service.js +139 -0
  16. package/esm2015/lib/icon-placeholder/icon-placeholder.component.js +34 -0
  17. package/esm2015/lib/loading-indicator-placeholder/loading-indicator-placeholder.component.js +42 -0
  18. package/esm2015/lib/message/message.component.js +74 -29
  19. package/esm2015/lib/message-actions-box/message-actions-box.component.js +114 -99
  20. package/esm2015/lib/message-input/autocomplete-textarea/autocomplete-textarea.component.js +13 -13
  21. package/esm2015/lib/message-input/message-input-config.service.js +1 -1
  22. package/esm2015/lib/message-input/message-input.component.js +56 -45
  23. package/esm2015/lib/message-input/textarea.directive.js +2 -18
  24. package/esm2015/lib/message-input/textarea.interface.js +1 -1
  25. package/esm2015/lib/message-list/message-list.component.js +32 -93
  26. package/esm2015/lib/message-preview.js +4 -17
  27. package/esm2015/lib/message-reactions/message-reactions.component.js +3 -3
  28. package/esm2015/lib/modal/modal.component.js +9 -6
  29. package/esm2015/lib/notification/notification.component.js +5 -2
  30. package/esm2015/lib/notification-list/notification-list.component.js +12 -10
  31. package/esm2015/lib/read-by.js +1 -1
  32. package/esm2015/lib/stream-avatar.module.js +5 -4
  33. package/esm2015/lib/stream-chat.module.js +13 -3
  34. package/esm2015/lib/thread/thread.component.js +19 -11
  35. package/esm2015/lib/types.js +1 -1
  36. package/esm2015/public-api.js +5 -1
  37. package/fesm2015/stream-chat-angular.js +735 -478
  38. package/fesm2015/stream-chat-angular.js.map +1 -1
  39. package/lib/attachment-list/attachment-list.component.d.ts +12 -8
  40. package/lib/attachment-preview-list/attachment-preview-list.component.d.ts +17 -7
  41. package/lib/attachment.service.d.ts +1 -1
  42. package/lib/avatar-placeholder/avatar-placeholder.component.d.ts +25 -0
  43. package/lib/channel-header/channel-header.component.d.ts +15 -12
  44. package/lib/channel-list/channel-list.component.d.ts +14 -11
  45. package/lib/channel-preview/channel-preview.component.d.ts +3 -2
  46. package/lib/channel.service.d.ts +33 -38
  47. package/lib/chat-client.service.d.ts +12 -11
  48. package/lib/custom-templates.service.d.ts +132 -0
  49. package/lib/icon-placeholder/icon-placeholder.component.d.ts +22 -0
  50. package/lib/loading-indicator-placeholder/loading-indicator-placeholder.component.d.ts +21 -0
  51. package/lib/message/message.component.d.ts +42 -30
  52. package/lib/message-actions-box/message-actions-box.component.d.ts +22 -26
  53. package/lib/message-input/autocomplete-textarea/autocomplete-textarea.component.d.ts +7 -11
  54. package/lib/message-input/message-input-config.service.d.ts +0 -19
  55. package/lib/message-input/message-input.component.d.ts +40 -26
  56. package/lib/message-input/textarea.directive.d.ts +3 -6
  57. package/lib/message-input/textarea.interface.d.ts +1 -4
  58. package/lib/message-list/group-styles.d.ts +1 -1
  59. package/lib/message-list/message-list.component.d.ts +10 -34
  60. package/lib/message-preview.d.ts +2 -1
  61. package/lib/message-reactions/message-reactions.component.d.ts +4 -5
  62. package/lib/modal/modal.component.d.ts +7 -3
  63. package/lib/notification/notification.component.d.ts +6 -1
  64. package/lib/notification-list/notification-list.component.d.ts +4 -2
  65. package/lib/read-by.d.ts +2 -1
  66. package/lib/stream-avatar.module.d.ts +4 -3
  67. package/lib/stream-chat.module.d.ts +6 -4
  68. package/lib/thread/thread.component.d.ts +6 -3
  69. package/lib/types.d.ts +115 -9
  70. package/package.json +2 -3
  71. package/public-api.d.ts +4 -0
  72. package/src/assets/styles/assets/EmojiOneColor.woff2 +0 -0
  73. package/src/assets/styles/assets/NotoColorEmoji-flags.woff2 +0 -0
  74. package/src/assets/styles/assets/Poweredby_100px-White_VertText.png +0 -0
  75. package/src/assets/styles/assets/str-chat__reaction-list-sprite@1x.png +0 -0
  76. package/src/assets/styles/assets/str-chat__reaction-list-sprite@2x.png +0 -0
  77. package/src/assets/styles/assets/str-chat__reaction-list-sprite@3x.png +0 -0
  78. package/src/assets/styles/css/index.css +1 -0
  79. package/src/assets/styles/css/index.css.map +1 -0
  80. package/src/assets/styles/scss/ActionsBox.scss +56 -0
  81. package/src/assets/styles/scss/Attachment.scss +227 -0
  82. package/src/assets/styles/scss/AttachmentActions.scss +44 -0
  83. package/src/assets/styles/scss/Audio.scss +112 -0
  84. package/src/assets/styles/scss/Avatar.scss +79 -0
  85. package/src/assets/styles/scss/Card.scss +100 -0
  86. package/src/assets/styles/scss/ChannelHeader.scss +284 -0
  87. package/src/assets/styles/scss/ChannelList.scss +117 -0
  88. package/src/assets/styles/scss/ChannelListMessenger.scss +9 -0
  89. package/src/assets/styles/scss/ChannelPreview.scss +108 -0
  90. package/src/assets/styles/scss/ChannelSearch.scss +111 -0
  91. package/src/assets/styles/scss/ChatDown.scss +15 -0
  92. package/src/assets/styles/scss/DateSeparator.scss +51 -0
  93. package/src/assets/styles/scss/EditMessageForm.scss +112 -0
  94. package/src/assets/styles/scss/EventComponent.scss +48 -0
  95. package/src/assets/styles/scss/Gallery.scss +135 -0
  96. package/src/assets/styles/scss/InfiniteScrollPaginator.scss +6 -0
  97. package/src/assets/styles/scss/LoadMoreButton.scss +44 -0
  98. package/src/assets/styles/scss/LoadingChannels.scss +70 -0
  99. package/src/assets/styles/scss/LoadingIndicator.scss +38 -0
  100. package/src/assets/styles/scss/Message.scss +1261 -0
  101. package/src/assets/styles/scss/MessageActions.scss +112 -0
  102. package/src/assets/styles/scss/MessageCommerce.scss +564 -0
  103. package/src/assets/styles/scss/MessageInput.scss +385 -0
  104. package/src/assets/styles/scss/MessageInputFlat.scss +305 -0
  105. package/src/assets/styles/scss/MessageList.scss +203 -0
  106. package/src/assets/styles/scss/MessageLivestream.scss +325 -0
  107. package/src/assets/styles/scss/MessageNotification.scss +49 -0
  108. package/src/assets/styles/scss/MessageRepliesCountButton.scss +33 -0
  109. package/src/assets/styles/scss/MessageTeam.scss +617 -0
  110. package/src/assets/styles/scss/Modal.scss +77 -0
  111. package/src/assets/styles/scss/ReactionList.scss +183 -0
  112. package/src/assets/styles/scss/ReactionSelector.scss +212 -0
  113. package/src/assets/styles/scss/SendButton.scss +14 -0
  114. package/src/assets/styles/scss/SimpleReactionsList.scss +76 -0
  115. package/src/assets/styles/scss/SmallMessageInput.scss +172 -0
  116. package/src/assets/styles/scss/Thread.scss +306 -0
  117. package/src/assets/styles/scss/Tooltip.scss +38 -0
  118. package/src/assets/styles/scss/TypingIndicator.scss +75 -0
  119. package/src/assets/styles/scss/VirtualMessage.scss +291 -0
  120. package/src/assets/styles/scss/_base.scss +206 -0
  121. package/src/assets/styles/scss/_variables.scss +158 -0
  122. package/src/assets/styles/scss/index.scss +50 -0
  123. package/src/assets/styles/scss/vendor/emoji-mart.scss +495 -0
  124. package/src/assets/styles/scss/vendor/mml-react.scss +1749 -0
  125. package/src/assets/styles/scss/vendor/react-file-utils.scss +378 -0
  126. package/src/assets/styles/scss/vendor/react-image-gallery.scss +224 -0
  127. package/src/assets/version.ts +1 -1
@@ -1,23 +1,23 @@
1
1
  import { __awaiter } from 'tslib';
2
2
  import * as i0 from '@angular/core';
3
- import { Injectable, Component, Input, InjectionToken, EventEmitter, Directive, Output, ViewChild, Inject, HostBinding, NgModule } from '@angular/core';
3
+ import { Injectable, Component, Input, EventEmitter, Output, ViewChild, InjectionToken, Directive, Inject, HostBinding, NgModule } from '@angular/core';
4
4
  import { BehaviorSubject, ReplaySubject, combineLatest, Subject, timer, of } from 'rxjs';
5
5
  import { StreamChat } from 'stream-chat';
6
6
  import { map, shareReplay, filter, first, take, tap, catchError, startWith, distinctUntilChanged, debounceTime } from 'rxjs/operators';
7
7
  import { v4 } from 'uuid';
8
8
  import * as i2 from '@ngx-translate/core';
9
9
  import { TranslateModule } from '@ngx-translate/core';
10
- import * as i6 from '@angular/common';
10
+ import * as i3 from '@angular/common';
11
11
  import { CommonModule } from '@angular/common';
12
12
  import prettybytes from 'pretty-bytes';
13
13
  import Dayjs from 'dayjs';
14
14
  import calendar from 'dayjs/plugin/calendar';
15
15
  import emojiRegex from 'emoji-regex';
16
16
  import transliterate from '@stream-io/transliterate';
17
- import * as i6$1 from 'angular-mentions';
17
+ import * as i7 from 'angular-mentions';
18
18
  import { MentionModule } from 'angular-mentions';
19
19
 
20
- const version = '2.21.0';
20
+ const version = '3.0.0-beta.11';
21
21
 
22
22
  /**
23
23
  * The `NotificationService` can be used to add or remove notifications. By default the [`NotificationList`](../components/NotificationListComponent.mdx) component displays the currently active notifications.
@@ -106,7 +106,7 @@ class ChatClientService {
106
106
  this.connectionStateSubject = new ReplaySubject(1);
107
107
  this.appSettingsSubject = new BehaviorSubject(undefined);
108
108
  this.pendingInvitesSubject = new BehaviorSubject([]);
109
- this.notification$ = this.notificationSubject.asObservable();
109
+ this.events$ = this.notificationSubject.asObservable();
110
110
  this.connectionState$ = this.connectionStateSubject.asObservable();
111
111
  this.appSettings$ = this.appSettingsSubject.asObservable();
112
112
  this.pendingInvites$ = this.pendingInvitesSubject.asObservable();
@@ -127,7 +127,8 @@ class ChatClientService {
127
127
  yield this.chatClient.connectUser(user, userTokenOrProvider);
128
128
  this.chatClient.setUserAgent(`stream-chat-angular-${version}-${this.chatClient.getUserAgent()}`);
129
129
  }));
130
- const channels = yield this.chatClient.queryChannels({ invite: 'pending' }, {}, { user_id: (_a = this.chatClient.user) === null || _a === void 0 ? void 0 : _a.id });
130
+ const channels = yield this.chatClient.queryChannels({ invite: 'pending' }, // TODO: find out why we need this typecast
131
+ {}, { user_id: (_a = this.chatClient.user) === null || _a === void 0 ? void 0 : _a.id });
131
132
  this.pendingInvitesSubject.next(channels);
132
133
  this.appSettingsSubject.next(undefined);
133
134
  this.chatClient.on((e) => {
@@ -201,7 +202,7 @@ class ChatClientService {
201
202
  { name: { $autocomplete: searchTerm } },
202
203
  ],
203
204
  id: { $ne: this.chatClient.userID },
204
- });
205
+ }); // TODO: find out why we need this typecast
205
206
  return result.users;
206
207
  });
207
208
  }
@@ -232,23 +233,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImpor
232
233
  }]
233
234
  }], ctorParameters: function () { return [{ type: i0.NgZone }, { type: NotificationService }]; } });
234
235
 
235
- const createMessagePreview = (user, text, attachments = [], mentionedUsers = [], parentId = undefined, quotedMessageId = undefined) => {
236
+ const createMessagePreview = (user, text, attachments = [], mentionedUsers = [], parentId = undefined, quotedMessageId = undefined, customData) => {
236
237
  const clientSideId = `${user.id}-${v4()}`;
237
- return {
238
- __html: text,
239
- created_at: new Date(),
240
- html: text,
241
- id: clientSideId,
242
- reactions: [],
243
- status: 'sending',
244
- text,
245
- type: 'regular',
246
- user,
247
- attachments,
248
- mentioned_users: mentionedUsers,
249
- parent_id: parentId,
250
- quoted_message_id: quotedMessageId,
251
- };
238
+ return Object.assign({ __html: text, created_at: new Date(), html: text, id: clientSideId, reactions: [], status: 'sending', text, type: 'regular', user,
239
+ attachments, mentioned_users: mentionedUsers, parent_id: parentId, quoted_message_id: quotedMessageId }, customData);
252
240
  };
253
241
 
254
242
  const getReadBy = (message, channel) => {
@@ -265,7 +253,7 @@ const getReadBy = (message, channel) => {
265
253
  };
266
254
 
267
255
  /**
268
- * The `ChannelService` provides data and interaction for the channel list and message list. TEST
256
+ * The `ChannelService` provides data and interaction for the channel list and message list.
269
257
  */
270
258
  class ChannelService {
271
259
  constructor(chatClientService, ngZone) {
@@ -358,21 +346,6 @@ class ChannelService {
358
346
  this.activeThreadMessagesSubject.next([]);
359
347
  this.messageToQuoteSubject.next(undefined);
360
348
  }
361
- /**
362
- * Deselects the currently active (if any) channel
363
- */
364
- deselectActiveChannel() {
365
- const activeChannel = this.activeChannelSubject.getValue();
366
- if (!activeChannel) {
367
- return;
368
- }
369
- this.activeChannelMessagesSubject.next([]);
370
- this.activeChannelSubject.next(undefined);
371
- this.activeParentMessageIdSubject.next(undefined);
372
- this.activeThreadMessagesSubject.next([]);
373
- this.latestMessageDateByUserByChannelsSubject.next({});
374
- this.selectMessageToQuote(undefined);
375
- }
376
349
  /**
377
350
  * Sets the given `message` as an active parent message. If `undefined` is provided, it will deleselect the current parent message.
378
351
  * @param message
@@ -443,10 +416,8 @@ class ChannelService {
443
416
  * @param filters
444
417
  * @param sort
445
418
  * @param options
446
- * @param shouldSetActiveChannel Decides if the first channel in the result should be made as an active channel, or no channel should be marked as active
447
- * @returns the list of channels found by the query
448
419
  */
449
- init(filters, sort, options, shouldSetActiveChannel = true) {
420
+ init(filters, sort, options) {
450
421
  return __awaiter(this, void 0, void 0, function* () {
451
422
  this.filters = filters;
452
423
  this.options = options || {
@@ -458,17 +429,21 @@ class ChannelService {
458
429
  message_limit: this.messagePageSize,
459
430
  };
460
431
  this.sort = sort || { last_message_at: -1, updated_at: -1 };
461
- const result = yield this.queryChannels(shouldSetActiveChannel);
462
- this.chatClientService.notification$.subscribe((notification) => void this.handleNotification(notification));
463
- return result;
432
+ yield this.queryChannels();
433
+ this.chatClientService.events$.subscribe((notification) => void this.handleNotification(notification));
464
434
  });
465
435
  }
466
436
  /**
467
437
  * Resets the `activeChannel$`, `channels$` and `activeChannelMessages$` Observables. Useful when disconnecting a chat user, use in combination with [`disconnectUser`](./ChatClientService.mdx/#disconnectuser).
468
438
  */
469
439
  reset() {
470
- this.deselectActiveChannel();
440
+ this.activeChannelMessagesSubject.next([]);
441
+ this.activeChannelSubject.next(undefined);
442
+ this.activeParentMessageIdSubject.next(undefined);
443
+ this.activeThreadMessagesSubject.next([]);
471
444
  this.channelsSubject.next(undefined);
445
+ this.latestMessageDateByUserByChannelsSubject.next({});
446
+ this.selectMessageToQuote(undefined);
472
447
  }
473
448
  /**
474
449
  * Loads the next page of channels. The page size can be set in the [query option](https://getstream.io/chat/docs/javascript/query_channels/?language=javascript#query-options) object.
@@ -476,20 +451,19 @@ class ChannelService {
476
451
  loadMoreChannels() {
477
452
  return __awaiter(this, void 0, void 0, function* () {
478
453
  this.options.offset = this.channels.length;
479
- yield this.queryChannels(false);
454
+ yield this.queryChannels();
480
455
  });
481
456
  }
482
457
  /**
483
458
  * Adds a reaction to a message.
484
459
  * @param messageId The id of the message to add the reaction to
485
460
  * @param reactionType The type of the reaction
461
+ * @param customData
486
462
  */
487
- addReaction(messageId, reactionType) {
463
+ addReaction(messageId, reactionType, customData) {
488
464
  var _a;
489
465
  return __awaiter(this, void 0, void 0, function* () {
490
- yield ((_a = this.activeChannelSubject.getValue()) === null || _a === void 0 ? void 0 : _a.sendReaction(messageId, {
491
- type: reactionType,
492
- }));
466
+ yield ((_a = this.activeChannelSubject.getValue()) === null || _a === void 0 ? void 0 : _a.sendReaction(messageId, Object.assign({ type: reactionType }, customData)));
493
467
  });
494
468
  }
495
469
  /**
@@ -511,14 +485,15 @@ class ChannelService {
511
485
  * @param mentionedUsers Mentioned users
512
486
  * @param parentId Id of the parent message (if sending a thread reply)
513
487
  * @param quotedMessageId Id of the message to quote (if sending a quote reply)
488
+ * @param customData
514
489
  */
515
- sendMessage(text, attachments = [], mentionedUsers = [], parentId = undefined, quotedMessageId = undefined) {
490
+ sendMessage(text, attachments = [], mentionedUsers = [], parentId = undefined, quotedMessageId = undefined, customData = undefined) {
516
491
  return __awaiter(this, void 0, void 0, function* () {
517
- const preview = createMessagePreview(this.chatClientService.chatClient.user, text, attachments, mentionedUsers, parentId, quotedMessageId);
492
+ const preview = createMessagePreview(this.chatClientService.chatClient.user, text, attachments, mentionedUsers, parentId, quotedMessageId, customData);
518
493
  const channel = this.activeChannelSubject.getValue();
519
494
  preview.readBy = [];
520
495
  channel.state.addMessageSorted(preview, true);
521
- yield this.sendMessageRequest(preview);
496
+ yield this.sendMessageRequest(preview, customData);
522
497
  });
523
498
  }
524
499
  /**
@@ -613,7 +588,7 @@ class ChannelService {
613
588
  const result = yield activeChannel.queryMembers({
614
589
  name: { $autocomplete: searchTerm },
615
590
  id: { $ne: this.chatClientService.chatClient.userID },
616
- });
591
+ }); // TODO: find out why we need typecast here
617
592
  return Object.values(result.members);
618
593
  }
619
594
  });
@@ -658,7 +633,7 @@ class ChannelService {
658
633
  selectMessageToQuote(message) {
659
634
  this.messageToQuoteSubject.next(message);
660
635
  }
661
- sendMessageRequest(preview) {
636
+ sendMessageRequest(preview, customData) {
662
637
  var _a;
663
638
  return __awaiter(this, void 0, void 0, function* () {
664
639
  const channel = this.activeChannelSubject.getValue();
@@ -669,14 +644,7 @@ class ChannelService {
669
644
  ])
670
645
  : this.activeChannelMessagesSubject.next([...channel.state.messages]);
671
646
  try {
672
- const response = yield channel.sendMessage({
673
- text: preview.text,
674
- attachments: preview.attachments,
675
- mentioned_users: (_a = preview.mentioned_users) === null || _a === void 0 ? void 0 : _a.map((u) => u.id),
676
- id: preview.id,
677
- parent_id: preview.parent_id,
678
- quoted_message_id: preview.quoted_message_id,
679
- });
647
+ const response = yield channel.sendMessage(Object.assign({ id: preview.id, text: preview.text, attachments: preview.attachments, mentioned_users: (_a = preview.mentioned_users) === null || _a === void 0 ? void 0 : _a.map((u) => u.id), parent_id: preview.parent_id, quoted_message_id: preview.quoted_message_id }, customData)); // TODO: find out why we need typecast here
680
648
  if (response === null || response === void 0 ? void 0 : response.message) {
681
649
  channel.state.addMessageSorted(Object.assign(Object.assign({}, response.message), { status: 'received' }), true);
682
650
  isThreadReply
@@ -700,15 +668,15 @@ class ChannelService {
700
668
  }
701
669
  });
702
670
  }
703
- handleNotification(notification) {
704
- switch (notification.eventType) {
671
+ handleNotification(clientEvent) {
672
+ switch (clientEvent.eventType) {
705
673
  case 'notification.message_new': {
706
674
  this.ngZone.run(() => {
707
675
  if (this.customNewMessageNotificationHandler) {
708
- this.customNewMessageNotificationHandler(notification, this.channelListSetter);
676
+ this.customNewMessageNotificationHandler(clientEvent, this.channelListSetter);
709
677
  }
710
678
  else {
711
- this.handleNewMessageNotification(notification);
679
+ this.handleNewMessageNotification(clientEvent);
712
680
  }
713
681
  });
714
682
  break;
@@ -716,10 +684,10 @@ class ChannelService {
716
684
  case 'notification.added_to_channel': {
717
685
  this.ngZone.run(() => {
718
686
  if (this.customAddedToChannelNotificationHandler) {
719
- this.customAddedToChannelNotificationHandler(notification, this.channelListSetter);
687
+ this.customAddedToChannelNotificationHandler(clientEvent, this.channelListSetter);
720
688
  }
721
689
  else {
722
- this.handleAddedToChannelNotification(notification);
690
+ this.handleAddedToChannelNotification(clientEvent);
723
691
  }
724
692
  });
725
693
  break;
@@ -727,27 +695,27 @@ class ChannelService {
727
695
  case 'notification.removed_from_channel': {
728
696
  this.ngZone.run(() => {
729
697
  if (this.customRemovedFromChannelNotificationHandler) {
730
- this.customRemovedFromChannelNotificationHandler(notification, this.channelListSetter);
698
+ this.customRemovedFromChannelNotificationHandler(clientEvent, this.channelListSetter);
731
699
  }
732
700
  else {
733
- this.handleRemovedFromChannelNotification(notification);
701
+ this.handleRemovedFromChannelNotification(clientEvent);
734
702
  }
735
703
  });
736
704
  }
737
705
  }
738
706
  }
739
- handleRemovedFromChannelNotification(notification) {
740
- const channelIdToBeRemoved = notification.event.channel.cid;
707
+ handleRemovedFromChannelNotification(clientEvent) {
708
+ const channelIdToBeRemoved = clientEvent.event.channel.cid;
741
709
  this.removeChannelsFromChannelList([channelIdToBeRemoved]);
742
710
  }
743
- handleNewMessageNotification(notification) {
744
- if (notification.event.channel) {
745
- this.addChannelsFromNotification([notification.event.channel]);
711
+ handleNewMessageNotification(clientEvent) {
712
+ if (clientEvent.event.channel) {
713
+ this.addChannelsFromNotification([clientEvent.event.channel]);
746
714
  }
747
715
  }
748
- handleAddedToChannelNotification(notification) {
749
- if (notification.event.channel) {
750
- this.addChannelsFromNotification([notification.event.channel]);
716
+ handleAddedToChannelNotification(clientEvent) {
717
+ if (clientEvent.event.channel) {
718
+ this.addChannelsFromNotification([clientEvent.event.channel]);
751
719
  }
752
720
  }
753
721
  addChannelsFromNotification(channelResponses) {
@@ -897,24 +865,20 @@ class ChannelService {
897
865
  this.activeChannelSubscriptions.forEach((s) => s.unsubscribe());
898
866
  this.activeChannelSubscriptions = [];
899
867
  }
900
- queryChannels(shouldSetActiveChannel) {
868
+ queryChannels() {
901
869
  return __awaiter(this, void 0, void 0, function* () {
902
870
  try {
903
871
  const channels = yield this.chatClientService.chatClient.queryChannels(this.filters, this.sort, this.options);
904
872
  channels.forEach((c) => this.watchForChannelEvents(c));
905
873
  const prevChannels = this.channelsSubject.getValue() || [];
906
874
  this.channelsSubject.next([...prevChannels, ...channels]);
907
- if (channels.length > 0 &&
908
- !this.activeChannelSubject.getValue() &&
909
- shouldSetActiveChannel) {
875
+ if (channels.length > 0 && !this.activeChannelSubject.getValue()) {
910
876
  this.setAsActiveChannel(channels[0]);
911
877
  }
912
878
  this.hasMoreChannelsSubject.next(channels.length >= this.options.limit);
913
- return channels;
914
879
  }
915
880
  catch (error) {
916
881
  this.channelsSubject.error(error);
917
- throw error;
918
882
  }
919
883
  });
920
884
  }
@@ -1332,19 +1296,25 @@ class AttachmentService {
1332
1296
  deleteAttachment(upload) {
1333
1297
  return __awaiter(this, void 0, void 0, function* () {
1334
1298
  const attachmentUploads = this.attachmentUploadsSubject.getValue();
1299
+ let result;
1335
1300
  if (upload.state === 'success') {
1336
1301
  try {
1337
1302
  yield this.channelService.deleteAttachment(upload);
1338
- attachmentUploads.splice(attachmentUploads.indexOf(upload), 1);
1303
+ result = [...attachmentUploads];
1304
+ const index = attachmentUploads.indexOf(upload);
1305
+ result.splice(index, 1);
1339
1306
  }
1340
1307
  catch (error) {
1308
+ result = attachmentUploads;
1341
1309
  this.notificationService.addTemporaryNotification('streamChat.Error deleting attachment');
1342
1310
  }
1343
1311
  }
1344
1312
  else {
1345
- attachmentUploads.splice(attachmentUploads.indexOf(upload), 1);
1313
+ result = [...attachmentUploads];
1314
+ const index = attachmentUploads.indexOf(upload);
1315
+ result.splice(index, 1);
1346
1316
  }
1347
- this.attachmentUploadsSubject.next([...attachmentUploads]);
1317
+ this.attachmentUploadsSubject.next([...result]);
1348
1318
  });
1349
1319
  }
1350
1320
  /**
@@ -1426,9 +1396,9 @@ class AttachmentService {
1426
1396
  }
1427
1397
  uploadAttachments(uploads) {
1428
1398
  return __awaiter(this, void 0, void 0, function* () {
1429
- const attachmentUploads = this.attachmentUploadsSubject.getValue();
1430
1399
  this.attachmentUploadInProgressCounterSubject.next(this.attachmentUploadInProgressCounterSubject.getValue() + 1);
1431
1400
  const result = yield this.channelService.uploadAttachments(uploads);
1401
+ const attachmentUploads = this.attachmentUploadsSubject.getValue();
1432
1402
  result.forEach((r) => {
1433
1403
  const upload = attachmentUploads.find((upload) => upload.file === r.file);
1434
1404
  if (!upload) {
@@ -1592,7 +1562,7 @@ class AvatarComponent {
1592
1562
  }
1593
1563
  }
1594
1564
  AvatarComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: AvatarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1595
- AvatarComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: AvatarComponent, selector: "stream-avatar", inputs: { name: "name", imageUrl: "imageUrl", size: "size" }, ngImport: i0, template: "<div\n class=\"str-chat__avatar str-chat__avatar--circle\"\n title=\"{{ name }}\"\n [style]=\"{\n flexBasis: size + 'px',\n fontSize: size / 2 + 'px',\n height: size + 'px',\n lineHeight: size + 'px',\n width: size + 'px'\n }\"\n>\n <img\n *ngIf=\"imageUrl && !isError; else fallback\"\n class=\"str-chat__avatar-image str-chat__avatar-image{{\n isLoaded ? ' str-chat__avatar-image--loaded' : ''\n }}\"\n src=\"{{ imageUrl }}\"\n alt=\"{{ initials }}\"\n data-testid=\"avatar-img\"\n (load)=\"isLoaded = true\"\n (error)=\"isError = true\"\n [style]=\"{\n flexBasis: size + 'px',\n height: size + 'px',\n objectFit: 'cover',\n width: size + 'px'\n }\"\n />\n <ng-template #fallback>\n <div data-testid=\"fallback-img\" class=\"str-chat__avatar-fallback\">\n {{ initials }}\n </div>\n </ng-template>\n</div>\n", styles: [""], directives: [{ type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
1565
+ AvatarComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: AvatarComponent, selector: "stream-avatar", inputs: { name: "name", imageUrl: "imageUrl", size: "size" }, ngImport: i0, template: "<div\n class=\"str-chat__avatar str-chat__avatar--circle\"\n title=\"{{ name }}\"\n [style]=\"{\n flexBasis: size + 'px',\n fontSize: size / 2 + 'px',\n height: size + 'px',\n lineHeight: size + 'px',\n width: size + 'px'\n }\"\n>\n <img\n *ngIf=\"imageUrl && !isError; else fallback\"\n class=\"str-chat__avatar-image str-chat__avatar-image{{\n isLoaded ? ' str-chat__avatar-image--loaded' : ''\n }}\"\n src=\"{{ imageUrl }}\"\n alt=\"{{ initials }}\"\n data-testid=\"avatar-img\"\n (load)=\"isLoaded = true\"\n (error)=\"isError = true\"\n [style]=\"{\n flexBasis: size + 'px',\n height: size + 'px',\n objectFit: 'cover',\n width: size + 'px'\n }\"\n />\n <ng-template #fallback>\n <div data-testid=\"fallback-img\" class=\"str-chat__avatar-fallback\">\n {{ initials }}\n </div>\n </ng-template>\n</div>\n", styles: [""], directives: [{ type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
1596
1566
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: AvatarComponent, decorators: [{
1597
1567
  type: Component,
1598
1568
  args: [{
@@ -1608,6 +1578,178 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImpor
1608
1578
  type: Input
1609
1579
  }] } });
1610
1580
 
1581
+ /**
1582
+ * A central location for registering your custom templates to override parts of the chat application.
1583
+ *
1584
+ * For code examples to the different customizations see our [customizations example application](https://github.com/GetStream/stream-chat-angular/tree/master/projects/customizations-example), specifically the [AppComponent](https://github.com/GetStream/stream-chat-angular/tree/master/projects/customizations-example/src/app) (see [README](https://github.com/GetStream/stream-chat-angular/blob/master/README.md#customization-examples) for instructions on how to start the application).
1585
+ */
1586
+ class CustomTemplatesService {
1587
+ constructor() {
1588
+ /**
1589
+ * The autocomplete list item template for mentioning users (used in the [`AutocompleteTextareaComponent`](../components/AutocompleteTextareaComponent.mdx))
1590
+ */
1591
+ this.mentionAutocompleteItemTemplate$ = new BehaviorSubject(undefined);
1592
+ /**
1593
+ * The autocomplete list item template for commands (used in the [`AutocompleteTextareaComponent`](../components/AutocompleteTextareaComponent.mdx))
1594
+ *
1595
+ * For code examples to the different customizations see our [customizations example application](https://github.com/GetStream/stream-chat-angular/tree/master/projects/customizations-example), specifically the [AppComponent](https://github.com/GetStream/stream-chat-angular/tree/master/projects/customizations-example/src/app) (see [README](https://github.com/GetStream/stream-chat-angular/blob/master/README.md#customization-examples) for instructions on how to start the application).
1596
+ */
1597
+ this.commandAutocompleteItemTemplate$ = new BehaviorSubject(undefined);
1598
+ /**
1599
+ * Template used to display an item in the [channel list](../components/ChannelListComponent.mdx) (instead of the default [channal list item](../components/ChannelPreviewComponent.mdx))
1600
+ *
1601
+ * For code examples to the different customizations see our [customizations example application](https://github.com/GetStream/stream-chat-angular/tree/master/projects/customizations-example), specifically the [AppComponent](https://github.com/GetStream/stream-chat-angular/tree/master/projects/customizations-example/src/app) (see [README](https://github.com/GetStream/stream-chat-angular/blob/master/README.md#customization-examples) for instructions on how to start the application).
1602
+ */
1603
+ this.channelPreviewTemplate$ = new BehaviorSubject(undefined);
1604
+ /**
1605
+ * The message input template used when editing a message (instead of the [default message input](../components/MessageInputComponent.mdx))
1606
+ *
1607
+ * For code examples to the different customizations see our [customizations example application](https://github.com/GetStream/stream-chat-angular/tree/master/projects/customizations-example), specifically the [AppComponent](https://github.com/GetStream/stream-chat-angular/tree/master/projects/customizations-example/src/app) (see [README](https://github.com/GetStream/stream-chat-angular/blob/master/README.md#customization-examples) for instructions on how to start the application).
1608
+ */
1609
+ this.messageInputTemplate$ = new BehaviorSubject(undefined);
1610
+ /**
1611
+ * The template used for displaying a [mention inside a message](../code-examples/mention-actions.mdx)
1612
+ *
1613
+ * For code examples to the different customizations see our [customizations example application](https://github.com/GetStream/stream-chat-angular/tree/master/projects/customizations-example), specifically the [AppComponent](https://github.com/GetStream/stream-chat-angular/tree/master/projects/customizations-example/src/app) (see [README](https://github.com/GetStream/stream-chat-angular/blob/master/README.md#customization-examples) for instructions on how to start the application).
1614
+ */
1615
+ this.mentionTemplate$ = new BehaviorSubject(undefined);
1616
+ /**
1617
+ * The template for [emoji picker](../code-examples/emoji-picker.mdx)
1618
+ *
1619
+ * For code examples to the different customizations see our [customizations example application](https://github.com/GetStream/stream-chat-angular/tree/master/projects/customizations-example), specifically the [AppComponent](https://github.com/GetStream/stream-chat-angular/tree/master/projects/customizations-example/src/app) (see [README](https://github.com/GetStream/stream-chat-angular/blob/master/README.md#customization-examples) for instructions on how to start the application).
1620
+ */
1621
+ this.emojiPickerTemplate$ = new BehaviorSubject(undefined);
1622
+ /**
1623
+ * The typing indicator template used in the [message list](../components/MessageListComponent.mdx)
1624
+ *
1625
+ * For code examples to the different customizations see our [customizations example application](https://github.com/GetStream/stream-chat-angular/tree/master/projects/customizations-example), specifically the [AppComponent](https://github.com/GetStream/stream-chat-angular/tree/master/projects/customizations-example/src/app) (see [README](https://github.com/GetStream/stream-chat-angular/blob/master/README.md#customization-examples) for instructions on how to start the application).
1626
+ */
1627
+ this.typingIndicatorTemplate$ = new BehaviorSubject(undefined);
1628
+ /**
1629
+ * The template used to display a message in the [message list](../components/MessageListComponent.mdx) (instead of the [default message component](../components/MessageComponent.mdx))
1630
+ *
1631
+ * For code examples to the different customizations see our [customizations example application](https://github.com/GetStream/stream-chat-angular/tree/master/projects/customizations-example), specifically the [AppComponent](https://github.com/GetStream/stream-chat-angular/tree/master/projects/customizations-example/src/app) (see [README](https://github.com/GetStream/stream-chat-angular/blob/master/README.md#customization-examples) for instructions on how to start the application).
1632
+ */
1633
+ this.messageTemplate$ = new BehaviorSubject(undefined);
1634
+ /**
1635
+ * The template for channel actions displayed in the [channel header](../components/ChannelHeaderComponent.mdx) (by default no channel action is displayed)
1636
+ *
1637
+ * For code examples to the different customizations see our [customizations example application](https://github.com/GetStream/stream-chat-angular/tree/master/projects/customizations-example), specifically the [AppComponent](https://github.com/GetStream/stream-chat-angular/tree/master/projects/customizations-example/src/app) (see [README](https://github.com/GetStream/stream-chat-angular/blob/master/README.md#customization-examples) for instructions on how to start the application).
1638
+ */
1639
+ this.channelActionsTemplate$ = new BehaviorSubject(undefined);
1640
+ /**
1641
+ * The template used to display attachments of a [message](../components/MessageComponent.mdx) (instead of the [default attachment list](../components/AttachmentListComponent.mdx))
1642
+ *
1643
+ * For code examples to the different customizations see our [customizations example application](https://github.com/GetStream/stream-chat-angular/tree/master/projects/customizations-example), specifically the [AppComponent](https://github.com/GetStream/stream-chat-angular/tree/master/projects/customizations-example/src/app) (see [README](https://github.com/GetStream/stream-chat-angular/blob/master/README.md#customization-examples) for instructions on how to start the application).
1644
+ */
1645
+ this.attachmentListTemplate$ = new BehaviorSubject(undefined);
1646
+ /**
1647
+ * The template used to display attachments in the [message input](../components/MessageInputComponent.mdx) component (instead of the [default attachment preview](../components/AttachmentPreviewListComponent.mdx))
1648
+ *
1649
+ * For code examples to the different customizations see our [customizations example application](https://github.com/GetStream/stream-chat-angular/tree/master/projects/customizations-example), specifically the [AppComponent](https://github.com/GetStream/stream-chat-angular/tree/master/projects/customizations-example/src/app) (see [README](https://github.com/GetStream/stream-chat-angular/blob/master/README.md#customization-examples) for instructions on how to start the application).
1650
+ */
1651
+ this.attachmentPreviewListTemplate$ = new BehaviorSubject(undefined);
1652
+ /**
1653
+ * The template used to display avatars for channels and users (instead of the [default avatar](../components/AvatarComponent.mdx))
1654
+ *
1655
+ * For code examples to the different customizations see our [customizations example application](https://github.com/GetStream/stream-chat-angular/tree/master/projects/customizations-example), specifically the [AppComponent](https://github.com/GetStream/stream-chat-angular/tree/master/projects/customizations-example/src/app) (see [README](https://github.com/GetStream/stream-chat-angular/blob/master/README.md#customization-examples) for instructions on how to start the application).
1656
+ */
1657
+ this.avatarTemplate$ = new BehaviorSubject(undefined);
1658
+ /**
1659
+ * Template for displaying icons (instead of the [default icon component](../components/IconComponent.mdx))
1660
+ *
1661
+ * For code examples to the different customizations see our [customizations example application](https://github.com/GetStream/stream-chat-angular/tree/master/projects/customizations-example), specifically the [AppComponent](https://github.com/GetStream/stream-chat-angular/tree/master/projects/customizations-example/src/app) (see [README](https://github.com/GetStream/stream-chat-angular/blob/master/README.md#customization-examples) for instructions on how to start the application).
1662
+ */
1663
+ this.iconTemplate$ = new BehaviorSubject(undefined);
1664
+ /**
1665
+ * Template for displaying the loading indicator (instead of the [default loading indicator](../components/LoadingIndicatorComponent.mdx))
1666
+ *
1667
+ * For code examples to the different customizations see our [customizations example application](https://github.com/GetStream/stream-chat-angular/tree/master/projects/customizations-example), specifically the [AppComponent](https://github.com/GetStream/stream-chat-angular/tree/master/projects/customizations-example/src/app) (see [README](https://github.com/GetStream/stream-chat-angular/blob/master/README.md#customization-examples) for instructions on how to start the application).
1668
+ */
1669
+ this.loadingIndicatorTemplate$ = new BehaviorSubject(undefined);
1670
+ /**
1671
+ * Template for displaying the message actions box (instead of the [default message actions box](../components/MessageActionsBoxComponent.mdx))
1672
+ *
1673
+ * For code examples to the different customizations see our [customizations example application](https://github.com/GetStream/stream-chat-angular/tree/master/projects/customizations-example), specifically the [AppComponent](https://github.com/GetStream/stream-chat-angular/tree/master/projects/customizations-example/src/app) (see [README](https://github.com/GetStream/stream-chat-angular/blob/master/README.md#customization-examples) for instructions on how to start the application).
1674
+ */
1675
+ this.messageActionsBoxTemplate$ = new BehaviorSubject(undefined);
1676
+ /**
1677
+ * The template used for displaying an item in the [message actions box](../components/MessageActionsBoxComponent.mdx)
1678
+ *
1679
+ * For code examples to the different customizations see our [customizations example application](https://github.com/GetStream/stream-chat-angular/tree/master/projects/customizations-example), specifically the [AppComponent](https://github.com/GetStream/stream-chat-angular/tree/master/projects/customizations-example/src/app) (see [README](https://github.com/GetStream/stream-chat-angular/blob/master/README.md#customization-examples) for instructions on how to start the application).
1680
+ */
1681
+ this.messageActionsBoxItemTemplate$ = new BehaviorSubject(undefined);
1682
+ /**
1683
+ * The template used to display the reactions of a [message](../components/MessageComponent.mdx), and the selector to add a reaction to a message (instead of the [default message reactions component](../components/MessageReactionsComponent.mdx))
1684
+ *
1685
+ * For code examples to the different customizations see our [customizations example application](https://github.com/GetStream/stream-chat-angular/tree/master/projects/customizations-example), specifically the [AppComponent](https://github.com/GetStream/stream-chat-angular/tree/master/projects/customizations-example/src/app) (see [README](https://github.com/GetStream/stream-chat-angular/blob/master/README.md#customization-examples) for instructions on how to start the application).
1686
+ */
1687
+ this.messageReactionsTemplate$ = new BehaviorSubject(undefined);
1688
+ /**
1689
+ * The template used to display a modal window (instead of the [default modal](../components/ModalComponent.mdx))
1690
+ *
1691
+ * For code examples to the different customizations see our [customizations example application](https://github.com/GetStream/stream-chat-angular/tree/master/projects/customizations-example), specifically the [AppComponent](https://github.com/GetStream/stream-chat-angular/tree/master/projects/customizations-example/src/app) (see [README](https://github.com/GetStream/stream-chat-angular/blob/master/README.md#customization-examples) for instructions on how to start the application).
1692
+ */
1693
+ this.modalTemplate$ = new BehaviorSubject(undefined);
1694
+ /**
1695
+ * The template used to override the [default notification component](../components/NotificationComponent.mdx)
1696
+ *
1697
+ * For code examples to the different customizations see our [customizations example application](https://github.com/GetStream/stream-chat-angular/tree/master/projects/customizations-example), specifically the [AppComponent](https://github.com/GetStream/stream-chat-angular/tree/master/projects/customizations-example/src/app) (see [README](https://github.com/GetStream/stream-chat-angular/blob/master/README.md#customization-examples) for instructions on how to start the application).
1698
+ */
1699
+ this.notificationTemplate$ = new BehaviorSubject(undefined);
1700
+ /**
1701
+ * The template used for header of a [thread](../components/ThreadComponent.mdx)
1702
+ *
1703
+ * For code examples to the different customizations see our [customizations example application](https://github.com/GetStream/stream-chat-angular/tree/master/projects/customizations-example), specifically the [AppComponent](https://github.com/GetStream/stream-chat-angular/tree/master/projects/customizations-example/src/app) (see [README](https://github.com/GetStream/stream-chat-angular/blob/master/README.md#customization-examples) for instructions on how to start the application).
1704
+ */
1705
+ this.threadHeaderTemplate$ = new BehaviorSubject(undefined);
1706
+ }
1707
+ }
1708
+ CustomTemplatesService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: CustomTemplatesService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1709
+ CustomTemplatesService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: CustomTemplatesService, providedIn: 'root' });
1710
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: CustomTemplatesService, decorators: [{
1711
+ type: Injectable,
1712
+ args: [{
1713
+ providedIn: 'root',
1714
+ }]
1715
+ }], ctorParameters: function () { return []; } });
1716
+
1717
+ /**
1718
+ * The `AvatarPlaceholder` component displays the [default avatar](./AvatarComponent.mdx) unless a [custom template](../services/CustomTemplatesService.mdx) is provided. This componet is used by the SDK internally, you likely won't need to use it.
1719
+ */
1720
+ class AvatarPlaceholderComponent {
1721
+ constructor(customTemplatesService) {
1722
+ this.customTemplatesService = customTemplatesService;
1723
+ /**
1724
+ * The size in pixels of the avatar image.
1725
+ */
1726
+ this.size = 32;
1727
+ }
1728
+ getAvatarContext() {
1729
+ return {
1730
+ name: this.name,
1731
+ imageUrl: this.imageUrl,
1732
+ size: this.size,
1733
+ };
1734
+ }
1735
+ }
1736
+ AvatarPlaceholderComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: AvatarPlaceholderComponent, deps: [{ token: CustomTemplatesService }], target: i0.ɵɵFactoryTarget.Component });
1737
+ AvatarPlaceholderComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: AvatarPlaceholderComponent, selector: "stream-avatar-placeholder", inputs: { name: "name", imageUrl: "imageUrl", size: "size" }, ngImport: i0, template: "<ng-template\n #defaultAvatar\n let-name=\"name\"\n let-imageUrl=\"imageUrl\"\n let-size=\"size\"\n>\n <stream-avatar\n [name]=\"name\"\n [imageUrl]=\"imageUrl\"\n [size]=\"size\"\n ></stream-avatar>\n</ng-template>\n<ng-container\n *ngTemplateOutlet=\"\n (customTemplatesService.avatarTemplate$ | async) || defaultAvatar;\n context: getAvatarContext()\n \"\n></ng-container>\n", components: [{ type: AvatarComponent, selector: "stream-avatar", inputs: ["name", "imageUrl", "size"] }], directives: [{ type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }], pipes: { "async": i3.AsyncPipe } });
1738
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: AvatarPlaceholderComponent, decorators: [{
1739
+ type: Component,
1740
+ args: [{
1741
+ selector: 'stream-avatar-placeholder',
1742
+ templateUrl: './avatar-placeholder.component.html',
1743
+ styles: [],
1744
+ }]
1745
+ }], ctorParameters: function () { return [{ type: CustomTemplatesService }]; }, propDecorators: { name: [{
1746
+ type: Input
1747
+ }], imageUrl: [{
1748
+ type: Input
1749
+ }], size: [{
1750
+ type: Input
1751
+ }] } });
1752
+
1611
1753
  /**
1612
1754
  * The `Icon` component can be used to display different icons (i. e. message delivered icon).
1613
1755
  */
@@ -1615,7 +1757,7 @@ class IconComponent {
1615
1757
  constructor() { }
1616
1758
  }
1617
1759
  IconComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: IconComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1618
- IconComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: IconComponent, selector: "stream-icon", inputs: { icon: "icon", size: "size" }, ngImport: i0, template: "<svg\n data-testid=\"action-icon\"\n *ngIf=\"icon === 'action-icon'\"\n height=\"4\"\n viewBox=\"0 0 11 4\"\n width=\"11\"\n xmlns=\"http://www.w3.org/2000/svg\"\n>\n <path\n d=\"M1.5 3a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zm4 0a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zm4 0a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3z\"\n fillRule=\"nonzero\"\n />\n</svg>\n<svg\n *ngIf=\"icon === 'delivered-icon'\"\n height=\"16\"\n width=\"16\"\n xmlns=\"http://www.w3.org/2000/svg\"\n data-testid=\"delivered-icon\"\n>\n <path\n d=\"M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0zm3.72 6.633a.955.955 0 1 0-1.352-1.352L6.986 8.663 5.633 7.31A.956.956 0 1 0 4.28 8.663l2.029 2.028a.956.956 0 0 0 1.353 0l4.058-4.058z\"\n fill=\"#006CFF\"\n fillRule=\"evenodd\"\n />\n</svg>\n<svg\n *ngIf=\"icon === 'reaction-icon'\"\n height=\"12\"\n viewBox=\"0 0 12 12\"\n width=\"12\"\n xmlns=\"http://www.w3.org/2000/svg\"\n data-testid=\"reaction-icon\"\n>\n <g clipRule=\"evenodd\" fillRule=\"evenodd\">\n <path\n d=\"M6 1.2C3.3 1.2 1.2 3.3 1.2 6c0 2.7 2.1 4.8 4.8 4.8 2.7 0 4.8-2.1 4.8-4.8 0-2.7-2.1-4.8-4.8-4.8zM0 6c0-3.3 2.7-6 6-6s6 2.7 6 6-2.7 6-6 6-6-2.7-6-6z\"\n ></path>\n <path\n d=\"M5.4 4.5c0 .5-.4.9-.9.9s-.9-.4-.9-.9.4-.9.9-.9.9.4.9.9zM8.4 4.5c0 .5-.4.9-.9.9s-.9-.4-.9-.9.4-.9.9-.9.9.4.9.9zM3.3 6.7c.3-.2.6-.1.8.1.3.4.8.9 1.5 1 .6.2 1.4.1 2.4-1 .2-.2.6-.3.8 0 .2.2.3.6 0 .8-1.1 1.3-2.4 1.7-3.5 1.5-1-.2-1.8-.9-2.2-1.5-.2-.3-.1-.7.2-.9z\"\n ></path>\n </g>\n</svg>\n<svg\n data-testid=\"connection-error\"\n *ngIf=\"icon === 'connection-error'\"\n width=\"78px\"\n height=\"78px\"\n viewBox=\"0 0 78 78\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n>\n <!-- Generator: Sketch 52.6 (67491) - http://www.bohemiancoding.com/sketch -->\n <title>Combined Shape</title>\n <desc>Created with Sketch.</desc>\n <g\n id=\"Interactions\"\n stroke=\"none\"\n stroke-width=\"1\"\n fill=\"none\"\n fill-rule=\"evenodd\"\n >\n <g\n id=\"Connection-Error-_-Connectivity\"\n transform=\"translate(-270.000000, -30.000000)\"\n fill=\"#CF1F25\"\n >\n <g\n id=\"109-network-connection\"\n transform=\"translate(270.000000, 30.000000)\"\n >\n <path\n d=\"M66.4609744,11.414231 C81.6225232,26.5757798 81.6225232,51.157545 66.4609744,66.3188467 C51.2994256,81.4803954 26.7176604,81.4803954 11.5563587,66.3188467 C-3.60519004,51.1572979 -3.60519004,26.5755327 11.5563587,11.414231 C26.7179075,-3.74731776 51.2996727,-3.74731776 66.4609744,11.414231 Z M54.7853215,45.8823776 L54.7853215,40.5882574 C54.7853215,39.613638 53.9952341,38.8235506 53.0206147,38.8235506 L44.9576695,38.8235506 L41.428256,42.3529641 L51.255555,42.3529641 L51.255555,45.8823776 L54.7853215,45.8823776 Z M40.6659027,43.1153174 L37.8988425,45.8823776 L40.6659027,45.8823776 L40.6659027,43.1153174 Z M51.1764962,56.4702653 L58.2353232,56.4702653 C59.2099355,56.4702653 60.00003,55.6801708 60.00003,54.7055585 L60.00003,51.176145 C60.00003,50.2015327 59.2099355,49.4114382 58.2353232,49.4114382 L51.1764962,49.4114382 C50.2018839,49.4114382 49.4117894,50.2015327 49.4117894,51.176145 L49.4117894,54.7055585 C49.4117894,55.6801708 50.2018839,56.4702653 51.1764962,56.4702653 Z M35.2941353,56.4702653 L42.3529624,56.4702653 C43.3275746,56.4702653 44.1176691,55.6801708 44.1176691,54.7055585 L44.1176691,51.176145 C44.1176691,50.2015327 43.3275746,49.4114382 42.3529624,49.4114382 L35.2941353,49.4114382 C34.319523,49.4114382 33.5294285,50.2015327 33.5294285,51.176145 L33.5294285,54.7055585 C33.5294285,55.6801708 34.319523,56.4702653 35.2941353,56.4702653 Z M56.6964989,19.0874231 C56.007381,18.3985134 54.8903216,18.3985134 54.2012036,19.087423 L45.882376,27.4062507 L45.882376,19.4117761 C45.882376,18.4371568 45.0922885,17.6470693 44.1176692,17.6470693 L33.5294286,17.6470693 C32.5548092,17.6470694 31.7647218,18.4371568 31.7647218,19.4117761 L31.7647218,30.0000167 C31.7647219,30.9746363 32.5548092,31.7647237 33.5294285,31.7647237 L41.5239031,31.7647237 L34.4650761,38.8235508 L24.7058947,38.8235508 C23.7312753,38.8235508 22.9411879,39.6136382 22.9411879,40.5882575 L22.9411879,45.8823778 L26.4706014,45.8823778 L26.4706014,42.3529643 L30.9356624,42.3529643 L23.8768354,49.4117914 L19.4117743,49.4117914 C18.4371549,49.4117914 17.6470675,50.2018788 17.6470675,51.1764981 L17.6470675,54.7059117 C17.6504049,54.9674302 17.7129076,55.2248042 17.8298886,55.4587302 L16.4456526,56.8429662 C15.7446193,57.5200453 15.7252005,58.6372282 16.4022825,59.3382615 C17.0793616,60.0392948 18.1965445,60.0587136 18.8975778,59.3816316 C18.9122847,59.3674273 18.9267436,59.3529684 18.940948,59.3382615 L56.6964963,21.5830662 C57.3856425,20.8939094 57.3856425,19.7765747 56.6964963,19.0874179 Z\"\n id=\"Combined-Shape\"\n ></path>\n </g>\n </g>\n </g>\n</svg>\n<svg\n *ngIf=\"icon === 'send'\"\n data-testid=\"send\"\n height=\"17\"\n viewBox=\"0 0 18 17\"\n width=\"18\"\n xmlns=\"http://www.w3.org/2000/svg\"\n>\n <title translate>streamChat.Send</title>\n <path\n d=\"M0 17.015l17.333-8.508L0 0v6.617l12.417 1.89L0 10.397z\"\n fill=\"#006cff\"\n fillRule=\"evenodd\"\n />\n</svg>\n<svg\n *ngIf=\"icon === 'file-upload'\"\n data-testid=\"file-upload\"\n height=\"14\"\n width=\"14\"\n xmlns=\"http://www.w3.org/2000/svg\"\n>\n <title translate>streamChat.Attach files</title>\n <path\n d=\"M1.667.333h10.666c.737 0 1.334.597 1.334 1.334v10.666c0 .737-.597 1.334-1.334 1.334H1.667a1.333 1.333 0 0 1-1.334-1.334V1.667C.333.93.93.333 1.667.333zm2 1.334a1.667 1.667 0 1 0 0 3.333 1.667 1.667 0 0 0 0-3.333zm-2 9.333v1.333h10.666v-4l-2-2-4 4-2-2L1.667 11z\"\n fillRule=\"nonzero\"\n />\n</svg>\n<svg\n data-testid=\"retry\"\n *ngIf=\"icon === 'retry'\"\n width=\"22\"\n height=\"20\"\n viewBox=\"0 0 22 20\"\n xmlns=\"http://www.w3.org/2000/svg\"\n>\n <path\n d=\"M20 5.535V2a1 1 0 0 1 2 0v6a1 1 0 0 1-1 1h-6a1 1 0 0 1 0-2h3.638l-2.975-2.653a8 8 0 1 0 1.884 8.32 1 1 0 1 1 1.886.666A10 10 0 1 1 5.175 1.245c3.901-2.15 8.754-1.462 11.88 1.667L20 5.535z\"\n fill=\"#FFF\"\n fill-rule=\"nonzero\"\n />\n</svg>\n<svg\n *ngIf=\"icon === 'close'\"\n data-testid=\"close\"\n width=\"28\"\n height=\"28\"\n viewBox=\"0 0 28 28\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n>\n <defs>\n <path\n d=\"M465 5c5.53 0 10 4.47 10 10s-4.47 10-10 10-10-4.47-10-10 4.47-10 10-10zm3.59 5L465 13.59 461.41 10 460 11.41l3.59 3.59-3.59 3.59 1.41 1.41 3.59-3.59 3.59 3.59 1.41-1.41-3.59-3.59 3.59-3.59-1.41-1.41z\"\n id=\"b\"\n />\n <filter\n x=\"-30%\"\n y=\"-30%\"\n width=\"160%\"\n height=\"160%\"\n filterUnits=\"objectBoundingBox\"\n id=\"a\"\n >\n <feOffset in=\"SourceAlpha\" result=\"shadowOffsetOuter1\" />\n <feGaussianBlur\n stdDeviation=\"2\"\n in=\"shadowOffsetOuter1\"\n result=\"shadowBlurOuter1\"\n />\n <feColorMatrix\n values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0\"\n in=\"shadowBlurOuter1\"\n />\n </filter>\n </defs>\n <g transform=\"translate(-451 -1)\" fill-rule=\"nonzero\" fill=\"none\">\n <use fill=\"#000\" filter=\"url(#a)\" xlink:href=\"#b\" />\n <use fill=\"#FFF\" fill-rule=\"evenodd\" xlink:href=\"#b\" />\n </g>\n</svg>\n<svg\n *ngIf=\"icon === 'file'\"\n data-testid=\"file\"\n className=\"rfu-file-icon--small fa-file-fallback\"\n [attr.height]=\"size || 20\"\n [attr.width]=\"size || 20\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 384 512\"\n>\n <path\n d=\"M369.9 97.9L286 14C277 5 264.8-.1 252.1-.1H48C21.5 0 0 21.5 0 48v416c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48V131.9c0-12.7-5.1-25-14.1-34zM332.1 128H256V51.9l76.1 76.1zM48 464V48h160v104c0 13.3 10.7 24 24 24h104v288H48z\"\n fill=\"#414D54\"\n />\n</svg>\n<svg\n *ngIf=\"icon === 'reply'\"\n data-testid=\"reply\"\n height=\"15\"\n width=\"18\"\n xmlns=\"http://www.w3.org/2000/svg\"\n>\n <path\n d=\"M.56 10.946H.06l-.002-.498L.025.92a.5.5 0 1 1 1-.004l.032 9.029H9.06v-4l9 4.5-9 4.5v-4H.56z\"\n fillRule=\"nonzero\"\n />\n</svg>\n<svg\n height=\"10\"\n width=\"10\"\n xmlns=\"http://www.w3.org/2000/svg\"\n data-testid=\"close-no-outline\"\n *ngIf=\"icon === 'close-no-outline'\"\n>\n <path\n d=\"M9.916 1.027L8.973.084 5 4.058 1.027.084l-.943.943L4.058 5 .084 8.973l.943.943L5 5.942l3.973 3.974.943-.943L5.942 5z\"\n fillRule=\"evenodd\"\n />\n</svg>\n<svg\n height=\"10\"\n width=\"14\"\n xmlns=\"http://www.w3.org/2000/svg\"\n data-testid=\"reply-in-thread\"\n *ngIf=\"icon === 'reply-in-thread'\"\n>\n <path\n d=\"M8.516 3c4.78 0 4.972 6.5 4.972 6.5-1.6-2.906-2.847-3.184-4.972-3.184v2.872L3.772 4.994 8.516.5V3zM.484 5l4.5-4.237v1.78L2.416 5l2.568 2.125v1.828L.484 5z\"\n fillRule=\"evenodd\"\n />\n</svg>\n<svg\n *ngIf=\"icon === 'arrow-left'\"\n data-testid=\"arrow-left\"\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n>\n <path\n d=\"M15.7049 7.41L14.2949 6L8.29492 12L14.2949 18L15.7049 16.59L11.1249 12L15.7049 7.41Z\"\n fill=\"var(--black)\"\n />\n</svg>\n\n<svg\n *ngIf=\"icon === 'arrow-right'\"\n data-testid=\"arrow-right\"\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n>\n <path\n d=\"M9.70492 6L8.29492 7.41L12.8749 12L8.29492 16.59L9.70492 18L15.7049 12L9.70492 6Z\"\n fill=\"var(--black)\"\n />\n</svg>\n<svg\n *ngIf=\"icon === 'menu'\"\n data-testid=\"menu\"\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n>\n <path\n fill-rule=\"evenodd\"\n clip-rule=\"evenodd\"\n d=\"M3 8V6H21V8H3ZM3 13H21V11H3V13ZM3 18H21V16H3V18Z\"\n fill=\"black\"\n />\n</svg>\n", directives: [{ type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }] });
1760
+ IconComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: IconComponent, selector: "stream-icon", inputs: { icon: "icon", size: "size" }, ngImport: i0, template: "<svg\n data-testid=\"action-icon\"\n *ngIf=\"icon === 'action-icon'\"\n height=\"4\"\n viewBox=\"0 0 11 4\"\n width=\"11\"\n xmlns=\"http://www.w3.org/2000/svg\"\n>\n <path\n d=\"M1.5 3a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zm4 0a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zm4 0a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3z\"\n fillRule=\"nonzero\"\n />\n</svg>\n<svg\n *ngIf=\"icon === 'delivered-icon'\"\n height=\"16\"\n width=\"16\"\n xmlns=\"http://www.w3.org/2000/svg\"\n data-testid=\"delivered-icon\"\n>\n <path\n d=\"M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0zm3.72 6.633a.955.955 0 1 0-1.352-1.352L6.986 8.663 5.633 7.31A.956.956 0 1 0 4.28 8.663l2.029 2.028a.956.956 0 0 0 1.353 0l4.058-4.058z\"\n fill=\"#006CFF\"\n fillRule=\"evenodd\"\n />\n</svg>\n<svg\n *ngIf=\"icon === 'reaction-icon'\"\n height=\"12\"\n viewBox=\"0 0 12 12\"\n width=\"12\"\n xmlns=\"http://www.w3.org/2000/svg\"\n data-testid=\"reaction-icon\"\n>\n <g clipRule=\"evenodd\" fillRule=\"evenodd\">\n <path\n d=\"M6 1.2C3.3 1.2 1.2 3.3 1.2 6c0 2.7 2.1 4.8 4.8 4.8 2.7 0 4.8-2.1 4.8-4.8 0-2.7-2.1-4.8-4.8-4.8zM0 6c0-3.3 2.7-6 6-6s6 2.7 6 6-2.7 6-6 6-6-2.7-6-6z\"\n ></path>\n <path\n d=\"M5.4 4.5c0 .5-.4.9-.9.9s-.9-.4-.9-.9.4-.9.9-.9.9.4.9.9zM8.4 4.5c0 .5-.4.9-.9.9s-.9-.4-.9-.9.4-.9.9-.9.9.4.9.9zM3.3 6.7c.3-.2.6-.1.8.1.3.4.8.9 1.5 1 .6.2 1.4.1 2.4-1 .2-.2.6-.3.8 0 .2.2.3.6 0 .8-1.1 1.3-2.4 1.7-3.5 1.5-1-.2-1.8-.9-2.2-1.5-.2-.3-.1-.7.2-.9z\"\n ></path>\n </g>\n</svg>\n<svg\n data-testid=\"connection-error\"\n *ngIf=\"icon === 'connection-error'\"\n width=\"78px\"\n height=\"78px\"\n viewBox=\"0 0 78 78\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n>\n <!-- Generator: Sketch 52.6 (67491) - http://www.bohemiancoding.com/sketch -->\n <title>Combined Shape</title>\n <desc>Created with Sketch.</desc>\n <g\n id=\"Interactions\"\n stroke=\"none\"\n stroke-width=\"1\"\n fill=\"none\"\n fill-rule=\"evenodd\"\n >\n <g\n id=\"Connection-Error-_-Connectivity\"\n transform=\"translate(-270.000000, -30.000000)\"\n fill=\"#CF1F25\"\n >\n <g\n id=\"109-network-connection\"\n transform=\"translate(270.000000, 30.000000)\"\n >\n <path\n d=\"M66.4609744,11.414231 C81.6225232,26.5757798 81.6225232,51.157545 66.4609744,66.3188467 C51.2994256,81.4803954 26.7176604,81.4803954 11.5563587,66.3188467 C-3.60519004,51.1572979 -3.60519004,26.5755327 11.5563587,11.414231 C26.7179075,-3.74731776 51.2996727,-3.74731776 66.4609744,11.414231 Z M54.7853215,45.8823776 L54.7853215,40.5882574 C54.7853215,39.613638 53.9952341,38.8235506 53.0206147,38.8235506 L44.9576695,38.8235506 L41.428256,42.3529641 L51.255555,42.3529641 L51.255555,45.8823776 L54.7853215,45.8823776 Z M40.6659027,43.1153174 L37.8988425,45.8823776 L40.6659027,45.8823776 L40.6659027,43.1153174 Z M51.1764962,56.4702653 L58.2353232,56.4702653 C59.2099355,56.4702653 60.00003,55.6801708 60.00003,54.7055585 L60.00003,51.176145 C60.00003,50.2015327 59.2099355,49.4114382 58.2353232,49.4114382 L51.1764962,49.4114382 C50.2018839,49.4114382 49.4117894,50.2015327 49.4117894,51.176145 L49.4117894,54.7055585 C49.4117894,55.6801708 50.2018839,56.4702653 51.1764962,56.4702653 Z M35.2941353,56.4702653 L42.3529624,56.4702653 C43.3275746,56.4702653 44.1176691,55.6801708 44.1176691,54.7055585 L44.1176691,51.176145 C44.1176691,50.2015327 43.3275746,49.4114382 42.3529624,49.4114382 L35.2941353,49.4114382 C34.319523,49.4114382 33.5294285,50.2015327 33.5294285,51.176145 L33.5294285,54.7055585 C33.5294285,55.6801708 34.319523,56.4702653 35.2941353,56.4702653 Z M56.6964989,19.0874231 C56.007381,18.3985134 54.8903216,18.3985134 54.2012036,19.087423 L45.882376,27.4062507 L45.882376,19.4117761 C45.882376,18.4371568 45.0922885,17.6470693 44.1176692,17.6470693 L33.5294286,17.6470693 C32.5548092,17.6470694 31.7647218,18.4371568 31.7647218,19.4117761 L31.7647218,30.0000167 C31.7647219,30.9746363 32.5548092,31.7647237 33.5294285,31.7647237 L41.5239031,31.7647237 L34.4650761,38.8235508 L24.7058947,38.8235508 C23.7312753,38.8235508 22.9411879,39.6136382 22.9411879,40.5882575 L22.9411879,45.8823778 L26.4706014,45.8823778 L26.4706014,42.3529643 L30.9356624,42.3529643 L23.8768354,49.4117914 L19.4117743,49.4117914 C18.4371549,49.4117914 17.6470675,50.2018788 17.6470675,51.1764981 L17.6470675,54.7059117 C17.6504049,54.9674302 17.7129076,55.2248042 17.8298886,55.4587302 L16.4456526,56.8429662 C15.7446193,57.5200453 15.7252005,58.6372282 16.4022825,59.3382615 C17.0793616,60.0392948 18.1965445,60.0587136 18.8975778,59.3816316 C18.9122847,59.3674273 18.9267436,59.3529684 18.940948,59.3382615 L56.6964963,21.5830662 C57.3856425,20.8939094 57.3856425,19.7765747 56.6964963,19.0874179 Z\"\n id=\"Combined-Shape\"\n ></path>\n </g>\n </g>\n </g>\n</svg>\n<svg\n *ngIf=\"icon === 'send'\"\n data-testid=\"send\"\n height=\"17\"\n viewBox=\"0 0 18 17\"\n width=\"18\"\n xmlns=\"http://www.w3.org/2000/svg\"\n>\n <title translate>streamChat.Send</title>\n <path\n d=\"M0 17.015l17.333-8.508L0 0v6.617l12.417 1.89L0 10.397z\"\n fill=\"#006cff\"\n fillRule=\"evenodd\"\n />\n</svg>\n<svg\n *ngIf=\"icon === 'file-upload'\"\n data-testid=\"file-upload\"\n height=\"14\"\n width=\"14\"\n xmlns=\"http://www.w3.org/2000/svg\"\n>\n <title translate>streamChat.Attach files</title>\n <path\n d=\"M1.667.333h10.666c.737 0 1.334.597 1.334 1.334v10.666c0 .737-.597 1.334-1.334 1.334H1.667a1.333 1.333 0 0 1-1.334-1.334V1.667C.333.93.93.333 1.667.333zm2 1.334a1.667 1.667 0 1 0 0 3.333 1.667 1.667 0 0 0 0-3.333zm-2 9.333v1.333h10.666v-4l-2-2-4 4-2-2L1.667 11z\"\n fillRule=\"nonzero\"\n />\n</svg>\n<svg\n data-testid=\"retry\"\n *ngIf=\"icon === 'retry'\"\n width=\"22\"\n height=\"20\"\n viewBox=\"0 0 22 20\"\n xmlns=\"http://www.w3.org/2000/svg\"\n>\n <path\n d=\"M20 5.535V2a1 1 0 0 1 2 0v6a1 1 0 0 1-1 1h-6a1 1 0 0 1 0-2h3.638l-2.975-2.653a8 8 0 1 0 1.884 8.32 1 1 0 1 1 1.886.666A10 10 0 1 1 5.175 1.245c3.901-2.15 8.754-1.462 11.88 1.667L20 5.535z\"\n fill=\"#FFF\"\n fill-rule=\"nonzero\"\n />\n</svg>\n<svg\n *ngIf=\"icon === 'close'\"\n data-testid=\"close\"\n width=\"28\"\n height=\"28\"\n viewBox=\"0 0 28 28\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n>\n <defs>\n <path\n d=\"M465 5c5.53 0 10 4.47 10 10s-4.47 10-10 10-10-4.47-10-10 4.47-10 10-10zm3.59 5L465 13.59 461.41 10 460 11.41l3.59 3.59-3.59 3.59 1.41 1.41 3.59-3.59 3.59 3.59 1.41-1.41-3.59-3.59 3.59-3.59-1.41-1.41z\"\n id=\"b\"\n />\n <filter\n x=\"-30%\"\n y=\"-30%\"\n width=\"160%\"\n height=\"160%\"\n filterUnits=\"objectBoundingBox\"\n id=\"a\"\n >\n <feOffset in=\"SourceAlpha\" result=\"shadowOffsetOuter1\" />\n <feGaussianBlur\n stdDeviation=\"2\"\n in=\"shadowOffsetOuter1\"\n result=\"shadowBlurOuter1\"\n />\n <feColorMatrix\n values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0\"\n in=\"shadowBlurOuter1\"\n />\n </filter>\n </defs>\n <g transform=\"translate(-451 -1)\" fill-rule=\"nonzero\" fill=\"none\">\n <use fill=\"#000\" filter=\"url(#a)\" xlink:href=\"#b\" />\n <use fill=\"#FFF\" fill-rule=\"evenodd\" xlink:href=\"#b\" />\n </g>\n</svg>\n<svg\n *ngIf=\"icon === 'file'\"\n data-testid=\"file\"\n className=\"rfu-file-icon--small fa-file-fallback\"\n [attr.height]=\"size || 20\"\n [attr.width]=\"size || 20\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 384 512\"\n>\n <path\n d=\"M369.9 97.9L286 14C277 5 264.8-.1 252.1-.1H48C21.5 0 0 21.5 0 48v416c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48V131.9c0-12.7-5.1-25-14.1-34zM332.1 128H256V51.9l76.1 76.1zM48 464V48h160v104c0 13.3 10.7 24 24 24h104v288H48z\"\n fill=\"#414D54\"\n />\n</svg>\n<svg\n *ngIf=\"icon === 'reply'\"\n data-testid=\"reply\"\n height=\"15\"\n width=\"18\"\n xmlns=\"http://www.w3.org/2000/svg\"\n>\n <path\n d=\"M.56 10.946H.06l-.002-.498L.025.92a.5.5 0 1 1 1-.004l.032 9.029H9.06v-4l9 4.5-9 4.5v-4H.56z\"\n fillRule=\"nonzero\"\n />\n</svg>\n<svg\n height=\"10\"\n width=\"10\"\n xmlns=\"http://www.w3.org/2000/svg\"\n data-testid=\"close-no-outline\"\n *ngIf=\"icon === 'close-no-outline'\"\n>\n <path\n d=\"M9.916 1.027L8.973.084 5 4.058 1.027.084l-.943.943L4.058 5 .084 8.973l.943.943L5 5.942l3.973 3.974.943-.943L5.942 5z\"\n fillRule=\"evenodd\"\n />\n</svg>\n<svg\n height=\"10\"\n width=\"14\"\n xmlns=\"http://www.w3.org/2000/svg\"\n data-testid=\"reply-in-thread\"\n *ngIf=\"icon === 'reply-in-thread'\"\n>\n <path\n d=\"M8.516 3c4.78 0 4.972 6.5 4.972 6.5-1.6-2.906-2.847-3.184-4.972-3.184v2.872L3.772 4.994 8.516.5V3zM.484 5l4.5-4.237v1.78L2.416 5l2.568 2.125v1.828L.484 5z\"\n fillRule=\"evenodd\"\n />\n</svg>\n<svg\n *ngIf=\"icon === 'arrow-left'\"\n data-testid=\"arrow-left\"\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n>\n <path\n d=\"M15.7049 7.41L14.2949 6L8.29492 12L14.2949 18L15.7049 16.59L11.1249 12L15.7049 7.41Z\"\n fill=\"var(--black)\"\n />\n</svg>\n\n<svg\n *ngIf=\"icon === 'arrow-right'\"\n data-testid=\"arrow-right\"\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n>\n <path\n d=\"M9.70492 6L8.29492 7.41L12.8749 12L8.29492 16.59L9.70492 18L15.7049 12L9.70492 6Z\"\n fill=\"var(--black)\"\n />\n</svg>\n<svg\n *ngIf=\"icon === 'menu'\"\n data-testid=\"menu\"\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n>\n <path\n fill-rule=\"evenodd\"\n clip-rule=\"evenodd\"\n d=\"M3 8V6H21V8H3ZM3 13H21V11H3V13ZM3 18H21V16H3V18Z\"\n fill=\"black\"\n />\n</svg>\n", directives: [{ type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }] });
1619
1761
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: IconComponent, decorators: [{
1620
1762
  type: Component,
1621
1763
  args: [{
@@ -1629,6 +1771,35 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImpor
1629
1771
  type: Input
1630
1772
  }] } });
1631
1773
 
1774
+ /**
1775
+ * The `IconPlaceholder` component displays the [default icons](./IconComponent.mdx) unless a [custom template](../services/CustomTemplatesService.mdx) is provided. This componet is used by the SDK internally, you likely won't need to use it.
1776
+ */
1777
+ class IconPlaceholderComponent {
1778
+ constructor(customTemplatesService) {
1779
+ this.customTemplatesService = customTemplatesService;
1780
+ }
1781
+ getIconContext() {
1782
+ return {
1783
+ icon: this.icon,
1784
+ size: this.size,
1785
+ };
1786
+ }
1787
+ }
1788
+ IconPlaceholderComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: IconPlaceholderComponent, deps: [{ token: CustomTemplatesService }], target: i0.ɵɵFactoryTarget.Component });
1789
+ IconPlaceholderComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: IconPlaceholderComponent, selector: "stream-icon-placeholder", inputs: { icon: "icon", size: "size" }, ngImport: i0, template: "<ng-template #defaultIcon let-icon=\"icon\" let-size=\"size\">\n <stream-icon [icon]=\"icon\" [size]=\"size\"></stream-icon>\n</ng-template>\n<ng-container\n *ngTemplateOutlet=\"\n (customTemplatesService.iconTemplate$ | async) || defaultIcon;\n context: getIconContext()\n \"\n></ng-container>\n", components: [{ type: IconComponent, selector: "stream-icon", inputs: ["icon", "size"] }], directives: [{ type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }], pipes: { "async": i3.AsyncPipe } });
1790
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: IconPlaceholderComponent, decorators: [{
1791
+ type: Component,
1792
+ args: [{
1793
+ selector: 'stream-icon-placeholder',
1794
+ templateUrl: './icon-placeholder.component.html',
1795
+ styles: [],
1796
+ }]
1797
+ }], ctorParameters: function () { return [{ type: CustomTemplatesService }]; }, propDecorators: { icon: [{
1798
+ type: Input
1799
+ }], size: [{
1800
+ type: Input
1801
+ }] } });
1802
+
1632
1803
  /**
1633
1804
  * The `LoadingIndicator` component displays a spinner to indicate that an action is in progress.
1634
1805
  */
@@ -1645,7 +1816,7 @@ class LoadingIndicatorComponent {
1645
1816
  }
1646
1817
  }
1647
1818
  LoadingIndicatorComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: LoadingIndicatorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1648
- LoadingIndicatorComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: LoadingIndicatorComponent, selector: "stream-loading-indicator", inputs: { size: "size", color: "color" }, ngImport: i0, template: "<div class=\"str-chat__loading-indicator\">\n <svg\n [attr.height]=\"size\"\n viewBox=\"0 0 30 30\"\n [attr.width]=\"size\"\n data-testid=\"loading-indicator\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <defs>\n <linearGradient id=\"a\" x1=\"50%\" x2=\"50%\" y1=\"0%\" y2=\"100%\">\n <stop offset=\"0%\" stop-color=\"#FFF\" stop-opacity=\"0\" />\n <stop\n data-testid=\"stop-color\"\n offset=\"100%\"\n [attr.stop-color]=\"color\"\n stop-opacity=\"1\"\n [ngStyle]=\"{ stopColor: color }\"\n />\n </linearGradient>\n </defs>\n <path\n d=\"M2.518 23.321l1.664-1.11A12.988 12.988 0 0 0 15 28c7.18 0 13-5.82 13-13S22.18 2 15 2V0c8.284 0 15 6.716 15 15 0 8.284-6.716 15-15 15-5.206 0-9.792-2.652-12.482-6.679z\"\n fill=\"url(#a)\"\n fillRule=\"evenodd\"\n />\n </svg>\n</div>\n", directives: [{ type: i6.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
1819
+ LoadingIndicatorComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: LoadingIndicatorComponent, selector: "stream-loading-indicator", inputs: { size: "size", color: "color" }, ngImport: i0, template: "<div class=\"str-chat__loading-indicator\">\n <svg\n [attr.height]=\"size\"\n viewBox=\"0 0 30 30\"\n [attr.width]=\"size\"\n data-testid=\"loading-indicator\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <defs>\n <linearGradient id=\"a\" x1=\"50%\" x2=\"50%\" y1=\"0%\" y2=\"100%\">\n <stop offset=\"0%\" stop-color=\"#FFF\" stop-opacity=\"0\" />\n <stop\n data-testid=\"stop-color\"\n offset=\"100%\"\n [attr.stop-color]=\"color\"\n stop-opacity=\"1\"\n [ngStyle]=\"{ stopColor: color }\"\n />\n </linearGradient>\n </defs>\n <path\n d=\"M2.518 23.321l1.664-1.11A12.988 12.988 0 0 0 15 28c7.18 0 13-5.82 13-13S22.18 2 15 2V0c8.284 0 15 6.716 15 15 0 8.284-6.716 15-15 15-5.206 0-9.792-2.652-12.482-6.679z\"\n fill=\"url(#a)\"\n fillRule=\"evenodd\"\n />\n </svg>\n</div>\n", directives: [{ type: i3.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
1649
1820
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: LoadingIndicatorComponent, decorators: [{
1650
1821
  type: Component,
1651
1822
  args: [{
@@ -1659,6 +1830,113 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImpor
1659
1830
  type: Input
1660
1831
  }] } });
1661
1832
 
1833
+ /**
1834
+ * The `LoadingInficatorPlaceholder` component displays the [default loading indicator](./LoadingIndicatorComponent.mdx) unless a [custom template](../services/CustomTemplatesService.mdx) is provided. This componet is used by the SDK internally, you likely won't need to use it.
1835
+ */
1836
+ class LoadingIndicatorPlaceholderComponent {
1837
+ constructor(customTemplatesService) {
1838
+ this.customTemplatesService = customTemplatesService;
1839
+ /**
1840
+ * The size of the indicator (in pixels)
1841
+ */
1842
+ this.size = 15;
1843
+ /**
1844
+ * The color of the indicator
1845
+ */
1846
+ this.color = '#006CFF';
1847
+ }
1848
+ getLoadingIndicatorContext() {
1849
+ return {
1850
+ size: this.size,
1851
+ color: this.color,
1852
+ };
1853
+ }
1854
+ }
1855
+ LoadingIndicatorPlaceholderComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: LoadingIndicatorPlaceholderComponent, deps: [{ token: CustomTemplatesService }], target: i0.ɵɵFactoryTarget.Component });
1856
+ LoadingIndicatorPlaceholderComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: LoadingIndicatorPlaceholderComponent, selector: "stream-loading-indicator-placeholder", inputs: { size: "size", color: "color" }, ngImport: i0, template: "<ng-template #defaultLoadingIndicator let-size=\"size\" let-color=\"color\">\n <stream-loading-indicator\n [size]=\"size\"\n [color]=\"color\"\n ></stream-loading-indicator>\n</ng-template>\n<ng-container\n *ngTemplateOutlet=\"\n (customTemplatesService.loadingIndicatorTemplate$ | async) ||\n defaultLoadingIndicator;\n context: getLoadingIndicatorContext()\n \"\n></ng-container>\n", components: [{ type: LoadingIndicatorComponent, selector: "stream-loading-indicator", inputs: ["size", "color"] }], directives: [{ type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }], pipes: { "async": i3.AsyncPipe } });
1857
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: LoadingIndicatorPlaceholderComponent, decorators: [{
1858
+ type: Component,
1859
+ args: [{
1860
+ selector: 'stream-loading-indicator-placeholder',
1861
+ templateUrl: './loading-indicator-placeholder.component.html',
1862
+ styles: [],
1863
+ }]
1864
+ }], ctorParameters: function () { return [{ type: CustomTemplatesService }]; }, propDecorators: { size: [{
1865
+ type: Input
1866
+ }], color: [{
1867
+ type: Input
1868
+ }] } });
1869
+
1870
+ /**
1871
+ * The `Modal` component displays its content in an overlay. The modal can be closed with a close button, if the user clicks outside of the modal content, or if the escape button is pressed. The modal can also be closed from outside.
1872
+ */
1873
+ class ModalComponent {
1874
+ constructor() {
1875
+ /**
1876
+ * If `true` the modal will be displayed, if `false` the modal will be hidden
1877
+ */
1878
+ this.isOpen = false;
1879
+ /**
1880
+ * Emits `true` if the modal becomes visible, and `false` if the modal is closed.
1881
+ */
1882
+ this.isOpenChange = new EventEmitter();
1883
+ this.watchForEscPress = (event) => {
1884
+ if (event.key === 'Escape') {
1885
+ this.close();
1886
+ }
1887
+ };
1888
+ this.stopWatchForEscPress = () => {
1889
+ window.removeEventListener('keyup', this.watchForEscPress);
1890
+ };
1891
+ this.watchForOutsideClicks = (event) => {
1892
+ var _a;
1893
+ if (!((_a = this.innerContainer) === null || _a === void 0 ? void 0 : _a.nativeElement.contains(event.target))) {
1894
+ this.close();
1895
+ }
1896
+ };
1897
+ }
1898
+ ngOnChanges(changes) {
1899
+ if (changes.isOpen) {
1900
+ if (this.isOpen) {
1901
+ window.addEventListener('keyup', this.watchForEscPress);
1902
+ setTimeout(() => window.addEventListener('click', this.watchForOutsideClicks), 0);
1903
+ }
1904
+ else {
1905
+ this.stopWatchForOutsideClicks();
1906
+ this.stopWatchForEscPress();
1907
+ }
1908
+ }
1909
+ }
1910
+ close() {
1911
+ this.isOpen = false;
1912
+ this.isOpenChange.emit(false);
1913
+ this.stopWatchForOutsideClicks();
1914
+ this.stopWatchForEscPress();
1915
+ }
1916
+ stopWatchForOutsideClicks() {
1917
+ window.removeEventListener('click', this.watchForOutsideClicks);
1918
+ }
1919
+ }
1920
+ ModalComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: ModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1921
+ ModalComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: ModalComponent, selector: "stream-modal", inputs: { isOpen: "isOpen", content: "content" }, outputs: { isOpenChange: "isOpenChange" }, viewQueries: [{ propertyName: "innerContainer", first: true, predicate: ["modalInner"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\n data-testid=\"modal\"\n class=\"str-chat__modal str-chat__modal--{{ isOpen ? 'open' : 'close' }}\"\n>\n <div\n data-testid=\"close\"\n class=\"str-chat__modal__close-button\"\n (click)=\"close()\"\n (keyup.enter)=\"close()\"\n translate\n >\n streamChat.Close\n <stream-icon-placeholder icon=\"close\"></stream-icon-placeholder>\n </div>\n <div class=\"str-chat__modal__inner\" #modalInner>\n <ng-container *ngIf=\"content; else elseContent\">\n <ng-container *ngTemplateOutlet=\"content\"></ng-container>\n </ng-container>\n <ng-template #elseContent>\n <ng-content></ng-content>\n </ng-template>\n </div>\n</div>\n", components: [{ type: IconPlaceholderComponent, selector: "stream-icon-placeholder", inputs: ["icon", "size"] }], directives: [{ type: i2.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }] });
1922
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: ModalComponent, decorators: [{
1923
+ type: Component,
1924
+ args: [{
1925
+ selector: 'stream-modal',
1926
+ templateUrl: './modal.component.html',
1927
+ styles: [],
1928
+ }]
1929
+ }], ctorParameters: function () { return []; }, propDecorators: { isOpen: [{
1930
+ type: Input
1931
+ }], content: [{
1932
+ type: Input
1933
+ }], isOpenChange: [{
1934
+ type: Output
1935
+ }], innerContainer: [{
1936
+ type: ViewChild,
1937
+ args: ['modalInner']
1938
+ }] } });
1939
+
1662
1940
  const textareaInjectionToken = new InjectionToken('textareaInjectionToken');
1663
1941
 
1664
1942
  class TextareaDirective {
@@ -1685,10 +1963,6 @@ class TextareaDirective {
1685
1963
  this.subscriptions.push(this.componentRef.instance.userMentions.subscribe((value) => this.userMentions.next(value)));
1686
1964
  }
1687
1965
  this.componentRef.instance.areMentionsEnabled = this.areMentionsEnabled;
1688
- this.componentRef.instance.mentionAutocompleteItemTemplate =
1689
- this.mentionAutocompleteItemTemplate;
1690
- this.componentRef.instance.commandAutocompleteItemTemplate =
1691
- this.commandAutocompleteItemTemplate;
1692
1966
  this.componentRef.instance.mentionScope = this.mentionScope;
1693
1967
  this.componentRef.instance.value = this.value;
1694
1968
  }
@@ -1696,14 +1970,6 @@ class TextareaDirective {
1696
1970
  if (changes.areMentionsEnabled) {
1697
1971
  this.componentRef.instance.areMentionsEnabled = this.areMentionsEnabled;
1698
1972
  }
1699
- if (changes.mentionAutocompleteItemTemplate) {
1700
- this.componentRef.instance.mentionAutocompleteItemTemplate =
1701
- this.mentionAutocompleteItemTemplate;
1702
- }
1703
- if (changes.commandAutocompleteItemTemplate) {
1704
- this.componentRef.instance.commandAutocompleteItemTemplate =
1705
- this.commandAutocompleteItemTemplate;
1706
- }
1707
1973
  if (changes.mentionScope) {
1708
1974
  this.componentRef.instance.mentionScope = this.mentionScope;
1709
1975
  }
@@ -1719,7 +1985,7 @@ class TextareaDirective {
1719
1985
  }
1720
1986
  }
1721
1987
  TextareaDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: TextareaDirective, deps: [{ token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Directive });
1722
- TextareaDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "12.2.5", type: TextareaDirective, selector: "[streamTextarea]", inputs: { componentRef: "componentRef", areMentionsEnabled: "areMentionsEnabled", mentionAutocompleteItemTemplate: "mentionAutocompleteItemTemplate", mentionScope: "mentionScope", commandAutocompleteItemTemplate: "commandAutocompleteItemTemplate", value: "value" }, outputs: { valueChange: "valueChange", send: "send", userMentions: "userMentions" }, usesOnChanges: true, ngImport: i0 });
1988
+ TextareaDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "12.2.5", type: TextareaDirective, selector: "[streamTextarea]", inputs: { componentRef: "componentRef", areMentionsEnabled: "areMentionsEnabled", mentionScope: "mentionScope", value: "value" }, outputs: { valueChange: "valueChange", send: "send", userMentions: "userMentions" }, usesOnChanges: true, ngImport: i0 });
1723
1989
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: TextareaDirective, decorators: [{
1724
1990
  type: Directive,
1725
1991
  args: [{
@@ -1729,12 +1995,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImpor
1729
1995
  type: Input
1730
1996
  }], areMentionsEnabled: [{
1731
1997
  type: Input
1732
- }], mentionAutocompleteItemTemplate: [{
1733
- type: Input
1734
1998
  }], mentionScope: [{
1735
1999
  type: Input
1736
- }], commandAutocompleteItemTemplate: [{
1737
- type: Input
1738
2000
  }], value: [{
1739
2001
  type: Input
1740
2002
  }], valueChange: [{
@@ -1817,79 +2079,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImpor
1817
2079
  }]
1818
2080
  }], ctorParameters: function () { return []; } });
1819
2081
 
1820
- /**
1821
- * The `Modal` component displays its content in an overlay. The modal can be closed with a close button, if the user clicks outside of the modal content, or if the escape button is pressed. The modal can also be closed from outside.
1822
- */
1823
- class ModalComponent {
1824
- constructor() {
1825
- /**
1826
- * If `true` the modal will be displayed, if `false` the modal will be hidden
1827
- */
1828
- this.isOpen = false;
1829
- /**
1830
- * Emits `true` if the modal becomes visible, and `false` if the modal is closed.
1831
- */
1832
- this.isOpenChange = new EventEmitter();
1833
- this.watchForEscPress = (event) => {
1834
- if (event.key === 'Escape') {
1835
- this.close();
1836
- }
1837
- };
1838
- this.stopWatchForEscPress = () => {
1839
- window.removeEventListener('keyup', this.watchForEscPress);
1840
- };
1841
- this.watchForOutsideClicks = (event) => {
1842
- var _a;
1843
- if (!((_a = this.content) === null || _a === void 0 ? void 0 : _a.nativeElement.contains(event.target))) {
1844
- this.close();
1845
- }
1846
- };
1847
- }
1848
- ngOnChanges(changes) {
1849
- if (changes.isOpen) {
1850
- if (this.isOpen) {
1851
- window.addEventListener('keyup', this.watchForEscPress);
1852
- setTimeout(() => window.addEventListener('click', this.watchForOutsideClicks), 0);
1853
- }
1854
- else {
1855
- this.stopWatchForOutsideClicks();
1856
- this.stopWatchForEscPress();
1857
- }
1858
- }
1859
- }
1860
- close() {
1861
- this.isOpen = false;
1862
- this.isOpenChange.emit(false);
1863
- this.stopWatchForOutsideClicks();
1864
- this.stopWatchForEscPress();
1865
- }
1866
- stopWatchForOutsideClicks() {
1867
- window.removeEventListener('click', this.watchForOutsideClicks);
1868
- }
1869
- }
1870
- ModalComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: ModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1871
- ModalComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: ModalComponent, selector: "stream-modal", inputs: { isOpen: "isOpen" }, outputs: { isOpenChange: "isOpenChange" }, viewQueries: [{ propertyName: "content", first: true, predicate: ["content"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\n data-testid=\"modal\"\n class=\"str-chat__modal str-chat__modal--{{ isOpen ? 'open' : 'close' }}\"\n>\n <div\n data-testid=\"close\"\n class=\"str-chat__modal__close-button\"\n (click)=\"close()\"\n (keyup.enter)=\"close()\"\n translate\n >\n streamChat.Close\n <stream-icon icon=\"close\"></stream-icon>\n </div>\n <div class=\"str-chat__modal__inner\" #content>\n <ng-content></ng-content>\n </div>\n</div>\n", components: [{ type: IconComponent, selector: "stream-icon", inputs: ["icon", "size"] }], directives: [{ type: i2.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }] });
1872
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: ModalComponent, decorators: [{
1873
- type: Component,
1874
- args: [{
1875
- selector: 'stream-modal',
1876
- templateUrl: './modal.component.html',
1877
- styles: [],
1878
- }]
1879
- }], ctorParameters: function () { return []; }, propDecorators: { isOpen: [{
1880
- type: Input
1881
- }], isOpenChange: [{
1882
- type: Output
1883
- }], content: [{
1884
- type: ViewChild,
1885
- args: ['content']
1886
- }] } });
1887
-
1888
2082
  /**
1889
2083
  * The `AttachmentList` compontent displays the attachments of a message
1890
2084
  */
1891
2085
  class AttachmentListComponent {
1892
- constructor(imageLoadService, channelService) {
2086
+ constructor(customTemplatesService, imageLoadService, channelService) {
2087
+ this.customTemplatesService = customTemplatesService;
1893
2088
  this.imageLoadService = imageLoadService;
1894
2089
  this.channelService = channelService;
1895
2090
  /**
@@ -1935,6 +2130,13 @@ class AttachmentListComponent {
1935
2130
  getFileSize(attachment) {
1936
2131
  return prettybytes(Number(attachment.file_size));
1937
2132
  }
2133
+ getModalContext() {
2134
+ return {
2135
+ isOpen: this.imagesToView && this.imagesToView.length > 0,
2136
+ isOpenChangeHandler: (isOpen) => (isOpen ? null : this.closeImageModal()),
2137
+ content: this.modalContent,
2138
+ };
2139
+ }
1938
2140
  trimUrl(url) {
1939
2141
  if (url !== undefined && url !== null) {
1940
2142
  const [trimmedUrl] = url
@@ -1956,9 +2158,6 @@ class AttachmentListComponent {
1956
2158
  this.imagesToView = attachments;
1957
2159
  this.imagesToViewCurrentIndex = selectedIndex;
1958
2160
  }
1959
- closeImageModal() {
1960
- this.imagesToView = [];
1961
- }
1962
2161
  stepImages(dir) {
1963
2162
  this.imagesToViewCurrentIndex += dir * 1;
1964
2163
  }
@@ -1979,9 +2178,12 @@ class AttachmentListComponent {
1979
2178
  },
1980
2179
  ];
1981
2180
  }
2181
+ closeImageModal() {
2182
+ this.imagesToView = [];
2183
+ }
1982
2184
  }
1983
- AttachmentListComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: AttachmentListComponent, deps: [{ token: ImageLoadService }, { token: ChannelService }], target: i0.ɵɵFactoryTarget.Component });
1984
- AttachmentListComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: AttachmentListComponent, selector: "stream-attachment-list", inputs: { messageId: "messageId", attachments: "attachments" }, usesOnChanges: true, ngImport: i0, template: "<ng-container *ngFor=\"let attachment of orderedAttachments; trackBy: trackById\">\n <div\n data-testclass=\"attachment-container\"\n class=\"str-chat__message-attachment str-chat__message-attachment--{{\n attachment.type\n }}\"\n [class.str-chat__message-attachment--card]=\"isCard(attachment)\"\n [class.str-chat-angular__message-attachment-file-single]=\"\n isFile(attachment)\n \"\n >\n <img\n *ngIf=\"isImage(attachment)\"\n class=\"str-chat__message-attachment--img\"\n data-testclass=\"image\"\n [src]=\"attachment.img_url || attachment.thumb_url || attachment.image_url\"\n [alt]=\"attachment?.fallback\"\n (load)=\"imageLoaded()\"\n (click)=\"openImageModal([attachment])\"\n (keyup.enter)=\"openImageModal([attachment])\"\n />\n <div\n class=\"str-chat__gallery\"\n data-testid=\"image-gallery\"\n *ngIf=\"isGallery(attachment)\"\n [class.str-chat__gallery--square]=\"(attachment?.images)!.length > 3\"\n >\n <ng-container\n *ngFor=\"\n let galleryImage of attachment.images;\n let index = index;\n let isLast = last;\n trackBy: trackByImageUrl\n \"\n >\n <button\n *ngIf=\"index < 3 || (index === 3 && isLast)\"\n class=\"str-chat__gallery-image\"\n data-testclass=\"gallery-image\"\n (click)=\"openImageModal(attachment.images!, index)\"\n (keyup.enter)=\"openImageModal(attachment.images!, index)\"\n >\n <img\n [src]=\"\n galleryImage.img_url ||\n galleryImage.thumb_url ||\n galleryImage.image_url\n \"\n [alt]=\"galleryImage.fallback\"\n (load)=\"imageLoaded()\"\n />\n </button>\n <button\n *ngIf=\"index === 3 && !isLast\"\n class=\"str-chat__gallery-placeholder\"\n data-testclass=\"gallery-image\"\n (click)=\"openImageModal(attachment.images!, index)\"\n (keyup.enter)=\"openImageModal(attachment.images!, index)\"\n [ngStyle]=\"{\n 'background-image':\n 'url(' +\n (galleryImage.img_url ||\n galleryImage.thumb_url ||\n galleryImage.image_url) +\n ')'\n }\"\n >\n <p\n [innerHTML]=\"\n 'streamChat.{{ imageCount }} more'\n | translate: { imageCount: attachment!.images!.length - 4 }\n \"\n ></p>\n </button>\n </ng-container>\n </div>\n <div\n *ngIf=\"isFile(attachment)\"\n class=\"\n str-chat__message-attachment-file--item\n str-chat-angular__message-attachment-file-single\n \"\n >\n <stream-icon icon=\"file\" [size]=\"30\"></stream-icon>\n <div class=\"str-chat__message-attachment-file--item-text\">\n <a\n data-testclass=\"file-link\"\n download\n href=\"{{ attachment.asset_url }}\"\n target=\"_blank\"\n >\n {{ attachment.title }}\n </a>\n <span data-testclass=\"size\" *ngIf=\"hasFileSize(attachment)\">{{\n getFileSize(attachment)\n }}</span>\n </div>\n </div>\n <div\n *ngIf=\"isCard(attachment)\"\n class=\"str-chat__message-attachment-card str-chat__message-attachment-card--{{\n attachment.type\n }}\"\n >\n <div\n *ngIf=\"attachment.image_url || attachment.thumb_url\"\n class=\"str-chat__message-attachment-card--header\"\n >\n <img\n data-testclass=\"card-img\"\n alt=\"{{ attachment.image_url || attachment.thumb_url }}\"\n src=\"{{ attachment.image_url || attachment.thumb_url }}\"\n />\n </div>\n <div class=\"str-chat__message-attachment-card--content\">\n <div class=\"str-chat__message-attachment-card--flex\">\n <div\n *ngIf=\"attachment.title\"\n data-testclass=\"card-title\"\n class=\"str-chat__message-attachment-card--title\"\n >\n {{ attachment.title }}\n </div>\n <div\n *ngIf=\"attachment.text\"\n class=\"str-chat__message-attachment-card--text\"\n data-testclass=\"card-text\"\n >\n {{ attachment.text }}\n </div>\n <a\n class=\"str-chat__message-attachment-card--url\"\n *ngIf=\"attachment.title_link || attachment.og_scrape_url\"\n data-testclass=\"url-link\"\n noopener\n noreferrer\n href=\"{{ attachment.title_link || attachment.og_scrape_url }}\"\n target=\"_blank\"\n >\n {{ trimUrl(attachment.title_link || attachment.og_scrape_url) }}\n </a>\n </div>\n </div>\n </div>\n <div\n class=\"str-chat__message-attachment-actions\"\n *ngIf=\"attachment.actions && attachment.actions.length > 0\"\n >\n <div class=\"str-chat__message-attachment-actions-form\">\n <button\n *ngFor=\"let action of attachment.actions; trackBy: trackByActionValue\"\n class=\"str-chat__message-attachment-actions-button str-chat__message-attachment-actions-button--{{\n action.style\n }}\"\n data-testclass=\"attachment-action\"\n (click)=\"sendAction(action)\"\n (keyup.enter)=\"sendAction(action)\"\n >\n {{ action.text }}\n </button>\n </div>\n </div>\n </div>\n</ng-container>\n\n<stream-modal\n *ngIf=\"imagesToView && imagesToView.length > 0\"\n [isOpen]=\"imagesToView && imagesToView.length > 0\"\n (isOpenChange)=\"$event ? null : closeImageModal()\"\n>\n <div class=\"stream-chat-angular__image-modal\">\n <button\n class=\"stream-chat-angular__image-modal-stepper\"\n [ngStyle]=\"{\n visibility: isImageModalPrevButtonVisible ? 'visible' : 'hidden'\n }\"\n data-testid=\"image-modal-prev\"\n type=\"button\"\n (click)=\"stepImages(-1)\"\n (keyup.enter)=\"stepImages(-1)\"\n >\n <stream-icon icon=\"arrow-left\"></stream-icon>\n </button>\n <img\n class=\"stream-chat-angular__image-modal-image\"\n data-testid=\"modal-image\"\n [src]=\"\n imagesToView[imagesToViewCurrentIndex].img_url ||\n imagesToView[imagesToViewCurrentIndex].thumb_url ||\n imagesToView[imagesToViewCurrentIndex].image_url\n \"\n [alt]=\"imagesToView[imagesToViewCurrentIndex].fallback\"\n />\n <button\n class=\"stream-chat-angular__image-modal-stepper\"\n type=\"button\"\n [ngStyle]=\"{\n visibility: isImageModalNextButtonVisible ? 'visible' : 'hidden'\n }\"\n data-testid=\"image-modal-next\"\n (click)=\"stepImages(1)\"\n (keyup.enter)=\"stepImages(1)\"\n >\n <stream-icon icon=\"arrow-right\"></stream-icon>\n </button>\n </div>\n</stream-modal>\n", components: [{ type: IconComponent, selector: "stream-icon", inputs: ["icon", "size"] }, { type: ModalComponent, selector: "stream-modal", inputs: ["isOpen"], outputs: ["isOpenChange"] }], directives: [{ type: i6.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i6.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }], pipes: { "translate": i2.TranslatePipe } });
2185
+ AttachmentListComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: AttachmentListComponent, deps: [{ token: CustomTemplatesService }, { token: ImageLoadService }, { token: ChannelService }], target: i0.ɵɵFactoryTarget.Component });
2186
+ AttachmentListComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: AttachmentListComponent, selector: "stream-attachment-list", inputs: { messageId: "messageId", attachments: "attachments" }, viewQueries: [{ propertyName: "modalContent", first: true, predicate: ["modalContent"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: "<ng-container *ngFor=\"let attachment of orderedAttachments; trackBy: trackById\">\n <div\n data-testclass=\"attachment-container\"\n class=\"str-chat__message-attachment str-chat__message-attachment--{{\n attachment.type\n }}\"\n [class.str-chat__message-attachment--card]=\"isCard(attachment)\"\n [class.str-chat-angular__message-attachment-file-single]=\"\n isFile(attachment)\n \"\n >\n <img\n *ngIf=\"isImage(attachment)\"\n class=\"str-chat__message-attachment--img\"\n data-testclass=\"image\"\n [src]=\"attachment.img_url || attachment.thumb_url || attachment.image_url\"\n [alt]=\"attachment?.fallback\"\n (load)=\"imageLoaded()\"\n (click)=\"openImageModal([attachment])\"\n (keyup.enter)=\"openImageModal([attachment])\"\n />\n <div\n class=\"str-chat__gallery\"\n data-testid=\"image-gallery\"\n *ngIf=\"isGallery(attachment)\"\n [class.str-chat__gallery--square]=\"(attachment?.images)!.length > 3\"\n >\n <ng-container\n *ngFor=\"\n let galleryImage of attachment.images;\n let index = index;\n let isLast = last;\n trackBy: trackByImageUrl\n \"\n >\n <button\n *ngIf=\"index < 3 || (index === 3 && isLast)\"\n class=\"str-chat__gallery-image\"\n data-testclass=\"gallery-image\"\n (click)=\"openImageModal(attachment.images!, index)\"\n (keyup.enter)=\"openImageModal(attachment.images!, index)\"\n >\n <img\n [src]=\"\n galleryImage.img_url ||\n galleryImage.thumb_url ||\n galleryImage.image_url\n \"\n [alt]=\"galleryImage.fallback\"\n (load)=\"imageLoaded()\"\n />\n </button>\n <button\n *ngIf=\"index === 3 && !isLast\"\n class=\"str-chat__gallery-placeholder\"\n data-testclass=\"gallery-image\"\n (click)=\"openImageModal(attachment.images!, index)\"\n (keyup.enter)=\"openImageModal(attachment.images!, index)\"\n [ngStyle]=\"{\n 'background-image':\n 'url(' +\n (galleryImage.img_url ||\n galleryImage.thumb_url ||\n galleryImage.image_url) +\n ')'\n }\"\n >\n <p\n [innerHTML]=\"\n 'streamChat.{{ imageCount }} more'\n | translate: { imageCount: attachment!.images!.length - 4 }\n \"\n ></p>\n </button>\n </ng-container>\n </div>\n <div\n *ngIf=\"isFile(attachment)\"\n class=\"\n str-chat__message-attachment-file--item\n str-chat-angular__message-attachment-file-single\n \"\n >\n <stream-icon-placeholder\n icon=\"file\"\n [size]=\"30\"\n ></stream-icon-placeholder>\n <div class=\"str-chat__message-attachment-file--item-text\">\n <a\n data-testclass=\"file-link\"\n download\n href=\"{{ attachment.asset_url }}\"\n target=\"_blank\"\n >\n {{ attachment.title }}\n </a>\n <span data-testclass=\"size\" *ngIf=\"hasFileSize(attachment)\">{{\n getFileSize(attachment)\n }}</span>\n </div>\n </div>\n <div\n *ngIf=\"isCard(attachment)\"\n class=\"str-chat__message-attachment-card str-chat__message-attachment-card--{{\n attachment.type\n }}\"\n >\n <div\n *ngIf=\"attachment.image_url || attachment.thumb_url\"\n class=\"str-chat__message-attachment-card--header\"\n >\n <img\n data-testclass=\"card-img\"\n alt=\"{{ attachment.image_url || attachment.thumb_url }}\"\n src=\"{{ attachment.image_url || attachment.thumb_url }}\"\n />\n </div>\n <div class=\"str-chat__message-attachment-card--content\">\n <div class=\"str-chat__message-attachment-card--flex\">\n <div\n *ngIf=\"attachment.title\"\n data-testclass=\"card-title\"\n class=\"str-chat__message-attachment-card--title\"\n >\n {{ attachment.title }}\n </div>\n <div\n *ngIf=\"attachment.text\"\n class=\"str-chat__message-attachment-card--text\"\n data-testclass=\"card-text\"\n >\n {{ attachment.text }}\n </div>\n <a\n class=\"str-chat__message-attachment-card--url\"\n *ngIf=\"attachment.title_link || attachment.og_scrape_url\"\n data-testclass=\"url-link\"\n noopener\n noreferrer\n href=\"{{ attachment.title_link || attachment.og_scrape_url }}\"\n target=\"_blank\"\n >\n {{ trimUrl(attachment.title_link || attachment.og_scrape_url) }}\n </a>\n </div>\n </div>\n </div>\n <div\n class=\"str-chat__message-attachment-actions\"\n *ngIf=\"attachment.actions && attachment.actions.length > 0\"\n >\n <div class=\"str-chat__message-attachment-actions-form\">\n <button\n *ngFor=\"let action of attachment.actions; trackBy: trackByActionValue\"\n class=\"str-chat__message-attachment-actions-button str-chat__message-attachment-actions-button--{{\n action.style\n }}\"\n data-testclass=\"attachment-action\"\n (click)=\"sendAction(action)\"\n (keyup.enter)=\"sendAction(action)\"\n >\n {{ action.text }}\n </button>\n </div>\n </div>\n </div>\n</ng-container>\n\n<ng-container *ngIf=\"imagesToView && imagesToView.length > 0\">\n <ng-container\n *ngTemplateOutlet=\"\n (customTemplatesService.modalTemplate$ | async) || defaultModal;\n context: getModalContext()\n \"\n ></ng-container>\n</ng-container>\n\n<ng-template\n #defaultModal\n let-isOpen=\"isOpen\"\n let-isOpenChangeHandler=\"isOpenChangeHandler\"\n let-content=\"content\"\n>\n <stream-modal\n [isOpen]=\"isOpen\"\n (isOpenChange)=\"isOpenChangeHandler($event)\"\n [content]=\"content\"\n >\n </stream-modal>\n</ng-template>\n\n<ng-template #modalContent>\n <div class=\"stream-chat-angular__image-modal\">\n <button\n class=\"stream-chat-angular__image-modal-stepper\"\n [ngStyle]=\"{\n visibility: isImageModalPrevButtonVisible ? 'visible' : 'hidden'\n }\"\n data-testid=\"image-modal-prev\"\n type=\"button\"\n (click)=\"stepImages(-1)\"\n (keyup.enter)=\"stepImages(-1)\"\n >\n <stream-icon-placeholder icon=\"arrow-left\"></stream-icon-placeholder>\n </button>\n <img\n class=\"stream-chat-angular__image-modal-image\"\n data-testid=\"modal-image\"\n [src]=\"\n imagesToView[imagesToViewCurrentIndex].img_url ||\n imagesToView[imagesToViewCurrentIndex].thumb_url ||\n imagesToView[imagesToViewCurrentIndex].image_url\n \"\n [alt]=\"imagesToView[imagesToViewCurrentIndex].fallback\"\n />\n <button\n class=\"stream-chat-angular__image-modal-stepper\"\n type=\"button\"\n [ngStyle]=\"{\n visibility: isImageModalNextButtonVisible ? 'visible' : 'hidden'\n }\"\n data-testid=\"image-modal-next\"\n (click)=\"stepImages(1)\"\n (keyup.enter)=\"stepImages(1)\"\n >\n <stream-icon-placeholder icon=\"arrow-right\"></stream-icon-placeholder>\n </button>\n </div>\n</ng-template>\n", components: [{ type: IconPlaceholderComponent, selector: "stream-icon-placeholder", inputs: ["icon", "size"] }, { type: ModalComponent, selector: "stream-modal", inputs: ["isOpen", "content"], outputs: ["isOpenChange"] }], directives: [{ type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }], pipes: { "translate": i2.TranslatePipe, "async": i3.AsyncPipe } });
1985
2187
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: AttachmentListComponent, decorators: [{
1986
2188
  type: Component,
1987
2189
  args: [{
@@ -1989,36 +2191,41 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImpor
1989
2191
  templateUrl: './attachment-list.component.html',
1990
2192
  styles: [],
1991
2193
  }]
1992
- }], ctorParameters: function () { return [{ type: ImageLoadService }, { type: ChannelService }]; }, propDecorators: { messageId: [{
2194
+ }], ctorParameters: function () { return [{ type: CustomTemplatesService }, { type: ImageLoadService }, { type: ChannelService }]; }, propDecorators: { messageId: [{
1993
2195
  type: Input
1994
2196
  }], attachments: [{
1995
2197
  type: Input
2198
+ }], modalContent: [{
2199
+ type: ViewChild,
2200
+ args: ['modalContent', { static: true }]
1996
2201
  }] } });
1997
2202
 
1998
2203
  /**
1999
2204
  * The `AttachmentPreviewList` compontent displays a preview of the attachments uploaded to a message. Users can delete attachments using the preview component, or retry upload if it failed previously.
2000
2205
  */
2001
2206
  class AttachmentPreviewListComponent {
2002
- constructor(attachmentService) {
2003
- this.attachmentService = attachmentService;
2004
- this.attachmentUploads$ = this.attachmentService.attachmentUploads$;
2207
+ constructor() {
2208
+ /**
2209
+ * An output to notify the parent component if the user tries to retry a failed upload
2210
+ */
2211
+ this.retryAttachmentUpload = new EventEmitter();
2212
+ /**
2213
+ * An output to notify the parent component if the user wants to delete a file
2214
+ */
2215
+ this.deleteAttachment = new EventEmitter();
2005
2216
  }
2006
- retryAttachmentUpload(file) {
2007
- return __awaiter(this, void 0, void 0, function* () {
2008
- yield this.attachmentService.retryAttachmentUpload(file);
2009
- });
2217
+ attachmentUploadRetried(file) {
2218
+ this.retryAttachmentUpload.emit(file);
2010
2219
  }
2011
- deleteAttachment(upload) {
2012
- return __awaiter(this, void 0, void 0, function* () {
2013
- yield this.attachmentService.deleteAttachment(upload);
2014
- });
2220
+ attachmentDeleted(upload) {
2221
+ this.deleteAttachment.emit(upload);
2015
2222
  }
2016
2223
  trackByFile(_, item) {
2017
2224
  return item.file;
2018
2225
  }
2019
2226
  }
2020
- AttachmentPreviewListComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: AttachmentPreviewListComponent, deps: [{ token: AttachmentService }], target: i0.ɵɵFactoryTarget.Component });
2021
- AttachmentPreviewListComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: AttachmentPreviewListComponent, selector: "stream-attachment-preview-list", ngImport: i0, template: "<div class=\"rfu-image-previewer\" *ngIf=\"(attachmentUploads$ | async)?.length\">\n <ng-container\n *ngFor=\"\n let attachmentUpload of attachmentUploads$ | async;\n trackBy: trackByFile\n \"\n >\n <div\n *ngIf=\"attachmentUpload.type === 'image'\"\n class=\"rfu-image-previewer__image\"\n [class.rfu-image-previewer__image--loaded]=\"\n attachmentUpload.state === 'success'\n \"\n data-testclass=\"attachment-image-preview\"\n >\n <div\n *ngIf=\"attachmentUpload.state === 'error'\"\n class=\"rfu-image-previewer__retry\"\n (click)=\"retryAttachmentUpload(attachmentUpload.file)\"\n (keyup.enter)=\"retryAttachmentUpload(attachmentUpload.file)\"\n data-testclass=\"upload-error\"\n >\n <stream-icon icon=\"retry\"></stream-icon>\n </div>\n <div class=\"rfu-thumbnail__wrapper\" style=\"width: 100; height: 100\">\n <div class=\"rfu-thumbnail__overlay\">\n <div\n class=\"rfu-icon-button\"\n data-testclass=\"delete-attachment\"\n role=\"button\"\n (click)=\"deleteAttachment(attachmentUpload)\"\n (keyup.enter)=\"deleteAttachment(attachmentUpload)\"\n >\n <stream-icon icon=\"close\"></stream-icon>\n </div>\n </div>\n <img\n *ngIf=\"attachmentUpload.url || attachmentUpload.previewUri\"\n src=\"{{\n attachmentUpload.url\n ? attachmentUpload.url\n : attachmentUpload.previewUri\n }}\"\n alt=\"attachmentUpload.file.name\"\n class=\"rfu-thumbnail__image\"\n data-testclass=\"attachment-image\"\n />\n </div>\n <stream-loading-indicator\n data-testclass=\"loading-indicator\"\n color=\"rgba(255,255,255,0.7)\"\n *ngIf=\"attachmentUpload.state === 'uploading'\"\n ></stream-loading-indicator>\n </div>\n <div\n class=\"rfu-file-previewer\"\n *ngIf=\"attachmentUpload.type === 'file'\"\n data-testclass=\"attachment-file-preview\"\n >\n <ol>\n <li\n class=\"rfu-file-previewer__file\"\n [class.rfu-file-previewer__file--uploading]=\"\n attachmentUpload.state === 'uploading'\n \"\n [class.rfu-file-previewer__file--failed]=\"\n attachmentUpload.state === 'error'\n \"\n >\n <stream-icon icon=\"file\"></stream-icon>\n\n <a\n data-testclass=\"file-download-link\"\n href=\"{{ attachmentUpload.url }}\"\n (click)=\"attachmentUpload.url ? null : $event.preventDefault()\"\n (keyup.enter)=\"\n attachmentUpload.url ? null : $event.preventDefault()\n \"\n download\n >\n {{ attachmentUpload.file.name }}\n <ng-container *ngIf=\"attachmentUpload.state === 'error'\">\n <div\n data-testclass=\"file-upload-retry\"\n class=\"rfu-file-previewer__failed\"\n (click)=\"retryAttachmentUpload(attachmentUpload.file)\"\n (keyup.enter)=\"retryAttachmentUpload(attachmentUpload.file)\"\n translate\n >\n streamChat.failed\n </div>\n <div\n class=\"rfu-file-previewer__retry\"\n (click)=\"retryAttachmentUpload(attachmentUpload.file)\"\n (keyup.enter)=\"retryAttachmentUpload(attachmentUpload.file)\"\n translate\n >\n streamChat.retry\n </div>\n </ng-container>\n </a>\n\n <span\n data-testclass=\"file-delete\"\n class=\"rfu-file-previewer__close-button\"\n (click)=\"deleteAttachment(attachmentUpload)\"\n (keyup.enter)=\"deleteAttachment(attachmentUpload)\"\n >\n \u2718\n </span>\n <div\n *ngIf=\"attachmentUpload.state === 'uploading'\"\n class=\"rfu-file-previewer__loading-indicator\"\n >\n <stream-loading-indicator></stream-loading-indicator>\n </div>\n </li>\n </ol>\n </div>\n </ng-container>\n</div>\n", components: [{ type: IconComponent, selector: "stream-icon", inputs: ["icon", "size"] }, { type: LoadingIndicatorComponent, selector: "stream-loading-indicator", inputs: ["size", "color"] }], directives: [{ type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i6.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i2.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }], pipes: { "async": i6.AsyncPipe } });
2227
+ AttachmentPreviewListComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: AttachmentPreviewListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2228
+ AttachmentPreviewListComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: AttachmentPreviewListComponent, selector: "stream-attachment-preview-list", inputs: { attachmentUploads$: "attachmentUploads$" }, outputs: { retryAttachmentUpload: "retryAttachmentUpload", deleteAttachment: "deleteAttachment" }, ngImport: i0, template: "<div class=\"rfu-image-previewer\" *ngIf=\"(attachmentUploads$ | async)?.length\">\n <ng-container\n *ngFor=\"\n let attachmentUpload of attachmentUploads$ | async;\n trackBy: trackByFile\n \"\n >\n <div\n *ngIf=\"attachmentUpload.type === 'image'\"\n class=\"rfu-image-previewer__image\"\n [class.rfu-image-previewer__image--loaded]=\"\n attachmentUpload.state === 'success'\n \"\n data-testclass=\"attachment-image-preview\"\n >\n <div\n *ngIf=\"attachmentUpload.state === 'error'\"\n class=\"rfu-image-previewer__retry\"\n (click)=\"attachmentUploadRetried(attachmentUpload.file)\"\n (keyup.enter)=\"attachmentUploadRetried(attachmentUpload.file)\"\n data-testclass=\"upload-error\"\n >\n <stream-icon-placeholder icon=\"retry\"></stream-icon-placeholder>\n </div>\n <div class=\"rfu-thumbnail__wrapper\" style=\"width: 100; height: 100\">\n <div class=\"rfu-thumbnail__overlay\">\n <div\n class=\"rfu-icon-button\"\n data-testclass=\"delete-attachment\"\n role=\"button\"\n (click)=\"attachmentDeleted(attachmentUpload)\"\n (keyup.enter)=\"attachmentDeleted(attachmentUpload)\"\n >\n <stream-icon-placeholder icon=\"close\"></stream-icon-placeholder>\n </div>\n </div>\n <img\n *ngIf=\"attachmentUpload.url || attachmentUpload.previewUri\"\n src=\"{{\n attachmentUpload.url\n ? attachmentUpload.url\n : attachmentUpload.previewUri\n }}\"\n alt=\"attachmentUpload.file.name\"\n class=\"rfu-thumbnail__image\"\n data-testclass=\"attachment-image\"\n />\n </div>\n <stream-loading-indicator-placeholder\n data-testclass=\"loading-indicator\"\n color=\"rgba(255,255,255,0.7)\"\n *ngIf=\"attachmentUpload.state === 'uploading'\"\n ></stream-loading-indicator-placeholder>\n </div>\n <div\n class=\"rfu-file-previewer\"\n *ngIf=\"attachmentUpload.type === 'file'\"\n data-testclass=\"attachment-file-preview\"\n >\n <ol>\n <li\n class=\"rfu-file-previewer__file\"\n [class.rfu-file-previewer__file--uploading]=\"\n attachmentUpload.state === 'uploading'\n \"\n [class.rfu-file-previewer__file--failed]=\"\n attachmentUpload.state === 'error'\n \"\n >\n <stream-icon-placeholder icon=\"file\"></stream-icon-placeholder>\n\n <a\n data-testclass=\"file-download-link\"\n href=\"{{ attachmentUpload.url }}\"\n (click)=\"attachmentUpload.url ? null : $event.preventDefault()\"\n (keyup.enter)=\"\n attachmentUpload.url ? null : $event.preventDefault()\n \"\n download\n >\n {{ attachmentUpload.file.name }}\n <ng-container *ngIf=\"attachmentUpload.state === 'error'\">\n <div\n data-testclass=\"file-upload-retry\"\n class=\"rfu-file-previewer__failed\"\n (click)=\"attachmentUploadRetried(attachmentUpload.file)\"\n (keyup.enter)=\"attachmentUploadRetried(attachmentUpload.file)\"\n translate\n >\n streamChat.failed\n </div>\n <div\n class=\"rfu-file-previewer__retry\"\n (click)=\"attachmentUploadRetried(attachmentUpload.file)\"\n (keyup.enter)=\"attachmentUploadRetried(attachmentUpload.file)\"\n translate\n >\n streamChat.retry\n </div>\n </ng-container>\n </a>\n\n <span\n data-testclass=\"file-delete\"\n class=\"rfu-file-previewer__close-button\"\n (click)=\"attachmentDeleted(attachmentUpload)\"\n (keyup.enter)=\"attachmentDeleted(attachmentUpload)\"\n >\n \u2718\n </span>\n <div\n *ngIf=\"attachmentUpload.state === 'uploading'\"\n class=\"rfu-file-previewer__loading-indicator\"\n >\n <stream-loading-indicator-placeholder></stream-loading-indicator-placeholder>\n </div>\n </li>\n </ol>\n </div>\n </ng-container>\n</div>\n", components: [{ type: IconPlaceholderComponent, selector: "stream-icon-placeholder", inputs: ["icon", "size"] }, { type: LoadingIndicatorPlaceholderComponent, selector: "stream-loading-indicator-placeholder", inputs: ["size", "color"] }], directives: [{ type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i2.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }], pipes: { "async": i3.AsyncPipe } });
2022
2229
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: AttachmentPreviewListComponent, decorators: [{
2023
2230
  type: Component,
2024
2231
  args: [{
@@ -2026,13 +2233,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImpor
2026
2233
  templateUrl: './attachment-preview-list.component.html',
2027
2234
  styles: [],
2028
2235
  }]
2029
- }], ctorParameters: function () { return [{ type: AttachmentService }]; } });
2236
+ }], ctorParameters: function () { return []; }, propDecorators: { attachmentUploads$: [{
2237
+ type: Input
2238
+ }], retryAttachmentUpload: [{
2239
+ type: Output
2240
+ }], deleteAttachment: [{
2241
+ type: Output
2242
+ }] } });
2030
2243
 
2031
2244
  /**
2032
2245
  * The `MessageInput` component displays an input where users can type their messages and upload files, and sends the message to the active channel. The component can be used to compose new messages or update existing ones. To send messages, the chat user needs to have the necessary [channel capability](https://getstream.io/chat/docs/javascript/channel_capabilities/?language=javascript).
2033
2246
  */
2034
2247
  class MessageInputComponent {
2035
- constructor(channelService, notificationService, attachmentService, configService, textareaType, componentFactoryResolver, cdRef, chatClient, emojiInputService) {
2248
+ constructor(channelService, notificationService, attachmentService, configService, textareaType, componentFactoryResolver, cdRef, chatClient, emojiInputService, customTemplatesService) {
2036
2249
  this.channelService = channelService;
2037
2250
  this.notificationService = notificationService;
2038
2251
  this.attachmentService = attachmentService;
@@ -2042,6 +2255,7 @@ class MessageInputComponent {
2042
2255
  this.cdRef = cdRef;
2043
2256
  this.chatClient = chatClient;
2044
2257
  this.emojiInputService = emojiInputService;
2258
+ this.customTemplatesService = customTemplatesService;
2045
2259
  /**
2046
2260
  * Determines if the message is being dispalyed in a channel or in a [thread](https://getstream.io/chat/docs/javascript/threads/?language=javascript).
2047
2261
  */
@@ -2086,16 +2300,10 @@ class MessageInputComponent {
2086
2300
  }));
2087
2301
  this.attachmentUploads$ = this.attachmentService.attachmentUploads$;
2088
2302
  this.isFileUploadEnabled = this.configService.isFileUploadEnabled;
2089
- this.acceptedFileTypes = this.configService.acceptedFileTypes;
2090
2303
  this.isMultipleFileUploadEnabled =
2091
2304
  this.configService.isMultipleFileUploadEnabled;
2092
2305
  this.areMentionsEnabled = this.configService.areMentionsEnabled;
2093
- this.mentionAutocompleteItemTemplate =
2094
- this.configService.mentionAutocompleteItemTemplate;
2095
2306
  this.mentionScope = this.configService.mentionScope;
2096
- this.commandAutocompleteItemTemplate =
2097
- this.configService.commandAutocompleteItemTemplate;
2098
- this.emojiPickerTemplate = this.configService.emojiPickerTemplate;
2099
2307
  this.subscriptions.push(this.typingStart$.subscribe(() => void this.channelService.typingStarted(this.parentMessageId)));
2100
2308
  this.subscriptions.push(combineLatest([
2101
2309
  this.channelService.latestMessageDateByUserByChannels$,
@@ -2118,6 +2326,16 @@ class MessageInputComponent {
2118
2326
  }
2119
2327
  }));
2120
2328
  }
2329
+ ngOnInit() {
2330
+ this.subscriptions.push(this.customTemplatesService.emojiPickerTemplate$.subscribe((template) => {
2331
+ this.emojiPickerTemplate = template;
2332
+ this.cdRef.detectChanges();
2333
+ }));
2334
+ this.subscriptions.push(this.customTemplatesService.attachmentPreviewListTemplate$.subscribe((template) => {
2335
+ this.attachmentPreviewListTemplate = template;
2336
+ this.cdRef.detectChanges();
2337
+ }));
2338
+ }
2121
2339
  ngAfterViewInit() {
2122
2340
  this.isViewInited = true;
2123
2341
  this.initTextarea();
@@ -2133,9 +2351,6 @@ class MessageInputComponent {
2133
2351
  if (changes.isFileUploadEnabled) {
2134
2352
  this.configService.isFileUploadEnabled = this.isFileUploadEnabled;
2135
2353
  }
2136
- if (changes.acceptedFileTypes) {
2137
- this.configService.acceptedFileTypes = this.acceptedFileTypes;
2138
- }
2139
2354
  if (changes.isMultipleFileUploadEnabled) {
2140
2355
  this.configService.isMultipleFileUploadEnabled =
2141
2356
  this.isMultipleFileUploadEnabled;
@@ -2143,25 +2358,25 @@ class MessageInputComponent {
2143
2358
  if (changes.areMentionsEnabled) {
2144
2359
  this.configService.areMentionsEnabled = this.areMentionsEnabled;
2145
2360
  }
2146
- if (changes.mentionAutocompleteItemTemplate) {
2147
- this.configService.mentionAutocompleteItemTemplate =
2148
- this.mentionAutocompleteItemTemplate;
2149
- }
2150
- if (changes.commandAutocompleteItemTemplate) {
2151
- this.configService.commandAutocompleteItemTemplate =
2152
- this.commandAutocompleteItemTemplate;
2153
- }
2154
2361
  if (changes.mentionScope) {
2155
2362
  this.configService.mentionScope = this.mentionScope;
2156
2363
  }
2157
- if (changes.emojiPickerTemplate) {
2158
- this.configService.emojiPickerTemplate = this.emojiPickerTemplate;
2159
- }
2160
2364
  if (changes.mode) {
2161
2365
  this.setCanSendMessages();
2162
2366
  }
2367
+ if (changes.sendMessage$) {
2368
+ if (this.sendMessageSubcription) {
2369
+ this.sendMessageSubcription.unsubscribe();
2370
+ }
2371
+ if (this.sendMessage$) {
2372
+ this.sendMessageSubcription = this.sendMessage$.subscribe(() => void this.messageSent());
2373
+ }
2374
+ }
2163
2375
  }
2164
2376
  ngOnDestroy() {
2377
+ if (this.sendMessageSubcription) {
2378
+ this.sendMessageSubcription.unsubscribe();
2379
+ }
2165
2380
  this.subscriptions.forEach((s) => s.unsubscribe());
2166
2381
  }
2167
2382
  messageSent() {
@@ -2213,10 +2428,6 @@ class MessageInputComponent {
2213
2428
  get containsLinks() {
2214
2429
  return /(?:(?:https?|ftp):\/\/)?[\w/\-?=%.]+\.[\w/\-&?=%.]+/.test(this.textareaValue);
2215
2430
  }
2216
- get accept() {
2217
- var _a;
2218
- return this.acceptedFileTypes ? (_a = this.acceptedFileTypes) === null || _a === void 0 ? void 0 : _a.join(',') : '';
2219
- }
2220
2431
  get quotedMessageAttachments() {
2221
2432
  var _a;
2222
2433
  const originalAttachments = (_a = this.quotedMessage) === null || _a === void 0 ? void 0 : _a.attachments;
@@ -2247,6 +2458,24 @@ class MessageInputComponent {
2247
2458
  deselectMessageToQuote() {
2248
2459
  this.channelService.selectMessageToQuote(undefined);
2249
2460
  }
2461
+ getEmojiPickerContext() {
2462
+ return {
2463
+ emojiInput$: this.emojiInputService.emojiInput$,
2464
+ };
2465
+ }
2466
+ getAttachmentPreviewListContext() {
2467
+ return {
2468
+ attachmentUploads$: this.attachmentService.attachmentUploads$,
2469
+ deleteUploadHandler: this.deleteUpload.bind(this),
2470
+ retryUploadHandler: this.retryUpload.bind(this),
2471
+ };
2472
+ }
2473
+ deleteUpload(upload) {
2474
+ void this.attachmentService.deleteAttachment(upload);
2475
+ }
2476
+ retryUpload(file) {
2477
+ void this.attachmentService.retryAttachmentUpload(file);
2478
+ }
2250
2479
  clearFileInput() {
2251
2480
  this.fileInput.nativeElement.value = '';
2252
2481
  }
@@ -2264,7 +2493,7 @@ class MessageInputComponent {
2264
2493
  }
2265
2494
  areAttachemntsValid(fileList) {
2266
2495
  return __awaiter(this, void 0, void 0, function* () {
2267
- if (!fileList || this.acceptedFileTypes) {
2496
+ if (!fileList) {
2268
2497
  return true;
2269
2498
  }
2270
2499
  if (!this.appSettings) {
@@ -2353,8 +2582,8 @@ class MessageInputComponent {
2353
2582
  setTimeout(() => this.initTextarea());
2354
2583
  }
2355
2584
  }
2356
- MessageInputComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: MessageInputComponent, deps: [{ token: ChannelService }, { token: NotificationService }, { token: AttachmentService }, { token: MessageInputConfigService }, { token: textareaInjectionToken }, { token: i0.ComponentFactoryResolver }, { token: i0.ChangeDetectorRef }, { token: ChatClientService }, { token: EmojiInputService }], target: i0.ɵɵFactoryTarget.Component });
2357
- MessageInputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: MessageInputComponent, selector: "stream-message-input", inputs: { isFileUploadEnabled: "isFileUploadEnabled", areMentionsEnabled: "areMentionsEnabled", mentionScope: "mentionScope", mentionAutocompleteItemTemplate: "mentionAutocompleteItemTemplate", commandAutocompleteItemTemplate: "commandAutocompleteItemTemplate", emojiPickerTemplate: "emojiPickerTemplate", mode: "mode", acceptedFileTypes: "acceptedFileTypes", isMultipleFileUploadEnabled: "isMultipleFileUploadEnabled", message: "message" }, outputs: { messageUpdate: "messageUpdate" }, providers: [AttachmentService, EmojiInputService], viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true }, { propertyName: "textareaAnchor", first: true, predicate: TextareaDirective, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\n class=\"{{\n mode === 'main' ? 'str-chat__input-flat' : 'str-chat__small-message-input'\n }}\"\n [class.str-chat__input-flat-has-attachments]=\"\n (attachmentUploads$ | async)!.length > 0\n \"\n [class.str-chat__input-flat-quoted]=\"!!quotedMessage\"\n>\n <div\n data-testid=\"quoted-message-container\"\n class=\"quoted-message-preview\"\n *ngIf=\"quotedMessage\"\n >\n <div class=\"quoted-message-preview-header\">\n <div>{{ \"streamChat.Reply to Message\" | translate }}</div>\n <button\n class=\"str-chat__square-button\"\n data-testid=\"remove-quote\"\n (click)=\"deselectMessageToQuote()\"\n (keyup.enter)=\"deselectMessageToQuote()\"\n >\n <stream-icon\n icon=\"close-no-outline\"\n style=\"font-size: 10px; line-height: 10px\"\n ></stream-icon>\n </button>\n </div>\n <div class=\"quoted-message-preview-content\">\n <stream-avatar\n data-testid=\"qouted-message-avatar\"\n class=\"str-chat-angular__avatar-host\"\n [imageUrl]=\"quotedMessage?.user?.image\"\n [name]=\"quotedMessage?.user?.name || quotedMessage?.user?.id\"\n [size]=\"20\"\n ></stream-avatar>\n <div class=\"quoted-message-preview-content-inner\">\n <stream-attachment-list\n *ngIf=\"\n quotedMessage?.attachments && quotedMessage?.attachments?.length\n \"\n [attachments]=\"quotedMessageAttachments\"\n [messageId]=\"quotedMessage?.id\"\n ></stream-attachment-list>\n <div\n data-testid=\"quoted-message-text\"\n [innerHTML]=\"quotedMessage?.html || quotedMessage?.text\"\n ></div>\n </div>\n </div>\n </div>\n <div class=\"str-chat__input-flat-wrapper\" style=\"width: 100%\">\n <div\n class=\"{{\n mode === 'main'\n ? 'str-chat__input-flat--textarea-wrapper'\n : 'str-chat__small-message-input--textarea-wrapper'\n }}\"\n >\n <stream-attachment-preview-list\n class=\"rfu-image-previewer-angular-host\"\n ></stream-attachment-preview-list>\n <div class=\"rta str-chat__textarea str-chat-angular__textarea\">\n <ng-container\n *ngIf=\"emojiPickerTemplate && !isCooldownInProgress\"\n data-testid=\"emoji-picker\"\n >\n <div\n class=\"\n str-chat__input-flat-emojiselect\n str-chat-angular__emojiselect\n \"\n >\n <ng-container\n *ngTemplateOutlet=\"\n emojiPickerTemplate;\n context: { emojiInput$: emojiInputService.emojiInput$ }\n \"\n ></ng-container>\n </div>\n </ng-container>\n <div\n class=\"str-chat__input-flat-cooldown str-chat-angular__cooldown\"\n *ngIf=\"isCooldownInProgress\"\n data-testid=\"cooldown-timer\"\n >\n {{ cooldown$ | async }}\n </div>\n <ng-template\n *ngIf=\"canSendMessages && !isCooldownInProgress; else notAllowed\"\n streamTextarea\n [(value)]=\"textareaValue\"\n (valueChange)=\"typingStart$.next()\"\n (send)=\"messageSent()\"\n [componentRef]=\"textareaRef\"\n (userMentions)=\"mentionedUsers = $event\"\n [areMentionsEnabled]=\"areMentionsEnabled\"\n [mentionAutocompleteItemTemplate]=\"mentionAutocompleteItemTemplate\"\n [commandAutocompleteItemTemplate]=\"commandAutocompleteItemTemplate\"\n [mentionScope]=\"mentionScope\"\n ></ng-template>\n <ng-template #notAllowed>\n <textarea\n disabled\n rows=\"1\"\n [value]=\"disabledTextareaText | translate\"\n class=\"rta__textarea str-chat__textarea__textarea\"\n data-testid=\"disabled-textarea\"\n ></textarea>\n </ng-template>\n </div>\n <div\n *ngIf=\"\n isFileUploadEnabled &&\n isFileUploadAuthorized &&\n canSendMessages &&\n !isCooldownInProgress\n \"\n class=\"str-chat__fileupload-wrapper\"\n data-testid=\"file-upload-button\"\n >\n <div class=\"str-chat__tooltip\">\n {{ \"streamChat.Attach files\" | translate }}\n </div>\n <div class=\"rfu-file-upload-button\">\n <label>\n <input\n #fileInput\n type=\"file\"\n class=\"rfu-file-input\"\n data-testid=\"file-input\"\n [accept]=\"accept\"\n [multiple]=\"isMultipleFileUploadEnabled\"\n (change)=\"filesSelected(fileInput.files)\"\n />\n <span class=\"str-chat__input-flat-fileupload\">\n <stream-icon icon=\"file-upload\"></stream-icon>\n </span>\n </label>\n </div>\n </div>\n </div>\n <button\n *ngIf=\"canSendMessages\"\n data-testid=\"send-button\"\n class=\"str-chat__send-button\"\n (click)=\"messageSent()\"\n (keyup.enter)=\"messageSent()\"\n >\n <stream-icon icon=\"send\"></stream-icon>\n </button>\n </div>\n</div>\n", components: [{ type: IconComponent, selector: "stream-icon", inputs: ["icon", "size"] }, { type: AvatarComponent, selector: "stream-avatar", inputs: ["name", "imageUrl", "size"] }, { type: AttachmentListComponent, selector: "stream-attachment-list", inputs: ["messageId", "attachments"] }, { type: AttachmentPreviewListComponent, selector: "stream-attachment-preview-list" }], directives: [{ type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i6.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: TextareaDirective, selector: "[streamTextarea]", inputs: ["componentRef", "areMentionsEnabled", "mentionAutocompleteItemTemplate", "mentionScope", "commandAutocompleteItemTemplate", "value"], outputs: ["valueChange", "send", "userMentions"] }], pipes: { "async": i6.AsyncPipe, "translate": i2.TranslatePipe } });
2585
+ MessageInputComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: MessageInputComponent, deps: [{ token: ChannelService }, { token: NotificationService }, { token: AttachmentService }, { token: MessageInputConfigService }, { token: textareaInjectionToken }, { token: i0.ComponentFactoryResolver }, { token: i0.ChangeDetectorRef }, { token: ChatClientService }, { token: EmojiInputService }, { token: CustomTemplatesService }], target: i0.ɵɵFactoryTarget.Component });
2586
+ MessageInputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: MessageInputComponent, selector: "stream-message-input", inputs: { isFileUploadEnabled: "isFileUploadEnabled", areMentionsEnabled: "areMentionsEnabled", mentionScope: "mentionScope", mode: "mode", isMultipleFileUploadEnabled: "isMultipleFileUploadEnabled", message: "message", sendMessage$: "sendMessage$" }, outputs: { messageUpdate: "messageUpdate" }, providers: [AttachmentService, EmojiInputService], viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true }, { propertyName: "textareaAnchor", first: true, predicate: TextareaDirective, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\n class=\"{{\n mode === 'main' ? 'str-chat__input-flat' : 'str-chat__small-message-input'\n }}\"\n [class.str-chat__input-flat-has-attachments]=\"\n (attachmentUploads$ | async)!.length > 0\n \"\n [class.str-chat__input-flat-quoted]=\"!!quotedMessage\"\n>\n <div\n data-testid=\"quoted-message-container\"\n class=\"quoted-message-preview\"\n *ngIf=\"quotedMessage\"\n >\n <div class=\"quoted-message-preview-header\">\n <div>{{ \"streamChat.Reply to Message\" | translate }}</div>\n <button\n class=\"str-chat__square-button\"\n data-testid=\"remove-quote\"\n (click)=\"deselectMessageToQuote()\"\n (keyup.enter)=\"deselectMessageToQuote()\"\n >\n <stream-icon-placeholder\n icon=\"close-no-outline\"\n style=\"font-size: 10px; line-height: 10px\"\n ></stream-icon-placeholder>\n </button>\n </div>\n <div class=\"quoted-message-preview-content\">\n <stream-avatar-placeholder\n data-testid=\"qouted-message-avatar\"\n class=\"str-chat-angular__avatar-host\"\n [imageUrl]=\"quotedMessage?.user?.image\"\n [name]=\"quotedMessage?.user?.name || quotedMessage?.user?.id\"\n [size]=\"20\"\n ></stream-avatar-placeholder>\n <div class=\"quoted-message-preview-content-inner\">\n <stream-attachment-list\n *ngIf=\"\n quotedMessage?.attachments && quotedMessage?.attachments?.length\n \"\n [attachments]=\"quotedMessageAttachments\"\n [messageId]=\"quotedMessage?.id\"\n ></stream-attachment-list>\n <div\n data-testid=\"quoted-message-text\"\n [innerHTML]=\"quotedMessage?.html || quotedMessage?.text\"\n ></div>\n </div>\n </div>\n </div>\n <div class=\"str-chat__input-flat-wrapper\" style=\"width: 100%\">\n <div\n class=\"{{\n mode === 'main'\n ? 'str-chat__input-flat--textarea-wrapper'\n : 'str-chat__small-message-input--textarea-wrapper'\n }}\"\n >\n <ng-template\n #defaultAttachmentsPreview\n let-attachmentUploads$=\"attachmentUploads$\"\n let-retryUploadHandler=\"retryUploadHandler\"\n let-deleteUploadHandler=\"deleteUploadHandler\"\n >\n <stream-attachment-preview-list\n [attachmentUploads$]=\"attachmentUploads$\"\n (retryAttachmentUpload)=\"retryUploadHandler($event)\"\n (deleteAttachment)=\"deleteUploadHandler($event)\"\n class=\"rfu-image-previewer-angular-host\"\n ></stream-attachment-preview-list>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n attachmentPreviewListTemplate || defaultAttachmentsPreview;\n context: getAttachmentPreviewListContext()\n \"\n ></ng-container>\n <div class=\"rta str-chat__textarea str-chat-angular__textarea\">\n <ng-container\n *ngIf=\"emojiPickerTemplate && !isCooldownInProgress\"\n data-testid=\"emoji-picker\"\n >\n <div\n class=\"\n str-chat__input-flat-emojiselect\n str-chat-angular__emojiselect\n \"\n >\n <ng-container\n *ngTemplateOutlet=\"\n emojiPickerTemplate;\n context: getEmojiPickerContext()\n \"\n ></ng-container>\n </div>\n </ng-container>\n <div\n class=\"str-chat__input-flat-cooldown str-chat-angular__cooldown\"\n *ngIf=\"isCooldownInProgress\"\n data-testid=\"cooldown-timer\"\n >\n {{ cooldown$ | async }}\n </div>\n <ng-template\n *ngIf=\"canSendMessages && !isCooldownInProgress; else notAllowed\"\n streamTextarea\n [(value)]=\"textareaValue\"\n (valueChange)=\"typingStart$.next()\"\n (send)=\"messageSent()\"\n [componentRef]=\"textareaRef\"\n (userMentions)=\"mentionedUsers = $event\"\n [areMentionsEnabled]=\"areMentionsEnabled\"\n [mentionScope]=\"mentionScope\"\n ></ng-template>\n <ng-template #notAllowed>\n <textarea\n disabled\n rows=\"1\"\n [value]=\"disabledTextareaText | translate\"\n class=\"rta__textarea str-chat__textarea__textarea\"\n data-testid=\"disabled-textarea\"\n ></textarea>\n </ng-template>\n </div>\n <div\n *ngIf=\"\n isFileUploadEnabled &&\n isFileUploadAuthorized &&\n canSendMessages &&\n !isCooldownInProgress\n \"\n class=\"str-chat__fileupload-wrapper\"\n data-testid=\"file-upload-button\"\n >\n <div class=\"str-chat__tooltip\">\n {{ \"streamChat.Attach files\" | translate }}\n </div>\n <div class=\"rfu-file-upload-button\">\n <label>\n <input\n #fileInput\n type=\"file\"\n class=\"rfu-file-input\"\n data-testid=\"file-input\"\n [multiple]=\"isMultipleFileUploadEnabled\"\n (change)=\"filesSelected(fileInput.files)\"\n />\n <span class=\"str-chat__input-flat-fileupload\">\n <stream-icon-placeholder\n icon=\"file-upload\"\n ></stream-icon-placeholder>\n </span>\n </label>\n </div>\n </div>\n </div>\n <button\n *ngIf=\"canSendMessages\"\n data-testid=\"send-button\"\n class=\"str-chat__send-button\"\n (click)=\"messageSent()\"\n (keyup.enter)=\"messageSent()\"\n >\n <stream-icon-placeholder icon=\"send\"></stream-icon-placeholder>\n </button>\n </div>\n</div>\n", components: [{ type: IconPlaceholderComponent, selector: "stream-icon-placeholder", inputs: ["icon", "size"] }, { type: AvatarPlaceholderComponent, selector: "stream-avatar-placeholder", inputs: ["name", "imageUrl", "size"] }, { type: AttachmentListComponent, selector: "stream-attachment-list", inputs: ["messageId", "attachments"] }, { type: AttachmentPreviewListComponent, selector: "stream-attachment-preview-list", inputs: ["attachmentUploads$"], outputs: ["retryAttachmentUpload", "deleteAttachment"] }], directives: [{ type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: TextareaDirective, selector: "[streamTextarea]", inputs: ["componentRef", "areMentionsEnabled", "mentionScope", "value"], outputs: ["valueChange", "send", "userMentions"] }], pipes: { "async": i3.AsyncPipe, "translate": i2.TranslatePipe } });
2358
2587
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: MessageInputComponent, decorators: [{
2359
2588
  type: Component,
2360
2589
  args: [{
@@ -2366,26 +2595,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImpor
2366
2595
  }], ctorParameters: function () { return [{ type: ChannelService }, { type: NotificationService }, { type: AttachmentService }, { type: MessageInputConfigService }, { type: i0.Type, decorators: [{
2367
2596
  type: Inject,
2368
2597
  args: [textareaInjectionToken]
2369
- }] }, { type: i0.ComponentFactoryResolver }, { type: i0.ChangeDetectorRef }, { type: ChatClientService }, { type: EmojiInputService }]; }, propDecorators: { isFileUploadEnabled: [{
2598
+ }] }, { type: i0.ComponentFactoryResolver }, { type: i0.ChangeDetectorRef }, { type: ChatClientService }, { type: EmojiInputService }, { type: CustomTemplatesService }]; }, propDecorators: { isFileUploadEnabled: [{
2370
2599
  type: Input
2371
2600
  }], areMentionsEnabled: [{
2372
2601
  type: Input
2373
2602
  }], mentionScope: [{
2374
2603
  type: Input
2375
- }], mentionAutocompleteItemTemplate: [{
2376
- type: Input
2377
- }], commandAutocompleteItemTemplate: [{
2378
- type: Input
2379
- }], emojiPickerTemplate: [{
2380
- type: Input
2381
2604
  }], mode: [{
2382
2605
  type: Input
2383
- }], acceptedFileTypes: [{
2384
- type: Input
2385
2606
  }], isMultipleFileUploadEnabled: [{
2386
2607
  type: Input
2387
2608
  }], message: [{
2388
2609
  type: Input
2610
+ }], sendMessage$: [{
2611
+ type: Input
2389
2612
  }], messageUpdate: [{
2390
2613
  type: Output
2391
2614
  }], fileInput: [{
@@ -2403,7 +2626,7 @@ class NotificationComponent {
2403
2626
  constructor() { }
2404
2627
  }
2405
2628
  NotificationComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: NotificationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2406
- NotificationComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: NotificationComponent, selector: "stream-notification", inputs: { type: "type" }, ngImport: i0, template: "<div\n class=\"str-chat__custom-notification notification-{{ type }}\"\n data-testid=\"custom-notification\"\n>\n <ng-content></ng-content>\n</div>\n" });
2629
+ NotificationComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: NotificationComponent, selector: "stream-notification", inputs: { type: "type", content: "content" }, ngImport: i0, template: "<div\n class=\"str-chat__custom-notification notification-{{ type }}\"\n data-testid=\"custom-notification\"\n>\n <ng-container *ngIf=\"content; else elseContent\">\n <ng-container *ngTemplateOutlet=\"content\"></ng-container>\n </ng-container>\n <ng-template #elseContent>\n <ng-content></ng-content>\n </ng-template>\n</div>\n", directives: [{ type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }] });
2407
2630
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: NotificationComponent, decorators: [{
2408
2631
  type: Component,
2409
2632
  args: [{
@@ -2413,25 +2636,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImpor
2413
2636
  }]
2414
2637
  }], ctorParameters: function () { return []; }, propDecorators: { type: [{
2415
2638
  type: Input
2639
+ }], content: [{
2640
+ type: Input
2416
2641
  }] } });
2417
2642
 
2418
2643
  /**
2419
2644
  * The `NotificationList` component displays the list of active notifications.
2420
2645
  */
2421
2646
  class NotificationListComponent {
2422
- constructor(notificationService) {
2647
+ constructor(customTemplatesService, notificationService) {
2648
+ this.customTemplatesService = customTemplatesService;
2423
2649
  this.notificationService = notificationService;
2424
2650
  this.notifications$ = this.notificationService.notifications$;
2425
2651
  }
2426
2652
  trackById(_, item) {
2427
2653
  return item.id;
2428
2654
  }
2429
- getTemplateContext(notification) {
2655
+ getNotificationContentContext(notification) {
2430
2656
  return Object.assign(Object.assign({}, notification.templateContext), { dismissFn: notification.dismissFn });
2431
2657
  }
2432
2658
  }
2433
- NotificationListComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: NotificationListComponent, deps: [{ token: NotificationService }], target: i0.ɵɵFactoryTarget.Component });
2434
- NotificationListComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: NotificationListComponent, selector: "stream-notification-list", ngImport: i0, template: "<div class=\"str-chat__list-notifications\">\n <stream-notification\n *ngFor=\"let notification of notifications$ | async; trackBy: trackById\"\n [type]=\"notification.type\"\n >\n <div\n *ngIf=\"notification.text !== undefined\"\n data-testclass=\"notification-content\"\n >\n {{ notification.text | translate: notification.translateParams }}\n </div>\n <ng-container *ngIf=\"notification.template !== undefined\">\n <ng-container\n *ngTemplateOutlet=\"\n notification.template;\n context: getTemplateContext(notification)\n \"\n ></ng-container>\n </ng-container>\n </stream-notification>\n</div>\n", components: [{ type: NotificationComponent, selector: "stream-notification", inputs: ["type"] }], directives: [{ type: i6.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i6.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }], pipes: { "async": i6.AsyncPipe, "translate": i2.TranslatePipe } });
2659
+ NotificationListComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: NotificationListComponent, deps: [{ token: CustomTemplatesService }, { token: NotificationService }], target: i0.ɵɵFactoryTarget.Component });
2660
+ NotificationListComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: NotificationListComponent, selector: "stream-notification-list", ngImport: i0, template: "<div class=\"str-chat__list-notifications\">\n <ng-container\n *ngFor=\"let notification of notifications$ | async; trackBy: trackById\"\n >\n <ng-template #notificationContent>\n <div\n *ngIf=\"notification.text !== undefined\"\n data-testclass=\"notification-content\"\n >\n {{ notification.text | translate: notification.translateParams }}\n </div>\n <ng-container *ngIf=\"notification.template !== undefined\">\n <ng-container\n *ngTemplateOutlet=\"\n notification.template;\n context: getNotificationContentContext(notification)\n \"\n ></ng-container>\n </ng-container>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n (customTemplatesService.notificationTemplate$ | async) ||\n defaultNotification;\n context: { type: notification.type, content: notificationContent }\n \"\n ></ng-container>\n </ng-container>\n</div>\n\n<ng-template #defaultNotification let-type=\"type\" let-content=\"content\">\n <stream-notification [type]=\"type\" [content]=\"content\"></stream-notification>\n</ng-template>\n", components: [{ type: NotificationComponent, selector: "stream-notification", inputs: ["type", "content"] }], directives: [{ type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }], pipes: { "async": i3.AsyncPipe, "translate": i2.TranslatePipe } });
2435
2661
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: NotificationListComponent, decorators: [{
2436
2662
  type: Component,
2437
2663
  args: [{
@@ -2439,16 +2665,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImpor
2439
2665
  templateUrl: './notification-list.component.html',
2440
2666
  styles: [],
2441
2667
  }]
2442
- }], ctorParameters: function () { return [{ type: NotificationService }]; } });
2668
+ }], ctorParameters: function () { return [{ type: CustomTemplatesService }, { type: NotificationService }]; } });
2443
2669
 
2444
2670
  /**
2445
2671
  * The `MessageActionsBox` component displays a list of message actions (i.e edit), that can be opened or closed. You can find the [list of the supported actions](../concepts/message-interactions.mdx) in the message interaction guide.
2446
2672
  */
2447
2673
  class MessageActionsBoxComponent {
2448
- constructor(chatClientService, notificationService, channelService) {
2674
+ constructor(chatClientService, notificationService, channelService, customTemplatesService) {
2449
2675
  this.chatClientService = chatClientService;
2450
2676
  this.notificationService = notificationService;
2451
2677
  this.channelService = channelService;
2678
+ this.customTemplatesService = customTemplatesService;
2452
2679
  /**
2453
2680
  * Indicates if the list should be opened or closed. Adding a UI element to open and close the list is the parent's component responsibility.
2454
2681
  */
@@ -2470,107 +2697,122 @@ class MessageActionsBoxComponent {
2470
2697
  */
2471
2698
  this.isEditing = new EventEmitter();
2472
2699
  this.isEditModalOpen = false;
2700
+ this.subscriptions = [];
2701
+ this.visibleMessageActionItems = [];
2702
+ this.sendMessageSubject = new Subject();
2473
2703
  this.modalClosed = () => {
2474
2704
  this.isEditModalOpen = false;
2475
2705
  this.isEditing.emit(false);
2476
2706
  };
2707
+ this.subscriptions.push(this.customTemplatesService.messageInputTemplate$.subscribe((template) => (this.messageInputTemplate = template)));
2708
+ this.subscriptions.push(this.customTemplatesService.messageActionsBoxItemTemplate$.subscribe((template) => (this.messageActionItemTemplate = template)));
2709
+ this.subscriptions.push(this.customTemplatesService.modalTemplate$.subscribe((template) => (this.modalTemplate = template)));
2710
+ this.messageActionItems = [
2711
+ {
2712
+ actionName: 'quote',
2713
+ actionLabelOrTranslationKey: 'streamChat.Reply',
2714
+ actionHandler: (message) => this.channelService.selectMessageToQuote(message),
2715
+ isVisible: (enabledActions, isMine, message) => enabledActions.indexOf('quote-message') !== -1 &&
2716
+ !(message === null || message === void 0 ? void 0 : message.quoted_message),
2717
+ },
2718
+ {
2719
+ actionName: 'pin',
2720
+ actionLabelOrTranslationKey: () => { var _a; return ((_a = this.message) === null || _a === void 0 ? void 0 : _a.pinned) ? 'streamChat.Unpin' : 'streamChat.Pin'; },
2721
+ actionHandler: () => alert('Feature not yet implemented'),
2722
+ isVisible: () => false,
2723
+ },
2724
+ {
2725
+ actionName: 'flag',
2726
+ actionLabelOrTranslationKey: 'streamChat.Flag',
2727
+ actionHandler: (message) => __awaiter(this, void 0, void 0, function* () {
2728
+ try {
2729
+ yield this.chatClientService.flagMessage(message.id);
2730
+ this.notificationService.addTemporaryNotification('streamChat.Message has been successfully flagged', 'success');
2731
+ }
2732
+ catch (err) {
2733
+ this.notificationService.addTemporaryNotification('streamChat.Error adding flag');
2734
+ }
2735
+ }),
2736
+ isVisible: (enabledActions, isMine) => enabledActions.indexOf('flag-message') !== -1 && !isMine,
2737
+ },
2738
+ {
2739
+ actionName: 'edit',
2740
+ actionLabelOrTranslationKey: 'streamChat.Edit Message',
2741
+ actionHandler: () => {
2742
+ this.isEditing.emit(true);
2743
+ this.isEditModalOpen = true;
2744
+ },
2745
+ isVisible: (enabledActions, isMine) => (enabledActions.indexOf('update-own-message') !== -1 && isMine) ||
2746
+ enabledActions.indexOf('update-any-message') !== -1,
2747
+ },
2748
+ {
2749
+ actionName: 'delete',
2750
+ actionLabelOrTranslationKey: 'streamChat.Delete',
2751
+ actionHandler: (message) => __awaiter(this, void 0, void 0, function* () {
2752
+ try {
2753
+ yield this.channelService.deleteMessage(message);
2754
+ }
2755
+ catch (error) {
2756
+ this.notificationService.addTemporaryNotification('streamChat.Error deleting message');
2757
+ }
2758
+ }),
2759
+ isVisible: (enabledActions, isMine) => ((enabledActions.indexOf('delete') !== -1 ||
2760
+ enabledActions.indexOf('delete-own-message') !== -1) &&
2761
+ isMine) ||
2762
+ enabledActions.indexOf('delete-any') !== -1 ||
2763
+ enabledActions.indexOf('delete-any-message') !== -1,
2764
+ },
2765
+ ];
2766
+ this.sendMessage$ = this.sendMessageSubject.asObservable();
2477
2767
  }
2478
2768
  ngOnChanges(changes) {
2479
- if (changes.isMine || changes.enabledActions) {
2480
- let displayedActionsCount = 0;
2481
- if (this.isQuoteVisible) {
2482
- displayedActionsCount++;
2483
- }
2484
- if (this.isEditVisible) {
2485
- displayedActionsCount++;
2486
- }
2487
- if (this.isDeleteVisible) {
2488
- displayedActionsCount++;
2489
- }
2490
- if (this.isMuteVisible) {
2491
- displayedActionsCount++;
2492
- }
2493
- if (this.isFlagVisible) {
2494
- displayedActionsCount++;
2495
- }
2496
- if (this.isPinVisible) {
2497
- displayedActionsCount++;
2498
- }
2499
- this.displayedActionsCount.next(displayedActionsCount);
2769
+ if (changes.isMine || changes.enabledActions || changes.message) {
2770
+ this.messageActionItems.forEach((i) => (i.actionHandler = i.actionHandler.bind(this, this.message, this.isMine)));
2771
+ this.visibleMessageActionItems = this.messageActionItems.filter((item) => item.isVisible(this.enabledActions, this.isMine, this.message));
2772
+ this.displayedActionsCount.emit(this.visibleMessageActionItems.length);
2500
2773
  }
2501
2774
  }
2502
- get isQuoteVisible() {
2503
- var _a;
2504
- return ((this.enabledActions.indexOf('quote') !== -1 ||
2505
- this.enabledActions.indexOf('quote-message') !== -1) &&
2506
- !((_a = this.message) === null || _a === void 0 ? void 0 : _a.quoted_message));
2507
- }
2508
- get isEditVisible() {
2509
- return (((this.enabledActions.indexOf('edit') !== -1 ||
2510
- this.enabledActions.indexOf('update-own-message') !== -1) &&
2511
- this.isMine) ||
2512
- this.enabledActions.indexOf('edit-any') !== -1 ||
2513
- this.enabledActions.indexOf('update-any-message') !== -1);
2514
- }
2515
- get isDeleteVisible() {
2516
- return (((this.enabledActions.indexOf('delete') !== -1 ||
2517
- this.enabledActions.indexOf('delete-own-message') !== -1) &&
2518
- this.isMine) ||
2519
- this.enabledActions.indexOf('delete-any') !== -1 ||
2520
- this.enabledActions.indexOf('delete-any-message') !== -1);
2521
- }
2522
- get isMuteVisible() {
2523
- return this.enabledActions.indexOf('mute') !== -1;
2524
- }
2525
- get isFlagVisible() {
2526
- return ((this.enabledActions.indexOf('flag') !== -1 ||
2527
- this.enabledActions.indexOf('flag-message') !== -1) &&
2528
- !this.isMine);
2529
- }
2530
- get isPinVisible() {
2531
- return this.enabledActions.indexOf('pin') !== -1;
2532
- }
2533
- pinClicked() {
2534
- alert('Feature not yet implemented');
2535
- }
2536
- flagClicked() {
2537
- return __awaiter(this, void 0, void 0, function* () {
2538
- try {
2539
- yield this.chatClientService.flagMessage(this.message.id);
2540
- this.notificationService.addTemporaryNotification('streamChat.Message has been successfully flagged', 'success');
2541
- }
2542
- catch (err) {
2543
- this.notificationService.addTemporaryNotification('streamChat.Error adding flag');
2544
- }
2545
- });
2775
+ ngOnDestroy() {
2776
+ this.subscriptions.forEach((s) => s.unsubscribe());
2546
2777
  }
2547
- muteClicked() {
2548
- alert('Feature not yet implemented');
2778
+ getActionLabel(actionLabelOrTranslationKey) {
2779
+ return typeof actionLabelOrTranslationKey === 'string'
2780
+ ? actionLabelOrTranslationKey
2781
+ : actionLabelOrTranslationKey();
2549
2782
  }
2550
- quoteClicked() {
2551
- this.channelService.selectMessageToQuote(this.message);
2783
+ sendClicked() {
2784
+ this.sendMessageSubject.next();
2552
2785
  }
2553
- editClicked() {
2554
- this.isEditing.emit(true);
2555
- this.isEditModalOpen = true;
2786
+ getMessageInputContext() {
2787
+ return {
2788
+ message: this.message,
2789
+ messageUpdateHandler: this.modalClosed,
2790
+ isFileUploadEnabled: undefined,
2791
+ areMentionsEnabled: undefined,
2792
+ isMultipleFileUploadEnabled: undefined,
2793
+ mentionScope: undefined,
2794
+ mode: undefined,
2795
+ sendMessage$: this.sendMessage$,
2796
+ };
2556
2797
  }
2557
- sendClicked() {
2558
- var _a;
2559
- (_a = this.messageInput) === null || _a === void 0 ? void 0 : _a.messageSent();
2798
+ getEditModalContext() {
2799
+ return {
2800
+ isOpen: this.isEditModalOpen,
2801
+ isOpenChangeHandler: (isOpen) => {
2802
+ this.isEditModalOpen = isOpen;
2803
+ if (!this.isEditModalOpen) {
2804
+ this.modalClosed();
2805
+ }
2806
+ },
2807
+ content: this.modalContent,
2808
+ };
2560
2809
  }
2561
- deleteClicked() {
2562
- return __awaiter(this, void 0, void 0, function* () {
2563
- try {
2564
- yield this.channelService.deleteMessage(this.message);
2565
- }
2566
- catch (error) {
2567
- this.notificationService.addTemporaryNotification('streamChat.Error deleting message');
2568
- }
2569
- });
2810
+ trackByActionName(_, item) {
2811
+ return item.actionName;
2570
2812
  }
2571
2813
  }
2572
- MessageActionsBoxComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: MessageActionsBoxComponent, deps: [{ token: ChatClientService }, { token: NotificationService }, { token: ChannelService }], target: i0.ɵɵFactoryTarget.Component });
2573
- MessageActionsBoxComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: MessageActionsBoxComponent, selector: "stream-message-actions-box", inputs: { messageInputTemplate: "messageInputTemplate", isOpen: "isOpen", isMine: "isMine", message: "message", enabledActions: "enabledActions" }, outputs: { displayedActionsCount: "displayedActionsCount", isEditing: "isEditing" }, viewQueries: [{ propertyName: "messageInput", first: true, predicate: MessageInputComponent, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\n data-testid=\"action-box\"\n class=\"str-chat__message-actions-box\"\n [class.str-chat__message-actions-box--open]=\"isOpen\"\n [class.str-chat__message-actions-box--mine]=\"isMine\"\n>\n <ul class=\"str-chat__message-actions-list\">\n <button\n data-testid=\"quote-action\"\n *ngIf=\"isQuoteVisible\"\n (click)=\"quoteClicked()\"\n >\n <li class=\"str-chat__message-actions-list-item\">\n {{ \"streamChat.Reply\" | translate }}\n </li>\n </button>\n <button\n data-testid=\"pin-action\"\n *ngIf=\"isPinVisible\"\n (click)=\"pinClicked()\"\n >\n <li class=\"str-chat__message-actions-list-item\">\n {{\n (message?.pinned ? \"streamChat.Unpin\" : \"streamChat.Pin\") | translate\n }}\n </li>\n </button>\n <button\n data-testid=\"flag-action\"\n *ngIf=\"isFlagVisible\"\n (click)=\"flagClicked()\"\n >\n <li class=\"str-chat__message-actions-list-item\">\n {{ \"streamChat.Flag\" | translate }}\n </li>\n </button>\n <button\n data-testid=\"mute-action\"\n *ngIf=\"isMuteVisible\"\n (click)=\"muteClicked()\"\n >\n <li class=\"str-chat__message-actions-list-item\">\n {{ \"streamChat.Mute\" | translate }}\n </li>\n </button>\n <button\n data-testid=\"edit-action\"\n *ngIf=\"isEditVisible\"\n (click)=\"editClicked()\"\n >\n <li class=\"str-chat__message-actions-list-item\">\n {{ \"streamChat.Edit Message\" | translate }}\n </li>\n </button>\n <button\n data-testid=\"delete-action\"\n *ngIf=\"isDeleteVisible\"\n (click)=\"deleteClicked()\"\n >\n <li class=\"str-chat__message-actions-list-item\">\n {{ \"streamChat.Delete\" | translate }}\n </li>\n </button>\n </ul>\n</div>\n\n<stream-modal\n [isOpen]=\"isEditModalOpen\"\n (isOpenChange)=\"\n isEditModalOpen = $event; isEditModalOpen ? '' : modalClosed()\n \"\n>\n <div class=\"str-chat__edit-message-form\" *ngIf=\"isEditModalOpen\">\n <ng-container *ngIf=\"messageInputTemplate; else defaultInput\">\n <ng-container\n *ngTemplateOutlet=\"\n messageInputTemplate;\n context: {\n message: message,\n messageUpdateHandler: modalClosed\n }\n \"\n ></ng-container>\n </ng-container>\n <ng-template #defaultInput>\n <stream-message-input\n [message]=\"message\"\n (messageUpdate)=\"modalClosed()\"\n ></stream-message-input>\n </ng-template>\n <stream-notification-list></stream-notification-list>\n <div\n class=\"\n str-chat__message-team-form-footer\n str-chat__message-team-form-footer-angular\n \"\n >\n <div class=\"str-chat__edit-message-form-options\">\n <button translate data-testid=\"cancel-button\" (click)=\"modalClosed()\">\n streamChat.Cancel\n </button>\n <button\n type=\"submit\"\n translate\n data-testid=\"send-button\"\n (click)=\"sendClicked()\"\n (keyup.enter)=\"sendClicked()\"\n >\n streamChat.Send\n </button>\n </div>\n </div>\n </div>\n</stream-modal>\n", components: [{ type: ModalComponent, selector: "stream-modal", inputs: ["isOpen"], outputs: ["isOpenChange"] }, { type: MessageInputComponent, selector: "stream-message-input", inputs: ["isFileUploadEnabled", "areMentionsEnabled", "mentionScope", "mentionAutocompleteItemTemplate", "commandAutocompleteItemTemplate", "emojiPickerTemplate", "mode", "acceptedFileTypes", "isMultipleFileUploadEnabled", "message"], outputs: ["messageUpdate"] }, { type: NotificationListComponent, selector: "stream-notification-list" }], directives: [{ type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i6.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i2.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }], pipes: { "translate": i2.TranslatePipe } });
2814
+ MessageActionsBoxComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: MessageActionsBoxComponent, deps: [{ token: ChatClientService }, { token: NotificationService }, { token: ChannelService }, { token: CustomTemplatesService }], target: i0.ɵɵFactoryTarget.Component });
2815
+ MessageActionsBoxComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: MessageActionsBoxComponent, selector: "stream-message-actions-box", inputs: { isOpen: "isOpen", isMine: "isMine", message: "message", enabledActions: "enabledActions" }, outputs: { displayedActionsCount: "displayedActionsCount", isEditing: "isEditing" }, viewQueries: [{ propertyName: "modalContent", first: true, predicate: ["modalContent"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: "<div\n data-testid=\"action-box\"\n class=\"str-chat__message-actions-box\"\n [class.str-chat__message-actions-box--open]=\"isOpen\"\n [class.str-chat__message-actions-box--mine]=\"isMine\"\n>\n <ul class=\"str-chat__message-actions-list\">\n <ng-container\n *ngFor=\"let item of visibleMessageActionItems; trackBy: trackByActionName\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n messageActionItemTemplate || defaultMessageActionItem;\n context: item\n \"\n ></ng-container>\n </ng-container>\n </ul>\n</div>\n\n<ng-template\n #defaultMessageActionItem\n let-actionName=\"actionName\"\n let-actionHandler=\"actionHandler\"\n let-actionLabelOrTranslationKey=\"actionLabelOrTranslationKey\"\n>\n <button [attr.data-testid]=\"actionName + '-action'\" (click)=\"actionHandler()\">\n <li class=\"str-chat__message-actions-list-item\">\n {{ getActionLabel(actionLabelOrTranslationKey) | translate }}\n </li>\n </button>\n</ng-template>\n\n<ng-container\n *ngTemplateOutlet=\"\n modalTemplate || defaultModal;\n context: getEditModalContext()\n \"\n></ng-container>\n\n<ng-template\n #defaultModal\n let-isOpen=\"isOpen\"\n let-isOpenChangeHandler=\"isOpenChangeHandler\"\n let-content=\"content\"\n>\n <stream-modal\n [isOpen]=\"isOpen\"\n (isOpenChange)=\"isOpenChangeHandler($event)\"\n [content]=\"content\"\n >\n </stream-modal>\n</ng-template>\n\n<ng-template #modalContent>\n <div class=\"str-chat__edit-message-form\" *ngIf=\"isEditModalOpen\">\n <ng-template\n #defaultInput\n let-messageInput=\"message\"\n let-messageUpdateHandler=\"messageUpdateHandler\"\n let-sendMessage$Input=\"sendMessage$\"\n >\n <stream-message-input\n [message]=\"messageInput\"\n (messageUpdate)=\"messageUpdateHandler()\"\n [sendMessage$]=\"sendMessage$Input\"\n ></stream-message-input>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n messageInputTemplate || defaultInput;\n context: getMessageInputContext()\n \"\n >\n </ng-container>\n\n <stream-notification-list></stream-notification-list>\n <div\n class=\"\n str-chat__message-team-form-footer\n str-chat__message-team-form-footer-angular\n \"\n >\n <div class=\"str-chat__edit-message-form-options\">\n <button translate data-testid=\"cancel-button\" (click)=\"modalClosed()\">\n streamChat.Cancel\n </button>\n <button\n type=\"submit\"\n translate\n data-testid=\"send-button\"\n (click)=\"sendClicked()\"\n (keyup.enter)=\"sendClicked()\"\n >\n streamChat.Send\n </button>\n </div>\n </div>\n </div>\n</ng-template>\n", components: [{ type: ModalComponent, selector: "stream-modal", inputs: ["isOpen", "content"], outputs: ["isOpenChange"] }, { type: MessageInputComponent, selector: "stream-message-input", inputs: ["isFileUploadEnabled", "areMentionsEnabled", "mentionScope", "mode", "isMultipleFileUploadEnabled", "message", "sendMessage$"], outputs: ["messageUpdate"] }, { type: NotificationListComponent, selector: "stream-notification-list" }], directives: [{ type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }], pipes: { "translate": i2.TranslatePipe } });
2574
2816
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: MessageActionsBoxComponent, decorators: [{
2575
2817
  type: Component,
2576
2818
  args: [{
@@ -2578,9 +2820,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImpor
2578
2820
  templateUrl: './message-actions-box.component.html',
2579
2821
  styles: [],
2580
2822
  }]
2581
- }], ctorParameters: function () { return [{ type: ChatClientService }, { type: NotificationService }, { type: ChannelService }]; }, propDecorators: { messageInputTemplate: [{
2582
- type: Input
2583
- }], isOpen: [{
2823
+ }], ctorParameters: function () { return [{ type: ChatClientService }, { type: NotificationService }, { type: ChannelService }, { type: CustomTemplatesService }]; }, propDecorators: { isOpen: [{
2584
2824
  type: Input
2585
2825
  }], isMine: [{
2586
2826
  type: Input
@@ -2592,9 +2832,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImpor
2592
2832
  type: Output
2593
2833
  }], isEditing: [{
2594
2834
  type: Output
2595
- }], messageInput: [{
2835
+ }], modalContent: [{
2596
2836
  type: ViewChild,
2597
- args: [MessageInputComponent]
2837
+ args: ['modalContent', { static: true }]
2598
2838
  }] } });
2599
2839
 
2600
2840
  /**
@@ -2610,7 +2850,7 @@ class ChannelComponent {
2610
2850
  }
2611
2851
  }
2612
2852
  ChannelComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: ChannelComponent, deps: [{ token: ChannelService }], target: i0.ɵɵFactoryTarget.Component });
2613
- ChannelComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: ChannelComponent, selector: "stream-channel", ngImport: i0, template: "<div\n *ngIf=\"(isError$ | async) === false && (isInitializing$ | async) === false\"\n class=\"str-chat str-chat-channel messaging\"\n>\n <div class=\"str-chat__container\">\n <div class=\"str-chat__main-panel\">\n <ng-content></ng-content>\n </div>\n <ng-content\n *ngIf=\"isActiveThread$ | async\"\n select='[name=\"thread\"]'\n ></ng-content>\n </div>\n</div>\n", directives: [{ type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], pipes: { "async": i6.AsyncPipe } });
2853
+ ChannelComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: ChannelComponent, selector: "stream-channel", ngImport: i0, template: "<div\n *ngIf=\"(isError$ | async) === false && (isInitializing$ | async) === false\"\n class=\"str-chat str-chat-channel messaging\"\n>\n <div class=\"str-chat__container\">\n <div class=\"str-chat__main-panel\">\n <ng-content></ng-content>\n </div>\n <ng-content\n *ngIf=\"isActiveThread$ | async\"\n select='[name=\"thread\"]'\n ></ng-content>\n </div>\n</div>\n", directives: [{ type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], pipes: { "async": i3.AsyncPipe } });
2614
2854
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: ChannelComponent, decorators: [{
2615
2855
  type: Component,
2616
2856
  args: [{
@@ -2704,9 +2944,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImpor
2704
2944
  * The `ChannelHeader` component displays the avatar and name of the currently active channel along with member and watcher information. You can read about [the difference between members and watchers](https://getstream.io/chat/docs/javascript/watch_channel/?language=javascript#watchers-vs-members) in the platform documentation. Please note that number of watchers is only displayed if the user has [`connect-events` capability](https://getstream.io/chat/docs/javascript/channel_capabilities/?language=javascript)
2705
2945
  */
2706
2946
  class ChannelHeaderComponent {
2707
- constructor(channelService, channelListToggleService) {
2947
+ constructor(channelService, channelListToggleService, customTemplatesService, cdRef) {
2708
2948
  this.channelService = channelService;
2709
2949
  this.channelListToggleService = channelListToggleService;
2950
+ this.customTemplatesService = customTemplatesService;
2951
+ this.cdRef = cdRef;
2952
+ this.subscriptions = [];
2710
2953
  this.channelService.activeChannel$.subscribe((c) => {
2711
2954
  var _a, _b;
2712
2955
  this.activeChannel = c;
@@ -2718,10 +2961,22 @@ class ChannelHeaderComponent {
2718
2961
  capabilities.indexOf('connect-events') !== -1;
2719
2962
  });
2720
2963
  }
2964
+ ngOnInit() {
2965
+ this.subscriptions.push(this.customTemplatesService.channelActionsTemplate$.subscribe((template) => {
2966
+ this.channelActionsTemplate = template;
2967
+ this.cdRef.detectChanges();
2968
+ }));
2969
+ }
2970
+ ngOnDestroy() {
2971
+ this.subscriptions.forEach((s) => s.unsubscribe());
2972
+ }
2721
2973
  toggleMenu(event) {
2722
2974
  event.stopPropagation();
2723
2975
  this.channelListToggleService.toggle();
2724
2976
  }
2977
+ getChannelActionsContext() {
2978
+ return { channel: this.activeChannel };
2979
+ }
2725
2980
  get memberCountParam() {
2726
2981
  var _a, _b;
2727
2982
  return { memberCount: ((_b = (_a = this.activeChannel) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.member_count) || 0 };
@@ -2731,8 +2986,8 @@ class ChannelHeaderComponent {
2731
2986
  return { watcherCount: ((_b = (_a = this.activeChannel) === null || _a === void 0 ? void 0 : _a.state) === null || _b === void 0 ? void 0 : _b.watcher_count) || 0 };
2732
2987
  }
2733
2988
  }
2734
- ChannelHeaderComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: ChannelHeaderComponent, deps: [{ token: ChannelService }, { token: ChannelListToggleService }], target: i0.ɵɵFactoryTarget.Component });
2735
- ChannelHeaderComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: ChannelHeaderComponent, selector: "stream-channel-header", inputs: { channelActionsTemplate: "channelActionsTemplate" }, ngImport: i0, template: "<div class=\"str-chat__header-livestream\">\n <div\n class=\"str-chat__header-hamburger\"\n (click)=\"toggleMenu($event)\"\n (keyup.enter)=\"toggleMenu($event)\"\n >\n <stream-icon icon=\"menu\"></stream-icon>\n </div>\n <stream-avatar\n imageUrl=\"{{ activeChannel?.data?.image }}\"\n name=\"{{ activeChannel?.data?.name }}\"\n ></stream-avatar>\n <div class=\"str-chat__header-livestream-left\">\n <p data-testid=\"name\" class=\"str-chat__header-livestream-left--title\">\n {{ activeChannel?.data?.name }}\n </p>\n <p data-testid=\"info\" class=\"str-chat__header-livestream-left--members\">\n {{'streamChat.{{ memberCount }} members' | translate:memberCountParam}}\n {{canReceiveConnectEvents ? ('streamChat.{{ watcherCount }} online' |\n translate:watcherCountParam) : ''}}\n </p>\n </div>\n <ng-container *ngIf=\"channelActionsTemplate\">\n <ng-container\n *ngTemplateOutlet=\"\n channelActionsTemplate;\n context: { channel: activeChannel }\n \"\n ></ng-container>\n </ng-container>\n</div>\n", components: [{ type: IconComponent, selector: "stream-icon", inputs: ["icon", "size"] }, { type: AvatarComponent, selector: "stream-avatar", inputs: ["name", "imageUrl", "size"] }], directives: [{ type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i6.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }], pipes: { "translate": i2.TranslatePipe } });
2989
+ ChannelHeaderComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: ChannelHeaderComponent, deps: [{ token: ChannelService }, { token: ChannelListToggleService }, { token: CustomTemplatesService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
2990
+ ChannelHeaderComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: ChannelHeaderComponent, selector: "stream-channel-header", ngImport: i0, template: "<div class=\"str-chat__header-livestream\">\n <div\n class=\"str-chat__header-hamburger\"\n (click)=\"toggleMenu($event)\"\n (keyup.enter)=\"toggleMenu($event)\"\n >\n <stream-icon-placeholder icon=\"menu\"></stream-icon-placeholder>\n </div>\n <stream-avatar-placeholder\n imageUrl=\"{{ activeChannel?.data?.image }}\"\n name=\"{{ activeChannel?.data?.name }}\"\n ></stream-avatar-placeholder>\n <div class=\"str-chat__header-livestream-left\">\n <p data-testid=\"name\" class=\"str-chat__header-livestream-left--title\">\n {{ activeChannel?.data?.name }}\n </p>\n <p data-testid=\"info\" class=\"str-chat__header-livestream-left--members\">\n {{'streamChat.{{ memberCount }} members' | translate:memberCountParam}}\n {{canReceiveConnectEvents ? ('streamChat.{{ watcherCount }} online' |\n translate:watcherCountParam) : ''}}\n </p>\n </div>\n <ng-container *ngIf=\"channelActionsTemplate\">\n <ng-container\n *ngTemplateOutlet=\"\n channelActionsTemplate;\n context: getChannelActionsContext()\n \"\n ></ng-container>\n </ng-container>\n</div>\n", components: [{ type: IconPlaceholderComponent, selector: "stream-icon-placeholder", inputs: ["icon", "size"] }, { type: AvatarPlaceholderComponent, selector: "stream-avatar-placeholder", inputs: ["name", "imageUrl", "size"] }], directives: [{ type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }], pipes: { "translate": i2.TranslatePipe } });
2736
2991
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: ChannelHeaderComponent, decorators: [{
2737
2992
  type: Component,
2738
2993
  args: [{
@@ -2740,9 +2995,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImpor
2740
2995
  templateUrl: './channel-header.component.html',
2741
2996
  styles: [],
2742
2997
  }]
2743
- }], ctorParameters: function () { return [{ type: ChannelService }, { type: ChannelListToggleService }]; }, propDecorators: { channelActionsTemplate: [{
2744
- type: Input
2745
- }] } });
2998
+ }], ctorParameters: function () { return [{ type: ChannelService }, { type: ChannelListToggleService }, { type: CustomTemplatesService }, { type: i0.ChangeDetectorRef }]; } });
2746
2999
 
2747
3000
  /**
2748
3001
  * The `ChannelPreview` component displays a channel preview in the channel list, it consists of the image, name and latest message of the channel.
@@ -2822,7 +3075,7 @@ class ChannelPreviewComponent {
2822
3075
  }
2823
3076
  }
2824
3077
  ChannelPreviewComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: ChannelPreviewComponent, deps: [{ token: ChannelService }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component });
2825
- ChannelPreviewComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: ChannelPreviewComponent, selector: "stream-channel-preview", inputs: { channel: "channel" }, ngImport: i0, template: "<button\n class=\"str-chat__channel-preview-messenger\"\n [class.str-chat__channel-preview-messenger--active]=\"isActive\"\n [class.str-chat__channel-preview-messenger--unread]=\"isUnread\"\n (click)=\"setAsActiveChannel()\"\n data-testid=\"channel-preview-container\"\n>\n <div class=\"str-chat__channel-preview-messenger--left\">\n <stream-avatar\n imageUrl=\"{{ avatarImage }}\"\n name=\"{{ avatarName }}\"\n [size]=\"40\"\n ></stream-avatar>\n </div>\n <div class=\"str-chat__channel-preview-messenger--right\">\n <div class=\"str-chat__channel-preview-messenger--name\">\n <span data-testid=\"channel-preview-title\">{{ title }}</span>\n </div>\n <div\n data-testid=\"latest-message\"\n class=\"str-chat__channel-preview-messenger--last-message\"\n >\n {{ latestMessage | translate }}\n </div>\n </div>\n</button>\n", components: [{ type: AvatarComponent, selector: "stream-avatar", inputs: ["name", "imageUrl", "size"] }], pipes: { "translate": i2.TranslatePipe } });
3078
+ ChannelPreviewComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: ChannelPreviewComponent, selector: "stream-channel-preview", inputs: { channel: "channel" }, ngImport: i0, template: "<button\n class=\"str-chat__channel-preview-messenger\"\n [class.str-chat__channel-preview-messenger--active]=\"isActive\"\n [class.str-chat__channel-preview-messenger--unread]=\"isUnread\"\n (click)=\"setAsActiveChannel()\"\n data-testid=\"channel-preview-container\"\n>\n <div class=\"str-chat__channel-preview-messenger--left\">\n <stream-avatar-placeholder\n imageUrl=\"{{ avatarImage }}\"\n name=\"{{ avatarName }}\"\n [size]=\"40\"\n ></stream-avatar-placeholder>\n </div>\n <div class=\"str-chat__channel-preview-messenger--right\">\n <div class=\"str-chat__channel-preview-messenger--name\">\n <span data-testid=\"channel-preview-title\">{{ title }}</span>\n </div>\n <div\n data-testid=\"latest-message\"\n class=\"str-chat__channel-preview-messenger--last-message\"\n >\n {{ latestMessage | translate }}\n </div>\n </div>\n</button>\n", components: [{ type: AvatarPlaceholderComponent, selector: "stream-avatar-placeholder", inputs: ["name", "imageUrl", "size"] }], pipes: { "translate": i2.TranslatePipe } });
2826
3079
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: ChannelPreviewComponent, decorators: [{
2827
3080
  type: Component,
2828
3081
  args: [{
@@ -2838,19 +3091,25 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImpor
2838
3091
  * The `ChannelList` component renders the list of channels.
2839
3092
  */
2840
3093
  class ChannelListComponent {
2841
- constructor(channelService, channelListToggleService) {
3094
+ constructor(channelService, channelListToggleService, customTemplatesService) {
2842
3095
  this.channelService = channelService;
2843
3096
  this.channelListToggleService = channelListToggleService;
3097
+ this.customTemplatesService = customTemplatesService;
2844
3098
  this.isLoadingMoreChannels = false;
3099
+ this.subscriptions = [];
2845
3100
  this.isOpen$ = this.channelListToggleService.isOpen$;
2846
3101
  this.channels$ = this.channelService.channels$;
2847
3102
  this.hasMoreChannels$ = this.channelService.hasMoreChannels$;
2848
3103
  this.isError$ = this.channels$.pipe(map(() => false), catchError(() => of(true)), startWith(false));
2849
3104
  this.isInitializing$ = this.channels$.pipe(map((channels) => !channels), catchError(() => of(false)));
3105
+ this.subscriptions.push(this.customTemplatesService.channelPreviewTemplate$.subscribe((template) => (this.customChannelPreviewTemplate = template)));
2850
3106
  }
2851
3107
  ngAfterViewInit() {
2852
3108
  this.channelListToggleService.setMenuElement(this.container.nativeElement);
2853
3109
  }
3110
+ ngOnDestroy() {
3111
+ this.subscriptions.forEach((s) => s.unsubscribe());
3112
+ }
2854
3113
  loadMoreChannels() {
2855
3114
  return __awaiter(this, void 0, void 0, function* () {
2856
3115
  this.isLoadingMoreChannels = true;
@@ -2864,9 +3123,14 @@ class ChannelListComponent {
2864
3123
  channelSelected() {
2865
3124
  this.channelListToggleService.channelSelected();
2866
3125
  }
3126
+ getChannelPreviewContext(channel) {
3127
+ return {
3128
+ channel,
3129
+ };
3130
+ }
2867
3131
  }
2868
- ChannelListComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: ChannelListComponent, deps: [{ token: ChannelService }, { token: ChannelListToggleService }], target: i0.ɵɵFactoryTarget.Component });
2869
- ChannelListComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: ChannelListComponent, selector: "stream-channel-list", inputs: { customChannelPreviewTemplate: "customChannelPreviewTemplate" }, viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true }], ngImport: i0, template: "<div\n #container\n data-testid=\"channel-list-container\"\n class=\"str-chat str-chat-channel-list messaging\"\n [class.str-chat-channel-list--open]=\"(isOpen$ | async) === true\"\n>\n <div\n *ngIf=\"\n (isError$ | async) === false && (isInitializing$ | async) === false;\n else statusIndicator\n \"\n class=\"str-chat__channel-list-messenger\"\n >\n <div class=\"str-chat__channel-list-messenger__main\">\n <p\n data-testid=\"empty-channel-list-indicator\"\n *ngIf=\"!(channels$ | async)?.length\"\n >\n {{ \"streamChat.You have no channels currently\" | translate }}\n </p>\n <ng-container\n *ngFor=\"let channel of channels$ | async; trackBy: trackByChannelId\"\n >\n <ng-container\n *ngIf=\"customChannelPreviewTemplate; else defaultTemplate\"\n >\n <div (click)=\"channelSelected()\" (keyup.enter)=\"channelSelected()\">\n <ng-container\n *ngTemplateOutlet=\"\n customChannelPreviewTemplate;\n context: { channel: channel }\n \"\n ></ng-container>\n </div>\n </ng-container>\n <ng-template #defaultTemplate>\n <stream-channel-preview\n data-testclass=\"channel-preview\"\n [channel]=\"channel\"\n (click)=\"channelSelected()\"\n (keyup.enter)=\"channelSelected()\"\n ></stream-channel-preview>\n </ng-template>\n </ng-container>\n <div\n *ngIf=\"hasMoreChannels$ | async\"\n class=\"str-chat__load-more-button\"\n (click)=\"loadMoreChannels()\"\n (keyup.enter)=\"loadMoreChannels()\"\n data-testid=\"load-more\"\n >\n <button\n class=\"str-chat__load-more-button__button\"\n data-testid=\"load-more-button\"\n [disabled]=\"isLoadingMoreChannels\"\n >\n <span *ngIf=\"!isLoadingMoreChannels; else loadingIndicator\">{{\n \"Load more\" | translate\n }}</span>\n <ng-template #loadingIndicator\n ><stream-loading-indicator></stream-loading-indicator\n ></ng-template>\n </button>\n </div>\n </div>\n </div>\n</div>\n\n<ng-template #statusIndicator>\n <ng-container *ngIf=\"isError$ | async\">\n <ng-container *ngTemplateOutlet=\"chatDown\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"isInitializing$ | async\">\n <ng-container *ngTemplateOutlet=\"loadingChannels\"></ng-container>\n </ng-container>\n</ng-template>\n\n<ng-template #chatDown>\n <div data-testid=\"chatdown-container\" class=\"str-chat__down\">\n <ng-container *ngTemplateOutlet=\"loadingChannels\"></ng-container>\n <div class=\"str-chat__down-main\">\n <stream-icon icon=\"connection-error\"></stream-icon>\n <h1>{{ \"streamChat.Connection error\" | translate }}</h1>\n <h3>\n {{\n \"streamChat.Error connecting to chat, refresh the page to try again.\"\n | translate\n }}\n </h3>\n </div>\n </div>\n</ng-template>\n\n<ng-template #loadingChannels>\n <div data-testid=\"loading-indicator\" class=\"str-chat__loading-channels\">\n <ng-container *ngTemplateOutlet=\"loadingChannel\"></ng-container>\n <ng-container *ngTemplateOutlet=\"loadingChannel\"></ng-container>\n <ng-container *ngTemplateOutlet=\"loadingChannel\"></ng-container>\n </div>\n</ng-template>\n\n<ng-template #loadingChannel>\n <div class=\"str-chat__loading-channels-item\">\n <div class=\"str-chat__loading-channels-avatar\"></div>\n <div class=\"str-chat__loading-channels-meta\">\n <div class=\"str-chat__loading-channels-username\"></div>\n <div class=\"str-chat__loading-channels-status\"></div>\n </div>\n </div>\n</ng-template>\n", components: [{ type: ChannelPreviewComponent, selector: "stream-channel-preview", inputs: ["channel"] }, { type: LoadingIndicatorComponent, selector: "stream-loading-indicator", inputs: ["size", "color"] }, { type: IconComponent, selector: "stream-icon", inputs: ["icon", "size"] }], directives: [{ type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i6.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i6.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }], pipes: { "async": i6.AsyncPipe, "translate": i2.TranslatePipe } });
3132
+ ChannelListComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: ChannelListComponent, deps: [{ token: ChannelService }, { token: ChannelListToggleService }, { token: CustomTemplatesService }], target: i0.ɵɵFactoryTarget.Component });
3133
+ ChannelListComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: ChannelListComponent, selector: "stream-channel-list", viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true }], ngImport: i0, template: "<div\n #container\n data-testid=\"channel-list-container\"\n class=\"str-chat str-chat-channel-list messaging\"\n [class.str-chat-channel-list--open]=\"(isOpen$ | async) === true\"\n>\n <div\n *ngIf=\"\n (isError$ | async) === false && (isInitializing$ | async) === false;\n else statusIndicator\n \"\n class=\"str-chat__channel-list-messenger\"\n >\n <div class=\"str-chat__channel-list-messenger__main\">\n <p\n data-testid=\"empty-channel-list-indicator\"\n *ngIf=\"!(channels$ | async)?.length\"\n >\n {{ \"streamChat.You have no channels currently\" | translate }}\n </p>\n <ng-container\n *ngFor=\"let channel of channels$ | async; trackBy: trackByChannelId\"\n >\n <ng-template #defaultTemplate let-channelInput=\"channel\">\n <stream-channel-preview\n data-testclass=\"channel-preview\"\n [channel]=\"channelInput\"\n ></stream-channel-preview>\n </ng-template>\n <div (click)=\"channelSelected()\" (keyup.enter)=\"channelSelected()\">\n <ng-container\n *ngTemplateOutlet=\"\n customChannelPreviewTemplate || defaultTemplate;\n context: getChannelPreviewContext(channel)\n \"\n ></ng-container>\n </div>\n </ng-container>\n <div\n *ngIf=\"hasMoreChannels$ | async\"\n class=\"str-chat__load-more-button\"\n (click)=\"loadMoreChannels()\"\n (keyup.enter)=\"loadMoreChannels()\"\n data-testid=\"load-more\"\n >\n <button\n class=\"str-chat__load-more-button__button\"\n data-testid=\"load-more-button\"\n [disabled]=\"isLoadingMoreChannels\"\n >\n <span *ngIf=\"!isLoadingMoreChannels; else loadingIndicator\">{{\n \"Load more\" | translate\n }}</span>\n <ng-template #loadingIndicator\n ><stream-loading-indicator-placeholder></stream-loading-indicator-placeholder\n ></ng-template>\n </button>\n </div>\n </div>\n </div>\n</div>\n\n<ng-template #statusIndicator>\n <ng-container *ngIf=\"isError$ | async\">\n <ng-container *ngTemplateOutlet=\"chatDown\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"isInitializing$ | async\">\n <ng-container *ngTemplateOutlet=\"loadingChannels\"></ng-container>\n </ng-container>\n</ng-template>\n\n<ng-template #chatDown>\n <div data-testid=\"chatdown-container\" class=\"str-chat__down\">\n <ng-container *ngTemplateOutlet=\"loadingChannels\"></ng-container>\n <div class=\"str-chat__down-main\">\n <stream-icon-placeholder\n icon=\"connection-error\"\n ></stream-icon-placeholder>\n <h1>{{ \"streamChat.Connection error\" | translate }}</h1>\n <h3>\n {{\n \"streamChat.Error connecting to chat, refresh the page to try again.\"\n | translate\n }}\n </h3>\n </div>\n </div>\n</ng-template>\n\n<ng-template #loadingChannels>\n <div data-testid=\"loading-indicator\" class=\"str-chat__loading-channels\">\n <ng-container *ngTemplateOutlet=\"loadingChannel\"></ng-container>\n <ng-container *ngTemplateOutlet=\"loadingChannel\"></ng-container>\n <ng-container *ngTemplateOutlet=\"loadingChannel\"></ng-container>\n </div>\n</ng-template>\n\n<ng-template #loadingChannel>\n <div class=\"str-chat__loading-channels-item\">\n <div class=\"str-chat__loading-channels-avatar\"></div>\n <div class=\"str-chat__loading-channels-meta\">\n <div class=\"str-chat__loading-channels-username\"></div>\n <div class=\"str-chat__loading-channels-status\"></div>\n </div>\n </div>\n</ng-template>\n", components: [{ type: ChannelPreviewComponent, selector: "stream-channel-preview", inputs: ["channel"] }, { type: LoadingIndicatorPlaceholderComponent, selector: "stream-loading-indicator-placeholder", inputs: ["size", "color"] }, { type: IconPlaceholderComponent, selector: "stream-icon-placeholder", inputs: ["icon", "size"] }], directives: [{ type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }], pipes: { "async": i3.AsyncPipe, "translate": i2.TranslatePipe } });
2870
3134
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: ChannelListComponent, decorators: [{
2871
3135
  type: Component,
2872
3136
  args: [{
@@ -2874,9 +3138,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImpor
2874
3138
  templateUrl: './channel-list.component.html',
2875
3139
  styles: [],
2876
3140
  }]
2877
- }], ctorParameters: function () { return [{ type: ChannelService }, { type: ChannelListToggleService }]; }, propDecorators: { customChannelPreviewTemplate: [{
2878
- type: Input
2879
- }], container: [{
3141
+ }], ctorParameters: function () { return [{ type: ChannelService }, { type: ChannelListToggleService }, { type: CustomTemplatesService }]; }, propDecorators: { container: [{
2880
3142
  type: ViewChild,
2881
3143
  args: ['container']
2882
3144
  }] } });
@@ -3035,7 +3297,7 @@ class MessageReactionsComponent {
3035
3297
  }
3036
3298
  }
3037
3299
  MessageReactionsComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: MessageReactionsComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: ChannelService }], target: i0.ɵɵFactoryTarget.Component });
3038
- MessageReactionsComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: MessageReactionsComponent, selector: "stream-message-reactions", inputs: { messageId: "messageId", messageReactionCounts: "messageReactionCounts", isSelectorOpen: "isSelectorOpen", latestReactions: "latestReactions", ownReactions: "ownReactions" }, outputs: { isSelectorOpenChange: "isSelectorOpenChange" }, viewQueries: [{ propertyName: "selectorContainer", first: true, predicate: ["selectorContainer"], descendants: true }, { propertyName: "selectorTooltip", first: true, predicate: ["selectorTooltip"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\n *ngIf=\"existingReactions.length > 0 && !isSelectorOpen\"\n class=\"str-chat__reaction-list\"\n [class.str-chat__reaction-list--reverse]=\"true\"\n data-testid=\"reaction-list\"\n>\n <ul>\n <li\n *ngFor=\"\n let reactionType of existingReactions;\n trackBy: trackByMessageReaction\n \"\n data-testclass=\"emoji\"\n >\n <span class=\"emoji\">\n {{ getEmojiByReaction(reactionType) }}\n </span>\n &nbsp;\n </li>\n <li>\n <span\n data-testid=\"reactions-count\"\n class=\"str-chat__reaction-list--counter\"\n >{{ reactionsCount }}</span\n >\n </li>\n </ul>\n</div>\n\n<div\n #selectorContainer\n class=\"str-chat__reaction-selector\"\n *ngIf=\"isSelectorOpen\"\n data-testid=\"reaction-selector\"\n>\n <div\n *ngIf=\"tooltipText\"\n data-testid=\"tooltip\"\n #selectorTooltip\n class=\"str-chat__reaction-selector-tooltip\"\n [ngStyle]=\"{\n left: tooltipPositions?.tooltip + 'px',\n visibility: tooltipPositions ? 'visible' : 'hidden'\n }\"\n >\n <div\n class=\"arrow\"\n [ngStyle]=\"{ left: tooltipPositions?.arrow + 'px' }\"\n ></div>\n <span class=\"latest-user-username\">\n {{ tooltipText }}\n </span>\n </div>\n <ul class=\"str-chat__message-reactions-list\">\n <li\n class=\"str-chat__message-reactions-list-item str-chat__emoji\"\n *ngFor=\"\n let reactionType of reactionOptions;\n trackBy: trackByMessageReaction\n \"\n data-testclass=\"emoji-option\"\n (click)=\"react(reactionType)\"\n (keyup.enter)=\"react(reactionType)\"\n >\n <div\n *ngIf=\"getLatestUserByReaction(reactionType) as user\"\n class=\"latest-user\"\n (click)=\"hideTooltip()\"\n (keyup.enter)=\"hideTooltip()\"\n (mouseenter)=\"showTooltip($event, reactionType)\"\n (mouseleave)=\"hideTooltip()\"\n attr.data-testid=\"{{ reactionType }}-last-user\"\n >\n <stream-avatar\n attr.data-testid=\"{{ reactionType }}-avatar\"\n [imageUrl]=\"user.image\"\n [name]=\"user.name || user.id\"\n [size]=\"20\"\n ></stream-avatar>\n </div>\n <span class=\"emoji\" style=\"width: 20px; height: 20px; top: 10px\">\n {{ getEmojiByReaction(reactionType) }}\n </span>\n <span\n *ngIf=\"\n messageReactionCounts[reactionType] &&\n messageReactionCounts[reactionType]! > 0\n \"\n class=\"str-chat__message-reactions-list-item__count\"\n attr.data-testid=\"{{ reactionType }}-reaction-count\"\n >\n {{ messageReactionCounts[reactionType] }}\n </span>\n </li>\n </ul>\n</div>\n", styles: [".emoji {position: relative; display: inline-block; }"], components: [{ type: AvatarComponent, selector: "stream-avatar", inputs: ["name", "imageUrl", "size"] }], directives: [{ type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i6.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i6.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
3300
+ MessageReactionsComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: MessageReactionsComponent, selector: "stream-message-reactions", inputs: { messageId: "messageId", messageReactionCounts: "messageReactionCounts", isSelectorOpen: "isSelectorOpen", latestReactions: "latestReactions", ownReactions: "ownReactions" }, outputs: { isSelectorOpenChange: "isSelectorOpenChange" }, viewQueries: [{ propertyName: "selectorContainer", first: true, predicate: ["selectorContainer"], descendants: true }, { propertyName: "selectorTooltip", first: true, predicate: ["selectorTooltip"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\n *ngIf=\"existingReactions.length > 0 && !isSelectorOpen\"\n class=\"str-chat__reaction-list\"\n [class.str-chat__reaction-list--reverse]=\"true\"\n data-testid=\"reaction-list\"\n>\n <ul>\n <li\n *ngFor=\"\n let reactionType of existingReactions;\n trackBy: trackByMessageReaction\n \"\n data-testclass=\"emoji\"\n >\n <span class=\"emoji\">\n {{ getEmojiByReaction(reactionType) }}\n </span>\n &nbsp;\n </li>\n <li>\n <span\n data-testid=\"reactions-count\"\n class=\"str-chat__reaction-list--counter\"\n >{{ reactionsCount }}</span\n >\n </li>\n </ul>\n</div>\n\n<div\n #selectorContainer\n class=\"str-chat__reaction-selector\"\n *ngIf=\"isSelectorOpen\"\n data-testid=\"reaction-selector\"\n>\n <div\n *ngIf=\"tooltipText\"\n data-testid=\"tooltip\"\n #selectorTooltip\n class=\"str-chat__reaction-selector-tooltip\"\n [ngStyle]=\"{\n left: tooltipPositions?.tooltip + 'px',\n visibility: tooltipPositions ? 'visible' : 'hidden'\n }\"\n >\n <div\n class=\"arrow\"\n [ngStyle]=\"{ left: tooltipPositions?.arrow + 'px' }\"\n ></div>\n <span class=\"latest-user-username\">\n {{ tooltipText }}\n </span>\n </div>\n <ul class=\"str-chat__message-reactions-list\">\n <li\n class=\"str-chat__message-reactions-list-item str-chat__emoji\"\n *ngFor=\"\n let reactionType of reactionOptions;\n trackBy: trackByMessageReaction\n \"\n data-testclass=\"emoji-option\"\n (click)=\"react(reactionType)\"\n (keyup.enter)=\"react(reactionType)\"\n >\n <div\n *ngIf=\"getLatestUserByReaction(reactionType) as user\"\n class=\"latest-user\"\n (click)=\"hideTooltip()\"\n (keyup.enter)=\"hideTooltip()\"\n (mouseenter)=\"showTooltip($event, reactionType)\"\n (mouseleave)=\"hideTooltip()\"\n attr.data-testid=\"{{ reactionType }}-last-user\"\n >\n <stream-avatar-placeholder\n attr.data-testid=\"{{ reactionType }}-avatar\"\n [imageUrl]=\"user.image\"\n [name]=\"user.name || user.id\"\n [size]=\"20\"\n ></stream-avatar-placeholder>\n </div>\n <span class=\"emoji\" style=\"width: 20px; height: 20px; top: 10px\">\n {{ getEmojiByReaction(reactionType) }}\n </span>\n <span\n *ngIf=\"\n messageReactionCounts[reactionType] &&\n messageReactionCounts[reactionType]! > 0\n \"\n class=\"str-chat__message-reactions-list-item__count\"\n attr.data-testid=\"{{ reactionType }}-reaction-count\"\n >\n {{ messageReactionCounts[reactionType] }}\n </span>\n </li>\n </ul>\n</div>\n", styles: [".emoji {position: relative; display: inline-block; }"], components: [{ type: AvatarPlaceholderComponent, selector: "stream-avatar-placeholder", inputs: ["name", "imageUrl", "size"] }], directives: [{ type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i3.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
3039
3301
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: MessageReactionsComponent, decorators: [{
3040
3302
  type: Component,
3041
3303
  args: [{
@@ -3067,9 +3329,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImpor
3067
3329
  * The `Message` component displays a message with additional information such as sender and date, and enables [interaction with the message (i.e. edit or react)](../concepts/message-interactions.mdx).
3068
3330
  */
3069
3331
  class MessageComponent {
3070
- constructor(chatClientService, channelService) {
3332
+ constructor(chatClientService, channelService, customTemplatesService, cdRef) {
3071
3333
  this.chatClientService = chatClientService;
3072
3334
  this.channelService = channelService;
3335
+ this.customTemplatesService = customTemplatesService;
3336
+ this.cdRef = cdRef;
3073
3337
  /**
3074
3338
  * The list of [channel capabilities](https://getstream.io/chat/docs/javascript/channel_capabilities/?language=javascript) that are enabled for the current user, the list of [supported interactions](../concepts/message-interactions.mdx) can be found in our message interaction guide. Unathorized actions won't be displayed on the UI. The [`MessageList`](./MessageListComponent.mdx) component automatically sets this based on [channel capabilities](https://getstream.io/chat/docs/javascript/channel_capabilities/?language=javascript).
3075
3339
  */
@@ -3083,12 +3347,28 @@ class MessageComponent {
3083
3347
  this.isPressedOnMobile = false;
3084
3348
  this.visibleMessageActionsCount = 0;
3085
3349
  this.messageTextParts = [];
3350
+ this.subscriptions = [];
3086
3351
  this.user = this.chatClientService.chatClient.user;
3087
3352
  }
3353
+ ngOnInit() {
3354
+ this.subscriptions.push(this.customTemplatesService.mentionTemplate$.subscribe((template) => (this.mentionTemplate = template)));
3355
+ this.subscriptions.push(this.customTemplatesService.attachmentListTemplate$.subscribe((template) => (this.attachmentListTemplate = template)));
3356
+ this.subscriptions.push(this.customTemplatesService.messageActionsBoxTemplate$.subscribe((template) => (this.messageActionsBoxTemplate = template)));
3357
+ this.subscriptions.push(this.customTemplatesService.messageReactionsTemplate$.subscribe((template) => (this.messageReactionsTemplate = template)));
3358
+ }
3088
3359
  ngOnChanges(changes) {
3089
3360
  if (changes.message) {
3090
3361
  this.createMessageParts();
3091
3362
  }
3363
+ if (changes.enabledMessageActions) {
3364
+ this.canReactToMessage =
3365
+ this.enabledMessageActions.indexOf('send-reaction') !== -1;
3366
+ this.canReceiveReadEvents =
3367
+ this.enabledMessageActions.indexOf('read-events') !== -1;
3368
+ }
3369
+ }
3370
+ ngOnDestroy() {
3371
+ this.subscriptions.forEach((s) => s.unsubscribe());
3092
3372
  }
3093
3373
  get isSentByCurrentUser() {
3094
3374
  var _a, _b, _c;
@@ -3156,6 +3436,24 @@ class MessageComponent {
3156
3436
  ? [originalAttachments[0]]
3157
3437
  : [];
3158
3438
  }
3439
+ getAttachmentListContext() {
3440
+ var _a, _b;
3441
+ return {
3442
+ messageId: ((_a = this.message) === null || _a === void 0 ? void 0 : _a.id) || '',
3443
+ attachments: ((_b = this.message) === null || _b === void 0 ? void 0 : _b.attachments) || [],
3444
+ };
3445
+ }
3446
+ getMessageReactionsContext() {
3447
+ var _a, _b, _c, _d;
3448
+ return {
3449
+ messageReactionCounts: ((_a = this.message) === null || _a === void 0 ? void 0 : _a.reaction_counts) || {},
3450
+ latestReactions: ((_b = this.message) === null || _b === void 0 ? void 0 : _b.latest_reactions) || [],
3451
+ isSelectorOpen: this.isReactionSelectorOpen,
3452
+ isSelectorOpenChangeHandler: (isOpen) => (this.isReactionSelectorOpen = isOpen),
3453
+ messageId: (_c = this.message) === null || _c === void 0 ? void 0 : _c.id,
3454
+ ownReactions: ((_d = this.message) === null || _d === void 0 ? void 0 : _d.own_reactions) || [],
3455
+ };
3456
+ }
3159
3457
  resendMessage() {
3160
3458
  void this.channelService.resendMessage(this.message);
3161
3459
  }
@@ -3180,6 +3478,29 @@ class MessageComponent {
3180
3478
  setAsActiveParentMessage() {
3181
3479
  void this.channelService.setAsActiveParentMessage(this.message);
3182
3480
  }
3481
+ getMentionContext(messagePart) {
3482
+ return {
3483
+ content: messagePart.content,
3484
+ user: messagePart.user,
3485
+ };
3486
+ }
3487
+ getMessageActionsBoxContext() {
3488
+ return {
3489
+ isOpen: this.isActionBoxOpen,
3490
+ isMine: this.isSentByCurrentUser,
3491
+ enabledActions: this.enabledMessageActions,
3492
+ message: this.message,
3493
+ displayedActionsCountChaneHanler: (count) => {
3494
+ this.visibleMessageActionsCount = count;
3495
+ // message action box changes UI bindings in parent, so we'll have to rerun change detection
3496
+ this.cdRef.detectChanges();
3497
+ },
3498
+ isEditingChangeHandler: (isEditing) => {
3499
+ this.isEditing = isEditing;
3500
+ this.isActionBoxOpen = !this.isEditing;
3501
+ },
3502
+ };
3503
+ }
3183
3504
  createMessageParts() {
3184
3505
  var _a, _b;
3185
3506
  let content = ((_a = this.message) === null || _a === void 0 ? void 0 : _a.html) || ((_b = this.message) === null || _b === void 0 ? void 0 : _b.text);
@@ -3198,12 +3519,7 @@ class MessageComponent {
3198
3519
  this.message.mentioned_users.length === 0) {
3199
3520
  // Wrap emojis in span to display emojis correctly in Chrome https://bugs.chromium.org/p/chromium/issues/detail?id=596223
3200
3521
  const regex = new RegExp(emojiRegex(), 'g');
3201
- // Based on this: https://stackoverflow.com/questions/4565112/javascript-how-to-find-out-if-the-user-browser-is-chrome
3202
- /* eslint-disable @typescript-eslint/no-unsafe-member-access */
3203
- const isChrome = !!window.chrome &&
3204
- typeof window.opr === 'undefined';
3205
- /* eslint-enable @typescript-eslint/no-unsafe-member-access */
3206
- content = content.replace(regex, (match) => `<span ${isChrome ? 'class="str-chat__emoji-display-fix"' : ''}>${match}</span>`);
3522
+ content = content.replace(regex, (match) => `<span class="str-chat__emoji-display-fix">${match}</span>`);
3207
3523
  this.messageTextParts = [{ content, type: 'text' }];
3208
3524
  }
3209
3525
  else {
@@ -3230,8 +3546,8 @@ class MessageComponent {
3230
3546
  }
3231
3547
  }
3232
3548
  }
3233
- MessageComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: MessageComponent, deps: [{ token: ChatClientService }, { token: ChannelService }], target: i0.ɵɵFactoryTarget.Component });
3234
- MessageComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: MessageComponent, selector: "stream-message", inputs: { messageInputTemplate: "messageInputTemplate", mentionTemplate: "mentionTemplate", message: "message", enabledMessageActions: "enabledMessageActions", areReactionsEnabled: "areReactionsEnabled", canReactToMessage: "canReactToMessage", isLastSentMessage: "isLastSentMessage", canReceiveReadEvents: "canReceiveReadEvents", mode: "mode" }, viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\n #container\n class=\"str-chat__message-simple str-chat__message str-chat__message--{{\n message?.type\n }} str-chat__message--{{ message?.status }} {{\n message?.text ? 'str-chat__message--has-text' : 'has-no-text'\n }}\"\n [class.str-chat__message--me]=\"isSentByCurrentUser\"\n [class.str-chat__message-simple--me]=\"isSentByCurrentUser\"\n [class.mobile-press]=\"isPressedOnMobile\"\n [class.str-chat__message--has-attachment]=\"hasAttachment\"\n [class.str-chat__message--with-reactions]=\"\n areReactionsEnabled !== false && hasReactions\n \"\n data-testid=\"message-container\"\n (mouseleave)=\"isActionBoxOpen = false\"\n>\n <ng-container *ngIf=\"!message?.deleted_at; else deletedMessage\">\n <ng-container *ngIf=\"message?.type !== 'system'; else systemMessage\">\n <ng-container\n *ngIf=\"\n isSentByCurrentUser &&\n ((isLastSentMessage && message?.status === 'received') ||\n message?.status === 'sending')\n \"\n >\n <ng-container *ngIf=\"message?.status === 'sending'; else sentStatus\">\n <ng-container *ngTemplateOutlet=\"sendingStatus\"></ng-container>\n </ng-container>\n <ng-template #sentStatus>\n <ng-container\n *ngIf=\"\n mode === 'main' &&\n isMessageDeliveredAndRead &&\n canDisplayReadStatus;\n else deliveredStatus\n \"\n >\n <ng-container *ngTemplateOutlet=\"readStatus\"></ng-container>\n </ng-container>\n </ng-template>\n </ng-container>\n <stream-avatar\n data-testid=\"avatar\"\n class=\"str-chat-angular__avatar-host\"\n [imageUrl]=\"message?.user?.image\"\n [name]=\"message?.user?.name || message?.user?.id\"\n ></stream-avatar>\n <div class=\"str-chat__message-inner\">\n <div\n class=\"str-chat__message-simple__actions\"\n data-testid=\"message-options\"\n *ngIf=\"areOptionsVisible\"\n >\n <div\n data-testid=\"message-actions-container\"\n class=\"\n str-chat__message-simple__actions__action\n str-chat__message-simple__actions__action--options\n \"\n [class.str-chat-angular__message-simple__actions__action--options--editing]=\"\n isEditing\n \"\n >\n <stream-message-actions-box\n [isOpen]=\"isActionBoxOpen\"\n [isMine]=\"isSentByCurrentUser\"\n [enabledActions]=\"enabledMessageActions\"\n [message]=\"message\"\n (displayedActionsCount)=\"visibleMessageActionsCount = $event\"\n (isEditing)=\"isEditing = $event; isActionBoxOpen = !isEditing\"\n [messageInputTemplate]=\"messageInputTemplate\"\n ></stream-message-actions-box>\n <stream-icon\n *ngIf=\"visibleMessageActionsCount > 0\"\n data-testid=\"action-icon\"\n icon=\"action-icon\"\n (keyup.enter)=\"isActionBoxOpen = !isActionBoxOpen\"\n (click)=\"isActionBoxOpen = !isActionBoxOpen\"\n ></stream-icon>\n </div>\n <!-- eslint-disable @angular-eslint/template/conditional-complexity -->\n <div\n *ngIf=\"\n enabledMessageActions.indexOf('send-reply') !== -1 &&\n mode === 'main'\n \"\n class=\"\n str-chat__message-simple__actions__action\n str-chat__message-simple__actions__action--thread\n \"\n data-testid=\"reply-in-thread\"\n (click)=\"setAsActiveParentMessage()\"\n (keyup.enter)=\"setAsActiveParentMessage()\"\n >\n <stream-icon icon=\"reply-in-thread\"></stream-icon>\n </div>\n <div\n *ngIf=\"\n areReactionsEnabled !== false &&\n canReactToMessage !== false &&\n enabledMessageActions.indexOf('send-reaction') !== -1\n \"\n class=\"\n str-chat__message-simple__actions__action\n str-chat__message-simple__actions__action--reactions\n \"\n data-testid=\"reaction-icon\"\n (click)=\"isReactionSelectorOpen = !isReactionSelectorOpen\"\n (keyup.enter)=\"isReactionSelectorOpen = !isReactionSelectorOpen\"\n >\n <stream-icon icon=\"reaction-icon\"></stream-icon>\n </div>\n </div>\n <!-- eslint-enable @angular-eslint/template/conditional-complexity -->\n <stream-message-reactions\n *ngIf=\"areReactionsEnabled !== false\"\n [messageReactionCounts]=\"message?.reaction_counts || {}\"\n [latestReactions]=\"message?.latest_reactions || []\"\n [(isSelectorOpen)]=\"isReactionSelectorOpen\"\n [messageId]=\"message?.id\"\n [ownReactions]=\"message?.own_reactions || []\"\n ></stream-message-reactions>\n <stream-attachment-list\n *ngIf=\"hasAttachment && !message?.quoted_message\"\n [attachments]=\"message!.attachments!\"\n [messageId]=\"message!.id\"\n ></stream-attachment-list>\n <div class=\"str-chat__message-text\" *ngIf=\"message?.text\">\n <div\n data-testid=\"inner-message\"\n class=\"\n str-chat__message-text-inner str-chat__message-simple-text-inner\n \"\n [class.str-chat__message-light-text-inner--has-attachment]=\"\n hasAttachment\n \"\n (click)=\"\n message?.status === 'failed' && message?.errorStatusCode !== 403\n ? resendMessage()\n : undefined\n \"\n (keyup.enter)=\"\n message?.status === 'failed' && message?.errorStatusCode !== 403\n ? resendMessage()\n : undefined\n \"\n >\n <ng-container *ngTemplateOutlet=\"quotedMessage\"></ng-container>\n <stream-attachment-list\n *ngIf=\"hasAttachment && message?.quoted_message\"\n [attachments]=\"message!.attachments!\"\n [messageId]=\"message!.id\"\n ></stream-attachment-list>\n <div\n data-testid=\"client-error-message\"\n *ngIf=\"message?.type === 'error'\"\n class=\"str-chat__simple-message--error-message\"\n >\n {{ \"streamChat.Error \u00B7 Unsent\" | translate }}\n </div>\n <div\n data-testid=\"error-message\"\n *ngIf=\"message?.status === 'failed'\"\n class=\"str-chat__simple-message--error-message\"\n >\n {{\n (message?.errorStatusCode === 403\n ? \"streamChat.Message Failed \u00B7 Unauthorized\"\n : \"streamChat.Message Failed \u00B7 Click to try again\"\n ) | translate\n }}\n </div>\n <div\n (click)=\"textClicked()\"\n (keyup.enter)=\"textClicked()\"\n data-testid=\"text\"\n >\n <p>\n <!-- eslint-disable-next-line @angular-eslint/template/use-track-by-function -->\n <ng-container *ngFor=\"let part of messageTextParts\">\n <span\n *ngIf=\"part.type === 'text'; else mention\"\n [innerHTML]=\"part.content\"\n ></span>\n <ng-template #mention>\n <ng-container *ngIf=\"mentionTemplate; else defaultMention\">\n <ng-container\n *ngTemplateOutlet=\"\n mentionTemplate;\n context: { user: part.user! }\n \"\n ></ng-container>\n </ng-container>\n <ng-template #defaultMention>\n <b>{{ part.content }}</b>\n </ng-template>\n </ng-template>\n </ng-container>\n </p>\n </div>\n </div>\n </div>\n <div class=\"str-chat__message-simple-reply-button\">\n <button\n *ngIf=\"\n !!message?.reply_count &&\n mode !== 'thread' &&\n enabledMessageActions.indexOf('send-reply') !== -1\n \"\n class=\"str-chat__message-replies-count-button\"\n data-testid=\"reply-count-button\"\n (click)=\"setAsActiveParentMessage()\"\n >\n <stream-icon icon=\"reply\"></stream-icon>\n {{message?.reply_count === 1 ? ('streamChat.1 reply' | translate) : ('streamChat.{{ replyCount }}\n replies' | translate:replyCountParam)}}\n </button>\n </div>\n <div class=\"str-chat__message-data str-chat__message-simple-data\">\n <span\n data-testid=\"sender\"\n *ngIf=\"!isSentByCurrentUser\"\n class=\"str-chat__message-simple-name\"\n >\n {{ message?.user?.name ? message?.user?.name : message?.user?.id }}\n </span>\n <span data-testid=\"date\" class=\"str-chat__message-simple-timestamp\">\n {{ parsedDate }}\n </span>\n </div>\n </div>\n </ng-container>\n </ng-container>\n</div>\n\n<ng-template #sendingStatus>\n <span\n class=\"\n str-chat__message-simple-status str-chat__message-simple-status-angular\n \"\n data-testid=\"sending-indicator\"\n >\n <div class=\"str-chat__tooltip\">\n {{ \"streamChat.Sending...\" | translate }}\n </div>\n <stream-loading-indicator\n data-testid=\"loading-indicator\"\n ></stream-loading-indicator>\n </span>\n</ng-template>\n<ng-template #readStatus>\n <span\n class=\"\n str-chat__message-simple-status str-chat__message-simple-status-angular\n \"\n data-testid=\"read-indicator\"\n >\n <div class=\"str-chat__tooltip\" data-testid=\"read-by-tooltip\">\n {{ readByText }}\n </div>\n <stream-avatar\n class=\"str-chat-angular__avatar-host\"\n data-test-id=\"last-read-user-avatar\"\n [size]=\"15\"\n [imageUrl]=\"lastReadUser?.image\"\n [name]=\"lastReadUser?.name || lastReadUser?.id\"\n ></stream-avatar>\n <span\n data-test-id=\"read-by-length\"\n *ngIf=\"isReadByMultipleUsers\"\n class=\"str-chat__message-simple-status-number\"\n >\n {{ (message?.readBy)!.length }}\n </span>\n </span>\n</ng-template>\n<ng-template #deliveredStatus>\n <span\n *ngIf=\"mode === 'main'\"\n class=\"\n str-chat__message-simple-status str-chat__message-simple-status-angular\n \"\n data-testid=\"delivered-indicator\"\n >\n <div class=\"str-chat__tooltip\">\n {{ \"streamChat.Delivered\" | translate }}\n </div>\n <stream-icon\n data-testid=\"delivered-icon\"\n icon=\"delivered-icon\"\n ></stream-icon>\n </span>\n</ng-template>\n\n<ng-template #deletedMessage>\n <div data-testid=\"message-deleted-component\">\n <div class=\"str-chat__message--deleted-inner\" translate>\n streamChat.This message was deleted...\n </div>\n </div>\n</ng-template>\n\n<ng-template #systemMessage>\n <div data-testid=\"system-message\" class=\"str-chat__message--system\">\n <div class=\"str-chat__message--system__text\">\n <div class=\"str-chat__message--system__line\"></div>\n <p>{{ message?.text }}</p>\n <div class=\"str-chat__message--system__line\"></div>\n </div>\n <div class=\"str-chat__message--system__date\">\n {{ parsedDate }}\n </div>\n </div>\n</ng-template>\n\n<ng-template #quotedMessage>\n <div\n *ngIf=\"message?.quoted_message\"\n class=\"quoted-message\"\n data-testid=\"quoted-message-container\"\n [class.mine]=\"isSentByCurrentUser\"\n >\n <stream-avatar\n data-testid=\"qouted-message-avatar\"\n class=\"str-chat-angular__avatar-host\"\n [imageUrl]=\"message?.quoted_message?.user?.image\"\n [name]=\"\n message?.quoted_message?.user?.name || message?.quoted_message?.user?.id\n \"\n [size]=\"20\"\n ></stream-avatar>\n <div class=\"quoted-message-inner\">\n <stream-attachment-list\n *ngIf=\"\n message?.quoted_message?.attachments &&\n message?.quoted_message?.attachments?.length\n \"\n [attachments]=\"quotedMessageAttachments\"\n [messageId]=\"message?.quoted_message?.id\"\n ></stream-attachment-list>\n <div\n data-testid=\"quoted-message-text\"\n [innerHTML]=\"\n message?.quoted_message?.html || message?.quoted_message?.text\n \"\n ></div>\n </div>\n </div>\n</ng-template>\n", components: [{ type: AvatarComponent, selector: "stream-avatar", inputs: ["name", "imageUrl", "size"] }, { type: MessageActionsBoxComponent, selector: "stream-message-actions-box", inputs: ["messageInputTemplate", "isOpen", "isMine", "message", "enabledActions"], outputs: ["displayedActionsCount", "isEditing"] }, { type: IconComponent, selector: "stream-icon", inputs: ["icon", "size"] }, { type: MessageReactionsComponent, selector: "stream-message-reactions", inputs: ["messageId", "messageReactionCounts", "isSelectorOpen", "latestReactions", "ownReactions"], outputs: ["isSelectorOpenChange"] }, { type: AttachmentListComponent, selector: "stream-attachment-list", inputs: ["messageId", "attachments"] }, { type: LoadingIndicatorComponent, selector: "stream-loading-indicator", inputs: ["size", "color"] }], directives: [{ type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i6.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i6.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i2.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }], pipes: { "translate": i2.TranslatePipe } });
3549
+ MessageComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: MessageComponent, deps: [{ token: ChatClientService }, { token: ChannelService }, { token: CustomTemplatesService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
3550
+ MessageComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: MessageComponent, selector: "stream-message", inputs: { message: "message", enabledMessageActions: "enabledMessageActions", isLastSentMessage: "isLastSentMessage", mode: "mode" }, viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\n #container\n class=\"str-chat__message-simple str-chat__message str-chat__message--{{\n message?.type\n }} str-chat__message--{{ message?.status }} {{\n message?.text ? 'str-chat__message--has-text' : 'has-no-text'\n }}\"\n [class.str-chat__message--me]=\"isSentByCurrentUser\"\n [class.str-chat__message-simple--me]=\"isSentByCurrentUser\"\n [class.mobile-press]=\"isPressedOnMobile\"\n [class.str-chat__message--has-attachment]=\"hasAttachment\"\n [class.str-chat__message--with-reactions]=\"hasReactions\"\n data-testid=\"message-container\"\n (mouseleave)=\"isActionBoxOpen = false\"\n>\n <ng-container *ngIf=\"!message?.deleted_at; else deletedMessage\">\n <ng-container *ngIf=\"message?.type !== 'system'; else systemMessage\">\n <ng-container\n *ngIf=\"\n isSentByCurrentUser &&\n ((isLastSentMessage && message?.status === 'received') ||\n message?.status === 'sending')\n \"\n >\n <ng-container *ngIf=\"message?.status === 'sending'; else sentStatus\">\n <ng-container *ngTemplateOutlet=\"sendingStatus\"></ng-container>\n </ng-container>\n <ng-template #sentStatus>\n <ng-container\n *ngIf=\"\n mode === 'main' &&\n isMessageDeliveredAndRead &&\n canDisplayReadStatus;\n else deliveredStatus\n \"\n >\n <ng-container *ngTemplateOutlet=\"readStatus\"></ng-container>\n </ng-container>\n </ng-template>\n </ng-container>\n <stream-avatar-placeholder\n data-testid=\"avatar\"\n class=\"str-chat-angular__avatar-host\"\n [imageUrl]=\"message?.user?.image\"\n [name]=\"message?.user?.name || message?.user?.id\"\n ></stream-avatar-placeholder>\n <div class=\"str-chat__message-inner\">\n <div\n class=\"str-chat__message-simple__actions\"\n data-testid=\"message-options\"\n *ngIf=\"areOptionsVisible\"\n >\n <div\n data-testid=\"message-actions-container\"\n class=\"\n str-chat__message-simple__actions__action\n str-chat__message-simple__actions__action--options\n \"\n [class.str-chat-angular__message-simple__actions__action--options--editing]=\"\n isEditing\n \"\n >\n <ng-template\n #defaultMessageActionsBox\n let-isOpen=\"isOpen\"\n let-isMine=\"isMine\"\n let-enabledActions=\"enabledActions\"\n let-messageInput=\"message\"\n let-displayedActionsCountChaneHanler=\"displayedActionsCountChaneHanler\"\n let-isEditingChangeHandler=\"isEditingChangeHandler\"\n >\n <stream-message-actions-box\n [isOpen]=\"isOpen\"\n [isMine]=\"isMine\"\n [enabledActions]=\"enabledActions\"\n [message]=\"messageInput\"\n (displayedActionsCount)=\"\n displayedActionsCountChaneHanler($event)\n \"\n (isEditing)=\"isEditingChangeHandler($event)\"\n ></stream-message-actions-box>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n messageActionsBoxTemplate || defaultMessageActionsBox;\n context: getMessageActionsBoxContext()\n \"\n ></ng-container>\n <stream-icon-placeholder\n *ngIf=\"visibleMessageActionsCount > 0\"\n data-testid=\"action-icon\"\n icon=\"action-icon\"\n (keyup.enter)=\"isActionBoxOpen = !isActionBoxOpen\"\n (click)=\"isActionBoxOpen = !isActionBoxOpen\"\n ></stream-icon-placeholder>\n </div>\n <!-- eslint-disable @angular-eslint/template/conditional-complexity -->\n <div\n *ngIf=\"\n enabledMessageActions.indexOf('send-reply') !== -1 &&\n mode === 'main'\n \"\n class=\"\n str-chat__message-simple__actions__action\n str-chat__message-simple__actions__action--thread\n \"\n data-testid=\"reply-in-thread\"\n (click)=\"setAsActiveParentMessage()\"\n (keyup.enter)=\"setAsActiveParentMessage()\"\n >\n <stream-icon-placeholder\n icon=\"reply-in-thread\"\n ></stream-icon-placeholder>\n </div>\n <div\n *ngIf=\"canReactToMessage\"\n class=\"\n str-chat__message-simple__actions__action\n str-chat__message-simple__actions__action--reactions\n \"\n data-testid=\"reaction-icon\"\n (click)=\"isReactionSelectorOpen = !isReactionSelectorOpen\"\n (keyup.enter)=\"isReactionSelectorOpen = !isReactionSelectorOpen\"\n >\n <stream-icon-placeholder\n icon=\"reaction-icon\"\n ></stream-icon-placeholder>\n </div>\n </div>\n <!-- eslint-enable @angular-eslint/template/conditional-complexity -->\n <ng-template\n #defaultMessageReactions\n let-messageReactionCounts=\"messageReactionCounts\"\n let-latestReactions=\"latestReactions\"\n let-isSelectorOpen=\"isSelectorOpen\"\n let-isSelectorOpenChangeHandler=\"isSelectorOpenChangeHandler\"\n let-messageId=\"messageId\"\n let-ownReactions=\"ownReactions\"\n >\n <stream-message-reactions\n [messageReactionCounts]=\"messageReactionCounts\"\n [latestReactions]=\"latestReactions\"\n [isSelectorOpen]=\"isSelectorOpen\"\n (isSelectorOpenChange)=\"isSelectorOpenChangeHandler($event)\"\n [messageId]=\"messageId\"\n [ownReactions]=\"ownReactions\"\n ></stream-message-reactions>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n messageReactionsTemplate || defaultMessageReactions;\n context: getMessageReactionsContext()\n \"\n ></ng-container>\n <ng-container *ngIf=\"hasAttachment && !message?.quoted_message\">\n <ng-template\n #defaultAttachments\n let-messageId=\"messageId\"\n let-attachments=\"attachments\"\n >\n <stream-attachment-list\n [messageId]=\"messageId\"\n [attachments]=\"attachments\"\n ></stream-attachment-list>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n attachmentListTemplate || defaultAttachments;\n context: getAttachmentListContext()\n \"\n ></ng-container>\n </ng-container>\n <div class=\"str-chat__message-text\" *ngIf=\"message?.text\">\n <div\n data-testid=\"inner-message\"\n class=\"\n str-chat__message-text-inner str-chat__message-simple-text-inner\n \"\n [class.str-chat__message-light-text-inner--has-attachment]=\"\n hasAttachment\n \"\n (click)=\"\n message?.status === 'failed' && message?.errorStatusCode !== 403\n ? resendMessage()\n : undefined\n \"\n (keyup.enter)=\"\n message?.status === 'failed' && message?.errorStatusCode !== 403\n ? resendMessage()\n : undefined\n \"\n >\n <ng-container *ngTemplateOutlet=\"quotedMessage\"></ng-container>\n <stream-attachment-list\n *ngIf=\"hasAttachment && message?.quoted_message\"\n [attachments]=\"message!.attachments!\"\n [messageId]=\"message!.id\"\n ></stream-attachment-list>\n <div\n data-testid=\"client-error-message\"\n *ngIf=\"message?.type === 'error'\"\n class=\"str-chat__simple-message--error-message\"\n >\n {{ \"streamChat.Error \u00B7 Unsent\" | translate }}\n </div>\n <div\n data-testid=\"error-message\"\n *ngIf=\"message?.status === 'failed'\"\n class=\"str-chat__simple-message--error-message\"\n >\n {{\n (message?.errorStatusCode === 403\n ? \"streamChat.Message Failed \u00B7 Unauthorized\"\n : \"streamChat.Message Failed \u00B7 Click to try again\"\n ) | translate\n }}\n </div>\n <div\n (click)=\"textClicked()\"\n (keyup.enter)=\"textClicked()\"\n data-testid=\"text\"\n >\n <p>\n <!-- eslint-disable-next-line @angular-eslint/template/use-track-by-function -->\n <ng-container *ngFor=\"let part of messageTextParts\">\n <span\n *ngIf=\"part.type === 'text'; else mention\"\n [innerHTML]=\"part.content\"\n ></span>\n <ng-template #mention>\n <ng-template #defaultMention let-content=\"content\">\n <b>{{ content }}</b>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n mentionTemplate || defaultMention;\n context: getMentionContext(part)\n \"\n ></ng-container>\n </ng-template>\n </ng-container>\n </p>\n </div>\n </div>\n </div>\n <div class=\"str-chat__message-simple-reply-button\">\n <button\n *ngIf=\"\n !!message?.reply_count &&\n mode !== 'thread' &&\n enabledMessageActions.indexOf('send-reply') !== -1\n \"\n class=\"str-chat__message-replies-count-button\"\n data-testid=\"reply-count-button\"\n (click)=\"setAsActiveParentMessage()\"\n >\n <stream-icon-placeholder icon=\"reply\"></stream-icon-placeholder>\n {{message?.reply_count === 1 ? ('streamChat.1 reply' | translate) : ('streamChat.{{ replyCount }}\n replies' | translate:replyCountParam)}}\n </button>\n </div>\n <div class=\"str-chat__message-data str-chat__message-simple-data\">\n <span\n data-testid=\"sender\"\n *ngIf=\"!isSentByCurrentUser\"\n class=\"str-chat__message-simple-name\"\n >\n {{ message?.user?.name ? message?.user?.name : message?.user?.id }}\n </span>\n <span data-testid=\"date\" class=\"str-chat__message-simple-timestamp\">\n {{ parsedDate }}\n </span>\n </div>\n </div>\n </ng-container>\n </ng-container>\n</div>\n\n<ng-template #sendingStatus>\n <span\n class=\"\n str-chat__message-simple-status str-chat__message-simple-status-angular\n \"\n data-testid=\"sending-indicator\"\n >\n <div class=\"str-chat__tooltip\">\n {{ \"streamChat.Sending...\" | translate }}\n </div>\n <stream-loading-indicator-placeholder\n data-testid=\"loading-indicator\"\n ></stream-loading-indicator-placeholder>\n </span>\n</ng-template>\n<ng-template #readStatus>\n <span\n class=\"\n str-chat__message-simple-status str-chat__message-simple-status-angular\n \"\n data-testid=\"read-indicator\"\n >\n <div class=\"str-chat__tooltip\" data-testid=\"read-by-tooltip\">\n {{ readByText }}\n </div>\n <stream-avatar-placeholder\n class=\"str-chat-angular__avatar-host\"\n data-test-id=\"last-read-user-avatar\"\n [size]=\"15\"\n [imageUrl]=\"lastReadUser?.image\"\n [name]=\"lastReadUser?.name || lastReadUser?.id\"\n ></stream-avatar-placeholder>\n <span\n data-test-id=\"read-by-length\"\n *ngIf=\"isReadByMultipleUsers\"\n class=\"str-chat__message-simple-status-number\"\n >\n {{ (message?.readBy)!.length }}\n </span>\n </span>\n</ng-template>\n<ng-template #deliveredStatus>\n <span\n *ngIf=\"mode === 'main'\"\n class=\"\n str-chat__message-simple-status str-chat__message-simple-status-angular\n \"\n data-testid=\"delivered-indicator\"\n >\n <div class=\"str-chat__tooltip\">\n {{ \"streamChat.Delivered\" | translate }}\n </div>\n <stream-icon-placeholder\n data-testid=\"delivered-icon\"\n icon=\"delivered-icon\"\n ></stream-icon-placeholder>\n </span>\n</ng-template>\n\n<ng-template #deletedMessage>\n <div data-testid=\"message-deleted-component\">\n <div class=\"str-chat__message--deleted-inner\" translate>\n streamChat.This message was deleted...\n </div>\n </div>\n</ng-template>\n\n<ng-template #systemMessage>\n <div data-testid=\"system-message\" class=\"str-chat__message--system\">\n <div class=\"str-chat__message--system__text\">\n <div class=\"str-chat__message--system__line\"></div>\n <p>{{ message?.text }}</p>\n <div class=\"str-chat__message--system__line\"></div>\n </div>\n <div class=\"str-chat__message--system__date\">\n {{ parsedDate }}\n </div>\n </div>\n</ng-template>\n\n<ng-template #quotedMessage>\n <div\n *ngIf=\"message?.quoted_message\"\n class=\"quoted-message\"\n data-testid=\"quoted-message-container\"\n [class.mine]=\"isSentByCurrentUser\"\n >\n <stream-avatar-placeholder\n data-testid=\"qouted-message-avatar\"\n class=\"str-chat-angular__avatar-host\"\n [imageUrl]=\"message?.quoted_message?.user?.image\"\n [name]=\"\n message?.quoted_message?.user?.name || message?.quoted_message?.user?.id\n \"\n [size]=\"20\"\n ></stream-avatar-placeholder>\n <div class=\"quoted-message-inner\">\n <stream-attachment-list\n *ngIf=\"\n message?.quoted_message?.attachments &&\n message?.quoted_message?.attachments?.length\n \"\n [attachments]=\"quotedMessageAttachments\"\n [messageId]=\"message?.quoted_message?.id\"\n ></stream-attachment-list>\n <div\n data-testid=\"quoted-message-text\"\n [innerHTML]=\"\n message?.quoted_message?.html || message?.quoted_message?.text\n \"\n ></div>\n </div>\n </div>\n</ng-template>\n", components: [{ type: AvatarPlaceholderComponent, selector: "stream-avatar-placeholder", inputs: ["name", "imageUrl", "size"] }, { type: MessageActionsBoxComponent, selector: "stream-message-actions-box", inputs: ["isOpen", "isMine", "message", "enabledActions"], outputs: ["displayedActionsCount", "isEditing"] }, { type: IconPlaceholderComponent, selector: "stream-icon-placeholder", inputs: ["icon", "size"] }, { type: MessageReactionsComponent, selector: "stream-message-reactions", inputs: ["messageId", "messageReactionCounts", "isSelectorOpen", "latestReactions", "ownReactions"], outputs: ["isSelectorOpenChange"] }, { type: AttachmentListComponent, selector: "stream-attachment-list", inputs: ["messageId", "attachments"] }, { type: LoadingIndicatorPlaceholderComponent, selector: "stream-loading-indicator-placeholder", inputs: ["size", "color"] }], directives: [{ type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i2.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }], pipes: { "translate": i2.TranslatePipe } });
3235
3551
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: MessageComponent, decorators: [{
3236
3552
  type: Component,
3237
3553
  args: [{
@@ -3239,22 +3555,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImpor
3239
3555
  templateUrl: './message.component.html',
3240
3556
  styles: [],
3241
3557
  }]
3242
- }], ctorParameters: function () { return [{ type: ChatClientService }, { type: ChannelService }]; }, propDecorators: { messageInputTemplate: [{
3243
- type: Input
3244
- }], mentionTemplate: [{
3245
- type: Input
3246
- }], message: [{
3558
+ }], ctorParameters: function () { return [{ type: ChatClientService }, { type: ChannelService }, { type: CustomTemplatesService }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { message: [{
3247
3559
  type: Input
3248
3560
  }], enabledMessageActions: [{
3249
3561
  type: Input
3250
- }], areReactionsEnabled: [{
3251
- type: Input
3252
- }], canReactToMessage: [{
3253
- type: Input
3254
3562
  }], isLastSentMessage: [{
3255
3563
  type: Input
3256
- }], canReceiveReadEvents: [{
3257
- type: Input
3258
3564
  }], mode: [{
3259
3565
  type: Input
3260
3566
  }], container: [{
@@ -3353,11 +3659,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImpor
3353
3659
  * The `AutocompleteTextarea` component is used by the [`MessageInput`](./MessageInputComponent.mdx) component to display the input HTML element where users can type their message.
3354
3660
  */
3355
3661
  class AutocompleteTextareaComponent {
3356
- constructor(channelService, chatClientService, transliterationService, emojiInputService) {
3662
+ constructor(channelService, chatClientService, transliterationService, emojiInputService, customTemplatesService) {
3357
3663
  this.channelService = channelService;
3358
3664
  this.chatClientService = chatClientService;
3359
3665
  this.transliterationService = transliterationService;
3360
3666
  this.emojiInputService = emojiInputService;
3667
+ this.customTemplatesService = customTemplatesService;
3361
3668
  this.class = 'str-chat__textarea';
3362
3669
  /**
3363
3670
  * The value of the input HTML element.
@@ -3433,6 +3740,8 @@ class AutocompleteTextareaComponent {
3433
3740
  selectionStart + emoji.length;
3434
3741
  this.inputChanged();
3435
3742
  }));
3743
+ this.subscriptions.push(this.customTemplatesService.mentionAutocompleteItemTemplate$.subscribe((template) => (this.mentionAutocompleteItemTemplate = template)));
3744
+ this.subscriptions.push(this.customTemplatesService.commandAutocompleteItemTemplate$.subscribe((template) => (this.commandAutocompleteItemTemplate = template)));
3436
3745
  this.autocompleteConfig.mentions = [
3437
3746
  this.userMentionConfig,
3438
3747
  this.slashCommandConfig,
@@ -3531,8 +3840,8 @@ class AutocompleteTextareaComponent {
3531
3840
  }
3532
3841
  }
3533
3842
  }
3534
- AutocompleteTextareaComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: AutocompleteTextareaComponent, deps: [{ token: ChannelService }, { token: ChatClientService }, { token: TransliterationService }, { token: EmojiInputService }], target: i0.ɵɵFactoryTarget.Component });
3535
- AutocompleteTextareaComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: AutocompleteTextareaComponent, selector: "stream-autocomplete-textarea", inputs: { value: "value", areMentionsEnabled: "areMentionsEnabled", mentionAutocompleteItemTemplate: "mentionAutocompleteItemTemplate", commandAutocompleteItemTemplate: "commandAutocompleteItemTemplate", mentionScope: "mentionScope" }, outputs: { valueChange: "valueChange", send: "send", userMentions: "userMentions" }, host: { properties: { "class": "this.class" } }, viewQueries: [{ propertyName: "messageInput", first: true, predicate: ["input"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<textarea\n [value]=\"value || ''\"\n autofocus\n data-testid=\"textarea\"\n #input\n placeholder=\"{{ 'streamChat.Type your message' | translate }}\"\n class=\"rta__textarea str-chat__textarea__textarea str-chat__angular-textarea\"\n rows=\"1\"\n (input)=\"inputChanged()\"\n (keydown.enter)=\"sent($event)\"\n [mentionConfig]=\"autocompleteConfig\"\n (searchTerm)=\"autcompleteSearchTermChanged($event)\"\n [mentionListTemplate]=\"autocompleteItem\"\n (blur)=\"inputLeft()\"\n></textarea>\n<ng-template #autocompleteItem let-item=\"item\">\n <div class=\"rta rta__item str-chat__emojisearch__item\" [ngSwitch]=\"item.type\">\n <div class=\"rta__entity\" *ngSwitchCase=\"'mention'\">\n <ng-container\n *ngTemplateOutlet=\"\n mentionAutocompleteItemTemplate || defaultMentionTemplate;\n context: { item: item }\n \"\n ></ng-container>\n </div>\n <div class=\"rta__entity\" *ngSwitchCase=\"'command'\">\n <ng-container\n *ngTemplateOutlet=\"\n commandAutocompleteItemTemplate || defaultCommandTemplate;\n context: { item: item }\n \"\n ></ng-container>\n </div>\n </div>\n</ng-template>\n\n<ng-template #defaultCommandTemplate let-item=\"item\">\n <div class=\"str-chat__slash-command\">\n <span class=\"str-chat__slash-command-header\">\n <strong data-testclass=\"command-name\">{{ item.name }}</strong>\n {{ item.args }}\n </span>\n <br />\n <span class=\"str-chat__slash-command-description\">{{\n item.description\n }}</span>\n </div>\n</ng-template>\n\n<ng-template #defaultMentionTemplate let-item=\"item\">\n <div class=\"str-chat__user-item\">\n <stream-avatar\n data-testclass=\"avatar\"\n class=\"str-chat__avatar str-chat__avatar--circle\"\n style=\"height: 20px\"\n [size]=\"20\"\n [imageUrl]=\"item.image || item.user?.image\"\n [name]=\"item.autocompleteLabel\"\n ></stream-avatar>\n <span data-testclass=\"username\" class=\"str-chat__user-item--name\">{{\n item.autocompleteLabel\n }}</span>\n </div>\n</ng-template>\n", components: [{ type: AvatarComponent, selector: "stream-avatar", inputs: ["name", "imageUrl", "size"] }], directives: [{ type: i6$1.MentionDirective, selector: "[mention], [mentionConfig]", inputs: ["mentionConfig", "mention", "mentionListTemplate"], outputs: ["searchTerm", "itemSelected", "opened", "closed"] }, { type: i6.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { type: i6.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { type: i6.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }], pipes: { "translate": i2.TranslatePipe } });
3843
+ AutocompleteTextareaComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: AutocompleteTextareaComponent, deps: [{ token: ChannelService }, { token: ChatClientService }, { token: TransliterationService }, { token: EmojiInputService }, { token: CustomTemplatesService }], target: i0.ɵɵFactoryTarget.Component });
3844
+ AutocompleteTextareaComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: AutocompleteTextareaComponent, selector: "stream-autocomplete-textarea", inputs: { value: "value", areMentionsEnabled: "areMentionsEnabled", mentionScope: "mentionScope" }, outputs: { valueChange: "valueChange", send: "send", userMentions: "userMentions" }, host: { properties: { "class": "this.class" } }, viewQueries: [{ propertyName: "messageInput", first: true, predicate: ["input"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<textarea\n [value]=\"value || ''\"\n autofocus\n data-testid=\"textarea\"\n #input\n placeholder=\"{{ 'streamChat.Type your message' | translate }}\"\n class=\"rta__textarea str-chat__textarea__textarea str-chat__angular-textarea\"\n rows=\"1\"\n (input)=\"inputChanged()\"\n (keydown.enter)=\"sent($event)\"\n [mentionConfig]=\"autocompleteConfig\"\n (searchTerm)=\"autcompleteSearchTermChanged($event)\"\n [mentionListTemplate]=\"autocompleteItem\"\n (blur)=\"inputLeft()\"\n></textarea>\n<ng-template #autocompleteItem let-item=\"item\">\n <div class=\"rta rta__item str-chat__emojisearch__item\" [ngSwitch]=\"item.type\">\n <div class=\"rta__entity\" *ngSwitchCase=\"'mention'\">\n <ng-container\n *ngTemplateOutlet=\"\n mentionAutocompleteItemTemplate || defaultMentionTemplate;\n context: { item: item }\n \"\n ></ng-container>\n </div>\n <div class=\"rta__entity\" *ngSwitchCase=\"'command'\">\n <ng-container\n *ngTemplateOutlet=\"\n commandAutocompleteItemTemplate || defaultCommandTemplate;\n context: { item: item }\n \"\n ></ng-container>\n </div>\n </div>\n</ng-template>\n\n<ng-template #defaultCommandTemplate let-item=\"item\">\n <div class=\"str-chat__slash-command\">\n <span class=\"str-chat__slash-command-header\">\n <strong data-testclass=\"command-name\">{{ item.name }}</strong>\n {{ item.args }}\n </span>\n <br />\n <span class=\"str-chat__slash-command-description\">{{\n item.description\n }}</span>\n </div>\n</ng-template>\n\n<ng-template #defaultMentionTemplate let-item=\"item\">\n <div class=\"str-chat__user-item\">\n <stream-avatar-placeholder\n data-testclass=\"avatar\"\n class=\"str-chat__avatar str-chat__avatar--circle\"\n style=\"height: 20px\"\n [size]=\"20\"\n [imageUrl]=\"item.image || item.user?.image\"\n [name]=\"item.autocompleteLabel\"\n ></stream-avatar-placeholder>\n <span data-testclass=\"username\" class=\"str-chat__user-item--name\">{{\n item.autocompleteLabel\n }}</span>\n </div>\n</ng-template>\n", components: [{ type: AvatarPlaceholderComponent, selector: "stream-avatar-placeholder", inputs: ["name", "imageUrl", "size"] }], directives: [{ type: i7.MentionDirective, selector: "[mention], [mentionConfig]", inputs: ["mentionConfig", "mention", "mentionListTemplate"], outputs: ["searchTerm", "itemSelected", "opened", "closed"] }, { type: i3.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { type: i3.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }], pipes: { "translate": i2.TranslatePipe } });
3536
3845
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: AutocompleteTextareaComponent, decorators: [{
3537
3846
  type: Component,
3538
3847
  args: [{
@@ -3540,16 +3849,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImpor
3540
3849
  templateUrl: './autocomplete-textarea.component.html',
3541
3850
  styles: [],
3542
3851
  }]
3543
- }], ctorParameters: function () { return [{ type: ChannelService }, { type: ChatClientService }, { type: TransliterationService }, { type: EmojiInputService }]; }, propDecorators: { class: [{
3852
+ }], ctorParameters: function () { return [{ type: ChannelService }, { type: ChatClientService }, { type: TransliterationService }, { type: EmojiInputService }, { type: CustomTemplatesService }]; }, propDecorators: { class: [{
3544
3853
  type: HostBinding
3545
3854
  }], value: [{
3546
3855
  type: Input
3547
3856
  }], areMentionsEnabled: [{
3548
3857
  type: Input
3549
- }], mentionAutocompleteItemTemplate: [{
3550
- type: Input
3551
- }], commandAutocompleteItemTemplate: [{
3552
- type: Input
3553
3858
  }], mentionScope: [{
3554
3859
  type: Input
3555
3860
  }], valueChange: [{
@@ -3607,19 +3912,11 @@ const isOnSameDay = (date1, date2) => {
3607
3912
  * The `MessageList` component renders a scrollable list of messages.
3608
3913
  */
3609
3914
  class MessageListComponent {
3610
- constructor(channelService, chatClientService, imageLoadService) {
3915
+ constructor(channelService, chatClientService, imageLoadService, customTemplatesService) {
3611
3916
  this.channelService = channelService;
3612
3917
  this.chatClientService = chatClientService;
3613
3918
  this.imageLoadService = imageLoadService;
3614
- /**
3615
- * @deprecated use [channel capabilities](https://getstream.io/chat/docs/javascript/channel_capabilities/?language=javascript) instead. If true, the message reactions are displayed. Users can also react to messages if they have the necessary [channel capability](https://getstream.io/chat/docs/javascript/channel_capabilities/?language=javascript).
3616
- */
3617
- this.areReactionsEnabled = undefined;
3618
- /**
3619
- * @deprecated use [channel capabilities](https://getstream.io/chat/docs/javascript/channel_capabilities/?language=javascript) instead. The list of [actions that are enabled](./MessageActionsBoxComponent.mdx), please note that the user also has to have the necessary [channel capabilities](https://getstream.io/chat/docs/javascript/channel_capabilities/?language=javascript) for actions to work. Unathorized actions won't be displayed on the UI. The `MessgaeList` component makes the necessary checks before passing the actions to the `Message` component.
3620
- */
3621
- /* eslint-disable-next-line @angular-eslint/no-input-rename */
3622
- this.enabledMessageActionsInput = undefined;
3919
+ this.customTemplatesService = customTemplatesService;
3623
3920
  /**
3624
3921
  * Determines if the message list should display channel messages or [thread messages](https://getstream.io/chat/docs/javascript/threads/?language=javascript).
3625
3922
  */
@@ -3628,7 +3925,6 @@ class MessageListComponent {
3628
3925
  this.class = 'str-chat-angular__main-panel-inner str-chat-angular__message-list-host';
3629
3926
  this.unreadMessageCount = 0;
3630
3927
  this.groupStyles = [];
3631
- this.authorizedMessageActions = ['flag'];
3632
3928
  this.isUserScrolledUpThreshold = 300;
3633
3929
  this.subscriptions = [];
3634
3930
  this.subscriptions.push(this.channelService.activeChannel$.subscribe((channel) => {
@@ -3636,39 +3932,7 @@ class MessageListComponent {
3636
3932
  this.resetScrollState();
3637
3933
  const capabilites = (_a = channel === null || channel === void 0 ? void 0 : channel.data) === null || _a === void 0 ? void 0 : _a.own_capabilities;
3638
3934
  if (capabilites) {
3639
- this.canReactToMessage = capabilites.indexOf('send-reaction') !== -1;
3640
- this.canReceiveReadEvents = capabilites.indexOf('read-events') !== -1;
3641
- this.authorizedMessageActions = [];
3642
- if (this.canReactToMessage) {
3643
- this.authorizedMessageActions.push('send-reaction');
3644
- }
3645
- if (this.canReceiveReadEvents) {
3646
- this.authorizedMessageActions.push('read-events');
3647
- }
3648
- if (capabilites.indexOf('flag-message') !== -1) {
3649
- this.authorizedMessageActions.push('flag');
3650
- }
3651
- if (capabilites.indexOf('update-own-message') !== -1) {
3652
- this.authorizedMessageActions.push('edit');
3653
- }
3654
- if (capabilites.indexOf('update-any-message') !== -1) {
3655
- this.authorizedMessageActions.push('edit');
3656
- this.authorizedMessageActions.push('edit-any');
3657
- }
3658
- if (capabilites.indexOf('delete-own-message') !== -1) {
3659
- this.authorizedMessageActions.push('delete');
3660
- }
3661
- if (capabilites.indexOf('delete-any-message') !== -1) {
3662
- this.authorizedMessageActions.push('delete');
3663
- this.authorizedMessageActions.push('delete-any');
3664
- }
3665
- if (capabilites.indexOf('send-reply') !== -1) {
3666
- this.authorizedMessageActions.push('send-reply');
3667
- }
3668
- if (capabilites.indexOf('quote-message') !== -1) {
3669
- this.authorizedMessageActions.push('quote-message');
3670
- }
3671
- this.setEnabledActions();
3935
+ this.enabledMessageActions = capabilites;
3672
3936
  }
3673
3937
  }));
3674
3938
  this.subscriptions.push(this.imageLoadService.imageLoad$.subscribe(() => {
@@ -3689,6 +3953,8 @@ class MessageListComponent {
3689
3953
  }
3690
3954
  this.parentMessage = message;
3691
3955
  }));
3956
+ this.subscriptions.push(this.customTemplatesService.messageTemplate$.subscribe((template) => (this.messageTemplate = template)));
3957
+ this.subscriptions.push(this.customTemplatesService.typingIndicatorTemplate$.subscribe((template) => (this.typingIndicatorTemplate = template)));
3692
3958
  this.usersTypingInChannel$ = this.channelService.usersTypingInChannel$;
3693
3959
  this.usersTypingInThread$ = this.channelService.usersTypingInThread$;
3694
3960
  }
@@ -3696,9 +3962,6 @@ class MessageListComponent {
3696
3962
  this.setMessages$();
3697
3963
  }
3698
3964
  ngOnChanges(changes) {
3699
- if (changes.enabledMessageActionsInput) {
3700
- this.setEnabledActions();
3701
- }
3702
3965
  if (changes.mode) {
3703
3966
  this.setMessages$();
3704
3967
  }
@@ -3730,11 +3993,6 @@ class MessageListComponent {
3730
3993
  ngOnDestroy() {
3731
3994
  this.subscriptions.forEach((s) => s.unsubscribe());
3732
3995
  }
3733
- get usersTyping$() {
3734
- return this.mode === 'thread'
3735
- ? this.usersTypingInThread$
3736
- : this.usersTypingInChannel$;
3737
- }
3738
3996
  trackByMessageId(index, item) {
3739
3997
  return item.id;
3740
3998
  }
@@ -3767,31 +4025,24 @@ class MessageListComponent {
3767
4025
  }
3768
4026
  this.prevScrollTop = this.scrollContainer.nativeElement.scrollTop;
3769
4027
  }
4028
+ getTypingIndicatorContext() {
4029
+ return {
4030
+ usersTyping$: this.usersTyping$,
4031
+ };
4032
+ }
4033
+ getMessageContext(message) {
4034
+ return {
4035
+ message,
4036
+ isLastSentMessage: !!(this.lastSentMessageId && (message === null || message === void 0 ? void 0 : message.id) === this.lastSentMessageId),
4037
+ enabledMessageActions: this.enabledMessageActions,
4038
+ mode: this.mode,
4039
+ };
4040
+ }
3770
4041
  preserveScrollbarPosition() {
3771
4042
  this.scrollContainer.nativeElement.scrollTop =
3772
4043
  (this.prevScrollTop || 0) +
3773
4044
  (this.scrollContainer.nativeElement.scrollHeight - this.containerHeight);
3774
4045
  }
3775
- setEnabledActions() {
3776
- this.enabledMessageActions = [];
3777
- if (!this.enabledMessageActionsInput) {
3778
- this.enabledMessageActions = this.authorizedMessageActions;
3779
- return;
3780
- }
3781
- this.enabledMessageActionsInput = [
3782
- ...this.enabledMessageActionsInput,
3783
- 'send-reaction',
3784
- 'read-events',
3785
- 'send-reply',
3786
- 'quote-message',
3787
- ];
3788
- this.enabledMessageActionsInput.forEach((action) => {
3789
- const isAuthorized = this.authorizedMessageActions.indexOf(action) !== -1;
3790
- if (isAuthorized) {
3791
- this.enabledMessageActions.push(action);
3792
- }
3793
- });
3794
- }
3795
4046
  setMessages$() {
3796
4047
  this.messages$ = (this.mode === 'main'
3797
4048
  ? this.channelService.activeChannelMessages$
@@ -3844,9 +4095,14 @@ class MessageListComponent {
3844
4095
  this.prevScrollTop = undefined;
3845
4096
  this.isNewMessageSentByUser = undefined;
3846
4097
  }
4098
+ get usersTyping$() {
4099
+ return this.mode === 'thread'
4100
+ ? this.usersTypingInThread$
4101
+ : this.usersTypingInChannel$;
4102
+ }
3847
4103
  }
3848
- MessageListComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: MessageListComponent, deps: [{ token: ChannelService }, { token: ChatClientService }, { token: ImageLoadService }], target: i0.ɵɵFactoryTarget.Component });
3849
- MessageListComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: MessageListComponent, selector: "stream-message-list", inputs: { messageTemplate: "messageTemplate", messageInputTemplate: "messageInputTemplate", mentionTemplate: "mentionTemplate", typingIndicatorTemplate: "typingIndicatorTemplate", areReactionsEnabled: "areReactionsEnabled", enabledMessageActionsInput: ["enabledMessageActions", "enabledMessageActionsInput"], mode: "mode" }, 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: "<div\n #scrollContainer\n data-testid=\"scroll-container\"\n class=\"str-chat__list\"\n (scroll)=\"scrolled()\"\n>\n <div class=\"str-chat__reverse-infinite-scroll\">\n <ul class=\"str-chat__ul\">\n <li\n #parentMessageElement\n *ngIf=\"mode === 'thread'\"\n data-testid=\"parent-message\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n messageTemplateContainer;\n context: { message: parentMessage }\n \"\n ></ng-container>\n <div class=\"str-chat__thread-start\" translate>\n streamChat.Start of a new thread\n </div>\n </li>\n <li\n data-testclass=\"message\"\n *ngFor=\"\n let message of messages$ | async;\n let i = index;\n trackBy: trackByMessageId\n \"\n class=\"str-chat__li str-chat__li--{{ groupStyles[i] }}\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n messageTemplateContainer;\n context: { message: message }\n \"\n ></ng-container>\n </li>\n </ul>\n <ng-container *ngIf=\"typingIndicatorTemplate; else defaultTypingIndicator\">\n <ng-container\n *ngTemplateOutlet=\"\n typingIndicatorTemplate;\n context: { usersTyping$: usersTyping$ }\n \"\n ></ng-container>\n </ng-container>\n <ng-template #defaultTypingIndicator>\n <div\n *ngIf=\"(usersTyping$ | async)?.length\"\n data-testid=\"typing-indicator\"\n class=\"str-chat__typing-indicator str-chat__typing-indicator--typing\"\n >\n <stream-avatar\n *ngFor=\"let user of usersTyping$ | async; trackBy: trackByUserId\"\n [name]=\"user.name || user.id\"\n [imageUrl]=\"user.image\"\n ></stream-avatar>\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 </ng-template>\n </div>\n</div>\n<div class=\"str-chat__list-notifications\">\n <button\n data-testid=\"scroll-to-bottom\"\n *ngIf=\"isUserScrolledUp\"\n class=\"\n str-chat__message-notification\n str-chat__message-notification-right\n str-chat__message-notification-scroll-down\n \"\n (keyup.enter)=\"scrollToBottom()\"\n (click)=\"scrollToBottom()\"\n >\n <div\n *ngIf=\"unreadMessageCount > 0\"\n class=\"\n str-chat__message-notification\n str-chat__message-notification-scroll-down-unread-count\n \"\n >\n {{ unreadMessageCount }}\n </div>\n </button>\n</div>\n\n<ng-template #messageTemplateContainer let-message=\"message\">\n <ng-container *ngIf=\"messageTemplate; else defaultMessageTemplate\">\n <ng-container\n *ngTemplateOutlet=\"\n messageTemplate;\n context: {\n message: message,\n areReactionsEnabled: areReactionsEnabled,\n canReactToMessage: canReactToMessage,\n lastSentMessageId: !!(\n lastSentMessageId && message?.id === lastSentMessageId\n ),\n canReceiveReadEvents: canReceiveReadEvents,\n messageInputTemplate: messageInputTemplate,\n mentionTemplate: mentionTemplate,\n mode: mode,\n enabledMessageActions: enabledMessageActions\n }\n \"\n ></ng-container>\n </ng-container>\n <ng-template #defaultMessageTemplate>\n <stream-message\n [message]=\"message\"\n [areReactionsEnabled]=\"areReactionsEnabled\"\n [canReactToMessage]=\"canReactToMessage\"\n [isLastSentMessage]=\"\n !!(lastSentMessageId && message?.id === lastSentMessageId)\n \"\n [enabledMessageActions]=\"enabledMessageActions\"\n [canReceiveReadEvents]=\"canReceiveReadEvents\"\n [messageInputTemplate]=\"messageInputTemplate\"\n [mentionTemplate]=\"mentionTemplate\"\n [mode]=\"mode\"\n ></stream-message>\n </ng-template>\n</ng-template>\n", components: [{ type: AvatarComponent, selector: "stream-avatar", inputs: ["name", "imageUrl", "size"] }, { type: MessageComponent, selector: "stream-message", inputs: ["messageInputTemplate", "mentionTemplate", "message", "enabledMessageActions", "areReactionsEnabled", "canReactToMessage", "isLastSentMessage", "canReceiveReadEvents", "mode"] }], directives: [{ type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i6.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i2.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i6.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], pipes: { "async": i6.AsyncPipe } });
4104
+ MessageListComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: MessageListComponent, deps: [{ token: ChannelService }, { token: ChatClientService }, { token: ImageLoadService }, { token: CustomTemplatesService }], target: i0.ɵɵFactoryTarget.Component });
4105
+ MessageListComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: MessageListComponent, selector: "stream-message-list", inputs: { mode: "mode" }, 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: "<div\n #scrollContainer\n data-testid=\"scroll-container\"\n class=\"str-chat__list\"\n (scroll)=\"scrolled()\"\n>\n <div class=\"str-chat__reverse-infinite-scroll\">\n <ul class=\"str-chat__ul\">\n <li\n #parentMessageElement\n *ngIf=\"mode === 'thread'\"\n data-testid=\"parent-message\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n messageTemplateContainer;\n context: { message: parentMessage }\n \"\n ></ng-container>\n <div class=\"str-chat__thread-start\" translate>\n streamChat.Start of a new thread\n </div>\n </li>\n <li\n data-testclass=\"message\"\n *ngFor=\"\n let message of messages$ | async;\n let i = index;\n trackBy: trackByMessageId\n \"\n class=\"str-chat__li str-chat__li--{{ groupStyles[i] }}\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n messageTemplateContainer;\n context: { message: message }\n \"\n ></ng-container>\n </li>\n </ul>\n <ng-template #defaultTypingIndicator let-usersTyping$=\"usersTyping$\">\n <div\n *ngIf=\"$any(usersTyping$ | async)?.length\"\n data-testid=\"typing-indicator\"\n class=\"str-chat__typing-indicator str-chat__typing-indicator--typing\"\n >\n <stream-avatar-placeholder\n *ngFor=\"let user of usersTyping$ | async; trackBy: trackByUserId\"\n [name]=\"user.name || user.id\"\n [imageUrl]=\"user.image\"\n ></stream-avatar-placeholder>\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 </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__list-notifications\">\n <button\n data-testid=\"scroll-to-bottom\"\n *ngIf=\"isUserScrolledUp\"\n class=\"\n str-chat__message-notification\n str-chat__message-notification-right\n str-chat__message-notification-scroll-down\n \"\n (keyup.enter)=\"scrollToBottom()\"\n (click)=\"scrollToBottom()\"\n >\n <div\n *ngIf=\"unreadMessageCount > 0\"\n class=\"\n str-chat__message-notification\n str-chat__message-notification-scroll-down-unread-count\n \"\n >\n {{ unreadMessageCount }}\n </div>\n </button>\n</div>\n\n<ng-template #messageTemplateContainer let-message=\"message\">\n <ng-template\n #defaultMessageTemplate\n let-messageInput=\"message\"\n let-isLastSentMessage=\"isLastSentMessage\"\n let-enabledMessageActions=\"enabledMessageActions\"\n let-mode=\"mode\"\n >\n <stream-message\n [message]=\"messageInput\"\n [isLastSentMessage]=\"isLastSentMessage\"\n [enabledMessageActions]=\"enabledMessageActions\"\n [mode]=\"mode\"\n ></stream-message>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n messageTemplate || defaultMessageTemplate;\n context: getMessageContext(message)\n \"\n ></ng-container>\n</ng-template>\n", components: [{ type: AvatarPlaceholderComponent, selector: "stream-avatar-placeholder", inputs: ["name", "imageUrl", "size"] }, { type: MessageComponent, selector: "stream-message", inputs: ["message", "enabledMessageActions", "isLastSentMessage", "mode"] }], directives: [{ type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i2.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], pipes: { "async": i3.AsyncPipe } });
3850
4106
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: MessageListComponent, decorators: [{
3851
4107
  type: Component,
3852
4108
  args: [{
@@ -3854,20 +4110,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImpor
3854
4110
  templateUrl: './message-list.component.html',
3855
4111
  styles: [],
3856
4112
  }]
3857
- }], ctorParameters: function () { return [{ type: ChannelService }, { type: ChatClientService }, { type: ImageLoadService }]; }, propDecorators: { messageTemplate: [{
3858
- type: Input
3859
- }], messageInputTemplate: [{
3860
- type: Input
3861
- }], mentionTemplate: [{
3862
- type: Input
3863
- }], typingIndicatorTemplate: [{
3864
- type: Input
3865
- }], areReactionsEnabled: [{
3866
- type: Input
3867
- }], enabledMessageActionsInput: [{
3868
- type: Input,
3869
- args: ['enabledMessageActions']
3870
- }], mode: [{
4113
+ }], ctorParameters: function () { return [{ type: ChannelService }, { type: ChatClientService }, { type: ImageLoadService }, { type: CustomTemplatesService }]; }, propDecorators: { mode: [{
3871
4114
  type: Input
3872
4115
  }], class: [{
3873
4116
  type: HostBinding,
@@ -3884,7 +4127,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImpor
3884
4127
  * The `Thread` component represents a [message thread](https://getstream.io/chat/docs/javascript/threads/?language=javascript), it is a container component that displays a thread with a header, [`MessageList`](./MessageListComponent.mdx) and [`MessageInput`](./MessageInputComponent.mdx) components.
3885
4128
  */
3886
4129
  class ThreadComponent {
3887
- constructor(channelService) {
4130
+ constructor(customTemplatesService, channelService) {
4131
+ this.customTemplatesService = customTemplatesService;
3888
4132
  this.channelService = channelService;
3889
4133
  this.class = 'str-chat__thread';
3890
4134
  this.subscriptions = [];
@@ -3893,16 +4137,21 @@ class ThreadComponent {
3893
4137
  ngOnDestroy() {
3894
4138
  this.subscriptions.forEach((s) => s.unsubscribe());
3895
4139
  }
3896
- get replyCountParam() {
3897
- var _a;
3898
- return { replyCount: (_a = this.parentMessage) === null || _a === void 0 ? void 0 : _a.reply_count };
4140
+ getThreadHeaderContext() {
4141
+ return {
4142
+ parentMessage: this.parentMessage,
4143
+ closeThreadHandler: () => this.closeThread(),
4144
+ };
4145
+ }
4146
+ getReplyCountParam(parentMessage) {
4147
+ return { replyCount: parentMessage === null || parentMessage === void 0 ? void 0 : parentMessage.reply_count };
3899
4148
  }
3900
4149
  closeThread() {
3901
4150
  void this.channelService.setAsActiveParentMessage(undefined);
3902
4151
  }
3903
4152
  }
3904
- ThreadComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: ThreadComponent, deps: [{ token: ChannelService }], target: i0.ɵɵFactoryTarget.Component });
3905
- ThreadComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: ThreadComponent, selector: "stream-thread", host: { properties: { "class": "this.class" } }, ngImport: i0, template: "<div class=\"str-chat__thread-header\">\n <div class=\"str-chat__thread-header-details\">\n <strong translate>streamChat.Thread</strong>\n <small data-testid=\"reply-count\">\n {{parentMessage?.reply_count === 1 ? ('streamChat.1 reply' | translate) : ('streamChat.{{ replyCount }}\n replies' | translate:replyCountParam)}}\n </small>\n </div>\n <button\n class=\"str-chat__square-button\"\n data-testid=\"close-button\"\n (click)=\"closeThread()\"\n >\n <stream-icon icon=\"close-no-outline\"></stream-icon>\n </button>\n</div>\n<ng-content select='[name=\"thread-message-list\"]'></ng-content>\n<div class=\"str-chat__small-message-input__wrapper\">\n <ng-content select='[name=\"thread-message-input\"]'></ng-content>\n</div>\n", components: [{ type: IconComponent, selector: "stream-icon", inputs: ["icon", "size"] }], directives: [{ type: i2.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }], pipes: { "translate": i2.TranslatePipe } });
4153
+ ThreadComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: ThreadComponent, deps: [{ token: CustomTemplatesService }, { token: ChannelService }], target: i0.ɵɵFactoryTarget.Component });
4154
+ ThreadComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: ThreadComponent, selector: "stream-thread", host: { properties: { "class": "this.class" } }, ngImport: i0, template: "<ng-container\n *ngTemplateOutlet=\"\n (customTemplatesService.threadHeaderTemplate$ | async) ||\n defaultThreadHeader;\n context: getThreadHeaderContext()\n \"\n></ng-container>\n<ng-content select='[name=\"thread-message-list\"]'></ng-content>\n<div class=\"str-chat__small-message-input__wrapper\">\n <ng-content select='[name=\"thread-message-input\"]'></ng-content>\n</div>\n\n<ng-template\n #defaultThreadHeader\n let-parentMessage=\"parentMessage\"\n let-closeThreadHandler=\"closeThreadHandler\"\n>\n <div class=\"str-chat__thread-header\">\n <div class=\"str-chat__thread-header-details\">\n <strong translate>streamChat.Thread</strong>\n <small data-testid=\"reply-count\">\n {{parentMessage?.reply_count === 1 ? ('streamChat.1 reply' | translate) : ('streamChat.{{ replyCount }}\n replies' | translate:getReplyCountParam(parentMessage))}}\n </small>\n </div>\n <button\n class=\"str-chat__square-button\"\n data-testid=\"close-button\"\n (click)=\"closeThreadHandler()\"\n >\n <stream-icon-placeholder\n icon=\"close-no-outline\"\n ></stream-icon-placeholder>\n </button>\n </div>\n</ng-template>\n", components: [{ type: IconPlaceholderComponent, selector: "stream-icon-placeholder", inputs: ["icon", "size"] }], directives: [{ type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i2.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }], pipes: { "async": i3.AsyncPipe, "translate": i2.TranslatePipe } });
3906
4155
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: ThreadComponent, decorators: [{
3907
4156
  type: Component,
3908
4157
  args: [{
@@ -3910,7 +4159,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImpor
3910
4159
  templateUrl: './thread.component.html',
3911
4160
  styles: [],
3912
4161
  }]
3913
- }], ctorParameters: function () { return [{ type: ChannelService }]; }, propDecorators: { class: [{
4162
+ }], ctorParameters: function () { return [{ type: CustomTemplatesService }, { type: ChannelService }]; }, propDecorators: { class: [{
3914
4163
  type: HostBinding,
3915
4164
  args: ['class']
3916
4165
  }] } });
@@ -3918,14 +4167,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImpor
3918
4167
  class StreamAvatarModule {
3919
4168
  }
3920
4169
  StreamAvatarModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: StreamAvatarModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
3921
- StreamAvatarModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: StreamAvatarModule, declarations: [AvatarComponent], imports: [CommonModule, TranslateModule], exports: [AvatarComponent] });
4170
+ StreamAvatarModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: StreamAvatarModule, declarations: [AvatarComponent, AvatarPlaceholderComponent], imports: [CommonModule, TranslateModule], exports: [AvatarComponent, AvatarPlaceholderComponent] });
3922
4171
  StreamAvatarModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: StreamAvatarModule, imports: [[CommonModule, TranslateModule]] });
3923
4172
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: StreamAvatarModule, decorators: [{
3924
4173
  type: NgModule,
3925
4174
  args: [{
3926
- declarations: [AvatarComponent],
4175
+ declarations: [AvatarComponent, AvatarPlaceholderComponent],
3927
4176
  imports: [CommonModule, TranslateModule],
3928
- exports: [AvatarComponent],
4177
+ exports: [AvatarComponent, AvatarPlaceholderComponent],
3929
4178
  }]
3930
4179
  }] });
3931
4180
 
@@ -3949,7 +4198,9 @@ StreamChatModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", versio
3949
4198
  AttachmentPreviewListComponent,
3950
4199
  ModalComponent,
3951
4200
  TextareaDirective,
3952
- ThreadComponent], imports: [CommonModule, TranslateModule, StreamAvatarModule], exports: [ChannelComponent,
4201
+ ThreadComponent,
4202
+ IconPlaceholderComponent,
4203
+ LoadingIndicatorPlaceholderComponent], imports: [CommonModule, TranslateModule, StreamAvatarModule], exports: [ChannelComponent,
3953
4204
  ChannelHeaderComponent,
3954
4205
  ChannelListComponent,
3955
4206
  ChannelPreviewComponent,
@@ -3966,7 +4217,9 @@ StreamChatModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", versio
3966
4217
  AttachmentPreviewListComponent,
3967
4218
  ModalComponent,
3968
4219
  StreamAvatarModule,
3969
- ThreadComponent] });
4220
+ ThreadComponent,
4221
+ IconPlaceholderComponent,
4222
+ LoadingIndicatorPlaceholderComponent] });
3970
4223
  StreamChatModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: StreamChatModule, imports: [[CommonModule, TranslateModule, StreamAvatarModule], StreamAvatarModule] });
3971
4224
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: StreamChatModule, decorators: [{
3972
4225
  type: NgModule,
@@ -3990,6 +4243,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImpor
3990
4243
  ModalComponent,
3991
4244
  TextareaDirective,
3992
4245
  ThreadComponent,
4246
+ IconPlaceholderComponent,
4247
+ LoadingIndicatorPlaceholderComponent,
3993
4248
  ],
3994
4249
  imports: [CommonModule, TranslateModule, StreamAvatarModule],
3995
4250
  exports: [
@@ -4011,6 +4266,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImpor
4011
4266
  ModalComponent,
4012
4267
  StreamAvatarModule,
4013
4268
  ThreadComponent,
4269
+ IconPlaceholderComponent,
4270
+ LoadingIndicatorPlaceholderComponent,
4014
4271
  ],
4015
4272
  }]
4016
4273
  }] });
@@ -4073,5 +4330,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImpor
4073
4330
  * Generated bundle index. Do not edit.
4074
4331
  */
4075
4332
 
4076
- export { AttachmentListComponent, AttachmentPreviewListComponent, AttachmentService, AutocompleteTextareaComponent, AvatarComponent, ChannelComponent, ChannelHeaderComponent, ChannelListComponent, ChannelListToggleService, ChannelPreviewComponent, ChannelService, ChatClientService, EmojiInputService, IconComponent, ImageLoadService, LoadingIndicatorComponent, MessageActionsBoxComponent, MessageComponent, MessageInputComponent, MessageInputConfigService, MessageListComponent, MessageReactionsComponent, ModalComponent, NotificationComponent, NotificationListComponent, NotificationService, StreamAutocompleteTextareaModule, StreamAvatarModule, StreamChatModule, StreamI18nService, StreamTextareaModule, TextareaComponent, TextareaDirective, ThemeService, ThreadComponent, TransliterationService, createMessagePreview, getDeviceWidth, getGroupStyles, getReadBy, getReadByText, isImageAttachment, isImageFile, parseDate, textareaInjectionToken };
4333
+ export { AttachmentListComponent, AttachmentPreviewListComponent, AttachmentService, AutocompleteTextareaComponent, AvatarComponent, AvatarPlaceholderComponent, ChannelComponent, ChannelHeaderComponent, ChannelListComponent, ChannelListToggleService, ChannelPreviewComponent, ChannelService, ChatClientService, CustomTemplatesService, EmojiInputService, IconComponent, IconPlaceholderComponent, ImageLoadService, LoadingIndicatorComponent, LoadingIndicatorPlaceholderComponent, MessageActionsBoxComponent, MessageComponent, MessageInputComponent, MessageInputConfigService, MessageListComponent, MessageReactionsComponent, ModalComponent, NotificationComponent, NotificationListComponent, NotificationService, StreamAutocompleteTextareaModule, StreamAvatarModule, StreamChatModule, StreamI18nService, StreamTextareaModule, TextareaComponent, TextareaDirective, ThemeService, ThreadComponent, TransliterationService, createMessagePreview, getDeviceWidth, getGroupStyles, getReadBy, getReadByText, isImageAttachment, isImageFile, parseDate, textareaInjectionToken };
4077
4334
  //# sourceMappingURL=stream-chat-angular.js.map