@buni.ai/chatbot-angular 1.0.24 → 1.0.26

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.
package/dist/index.js CHANGED
@@ -60,6 +60,31 @@ class BuniChatWidget {
60
60
  this.chatTargetOrigin = null;
61
61
  this.handshakeComplete = false;
62
62
  this.outboundMessageQueue = [];
63
+ this.displayMode = "hidden";
64
+ this.serverBehavior = {};
65
+ }
66
+ isMinimalModeEnabled() {
67
+ var _a, _b;
68
+ if (typeof ((_b = (_a = this.options) === null || _a === void 0 ? void 0 : _a.config) === null || _b === void 0 ? void 0 : _b.enableMinimalMode) === "boolean") {
69
+ return this.options.config.enableMinimalMode;
70
+ }
71
+ return Boolean(this.serverBehavior.enableMinimalMode);
72
+ }
73
+ syncServerBehaviorFromData(data) {
74
+ if (!data || typeof data !== "object") {
75
+ return;
76
+ }
77
+ const behaviorCandidate = data.behavior && typeof data.behavior === "object"
78
+ ? data.behavior
79
+ : data;
80
+ if (typeof behaviorCandidate.enableMinimalMode === "boolean") {
81
+ this.serverBehavior.enableMinimalMode = behaviorCandidate.enableMinimalMode;
82
+ }
83
+ if (behaviorCandidate.defaultMode === "full" ||
84
+ behaviorCandidate.defaultMode === "minimal" ||
85
+ behaviorCandidate.defaultMode === "hidden") {
86
+ this.serverBehavior.defaultMode = behaviorCandidate.defaultMode;
87
+ }
63
88
  }
64
89
  async initialize(options) {
65
90
  this.options = options;
@@ -223,6 +248,15 @@ class BuniChatWidget {
223
248
  params.set("startButtonText", config.startButtonText);
224
249
  if (config.preChatFormFields)
225
250
  params.set("preChatFormFields", JSON.stringify(config.preChatFormFields));
251
+ if (config.enableMinimalMode !== undefined) {
252
+ params.set("enableMinimalMode", String(config.enableMinimalMode));
253
+ }
254
+ if (config.defaultMode) {
255
+ params.set("defaultMode", config.defaultMode);
256
+ }
257
+ if (config.autoMessages && Array.isArray(config.autoMessages)) {
258
+ params.set("autoMessages", JSON.stringify(config.autoMessages));
259
+ }
226
260
  chatIframe.src = `${this.getBaseUrl()}/embed/chat?${params.toString()}`;
227
261
  // Chat iframe styling - initially hidden
228
262
  chatIframe.style.cssText = `
@@ -263,13 +297,15 @@ class BuniChatWidget {
263
297
  this.triggerIframe = triggerIframe;
264
298
  this.chatIframe = chatIframe;
265
299
  this.state.isMinimized = true;
300
+ this.state.displayMode = "hidden";
301
+ this.displayMode = "hidden";
266
302
  this.state.isLoaded = true;
267
303
  resolve();
268
304
  };
269
305
  };
270
306
  // Listen for trigger and connection events
271
307
  window.addEventListener("message", (event) => {
272
- var _a, _b;
308
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
273
309
  const payload = event.data;
274
310
  if (!payload || typeof payload !== "object")
275
311
  return;
@@ -280,20 +316,62 @@ class BuniChatWidget {
280
316
  // Check if message is from chat iframe
281
317
  if (event.source === ((_a = this.chatIframe) === null || _a === void 0 ? void 0 : _a.contentWindow) &&
282
318
  event.origin === this.getBaseUrl()) {
283
- // Connection is ready, show the trigger button
284
- if (container && !config.hideDefaultTrigger) {
319
+ this.syncServerBehaviorFromData(payload.data);
320
+ const effectiveDefaultMode = (_d = (_c = (_b = this.options.config) === null || _b === void 0 ? void 0 : _b.defaultMode) !== null && _c !== void 0 ? _c : this.serverBehavior.defaultMode) !== null && _d !== void 0 ? _d : "full";
321
+ const effectiveMinimalEnabled = this.isMinimalModeEnabled();
322
+ if (effectiveMinimalEnabled && effectiveDefaultMode === "minimal") {
323
+ // Auto-open in minimal card mode
324
+ void this.openChatInMinimalMode();
325
+ }
326
+ else if ((_e = this.options.config) === null || _e === void 0 ? void 0 : _e.autoOpen) {
327
+ void this.openChat();
328
+ }
329
+ else if (container && !config.hideDefaultTrigger) {
330
+ // Show the trigger button
285
331
  container.style.display = "block";
286
332
  }
287
333
  // Emit connection_ready event for consumers
288
- this.emit("connection_ready", { timestamp: Date.now() });
334
+ this.emit("connection_ready", {
335
+ timestamp: Date.now(),
336
+ behavior: (_f = payload.data) === null || _f === void 0 ? void 0 : _f.behavior,
337
+ });
289
338
  if (this.options.onConnectionReady &&
290
339
  typeof this.options.onConnectionReady === "function") {
291
- this.options.onConnectionReady({ timestamp: Date.now() });
340
+ this.options.onConnectionReady({
341
+ timestamp: Date.now(),
342
+ behavior: (_g = payload.data) === null || _g === void 0 ? void 0 : _g.behavior,
343
+ });
344
+ }
345
+ }
346
+ break;
347
+ case "chatbot:close":
348
+ if (event.source === ((_h = this.chatIframe) === null || _h === void 0 ? void 0 : _h.contentWindow) &&
349
+ event.origin === this.getBaseUrl()) {
350
+ this.closeChat();
351
+ this.displayMode = "hidden";
352
+ this.state.displayMode = "hidden";
353
+ }
354
+ break;
355
+ case "chatbot:minimize":
356
+ if (event.source === ((_j = this.chatIframe) === null || _j === void 0 ? void 0 : _j.contentWindow) &&
357
+ event.origin === this.getBaseUrl()) {
358
+ if (this.isMinimalModeEnabled()) {
359
+ if (!this.state.isOpen) {
360
+ void this.openChat();
361
+ }
362
+ this.postMessageToWidget("minimize");
363
+ this.displayMode = "minimal";
364
+ this.state.displayMode = "minimal";
365
+ }
366
+ else {
367
+ this.closeChat();
368
+ this.displayMode = "hidden";
369
+ this.state.displayMode = "hidden";
292
370
  }
293
371
  }
294
372
  break;
295
373
  case "trigger_clicked":
296
- if (event.source === ((_b = this.triggerIframe) === null || _b === void 0 ? void 0 : _b.contentWindow) &&
374
+ if (event.source === ((_k = this.triggerIframe) === null || _k === void 0 ? void 0 : _k.contentWindow) &&
297
375
  event.origin === window.location.origin) {
298
376
  this.openChat();
299
377
  }
@@ -303,13 +381,11 @@ class BuniChatWidget {
303
381
  // Trigger the load event
304
382
  // if by 10 seconds the ready message is not received, we want to manually, set the container to visible
305
383
  setTimeout(() => {
306
- if (!this.state.isLoaded) {
307
- if (container &&
308
- !config.hideDefaultTrigger &&
309
- container.style.display === "none" &&
310
- this.state.isOpen === false) {
311
- container.style.display = "block";
312
- }
384
+ if (container &&
385
+ !config.hideDefaultTrigger &&
386
+ container.style.display === "none" &&
387
+ this.state.isOpen === false) {
388
+ container.style.display = "block";
313
389
  }
314
390
  }, 10000);
315
391
  triggerIframe.src = "about:blank";
@@ -435,11 +511,65 @@ class BuniChatWidget {
435
511
  </body>
436
512
  </html>`;
437
513
  }
514
+ async openChatInMinimalMode() {
515
+ if (!this.chatIframe || !this.widgetElement || !this.triggerIframe)
516
+ return;
517
+ const config = this.options.config || {};
518
+ const isMobile = window.innerWidth <= 768;
519
+ const isTablet = window.innerWidth > 768 && window.innerWidth <= 1024;
520
+ const ensureUnits = (value, defaultValue) => {
521
+ if (!value)
522
+ return defaultValue;
523
+ const str = String(value);
524
+ if (str.match(/^[\d.]+\s*(px|em|rem|%|vh|vw)$/))
525
+ return str;
526
+ if (str.match(/^[\d.]+$/))
527
+ return `${str}px`;
528
+ return str;
529
+ };
530
+ const widthValue = ensureUnits(config.width, "350px");
531
+ const heightValue = ensureUnits(config.height, "650px");
532
+ const chatWidth = isMobile
533
+ ? "100vw"
534
+ : isTablet
535
+ ? "min(calc(100vw - 3rem), 370px)"
536
+ : widthValue;
537
+ const chatHeight = isMobile
538
+ ? "100vh"
539
+ : isTablet
540
+ ? "min(calc(100vh - 3rem), 620px)"
541
+ : heightValue;
542
+ // Size container to full chat dimensions initially (iframe needs space to render)
543
+ this.widgetElement.style.cssText = `
544
+ position: fixed;
545
+ pointer-events: none;
546
+ z-index: 999999;
547
+ width: ${chatWidth};
548
+ height: ${chatHeight};
549
+ ${isMobile ? "max-width: 100vw; max-height: 100vh;" : ""}
550
+ transition: width 0.3s ease, height 0.3s ease, border-radius 0.3s ease;
551
+ ${this.getPositionStyles(config.position || "bottom-right", false)}
552
+ display: block;
553
+ overflow: visible;
554
+ box-sizing: border-box;
555
+ `;
556
+ // Hide trigger, show chat iframe
557
+ this.triggerIframe.style.display = "none";
558
+ this.chatIframe.style.display = "block";
559
+ this.chatIframe.style.visibility = "visible";
560
+ this.state.isMinimized = false;
561
+ this.state.isOpen = true;
562
+ this.displayMode = "minimal";
563
+ this.state.displayMode = "minimal";
564
+ // Ask the iframe to enter minimal mode; it will reply with "minimized" when ready
565
+ this.postMessageToWidget("minimize");
566
+ this.emit("minimized", { timestamp: Date.now() });
567
+ }
438
568
  async openChat() {
439
569
  if (!this.chatIframe || !this.widgetElement || !this.triggerIframe)
440
570
  return;
441
- if (this.state.isOpen)
442
- return; // Already open
571
+ if (this.state.isOpen && this.displayMode !== "minimal")
572
+ return; // Already open in full mode
443
573
  const config = this.options.config || {};
444
574
  const isMobile = window.innerWidth <= 768;
445
575
  const isTablet = window.innerWidth > 768 && window.innerWidth <= 1024;
@@ -486,6 +616,8 @@ class BuniChatWidget {
486
616
  this.chatIframe.style.visibility = "visible";
487
617
  this.state.isMinimized = false;
488
618
  this.state.isOpen = true;
619
+ this.displayMode = "full";
620
+ this.state.displayMode = "full";
489
621
  this.emit("maximized", { timestamp: Date.now() });
490
622
  }
491
623
  closeChat() {
@@ -518,6 +650,8 @@ class BuniChatWidget {
518
650
  this.triggerIframe.style.display = "block";
519
651
  this.state.isMinimized = true;
520
652
  this.state.isOpen = false;
653
+ this.displayMode = "hidden";
654
+ this.state.displayMode = "hidden";
521
655
  this.emit("minimized", { timestamp: Date.now() });
522
656
  }
523
657
  getPositionStyles(position, isMinimized = false) {
@@ -609,8 +743,30 @@ class BuniChatWidget {
609
743
  }
610
744
  break;
611
745
  case "minimized":
612
- // User clicked minimize in chat - close chat and show trigger
613
- this.closeChat();
746
+ this.syncServerBehaviorFromData(data);
747
+ if (this.isMinimalModeEnabled()) {
748
+ if (!this.state.isOpen) {
749
+ void this.openChat();
750
+ }
751
+ this.displayMode = "minimal";
752
+ this.state.displayMode = "minimal";
753
+ // Shrink container to actual minimal card size
754
+ if (this.widgetElement && this.chatIframe) {
755
+ const isMobile = window.innerWidth <= 768;
756
+ if (!isMobile) {
757
+ this.widgetElement.style.width =
758
+ "min(calc(100vw - 1.5rem), 390px)";
759
+ this.widgetElement.style.height = "auto";
760
+ this.widgetElement.style.overflow = "visible";
761
+ this.chatIframe.style.height = "520px";
762
+ this.chatIframe.style.width = "100%";
763
+ }
764
+ }
765
+ }
766
+ else {
767
+ // Backward-compatible behavior.
768
+ this.closeChat();
769
+ }
614
770
  break;
615
771
  case "new_unread_message":
616
772
  // Update unread count in trigger
@@ -745,10 +901,21 @@ class BuniChatWidget {
745
901
  }
746
902
  }
747
903
  minimize() {
904
+ if (this.isMinimalModeEnabled()) {
905
+ if (!this.state.isOpen) {
906
+ void this.openChat();
907
+ }
908
+ this.postMessageToWidget("minimize");
909
+ this.displayMode = "minimal";
910
+ this.state.displayMode = "minimal";
911
+ return;
912
+ }
748
913
  this.closeChat();
749
914
  }
750
915
  maximize() {
751
- this.openChat();
916
+ void this.openChat();
917
+ this.displayMode = "full";
918
+ this.state.displayMode = "full";
752
919
  }
753
920
  setCustomerData(data) {
754
921
  this.customerData = { ...this.customerData, ...data };
@@ -789,6 +956,8 @@ class BuniChatWidget {
789
956
  }
790
957
  close() {
791
958
  this.closeChat();
959
+ this.displayMode = "hidden";
960
+ this.state.displayMode = "hidden";
792
961
  }
793
962
  on(event, callback) {
794
963
  if (!this.eventListeners.has(event)) {
@@ -824,7 +993,10 @@ class BuniChatWidget {
824
993
  }
825
994
  }
826
995
  getState() {
827
- return { ...this.state };
996
+ return {
997
+ ...this.state,
998
+ displayMode: this.displayMode,
999
+ };
828
1000
  }
829
1001
  isReady() {
830
1002
  return this.state.isLoaded;