embeddedaichatux 1.3.1 → 1.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 (2) hide show
  1. package/EmbeddedChat.js +121 -44
  2. package/package.json +1 -1
package/EmbeddedChat.js CHANGED
@@ -1,5 +1,4 @@
1
- // embeddedChat.js
2
- class EmbeddedChat {
1
+ class EmbeddedChat {
3
2
  constructor(containerDiv, chatId, options) {
4
3
  if (!containerDiv) {
5
4
  containerDiv = this.createChatContainer();
@@ -8,70 +7,146 @@ class EmbeddedChat {
8
7
  this.chatId = chatId;
9
8
  this.options = options || {};
10
9
  this.isPreview = this.options.isPreview || false;
10
+ this.locale = options.locale || 'en';
11
11
  this.previewParam = this.isPreview ? "?isPreview=true" : "";
12
12
  this.serverUrl = this.options.serverUrl || 'https://embedgpt.chat/';
13
- this.positionStyle = this.containerDiv.dataset.position === 'in-place' ? 'width:100%; height:600px' : 'position: fixed; right: 0; bottom: 0; width: 300px; height: 600px; z-index: 100000';
13
+ this.height = options.height || 600; // Default height
14
+ this.width = options.width || 300; // Default width
15
+ this.enableAnimation = options.enableAnimation !== false; // Default to true if not provided
16
+ this.minimizedHeight = `${this.height * 0.3}px`; // 30% of the full height
17
+ this.mouseInsideChat = false;
18
+
19
+ // Determine transition styles
20
+ const transitionStyle = this.enableAnimation ? 'transition: height 0.3s ease, opacity 0.3s ease;' : '';
21
+
22
+ this.positionStyle = this.containerDiv.dataset.position === 'in-place' ?
23
+ `width:100%; height:${this.height}px; ${transitionStyle}` :
24
+ `position: fixed; right: 0; bottom: 0; width: ${this.width}px; height: ${this.height}px; z-index: 100000; ${transitionStyle}`;
14
25
  this.mode = options.mode || 'Chat'; // default to 'chat' if mode isn't provided
26
+ this.minimizeOnScroll = false; // Default to false
15
27
  if (this.mode === 'ContactForm') {
16
28
  // Adjust position style for contact form if mode is 'ContactForm'
17
- this.positionStyle = 'width:100%; height:600px';
18
- this.containerDiv.style.height = '600px';
29
+ this.positionStyle = `width:100%; height:${this.height}px; ${transitionStyle}`;
30
+ this.containerDiv.style.height = `${this.height}px`;
19
31
  }
32
+ this.sessionInfo = options.sessionInfo || null;
20
33
  this.init();
21
34
  }
22
35
 
23
- init() {
24
- const cleanedServerUrl = this.serverUrl.endsWith('/') ? this.serverUrl.slice(0, -1) : this.serverUrl;
25
- const baseIframeUrl = `${cleanedServerUrl}/ChatUX/${this.chatId}`;
26
- const minimizedPositionStyle = 'position: fixed; right: 0; bottom: 0; width: 300px; height: 70px; z-index: 100000';
36
+ init() {
37
+ const cleanedServerUrl = this.serverUrl.endsWith('/') ? this.serverUrl.slice(0, -1) : this.serverUrl;
38
+ const baseIframeUrl = `${cleanedServerUrl}/ChatUX/${this.chatId}`;
39
+ const minimizedPositionStyle = `position: fixed; right: 0; bottom: 0; width: ${this.width}px; height: ${this.minimizedHeight}; z-index: 100000; ${this.enableAnimation ? 'transition: height 0.3s ease, opacity 0.3s ease;' : ''}`;
27
40
 
28
- const iframeHtml = `
29
- <iframe id="embedded-chat" style="${this.positionStyle}; display: none; border:none; overflow:hidden;" frameborder="0" sandbox="allow-same-origin allow-scripts allow-popups allow-forms" src="${this.buildIframeUrl(baseIframeUrl, { isPreview: this.isPreview, mode: this.mode })}"></iframe>
30
- <iframe id="embedded-chat-minimized" style="${minimizedPositionStyle}; display: none; border:none; overflow:hidden;" frameborder="0" sandbox="allow-same-origin allow-scripts allow-popups allow-forms" src="${this.buildIframeUrl(baseIframeUrl, { isPreview: this.isPreview, isMinimized: true })}"></iframe>
31
- `;
41
+ const iframeHtml = `
42
+ <iframe id="embedded-chat" style="${this.positionStyle}; display: none; border:none; overflow:hidden;" frameborder="0" sandbox="allow-same-origin allow-scripts allow-popups allow-forms" src="${this.buildIframeUrl(baseIframeUrl, { isPreview: this.isPreview, mode: this.mode, locale: this.locale })}"></iframe>
43
+ <iframe id="embedded-chat-minimized" style="${minimizedPositionStyle}; display: none; border:none; overflow:hidden;" frameborder="0" sandbox="allow-same-origin allow-scripts allow-popups allow-forms" src="${this.buildIframeUrl(baseIframeUrl, { isPreview: this.isPreview, isMinimized: true, locale: this.locale })}"></iframe>
44
+ `;
32
45
 
33
46
  this.containerDiv.innerHTML = iframeHtml;
34
47
  this.iframe = this.containerDiv.querySelector("#embedded-chat");
35
48
  this.minimizedIframe = this.containerDiv.querySelector("#embedded-chat-minimized");
36
49
 
50
+ // Add event listeners to track mouse position
51
+ this.iframe.addEventListener("mouseenter", () => { this.mouseInsideChat = true; });
52
+ this.iframe.addEventListener("mouseleave", () => { this.mouseInsideChat = false; });
53
+ this.minimizedIframe.addEventListener("mouseenter", () => { this.mouseInsideChat = true; });
54
+ this.minimizedIframe.addEventListener("mouseleave", () => { this.mouseInsideChat = false; });
55
+
37
56
  window.addEventListener("message", (e) => {
38
- // Check if the data is an object and has a message property
39
- if (typeof e.data === "object" && e.data.message && (!e.data.chatId || e.data.chatId === this.chatId)) {
57
+ this.handleMessage(e);
58
+ });
59
+
60
+ window.addEventListener("scroll", () => {
61
+ if (this.minimizeOnScroll && !this.mouseInsideChat) {
62
+ this.minimizeOnScrollAction();
63
+ }
64
+ });
65
+ }
66
+
67
+ handleMessage(e) {
68
+ if (typeof e.data === "object" && (!e.data.chatId || e.data.chatId === this.chatId)) {
69
+ if (e.data.type === "setMinimizeOnScroll") {
70
+ this.minimizeOnScroll = e.data.value === "true";
71
+ }
72
+ if (e.data.message) {
40
73
  if (e.data.message === "minimize") {
41
74
  if (this.mode !== 'ContactForm') {
42
- // No minimize support for ContactForm
43
- this.iframe.style.display = "none";
44
- this.minimizedIframe.style.display = "block";
75
+ this.animateMinimize();
45
76
  }
46
77
  } else if (e.data.message === "show" || e.data.message === "maximize") {
47
- this.iframe.style.display = "block";
48
- this.minimizedIframe.style.display = "none";
49
- // Check if the data has a scale property
50
- if (e.data.scale) {
51
- if (this.mode !== 'ContactForm') {
52
- // No scaling support for ContactForm
53
-
54
- // Resize the iframe according to the scale factor
55
- this.iframe.style.transform = `scale(${e.data.scale})`;
56
- this.iframe.style.transformOrigin = "bottom right";
57
- }
58
- }
78
+ this.showMaximized();
59
79
  }
60
- }
61
- // For backward compatibility, handle the case when the data is a string
62
- else if (typeof e.data === "string") {
63
- if (e.data === "minimize") {
64
- this.iframe.style.display = "none";
65
- this.minimizedIframe.style.display = "block";
66
- } else if (e.data === "show" || e.data === "maximize") {
67
- this.iframe.style.display = "block";
68
- this.minimizedIframe.style.display = "none";
80
+ if (e.data.scale) {
81
+ this.applyScale(e.data.scale);
82
+ }
83
+ if (this.sessionInfo !== null) {
84
+ this.setSessionInfo(this.sessionInfo);
69
85
  }
70
86
  }
71
- });
87
+ } else if (typeof e.data === "string") {
88
+ if (e.data === "minimize") {
89
+ this.animateMinimize();
90
+ } else if (e.data === "show" || e.data === "maximize") {
91
+ this.showMaximized();
92
+ }
93
+ }
94
+ }
95
+
96
+ animateMinimize() {
97
+ if (this.mode !== 'ContactForm') {
98
+ this.iframe.style.height = this.minimizedHeight;
99
+ this.iframe.style.opacity = '0'; // Full transparency at the end
100
+ setTimeout(() => {
101
+ this.iframe.style.display = "none";
102
+ this.iframe.style.opacity = '1'; // Reset opacity to 1 for next time
103
+ this.minimizedIframe.style.display = "block";
104
+ this.minimizedIframe.style.height = this.minimizedHeight;
105
+ this.minimizedIframe.style.opacity = '1'; // Reset opacity to 1
106
+ }, this.enableAnimation ? 300 : 0); // Match the transition duration
107
+ }
72
108
  }
73
109
 
110
+ showMaximized() {
111
+ this.minimizedIframe.style.display = "none";
112
+ this.minimizedIframe.style.height = `${this.height}px`;
113
+ this.minimizedIframe.style.opacity = ''; // Reset opacity to unset
114
+ this.iframe.style.display = "block";
115
+ this.iframe.style.height = `${this.height}px`;
116
+ this.iframe.style.opacity = '1';
117
+ }
118
+
119
+ applyScale(scale) {
120
+ if (this.mode !== 'ContactForm') {
121
+ this.iframe.style.transform = `scale(${scale})`;
122
+ this.iframe.style.transformOrigin = "bottom right";
123
+ this.minimizedIframe.style.transform = `scale(${scale})`;
124
+ this.minimizedIframe.style.transformOrigin = "bottom right";
125
+ }
126
+ }
127
+
128
+ minimizeOnScrollAction() {
129
+ if (this.mode !== 'ContactForm' && this.iframe.style.display !== "none") {
130
+ this.animateMinimize();
131
+ }
132
+ }
74
133
 
134
+ setSessionInfo(sessionInfo) {
135
+ console.log('setSessionInfo called with sessionInfo:', sessionInfo);
136
+
137
+ this.sessionInfo = sessionInfo;
138
+
139
+ const iframe = this.containerDiv.querySelector("#embedded-chat");
140
+
141
+ const postMessage = () => {
142
+ console.log('Posting message to iframe:', { type: 'setSessionInfo', sessionInfo: sessionInfo });
143
+ iframe.contentWindow.postMessage({ type: 'setSessionInfo', sessionInfo: sessionInfo }, "*");
144
+ };
145
+
146
+ if (iframe.style.display !== "none") {
147
+ postMessage();
148
+ }
149
+ }
75
150
 
76
151
  createChatContainer() {
77
152
  const chatContainer = document.createElement('div');
@@ -84,7 +159,6 @@ init() {
84
159
  buildIframeUrl(baseIframeUrl, params = {}) {
85
160
  const urlParams = new URLSearchParams(params);
86
161
 
87
- // Add parameters as needed, based on values in the params object
88
162
  if (params.isPreview) {
89
163
  urlParams.set('isPreview', 'true');
90
164
  }
@@ -93,9 +167,12 @@ init() {
93
167
  urlParams.set('mode', 'ContactForm');
94
168
  }
95
169
 
96
- // Handle other parameters directly from the params object
170
+ if (params.locale) {
171
+ urlParams.set('locale', params.locale);
172
+ }
173
+
97
174
  for (const [key, value] of Object.entries(params)) {
98
- if (key !== 'mode' && key !== 'isPreview') { // Avoid duplicates
175
+ if (key !== 'mode' && key !== 'isPreview') {
99
176
  urlParams.set(key, value);
100
177
  }
101
178
  }
@@ -109,6 +186,6 @@ export function initEmbeddedChat(containerDiv, chatId, options) {
109
186
  }
110
187
 
111
188
  export function initContactForm(containerDiv, chatId, options) {
112
- const clonedOptions = { ...options, mode: 'ContactForm' }; // Clone with spread syntax
189
+ const clonedOptions = { ...options, mode: 'ContactForm' };
113
190
  return new EmbeddedChat(containerDiv, chatId, clonedOptions);
114
191
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "embeddedaichatux",
3
- "version": "1.3.1",
3
+ "version": "1.4.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": {