embeddedaichatux 2.2.0 → 2.2.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 (2) hide show
  1. package/EmbeddedChat.js +167 -140
  2. package/package.json +1 -1
package/EmbeddedChat.js CHANGED
@@ -13,16 +13,17 @@
13
13
  this.options = options || {};
14
14
  this.isPreview = this.options.isPreview || false;
15
15
  this.locale = options.locale || 'en';
16
- this.previewParam = this.isPreview ? "?isPreview=true" : "";
16
+
17
17
  this.serverUrl = this.options.serverUrl || 'https://app.bizdriver.ai/';
18
18
  this.height = options.height || 600; // Default height
19
- this.width = options.width || 320; // Default width
19
+ this.width = options.width || 400; // Default width
20
20
  this.marginBottom = options.marginBottom || 0;
21
21
  this.enableAnimation = options.enableAnimation !== false; // Default to true if not provided
22
- this.minimizedHeight = "180px"; // Sensible default instead of 30% calculation
22
+ this.theme = options.theme || this.containerDiv.dataset.theme || 'Standard';
23
+ this.minimizedHeight = this.theme === 'MinimalInput' ? "75px" : "80px"; // Default heights for different themes
23
24
  this.hasMeasuredSize = false;
24
25
  this.mouseInsideChat = false;
25
- this.hasRefreshed = false; // Flag to prevent endless loop
26
+
26
27
  this.conversationId = null;
27
28
  this.userTokenProvider = options.userTokenProvider;
28
29
  this.targetOrigin = "*";
@@ -33,7 +34,9 @@
33
34
  this.position = this.options.position || this.containerDiv.dataset.position || 'fixed';
34
35
  this.positionStyle = this.position === 'in-place' ?
35
36
  `position: relative; width:100%; height:${this.height}px; ${transitionStyle}` :
36
- `position: fixed; right: 1em; bottom: 0; width: ${this.width}px; z-index: 100000; max-width:90vw; max-height: 90vh; ${transitionStyle}`;
37
+ (this.theme === 'MinimalInput' ?
38
+ `position: fixed; left: 0; right: 0; margin-left: auto; margin-right: auto; width: 100%; max-width: ${this.width}px; bottom: ${this.marginBottom}px; z-index: 100000; max-height: 90vh; ${transitionStyle}` :
39
+ `position: fixed; right: 1em; bottom: ${this.marginBottom}px; width: 100%; max-width: ${this.width}px; z-index: 100000; max-height: 90vh; ${transitionStyle}`);
37
40
  this.mode = options.mode || 'Chat'; // default to 'chat'
38
41
  this.minimizeOnScroll = false; // Default to false
39
42
  if (this.mode === 'ContactForm' || this.mode === 'PartnerOffers') {
@@ -93,13 +96,25 @@
93
96
  ? this.serverUrl.slice(0, -1)
94
97
  : this.serverUrl;
95
98
  const baseIframeUrl = `${cleanedServerUrl}/ChatUX/${this.chatId}`;
99
+ const transitionStyle = this.enableAnimation ? 'transition: height 0.3s ease, opacity 0.3s ease;' : '';
100
+
101
+ // Recalculate positionStyle conditionally in case theme changed dynamically
102
+ this.positionStyle = this.position === 'in-place' ?
103
+ `position: relative; width:100%; height:${this.height}px; ${transitionStyle}` :
104
+ (this.theme === 'MinimalInput' ?
105
+ `position: fixed; left: 0; right: 0; margin-left: auto; margin-right: auto; bottom: ${this.marginBottom}px; width: 95vw; max-width: ${this.width}px; z-index: 100000; max-height: 90vh; pointer-events: auto; ${transitionStyle}` :
106
+ `position: fixed; right: 1em; bottom: ${this.marginBottom}px; width: ${this.width}px; z-index: 100000; max-width:90vw; max-height: 90vh; pointer-events: auto; ${transitionStyle}`);
107
+
96
108
  const minimizedPositionStyle = this.position === 'in-place' ?
97
- `position: relative; width: 100%; height: ${this.minimizedHeight}; ${this.enableAnimation ? 'transition: height 0.3s ease, opacity 0.3s ease;' : ''}` :
98
- `position: fixed; right: 0; bottom: 0; width: 150px; height: ${this.minimizedHeight}; z-index: 100000; ${this.enableAnimation ? 'transition: height 0.3s ease, opacity 0.3s ease;' : ''}`;
109
+ `position: relative; width: 100%; height: ${this.minimizedHeight}; ${transitionStyle}` :
110
+ (this.theme === 'MinimalInput' ?
111
+ `position: fixed; left: 0; right: 0; margin-left: auto; margin-right: auto; bottom: ${this.marginBottom}px; width: 100vw; max-width: ${Math.min(300, this.width) + 40}px; height: ${this.minimizedHeight}; z-index: 100000; pointer-events: auto; ${transitionStyle}` :
112
+ `position: fixed; right: 0; bottom: ${this.marginBottom}px; width: 150px; height: ${this.minimizedHeight}; z-index: 100000; max-width: 95vw; pointer-events: auto; ${transitionStyle}`);
99
113
 
100
114
  const params = {
101
115
  isPreview: this.isPreview,
102
116
  mode: this.mode,
117
+ theme: this.theme,
103
118
  locale: this.locale,
104
119
  conversationId: this.conversationId,
105
120
  instanceId: this.instanceId,
@@ -144,11 +159,18 @@
144
159
  // Send auth to iframes after load
145
160
  await this.postAuthToIframes();
146
161
 
147
- // restore your ContactForm logic
162
+ // Restore ContactForm logic
148
163
  if (this.mode === 'ContactForm' || this.mode === 'PartnerOffers') {
149
164
  this.iframe.style.maxWidth = '100%';
150
165
  this.iframe.style.display = 'block';
151
166
  }
167
+
168
+ // Apply pointer-events to container if theme is MinimalInput to prevent blocking page
169
+ if (this.theme === 'MinimalInput' && this.position !== 'in-place') {
170
+ this.containerDiv.style.pointerEvents = 'none';
171
+ } else {
172
+ this.containerDiv.style.pointerEvents = 'auto'; // Reset for other themes
173
+ }
152
174
  }
153
175
 
154
176
  addIframeEventListeners() {
@@ -163,12 +185,9 @@
163
185
  }
164
186
 
165
187
  addWindowEventListeners() {
166
-
167
- // Use a flag to ensure window listeners aren't duplicated for this specific instance if setMode is called (though it shouldn't be)
168
188
  if (this.windowListenersAdded) return;
169
189
 
170
190
  window.addEventListener("message", (e) => {
171
- // Only trust messages from our server (when targetOrigin is not "*")
172
191
  if (this.targetOrigin !== "*" && e.origin !== this.targetOrigin) return;
173
192
  this.handleMessage(e);
174
193
  });
@@ -197,7 +216,7 @@
197
216
  if (this.iframe?.contentWindow) {
198
217
  this.iframe.contentWindow.postMessage({
199
218
  message: "resize",
200
- width: window.innerWidth, // Ensure correct size
219
+ width: window.innerWidth,
201
220
  height: window.innerHeight,
202
221
  instanceId: this.instanceId
203
222
  }, this.targetOrigin);
@@ -205,11 +224,9 @@
205
224
  }
206
225
 
207
226
  handleMessage(e) {
208
- // Only trust messages from our server (when targetOrigin is not "*")
209
227
  if (this.targetOrigin !== "*" && e.origin !== this.targetOrigin) return;
210
228
 
211
229
  if (typeof e.data !== "object") {
212
- // Preserve original handling for string messages
213
230
  if (typeof e.data === "string") {
214
231
  if (e.data === "minimize") {
215
232
  this.animateMinimize();
@@ -234,56 +251,68 @@
234
251
  const targetChatId = (this.chatId || "").toString().toLowerCase();
235
252
  const incomingInstanceId = data.instanceId;
236
253
 
237
- // Priority 1: Handle instance-specific routing
238
254
  if (incomingInstanceId && incomingInstanceId !== this.instanceId) return;
239
-
240
- // Priority 2: Bail out if chatId doesn't match and is provided (legacy/fallback)
241
255
  if (!incomingInstanceId && incomingChatId && targetChatId && incomingChatId !== targetChatId) return;
242
256
 
243
- // Allow the iframe to request a fresh token
244
257
  if (data.type === "requestAuth") {
245
258
  this.postAuthToIframes();
246
259
  return;
247
260
  }
248
261
 
249
- // Priority 1: Handle minimized size updates (CRITICAL: Bail out early and DO NOT pollute configuration)
250
262
  if (msg === "updateMinimizedSize") {
251
- // Support both new and legacy keys for compatibility with cached scripts
252
263
  const h = data.minimizedHeight || data.height;
253
264
  const w = data.minimizedWidth || data.width;
254
265
  this.updateMinimizedSize(h, w);
255
266
  return;
256
267
  }
257
268
 
258
- const updates = {};
269
+ if (msg === "collapseMinimalInput") {
270
+ if (this.minimizedIframe) {
271
+ this.minimizedIframe.style.width = '80px';
272
+ this.minimizedIframe.style.height = '80px';
273
+ this.minimizedIframe.style.left = 'auto';
274
+ this.minimizedIframe.style.right = '0';
275
+ this.minimizedIframe.style.marginLeft = '0';
276
+ this.minimizedIframe.style.marginRight = '0';
277
+ this.minimizedIframe.style.pointerEvents = 'auto';
278
+ }
279
+ return;
280
+ }
281
+
282
+ if (msg === "restoreMinimalInput") {
283
+ if (this.minimizedIframe) {
284
+ this.minimizedIframe.style.width = '100vw';
285
+ this.minimizedIframe.style.maxWidth = `${Math.min(300, this.width) + 40}px`;
286
+ this.minimizedIframe.style.height = this.theme === 'MinimalInput' ? "75px" : this.minimizedHeight;
287
+ this.minimizedIframe.style.left = '0';
288
+ this.minimizedIframe.style.right = '0';
289
+ this.minimizedIframe.style.marginLeft = 'auto';
290
+ this.minimizedIframe.style.marginRight = 'auto';
291
+ this.minimizedIframe.style.pointerEvents = 'auto';
292
+ }
293
+ if (this.theme === 'MinimalInput' && this.position !== 'in-place') {
294
+ this.containerDiv.style.pointerEvents = 'none';
295
+ }
296
+ return;
297
+ }
259
298
 
299
+ const updates = {};
260
300
  if (data.type === "setMinimizeOnScroll" || data.minimizeOnScroll !== undefined) {
261
301
  const minimizeValue = data.type === "setMinimizeOnScroll" ? data.value : data.minimizeOnScroll;
262
302
  this.minimizeOnScroll = minimizeValue === true || minimizeValue === "true";
263
303
  }
264
304
 
265
- if (data.locale) {
266
- updates.locale = data.locale;
267
- }
268
- if (data.width) {
269
- updates.width = data.width;
270
- }
271
- if (data.height) {
272
- updates.height = data.height;
273
- }
274
- if (data.marginBottom) {
275
- updates.marginBottom = data.marginBottom;
276
- }
277
- if (data.scale) {
278
- updates.scale = data.scale;
279
- }
305
+ if (data.locale) updates.locale = data.locale;
306
+ if (data.width) updates.width = data.width;
307
+ if (data.height) updates.height = data.height;
308
+ if (data.marginBottom) updates.marginBottom = data.marginBottom;
309
+ if (data.scale) updates.scale = data.scale;
310
+ if (data.theme) updates.theme = data.theme;
280
311
 
281
- // Apply iframe updates in one go
282
312
  if (Object.keys(updates).length > 0) {
283
313
  this.applyIframeUpdates(updates);
284
314
  }
285
315
 
286
- // Handle maximize/minimize/navigate
287
316
  if (msg === "minimize") {
288
317
  if (typeof this.options.onMinimize === 'function') {
289
318
  this.options.onMinimize();
@@ -292,7 +321,7 @@
292
321
  }
293
322
  } else if (msg === "show" || msg === "maximize") {
294
323
  const animate = data.animate === true;
295
- this.showMaximized(animate);
324
+ this.showMaximized(animate, data.initialMessage);
296
325
  } else if (msg === "navigate" && data.url) {
297
326
  window.location.href = data.url;
298
327
  } else if (data.type === "switchToChat" || msg === "switchToChat") {
@@ -309,7 +338,6 @@
309
338
  }
310
339
  }
311
340
 
312
- // Handle conversationId update
313
341
  if (data.conversationId) {
314
342
  this.setConversationId(data.conversationId);
315
343
  }
@@ -326,7 +354,6 @@
326
354
  this.minimizedIframe.style.height = this.minimizedHeight;
327
355
  this.minimizedIframe.style.opacity = '1';
328
356
 
329
- // Request a height update after showing
330
357
  if (this.minimizedIframe.contentWindow) {
331
358
  this.minimizedIframe.contentWindow.postMessage({ message: "requestHeightUpdate", instanceId: this.instanceId }, this.targetOrigin);
332
359
  }
@@ -339,7 +366,6 @@
339
366
 
340
367
  this.hasMeasuredSize = true;
341
368
 
342
- // Apply height update
343
369
  if (contentHeight && contentHeight >= 10) {
344
370
  const newHeight = `${contentHeight}px`;
345
371
  this.minimizedHeight = newHeight;
@@ -348,9 +374,8 @@
348
374
  }
349
375
  }
350
376
 
351
- // Apply width update
352
377
  if (contentWidth && contentWidth >= 10) {
353
- if (this.minimizedIframe) {
378
+ if (this.minimizedIframe && this.theme !== 'MinimalInput') {
354
379
  this.minimizedIframe.style.width = `${contentWidth}px`;
355
380
  }
356
381
  }
@@ -358,97 +383,126 @@
358
383
 
359
384
  animateMaximize() {
360
385
  if (this.mode !== 'ContactForm' && this.mode !== 'PartnerOffers') {
361
- // Start the animation for minimizing iframe
362
- this.minimizedIframe.style.height = `${this.height}px`;
363
- this.minimizedIframe.style.opacity = '0';
364
-
365
- setTimeout(() => {
366
- // Hide the minimized iframe
386
+ const onMinimizedAnimateEnd = () => {
387
+ this.minimizedIframe.removeEventListener("transitionend", onMinimizedAnimateEnd);
367
388
  this.minimizedIframe.style.display = "none";
368
- this.minimizedIframe.style.opacity = '1'; // Reset opacity
389
+ this.minimizedIframe.style.opacity = '1';
369
390
 
370
- // Show and animate the main iframe
371
391
  this.iframe.style.display = "block";
372
- this.iframe.style.height = this.minimizedHeight; // Start with minimized height
373
- this.iframe.style.opacity = '0'; // Start with zero opacity
392
+ this.iframe.style.height = this.minimizedHeight;
393
+ this.iframe.style.opacity = "0";
374
394
 
375
- // Trigger the maximize animation
376
- setTimeout(() => {
377
- this.iframe.style.height = `${this.height}px`; // Animate to full height
378
- this.iframe.style.opacity = '1'; // Animate opacity to full
379
- }, 10); // Small delay to allow display changes to take effect
380
- }, this.enableAnimation ? 300 : 0); // Match the minimize animation duration
395
+ this.iframe.offsetHeight;
396
+
397
+ this.iframe.style.height = `${this.height}px`;
398
+ this.iframe.style.opacity = "1";
399
+ };
400
+
401
+ if (this.enableAnimation) {
402
+ this.minimizedIframe.addEventListener("transitionend", onMinimizedAnimateEnd);
403
+ this.minimizedIframe.style.height = this.minimizedHeight;
404
+ this.minimizedIframe.style.opacity = "0";
405
+
406
+ // Notify iframe when maximize transition finishes to ensure final scroll-into-view
407
+ this.iframe.addEventListener("transitionend", (e) => {
408
+ if (e.propertyName === 'height' && this.iframe.style.display !== 'none') {
409
+ if (this.iframe.contentWindow) {
410
+ this.iframe.contentWindow.postMessage({ message: "maximizeComplete", instanceId: this.instanceId }, this.targetOrigin);
411
+ }
412
+ }
413
+ }, { once: true });
414
+ } else {
415
+ onMinimizedAnimateEnd();
416
+ }
381
417
  }
382
418
  }
383
419
 
384
- applyIframeUpdates({ locale, width, height, marginBottom, scale } = {}) {
385
- // Update locale if provided and different (but do not update the iframe URL)
420
+ applyIframeUpdates({ locale, width, height, marginBottom, scale, theme } = {}) {
421
+ if (theme && typeof theme === 'string' && theme !== this.theme) {
422
+ this.theme = theme;
423
+ console.log(`Theme updated to: ${this.theme}`);
424
+ this.minimizedHeight = this.theme === 'MinimalInput' ? "75px" : "80px";
425
+ this.updateIframes();
426
+ return;
427
+ }
428
+
386
429
  if (locale && typeof locale === 'string' && locale !== this.locale) {
387
430
  this.locale = locale;
388
431
  console.log(`Locale stored locally: ${this.locale}`);
389
432
  }
390
433
 
391
- // Update width if provided and different
392
434
  const parsedWidth = parseInt(width, 10);
393
435
  if (!isNaN(parsedWidth) && parsedWidth > 0 && parsedWidth !== this.width) {
394
436
  this.width = parsedWidth;
395
437
  console.log(`Width updated to: ${this.width}px`);
396
438
 
397
- // Apply width only if not in-place
398
439
  if (this.position !== 'in-place') {
399
- this.containerDiv.style.width = `${this.width}px`;
400
- if (this.iframe) {
401
- this.iframe.style.width = `${this.width}px`;
440
+ if (this.theme === 'MinimalInput') {
441
+ this.containerDiv.style.width = '100vw'; // Use 100vw but keep pointerEvents none
442
+ this.containerDiv.style.left = '0';
443
+ this.containerDiv.style.right = '0';
444
+ this.containerDiv.style.marginLeft = 'auto';
445
+ this.containerDiv.style.marginRight = 'auto';
446
+ this.containerDiv.style.pointerEvents = 'none'; // Prevent invisible area from blocking clicks
447
+ if (this.iframe) {
448
+ this.iframe.style.width = '95vw';
449
+ this.iframe.style.maxWidth = `${this.width}px`;
450
+ this.iframe.style.pointerEvents = 'auto';
451
+ this.iframe.style.left = '0';
452
+ this.iframe.style.right = '0';
453
+ this.iframe.style.margin = 'auto';
454
+ }
455
+ if (this.minimizedIframe) {
456
+ this.minimizedIframe.style.width = '100vw'; // Use 100vw to allow centering
457
+ this.minimizedIframe.style.maxWidth = `${Math.min(300, this.width) + 40}px`;
458
+ this.minimizedIframe.style.pointerEvents = 'auto';
459
+ this.minimizedIframe.style.left = '0';
460
+ this.minimizedIframe.style.right = '0';
461
+ this.minimizedIframe.style.margin = 'auto';
462
+ }
463
+ } else {
464
+ this.containerDiv.style.width = `${this.width}px`;
465
+ this.containerDiv.style.pointerEvents = 'auto'; // Ensure auto for other themes
466
+ if (this.iframe) this.iframe.style.width = `${this.width}px`;
402
467
  }
403
468
  } else {
404
469
  this.containerDiv.style.width = '100%';
405
- if (this.iframe) {
406
- this.iframe.style.width = '100%';
407
- }
470
+ this.containerDiv.style.pointerEvents = 'auto';
471
+ if (this.iframe) this.iframe.style.width = '100%';
408
472
  }
409
473
  }
410
474
 
411
- // Apply scale if provided
412
475
  if (typeof scale === 'number' && scale > 0) {
413
476
  this.applyScale(scale);
414
477
  console.log(`Scale applied: ${scale}`);
415
478
  }
416
479
 
417
- // Handle height and marginBottom
418
480
  let parsedHeight = parseInt(height, 10);
419
481
  let parsedMarginBottom = parseInt(marginBottom, 10);
420
482
 
421
- // Default to existing values if not provided or invalid
422
- if (isNaN(parsedHeight) || parsedHeight <= 0) {
423
- parsedHeight = this.height;
424
- }
483
+ if (isNaN(parsedHeight) || parsedHeight <= 0) parsedHeight = this.height;
425
484
  if (isNaN(parsedMarginBottom) || parsedMarginBottom < 0) {
426
485
  parsedMarginBottom = (typeof this.marginBottom === 'number') ? this.marginBottom : 0;
427
486
  }
428
487
 
429
- // Clamp so that height + marginBottom doesn't exceed 90% of viewport
430
488
  const viewportHeight = window.innerHeight;
431
489
  let effectiveHeight = parsedHeight;
432
490
  if (effectiveHeight + parsedMarginBottom > 0.9 * viewportHeight) {
433
491
  effectiveHeight = Math.max(100, 0.9 * viewportHeight - parsedMarginBottom);
434
492
  }
435
493
 
436
- // Only apply if there's an actual change
437
494
  if (parsedHeight !== this.height || parsedMarginBottom !== this.marginBottom) {
438
495
  this.height = parsedHeight;
439
496
  this.marginBottom = parsedMarginBottom;
440
497
 
441
- // Only use the 30% estimate if we haven't received a real measurement yet
442
498
  if (!this.hasMeasuredSize) {
443
- this.minimizedHeight = `${this.height * 0.3}px`;
499
+ this.minimizedHeight = this.theme === 'MinimalInput' ? "75px" : "80px";
444
500
  }
445
501
 
446
- console.log(`Height updated to: ${this.height}px (clamped to ${effectiveHeight}px for display), marginBottom: ${this.marginBottom}px`);
502
+ console.log(`Height updated to: ${this.height}px, marginBottom: ${this.marginBottom}px`);
447
503
 
448
- // Apply the updated height/marginBottom
449
504
  if (this.mode !== 'ContactForm' && this.mode !== 'PartnerOffers') {
450
505
  if (this.position === 'in-place') {
451
- // "in-place" uses full width, sets containerDiv height
452
506
  this.containerDiv.style.position = 'relative';
453
507
  this.containerDiv.style.width = '100%';
454
508
  this.containerDiv.style.height = `${effectiveHeight}px`;
@@ -467,8 +521,6 @@
467
521
  this.minimizedIframe.style.right = 'unset';
468
522
  }
469
523
  } else {
470
- // position: fixed (typical floating chat)
471
- // Update bottom offset, main height
472
524
  if (this.iframe) {
473
525
  this.iframe.style.height = `${this.height}px`;
474
526
  this.iframe.style.bottom = `${this.marginBottom}px`;
@@ -476,34 +528,36 @@
476
528
  if (this.minimizedIframe) {
477
529
  this.minimizedIframe.style.height = this.minimizedHeight;
478
530
  this.minimizedIframe.style.bottom = `${this.marginBottom}px`;
531
+ if (this.theme === 'MinimalInput') {
532
+ this.minimizedIframe.style.width = '100vw';
533
+ this.minimizedIframe.style.maxWidth = `${Math.min(300, this.width) + 40}px`;
534
+ }
479
535
  }
480
536
  }
481
537
  } else {
482
- // ContactForm mode
483
538
  this.containerDiv.style.height = `${this.height}px`;
484
- if (this.iframe) {
485
- this.iframe.style.height = `${this.height}px`;
486
- }
539
+ if (this.iframe) this.iframe.style.height = `${this.height}px`;
487
540
  }
488
541
  }
489
542
  }
490
543
 
491
- showMaximized(animate = false) {
544
+ showMaximized(animate = false, initialMessage = null) {
492
545
  const schedulePostMessage = () => {
493
546
  if (this.iframe.contentWindow) {
494
547
  this.iframe.contentWindow.postMessage({
495
548
  message: "show",
496
549
  sessionInfo: this.sessionInfo || null,
497
- instanceId: this.instanceId
550
+ instanceId: this.instanceId,
551
+ initialMessage: initialMessage
498
552
  }, this.targetOrigin);
499
553
  } else {
500
- // Schedule a single retry with a delay
501
554
  setTimeout(() => {
502
555
  if (this.iframe.contentWindow) {
503
556
  this.iframe.contentWindow.postMessage({
504
557
  message: "show",
505
558
  sessionInfo: this.sessionInfo || null,
506
- instanceId: this.instanceId
559
+ instanceId: this.instanceId,
560
+ initialMessage: initialMessage
507
561
  }, this.targetOrigin);
508
562
  } else {
509
563
  console.warn("iframe contentWindow is not available.");
@@ -516,8 +570,7 @@
516
570
  this.animateMaximize();
517
571
  } else {
518
572
  this.minimizedIframe.style.display = "none";
519
- this.minimizedIframe.style.height = `${this.height}px`;
520
- this.minimizedIframe.style.opacity = ''; // Reset opacity to unset
573
+ this.minimizedIframe.style.opacity = '';
521
574
 
522
575
  this.iframe.style.display = "block";
523
576
  this.iframe.style.height = `${this.height}px`;
@@ -529,7 +582,8 @@
529
582
 
530
583
  applyScale(scale) {
531
584
  if (this.mode !== 'ContactForm' && this.mode !== 'PartnerOffers') {
532
- const origin = this.position === 'in-place' ? 'top center' : 'bottom right';
585
+ let origin = this.position === 'in-place' ? 'top center' : 'bottom right';
586
+ if (this.theme === 'MinimalInput') origin = 'bottom center';
533
587
  if (this.iframe) {
534
588
  this.iframe.style.transform = `scale(${scale})`;
535
589
  this.iframe.style.transformOrigin = origin;
@@ -548,10 +602,7 @@
548
602
  }
549
603
 
550
604
  setSessionInfo(sessionInfo) {
551
- console.log('setSessionInfo called with sessionInfo:', sessionInfo);
552
605
  this.sessionInfo = sessionInfo;
553
-
554
- // Send session info immediately if the chat is already maximized
555
606
  if (this.iframe?.contentWindow && this.iframe.style.display !== "none") {
556
607
  this.iframe.contentWindow.postMessage({ type: 'setSessionInfo', sessionInfo: this.sessionInfo, instanceId: this.instanceId }, this.targetOrigin);
557
608
  }
@@ -565,78 +616,55 @@
565
616
  return chatContainer;
566
617
  }
567
618
 
619
+ maximizeWithText(text) {
620
+ this.showMaximized(true, text);
621
+ }
622
+
568
623
  buildIframeUrl(baseIframeUrl, params = {}) {
569
624
  const urlParams = new URLSearchParams();
570
-
571
- if (params.isPreview) {
572
- urlParams.set('isPreview', 'true');
573
- }
574
-
625
+ if (params.isPreview) urlParams.set('isPreview', 'true');
575
626
  if (params.mode === 'ContactForm' || params.mode === 'PartnerOffers' || params.mode === 'Chat') {
576
627
  urlParams.set('mode', params.mode);
577
628
  }
578
-
579
- if (params.locale) {
580
- urlParams.set('locale', params.locale);
581
- }
582
-
583
- if (params.conversationId) {
584
- urlParams.set('conversationId', params.conversationId);
585
- }
629
+ if (params.locale) urlParams.set('locale', params.locale);
630
+ if (params.conversationId) urlParams.set('conversationId', params.conversationId);
631
+ if (params.instanceId) urlParams.set('instanceId', params.instanceId);
586
632
 
587
633
  for (const [key, value] of Object.entries(params)) {
588
- if (key !== 'mode' && key !== 'isPreview' && key !== 'conversationId' && key !== 'userToken' && value !== null && value !== undefined) {
634
+ if (!['mode', 'isPreview', 'conversationId', 'instanceId', 'userToken'].includes(key) && value !== null && value !== undefined) {
589
635
  urlParams.set(key, value);
590
636
  }
591
637
  }
592
-
593
638
  return `${baseIframeUrl}?${urlParams.toString()}`;
594
639
  }
595
640
 
596
641
  waitForIframeLoad(iframe, timeout = 10000) {
597
642
  return new Promise((resolve) => {
598
- // Set up a timeout to avoid waiting indefinitely
599
643
  const timeoutId = setTimeout(() => {
600
644
  console.warn('EmbeddedChat: Iframe load timeout, proceeding with initialization.');
601
645
  resolve();
602
646
  }, timeout);
603
647
 
604
- // Add the load event listener
605
648
  iframe.addEventListener('load', () => {
606
- clearTimeout(timeoutId); // Clear the timeout
649
+ clearTimeout(timeoutId);
607
650
  resolve();
608
- }, { once: true }); // Ensure the listener is triggered only once
651
+ }, { once: true });
609
652
  });
610
653
  }
611
654
 
612
655
  async postAuthToIframes() {
613
- console.log('[EmbeddedChat] postAuthToIframes called');
614
- if (typeof this.userTokenProvider !== 'function') {
615
- console.warn('[EmbeddedChat] No userTokenProvider function provided');
616
- return;
617
- }
618
-
656
+ if (typeof this.userTokenProvider !== 'function') return;
619
657
  try {
620
658
  const userToken = await this.userTokenProvider();
621
-
622
- if (!userToken) {
623
- console.warn('[EmbeddedChat] userTokenProvider returned null/empty token');
624
- return;
625
- }
626
-
659
+ if (!userToken) return;
627
660
  if (this.iframe?.contentWindow) {
628
- console.log('[EmbeddedChat] Sending auth message to iframe with targetOrigin:', this.targetOrigin);
629
661
  this.iframe.contentWindow.postMessage({
630
662
  type: 'auth',
631
663
  userToken: userToken,
632
664
  chatId: this.chatId,
633
665
  instanceId: this.instanceId
634
666
  }, this.targetOrigin);
635
- console.log('[EmbeddedChat] Auth message sent successfully');
636
- } else {
637
- console.error('[EmbeddedChat] iframe.contentWindow is not available');
638
667
  }
639
- // No longer send auth to minimizedIframe
640
668
  } catch (err) {
641
669
  console.error('[EmbeddedChat] Failed to get user token:', err);
642
670
  }
@@ -647,9 +675,7 @@
647
675
 
648
676
  console.log(`[EmbeddedChat] Setting mode to ${newMode}`, options);
649
677
  this.mode = newMode;
650
- if (options.chatId) {
651
- this.chatId = options.chatId;
652
- }
678
+ if (options.chatId) this.chatId = options.chatId;
653
679
  this.options = { ...this.options, ...options };
654
680
  const transitionStyle = this.enableAnimation ? 'transition: height 0.3s ease, opacity 0.3s ease;' : '';
655
681
  if (this.mode === 'ContactForm' || this.mode === 'PartnerOffers') {
@@ -659,7 +685,9 @@
659
685
  } else {
660
686
  this.positionStyle = this.position === 'in-place' ?
661
687
  `position: relative; width:100%; height:${this.height}px; ${transitionStyle}` :
662
- `position: fixed; right: 1em; bottom: 0; width: ${this.width}px; z-index: 100000; max-width:90vw; max-height: 90vh; ${transitionStyle}`;
688
+ (this.theme === 'MinimalInput' ?
689
+ `position: fixed; left: 0; right: 0; margin-left: auto; margin-right: auto; bottom: ${this.marginBottom}px; width: ${this.width}px; z-index: 100000; max-width:90vw; max-height: 90vh; ${transitionStyle}` :
690
+ `position: fixed; right: 1em; bottom: ${this.marginBottom}px; width: ${this.width}px; z-index: 100000; max-width:90vw; max-height: 90vh; ${transitionStyle}`);
663
691
  if (this.position === 'in-place') {
664
692
  this.containerDiv.style.position = 'relative';
665
693
  this.containerDiv.style.width = '100%';
@@ -684,4 +712,3 @@ export function initOffers(options = {}) {
684
712
  const mergedOptions = { ...options, mode: 'PartnerOffers', height: options.height || 500 };
685
713
  return new EmbeddedChat(options.container, chatId, mergedOptions);
686
714
  }
687
-
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "embeddedaichatux",
3
- "version": "2.2.0",
3
+ "version": "2.2.1",
4
4
  "description": "A lightweight and customizable embedded AI chat UI component that seamlessly integrates into web applications, offering minimized and expanded views, with iframe-based content rendering.",
5
5
  "main": "EmbeddedChat.js",
6
6
  "scripts": {