stream-chat-angular 2.20.0 → 3.0.0-beta.3

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 (61) hide show
  1. package/assets/version.d.ts +1 -1
  2. package/bundles/stream-chat-angular.umd.js +623 -399
  3. package/bundles/stream-chat-angular.umd.js.map +1 -1
  4. package/esm2015/assets/version.js +2 -2
  5. package/esm2015/lib/attachment-list/attachment-list.component.js +27 -15
  6. package/esm2015/lib/attachment-preview-list/attachment-preview-list.component.js +28 -22
  7. package/esm2015/lib/avatar-placeholder/avatar-placeholder.component.js +41 -0
  8. package/esm2015/lib/channel-header/channel-header.component.js +26 -12
  9. package/esm2015/lib/channel-list/channel-list.component.js +23 -13
  10. package/esm2015/lib/channel-preview/channel-preview.component.js +3 -3
  11. package/esm2015/lib/channel.service.js +1 -1
  12. package/esm2015/lib/custom-templates.service.js +99 -0
  13. package/esm2015/lib/icon-placeholder/icon-placeholder.component.js +34 -0
  14. package/esm2015/lib/loading-indicator-placeholder/loading-indicator-placeholder.component.js +42 -0
  15. package/esm2015/lib/message/message.component.js +73 -23
  16. package/esm2015/lib/message-actions-box/message-actions-box.component.js +123 -95
  17. package/esm2015/lib/message-input/autocomplete-textarea/autocomplete-textarea.component.js +13 -13
  18. package/esm2015/lib/message-input/message-input-config.service.js +1 -1
  19. package/esm2015/lib/message-input/message-input.component.js +43 -45
  20. package/esm2015/lib/message-input/textarea.directive.js +2 -18
  21. package/esm2015/lib/message-input/textarea.interface.js +1 -1
  22. package/esm2015/lib/message-list/message-list.component.js +32 -93
  23. package/esm2015/lib/message-reactions/message-reactions.component.js +3 -3
  24. package/esm2015/lib/modal/modal.component.js +9 -6
  25. package/esm2015/lib/notification/notification.component.js +5 -2
  26. package/esm2015/lib/notification-list/notification-list.component.js +12 -10
  27. package/esm2015/lib/stream-avatar.module.js +5 -4
  28. package/esm2015/lib/stream-chat.module.js +13 -3
  29. package/esm2015/lib/thread/thread.component.js +19 -11
  30. package/esm2015/lib/types.js +1 -1
  31. package/esm2015/public-api.js +5 -1
  32. package/fesm2015/stream-chat-angular.js +570 -318
  33. package/fesm2015/stream-chat-angular.js.map +1 -1
  34. package/lib/attachment-list/attachment-list.component.d.ts +7 -3
  35. package/lib/attachment-preview-list/attachment-preview-list.component.d.ts +17 -7
  36. package/lib/avatar-placeholder/avatar-placeholder.component.d.ts +25 -0
  37. package/lib/channel-header/channel-header.component.d.ts +13 -10
  38. package/lib/channel-list/channel-list.component.d.ts +12 -9
  39. package/lib/channel.service.d.ts +1 -2
  40. package/lib/custom-templates.service.d.ts +92 -0
  41. package/lib/icon-placeholder/icon-placeholder.component.d.ts +22 -0
  42. package/lib/loading-indicator-placeholder/loading-indicator-placeholder.component.d.ts +21 -0
  43. package/lib/message/message.component.d.ts +21 -28
  44. package/lib/message-actions-box/message-actions-box.component.d.ts +20 -25
  45. package/lib/message-input/autocomplete-textarea/autocomplete-textarea.component.d.ts +6 -10
  46. package/lib/message-input/message-input-config.service.d.ts +0 -19
  47. package/lib/message-input/message-input.component.d.ts +15 -25
  48. package/lib/message-input/textarea.directive.d.ts +2 -5
  49. package/lib/message-input/textarea.interface.d.ts +1 -4
  50. package/lib/message-list/message-list.component.d.ts +10 -34
  51. package/lib/message-reactions/message-reactions.component.d.ts +1 -2
  52. package/lib/modal/modal.component.d.ts +7 -3
  53. package/lib/notification/notification.component.d.ts +6 -1
  54. package/lib/notification-list/notification-list.component.d.ts +4 -2
  55. package/lib/stream-avatar.module.d.ts +4 -3
  56. package/lib/stream-chat.module.d.ts +6 -4
  57. package/lib/thread/thread.component.d.ts +6 -3
  58. package/lib/types.d.ts +99 -1
  59. package/package.json +1 -1
  60. package/public-api.d.ts +4 -0
  61. package/src/assets/version.ts +1 -1
@@ -1,8 +1,8 @@
1
1
  (function (global, factory) {
2
2
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/core'), require('rxjs'), require('stream-chat'), require('rxjs/operators'), require('uuid'), require('@ngx-translate/core'), require('@angular/common'), require('pretty-bytes'), require('dayjs'), require('dayjs/plugin/calendar'), require('emoji-regex'), require('@stream-io/transliterate'), require('angular-mentions')) :
3
3
  typeof define === 'function' && define.amd ? define('stream-chat-angular', ['exports', '@angular/core', 'rxjs', 'stream-chat', 'rxjs/operators', 'uuid', '@ngx-translate/core', '@angular/common', 'pretty-bytes', 'dayjs', 'dayjs/plugin/calendar', 'emoji-regex', '@stream-io/transliterate', 'angular-mentions'], factory) :
4
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global['stream-chat-angular'] = {}, global.ng.core, global.rxjs, global.streamChat, global.rxjs.operators, global.uuid, global.i2, global.ng.common, global.prettybytes, global.Dayjs, global.calendar, global.emojiRegex, global.transliterate, global.i6$1));
5
- }(this, (function (exports, i0, rxjs, streamChat, operators, uuid, i2, i6, prettybytes, Dayjs, calendar, emojiRegex, transliterate, i6$1) { 'use strict';
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global['stream-chat-angular'] = {}, global.ng.core, global.rxjs, global.streamChat, global.rxjs.operators, global.uuid, global.i2, global.ng.common, global.prettybytes, global.Dayjs, global.calendar, global.emojiRegex, global.transliterate, global.i7));
5
+ }(this, (function (exports, i0, rxjs, streamChat, operators, uuid, i2, i3, prettybytes, Dayjs, calendar, emojiRegex, transliterate, i7) { 'use strict';
6
6
 
7
7
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
8
8
 
@@ -28,13 +28,13 @@
28
28
 
29
29
  var i0__namespace = /*#__PURE__*/_interopNamespace(i0);
30
30
  var i2__namespace = /*#__PURE__*/_interopNamespace(i2);
31
- var i6__namespace = /*#__PURE__*/_interopNamespace(i6);
31
+ var i3__namespace = /*#__PURE__*/_interopNamespace(i3);
32
32
  var prettybytes__default = /*#__PURE__*/_interopDefaultLegacy(prettybytes);
33
33
  var Dayjs__default = /*#__PURE__*/_interopDefaultLegacy(Dayjs);
34
34
  var calendar__default = /*#__PURE__*/_interopDefaultLegacy(calendar);
35
35
  var emojiRegex__default = /*#__PURE__*/_interopDefaultLegacy(emojiRegex);
36
36
  var transliterate__default = /*#__PURE__*/_interopDefaultLegacy(transliterate);
37
- var i6__namespace$1 = /*#__PURE__*/_interopNamespace(i6$1);
37
+ var i7__namespace = /*#__PURE__*/_interopNamespace(i7);
38
38
 
39
39
  /*! *****************************************************************************
40
40
  Copyright (c) Microsoft Corporation.
@@ -354,7 +354,7 @@
354
354
  return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
355
355
  }
356
356
 
357
- var version = '2.20.0';
357
+ var version = '3.0.0-beta.3';
358
358
 
359
359
  /**
360
360
  * The `NotificationService` can be used to add or remove notifications. By default the [`NotificationList`](../components/NotificationListComponent.mdx) component displays the currently active notifications.
@@ -2197,7 +2197,7 @@
2197
2197
  return AvatarComponent;
2198
2198
  }());
2199
2199
  AvatarComponent.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: AvatarComponent, deps: [], target: i0__namespace.ɵɵFactoryTarget.Component });
2200
- AvatarComponent.ɵcmp = i0__namespace.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: AvatarComponent, selector: "stream-avatar", inputs: { name: "name", imageUrl: "imageUrl", size: "size" }, ngImport: i0__namespace, 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__namespace.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
2200
+ AvatarComponent.ɵcmp = i0__namespace.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: AvatarComponent, selector: "stream-avatar", inputs: { name: "name", imageUrl: "imageUrl", size: "size" }, ngImport: i0__namespace, 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__namespace.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
2201
2201
  i0__namespace.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: AvatarComponent, decorators: [{
2202
2202
  type: i0.Component,
2203
2203
  args: [{
@@ -2213,6 +2213,140 @@
2213
2213
  type: i0.Input
2214
2214
  }] } });
2215
2215
 
2216
+ /**
2217
+ * A central location for registering your custom templates to override parts of the chat application
2218
+ */
2219
+ var CustomTemplatesService = /** @class */ (function () {
2220
+ function CustomTemplatesService() {
2221
+ /**
2222
+ * The autocomplete list item template for mentioning users
2223
+ */
2224
+ this.mentionAutocompleteItemTemplate$ = new rxjs.BehaviorSubject(undefined);
2225
+ /**
2226
+ * The autocomplete list item template for commands
2227
+ */
2228
+ this.commandAutocompleteItemTemplate$ = new rxjs.BehaviorSubject(undefined);
2229
+ /**
2230
+ * Item in the channel list
2231
+ */
2232
+ this.channelPreviewTemplate$ = new rxjs.BehaviorSubject(undefined);
2233
+ /**
2234
+ * The message input template used when editing a message
2235
+ */
2236
+ this.messageInputTemplate$ = new rxjs.BehaviorSubject(undefined);
2237
+ /**
2238
+ * The template used for displaying a mention inside a message
2239
+ */
2240
+ this.mentionTemplate$ = new rxjs.BehaviorSubject(undefined);
2241
+ /**
2242
+ * The template for emoji picker
2243
+ */
2244
+ this.emojiPickerTemplate$ = new rxjs.BehaviorSubject(undefined);
2245
+ /**
2246
+ * The typing indicator template used in the message list
2247
+ */
2248
+ this.typingIndicatorTemplate$ = new rxjs.BehaviorSubject(undefined);
2249
+ /**
2250
+ * The template used to display a message in the message list
2251
+ */
2252
+ this.messageTemplate$ = new rxjs.BehaviorSubject(undefined);
2253
+ /**
2254
+ * The template for channel actions
2255
+ */
2256
+ this.channelActionsTemplate$ = new rxjs.BehaviorSubject(undefined);
2257
+ /**
2258
+ * The template used to display attachments of a message
2259
+ */
2260
+ this.attachmentListTemplate$ = new rxjs.BehaviorSubject(undefined);
2261
+ /**
2262
+ * The template used to display attachments in the message input component
2263
+ */
2264
+ this.attachmentPreviewListTemplate$ = new rxjs.BehaviorSubject(undefined);
2265
+ /**
2266
+ * The template used to display avatars for channels and users
2267
+ */
2268
+ this.avatarTemplate$ = new rxjs.BehaviorSubject(undefined);
2269
+ /**
2270
+ * Template for displaying icons
2271
+ */
2272
+ this.iconTemplate$ = new rxjs.BehaviorSubject(undefined);
2273
+ /**
2274
+ * Template for displaying the loading indicator (instead of the [default loading indicator](../components/LoadingIndicatorComponent.mdx))
2275
+ */
2276
+ this.loadingIndicatorTemplate$ = new rxjs.BehaviorSubject(undefined);
2277
+ /**
2278
+ * Template for displaying the message actions box (instead of the [default message actions box](../components/MessageActionsBoxComponent.mdx))
2279
+ */
2280
+ this.messageActionsBoxTemplate$ = new rxjs.BehaviorSubject(undefined);
2281
+ /**
2282
+ * The template used for displaying an item in the [message actions box](../components/MessageActionsBoxComponent.mdx)]
2283
+ */
2284
+ this.messageActionsBoxItemTemplate$ = new rxjs.BehaviorSubject(undefined);
2285
+ /**
2286
+ * The template used to display the reactions of a message, and the selector to add a reaction to a message (instead of the [default message reactions component](../components/MessageReactionsComponent.mdx))
2287
+ */
2288
+ this.messageReactionsTemplate$ = new rxjs.BehaviorSubject(undefined);
2289
+ /**
2290
+ * The template used to display a modal window (instead of the [default modal](../components/ModalComponent.mdx))
2291
+ */
2292
+ this.modalTemplate$ = new rxjs.BehaviorSubject(undefined);
2293
+ /**
2294
+ * The template used to override the [default notification component](../components/NotificationComponent.mdx)
2295
+ */
2296
+ this.notificationTemplate$ = new rxjs.BehaviorSubject(undefined);
2297
+ /**
2298
+ * The template used for header of thread
2299
+ */
2300
+ this.threadHeaderTemplate$ = new rxjs.BehaviorSubject(undefined);
2301
+ }
2302
+ return CustomTemplatesService;
2303
+ }());
2304
+ CustomTemplatesService.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: CustomTemplatesService, deps: [], target: i0__namespace.ɵɵFactoryTarget.Injectable });
2305
+ CustomTemplatesService.ɵprov = i0__namespace.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: CustomTemplatesService, providedIn: 'root' });
2306
+ i0__namespace.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: CustomTemplatesService, decorators: [{
2307
+ type: i0.Injectable,
2308
+ args: [{
2309
+ providedIn: 'root',
2310
+ }]
2311
+ }], ctorParameters: function () { return []; } });
2312
+
2313
+ /**
2314
+ * 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.
2315
+ */
2316
+ var AvatarPlaceholderComponent = /** @class */ (function () {
2317
+ function AvatarPlaceholderComponent(customTemplatesService) {
2318
+ this.customTemplatesService = customTemplatesService;
2319
+ /**
2320
+ * The size in pixels of the avatar image.
2321
+ */
2322
+ this.size = 32;
2323
+ }
2324
+ AvatarPlaceholderComponent.prototype.getAvatarContext = function () {
2325
+ return {
2326
+ name: this.name,
2327
+ imageUrl: this.imageUrl,
2328
+ size: this.size,
2329
+ };
2330
+ };
2331
+ return AvatarPlaceholderComponent;
2332
+ }());
2333
+ AvatarPlaceholderComponent.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: AvatarPlaceholderComponent, deps: [{ token: CustomTemplatesService }], target: i0__namespace.ɵɵFactoryTarget.Component });
2334
+ AvatarPlaceholderComponent.ɵcmp = i0__namespace.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: AvatarPlaceholderComponent, selector: "stream-avatar-placeholder", inputs: { name: "name", imageUrl: "imageUrl", size: "size" }, ngImport: i0__namespace, 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__namespace.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }], pipes: { "async": i3__namespace.AsyncPipe } });
2335
+ i0__namespace.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: AvatarPlaceholderComponent, decorators: [{
2336
+ type: i0.Component,
2337
+ args: [{
2338
+ selector: 'stream-avatar-placeholder',
2339
+ templateUrl: './avatar-placeholder.component.html',
2340
+ styles: [],
2341
+ }]
2342
+ }], ctorParameters: function () { return [{ type: CustomTemplatesService }]; }, propDecorators: { name: [{
2343
+ type: i0.Input
2344
+ }], imageUrl: [{
2345
+ type: i0.Input
2346
+ }], size: [{
2347
+ type: i0.Input
2348
+ }] } });
2349
+
2216
2350
  /**
2217
2351
  * The `Icon` component can be used to display different icons (i. e. message delivered icon).
2218
2352
  */
@@ -2222,7 +2356,7 @@
2222
2356
  return IconComponent;
2223
2357
  }());
2224
2358
  IconComponent.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: IconComponent, deps: [], target: i0__namespace.ɵɵFactoryTarget.Component });
2225
- IconComponent.ɵcmp = i0__namespace.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: IconComponent, selector: "stream-icon", inputs: { icon: "icon", size: "size" }, ngImport: i0__namespace, 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__namespace.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2__namespace.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }] });
2359
+ IconComponent.ɵcmp = i0__namespace.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: IconComponent, selector: "stream-icon", inputs: { icon: "icon", size: "size" }, ngImport: i0__namespace, 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__namespace.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2__namespace.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }] });
2226
2360
  i0__namespace.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: IconComponent, decorators: [{
2227
2361
  type: i0.Component,
2228
2362
  args: [{
@@ -2236,6 +2370,36 @@
2236
2370
  type: i0.Input
2237
2371
  }] } });
2238
2372
 
2373
+ /**
2374
+ * 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.
2375
+ */
2376
+ var IconPlaceholderComponent = /** @class */ (function () {
2377
+ function IconPlaceholderComponent(customTemplatesService) {
2378
+ this.customTemplatesService = customTemplatesService;
2379
+ }
2380
+ IconPlaceholderComponent.prototype.getIconContext = function () {
2381
+ return {
2382
+ icon: this.icon,
2383
+ size: this.size,
2384
+ };
2385
+ };
2386
+ return IconPlaceholderComponent;
2387
+ }());
2388
+ IconPlaceholderComponent.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: IconPlaceholderComponent, deps: [{ token: CustomTemplatesService }], target: i0__namespace.ɵɵFactoryTarget.Component });
2389
+ IconPlaceholderComponent.ɵcmp = i0__namespace.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: IconPlaceholderComponent, selector: "stream-icon-placeholder", inputs: { icon: "icon", size: "size" }, ngImport: i0__namespace, 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__namespace.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }], pipes: { "async": i3__namespace.AsyncPipe } });
2390
+ i0__namespace.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: IconPlaceholderComponent, decorators: [{
2391
+ type: i0.Component,
2392
+ args: [{
2393
+ selector: 'stream-icon-placeholder',
2394
+ templateUrl: './icon-placeholder.component.html',
2395
+ styles: [],
2396
+ }]
2397
+ }], ctorParameters: function () { return [{ type: CustomTemplatesService }]; }, propDecorators: { icon: [{
2398
+ type: i0.Input
2399
+ }], size: [{
2400
+ type: i0.Input
2401
+ }] } });
2402
+
2239
2403
  /**
2240
2404
  * The `LoadingIndicator` component displays a spinner to indicate that an action is in progress.
2241
2405
  */
@@ -2253,7 +2417,7 @@
2253
2417
  return LoadingIndicatorComponent;
2254
2418
  }());
2255
2419
  LoadingIndicatorComponent.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: LoadingIndicatorComponent, deps: [], target: i0__namespace.ɵɵFactoryTarget.Component });
2256
- LoadingIndicatorComponent.ɵcmp = i0__namespace.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: LoadingIndicatorComponent, selector: "stream-loading-indicator", inputs: { size: "size", color: "color" }, ngImport: i0__namespace, 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__namespace.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
2420
+ LoadingIndicatorComponent.ɵcmp = i0__namespace.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: LoadingIndicatorComponent, selector: "stream-loading-indicator", inputs: { size: "size", color: "color" }, ngImport: i0__namespace, 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__namespace.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
2257
2421
  i0__namespace.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: LoadingIndicatorComponent, decorators: [{
2258
2422
  type: i0.Component,
2259
2423
  args: [{
@@ -2267,6 +2431,44 @@
2267
2431
  type: i0.Input
2268
2432
  }] } });
2269
2433
 
2434
+ /**
2435
+ * 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.
2436
+ */
2437
+ var LoadingIndicatorPlaceholderComponent = /** @class */ (function () {
2438
+ function LoadingIndicatorPlaceholderComponent(customTemplatesService) {
2439
+ this.customTemplatesService = customTemplatesService;
2440
+ /**
2441
+ * The size of the indicator (in pixels)
2442
+ */
2443
+ this.size = 15;
2444
+ /**
2445
+ * The color of the indicator
2446
+ */
2447
+ this.color = '#006CFF';
2448
+ }
2449
+ LoadingIndicatorPlaceholderComponent.prototype.getLoadingIndicatorContext = function () {
2450
+ return {
2451
+ size: this.size,
2452
+ color: this.color,
2453
+ };
2454
+ };
2455
+ return LoadingIndicatorPlaceholderComponent;
2456
+ }());
2457
+ LoadingIndicatorPlaceholderComponent.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: LoadingIndicatorPlaceholderComponent, deps: [{ token: CustomTemplatesService }], target: i0__namespace.ɵɵFactoryTarget.Component });
2458
+ LoadingIndicatorPlaceholderComponent.ɵcmp = i0__namespace.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: LoadingIndicatorPlaceholderComponent, selector: "stream-loading-indicator-placeholder", inputs: { size: "size", color: "color" }, ngImport: i0__namespace, 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__namespace.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }], pipes: { "async": i3__namespace.AsyncPipe } });
2459
+ i0__namespace.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: LoadingIndicatorPlaceholderComponent, decorators: [{
2460
+ type: i0.Component,
2461
+ args: [{
2462
+ selector: 'stream-loading-indicator-placeholder',
2463
+ templateUrl: './loading-indicator-placeholder.component.html',
2464
+ styles: [],
2465
+ }]
2466
+ }], ctorParameters: function () { return [{ type: CustomTemplatesService }]; }, propDecorators: { size: [{
2467
+ type: i0.Input
2468
+ }], color: [{
2469
+ type: i0.Input
2470
+ }] } });
2471
+
2270
2472
  var textareaInjectionToken = new i0.InjectionToken('textareaInjectionToken');
2271
2473
 
2272
2474
  var TextareaDirective = /** @class */ (function () {
@@ -2294,10 +2496,6 @@
2294
2496
  this.subscriptions.push(this.componentRef.instance.userMentions.subscribe(function (value) { return _this.userMentions.next(value); }));
2295
2497
  }
2296
2498
  this.componentRef.instance.areMentionsEnabled = this.areMentionsEnabled;
2297
- this.componentRef.instance.mentionAutocompleteItemTemplate =
2298
- this.mentionAutocompleteItemTemplate;
2299
- this.componentRef.instance.commandAutocompleteItemTemplate =
2300
- this.commandAutocompleteItemTemplate;
2301
2499
  this.componentRef.instance.mentionScope = this.mentionScope;
2302
2500
  this.componentRef.instance.value = this.value;
2303
2501
  }
@@ -2305,14 +2503,6 @@
2305
2503
  if (changes.areMentionsEnabled) {
2306
2504
  this.componentRef.instance.areMentionsEnabled = this.areMentionsEnabled;
2307
2505
  }
2308
- if (changes.mentionAutocompleteItemTemplate) {
2309
- this.componentRef.instance.mentionAutocompleteItemTemplate =
2310
- this.mentionAutocompleteItemTemplate;
2311
- }
2312
- if (changes.commandAutocompleteItemTemplate) {
2313
- this.componentRef.instance.commandAutocompleteItemTemplate =
2314
- this.commandAutocompleteItemTemplate;
2315
- }
2316
2506
  if (changes.mentionScope) {
2317
2507
  this.componentRef.instance.mentionScope = this.mentionScope;
2318
2508
  }
@@ -2329,7 +2519,7 @@
2329
2519
  return TextareaDirective;
2330
2520
  }());
2331
2521
  TextareaDirective.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: TextareaDirective, deps: [{ token: i0__namespace.ViewContainerRef }], target: i0__namespace.ɵɵFactoryTarget.Directive });
2332
- TextareaDirective.ɵdir = i0__namespace.ɵɵ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__namespace });
2522
+ TextareaDirective.ɵdir = i0__namespace.ɵɵ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__namespace });
2333
2523
  i0__namespace.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: TextareaDirective, decorators: [{
2334
2524
  type: i0.Directive,
2335
2525
  args: [{
@@ -2339,12 +2529,8 @@
2339
2529
  type: i0.Input
2340
2530
  }], areMentionsEnabled: [{
2341
2531
  type: i0.Input
2342
- }], mentionAutocompleteItemTemplate: [{
2343
- type: i0.Input
2344
2532
  }], mentionScope: [{
2345
2533
  type: i0.Input
2346
- }], commandAutocompleteItemTemplate: [{
2347
- type: i0.Input
2348
2534
  }], value: [{
2349
2535
  type: i0.Input
2350
2536
  }], valueChange: [{
@@ -2454,7 +2640,7 @@
2454
2640
  };
2455
2641
  this.watchForOutsideClicks = function (event) {
2456
2642
  var _a;
2457
- if (!((_a = _this.content) === null || _a === void 0 ? void 0 : _a.nativeElement.contains(event.target))) {
2643
+ if (!((_a = _this.innerContainer) === null || _a === void 0 ? void 0 : _a.nativeElement.contains(event.target))) {
2458
2644
  _this.close();
2459
2645
  }
2460
2646
  };
@@ -2484,7 +2670,7 @@
2484
2670
  return ModalComponent;
2485
2671
  }());
2486
2672
  ModalComponent.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: ModalComponent, deps: [], target: i0__namespace.ɵɵFactoryTarget.Component });
2487
- ModalComponent.ɵcmp = i0__namespace.ɵɵ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__namespace, 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__namespace.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }] });
2673
+ ModalComponent.ɵcmp = i0__namespace.ɵɵ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__namespace, 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__namespace.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i3__namespace.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3__namespace.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }] });
2488
2674
  i0__namespace.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: ModalComponent, decorators: [{
2489
2675
  type: i0.Component,
2490
2676
  args: [{
@@ -2494,18 +2680,21 @@
2494
2680
  }]
2495
2681
  }], ctorParameters: function () { return []; }, propDecorators: { isOpen: [{
2496
2682
  type: i0.Input
2683
+ }], content: [{
2684
+ type: i0.Input
2497
2685
  }], isOpenChange: [{
2498
2686
  type: i0.Output
2499
- }], content: [{
2687
+ }], innerContainer: [{
2500
2688
  type: i0.ViewChild,
2501
- args: ['content']
2689
+ args: ['modalInner']
2502
2690
  }] } });
2503
2691
 
2504
2692
  /**
2505
2693
  * The `AttachmentList` compontent displays the attachments of a message
2506
2694
  */
2507
2695
  var AttachmentListComponent = /** @class */ (function () {
2508
- function AttachmentListComponent(imageLoadService, channelService) {
2696
+ function AttachmentListComponent(customTemplatesService, imageLoadService, channelService) {
2697
+ this.customTemplatesService = customTemplatesService;
2509
2698
  this.imageLoadService = imageLoadService;
2510
2699
  this.channelService = channelService;
2511
2700
  /**
@@ -2548,6 +2737,14 @@
2548
2737
  AttachmentListComponent.prototype.getFileSize = function (attachment) {
2549
2738
  return prettybytes__default['default'](Number(attachment.file_size));
2550
2739
  };
2740
+ AttachmentListComponent.prototype.getModalContext = function () {
2741
+ var _this = this;
2742
+ return {
2743
+ isOpen: this.imagesToView && this.imagesToView.length > 0,
2744
+ isOpenChangeHandler: function (isOpen) { return (isOpen ? null : _this.closeImageModal()); },
2745
+ content: this.modalContent,
2746
+ };
2747
+ };
2551
2748
  AttachmentListComponent.prototype.trimUrl = function (url) {
2552
2749
  if (url !== undefined && url !== null) {
2553
2750
  var _a = __read(url
@@ -2571,9 +2768,6 @@
2571
2768
  this.imagesToView = attachments;
2572
2769
  this.imagesToViewCurrentIndex = selectedIndex;
2573
2770
  };
2574
- AttachmentListComponent.prototype.closeImageModal = function () {
2575
- this.imagesToView = [];
2576
- };
2577
2771
  AttachmentListComponent.prototype.stepImages = function (dir) {
2578
2772
  this.imagesToViewCurrentIndex += dir * 1;
2579
2773
  };
@@ -2602,10 +2796,13 @@
2602
2796
  },
2603
2797
  ];
2604
2798
  };
2799
+ AttachmentListComponent.prototype.closeImageModal = function () {
2800
+ this.imagesToView = [];
2801
+ };
2605
2802
  return AttachmentListComponent;
2606
2803
  }());
2607
- AttachmentListComponent.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: AttachmentListComponent, deps: [{ token: ImageLoadService }, { token: ChannelService }], target: i0__namespace.ɵɵFactoryTarget.Component });
2608
- AttachmentListComponent.ɵcmp = i0__namespace.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: AttachmentListComponent, selector: "stream-attachment-list", inputs: { messageId: "messageId", attachments: "attachments" }, usesOnChanges: true, ngImport: i0__namespace, 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__namespace.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i6__namespace.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i6__namespace.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }], pipes: { "translate": i2__namespace.TranslatePipe } });
2804
+ AttachmentListComponent.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: AttachmentListComponent, deps: [{ token: CustomTemplatesService }, { token: ImageLoadService }, { token: ChannelService }], target: i0__namespace.ɵɵFactoryTarget.Component });
2805
+ AttachmentListComponent.ɵcmp = i0__namespace.ɵɵ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__namespace, 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__namespace.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i3__namespace.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3__namespace.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { type: i3__namespace.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }], pipes: { "translate": i2__namespace.TranslatePipe, "async": i3__namespace.AsyncPipe } });
2609
2806
  i0__namespace.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: AttachmentListComponent, decorators: [{
2610
2807
  type: i0.Component,
2611
2808
  args: [{
@@ -2613,51 +2810,42 @@
2613
2810
  templateUrl: './attachment-list.component.html',
2614
2811
  styles: [],
2615
2812
  }]
2616
- }], ctorParameters: function () { return [{ type: ImageLoadService }, { type: ChannelService }]; }, propDecorators: { messageId: [{
2813
+ }], ctorParameters: function () { return [{ type: CustomTemplatesService }, { type: ImageLoadService }, { type: ChannelService }]; }, propDecorators: { messageId: [{
2617
2814
  type: i0.Input
2618
2815
  }], attachments: [{
2619
2816
  type: i0.Input
2817
+ }], modalContent: [{
2818
+ type: i0.ViewChild,
2819
+ args: ['modalContent', { static: true }]
2620
2820
  }] } });
2621
2821
 
2622
2822
  /**
2623
2823
  * 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.
2624
2824
  */
2625
2825
  var AttachmentPreviewListComponent = /** @class */ (function () {
2626
- function AttachmentPreviewListComponent(attachmentService) {
2627
- this.attachmentService = attachmentService;
2628
- this.attachmentUploads$ = this.attachmentService.attachmentUploads$;
2826
+ function AttachmentPreviewListComponent() {
2827
+ /**
2828
+ * An output to notify the parent component if the user tries to retry a failed upload
2829
+ */
2830
+ this.retryAttachmentUpload = new i0.EventEmitter();
2831
+ /**
2832
+ * An output to notify the parent component if the user wants to delete a file
2833
+ */
2834
+ this.deleteAttachment = new i0.EventEmitter();
2629
2835
  }
2630
- AttachmentPreviewListComponent.prototype.retryAttachmentUpload = function (file) {
2631
- return __awaiter(this, void 0, void 0, function () {
2632
- return __generator(this, function (_a) {
2633
- switch (_a.label) {
2634
- case 0: return [4 /*yield*/, this.attachmentService.retryAttachmentUpload(file)];
2635
- case 1:
2636
- _a.sent();
2637
- return [2 /*return*/];
2638
- }
2639
- });
2640
- });
2836
+ AttachmentPreviewListComponent.prototype.attachmentUploadRetried = function (file) {
2837
+ this.retryAttachmentUpload.emit(file);
2641
2838
  };
2642
- AttachmentPreviewListComponent.prototype.deleteAttachment = function (upload) {
2643
- return __awaiter(this, void 0, void 0, function () {
2644
- return __generator(this, function (_a) {
2645
- switch (_a.label) {
2646
- case 0: return [4 /*yield*/, this.attachmentService.deleteAttachment(upload)];
2647
- case 1:
2648
- _a.sent();
2649
- return [2 /*return*/];
2650
- }
2651
- });
2652
- });
2839
+ AttachmentPreviewListComponent.prototype.attachmentDeleted = function (upload) {
2840
+ this.deleteAttachment.emit(upload);
2653
2841
  };
2654
2842
  AttachmentPreviewListComponent.prototype.trackByFile = function (_, item) {
2655
2843
  return item.file;
2656
2844
  };
2657
2845
  return AttachmentPreviewListComponent;
2658
2846
  }());
2659
- AttachmentPreviewListComponent.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: AttachmentPreviewListComponent, deps: [{ token: AttachmentService }], target: i0__namespace.ɵɵFactoryTarget.Component });
2660
- AttachmentPreviewListComponent.ɵcmp = i0__namespace.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: AttachmentPreviewListComponent, selector: "stream-attachment-preview-list", ngImport: i0__namespace, 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__namespace.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i6__namespace.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i2__namespace.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }], pipes: { "async": i6__namespace.AsyncPipe } });
2847
+ AttachmentPreviewListComponent.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: AttachmentPreviewListComponent, deps: [], target: i0__namespace.ɵɵFactoryTarget.Component });
2848
+ AttachmentPreviewListComponent.ɵcmp = i0__namespace.ɵɵ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__namespace, 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__namespace.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3__namespace.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i2__namespace.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }], pipes: { "async": i3__namespace.AsyncPipe } });
2661
2849
  i0__namespace.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: AttachmentPreviewListComponent, decorators: [{
2662
2850
  type: i0.Component,
2663
2851
  args: [{
@@ -2665,13 +2853,19 @@
2665
2853
  templateUrl: './attachment-preview-list.component.html',
2666
2854
  styles: [],
2667
2855
  }]
2668
- }], ctorParameters: function () { return [{ type: AttachmentService }]; } });
2856
+ }], ctorParameters: function () { return []; }, propDecorators: { attachmentUploads$: [{
2857
+ type: i0.Input
2858
+ }], retryAttachmentUpload: [{
2859
+ type: i0.Output
2860
+ }], deleteAttachment: [{
2861
+ type: i0.Output
2862
+ }] } });
2669
2863
 
2670
2864
  /**
2671
2865
  * 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).
2672
2866
  */
2673
2867
  var MessageInputComponent = /** @class */ (function () {
2674
- function MessageInputComponent(channelService, notificationService, attachmentService, configService, textareaType, componentFactoryResolver, cdRef, chatClient, emojiInputService) {
2868
+ function MessageInputComponent(channelService, notificationService, attachmentService, configService, textareaType, componentFactoryResolver, cdRef, chatClient, emojiInputService, customTemplatesService) {
2675
2869
  var _this = this;
2676
2870
  this.channelService = channelService;
2677
2871
  this.notificationService = notificationService;
@@ -2682,6 +2876,7 @@
2682
2876
  this.cdRef = cdRef;
2683
2877
  this.chatClient = chatClient;
2684
2878
  this.emojiInputService = emojiInputService;
2879
+ this.customTemplatesService = customTemplatesService;
2685
2880
  /**
2686
2881
  * Determines if the message is being dispalyed in a channel or in a [thread](https://getstream.io/chat/docs/javascript/threads/?language=javascript).
2687
2882
  */
@@ -2726,16 +2921,10 @@
2726
2921
  }));
2727
2922
  this.attachmentUploads$ = this.attachmentService.attachmentUploads$;
2728
2923
  this.isFileUploadEnabled = this.configService.isFileUploadEnabled;
2729
- this.acceptedFileTypes = this.configService.acceptedFileTypes;
2730
2924
  this.isMultipleFileUploadEnabled =
2731
2925
  this.configService.isMultipleFileUploadEnabled;
2732
2926
  this.areMentionsEnabled = this.configService.areMentionsEnabled;
2733
- this.mentionAutocompleteItemTemplate =
2734
- this.configService.mentionAutocompleteItemTemplate;
2735
2927
  this.mentionScope = this.configService.mentionScope;
2736
- this.commandAutocompleteItemTemplate =
2737
- this.configService.commandAutocompleteItemTemplate;
2738
- this.emojiPickerTemplate = this.configService.emojiPickerTemplate;
2739
2928
  this.subscriptions.push(this.typingStart$.subscribe(function () { return void _this.channelService.typingStarted(_this.parentMessageId); }));
2740
2929
  this.subscriptions.push(rxjs.combineLatest([
2741
2930
  this.channelService.latestMessageDateByUserByChannels$,
@@ -2762,6 +2951,17 @@
2762
2951
  }
2763
2952
  }));
2764
2953
  }
2954
+ MessageInputComponent.prototype.ngOnInit = function () {
2955
+ var _this = this;
2956
+ this.subscriptions.push(this.customTemplatesService.emojiPickerTemplate$.subscribe(function (template) {
2957
+ _this.emojiPickerTemplate = template;
2958
+ _this.cdRef.detectChanges();
2959
+ }));
2960
+ this.subscriptions.push(this.customTemplatesService.attachmentPreviewListTemplate$.subscribe(function (template) {
2961
+ _this.attachmentPreviewListTemplate = template;
2962
+ _this.cdRef.detectChanges();
2963
+ }));
2964
+ };
2765
2965
  MessageInputComponent.prototype.ngAfterViewInit = function () {
2766
2966
  this.isViewInited = true;
2767
2967
  this.initTextarea();
@@ -2777,9 +2977,6 @@
2777
2977
  if (changes.isFileUploadEnabled) {
2778
2978
  this.configService.isFileUploadEnabled = this.isFileUploadEnabled;
2779
2979
  }
2780
- if (changes.acceptedFileTypes) {
2781
- this.configService.acceptedFileTypes = this.acceptedFileTypes;
2782
- }
2783
2980
  if (changes.isMultipleFileUploadEnabled) {
2784
2981
  this.configService.isMultipleFileUploadEnabled =
2785
2982
  this.isMultipleFileUploadEnabled;
@@ -2787,20 +2984,9 @@
2787
2984
  if (changes.areMentionsEnabled) {
2788
2985
  this.configService.areMentionsEnabled = this.areMentionsEnabled;
2789
2986
  }
2790
- if (changes.mentionAutocompleteItemTemplate) {
2791
- this.configService.mentionAutocompleteItemTemplate =
2792
- this.mentionAutocompleteItemTemplate;
2793
- }
2794
- if (changes.commandAutocompleteItemTemplate) {
2795
- this.configService.commandAutocompleteItemTemplate =
2796
- this.commandAutocompleteItemTemplate;
2797
- }
2798
2987
  if (changes.mentionScope) {
2799
2988
  this.configService.mentionScope = this.mentionScope;
2800
2989
  }
2801
- if (changes.emojiPickerTemplate) {
2802
- this.configService.emojiPickerTemplate = this.emojiPickerTemplate;
2803
- }
2804
2990
  if (changes.mode) {
2805
2991
  this.setCanSendMessages();
2806
2992
  }
@@ -2873,14 +3059,6 @@
2873
3059
  enumerable: false,
2874
3060
  configurable: true
2875
3061
  });
2876
- Object.defineProperty(MessageInputComponent.prototype, "accept", {
2877
- get: function () {
2878
- var _a;
2879
- return this.acceptedFileTypes ? (_a = this.acceptedFileTypes) === null || _a === void 0 ? void 0 : _a.join(',') : '';
2880
- },
2881
- enumerable: false,
2882
- configurable: true
2883
- });
2884
3062
  Object.defineProperty(MessageInputComponent.prototype, "quotedMessageAttachments", {
2885
3063
  get: function () {
2886
3064
  var _a;
@@ -2928,6 +3106,24 @@
2928
3106
  MessageInputComponent.prototype.deselectMessageToQuote = function () {
2929
3107
  this.channelService.selectMessageToQuote(undefined);
2930
3108
  };
3109
+ MessageInputComponent.prototype.getEmojiPickerContext = function () {
3110
+ return {
3111
+ emojiInput$: this.emojiInputService.emojiInput$,
3112
+ };
3113
+ };
3114
+ MessageInputComponent.prototype.getAttachmentPreviewListContext = function () {
3115
+ return {
3116
+ attachmentUploads$: this.attachmentService.attachmentUploads$,
3117
+ deleteUploadHandler: this.deleteUpload.bind(this),
3118
+ retryUploadHandler: this.retryUpload.bind(this),
3119
+ };
3120
+ };
3121
+ MessageInputComponent.prototype.deleteUpload = function (upload) {
3122
+ void this.attachmentService.deleteAttachment(upload);
3123
+ };
3124
+ MessageInputComponent.prototype.retryUpload = function (file) {
3125
+ void this.attachmentService.retryAttachmentUpload(file);
3126
+ };
2931
3127
  MessageInputComponent.prototype.clearFileInput = function () {
2932
3128
  this.fileInput.nativeElement.value = '';
2933
3129
  };
@@ -2954,7 +3150,7 @@
2954
3150
  return __generator(this, function (_12) {
2955
3151
  switch (_12.label) {
2956
3152
  case 0:
2957
- if (!fileList || this.acceptedFileTypes) {
3153
+ if (!fileList) {
2958
3154
  return [2 /*return*/, true];
2959
3155
  }
2960
3156
  if (!!this.appSettings) return [3 /*break*/, 2];
@@ -3055,8 +3251,8 @@
3055
3251
  };
3056
3252
  return MessageInputComponent;
3057
3253
  }());
3058
- MessageInputComponent.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: MessageInputComponent, deps: [{ token: ChannelService }, { token: NotificationService }, { token: AttachmentService }, { token: MessageInputConfigService }, { token: textareaInjectionToken }, { token: i0__namespace.ComponentFactoryResolver }, { token: i0__namespace.ChangeDetectorRef }, { token: ChatClientService }, { token: EmojiInputService }], target: i0__namespace.ɵɵFactoryTarget.Component });
3059
- MessageInputComponent.ɵcmp = i0__namespace.ɵɵ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__namespace, 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__namespace.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i6__namespace.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: TextareaDirective, selector: "[streamTextarea]", inputs: ["componentRef", "areMentionsEnabled", "mentionAutocompleteItemTemplate", "mentionScope", "commandAutocompleteItemTemplate", "value"], outputs: ["valueChange", "send", "userMentions"] }], pipes: { "async": i6__namespace.AsyncPipe, "translate": i2__namespace.TranslatePipe } });
3254
+ MessageInputComponent.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: MessageInputComponent, deps: [{ token: ChannelService }, { token: NotificationService }, { token: AttachmentService }, { token: MessageInputConfigService }, { token: textareaInjectionToken }, { token: i0__namespace.ComponentFactoryResolver }, { token: i0__namespace.ChangeDetectorRef }, { token: ChatClientService }, { token: EmojiInputService }, { token: CustomTemplatesService }], target: i0__namespace.ɵɵFactoryTarget.Component });
3255
+ MessageInputComponent.ɵcmp = i0__namespace.ɵɵ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" }, 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__namespace, 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__namespace.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3__namespace.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: TextareaDirective, selector: "[streamTextarea]", inputs: ["componentRef", "areMentionsEnabled", "mentionScope", "value"], outputs: ["valueChange", "send", "userMentions"] }], pipes: { "async": i3__namespace.AsyncPipe, "translate": i2__namespace.TranslatePipe } });
3060
3256
  i0__namespace.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: MessageInputComponent, decorators: [{
3061
3257
  type: i0.Component,
3062
3258
  args: [{
@@ -3069,23 +3265,15 @@
3069
3265
  return [{ type: ChannelService }, { type: NotificationService }, { type: AttachmentService }, { type: MessageInputConfigService }, { type: i0__namespace.Type, decorators: [{
3070
3266
  type: i0.Inject,
3071
3267
  args: [textareaInjectionToken]
3072
- }] }, { type: i0__namespace.ComponentFactoryResolver }, { type: i0__namespace.ChangeDetectorRef }, { type: ChatClientService }, { type: EmojiInputService }];
3268
+ }] }, { type: i0__namespace.ComponentFactoryResolver }, { type: i0__namespace.ChangeDetectorRef }, { type: ChatClientService }, { type: EmojiInputService }, { type: CustomTemplatesService }];
3073
3269
  }, propDecorators: { isFileUploadEnabled: [{
3074
3270
  type: i0.Input
3075
3271
  }], areMentionsEnabled: [{
3076
3272
  type: i0.Input
3077
3273
  }], mentionScope: [{
3078
3274
  type: i0.Input
3079
- }], mentionAutocompleteItemTemplate: [{
3080
- type: i0.Input
3081
- }], commandAutocompleteItemTemplate: [{
3082
- type: i0.Input
3083
- }], emojiPickerTemplate: [{
3084
- type: i0.Input
3085
3275
  }], mode: [{
3086
3276
  type: i0.Input
3087
- }], acceptedFileTypes: [{
3088
- type: i0.Input
3089
3277
  }], isMultipleFileUploadEnabled: [{
3090
3278
  type: i0.Input
3091
3279
  }], message: [{
@@ -3109,7 +3297,7 @@
3109
3297
  return NotificationComponent;
3110
3298
  }());
3111
3299
  NotificationComponent.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: NotificationComponent, deps: [], target: i0__namespace.ɵɵFactoryTarget.Component });
3112
- NotificationComponent.ɵcmp = i0__namespace.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: NotificationComponent, selector: "stream-notification", inputs: { type: "type" }, ngImport: i0__namespace, template: "<div\n class=\"str-chat__custom-notification notification-{{ type }}\"\n data-testid=\"custom-notification\"\n>\n <ng-content></ng-content>\n</div>\n" });
3300
+ NotificationComponent.ɵcmp = i0__namespace.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: NotificationComponent, selector: "stream-notification", inputs: { type: "type", content: "content" }, ngImport: i0__namespace, 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__namespace.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3__namespace.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }] });
3113
3301
  i0__namespace.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: NotificationComponent, decorators: [{
3114
3302
  type: i0.Component,
3115
3303
  args: [{
@@ -3119,26 +3307,29 @@
3119
3307
  }]
3120
3308
  }], ctorParameters: function () { return []; }, propDecorators: { type: [{
3121
3309
  type: i0.Input
3310
+ }], content: [{
3311
+ type: i0.Input
3122
3312
  }] } });
3123
3313
 
3124
3314
  /**
3125
3315
  * The `NotificationList` component displays the list of active notifications.
3126
3316
  */
3127
3317
  var NotificationListComponent = /** @class */ (function () {
3128
- function NotificationListComponent(notificationService) {
3318
+ function NotificationListComponent(customTemplatesService, notificationService) {
3319
+ this.customTemplatesService = customTemplatesService;
3129
3320
  this.notificationService = notificationService;
3130
3321
  this.notifications$ = this.notificationService.notifications$;
3131
3322
  }
3132
3323
  NotificationListComponent.prototype.trackById = function (_, item) {
3133
3324
  return item.id;
3134
3325
  };
3135
- NotificationListComponent.prototype.getTemplateContext = function (notification) {
3326
+ NotificationListComponent.prototype.getNotificationContentContext = function (notification) {
3136
3327
  return Object.assign(Object.assign({}, notification.templateContext), { dismissFn: notification.dismissFn });
3137
3328
  };
3138
3329
  return NotificationListComponent;
3139
3330
  }());
3140
- NotificationListComponent.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: NotificationListComponent, deps: [{ token: NotificationService }], target: i0__namespace.ɵɵFactoryTarget.Component });
3141
- NotificationListComponent.ɵcmp = i0__namespace.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: NotificationListComponent, selector: "stream-notification-list", ngImport: i0__namespace, 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__namespace.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i6__namespace.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i6__namespace.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }], pipes: { "async": i6__namespace.AsyncPipe, "translate": i2__namespace.TranslatePipe } });
3331
+ NotificationListComponent.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: NotificationListComponent, deps: [{ token: CustomTemplatesService }, { token: NotificationService }], target: i0__namespace.ɵɵFactoryTarget.Component });
3332
+ NotificationListComponent.ɵcmp = i0__namespace.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: NotificationListComponent, selector: "stream-notification-list", ngImport: i0__namespace, 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__namespace.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i3__namespace.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3__namespace.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }], pipes: { "async": i3__namespace.AsyncPipe, "translate": i2__namespace.TranslatePipe } });
3142
3333
  i0__namespace.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: NotificationListComponent, decorators: [{
3143
3334
  type: i0.Component,
3144
3335
  args: [{
@@ -3146,17 +3337,18 @@
3146
3337
  templateUrl: './notification-list.component.html',
3147
3338
  styles: [],
3148
3339
  }]
3149
- }], ctorParameters: function () { return [{ type: NotificationService }]; } });
3340
+ }], ctorParameters: function () { return [{ type: CustomTemplatesService }, { type: NotificationService }]; } });
3150
3341
 
3151
3342
  /**
3152
3343
  * 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.
3153
3344
  */
3154
3345
  var MessageActionsBoxComponent = /** @class */ (function () {
3155
- function MessageActionsBoxComponent(chatClientService, notificationService, channelService) {
3346
+ function MessageActionsBoxComponent(chatClientService, notificationService, channelService, customTemplatesService) {
3156
3347
  var _this = this;
3157
3348
  this.chatClientService = chatClientService;
3158
3349
  this.notificationService = notificationService;
3159
3350
  this.channelService = channelService;
3351
+ this.customTemplatesService = customTemplatesService;
3160
3352
  /**
3161
3353
  * 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.
3162
3354
  */
@@ -3178,152 +3370,155 @@
3178
3370
  */
3179
3371
  this.isEditing = new i0.EventEmitter();
3180
3372
  this.isEditModalOpen = false;
3373
+ this.subscriptions = [];
3374
+ this.visibleMessageActionItems = [];
3181
3375
  this.modalClosed = function () {
3182
3376
  _this.isEditModalOpen = false;
3183
3377
  _this.isEditing.emit(false);
3184
3378
  };
3379
+ this.subscriptions.push(this.customTemplatesService.messageInputTemplate$.subscribe(function (template) { return (_this.messageInputTemplate = template); }));
3380
+ this.subscriptions.push(this.customTemplatesService.messageActionsBoxItemTemplate$.subscribe(function (template) { return (_this.messageActionItemTemplate = template); }));
3381
+ this.subscriptions.push(this.customTemplatesService.modalTemplate$.subscribe(function (template) { return (_this.modalTemplate = template); }));
3382
+ this.messageActionItems = [
3383
+ {
3384
+ actionName: 'quote',
3385
+ actionLabelOrTranslationKey: 'streamChat.Reply',
3386
+ actionHandler: function (message) { return _this.channelService.selectMessageToQuote(message); },
3387
+ isVisible: function (enabledActions, isMine, message) { return (enabledActions.indexOf('quote') !== -1 ||
3388
+ enabledActions.indexOf('quote-message') !== -1) &&
3389
+ !(message === null || message === void 0 ? void 0 : message.quoted_message); },
3390
+ },
3391
+ {
3392
+ actionName: 'pin',
3393
+ actionLabelOrTranslationKey: function () { var _a; return ((_a = _this.message) === null || _a === void 0 ? void 0 : _a.pinned) ? 'streamChat.Unpin' : 'streamChat.Pin'; },
3394
+ actionHandler: function () { return alert('Feature not yet implemented'); },
3395
+ isVisible: function (enabledActions) { return enabledActions.indexOf('pin') !== -1; },
3396
+ },
3397
+ {
3398
+ actionName: 'flag',
3399
+ actionLabelOrTranslationKey: 'streamChat.Flag',
3400
+ actionHandler: function (message) { return __awaiter(_this, void 0, void 0, function () {
3401
+ var err_1;
3402
+ return __generator(this, function (_b) {
3403
+ switch (_b.label) {
3404
+ case 0:
3405
+ _b.trys.push([0, 2, , 3]);
3406
+ return [4 /*yield*/, this.chatClientService.flagMessage(message.id)];
3407
+ case 1:
3408
+ _b.sent();
3409
+ this.notificationService.addTemporaryNotification('streamChat.Message has been successfully flagged', 'success');
3410
+ return [3 /*break*/, 3];
3411
+ case 2:
3412
+ err_1 = _b.sent();
3413
+ this.notificationService.addTemporaryNotification('streamChat.Error adding flag');
3414
+ return [3 /*break*/, 3];
3415
+ case 3: return [2 /*return*/];
3416
+ }
3417
+ });
3418
+ }); },
3419
+ isVisible: function (enabledActions, isMine) { return (enabledActions.indexOf('flag') !== -1 ||
3420
+ enabledActions.indexOf('flag-message') !== -1) &&
3421
+ !isMine; },
3422
+ },
3423
+ {
3424
+ actionName: 'mute',
3425
+ actionLabelOrTranslationKey: 'streamChat.Mute',
3426
+ actionHandler: function () { return alert('Feature not yet implemented'); },
3427
+ isVisible: function (enabledActions) { return enabledActions.indexOf('mute') !== -1; },
3428
+ },
3429
+ {
3430
+ actionName: 'edit',
3431
+ actionLabelOrTranslationKey: 'streamChat.Edit Message',
3432
+ actionHandler: function () {
3433
+ _this.isEditing.emit(true);
3434
+ _this.isEditModalOpen = true;
3435
+ },
3436
+ isVisible: function (enabledActions, isMine) { return ((enabledActions.indexOf('edit') !== -1 ||
3437
+ enabledActions.indexOf('update-own-message') !== -1) &&
3438
+ isMine) ||
3439
+ enabledActions.indexOf('edit-any') !== -1 ||
3440
+ enabledActions.indexOf('update-any-message') !== -1; },
3441
+ },
3442
+ {
3443
+ actionName: 'delete',
3444
+ actionLabelOrTranslationKey: 'streamChat.Delete',
3445
+ actionHandler: function (message) { return __awaiter(_this, void 0, void 0, function () {
3446
+ var error_1;
3447
+ return __generator(this, function (_b) {
3448
+ switch (_b.label) {
3449
+ case 0:
3450
+ _b.trys.push([0, 2, , 3]);
3451
+ return [4 /*yield*/, this.channelService.deleteMessage(message)];
3452
+ case 1:
3453
+ _b.sent();
3454
+ return [3 /*break*/, 3];
3455
+ case 2:
3456
+ error_1 = _b.sent();
3457
+ this.notificationService.addTemporaryNotification('streamChat.Error deleting message');
3458
+ return [3 /*break*/, 3];
3459
+ case 3: return [2 /*return*/];
3460
+ }
3461
+ });
3462
+ }); },
3463
+ isVisible: function (enabledActions, isMine) { return ((enabledActions.indexOf('delete') !== -1 ||
3464
+ enabledActions.indexOf('delete-own-message') !== -1) &&
3465
+ isMine) ||
3466
+ enabledActions.indexOf('delete-any') !== -1 ||
3467
+ enabledActions.indexOf('delete-any-message') !== -1; },
3468
+ },
3469
+ ];
3185
3470
  }
3186
3471
  MessageActionsBoxComponent.prototype.ngOnChanges = function (changes) {
3187
- if (changes.isMine || changes.enabledActions) {
3188
- var displayedActionsCount = 0;
3189
- if (this.isQuoteVisible) {
3190
- displayedActionsCount++;
3191
- }
3192
- if (this.isEditVisible) {
3193
- displayedActionsCount++;
3194
- }
3195
- if (this.isDeleteVisible) {
3196
- displayedActionsCount++;
3197
- }
3198
- if (this.isMuteVisible) {
3199
- displayedActionsCount++;
3200
- }
3201
- if (this.isFlagVisible) {
3202
- displayedActionsCount++;
3203
- }
3204
- if (this.isPinVisible) {
3205
- displayedActionsCount++;
3206
- }
3207
- this.displayedActionsCount.next(displayedActionsCount);
3472
+ var _this = this;
3473
+ if (changes.isMine || changes.enabledActions || changes.message) {
3474
+ this.messageActionItems.forEach(function (i) { return (i.actionHandler = i.actionHandler.bind(_this, _this.message, _this.isMine)); });
3475
+ this.visibleMessageActionItems = this.messageActionItems.filter(function (item) { return item.isVisible(_this.enabledActions, _this.isMine, _this.message); });
3476
+ this.displayedActionsCount.emit(this.visibleMessageActionItems.length);
3208
3477
  }
3209
3478
  };
3210
- Object.defineProperty(MessageActionsBoxComponent.prototype, "isQuoteVisible", {
3211
- get: function () {
3212
- var _a;
3213
- return ((this.enabledActions.indexOf('quote') !== -1 ||
3214
- this.enabledActions.indexOf('quote-message') !== -1) &&
3215
- !((_a = this.message) === null || _a === void 0 ? void 0 : _a.quoted_message));
3216
- },
3217
- enumerable: false,
3218
- configurable: true
3219
- });
3220
- Object.defineProperty(MessageActionsBoxComponent.prototype, "isEditVisible", {
3221
- get: function () {
3222
- return (((this.enabledActions.indexOf('edit') !== -1 ||
3223
- this.enabledActions.indexOf('update-own-message') !== -1) &&
3224
- this.isMine) ||
3225
- this.enabledActions.indexOf('edit-any') !== -1 ||
3226
- this.enabledActions.indexOf('update-any-message') !== -1);
3227
- },
3228
- enumerable: false,
3229
- configurable: true
3230
- });
3231
- Object.defineProperty(MessageActionsBoxComponent.prototype, "isDeleteVisible", {
3232
- get: function () {
3233
- return (((this.enabledActions.indexOf('delete') !== -1 ||
3234
- this.enabledActions.indexOf('delete-own-message') !== -1) &&
3235
- this.isMine) ||
3236
- this.enabledActions.indexOf('delete-any') !== -1 ||
3237
- this.enabledActions.indexOf('delete-any-message') !== -1);
3238
- },
3239
- enumerable: false,
3240
- configurable: true
3241
- });
3242
- Object.defineProperty(MessageActionsBoxComponent.prototype, "isMuteVisible", {
3243
- get: function () {
3244
- return this.enabledActions.indexOf('mute') !== -1;
3245
- },
3246
- enumerable: false,
3247
- configurable: true
3248
- });
3249
- Object.defineProperty(MessageActionsBoxComponent.prototype, "isFlagVisible", {
3250
- get: function () {
3251
- return ((this.enabledActions.indexOf('flag') !== -1 ||
3252
- this.enabledActions.indexOf('flag-message') !== -1) &&
3253
- !this.isMine);
3254
- },
3255
- enumerable: false,
3256
- configurable: true
3257
- });
3258
- Object.defineProperty(MessageActionsBoxComponent.prototype, "isPinVisible", {
3259
- get: function () {
3260
- return this.enabledActions.indexOf('pin') !== -1;
3261
- },
3262
- enumerable: false,
3263
- configurable: true
3264
- });
3265
- MessageActionsBoxComponent.prototype.pinClicked = function () {
3266
- alert('Feature not yet implemented');
3267
- };
3268
- MessageActionsBoxComponent.prototype.flagClicked = function () {
3269
- return __awaiter(this, void 0, void 0, function () {
3270
- var err_1;
3271
- return __generator(this, function (_b) {
3272
- switch (_b.label) {
3273
- case 0:
3274
- _b.trys.push([0, 2, , 3]);
3275
- return [4 /*yield*/, this.chatClientService.flagMessage(this.message.id)];
3276
- case 1:
3277
- _b.sent();
3278
- this.notificationService.addTemporaryNotification('streamChat.Message has been successfully flagged', 'success');
3279
- return [3 /*break*/, 3];
3280
- case 2:
3281
- err_1 = _b.sent();
3282
- this.notificationService.addTemporaryNotification('streamChat.Error adding flag');
3283
- return [3 /*break*/, 3];
3284
- case 3: return [2 /*return*/];
3285
- }
3286
- });
3287
- });
3288
- };
3289
- MessageActionsBoxComponent.prototype.muteClicked = function () {
3290
- alert('Feature not yet implemented');
3291
- };
3292
- MessageActionsBoxComponent.prototype.quoteClicked = function () {
3293
- this.channelService.selectMessageToQuote(this.message);
3479
+ MessageActionsBoxComponent.prototype.ngOnDestroy = function () {
3480
+ this.subscriptions.forEach(function (s) { return s.unsubscribe(); });
3294
3481
  };
3295
- MessageActionsBoxComponent.prototype.editClicked = function () {
3296
- this.isEditing.emit(true);
3297
- this.isEditModalOpen = true;
3482
+ MessageActionsBoxComponent.prototype.getActionLabel = function (actionLabelOrTranslationKey) {
3483
+ return typeof actionLabelOrTranslationKey === 'string'
3484
+ ? actionLabelOrTranslationKey
3485
+ : actionLabelOrTranslationKey();
3298
3486
  };
3299
3487
  MessageActionsBoxComponent.prototype.sendClicked = function () {
3300
3488
  var _a;
3301
3489
  (_a = this.messageInput) === null || _a === void 0 ? void 0 : _a.messageSent();
3302
3490
  };
3303
- MessageActionsBoxComponent.prototype.deleteClicked = function () {
3304
- return __awaiter(this, void 0, void 0, function () {
3305
- var error_1;
3306
- return __generator(this, function (_b) {
3307
- switch (_b.label) {
3308
- case 0:
3309
- _b.trys.push([0, 2, , 3]);
3310
- return [4 /*yield*/, this.channelService.deleteMessage(this.message)];
3311
- case 1:
3312
- _b.sent();
3313
- return [3 /*break*/, 3];
3314
- case 2:
3315
- error_1 = _b.sent();
3316
- this.notificationService.addTemporaryNotification('streamChat.Error deleting message');
3317
- return [3 /*break*/, 3];
3318
- case 3: return [2 /*return*/];
3491
+ MessageActionsBoxComponent.prototype.getMessageInputContext = function () {
3492
+ return {
3493
+ message: this.message,
3494
+ messageUpdateHandler: this.modalClosed,
3495
+ isFileUploadEnabled: undefined,
3496
+ areMentionsEnabled: undefined,
3497
+ isMultipleFileUploadEnabled: undefined,
3498
+ mentionScope: undefined,
3499
+ mode: undefined,
3500
+ };
3501
+ };
3502
+ MessageActionsBoxComponent.prototype.getEditModalContext = function () {
3503
+ var _this = this;
3504
+ return {
3505
+ isOpen: this.isEditModalOpen,
3506
+ isOpenChangeHandler: function (isOpen) {
3507
+ _this.isEditModalOpen = isOpen;
3508
+ if (!_this.isEditModalOpen) {
3509
+ _this.modalClosed();
3319
3510
  }
3320
- });
3321
- });
3511
+ },
3512
+ content: this.modalContent,
3513
+ };
3514
+ };
3515
+ MessageActionsBoxComponent.prototype.trackByActionName = function (_, item) {
3516
+ return item.actionName;
3322
3517
  };
3323
3518
  return MessageActionsBoxComponent;
3324
3519
  }());
3325
- MessageActionsBoxComponent.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: MessageActionsBoxComponent, deps: [{ token: ChatClientService }, { token: NotificationService }, { token: ChannelService }], target: i0__namespace.ɵɵFactoryTarget.Component });
3326
- MessageActionsBoxComponent.ɵcmp = i0__namespace.ɵɵ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__namespace, 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__namespace.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i6__namespace.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i2__namespace.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }], pipes: { "translate": i2__namespace.TranslatePipe } });
3520
+ MessageActionsBoxComponent.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: MessageActionsBoxComponent, deps: [{ token: ChatClientService }, { token: NotificationService }, { token: ChannelService }, { token: CustomTemplatesService }], target: i0__namespace.ɵɵFactoryTarget.Component });
3521
+ MessageActionsBoxComponent.ɵcmp = i0__namespace.ɵɵ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: "messageInput", first: true, predicate: MessageInputComponent, descendants: true }, { propertyName: "modalContent", first: true, predicate: ["modalContent"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0__namespace, 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 >\n <stream-message-input\n [message]=\"messageInput\"\n (messageUpdate)=\"messageUpdateHandler()\"\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"], outputs: ["messageUpdate"] }, { type: NotificationListComponent, selector: "stream-notification-list" }], directives: [{ type: i3__namespace.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i3__namespace.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i3__namespace.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2__namespace.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }], pipes: { "translate": i2__namespace.TranslatePipe } });
3327
3522
  i0__namespace.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: MessageActionsBoxComponent, decorators: [{
3328
3523
  type: i0.Component,
3329
3524
  args: [{
@@ -3331,9 +3526,7 @@
3331
3526
  templateUrl: './message-actions-box.component.html',
3332
3527
  styles: [],
3333
3528
  }]
3334
- }], ctorParameters: function () { return [{ type: ChatClientService }, { type: NotificationService }, { type: ChannelService }]; }, propDecorators: { messageInputTemplate: [{
3335
- type: i0.Input
3336
- }], isOpen: [{
3529
+ }], ctorParameters: function () { return [{ type: ChatClientService }, { type: NotificationService }, { type: ChannelService }, { type: CustomTemplatesService }]; }, propDecorators: { isOpen: [{
3337
3530
  type: i0.Input
3338
3531
  }], isMine: [{
3339
3532
  type: i0.Input
@@ -3348,6 +3541,9 @@
3348
3541
  }], messageInput: [{
3349
3542
  type: i0.ViewChild,
3350
3543
  args: [MessageInputComponent]
3544
+ }], modalContent: [{
3545
+ type: i0.ViewChild,
3546
+ args: ['modalContent', { static: true }]
3351
3547
  }] } });
3352
3548
 
3353
3549
  /**
@@ -3364,7 +3560,7 @@
3364
3560
  return ChannelComponent;
3365
3561
  }());
3366
3562
  ChannelComponent.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: ChannelComponent, deps: [{ token: ChannelService }], target: i0__namespace.ɵɵFactoryTarget.Component });
3367
- ChannelComponent.ɵcmp = i0__namespace.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: ChannelComponent, selector: "stream-channel", ngImport: i0__namespace, 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__namespace.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], pipes: { "async": i6__namespace.AsyncPipe } });
3563
+ ChannelComponent.ɵcmp = i0__namespace.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: ChannelComponent, selector: "stream-channel", ngImport: i0__namespace, 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__namespace.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], pipes: { "async": i3__namespace.AsyncPipe } });
3368
3564
  i0__namespace.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: ChannelComponent, decorators: [{
3369
3565
  type: i0.Component,
3370
3566
  args: [{
@@ -3461,10 +3657,13 @@
3461
3657
  * 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)
3462
3658
  */
3463
3659
  var ChannelHeaderComponent = /** @class */ (function () {
3464
- function ChannelHeaderComponent(channelService, channelListToggleService) {
3660
+ function ChannelHeaderComponent(channelService, channelListToggleService, customTemplatesService, cdRef) {
3465
3661
  var _this = this;
3466
3662
  this.channelService = channelService;
3467
3663
  this.channelListToggleService = channelListToggleService;
3664
+ this.customTemplatesService = customTemplatesService;
3665
+ this.cdRef = cdRef;
3666
+ this.subscriptions = [];
3468
3667
  this.channelService.activeChannel$.subscribe(function (c) {
3469
3668
  var _a, _b;
3470
3669
  _this.activeChannel = c;
@@ -3476,10 +3675,23 @@
3476
3675
  capabilities.indexOf('connect-events') !== -1;
3477
3676
  });
3478
3677
  }
3678
+ ChannelHeaderComponent.prototype.ngOnInit = function () {
3679
+ var _this = this;
3680
+ this.subscriptions.push(this.customTemplatesService.channelActionsTemplate$.subscribe(function (template) {
3681
+ _this.channelActionsTemplate = template;
3682
+ _this.cdRef.detectChanges();
3683
+ }));
3684
+ };
3685
+ ChannelHeaderComponent.prototype.ngOnDestroy = function () {
3686
+ this.subscriptions.forEach(function (s) { return s.unsubscribe(); });
3687
+ };
3479
3688
  ChannelHeaderComponent.prototype.toggleMenu = function (event) {
3480
3689
  event.stopPropagation();
3481
3690
  this.channelListToggleService.toggle();
3482
3691
  };
3692
+ ChannelHeaderComponent.prototype.getChannelActionsContext = function () {
3693
+ return { channel: this.activeChannel };
3694
+ };
3483
3695
  Object.defineProperty(ChannelHeaderComponent.prototype, "memberCountParam", {
3484
3696
  get: function () {
3485
3697
  var _a, _b;
@@ -3498,8 +3710,8 @@
3498
3710
  });
3499
3711
  return ChannelHeaderComponent;
3500
3712
  }());
3501
- ChannelHeaderComponent.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: ChannelHeaderComponent, deps: [{ token: ChannelService }, { token: ChannelListToggleService }], target: i0__namespace.ɵɵFactoryTarget.Component });
3502
- ChannelHeaderComponent.ɵcmp = i0__namespace.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: ChannelHeaderComponent, selector: "stream-channel-header", inputs: { channelActionsTemplate: "channelActionsTemplate" }, ngImport: i0__namespace, 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__namespace.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i6__namespace.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }], pipes: { "translate": i2__namespace.TranslatePipe } });
3713
+ ChannelHeaderComponent.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: ChannelHeaderComponent, deps: [{ token: ChannelService }, { token: ChannelListToggleService }, { token: CustomTemplatesService }, { token: i0__namespace.ChangeDetectorRef }], target: i0__namespace.ɵɵFactoryTarget.Component });
3714
+ ChannelHeaderComponent.ɵcmp = i0__namespace.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: ChannelHeaderComponent, selector: "stream-channel-header", ngImport: i0__namespace, 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__namespace.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3__namespace.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }], pipes: { "translate": i2__namespace.TranslatePipe } });
3503
3715
  i0__namespace.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: ChannelHeaderComponent, decorators: [{
3504
3716
  type: i0.Component,
3505
3717
  args: [{
@@ -3507,9 +3719,7 @@
3507
3719
  templateUrl: './channel-header.component.html',
3508
3720
  styles: [],
3509
3721
  }]
3510
- }], ctorParameters: function () { return [{ type: ChannelService }, { type: ChannelListToggleService }]; }, propDecorators: { channelActionsTemplate: [{
3511
- type: i0.Input
3512
- }] } });
3722
+ }], ctorParameters: function () { return [{ type: ChannelService }, { type: ChannelListToggleService }, { type: CustomTemplatesService }, { type: i0__namespace.ChangeDetectorRef }]; } });
3513
3723
 
3514
3724
  /**
3515
3725
  * The `ChannelPreview` component displays a channel preview in the channel list, it consists of the image, name and latest message of the channel.
@@ -3604,7 +3814,7 @@
3604
3814
  return ChannelPreviewComponent;
3605
3815
  }());
3606
3816
  ChannelPreviewComponent.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: ChannelPreviewComponent, deps: [{ token: ChannelService }, { token: i0__namespace.NgZone }], target: i0__namespace.ɵɵFactoryTarget.Component });
3607
- ChannelPreviewComponent.ɵcmp = i0__namespace.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: ChannelPreviewComponent, selector: "stream-channel-preview", inputs: { channel: "channel" }, ngImport: i0__namespace, 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__namespace.TranslatePipe } });
3817
+ ChannelPreviewComponent.ɵcmp = i0__namespace.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: ChannelPreviewComponent, selector: "stream-channel-preview", inputs: { channel: "channel" }, ngImport: i0__namespace, 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__namespace.TranslatePipe } });
3608
3818
  i0__namespace.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: ChannelPreviewComponent, decorators: [{
3609
3819
  type: i0.Component,
3610
3820
  args: [{
@@ -3620,19 +3830,26 @@
3620
3830
  * The `ChannelList` component renders the list of channels.
3621
3831
  */
3622
3832
  var ChannelListComponent = /** @class */ (function () {
3623
- function ChannelListComponent(channelService, channelListToggleService) {
3833
+ function ChannelListComponent(channelService, channelListToggleService, customTemplatesService) {
3834
+ var _this = this;
3624
3835
  this.channelService = channelService;
3625
3836
  this.channelListToggleService = channelListToggleService;
3837
+ this.customTemplatesService = customTemplatesService;
3626
3838
  this.isLoadingMoreChannels = false;
3839
+ this.subscriptions = [];
3627
3840
  this.isOpen$ = this.channelListToggleService.isOpen$;
3628
3841
  this.channels$ = this.channelService.channels$;
3629
3842
  this.hasMoreChannels$ = this.channelService.hasMoreChannels$;
3630
3843
  this.isError$ = this.channels$.pipe(operators.map(function () { return false; }), operators.catchError(function () { return rxjs.of(true); }), operators.startWith(false));
3631
3844
  this.isInitializing$ = this.channels$.pipe(operators.map(function (channels) { return !channels; }), operators.catchError(function () { return rxjs.of(false); }));
3845
+ this.subscriptions.push(this.customTemplatesService.channelPreviewTemplate$.subscribe(function (template) { return (_this.customChannelPreviewTemplate = template); }));
3632
3846
  }
3633
3847
  ChannelListComponent.prototype.ngAfterViewInit = function () {
3634
3848
  this.channelListToggleService.setMenuElement(this.container.nativeElement);
3635
3849
  };
3850
+ ChannelListComponent.prototype.ngOnDestroy = function () {
3851
+ this.subscriptions.forEach(function (s) { return s.unsubscribe(); });
3852
+ };
3636
3853
  ChannelListComponent.prototype.loadMoreChannels = function () {
3637
3854
  return __awaiter(this, void 0, void 0, function () {
3638
3855
  return __generator(this, function (_a) {
@@ -3654,10 +3871,15 @@
3654
3871
  ChannelListComponent.prototype.channelSelected = function () {
3655
3872
  this.channelListToggleService.channelSelected();
3656
3873
  };
3874
+ ChannelListComponent.prototype.getChannelPreviewContext = function (channel) {
3875
+ return {
3876
+ channel: channel,
3877
+ };
3878
+ };
3657
3879
  return ChannelListComponent;
3658
3880
  }());
3659
- ChannelListComponent.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: ChannelListComponent, deps: [{ token: ChannelService }, { token: ChannelListToggleService }], target: i0__namespace.ɵɵFactoryTarget.Component });
3660
- ChannelListComponent.ɵcmp = i0__namespace.ɵɵ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__namespace, 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__namespace.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i6__namespace.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i6__namespace.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }], pipes: { "async": i6__namespace.AsyncPipe, "translate": i2__namespace.TranslatePipe } });
3881
+ ChannelListComponent.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: ChannelListComponent, deps: [{ token: ChannelService }, { token: ChannelListToggleService }, { token: CustomTemplatesService }], target: i0__namespace.ɵɵFactoryTarget.Component });
3882
+ ChannelListComponent.ɵcmp = i0__namespace.ɵɵ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__namespace, 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__namespace.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3__namespace.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i3__namespace.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }], pipes: { "async": i3__namespace.AsyncPipe, "translate": i2__namespace.TranslatePipe } });
3661
3883
  i0__namespace.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: ChannelListComponent, decorators: [{
3662
3884
  type: i0.Component,
3663
3885
  args: [{
@@ -3665,9 +3887,7 @@
3665
3887
  templateUrl: './channel-list.component.html',
3666
3888
  styles: [],
3667
3889
  }]
3668
- }], ctorParameters: function () { return [{ type: ChannelService }, { type: ChannelListToggleService }]; }, propDecorators: { customChannelPreviewTemplate: [{
3669
- type: i0.Input
3670
- }], container: [{
3890
+ }], ctorParameters: function () { return [{ type: ChannelService }, { type: ChannelListToggleService }, { type: CustomTemplatesService }]; }, propDecorators: { container: [{
3671
3891
  type: i0.ViewChild,
3672
3892
  args: ['container']
3673
3893
  }] } });
@@ -3842,7 +4062,7 @@
3842
4062
  return MessageReactionsComponent;
3843
4063
  }());
3844
4064
  MessageReactionsComponent.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: MessageReactionsComponent, deps: [{ token: i0__namespace.ChangeDetectorRef }, { token: ChannelService }], target: i0__namespace.ɵɵFactoryTarget.Component });
3845
- MessageReactionsComponent.ɵcmp = i0__namespace.ɵɵ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__namespace, 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__namespace.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i6__namespace.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i6__namespace.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
4065
+ MessageReactionsComponent.ɵcmp = i0__namespace.ɵɵ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__namespace, 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__namespace.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3__namespace.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i3__namespace.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
3846
4066
  i0__namespace.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: MessageReactionsComponent, decorators: [{
3847
4067
  type: i0.Component,
3848
4068
  args: [{
@@ -3874,9 +4094,11 @@
3874
4094
  * 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).
3875
4095
  */
3876
4096
  var MessageComponent = /** @class */ (function () {
3877
- function MessageComponent(chatClientService, channelService) {
4097
+ function MessageComponent(chatClientService, channelService, customTemplatesService, cdRef) {
3878
4098
  this.chatClientService = chatClientService;
3879
4099
  this.channelService = channelService;
4100
+ this.customTemplatesService = customTemplatesService;
4101
+ this.cdRef = cdRef;
3880
4102
  /**
3881
4103
  * 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).
3882
4104
  */
@@ -3890,12 +4112,29 @@
3890
4112
  this.isPressedOnMobile = false;
3891
4113
  this.visibleMessageActionsCount = 0;
3892
4114
  this.messageTextParts = [];
4115
+ this.subscriptions = [];
3893
4116
  this.user = this.chatClientService.chatClient.user;
3894
4117
  }
4118
+ MessageComponent.prototype.ngOnInit = function () {
4119
+ var _this = this;
4120
+ this.subscriptions.push(this.customTemplatesService.mentionTemplate$.subscribe(function (template) { return (_this.mentionTemplate = template); }));
4121
+ this.subscriptions.push(this.customTemplatesService.attachmentListTemplate$.subscribe(function (template) { return (_this.attachmentListTemplate = template); }));
4122
+ this.subscriptions.push(this.customTemplatesService.messageActionsBoxTemplate$.subscribe(function (template) { return (_this.messageActionsBoxTemplate = template); }));
4123
+ this.subscriptions.push(this.customTemplatesService.messageReactionsTemplate$.subscribe(function (template) { return (_this.messageReactionsTemplate = template); }));
4124
+ };
3895
4125
  MessageComponent.prototype.ngOnChanges = function (changes) {
3896
4126
  if (changes.message) {
3897
4127
  this.createMessageParts();
3898
4128
  }
4129
+ if (changes.enabledMessageActions) {
4130
+ this.canReactToMessage =
4131
+ this.enabledMessageActions.indexOf('send-reaction') !== -1;
4132
+ this.canReceiveReadEvents =
4133
+ this.enabledMessageActions.indexOf('read-events') !== -1;
4134
+ }
4135
+ };
4136
+ MessageComponent.prototype.ngOnDestroy = function () {
4137
+ this.subscriptions.forEach(function (s) { return s.unsubscribe(); });
3899
4138
  };
3900
4139
  Object.defineProperty(MessageComponent.prototype, "isSentByCurrentUser", {
3901
4140
  get: function () {
@@ -4016,6 +4255,25 @@
4016
4255
  enumerable: false,
4017
4256
  configurable: true
4018
4257
  });
4258
+ MessageComponent.prototype.getAttachmentListContext = function () {
4259
+ var _a, _b;
4260
+ return {
4261
+ messageId: ((_a = this.message) === null || _a === void 0 ? void 0 : _a.id) || '',
4262
+ attachments: ((_b = this.message) === null || _b === void 0 ? void 0 : _b.attachments) || [],
4263
+ };
4264
+ };
4265
+ MessageComponent.prototype.getMessageReactionsContext = function () {
4266
+ var _this = this;
4267
+ var _a, _b, _c, _d;
4268
+ return {
4269
+ messageReactionCounts: ((_a = this.message) === null || _a === void 0 ? void 0 : _a.reaction_counts) || {},
4270
+ latestReactions: ((_b = this.message) === null || _b === void 0 ? void 0 : _b.latest_reactions) || [],
4271
+ isSelectorOpen: this.isReactionSelectorOpen,
4272
+ isSelectorOpenChangeHandler: function (isOpen) { return (_this.isReactionSelectorOpen = isOpen); },
4273
+ messageId: (_c = this.message) === null || _c === void 0 ? void 0 : _c.id,
4274
+ ownReactions: ((_d = this.message) === null || _d === void 0 ? void 0 : _d.own_reactions) || [],
4275
+ };
4276
+ };
4019
4277
  MessageComponent.prototype.resendMessage = function () {
4020
4278
  void this.channelService.resendMessage(this.message);
4021
4279
  };
@@ -4041,6 +4299,30 @@
4041
4299
  MessageComponent.prototype.setAsActiveParentMessage = function () {
4042
4300
  void this.channelService.setAsActiveParentMessage(this.message);
4043
4301
  };
4302
+ MessageComponent.prototype.getMentionContext = function (messagePart) {
4303
+ return {
4304
+ content: messagePart.content,
4305
+ user: messagePart.user,
4306
+ };
4307
+ };
4308
+ MessageComponent.prototype.getMessageActionsBoxContext = function () {
4309
+ var _this = this;
4310
+ return {
4311
+ isOpen: this.isActionBoxOpen,
4312
+ isMine: this.isSentByCurrentUser,
4313
+ enabledActions: this.enabledMessageActions,
4314
+ message: this.message,
4315
+ displayedActionsCountChaneHanler: function (count) {
4316
+ _this.visibleMessageActionsCount = count;
4317
+ // message action box changes UI bindings in parent, so we'll have to rerun change detection
4318
+ _this.cdRef.detectChanges();
4319
+ },
4320
+ isEditingChangeHandler: function (isEditing) {
4321
+ _this.isEditing = isEditing;
4322
+ _this.isActionBoxOpen = !_this.isEditing;
4323
+ },
4324
+ };
4325
+ };
4044
4326
  MessageComponent.prototype.createMessageParts = function () {
4045
4327
  var _this = this;
4046
4328
  var _a, _b;
@@ -4088,8 +4370,8 @@
4088
4370
  };
4089
4371
  return MessageComponent;
4090
4372
  }());
4091
- MessageComponent.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: MessageComponent, deps: [{ token: ChatClientService }, { token: ChannelService }], target: i0__namespace.ɵɵFactoryTarget.Component });
4092
- MessageComponent.ɵcmp = i0__namespace.ɵɵ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__namespace, 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__namespace.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i6__namespace.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i6__namespace.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i2__namespace.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }], pipes: { "translate": i2__namespace.TranslatePipe } });
4373
+ MessageComponent.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: MessageComponent, deps: [{ token: ChatClientService }, { token: ChannelService }, { token: CustomTemplatesService }, { token: i0__namespace.ChangeDetectorRef }], target: i0__namespace.ɵɵFactoryTarget.Component });
4374
+ MessageComponent.ɵcmp = i0__namespace.ɵɵ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__namespace, 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__namespace.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3__namespace.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i3__namespace.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i2__namespace.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }], pipes: { "translate": i2__namespace.TranslatePipe } });
4093
4375
  i0__namespace.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: MessageComponent, decorators: [{
4094
4376
  type: i0.Component,
4095
4377
  args: [{
@@ -4097,22 +4379,12 @@
4097
4379
  templateUrl: './message.component.html',
4098
4380
  styles: [],
4099
4381
  }]
4100
- }], ctorParameters: function () { return [{ type: ChatClientService }, { type: ChannelService }]; }, propDecorators: { messageInputTemplate: [{
4101
- type: i0.Input
4102
- }], mentionTemplate: [{
4103
- type: i0.Input
4104
- }], message: [{
4382
+ }], ctorParameters: function () { return [{ type: ChatClientService }, { type: ChannelService }, { type: CustomTemplatesService }, { type: i0__namespace.ChangeDetectorRef }]; }, propDecorators: { message: [{
4105
4383
  type: i0.Input
4106
4384
  }], enabledMessageActions: [{
4107
4385
  type: i0.Input
4108
- }], areReactionsEnabled: [{
4109
- type: i0.Input
4110
- }], canReactToMessage: [{
4111
- type: i0.Input
4112
4386
  }], isLastSentMessage: [{
4113
4387
  type: i0.Input
4114
- }], canReceiveReadEvents: [{
4115
- type: i0.Input
4116
4388
  }], mode: [{
4117
4389
  type: i0.Input
4118
4390
  }], container: [{
@@ -4215,12 +4487,13 @@
4215
4487
  * The `AutocompleteTextarea` component is used by the [`MessageInput`](./MessageInputComponent.mdx) component to display the input HTML element where users can type their message.
4216
4488
  */
4217
4489
  var AutocompleteTextareaComponent = /** @class */ (function () {
4218
- function AutocompleteTextareaComponent(channelService, chatClientService, transliterationService, emojiInputService) {
4490
+ function AutocompleteTextareaComponent(channelService, chatClientService, transliterationService, emojiInputService, customTemplatesService) {
4219
4491
  var _this = this;
4220
4492
  this.channelService = channelService;
4221
4493
  this.chatClientService = chatClientService;
4222
4494
  this.transliterationService = transliterationService;
4223
4495
  this.emojiInputService = emojiInputService;
4496
+ this.customTemplatesService = customTemplatesService;
4224
4497
  this.class = 'str-chat__textarea';
4225
4498
  /**
4226
4499
  * The value of the input HTML element.
@@ -4299,6 +4572,8 @@
4299
4572
  selectionStart + emoji.length;
4300
4573
  _this.inputChanged();
4301
4574
  }));
4575
+ this.subscriptions.push(this.customTemplatesService.mentionAutocompleteItemTemplate$.subscribe(function (template) { return (_this.mentionAutocompleteItemTemplate = template); }));
4576
+ this.subscriptions.push(this.customTemplatesService.commandAutocompleteItemTemplate$.subscribe(function (template) { return (_this.commandAutocompleteItemTemplate = template); }));
4302
4577
  this.autocompleteConfig.mentions = [
4303
4578
  this.userMentionConfig,
4304
4579
  this.slashCommandConfig,
@@ -4411,8 +4686,8 @@
4411
4686
  };
4412
4687
  return AutocompleteTextareaComponent;
4413
4688
  }());
4414
- AutocompleteTextareaComponent.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: AutocompleteTextareaComponent, deps: [{ token: ChannelService }, { token: ChatClientService }, { token: TransliterationService }, { token: EmojiInputService }], target: i0__namespace.ɵɵFactoryTarget.Component });
4415
- AutocompleteTextareaComponent.ɵcmp = i0__namespace.ɵɵ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__namespace, 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__namespace$1.MentionDirective, selector: "[mention], [mentionConfig]", inputs: ["mentionConfig", "mention", "mentionListTemplate"], outputs: ["searchTerm", "itemSelected", "opened", "closed"] }, { type: i6__namespace.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { type: i6__namespace.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { type: i6__namespace.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }], pipes: { "translate": i2__namespace.TranslatePipe } });
4689
+ AutocompleteTextareaComponent.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: AutocompleteTextareaComponent, deps: [{ token: ChannelService }, { token: ChatClientService }, { token: TransliterationService }, { token: EmojiInputService }, { token: CustomTemplatesService }], target: i0__namespace.ɵɵFactoryTarget.Component });
4690
+ AutocompleteTextareaComponent.ɵcmp = i0__namespace.ɵɵ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__namespace, 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__namespace.MentionDirective, selector: "[mention], [mentionConfig]", inputs: ["mentionConfig", "mention", "mentionListTemplate"], outputs: ["searchTerm", "itemSelected", "opened", "closed"] }, { type: i3__namespace.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { type: i3__namespace.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { type: i3__namespace.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }], pipes: { "translate": i2__namespace.TranslatePipe } });
4416
4691
  i0__namespace.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: AutocompleteTextareaComponent, decorators: [{
4417
4692
  type: i0.Component,
4418
4693
  args: [{
@@ -4420,16 +4695,12 @@
4420
4695
  templateUrl: './autocomplete-textarea.component.html',
4421
4696
  styles: [],
4422
4697
  }]
4423
- }], ctorParameters: function () { return [{ type: ChannelService }, { type: ChatClientService }, { type: TransliterationService }, { type: EmojiInputService }]; }, propDecorators: { class: [{
4698
+ }], ctorParameters: function () { return [{ type: ChannelService }, { type: ChatClientService }, { type: TransliterationService }, { type: EmojiInputService }, { type: CustomTemplatesService }]; }, propDecorators: { class: [{
4424
4699
  type: i0.HostBinding
4425
4700
  }], value: [{
4426
4701
  type: i0.Input
4427
4702
  }], areMentionsEnabled: [{
4428
4703
  type: i0.Input
4429
- }], mentionAutocompleteItemTemplate: [{
4430
- type: i0.Input
4431
- }], commandAutocompleteItemTemplate: [{
4432
- type: i0.Input
4433
4704
  }], mentionScope: [{
4434
4705
  type: i0.Input
4435
4706
  }], valueChange: [{
@@ -4488,20 +4759,12 @@
4488
4759
  * The `MessageList` component renders a scrollable list of messages.
4489
4760
  */
4490
4761
  var MessageListComponent = /** @class */ (function () {
4491
- function MessageListComponent(channelService, chatClientService, imageLoadService) {
4762
+ function MessageListComponent(channelService, chatClientService, imageLoadService, customTemplatesService) {
4492
4763
  var _this = this;
4493
4764
  this.channelService = channelService;
4494
4765
  this.chatClientService = chatClientService;
4495
4766
  this.imageLoadService = imageLoadService;
4496
- /**
4497
- * @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).
4498
- */
4499
- this.areReactionsEnabled = undefined;
4500
- /**
4501
- * @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.
4502
- */
4503
- /* eslint-disable-next-line @angular-eslint/no-input-rename */
4504
- this.enabledMessageActionsInput = undefined;
4767
+ this.customTemplatesService = customTemplatesService;
4505
4768
  /**
4506
4769
  * Determines if the message list should display channel messages or [thread messages](https://getstream.io/chat/docs/javascript/threads/?language=javascript).
4507
4770
  */
@@ -4510,7 +4773,6 @@
4510
4773
  this.class = 'str-chat-angular__main-panel-inner str-chat-angular__message-list-host';
4511
4774
  this.unreadMessageCount = 0;
4512
4775
  this.groupStyles = [];
4513
- this.authorizedMessageActions = ['flag'];
4514
4776
  this.isUserScrolledUpThreshold = 300;
4515
4777
  this.subscriptions = [];
4516
4778
  this.subscriptions.push(this.channelService.activeChannel$.subscribe(function (channel) {
@@ -4518,39 +4780,7 @@
4518
4780
  _this.resetScrollState();
4519
4781
  var capabilites = (_a = channel === null || channel === void 0 ? void 0 : channel.data) === null || _a === void 0 ? void 0 : _a.own_capabilities;
4520
4782
  if (capabilites) {
4521
- _this.canReactToMessage = capabilites.indexOf('send-reaction') !== -1;
4522
- _this.canReceiveReadEvents = capabilites.indexOf('read-events') !== -1;
4523
- _this.authorizedMessageActions = [];
4524
- if (_this.canReactToMessage) {
4525
- _this.authorizedMessageActions.push('send-reaction');
4526
- }
4527
- if (_this.canReceiveReadEvents) {
4528
- _this.authorizedMessageActions.push('read-events');
4529
- }
4530
- if (capabilites.indexOf('flag-message') !== -1) {
4531
- _this.authorizedMessageActions.push('flag');
4532
- }
4533
- if (capabilites.indexOf('update-own-message') !== -1) {
4534
- _this.authorizedMessageActions.push('edit');
4535
- }
4536
- if (capabilites.indexOf('update-any-message') !== -1) {
4537
- _this.authorizedMessageActions.push('edit');
4538
- _this.authorizedMessageActions.push('edit-any');
4539
- }
4540
- if (capabilites.indexOf('delete-own-message') !== -1) {
4541
- _this.authorizedMessageActions.push('delete');
4542
- }
4543
- if (capabilites.indexOf('delete-any-message') !== -1) {
4544
- _this.authorizedMessageActions.push('delete');
4545
- _this.authorizedMessageActions.push('delete-any');
4546
- }
4547
- if (capabilites.indexOf('send-reply') !== -1) {
4548
- _this.authorizedMessageActions.push('send-reply');
4549
- }
4550
- if (capabilites.indexOf('quote-message') !== -1) {
4551
- _this.authorizedMessageActions.push('quote-message');
4552
- }
4553
- _this.setEnabledActions();
4783
+ _this.enabledMessageActions = capabilites;
4554
4784
  }
4555
4785
  }));
4556
4786
  this.subscriptions.push(this.imageLoadService.imageLoad$.subscribe(function () {
@@ -4571,6 +4801,8 @@
4571
4801
  }
4572
4802
  _this.parentMessage = message;
4573
4803
  }));
4804
+ this.subscriptions.push(this.customTemplatesService.messageTemplate$.subscribe(function (template) { return (_this.messageTemplate = template); }));
4805
+ this.subscriptions.push(this.customTemplatesService.typingIndicatorTemplate$.subscribe(function (template) { return (_this.typingIndicatorTemplate = template); }));
4574
4806
  this.usersTypingInChannel$ = this.channelService.usersTypingInChannel$;
4575
4807
  this.usersTypingInThread$ = this.channelService.usersTypingInThread$;
4576
4808
  }
@@ -4578,9 +4810,6 @@
4578
4810
  this.setMessages$();
4579
4811
  };
4580
4812
  MessageListComponent.prototype.ngOnChanges = function (changes) {
4581
- if (changes.enabledMessageActionsInput) {
4582
- this.setEnabledActions();
4583
- }
4584
4813
  if (changes.mode) {
4585
4814
  this.setMessages$();
4586
4815
  }
@@ -4613,15 +4842,6 @@
4613
4842
  MessageListComponent.prototype.ngOnDestroy = function () {
4614
4843
  this.subscriptions.forEach(function (s) { return s.unsubscribe(); });
4615
4844
  };
4616
- Object.defineProperty(MessageListComponent.prototype, "usersTyping$", {
4617
- get: function () {
4618
- return this.mode === 'thread'
4619
- ? this.usersTypingInThread$
4620
- : this.usersTypingInChannel$;
4621
- },
4622
- enumerable: false,
4623
- configurable: true
4624
- });
4625
4845
  MessageListComponent.prototype.trackByMessageId = function (index, item) {
4626
4846
  return item.id;
4627
4847
  };
@@ -4654,31 +4874,24 @@
4654
4874
  }
4655
4875
  this.prevScrollTop = this.scrollContainer.nativeElement.scrollTop;
4656
4876
  };
4877
+ MessageListComponent.prototype.getTypingIndicatorContext = function () {
4878
+ return {
4879
+ usersTyping$: this.usersTyping$,
4880
+ };
4881
+ };
4882
+ MessageListComponent.prototype.getMessageContext = function (message) {
4883
+ return {
4884
+ message: message,
4885
+ isLastSentMessage: !!(this.lastSentMessageId && (message === null || message === void 0 ? void 0 : message.id) === this.lastSentMessageId),
4886
+ enabledMessageActions: this.enabledMessageActions,
4887
+ mode: this.mode,
4888
+ };
4889
+ };
4657
4890
  MessageListComponent.prototype.preserveScrollbarPosition = function () {
4658
4891
  this.scrollContainer.nativeElement.scrollTop =
4659
4892
  (this.prevScrollTop || 0) +
4660
4893
  (this.scrollContainer.nativeElement.scrollHeight - this.containerHeight);
4661
4894
  };
4662
- MessageListComponent.prototype.setEnabledActions = function () {
4663
- var _this = this;
4664
- this.enabledMessageActions = [];
4665
- if (!this.enabledMessageActionsInput) {
4666
- this.enabledMessageActions = this.authorizedMessageActions;
4667
- return;
4668
- }
4669
- this.enabledMessageActionsInput = __spreadArray(__spreadArray([], __read(this.enabledMessageActionsInput)), [
4670
- 'send-reaction',
4671
- 'read-events',
4672
- 'send-reply',
4673
- 'quote-message',
4674
- ]);
4675
- this.enabledMessageActionsInput.forEach(function (action) {
4676
- var isAuthorized = _this.authorizedMessageActions.indexOf(action) !== -1;
4677
- if (isAuthorized) {
4678
- _this.enabledMessageActions.push(action);
4679
- }
4680
- });
4681
- };
4682
4895
  MessageListComponent.prototype.setMessages$ = function () {
4683
4896
  var _this = this;
4684
4897
  this.messages$ = (this.mode === 'main'
@@ -4731,10 +4944,19 @@
4731
4944
  this.prevScrollTop = undefined;
4732
4945
  this.isNewMessageSentByUser = undefined;
4733
4946
  };
4947
+ Object.defineProperty(MessageListComponent.prototype, "usersTyping$", {
4948
+ get: function () {
4949
+ return this.mode === 'thread'
4950
+ ? this.usersTypingInThread$
4951
+ : this.usersTypingInChannel$;
4952
+ },
4953
+ enumerable: false,
4954
+ configurable: true
4955
+ });
4734
4956
  return MessageListComponent;
4735
4957
  }());
4736
- MessageListComponent.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: MessageListComponent, deps: [{ token: ChannelService }, { token: ChatClientService }, { token: ImageLoadService }], target: i0__namespace.ɵɵFactoryTarget.Component });
4737
- MessageListComponent.ɵcmp = i0__namespace.ɵɵ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__namespace, 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 }\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__namespace.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i6__namespace.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i2__namespace.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i6__namespace.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], pipes: { "async": i6__namespace.AsyncPipe } });
4958
+ MessageListComponent.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: MessageListComponent, deps: [{ token: ChannelService }, { token: ChatClientService }, { token: ImageLoadService }, { token: CustomTemplatesService }], target: i0__namespace.ɵɵFactoryTarget.Component });
4959
+ MessageListComponent.ɵcmp = i0__namespace.ɵɵ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__namespace, 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__namespace.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3__namespace.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i2__namespace.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i3__namespace.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], pipes: { "async": i3__namespace.AsyncPipe } });
4738
4960
  i0__namespace.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: MessageListComponent, decorators: [{
4739
4961
  type: i0.Component,
4740
4962
  args: [{
@@ -4742,20 +4964,7 @@
4742
4964
  templateUrl: './message-list.component.html',
4743
4965
  styles: [],
4744
4966
  }]
4745
- }], ctorParameters: function () { return [{ type: ChannelService }, { type: ChatClientService }, { type: ImageLoadService }]; }, propDecorators: { messageTemplate: [{
4746
- type: i0.Input
4747
- }], messageInputTemplate: [{
4748
- type: i0.Input
4749
- }], mentionTemplate: [{
4750
- type: i0.Input
4751
- }], typingIndicatorTemplate: [{
4752
- type: i0.Input
4753
- }], areReactionsEnabled: [{
4754
- type: i0.Input
4755
- }], enabledMessageActionsInput: [{
4756
- type: i0.Input,
4757
- args: ['enabledMessageActions']
4758
- }], mode: [{
4967
+ }], ctorParameters: function () { return [{ type: ChannelService }, { type: ChatClientService }, { type: ImageLoadService }, { type: CustomTemplatesService }]; }, propDecorators: { mode: [{
4759
4968
  type: i0.Input
4760
4969
  }], class: [{
4761
4970
  type: i0.HostBinding,
@@ -4772,8 +4981,9 @@
4772
4981
  * 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.
4773
4982
  */
4774
4983
  var ThreadComponent = /** @class */ (function () {
4775
- function ThreadComponent(channelService) {
4984
+ function ThreadComponent(customTemplatesService, channelService) {
4776
4985
  var _this = this;
4986
+ this.customTemplatesService = customTemplatesService;
4777
4987
  this.channelService = channelService;
4778
4988
  this.class = 'str-chat__thread';
4779
4989
  this.subscriptions = [];
@@ -4782,21 +4992,23 @@
4782
4992
  ThreadComponent.prototype.ngOnDestroy = function () {
4783
4993
  this.subscriptions.forEach(function (s) { return s.unsubscribe(); });
4784
4994
  };
4785
- Object.defineProperty(ThreadComponent.prototype, "replyCountParam", {
4786
- get: function () {
4787
- var _a;
4788
- return { replyCount: (_a = this.parentMessage) === null || _a === void 0 ? void 0 : _a.reply_count };
4789
- },
4790
- enumerable: false,
4791
- configurable: true
4792
- });
4995
+ ThreadComponent.prototype.getThreadHeaderContext = function () {
4996
+ var _this = this;
4997
+ return {
4998
+ parentMessage: this.parentMessage,
4999
+ closeThreadHandler: function () { return _this.closeThread(); },
5000
+ };
5001
+ };
5002
+ ThreadComponent.prototype.getReplyCountParam = function (parentMessage) {
5003
+ return { replyCount: parentMessage === null || parentMessage === void 0 ? void 0 : parentMessage.reply_count };
5004
+ };
4793
5005
  ThreadComponent.prototype.closeThread = function () {
4794
5006
  void this.channelService.setAsActiveParentMessage(undefined);
4795
5007
  };
4796
5008
  return ThreadComponent;
4797
5009
  }());
4798
- ThreadComponent.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: ThreadComponent, deps: [{ token: ChannelService }], target: i0__namespace.ɵɵFactoryTarget.Component });
4799
- ThreadComponent.ɵcmp = i0__namespace.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: ThreadComponent, selector: "stream-thread", host: { properties: { "class": "this.class" } }, ngImport: i0__namespace, 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__namespace.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }], pipes: { "translate": i2__namespace.TranslatePipe } });
5010
+ ThreadComponent.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: ThreadComponent, deps: [{ token: CustomTemplatesService }, { token: ChannelService }], target: i0__namespace.ɵɵFactoryTarget.Component });
5011
+ ThreadComponent.ɵcmp = i0__namespace.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: ThreadComponent, selector: "stream-thread", host: { properties: { "class": "this.class" } }, ngImport: i0__namespace, 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__namespace.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i2__namespace.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }], pipes: { "async": i3__namespace.AsyncPipe, "translate": i2__namespace.TranslatePipe } });
4800
5012
  i0__namespace.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: ThreadComponent, decorators: [{
4801
5013
  type: i0.Component,
4802
5014
  args: [{
@@ -4804,7 +5016,7 @@
4804
5016
  templateUrl: './thread.component.html',
4805
5017
  styles: [],
4806
5018
  }]
4807
- }], ctorParameters: function () { return [{ type: ChannelService }]; }, propDecorators: { class: [{
5019
+ }], ctorParameters: function () { return [{ type: CustomTemplatesService }, { type: ChannelService }]; }, propDecorators: { class: [{
4808
5020
  type: i0.HostBinding,
4809
5021
  args: ['class']
4810
5022
  }] } });
@@ -4815,14 +5027,14 @@
4815
5027
  return StreamAvatarModule;
4816
5028
  }());
4817
5029
  StreamAvatarModule.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: StreamAvatarModule, deps: [], target: i0__namespace.ɵɵFactoryTarget.NgModule });
4818
- StreamAvatarModule.ɵmod = i0__namespace.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: StreamAvatarModule, declarations: [AvatarComponent], imports: [i6.CommonModule, i2.TranslateModule], exports: [AvatarComponent] });
4819
- StreamAvatarModule.ɵinj = i0__namespace.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: StreamAvatarModule, imports: [[i6.CommonModule, i2.TranslateModule]] });
5030
+ StreamAvatarModule.ɵmod = i0__namespace.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: StreamAvatarModule, declarations: [AvatarComponent, AvatarPlaceholderComponent], imports: [i3.CommonModule, i2.TranslateModule], exports: [AvatarComponent, AvatarPlaceholderComponent] });
5031
+ StreamAvatarModule.ɵinj = i0__namespace.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: StreamAvatarModule, imports: [[i3.CommonModule, i2.TranslateModule]] });
4820
5032
  i0__namespace.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: StreamAvatarModule, decorators: [{
4821
5033
  type: i0.NgModule,
4822
5034
  args: [{
4823
- declarations: [AvatarComponent],
4824
- imports: [i6.CommonModule, i2.TranslateModule],
4825
- exports: [AvatarComponent],
5035
+ declarations: [AvatarComponent, AvatarPlaceholderComponent],
5036
+ imports: [i3.CommonModule, i2.TranslateModule],
5037
+ exports: [AvatarComponent, AvatarPlaceholderComponent],
4826
5038
  }]
4827
5039
  }] });
4828
5040
 
@@ -4849,7 +5061,9 @@
4849
5061
  AttachmentPreviewListComponent,
4850
5062
  ModalComponent,
4851
5063
  TextareaDirective,
4852
- ThreadComponent], imports: [i6.CommonModule, i2.TranslateModule, StreamAvatarModule], exports: [ChannelComponent,
5064
+ ThreadComponent,
5065
+ IconPlaceholderComponent,
5066
+ LoadingIndicatorPlaceholderComponent], imports: [i3.CommonModule, i2.TranslateModule, StreamAvatarModule], exports: [ChannelComponent,
4853
5067
  ChannelHeaderComponent,
4854
5068
  ChannelListComponent,
4855
5069
  ChannelPreviewComponent,
@@ -4866,8 +5080,10 @@
4866
5080
  AttachmentPreviewListComponent,
4867
5081
  ModalComponent,
4868
5082
  StreamAvatarModule,
4869
- ThreadComponent] });
4870
- StreamChatModule.ɵinj = i0__namespace.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: StreamChatModule, imports: [[i6.CommonModule, i2.TranslateModule, StreamAvatarModule], StreamAvatarModule] });
5083
+ ThreadComponent,
5084
+ IconPlaceholderComponent,
5085
+ LoadingIndicatorPlaceholderComponent] });
5086
+ StreamChatModule.ɵinj = i0__namespace.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: StreamChatModule, imports: [[i3.CommonModule, i2.TranslateModule, StreamAvatarModule], StreamAvatarModule] });
4871
5087
  i0__namespace.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: StreamChatModule, decorators: [{
4872
5088
  type: i0.NgModule,
4873
5089
  args: [{
@@ -4890,8 +5106,10 @@
4890
5106
  ModalComponent,
4891
5107
  TextareaDirective,
4892
5108
  ThreadComponent,
5109
+ IconPlaceholderComponent,
5110
+ LoadingIndicatorPlaceholderComponent,
4893
5111
  ],
4894
- imports: [i6.CommonModule, i2.TranslateModule, StreamAvatarModule],
5112
+ imports: [i3.CommonModule, i2.TranslateModule, StreamAvatarModule],
4895
5113
  exports: [
4896
5114
  ChannelComponent,
4897
5115
  ChannelHeaderComponent,
@@ -4911,6 +5129,8 @@
4911
5129
  ModalComponent,
4912
5130
  StreamAvatarModule,
4913
5131
  ThreadComponent,
5132
+ IconPlaceholderComponent,
5133
+ LoadingIndicatorPlaceholderComponent,
4914
5134
  ],
4915
5135
  }]
4916
5136
  }] });
@@ -4921,18 +5141,18 @@
4921
5141
  return StreamAutocompleteTextareaModule;
4922
5142
  }());
4923
5143
  StreamAutocompleteTextareaModule.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: StreamAutocompleteTextareaModule, deps: [], target: i0__namespace.ɵɵFactoryTarget.NgModule });
4924
- StreamAutocompleteTextareaModule.ɵmod = i0__namespace.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: StreamAutocompleteTextareaModule, declarations: [AutocompleteTextareaComponent], imports: [i6.CommonModule, i2.TranslateModule, i6$1.MentionModule, StreamAvatarModule], exports: [AutocompleteTextareaComponent] });
5144
+ StreamAutocompleteTextareaModule.ɵmod = i0__namespace.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: StreamAutocompleteTextareaModule, declarations: [AutocompleteTextareaComponent], imports: [i3.CommonModule, i2.TranslateModule, i7.MentionModule, StreamAvatarModule], exports: [AutocompleteTextareaComponent] });
4925
5145
  StreamAutocompleteTextareaModule.ɵinj = i0__namespace.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: StreamAutocompleteTextareaModule, providers: [
4926
5146
  {
4927
5147
  provide: textareaInjectionToken,
4928
5148
  useValue: AutocompleteTextareaComponent,
4929
5149
  },
4930
- ], imports: [[i6.CommonModule, i2.TranslateModule, i6$1.MentionModule, StreamAvatarModule]] });
5150
+ ], imports: [[i3.CommonModule, i2.TranslateModule, i7.MentionModule, StreamAvatarModule]] });
4931
5151
  i0__namespace.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: StreamAutocompleteTextareaModule, decorators: [{
4932
5152
  type: i0.NgModule,
4933
5153
  args: [{
4934
5154
  declarations: [AutocompleteTextareaComponent],
4935
- imports: [i6.CommonModule, i2.TranslateModule, i6$1.MentionModule, StreamAvatarModule],
5155
+ imports: [i3.CommonModule, i2.TranslateModule, i7.MentionModule, StreamAvatarModule],
4936
5156
  exports: [AutocompleteTextareaComponent],
4937
5157
  providers: [
4938
5158
  {
@@ -4949,18 +5169,18 @@
4949
5169
  return StreamTextareaModule;
4950
5170
  }());
4951
5171
  StreamTextareaModule.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: StreamTextareaModule, deps: [], target: i0__namespace.ɵɵFactoryTarget.NgModule });
4952
- StreamTextareaModule.ɵmod = i0__namespace.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: StreamTextareaModule, declarations: [TextareaComponent], imports: [i6.CommonModule, i2.TranslateModule], exports: [TextareaComponent] });
5172
+ StreamTextareaModule.ɵmod = i0__namespace.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: StreamTextareaModule, declarations: [TextareaComponent], imports: [i3.CommonModule, i2.TranslateModule], exports: [TextareaComponent] });
4953
5173
  StreamTextareaModule.ɵinj = i0__namespace.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: StreamTextareaModule, providers: [
4954
5174
  {
4955
5175
  provide: textareaInjectionToken,
4956
5176
  useValue: TextareaComponent,
4957
5177
  },
4958
- ], imports: [[i6.CommonModule, i2.TranslateModule]] });
5178
+ ], imports: [[i3.CommonModule, i2.TranslateModule]] });
4959
5179
  i0__namespace.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: StreamTextareaModule, decorators: [{
4960
5180
  type: i0.NgModule,
4961
5181
  args: [{
4962
5182
  declarations: [TextareaComponent],
4963
- imports: [i6.CommonModule, i2.TranslateModule],
5183
+ imports: [i3.CommonModule, i2.TranslateModule],
4964
5184
  exports: [TextareaComponent],
4965
5185
  providers: [
4966
5186
  {
@@ -4984,6 +5204,7 @@
4984
5204
  exports.AttachmentService = AttachmentService;
4985
5205
  exports.AutocompleteTextareaComponent = AutocompleteTextareaComponent;
4986
5206
  exports.AvatarComponent = AvatarComponent;
5207
+ exports.AvatarPlaceholderComponent = AvatarPlaceholderComponent;
4987
5208
  exports.ChannelComponent = ChannelComponent;
4988
5209
  exports.ChannelHeaderComponent = ChannelHeaderComponent;
4989
5210
  exports.ChannelListComponent = ChannelListComponent;
@@ -4991,10 +5212,13 @@
4991
5212
  exports.ChannelPreviewComponent = ChannelPreviewComponent;
4992
5213
  exports.ChannelService = ChannelService;
4993
5214
  exports.ChatClientService = ChatClientService;
5215
+ exports.CustomTemplatesService = CustomTemplatesService;
4994
5216
  exports.EmojiInputService = EmojiInputService;
4995
5217
  exports.IconComponent = IconComponent;
5218
+ exports.IconPlaceholderComponent = IconPlaceholderComponent;
4996
5219
  exports.ImageLoadService = ImageLoadService;
4997
5220
  exports.LoadingIndicatorComponent = LoadingIndicatorComponent;
5221
+ exports.LoadingIndicatorPlaceholderComponent = LoadingIndicatorPlaceholderComponent;
4998
5222
  exports.MessageActionsBoxComponent = MessageActionsBoxComponent;
4999
5223
  exports.MessageComponent = MessageComponent;
5000
5224
  exports.MessageInputComponent = MessageInputComponent;