@hellotext/hellotext 2.3.9 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 +165 -22
  19. package/lib/controllers/webchat_controller.js +173 -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 +187 -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,33 @@ 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) {
396
+ this.teaserTarget.innerHTML = this.messageTeaserValue;
397
+ this.teaserTarget.classList.toggle('invisible', this.openValue);
398
+ }
352
399
  }
353
400
  }, {
354
401
  key: "insertCarouselMessage",
@@ -356,6 +403,8 @@ var _default = /*#__PURE__*/function (_Controller) {
356
403
  var _element$querySelecto;
357
404
  var html = message.html;
358
405
  var element = new DOMParser().parseFromString(html, 'text/html').body.firstElementChild;
406
+ element.setAttribute('data-id', message.id);
407
+ element.setAttribute('data-hellotext--webchat-target', 'message');
359
408
  this.clearTypingIndicator();
360
409
  this.messagesContainerTarget.appendChild(element);
361
410
  element.scrollIntoView({
@@ -364,13 +413,12 @@ var _default = /*#__PURE__*/function (_Controller) {
364
413
  Hellotext.eventEmitter.dispatch('webchat:message:received', _objectSpread(_objectSpread({}, message), {}, {
365
414
  body: ((_element$querySelecto = element.querySelector('[data-body]')) === null || _element$querySelecto === void 0 ? void 0 : _element$querySelecto.innerText) || ''
366
415
  }));
416
+ this.updateMessageTeaser(message.teaser);
367
417
  if (this.openValue) {
368
418
  this.messagesAPI.markAsSeen(message.id);
369
419
  return;
370
420
  }
371
- this.unreadCounterTarget.style.display = 'flex';
372
- var unreadCount = (parseInt(this.unreadCounterTarget.innerText) || 0) + 1;
373
- this.unreadCounterTarget.innerText = unreadCount > 99 ? '99+' : unreadCount;
421
+ this.incrementUnreadCounter();
374
422
  }
375
423
  }, {
376
424
  key: "resizeInput",
@@ -389,7 +437,7 @@ var _default = /*#__PURE__*/function (_Controller) {
389
437
  key: "sendQuickReplyMessage",
390
438
  value: function () {
391
439
  var _sendQuickReplyMessage = _asyncToGenerator(function* (_ref) {
392
- var _cardElement$querySel;
440
+ var _this$dismissTeaserFo2, _cardElement$querySel;
393
441
  var {
394
442
  detail: {
395
443
  id,
@@ -399,6 +447,7 @@ var _default = /*#__PURE__*/function (_Controller) {
399
447
  cardElement
400
448
  }
401
449
  } = _ref;
450
+ (_this$dismissTeaserFo2 = this.dismissTeaserForSession) === null || _this$dismissTeaserFo2 === void 0 ? void 0 : _this$dismissTeaserFo2.call(this);
402
451
  var formData = new FormData();
403
452
  formData.append('message[body]', body);
404
453
  formData.append('message[replied_to]', id);
@@ -406,13 +455,15 @@ var _default = /*#__PURE__*/function (_Controller) {
406
455
  formData.append('message[button]', buttonId);
407
456
  formData.append('session', Hellotext.session);
408
457
  formData.append('locale', Locale.toString());
458
+ this.appendOpeningSequenceMessageIds(formData);
409
459
  var element = this.buildMessageElement();
410
460
  var attachment = (_cardElement$querySel = cardElement.querySelector('img')) === null || _cardElement$querySel === void 0 ? void 0 : _cardElement$querySel.cloneNode(true);
411
461
  element.querySelector('[data-body]').innerText = body;
412
462
  if (attachment) {
463
+ var _this$messageAttachme3;
413
464
  attachment.removeAttribute('width');
414
465
  attachment.removeAttribute('height');
415
- element.querySelector('[data-attachment-container]').appendChild(attachment);
466
+ (_this$messageAttachme3 = this.messageAttachmentsContainer(element)) === null || _this$messageAttachme3 === void 0 ? void 0 : _this$messageAttachme3.appendChild(attachment);
416
467
  }
417
468
  if (this.typingIndicatorVisible && this.hasTypingIndicatorTarget) {
418
469
  this.messagesContainerTarget.insertBefore(element, this.typingIndicatorTarget);
@@ -441,6 +492,7 @@ var _default = /*#__PURE__*/function (_Controller) {
441
492
  target: element,
442
493
  detail: data.id
443
494
  });
495
+ this.clearRevealedOpeningSequenceMessageIds();
444
496
  var message = {
445
497
  id: data.id,
446
498
  body: body,
@@ -457,11 +509,87 @@ var _default = /*#__PURE__*/function (_Controller) {
457
509
  }
458
510
  return sendQuickReplyMessage;
459
511
  }()
512
+ }, {
513
+ key: "sendTeaserQuickReply",
514
+ value: function () {
515
+ var _sendTeaserQuickReply = _asyncToGenerator(function* (event) {
516
+ var _this$dismissTeaserFo3;
517
+ event.preventDefault();
518
+ event.stopPropagation();
519
+ var button = event.currentTarget;
520
+ var value = (button.dataset.value || '').trim();
521
+ var label = [button.dataset.text, button.textContent].map(text => (text || '').trim()).find(text => text.length > 0);
522
+ var text = value || label;
523
+ if (!text) return;
524
+ (_this$dismissTeaserFo3 = this.dismissTeaserForSession) === null || _this$dismissTeaserFo3 === void 0 ? void 0 : _this$dismissTeaserFo3.call(this);
525
+ this.show();
526
+ var buttonType = (button.dataset.type || '').trim() || 'quick_reply';
527
+ var formData = new FormData();
528
+ formData.append('message[body]', text);
529
+ formData.append('session', Hellotext.session);
530
+ formData.append('locale', Locale.toString());
531
+ this.appendOpeningSequenceMessageIds(formData);
532
+ var element = this.buildMessageElement();
533
+ element.querySelector('[data-body]').innerText = text;
534
+ if (this.typingIndicatorVisible && this.hasTypingIndicatorTarget) {
535
+ this.messagesContainerTarget.insertBefore(element, this.typingIndicatorTarget);
536
+ } else {
537
+ this.messagesContainerTarget.appendChild(element);
538
+ }
539
+ element.scrollIntoView({
540
+ behavior: 'smooth'
541
+ });
542
+ this.broadcastChannel.postMessage({
543
+ type: 'message:sent',
544
+ element: element.outerHTML
545
+ });
546
+ if (!this.typingIndicatorVisible) {
547
+ clearTimeout(this.optimisticTypingTimeout);
548
+ this.optimisticTypingTimeout = setTimeout(() => {
549
+ this.showOptimisticTypingIndicator();
550
+ }, this.optimisticTypingIndicatorWaitValue);
551
+ }
552
+ var response = yield this.messagesAPI.create(formData);
553
+ if (response.failed) {
554
+ clearTimeout(this.optimisticTypingTimeout);
555
+ this.broadcastChannel.postMessage({
556
+ type: 'message:failed',
557
+ id: element.id
558
+ });
559
+ return element.classList.add('failed');
560
+ }
561
+ var data = yield response.json();
562
+ element.setAttribute('data-id', data.id);
563
+ this.clearRevealedOpeningSequenceMessageIds();
564
+ Hellotext.eventEmitter.dispatch('webchat:message:sent', {
565
+ id: data.id,
566
+ body: text,
567
+ attachments: [],
568
+ type: 'quick_reply',
569
+ teaser: {
570
+ text: label || text,
571
+ value: value || text,
572
+ type: buttonType
573
+ }
574
+ });
575
+ if (data.conversation && data.conversation !== this.conversationIdValue) {
576
+ this.conversationIdValue = data.conversation;
577
+ this.webChatChannel.updateSubscriptionWith(this.conversationIdValue);
578
+ }
579
+ if (this.typingIndicatorVisible) {
580
+ this.resetTypingIndicatorTimer();
581
+ }
582
+ });
583
+ function sendTeaserQuickReply(_x2) {
584
+ return _sendTeaserQuickReply.apply(this, arguments);
585
+ }
586
+ return sendTeaserQuickReply;
587
+ }()
460
588
  }, {
461
589
  key: "sendMessage",
462
590
  value: function () {
463
591
  var _sendMessage = _asyncToGenerator(function* (e) {
464
- var formData = new FormData();
592
+ var _this$dismissTeaserFo4;
465
593
  var message = {
466
594
  body: this.inputTarget.value,
467
595
  attachments: this.files
@@ -472,6 +600,8 @@ var _default = /*#__PURE__*/function (_Controller) {
472
600
  }
473
601
  return;
474
602
  }
603
+ (_this$dismissTeaserFo4 = this.dismissTeaserForSession) === null || _this$dismissTeaserFo4 === void 0 ? void 0 : _this$dismissTeaserFo4.call(this);
604
+ var formData = new FormData();
475
605
  if (this.inputTarget.value.trim().length > 0) {
476
606
  formData.append('message[body]', this.inputTarget.value);
477
607
  } else {
@@ -482,6 +612,7 @@ var _default = /*#__PURE__*/function (_Controller) {
482
612
  });
483
613
  formData.append('session', Hellotext.session);
484
614
  formData.append('locale', Locale.toString());
615
+ this.appendOpeningSequenceMessageIds(formData);
485
616
  var element = this.buildMessageElement();
486
617
  if (this.inputTarget.value.trim().length > 0) {
487
618
  element.querySelector('[data-body]').innerText = this.inputTarget.value;
@@ -491,7 +622,8 @@ var _default = /*#__PURE__*/function (_Controller) {
491
622
  var attachments = this.attachmentContainerTarget.querySelectorAll('img');
492
623
  if (attachments.length > 0) {
493
624
  attachments.forEach(attachment => {
494
- element.querySelector('[data-attachment-container]').appendChild(attachment.cloneNode(true));
625
+ var _this$messageAttachme4;
626
+ (_this$messageAttachme4 = this.messageAttachmentsContainer(element)) === null || _this$messageAttachme4 === void 0 ? void 0 : _this$messageAttachme4.appendChild(attachment.cloneNode(true));
495
627
  });
496
628
  }
497
629
 
@@ -538,6 +670,7 @@ var _default = /*#__PURE__*/function (_Controller) {
538
670
  var data = yield response.json();
539
671
  element.setAttribute('data-id', data.id);
540
672
  message.id = data.id;
673
+ this.clearRevealedOpeningSequenceMessageIds();
541
674
  Hellotext.eventEmitter.dispatch('webchat:message:sent', message);
542
675
  if (data.conversation !== this.conversationIdValue) {
543
676
  this.conversationIdValue = data.conversation;
@@ -550,7 +683,7 @@ var _default = /*#__PURE__*/function (_Controller) {
550
683
  }
551
684
  this.attachmentContainerTarget.style.display = '';
552
685
  });
553
- function sendMessage(_x2) {
686
+ function sendMessage(_x3) {
554
687
  return _sendMessage.apply(this, arguments);
555
688
  }
556
689
  return sendMessage;
@@ -566,6 +699,18 @@ var _default = /*#__PURE__*/function (_Controller) {
566
699
  element.setAttribute('data-hellotext--webchat-target', 'message');
567
700
  return element;
568
701
  }
702
+ }, {
703
+ key: "messageAttachmentsContainer",
704
+ value: function messageAttachmentsContainer(element) {
705
+ return element.querySelector('[data-attachments-container], [data-attachment-container]');
706
+ }
707
+ }, {
708
+ key: "incrementUnreadCounter",
709
+ value: function incrementUnreadCounter() {
710
+ this.unreadCounterTarget.style.display = 'flex';
711
+ var unreadCount = (parseInt(this.unreadCounterTarget.innerText) || 0) + 1;
712
+ this.unreadCounterTarget.innerText = Math.min(unreadCount, 9);
713
+ }
569
714
  }, {
570
715
  key: "openAttachment",
571
716
  value: function openAttachment() {
@@ -732,8 +877,12 @@ _default.values = {
732
877
  optimisticTypingIndicatorWait: {
733
878
  type: Number,
734
879
  default: 1000
735
- } // 1 second
880
+ },
881
+ // 1 second,
882
+ teaser: Object,
883
+ messageTeaser: String,
884
+ behaviour: Object
736
885
  };
737
886
  _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'];
887
+ _default.targets = ['trigger', 'popover', 'input', 'attachmentInput', 'attachmentButton', 'errorMessageContainer', 'attachmentTemplate', 'attachmentContainer', 'attachment', 'messageTemplate', 'messagesContainer', 'title', 'attachmentImage', 'footer', 'toolbar', 'message', 'unreadCounter', 'typingIndicator', 'typingIndicatorTemplate', 'teaser', 'openingSequence', 'openingSequenceMessage'];
739
888
  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;