@hellotext/hellotext 2.3.9 → 2.4.1

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 (39) hide show
  1. package/dist/hellotext.js +1 -1
  2. package/dist/webchat-emoji-en.js +1 -0
  3. package/dist/webchat-emoji-es.js +1 -0
  4. package/dist/webchat-emoji.js +1 -0
  5. package/index.d.ts +30 -4
  6. package/lib/api/webchats.cjs +20 -0
  7. package/lib/api/webchats.js +20 -0
  8. package/lib/controllers/mixins/usePopover.cjs +7 -2
  9. package/lib/controllers/mixins/usePopover.js +7 -2
  10. package/lib/controllers/webchat/emoji_picker_controller.cjs +49 -10
  11. package/lib/controllers/webchat/emoji_picker_controller.js +66 -8
  12. package/lib/controllers/webchat/useBehaviour.cjs +74 -0
  13. package/lib/controllers/webchat/useBehaviour.js +67 -0
  14. package/lib/controllers/webchat/useOpeningSequence.cjs +103 -0
  15. package/lib/controllers/webchat/useOpeningSequence.js +96 -0
  16. package/lib/controllers/webchat/useTeaser.cjs +163 -0
  17. package/lib/controllers/webchat/useTeaser.js +156 -0
  18. package/lib/controllers/webchat_controller.cjs +168 -22
  19. package/lib/controllers/webchat_controller.js +176 -24
  20. package/lib/core/configuration/webchat.cjs +117 -42
  21. package/lib/core/configuration/webchat.js +121 -43
  22. package/lib/hellotext.cjs +28 -4
  23. package/lib/hellotext.js +28 -1
  24. package/lib/models/business.cjs +2 -0
  25. package/lib/models/business.js +2 -0
  26. package/lib/models/webchat.cjs +25 -0
  27. package/lib/models/webchat.js +25 -0
  28. package/package.json +1 -1
  29. package/src/api/webchats.js +17 -0
  30. package/src/controllers/mixins/usePopover.js +4 -2
  31. package/src/controllers/webchat/emoji_picker_controller.js +51 -9
  32. package/src/controllers/webchat/useBehaviour.js +81 -0
  33. package/src/controllers/webchat/useOpeningSequence.js +127 -0
  34. package/src/controllers/webchat/useTeaser.js +192 -0
  35. package/src/controllers/webchat_controller.js +200 -23
  36. package/src/core/configuration/webchat.js +127 -43
  37. package/src/hellotext.js +32 -4
  38. package/src/models/business.js +2 -0
  39. package/src/models/webchat.js +28 -0
@@ -23,9 +23,11 @@ import WebchatMessagesAPI from '../api/webchat/messages';
23
23
  import WebchatChannel from '../channels/webchat_channel';
24
24
  import Hellotext from '../hellotext';
25
25
  import { Locale } from '../core';
26
- import { Webchat as WebchatConfiguration, behaviors } from '../core/configuration/webchat';
27
- import { LogoBuilder } from '../builders/logo_builder';
26
+ import { Webchat as WebchatConfiguration, modes } from '../core/configuration/webchat';
28
27
  import { usePopover } from './mixins/usePopover';
28
+ import { useBehaviour } from './webchat/useBehaviour';
29
+ import { useOpeningSequence } from './webchat/useOpeningSequence';
30
+ import { useTeaser } from './webchat/useTeaser';
29
31
  var _default = /*#__PURE__*/function (_Controller) {
30
32
  _inherits(_default, _Controller);
31
33
  var _super = _createSuper(_default);
@@ -39,6 +41,7 @@ var _default = /*#__PURE__*/function (_Controller) {
39
41
  this.messagesAPI = new WebchatMessagesAPI(this.idValue);
40
42
  this.webChatChannel = new WebchatChannel(this.idValue, Hellotext.session, this.conversationIdValue);
41
43
  this.files = [];
44
+ this.messageIds = new Set();
42
45
  this.onMessageReceived = this.onMessageReceived.bind(this);
43
46
  this.onMessageReaction = this.onMessageReaction.bind(this);
44
47
  this.onTypingStart = this.onTypingStart.bind(this);
@@ -50,30 +53,41 @@ var _default = /*#__PURE__*/function (_Controller) {
50
53
  }, {
51
54
  key: "connect",
52
55
  value: function connect() {
56
+ useBehaviour(this);
53
57
  usePopover(this);
54
- this.popoverTarget.classList.add(...WebchatConfiguration.classes);
55
- this.triggerTarget.classList.add(...WebchatConfiguration.triggerClasses);
58
+ useOpeningSequence(this);
59
+ useTeaser(this);
56
60
  this.setupFloatingUI({
57
61
  trigger: this.triggerTarget,
58
62
  popover: this.popoverTarget
59
63
  });
64
+ if (this.hasTeaserTarget) {
65
+ this.setupFloatingUI({
66
+ trigger: this.triggerTarget,
67
+ popover: this.teaserTarget,
68
+ strategy: 'absolute'
69
+ });
70
+ }
71
+ this.setupTeaser();
72
+ this.setupOpeningSequence();
60
73
  this.webChatChannel.onMessage(this.onMessageReceived);
61
74
  this.webChatChannel.onTypingStart(this.onTypingStart);
62
75
  this.webChatChannel.onReaction(this.onMessageReaction);
63
76
  this.messagesContainerTarget.addEventListener('scroll', this.onScroll);
64
- if (!Hellotext.business.features.white_label) {
65
- this.toolbarTarget.appendChild(LogoBuilder.build());
66
- }
67
77
  if (this.shouldOpenOnMount) {
68
78
  this.openValue = true;
69
79
  }
70
80
  Hellotext.eventEmitter.dispatch('webchat:mounted');
71
81
  this.broadcastChannel.addEventListener('message', this.onOutboundMessageSent);
82
+ this.scheduleBehaviourOpen();
72
83
  _get(_getPrototypeOf(_default.prototype), "connect", this).call(this);
73
84
  }
74
85
  }, {
75
86
  key: "disconnect",
76
87
  value: function disconnect() {
88
+ this.cancelBehaviourOpen();
89
+ this.teardownTeaser();
90
+ this.teardownOpeningSequence();
77
91
  this.broadcastChannel.removeEventListener('message', this.onOutboundMessageSent);
78
92
  this.messagesContainerTarget.removeEventListener('scroll', this.onScroll);
79
93
 
@@ -220,11 +234,12 @@ var _default = /*#__PURE__*/function (_Controller) {
220
234
  }
221
235
  if (attachments) {
222
236
  attachments.forEach(attachmentUrl => {
237
+ var _this$messageAttachme;
223
238
  var image = this.attachmentImageTarget.cloneNode(true);
224
239
  image.removeAttribute('data-hellotext--webchat-target');
225
240
  image.src = attachmentUrl;
226
241
  image.style.display = 'block';
227
- element.querySelector('[data-attachment-container]').appendChild(image);
242
+ (_this$messageAttachme = this.messageAttachmentsContainer(element)) === null || _this$messageAttachme === void 0 ? void 0 : _this$messageAttachme.appendChild(image);
228
243
  });
229
244
  }
230
245
  element.setAttribute('data-body', body);
@@ -244,7 +259,7 @@ var _default = /*#__PURE__*/function (_Controller) {
244
259
  }, {
245
260
  key: "onClickOutside",
246
261
  value: function onClickOutside(event) {
247
- if (WebchatConfiguration.behaviour === behaviors.POPOVER && this.openValue && event.target.nodeType && this.element.contains(event.target) === false) {
262
+ if (WebchatConfiguration.mode === modes.POPOVER && this.openValue && event.target.nodeType && this.element.contains(event.target) === false) {
248
263
  this.openValue = false;
249
264
  }
250
265
  }
@@ -259,7 +274,9 @@ var _default = /*#__PURE__*/function (_Controller) {
259
274
  }, {
260
275
  key: "onPopoverOpened",
261
276
  value: function onPopoverOpened() {
277
+ var _this$dismissTeaserFo;
262
278
  this.popoverTarget.classList.remove(...this.fadeOutClasses);
279
+ (_this$dismissTeaserFo = this.dismissTeaserForSession) === null || _this$dismissTeaserFo === void 0 ? void 0 : _this$dismissTeaserFo.call(this);
263
280
  if (!this.onMobile) {
264
281
  this.inputTarget.focus();
265
282
  }
@@ -274,6 +291,10 @@ var _default = /*#__PURE__*/function (_Controller) {
274
291
  }
275
292
  Hellotext.eventEmitter.dispatch('webchat:opened');
276
293
  localStorage.setItem("hellotext--webchat--".concat(this.idValue), 'opened');
294
+ if (this.messageTeaserValue) {
295
+ this.messageTeaserValue = null;
296
+ }
297
+ this.startOpeningSequence();
277
298
  if (this.unreadCounterTarget.style.display === 'none') return;
278
299
  this.unreadCounterTarget.style.display = 'none';
279
300
  this.unreadCounterTarget.innerText = '0';
@@ -312,11 +333,15 @@ var _default = /*#__PURE__*/function (_Controller) {
312
333
  }, {
313
334
  key: "onMessageReceived",
314
335
  value: function onMessageReceived(message) {
336
+ var _this$hideTeaser;
315
337
  var {
316
338
  id,
317
339
  body,
318
- attachments
340
+ attachments,
341
+ teaser
319
342
  } = message;
343
+ if (!this.claimMessageId(id)) return;
344
+ (_this$hideTeaser = this.hideTeaser) === null || _this$hideTeaser === void 0 ? void 0 : _this$hideTeaser.call(this);
320
345
  if (message.carousel) {
321
346
  return this.insertCarouselMessage(message);
322
347
  }
@@ -325,13 +350,15 @@ var _default = /*#__PURE__*/function (_Controller) {
325
350
  var element = this.messageTemplateTarget.cloneNode(true);
326
351
  element.style.display = 'flex';
327
352
  element.querySelector('[data-body]').innerHTML = div.innerHTML;
353
+ element.setAttribute('data-id', id);
328
354
  element.setAttribute('data-hellotext--webchat-target', 'message');
329
355
  if (attachments) {
330
356
  attachments.forEach(attachmentUrl => {
357
+ var _this$messageAttachme2;
331
358
  var image = this.attachmentImageTarget.cloneNode(true);
332
359
  image.src = attachmentUrl;
333
360
  image.style.display = 'block';
334
- element.querySelector('[data-attachment-container]').appendChild(image);
361
+ (_this$messageAttachme2 = this.messageAttachmentsContainer(element)) === null || _this$messageAttachme2 === void 0 ? void 0 : _this$messageAttachme2.appendChild(image);
335
362
  });
336
363
  }
337
364
  this.clearTypingIndicator();
@@ -342,13 +369,36 @@ var _default = /*#__PURE__*/function (_Controller) {
342
369
  element.scrollIntoView({
343
370
  behavior: 'smooth'
344
371
  });
372
+ this.updateMessageTeaser(teaser);
345
373
  if (this.openValue) {
346
374
  this.messagesAPI.markAsSeen(id);
347
375
  return;
348
376
  }
349
- this.unreadCounterTarget.style.display = 'flex';
350
- var unreadCount = (parseInt(this.unreadCounterTarget.innerText) || 0) + 1;
351
- this.unreadCounterTarget.innerText = unreadCount > 99 ? '99+' : unreadCount;
377
+ this.incrementUnreadCounter();
378
+ }
379
+
380
+ // TCP broadcasts may deliver the same incoming message twice before Stimulus
381
+ // has connected the appended message target. Claiming the id in memory closes
382
+ // that window, while the target check still drops messages rendered earlier.
383
+ }, {
384
+ key: "claimMessageId",
385
+ value: function claimMessageId(id) {
386
+ var messageTargets = this.messageTargets || [];
387
+ if (this.messageIds.has(id)) return false;
388
+ this.messageIds.add(id);
389
+ return !messageTargets.some(element => element.dataset.id === id);
390
+ }
391
+ }, {
392
+ key: "updateMessageTeaser",
393
+ value: function updateMessageTeaser(teaser) {
394
+ this.messageTeaserValue = teaser;
395
+ if (!this.messageTeaserValue || !this.hasTeaserTarget || !this.hasInboundMessageTeaserTarget || !this.hasInboundMessageTeaserBodyTarget) {
396
+ return;
397
+ }
398
+ this.teaserMessageTargets.forEach(teaserMessage => teaserMessage.classList.add('hidden'));
399
+ this.inboundMessageTeaserBodyTarget.innerHTML = this.messageTeaserValue;
400
+ this.inboundMessageTeaserTarget.classList.remove('hidden');
401
+ this.teaserTarget.classList.toggle('invisible', this.openValue);
352
402
  }
353
403
  }, {
354
404
  key: "insertCarouselMessage",
@@ -356,6 +406,8 @@ var _default = /*#__PURE__*/function (_Controller) {
356
406
  var _element$querySelecto;
357
407
  var html = message.html;
358
408
  var element = new DOMParser().parseFromString(html, 'text/html').body.firstElementChild;
409
+ element.setAttribute('data-id', message.id);
410
+ element.setAttribute('data-hellotext--webchat-target', 'message');
359
411
  this.clearTypingIndicator();
360
412
  this.messagesContainerTarget.appendChild(element);
361
413
  element.scrollIntoView({
@@ -364,13 +416,12 @@ var _default = /*#__PURE__*/function (_Controller) {
364
416
  Hellotext.eventEmitter.dispatch('webchat:message:received', _objectSpread(_objectSpread({}, message), {}, {
365
417
  body: ((_element$querySelecto = element.querySelector('[data-body]')) === null || _element$querySelecto === void 0 ? void 0 : _element$querySelecto.innerText) || ''
366
418
  }));
419
+ this.updateMessageTeaser(message.teaser);
367
420
  if (this.openValue) {
368
421
  this.messagesAPI.markAsSeen(message.id);
369
422
  return;
370
423
  }
371
- this.unreadCounterTarget.style.display = 'flex';
372
- var unreadCount = (parseInt(this.unreadCounterTarget.innerText) || 0) + 1;
373
- this.unreadCounterTarget.innerText = unreadCount > 99 ? '99+' : unreadCount;
424
+ this.incrementUnreadCounter();
374
425
  }
375
426
  }, {
376
427
  key: "resizeInput",
@@ -389,7 +440,7 @@ var _default = /*#__PURE__*/function (_Controller) {
389
440
  key: "sendQuickReplyMessage",
390
441
  value: function () {
391
442
  var _sendQuickReplyMessage = _asyncToGenerator(function* (_ref) {
392
- var _cardElement$querySel;
443
+ var _this$dismissTeaserFo2, _cardElement$querySel;
393
444
  var {
394
445
  detail: {
395
446
  id,
@@ -399,6 +450,7 @@ var _default = /*#__PURE__*/function (_Controller) {
399
450
  cardElement
400
451
  }
401
452
  } = _ref;
453
+ (_this$dismissTeaserFo2 = this.dismissTeaserForSession) === null || _this$dismissTeaserFo2 === void 0 ? void 0 : _this$dismissTeaserFo2.call(this);
402
454
  var formData = new FormData();
403
455
  formData.append('message[body]', body);
404
456
  formData.append('message[replied_to]', id);
@@ -406,13 +458,15 @@ var _default = /*#__PURE__*/function (_Controller) {
406
458
  formData.append('message[button]', buttonId);
407
459
  formData.append('session', Hellotext.session);
408
460
  formData.append('locale', Locale.toString());
461
+ this.appendOpeningSequenceMessageIds(formData);
409
462
  var element = this.buildMessageElement();
410
463
  var attachment = (_cardElement$querySel = cardElement.querySelector('img')) === null || _cardElement$querySel === void 0 ? void 0 : _cardElement$querySel.cloneNode(true);
411
464
  element.querySelector('[data-body]').innerText = body;
412
465
  if (attachment) {
466
+ var _this$messageAttachme3;
413
467
  attachment.removeAttribute('width');
414
468
  attachment.removeAttribute('height');
415
- element.querySelector('[data-attachment-container]').appendChild(attachment);
469
+ (_this$messageAttachme3 = this.messageAttachmentsContainer(element)) === null || _this$messageAttachme3 === void 0 ? void 0 : _this$messageAttachme3.appendChild(attachment);
416
470
  }
417
471
  if (this.typingIndicatorVisible && this.hasTypingIndicatorTarget) {
418
472
  this.messagesContainerTarget.insertBefore(element, this.typingIndicatorTarget);
@@ -441,6 +495,7 @@ var _default = /*#__PURE__*/function (_Controller) {
441
495
  target: element,
442
496
  detail: data.id
443
497
  });
498
+ this.clearRevealedOpeningSequenceMessageIds();
444
499
  var message = {
445
500
  id: data.id,
446
501
  body: body,
@@ -457,11 +512,87 @@ var _default = /*#__PURE__*/function (_Controller) {
457
512
  }
458
513
  return sendQuickReplyMessage;
459
514
  }()
515
+ }, {
516
+ key: "sendTeaserQuickReply",
517
+ value: function () {
518
+ var _sendTeaserQuickReply = _asyncToGenerator(function* (event) {
519
+ var _this$dismissTeaserFo3;
520
+ event.preventDefault();
521
+ event.stopPropagation();
522
+ var button = event.currentTarget;
523
+ var value = (button.dataset.value || '').trim();
524
+ var label = [button.dataset.text, button.textContent].map(text => (text || '').trim()).find(text => text.length > 0);
525
+ var text = value || label;
526
+ if (!text) return;
527
+ (_this$dismissTeaserFo3 = this.dismissTeaserForSession) === null || _this$dismissTeaserFo3 === void 0 ? void 0 : _this$dismissTeaserFo3.call(this);
528
+ this.show();
529
+ var buttonType = (button.dataset.type || '').trim() || 'quick_reply';
530
+ var formData = new FormData();
531
+ formData.append('message[body]', text);
532
+ formData.append('session', Hellotext.session);
533
+ formData.append('locale', Locale.toString());
534
+ this.appendOpeningSequenceMessageIds(formData);
535
+ var element = this.buildMessageElement();
536
+ element.querySelector('[data-body]').innerText = text;
537
+ if (this.typingIndicatorVisible && this.hasTypingIndicatorTarget) {
538
+ this.messagesContainerTarget.insertBefore(element, this.typingIndicatorTarget);
539
+ } else {
540
+ this.messagesContainerTarget.appendChild(element);
541
+ }
542
+ element.scrollIntoView({
543
+ behavior: 'smooth'
544
+ });
545
+ this.broadcastChannel.postMessage({
546
+ type: 'message:sent',
547
+ element: element.outerHTML
548
+ });
549
+ if (!this.typingIndicatorVisible) {
550
+ clearTimeout(this.optimisticTypingTimeout);
551
+ this.optimisticTypingTimeout = setTimeout(() => {
552
+ this.showOptimisticTypingIndicator();
553
+ }, this.optimisticTypingIndicatorWaitValue);
554
+ }
555
+ var response = yield this.messagesAPI.create(formData);
556
+ if (response.failed) {
557
+ clearTimeout(this.optimisticTypingTimeout);
558
+ this.broadcastChannel.postMessage({
559
+ type: 'message:failed',
560
+ id: element.id
561
+ });
562
+ return element.classList.add('failed');
563
+ }
564
+ var data = yield response.json();
565
+ element.setAttribute('data-id', data.id);
566
+ this.clearRevealedOpeningSequenceMessageIds();
567
+ Hellotext.eventEmitter.dispatch('webchat:message:sent', {
568
+ id: data.id,
569
+ body: text,
570
+ attachments: [],
571
+ type: 'quick_reply',
572
+ teaser: {
573
+ text: label || text,
574
+ value: value || text,
575
+ type: buttonType
576
+ }
577
+ });
578
+ if (data.conversation && data.conversation !== this.conversationIdValue) {
579
+ this.conversationIdValue = data.conversation;
580
+ this.webChatChannel.updateSubscriptionWith(this.conversationIdValue);
581
+ }
582
+ if (this.typingIndicatorVisible) {
583
+ this.resetTypingIndicatorTimer();
584
+ }
585
+ });
586
+ function sendTeaserQuickReply(_x2) {
587
+ return _sendTeaserQuickReply.apply(this, arguments);
588
+ }
589
+ return sendTeaserQuickReply;
590
+ }()
460
591
  }, {
461
592
  key: "sendMessage",
462
593
  value: function () {
463
594
  var _sendMessage = _asyncToGenerator(function* (e) {
464
- var formData = new FormData();
595
+ var _this$dismissTeaserFo4;
465
596
  var message = {
466
597
  body: this.inputTarget.value,
467
598
  attachments: this.files
@@ -472,6 +603,8 @@ var _default = /*#__PURE__*/function (_Controller) {
472
603
  }
473
604
  return;
474
605
  }
606
+ (_this$dismissTeaserFo4 = this.dismissTeaserForSession) === null || _this$dismissTeaserFo4 === void 0 ? void 0 : _this$dismissTeaserFo4.call(this);
607
+ var formData = new FormData();
475
608
  if (this.inputTarget.value.trim().length > 0) {
476
609
  formData.append('message[body]', this.inputTarget.value);
477
610
  } else {
@@ -482,6 +615,7 @@ var _default = /*#__PURE__*/function (_Controller) {
482
615
  });
483
616
  formData.append('session', Hellotext.session);
484
617
  formData.append('locale', Locale.toString());
618
+ this.appendOpeningSequenceMessageIds(formData);
485
619
  var element = this.buildMessageElement();
486
620
  if (this.inputTarget.value.trim().length > 0) {
487
621
  element.querySelector('[data-body]').innerText = this.inputTarget.value;
@@ -491,7 +625,8 @@ var _default = /*#__PURE__*/function (_Controller) {
491
625
  var attachments = this.attachmentContainerTarget.querySelectorAll('img');
492
626
  if (attachments.length > 0) {
493
627
  attachments.forEach(attachment => {
494
- element.querySelector('[data-attachment-container]').appendChild(attachment.cloneNode(true));
628
+ var _this$messageAttachme4;
629
+ (_this$messageAttachme4 = this.messageAttachmentsContainer(element)) === null || _this$messageAttachme4 === void 0 ? void 0 : _this$messageAttachme4.appendChild(attachment.cloneNode(true));
495
630
  });
496
631
  }
497
632
 
@@ -538,6 +673,7 @@ var _default = /*#__PURE__*/function (_Controller) {
538
673
  var data = yield response.json();
539
674
  element.setAttribute('data-id', data.id);
540
675
  message.id = data.id;
676
+ this.clearRevealedOpeningSequenceMessageIds();
541
677
  Hellotext.eventEmitter.dispatch('webchat:message:sent', message);
542
678
  if (data.conversation !== this.conversationIdValue) {
543
679
  this.conversationIdValue = data.conversation;
@@ -550,7 +686,7 @@ var _default = /*#__PURE__*/function (_Controller) {
550
686
  }
551
687
  this.attachmentContainerTarget.style.display = '';
552
688
  });
553
- function sendMessage(_x2) {
689
+ function sendMessage(_x3) {
554
690
  return _sendMessage.apply(this, arguments);
555
691
  }
556
692
  return sendMessage;
@@ -566,6 +702,18 @@ var _default = /*#__PURE__*/function (_Controller) {
566
702
  element.setAttribute('data-hellotext--webchat-target', 'message');
567
703
  return element;
568
704
  }
705
+ }, {
706
+ key: "messageAttachmentsContainer",
707
+ value: function messageAttachmentsContainer(element) {
708
+ return element.querySelector('[data-attachments-container], [data-attachment-container]');
709
+ }
710
+ }, {
711
+ key: "incrementUnreadCounter",
712
+ value: function incrementUnreadCounter() {
713
+ this.unreadCounterTarget.style.display = 'flex';
714
+ var unreadCount = (parseInt(this.unreadCounterTarget.innerText) || 0) + 1;
715
+ this.unreadCounterTarget.innerText = Math.min(unreadCount, 9);
716
+ }
569
717
  }, {
570
718
  key: "openAttachment",
571
719
  value: function openAttachment() {
@@ -732,8 +880,12 @@ _default.values = {
732
880
  optimisticTypingIndicatorWait: {
733
881
  type: Number,
734
882
  default: 1000
735
- } // 1 second
883
+ },
884
+ // 1 second,
885
+ teaser: Object,
886
+ messageTeaser: String,
887
+ behaviour: Object
736
888
  };
737
889
  _default.classes = ['fadeOut'];
738
- _default.targets = ['trigger', 'popover', 'input', 'attachmentInput', 'attachmentButton', 'errorMessageContainer', 'attachmentTemplate', 'attachmentContainer', 'attachment', 'messageTemplate', 'messagesContainer', 'title', 'attachmentImage', 'footer', 'toolbar', 'message', 'unreadCounter', 'typingIndicator', 'typingIndicatorTemplate'];
890
+ _default.targets = ['trigger', 'popover', 'input', 'attachmentInput', 'attachmentButton', 'errorMessageContainer', 'attachmentTemplate', 'attachmentContainer', 'attachment', 'messageTemplate', 'messagesContainer', 'title', 'attachmentImage', 'footer', 'toolbar', 'message', 'unreadCounter', 'typingIndicator', 'typingIndicatorTemplate', 'teaser', 'teaserMessage', 'inboundMessageTeaser', 'inboundMessageTeaserBody', 'openingSequence', 'openingSequenceMessage'];
739
891
  export { _default as default };
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.behaviors = exports.Webchat = void 0;
6
+ exports.modes = exports.Webchat = void 0;
7
7
  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
8
8
  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
9
  function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
@@ -39,13 +39,13 @@ const strategies = {
39
39
  };
40
40
 
41
41
  /**
42
- * @typedef {'modal' | 'popover'} Behaviour
42
+ * @typedef {'modal' | 'popover'} Mode
43
43
  */
44
44
 
45
45
  /**
46
- * @enum {Behaviour}
46
+ * @enum {Mode}
47
47
  */
48
- const behaviors = {
48
+ const modes = {
49
49
  MODAL: 'modal',
50
50
  POPOVER: 'popover'
51
51
  };
@@ -57,6 +57,20 @@ const behaviors = {
57
57
  * @property {string} typography - The typography style (e.g., font family).
58
58
  */
59
59
 
60
+ /**
61
+ * @typedef {Object} Appearance
62
+ * @property {Object} [header] - Header appearance overrides.
63
+ * @property {string} [header.name] - Business name shown in the webchat header.
64
+ * @property {Object} [launcher] - Launcher appearance overrides.
65
+ * @property {string} [launcher.iconUrl] - Image URL used for the launcher icon.
66
+ */
67
+
68
+ /**
69
+ * @typedef {Object} WhatsApp
70
+ * @property {string} [number] - WhatsApp number used by the handoff configuration.
71
+ * @property {boolean} [restrictToChannel] - Whether handoff should be restricted to the configured channel.
72
+ */
73
+
60
74
  /**
61
75
  * @class Webchat
62
76
  * @classdesc
@@ -64,13 +78,14 @@ const behaviors = {
64
78
  * @property {String} id - the id of the webchat.
65
79
  * @property {String} container - the container to append the webchat to, defaults to 'body'
66
80
  * @property {Placement} placement - the placement of the webchat within the container, defaults to "bottom-right".
67
- * @property {String} classes - additional classes to apply to the webchat popup.
68
- * @property {String} triggerClasses - additional classes to apply to the webchat popup trigger.
69
- * @property {Behaviour} behaviour - the behaviour of the webchat, defaults to 'popover'.
81
+ * @property {Mode} mode - how the webchat behaves while open, defaults to 'popover'.
82
+ * @property {Object} behaviour - runtime opening behaviour for the webchat.
70
83
  * @property {Style} style - the style of the webchat.
84
+ * @property {Appearance} appearance - appearance overrides.
85
+ * @property {WhatsApp} whatsapp - WhatsApp handoff overrides.
71
86
  * @property {Strategy} strategy - the strategy used to position the webchat. Defaults to 'absolute'
72
87
  */
73
- exports.behaviors = behaviors;
88
+ exports.modes = modes;
74
89
  let Webchat = /*#__PURE__*/function () {
75
90
  function Webchat() {
76
91
  _classCallCheck(this, Webchat);
@@ -94,36 +109,6 @@ let Webchat = /*#__PURE__*/function () {
94
109
  }
95
110
  this._placement = value;
96
111
  }
97
- }, {
98
- key: "classes",
99
- get: function () {
100
- if (typeof this._classes === 'string') {
101
- return this._classes.split(',').map(c => c.trim());
102
- } else {
103
- return this._classes;
104
- }
105
- },
106
- set: function (value) {
107
- if (!Array.isArray(value) && typeof value !== 'string') {
108
- throw new Error('classes must be an array or a string');
109
- }
110
- this._classes = value;
111
- }
112
- }, {
113
- key: "triggerClasses",
114
- get: function () {
115
- if (typeof this._triggerClasses === 'string') {
116
- return this._triggerClasses.split(',').map(c => c.trim());
117
- } else {
118
- return this._triggerClasses;
119
- }
120
- },
121
- set: function (value) {
122
- if (!Array.isArray(value) && typeof value !== 'string') {
123
- throw new Error('triggerClasses must be an array or a string');
124
- }
125
- this._triggerClasses = value;
126
- }
127
112
  }, {
128
113
  key: "id",
129
114
  get: function () {
@@ -159,17 +144,100 @@ let Webchat = /*#__PURE__*/function () {
159
144
  });
160
145
  this._style = value;
161
146
  }
147
+ }, {
148
+ key: "appearance",
149
+ get: function () {
150
+ return this._appearance;
151
+ },
152
+ set: function (value) {
153
+ if (!this.isPlainObject(value)) {
154
+ throw new Error('Appearance must be an object');
155
+ }
156
+ Object.entries(value).forEach(([key, nestedValue]) => {
157
+ if (!['header', 'launcher'].includes(key)) {
158
+ throw new Error(`Invalid appearance property: ${key}`);
159
+ }
160
+ if (!this.isPlainObject(nestedValue)) {
161
+ throw new Error(`Appearance ${key} must be an object`);
162
+ }
163
+ Object.entries(nestedValue).forEach(([nestedKey, propertyValue]) => {
164
+ if (key === 'header' && nestedKey !== 'name') {
165
+ throw new Error(`Invalid appearance header property: ${nestedKey}`);
166
+ }
167
+ if (key === 'launcher' && nestedKey !== 'iconUrl') {
168
+ throw new Error(`Invalid appearance launcher property: ${nestedKey}`);
169
+ }
170
+ if (propertyValue == null) {
171
+ return;
172
+ }
173
+ if (typeof propertyValue !== 'string') {
174
+ throw new Error(`Invalid appearance ${key}.${nestedKey} value: ${propertyValue}`);
175
+ }
176
+ });
177
+ });
178
+ this._appearance = value;
179
+ }
180
+ }, {
181
+ key: "whatsapp",
182
+ get: function () {
183
+ return this._whatsapp;
184
+ },
185
+ set: function (value) {
186
+ if (!this.isPlainObject(value)) {
187
+ throw new Error('WhatsApp must be an object');
188
+ }
189
+ Object.entries(value).forEach(([key, nestedValue]) => {
190
+ if (!['number', 'restrictToChannel'].includes(key)) {
191
+ throw new Error(`Invalid WhatsApp property: ${key}`);
192
+ }
193
+ if (nestedValue == null) {
194
+ return;
195
+ }
196
+ if (key === 'number' && typeof nestedValue !== 'string') {
197
+ throw new Error(`Invalid WhatsApp number value: ${nestedValue}`);
198
+ }
199
+ if (key === 'restrictToChannel' && typeof nestedValue !== 'boolean') {
200
+ throw new Error(`Invalid WhatsApp restrictToChannel value: ${nestedValue}`);
201
+ }
202
+ });
203
+ this._whatsapp = value;
204
+ }
205
+ }, {
206
+ key: "mode",
207
+ get: function () {
208
+ return this._mode;
209
+ },
210
+ set: function (value) {
211
+ if (!Object.values(modes).includes(value)) {
212
+ throw new Error(`Invalid mode value: ${value}`);
213
+ }
214
+ this._mode = value;
215
+ }
162
216
  }, {
163
217
  key: "behaviour",
164
218
  get: function () {
165
219
  return this._behaviour;
166
220
  },
167
221
  set: function (value) {
168
- if (!Object.values(behaviors).includes(value)) {
222
+ if (value == null) {
223
+ this._behaviour = value;
224
+ return;
225
+ }
226
+ if (typeof value !== 'object' || Array.isArray(value)) {
169
227
  throw new Error(`Invalid behaviour value: ${value}`);
170
228
  }
171
229
  this._behaviour = value;
172
230
  }
231
+ }, {
232
+ key: "hasBehaviourOverride",
233
+ get: function () {
234
+ return this._hasBehaviourOverride;
235
+ }
236
+ }, {
237
+ key: "behaviourOverride",
238
+ set: function (value) {
239
+ this._hasBehaviourOverride = !!value;
240
+ }
173
241
  }, {
174
242
  key: "strategy",
175
243
  get: function () {
@@ -199,6 +267,11 @@ let Webchat = /*#__PURE__*/function () {
199
267
  value: function isHexOrRgba(value) {
200
268
  return /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(value) || /^rgba?\(\s*\d{1,3},\s*\d{1,3},\s*\d{1,3},?\s*(0|1|0?\.\d+)?\s*\)$/.test(value);
201
269
  }
270
+ }, {
271
+ key: "isPlainObject",
272
+ value: function isPlainObject(value) {
273
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
274
+ }
202
275
  }]);
203
276
  return Webchat;
204
277
  }();
@@ -206,8 +279,10 @@ exports.Webchat = Webchat;
206
279
  Webchat._id = void 0;
207
280
  Webchat._container = 'body';
208
281
  Webchat._placement = 'bottom-right';
209
- Webchat._classes = [];
210
- Webchat._triggerClasses = [];
211
282
  Webchat._style = {};
212
- Webchat._behaviour = behaviors.POPOVER;
283
+ Webchat._appearance = {};
284
+ Webchat._whatsapp = {};
285
+ Webchat._mode = modes.POPOVER;
286
+ Webchat._behaviour = null;
287
+ Webchat._hasBehaviourOverride = false;
213
288
  Webchat._strategy = null;