@hellotext/hellotext 2.1.3 → 2.1.4

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.
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
+ var _core = require("../core");
7
8
  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
8
9
  function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
9
10
  function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
@@ -17,17 +18,19 @@ let ApplicationChannel = /*#__PURE__*/function () {
17
18
  key: "send",
18
19
  value: function send({
19
20
  command,
20
- identifier
21
+ identifier,
22
+ data
21
23
  }) {
22
- const data = {
24
+ const payload = {
23
25
  command,
24
- identifier: JSON.stringify(identifier)
26
+ identifier: JSON.stringify(identifier),
27
+ data: JSON.stringify(data || {})
25
28
  };
26
29
  if (this.webSocket.readyState === WebSocket.OPEN) {
27
- this.webSocket.send(JSON.stringify(data));
30
+ this.webSocket.send(JSON.stringify(payload));
28
31
  } else {
29
32
  this.webSocket.addEventListener('open', () => {
30
- this.webSocket.send(JSON.stringify(data));
33
+ this.webSocket.send(JSON.stringify(payload));
31
34
  });
32
35
  }
33
36
  }
@@ -50,7 +53,7 @@ let ApplicationChannel = /*#__PURE__*/function () {
50
53
  key: "webSocket",
51
54
  get: function () {
52
55
  if (!ApplicationChannel.webSocket) {
53
- return ApplicationChannel.webSocket = new WebSocket("wss://www.hellotext.com/cable");
56
+ return ApplicationChannel.webSocket = new WebSocket(_core.Configuration.actionCableUrl);
54
57
  }
55
58
  return ApplicationChannel.webSocket;
56
59
  }
@@ -3,6 +3,7 @@ function _defineProperties(target, props) { for (var i = 0; i < props.length; i+
3
3
  function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
4
4
  function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
5
5
  function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
6
+ import { Configuration } from '../core';
6
7
  var ApplicationChannel = /*#__PURE__*/function () {
7
8
  function ApplicationChannel() {
8
9
  _classCallCheck(this, ApplicationChannel);
@@ -12,17 +13,19 @@ var ApplicationChannel = /*#__PURE__*/function () {
12
13
  value: function send(_ref) {
13
14
  var {
14
15
  command,
15
- identifier
16
+ identifier,
17
+ data
16
18
  } = _ref;
17
- var data = {
19
+ var payload = {
18
20
  command,
19
- identifier: JSON.stringify(identifier)
21
+ identifier: JSON.stringify(identifier),
22
+ data: JSON.stringify(data || {})
20
23
  };
21
24
  if (this.webSocket.readyState === WebSocket.OPEN) {
22
- this.webSocket.send(JSON.stringify(data));
25
+ this.webSocket.send(JSON.stringify(payload));
23
26
  } else {
24
27
  this.webSocket.addEventListener('open', () => {
25
- this.webSocket.send(JSON.stringify(data));
28
+ this.webSocket.send(JSON.stringify(payload));
26
29
  });
27
30
  }
28
31
  }
@@ -45,7 +48,7 @@ var ApplicationChannel = /*#__PURE__*/function () {
45
48
  key: "webSocket",
46
49
  get: function get() {
47
50
  if (!ApplicationChannel.webSocket) {
48
- return ApplicationChannel.webSocket = new WebSocket("wss://www.hellotext.com/cable");
51
+ return ApplicationChannel.webSocket = new WebSocket(Configuration.actionCableUrl);
49
52
  }
50
53
  return ApplicationChannel.webSocket;
51
54
  }
@@ -37,7 +37,7 @@ let WebchatChannel = /*#__PURE__*/function (_ApplicationChannel) {
37
37
  key: "subscribe",
38
38
  value: function subscribe() {
39
39
  const params = {
40
- channel: "WebchatChannel",
40
+ channel: 'WebchatChannel',
41
41
  id: this.id,
42
42
  session: this.session,
43
43
  conversation: this.conversation
@@ -51,7 +51,7 @@ let WebchatChannel = /*#__PURE__*/function (_ApplicationChannel) {
51
51
  key: "unsubscribe",
52
52
  value: function unsubscribe() {
53
53
  const params = {
54
- channel: "WebchatChannel",
54
+ channel: 'WebchatChannel',
55
55
  id: this.id,
56
56
  session: this.session,
57
57
  conversation: this.conversation
@@ -62,29 +62,45 @@ let WebchatChannel = /*#__PURE__*/function (_ApplicationChannel) {
62
62
  });
63
63
  }
64
64
  }, {
65
- key: "onMessage",
66
- value: function onMessage(callback) {
67
- _get(_getPrototypeOf(WebchatChannel.prototype), "onMessage", this).call(this, message => {
68
- if (message.type !== 'message') return;
69
- callback(message);
65
+ key: "startTypingIndicator",
66
+ value: function startTypingIndicator() {
67
+ const params = {
68
+ channel: 'WebchatChannel',
69
+ id: this.id,
70
+ session: this.session,
71
+ conversation: this.conversation
72
+ };
73
+ this.send({
74
+ command: 'message',
75
+ identifier: params,
76
+ data: {
77
+ action: 'started_typing'
78
+ }
70
79
  });
71
80
  }
72
81
  }, {
73
- key: "onConversationAssignment",
74
- value: function onConversationAssignment(callback) {
75
- _get(_getPrototypeOf(WebchatChannel.prototype), "onMessage", this).call(this, message => {
76
- if (message.type === 'conversation.assigned') {
77
- callback(message);
82
+ key: "stopTypingIndicator",
83
+ value: function stopTypingIndicator() {
84
+ const params = {
85
+ channel: 'WebchatChannel',
86
+ id: this.id,
87
+ session: this.session,
88
+ conversation: this.conversation
89
+ };
90
+ this.send({
91
+ command: 'typing:stop',
92
+ identifier: params,
93
+ data: {
94
+ action: 'stopped_typing'
78
95
  }
79
96
  });
80
97
  }
81
98
  }, {
82
- key: "onAgentOnline",
83
- value: function onAgentOnline(callback) {
99
+ key: "onMessage",
100
+ value: function onMessage(callback) {
84
101
  _get(_getPrototypeOf(WebchatChannel.prototype), "onMessage", this).call(this, message => {
85
- if (message.type === 'agent_is_online') {
86
- callback(message);
87
- }
102
+ if (message.type !== 'message') return;
103
+ callback(message);
88
104
  });
89
105
  }
90
106
  }, {
@@ -96,6 +112,15 @@ let WebchatChannel = /*#__PURE__*/function (_ApplicationChannel) {
96
112
  }
97
113
  });
98
114
  }
115
+ }, {
116
+ key: "onTypingStart",
117
+ value: function onTypingStart(callback) {
118
+ _get(_getPrototypeOf(WebchatChannel.prototype), "onMessage", this).call(this, message => {
119
+ if (message.type === 'started_typing') {
120
+ callback(message);
121
+ }
122
+ });
123
+ }
99
124
  }, {
100
125
  key: "updateSubscriptionWith",
101
126
  value: function updateSubscriptionWith(conversation) {
@@ -30,7 +30,7 @@ var WebchatChannel = /*#__PURE__*/function (_ApplicationChannel) {
30
30
  key: "subscribe",
31
31
  value: function subscribe() {
32
32
  var params = {
33
- channel: "WebchatChannel",
33
+ channel: 'WebchatChannel',
34
34
  id: this.id,
35
35
  session: this.session,
36
36
  conversation: this.conversation
@@ -44,7 +44,7 @@ var WebchatChannel = /*#__PURE__*/function (_ApplicationChannel) {
44
44
  key: "unsubscribe",
45
45
  value: function unsubscribe() {
46
46
  var params = {
47
- channel: "WebchatChannel",
47
+ channel: 'WebchatChannel',
48
48
  id: this.id,
49
49
  session: this.session,
50
50
  conversation: this.conversation
@@ -55,29 +55,45 @@ var WebchatChannel = /*#__PURE__*/function (_ApplicationChannel) {
55
55
  });
56
56
  }
57
57
  }, {
58
- key: "onMessage",
59
- value: function onMessage(callback) {
60
- _get(_getPrototypeOf(WebchatChannel.prototype), "onMessage", this).call(this, message => {
61
- if (message.type !== 'message') return;
62
- callback(message);
58
+ key: "startTypingIndicator",
59
+ value: function startTypingIndicator() {
60
+ var params = {
61
+ channel: 'WebchatChannel',
62
+ id: this.id,
63
+ session: this.session,
64
+ conversation: this.conversation
65
+ };
66
+ this.send({
67
+ command: 'message',
68
+ identifier: params,
69
+ data: {
70
+ action: 'started_typing'
71
+ }
63
72
  });
64
73
  }
65
74
  }, {
66
- key: "onConversationAssignment",
67
- value: function onConversationAssignment(callback) {
68
- _get(_getPrototypeOf(WebchatChannel.prototype), "onMessage", this).call(this, message => {
69
- if (message.type === 'conversation.assigned') {
70
- callback(message);
75
+ key: "stopTypingIndicator",
76
+ value: function stopTypingIndicator() {
77
+ var params = {
78
+ channel: 'WebchatChannel',
79
+ id: this.id,
80
+ session: this.session,
81
+ conversation: this.conversation
82
+ };
83
+ this.send({
84
+ command: 'typing:stop',
85
+ identifier: params,
86
+ data: {
87
+ action: 'stopped_typing'
71
88
  }
72
89
  });
73
90
  }
74
91
  }, {
75
- key: "onAgentOnline",
76
- value: function onAgentOnline(callback) {
92
+ key: "onMessage",
93
+ value: function onMessage(callback) {
77
94
  _get(_getPrototypeOf(WebchatChannel.prototype), "onMessage", this).call(this, message => {
78
- if (message.type === 'agent_is_online') {
79
- callback(message);
80
- }
95
+ if (message.type !== 'message') return;
96
+ callback(message);
81
97
  });
82
98
  }
83
99
  }, {
@@ -89,6 +105,15 @@ var WebchatChannel = /*#__PURE__*/function (_ApplicationChannel) {
89
105
  }
90
106
  });
91
107
  }
108
+ }, {
109
+ key: "onTypingStart",
110
+ value: function onTypingStart(callback) {
111
+ _get(_getPrototypeOf(WebchatChannel.prototype), "onMessage", this).call(this, message => {
112
+ if (message.type === 'started_typing') {
113
+ callback(message);
114
+ }
115
+ });
116
+ }
92
117
  }, {
93
118
  key: "updateSubscriptionWith",
94
119
  value: function updateSubscriptionWith(conversation) {
@@ -42,9 +42,8 @@ let _default = /*#__PURE__*/function (_Controller) {
42
42
  this.webChatChannel = new _webchat_channel.default(this.idValue, _hellotext.default.session, this.conversationIdValue);
43
43
  this.files = [];
44
44
  this.onMessageReceived = this.onMessageReceived.bind(this);
45
- this.onConversationAssignment = this.onConversationAssignment.bind(this);
46
- this.onAgentOnline = this.onAgentOnline.bind(this);
47
45
  this.onMessageReaction = this.onMessageReaction.bind(this);
46
+ this.onTypingStart = this.onTypingStart.bind(this);
48
47
  this.onScroll = this.onScroll.bind(this);
49
48
  this.onOutboundMessageSent = this.onOutboundMessageSent.bind(this);
50
49
  this.broadcastChannel = new BroadcastChannel(`hellotext--webchat--${this.idValue}`);
@@ -61,8 +60,7 @@ let _default = /*#__PURE__*/function (_Controller) {
61
60
  popover: this.popoverTarget
62
61
  });
63
62
  this.webChatChannel.onMessage(this.onMessageReceived);
64
- this.webChatChannel.onConversationAssignment(this.onConversationAssignment);
65
- this.webChatChannel.onAgentOnline(this.onAgentOnline);
63
+ this.webChatChannel.onTypingStart(this.onTypingStart);
66
64
  this.webChatChannel.onReaction(this.onMessageReaction);
67
65
  this.messagesContainerTarget.addEventListener('scroll', this.onScroll);
68
66
  if (!_hellotext.default.business.features.white_label) {
@@ -80,10 +78,85 @@ let _default = /*#__PURE__*/function (_Controller) {
80
78
  value: function disconnect() {
81
79
  this.broadcastChannel.removeEventListener('message', this.onOutboundMessageSent);
82
80
  this.messagesContainerTarget.removeEventListener('scroll', this.onScroll);
81
+
82
+ // Clean up typing indicator timeouts
83
+ this.clearTypingIndicator();
83
84
  this.broadcastChannel.close();
84
85
  this.floatingUICleanup();
85
86
  _get(_getPrototypeOf(_default.prototype), "disconnect", this).call(this);
86
87
  }
88
+ }, {
89
+ key: "onTypingStart",
90
+ value: function onTypingStart() {
91
+ if (this.typingIndicatorVisible) {
92
+ return this.resetTypingIndicatorTimer();
93
+ }
94
+ this.showTypingIndicator();
95
+ }
96
+ }, {
97
+ key: "showOptimisticTypingIndicator",
98
+ value: function showOptimisticTypingIndicator() {
99
+ if (this.typingIndicatorVisible) return;
100
+ this.showTypingIndicator();
101
+ }
102
+ }, {
103
+ key: "showTypingIndicator",
104
+ value: function showTypingIndicator() {
105
+ this.clearTypingIndicator();
106
+ this.typingIndicatorVisible = true;
107
+ const indicator = this.typingIndicatorTemplateTarget.cloneNode(true);
108
+ indicator.setAttribute('data-hellotext--webchat-target', 'typingIndicator');
109
+ indicator.style.display = 'flex';
110
+ this.messagesContainerTarget.appendChild(indicator);
111
+ requestAnimationFrame(() => {
112
+ this.messagesContainerTarget.scroll({
113
+ top: this.messagesContainerTarget.scrollHeight,
114
+ behavior: 'instant'
115
+ });
116
+ });
117
+ const timeout = this.typingIndicatorKeepAliveValue;
118
+ this.incomingTypingIndicatorTimeout = setTimeout(() => {
119
+ this.clearTypingIndicator();
120
+ }, timeout);
121
+ }
122
+ }, {
123
+ key: "resetTypingIndicatorTimer",
124
+ value: function resetTypingIndicatorTimer() {
125
+ if (!this.typingIndicatorVisible) return;
126
+
127
+ // Clear existing timeout
128
+ clearTimeout(this.incomingTypingIndicatorTimeout);
129
+ clearTimeout(this.optimisticTypingTimeout);
130
+
131
+ // Use unified timeout for all typing indicators
132
+ const timeout = this.typingIndicatorKeepAliveValue;
133
+ this.incomingTypingIndicatorTimeout = setTimeout(() => {
134
+ this.clearTypingIndicator();
135
+ }, timeout);
136
+ }
137
+ }, {
138
+ key: "clearTypingIndicator",
139
+ value: function clearTypingIndicator() {
140
+ if (this.hasTypingIndicatorTarget) {
141
+ this.typingIndicatorTarget.remove();
142
+ }
143
+ this.typingIndicatorVisible = false;
144
+ clearTimeout(this.incomingTypingIndicatorTimeout);
145
+ clearTimeout(this.optimisticTypingTimeout);
146
+ }
147
+ }, {
148
+ key: "onMessageInputChange",
149
+ value: function onMessageInputChange() {
150
+ this.resizeInput();
151
+ clearTimeout(this.typingIndicatorTimeout);
152
+ if (!this.hasSentTypingIndicator) {
153
+ this.webChatChannel.startTypingIndicator();
154
+ this.hasSentTypingIndicator = true;
155
+ }
156
+ this.typingIndicatorTimeout = setTimeout(() => {
157
+ this.hasSentTypingIndicator = false;
158
+ }, 3000);
159
+ }
87
160
  }, {
88
161
  key: "onOutboundMessageSent",
89
162
  value: function onOutboundMessageSent(event) {
@@ -93,7 +166,13 @@ let _default = /*#__PURE__*/function (_Controller) {
93
166
  const callbacks = {
94
167
  'message:sent': data => {
95
168
  const element = new DOMParser().parseFromString(data.element, 'text/html').body.firstElementChild;
96
- this.messagesContainerTarget.appendChild(element);
169
+
170
+ // Insert message before typing indicator if one exists
171
+ if (this.typingIndicatorVisible && this.hasTypingIndicatorTarget) {
172
+ this.messagesContainerTarget.insertBefore(element, this.typingIndicatorTarget);
173
+ } else {
174
+ this.messagesContainerTarget.appendChild(element);
175
+ }
97
176
  element.scrollIntoView({
98
177
  behavior: 'instant'
99
178
  });
@@ -247,6 +326,11 @@ let _default = /*#__PURE__*/function (_Controller) {
247
326
  element.querySelector('[data-attachment-container]').appendChild(image);
248
327
  });
249
328
  }
329
+
330
+ // Clear any typing indicator when message is received
331
+ if (this.typingIndicatorVisible) {
332
+ this.clearTypingIndicator();
333
+ }
250
334
  this.messagesContainerTarget.appendChild(element);
251
335
  _hellotext.default.eventEmitter.dispatch('webchat:message:received', {
252
336
  ...message,
@@ -255,7 +339,6 @@ let _default = /*#__PURE__*/function (_Controller) {
255
339
  element.scrollIntoView({
256
340
  behavior: 'smooth'
257
341
  });
258
- this.setOfflineTimeout();
259
342
  if (this.openValue) {
260
343
  this.messagesAPI.markAsSeen(id);
261
344
  return;
@@ -265,33 +348,30 @@ let _default = /*#__PURE__*/function (_Controller) {
265
348
  this.unreadCounterTarget.innerText = unreadCount > 99 ? '99+' : unreadCount;
266
349
  }
267
350
  }, {
268
- key: "onConversationAssignment",
269
- value: function onConversationAssignment(conversation) {
270
- const {
271
- to: user
272
- } = conversation;
273
- this.titleTarget.innerText = user.name;
274
- if (user.online) {
275
- this.onlineStatusTarget.style.display = 'flex';
276
- } else {
277
- this.onlineStatusTarget.style.display = 'none';
278
- }
279
- }
280
- }, {
281
- key: "onAgentOnline",
282
- value: function onAgentOnline() {
283
- this.onlineStatusTarget.style.display = 'flex';
284
- this.setOfflineTimeout();
351
+ key: "resizeInput",
352
+ value: function resizeInput() {
353
+ const maxHeight = 96;
354
+
355
+ // Temporarily reset height to its natural content size
356
+ this.inputTarget.style.height = 'auto';
357
+
358
+ // Set the height to the scrollHeight, which is the minimum height
359
+ // the element needs to fit its content without a scrollbar.
360
+ const scrollHeight = this.inputTarget.scrollHeight;
361
+ this.inputTarget.style.height = `${Math.min(scrollHeight, maxHeight)}px`;
285
362
  }
286
363
  }, {
287
364
  key: "sendMessage",
288
- value: async function sendMessage() {
365
+ value: async function sendMessage(e) {
289
366
  const formData = new FormData();
290
367
  const message = {
291
368
  body: this.inputTarget.value,
292
369
  attachments: this.files
293
370
  };
294
371
  if (this.inputTarget.value.trim().length === 0 && this.files.length === 0) {
372
+ if (e && e.target) {
373
+ e.preventDefault();
374
+ }
295
375
  return;
296
376
  }
297
377
  if (this.inputTarget.value.trim().length > 0) {
@@ -320,7 +400,13 @@ let _default = /*#__PURE__*/function (_Controller) {
320
400
  element.querySelector('[data-attachment-container]').appendChild(attachment);
321
401
  });
322
402
  }
323
- this.messagesContainerTarget.appendChild(element);
403
+
404
+ // Insert message before typing indicator if one exists
405
+ if (this.typingIndicatorVisible && this.hasTypingIndicatorTarget) {
406
+ this.messagesContainerTarget.insertBefore(element, this.typingIndicatorTarget);
407
+ } else {
408
+ this.messagesContainerTarget.appendChild(element);
409
+ }
324
410
  element.scrollIntoView({
325
411
  behavior: 'smooth'
326
412
  });
@@ -329,6 +415,7 @@ let _default = /*#__PURE__*/function (_Controller) {
329
415
  element: element.outerHTML
330
416
  });
331
417
  this.inputTarget.value = '';
418
+ this.resizeInput();
332
419
  this.files = [];
333
420
  this.attachmentInputTarget.value = '';
334
421
  this.attachmentContainerTarget.innerHTML = '';
@@ -351,6 +438,14 @@ let _default = /*#__PURE__*/function (_Controller) {
351
438
  this.conversationIdValue = data.conversation;
352
439
  this.webChatChannel.updateSubscriptionWith(this.conversationIdValue);
353
440
  }
441
+ if (this.typingIndicatorVisible) {
442
+ this.resetTypingIndicatorTimer();
443
+ } else {
444
+ clearTimeout(this.optimisticTypingTimeout);
445
+ this.optimisticTypingTimeout = setTimeout(() => {
446
+ this.showOptimisticTypingIndicator();
447
+ }, this.optimisticTypingIndicatorWaitValue);
448
+ }
354
449
  this.attachmentContainerTarget.style.display = '';
355
450
  }
356
451
  }, {
@@ -447,29 +542,16 @@ let _default = /*#__PURE__*/function (_Controller) {
447
542
  this.inputTarget.selectionStart = this.inputTarget.selectionEnd = start + emoji.length;
448
543
  this.inputTarget.focus();
449
544
  }
450
- }, {
451
- key: "setOfflineTimeout",
452
- value: function setOfflineTimeout() {
453
- clearTimeout(this.offlineTimeout);
454
- this.offlineTimeout = setTimeout(() => {
455
- this.onlineStatusTarget.style.display = 'none';
456
- }, this.fiveMinutes);
457
- }
458
545
  }, {
459
546
  key: "byteToMegabyte",
460
547
  value: function byteToMegabyte(bytes) {
461
548
  return Math.ceil(bytes / 1024 / 1024);
462
549
  }
463
- }, {
464
- key: "fiveMinutes",
465
- get: function () {
466
- return 300000;
467
- }
468
550
  }, {
469
551
  key: "middlewares",
470
552
  get: function () {
471
- return [(0, _dom.offset)(5), (0, _dom.shift)({
472
- padding: 24
553
+ return [(0, _dom.offset)(this.offsetValue), (0, _dom.shift)({
554
+ padding: this.paddingValue
473
555
  }), (0, _dom.flip)()];
474
556
  }
475
557
  }, {
@@ -514,7 +596,24 @@ _default.values = {
514
596
  fullScreenThreshold: {
515
597
  type: Number,
516
598
  default: 1024
517
- }
599
+ },
600
+ typingIndicatorKeepAlive: {
601
+ type: Number,
602
+ default: 30000
603
+ },
604
+ // 30 seconds
605
+ offset: {
606
+ type: Number,
607
+ default: 24
608
+ },
609
+ padding: {
610
+ type: Number,
611
+ default: 24
612
+ },
613
+ optimisticTypingIndicatorWait: {
614
+ type: Number,
615
+ default: 1000
616
+ } // 1 second
518
617
  };
519
618
  _default.classes = ['fadeOut'];
520
- _default.targets = ['trigger', 'popover', 'input', 'attachmentInput', 'attachmentButton', 'errorMessageContainer', 'attachmentTemplate', 'attachmentContainer', 'attachment', 'messageTemplate', 'messagesContainer', 'title', 'onlineStatus', 'attachmentImage', 'footer', 'toolbar', 'message', 'unreadCounter'];
619
+ _default.targets = ['trigger', 'popover', 'input', 'attachmentInput', 'attachmentButton', 'errorMessageContainer', 'attachmentTemplate', 'attachmentContainer', 'attachment', 'messageTemplate', 'messagesContainer', 'title', 'attachmentImage', 'footer', 'toolbar', 'message', 'unreadCounter', 'typingIndicator', 'typingIndicatorTemplate'];