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