@buni.ai/chatbot-angular 1.0.15 → 1.0.17
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 +397 -260
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +397 -260
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -49,7 +49,8 @@ class BuniChatWidget {
|
|
|
49
49
|
};
|
|
50
50
|
this.eventListeners = new Map();
|
|
51
51
|
this.widgetElement = null;
|
|
52
|
-
this.
|
|
52
|
+
this.triggerIframe = null;
|
|
53
|
+
this.chatIframe = null;
|
|
53
54
|
this.customerData = null;
|
|
54
55
|
this.sessionVariables = null;
|
|
55
56
|
}
|
|
@@ -95,193 +96,382 @@ class BuniChatWidget {
|
|
|
95
96
|
};
|
|
96
97
|
const widthValue = ensureUnits(config.width, "350px");
|
|
97
98
|
const heightValue = ensureUnits(config.height, "650px");
|
|
98
|
-
//
|
|
99
|
-
const shouldStartMinimized = config.initialMinimized === true;
|
|
99
|
+
// Configuration
|
|
100
100
|
const showTriggerText = config.showTriggerText !== false;
|
|
101
101
|
const hasTriggerText = !!config.triggerText;
|
|
102
|
-
|
|
102
|
+
const primaryColor = config.primaryColor || "#795548";
|
|
103
|
+
const triggerText = config.triggerText || "";
|
|
104
|
+
const companyName = config.companyName || "Chat Support";
|
|
105
|
+
// Responsive breakpoints
|
|
103
106
|
const isMobile = window.innerWidth <= 768;
|
|
104
|
-
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
? showTriggerText && hasTriggerText
|
|
110
|
-
? "auto"
|
|
111
|
-
: "52px"
|
|
112
|
-
: isExtraSmall
|
|
113
|
-
? "100vw" // Full width on very small devices
|
|
114
|
-
: isMobile
|
|
115
|
-
? "min(100vw, 370px)" // Constrained width on mobile
|
|
116
|
-
: isTablet
|
|
117
|
-
? "min(calc(100vw - 3rem), 370px)" // Slightly smaller on tablets
|
|
118
|
-
: widthValue; // Custom width on desktop
|
|
119
|
-
const initialHeight = shouldStartMinimized
|
|
120
|
-
? "52px"
|
|
121
|
-
: isExtraSmall
|
|
122
|
-
? "100vh" // Full height on very small devices
|
|
123
|
-
: isMobile
|
|
124
|
-
? "min(100vh, 600px)" // Constrained height on mobile
|
|
125
|
-
: isTablet
|
|
126
|
-
? "min(calc(100vh - 3rem), 620px)" // Slightly smaller on tablets
|
|
127
|
-
: heightValue; // Custom height on desktop
|
|
128
|
-
const initialMinWidth = shouldStartMinimized && showTriggerText && hasTriggerText ? "auto" : "";
|
|
129
|
-
// Use CSS custom properties for dynamic styling
|
|
107
|
+
// Calculate trigger dimensions
|
|
108
|
+
const triggerWidth = showTriggerText && hasTriggerText ? "auto" : "52px";
|
|
109
|
+
const triggerHeight = "52px";
|
|
110
|
+
const triggerMinWidth = showTriggerText && hasTriggerText ? "auto" : "";
|
|
111
|
+
// Container starts as trigger size, initially hidden until connection is ready
|
|
130
112
|
container.style.cssText = `
|
|
131
113
|
position: fixed;
|
|
132
114
|
pointer-events: none;
|
|
133
115
|
z-index: 999999;
|
|
134
|
-
width: ${
|
|
135
|
-
height: ${
|
|
136
|
-
${
|
|
137
|
-
${isMobile && !shouldStartMinimized ? "max-width: 100vw; max-height: 100vh;" : ""}
|
|
116
|
+
width: ${triggerWidth};
|
|
117
|
+
height: ${triggerHeight};
|
|
118
|
+
${triggerMinWidth ? `min-width: ${triggerMinWidth};` : ""}
|
|
138
119
|
transition: width 0.3s ease, height 0.3s ease, border-radius 0.3s ease;
|
|
139
|
-
${this.getPositionStyles(config.position || "bottom-right",
|
|
140
|
-
display:
|
|
141
|
-
overflow:
|
|
120
|
+
${this.getPositionStyles(config.position || "bottom-right", true)}
|
|
121
|
+
display: none;
|
|
122
|
+
overflow: hidden;
|
|
142
123
|
box-sizing: border-box;
|
|
143
124
|
`;
|
|
144
|
-
// Create iframe
|
|
145
|
-
const
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
else {
|
|
263
|
-
iframe.style.boxShadow = "0 8px 32px rgba(0,0,0,0.15)";
|
|
264
|
-
}
|
|
265
|
-
iframe.setAttribute("allow", "clipboard-write");
|
|
266
|
-
iframe.setAttribute("title", "BuniAI Chat Widget");
|
|
267
|
-
iframe.onload = () => {
|
|
125
|
+
// Create inline trigger iframe (no src)
|
|
126
|
+
const triggerIframe = document.createElement("iframe");
|
|
127
|
+
triggerIframe.id = "buni-trigger-iframe";
|
|
128
|
+
triggerIframe.style.cssText = `
|
|
129
|
+
position: absolute;
|
|
130
|
+
top: 0;
|
|
131
|
+
left: 0;
|
|
132
|
+
border: none;
|
|
133
|
+
width: 100%;
|
|
134
|
+
height: 100%;
|
|
135
|
+
box-sizing: border-box;
|
|
136
|
+
border-radius: ${showTriggerText && hasTriggerText ? "26px" : "50%"};
|
|
137
|
+
transition: border-radius 0.3s ease, box-shadow 0.3s ease;
|
|
138
|
+
pointer-events: auto;
|
|
139
|
+
`;
|
|
140
|
+
triggerIframe.setAttribute("title", "BuniAI Chat Trigger");
|
|
141
|
+
// Inject trigger HTML content directly (no src)
|
|
142
|
+
container.appendChild(triggerIframe);
|
|
143
|
+
document.body.appendChild(container);
|
|
144
|
+
triggerIframe.onload = () => {
|
|
145
|
+
var _a;
|
|
146
|
+
const triggerDoc = triggerIframe.contentDocument ||
|
|
147
|
+
((_a = triggerIframe.contentWindow) === null || _a === void 0 ? void 0 : _a.document);
|
|
148
|
+
if (!triggerDoc) {
|
|
149
|
+
reject(new Error("Failed to access trigger iframe document"));
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
// Build inline HTML for trigger
|
|
153
|
+
const triggerHTML = this.buildTriggerHTML(primaryColor, triggerText || companyName, showTriggerText && hasTriggerText, config.customAvatar, config.avatarType, config.avatarText);
|
|
154
|
+
triggerDoc.open();
|
|
155
|
+
triggerDoc.write(triggerHTML);
|
|
156
|
+
triggerDoc.close();
|
|
157
|
+
// Create chat iframe (initially hidden)
|
|
158
|
+
const chatIframe = document.createElement("iframe");
|
|
159
|
+
chatIframe.id = "buni-chat-iframe";
|
|
160
|
+
// Build URL with configuration parameters
|
|
161
|
+
const params = new URLSearchParams({
|
|
162
|
+
token: this.options.token,
|
|
163
|
+
embedded: "true",
|
|
164
|
+
source: "package",
|
|
165
|
+
framework: this.options.framework || "vanilla",
|
|
166
|
+
});
|
|
167
|
+
// Add all configuration parameters
|
|
168
|
+
if (config.theme)
|
|
169
|
+
params.set("theme", config.theme);
|
|
170
|
+
if (config.primaryColor)
|
|
171
|
+
params.set("primaryColor", config.primaryColor);
|
|
172
|
+
if (config.secondaryColor)
|
|
173
|
+
params.set("secondaryColor", config.secondaryColor);
|
|
174
|
+
if (config.position)
|
|
175
|
+
params.set("position", config.position);
|
|
176
|
+
if (widthValue && config.width !== undefined)
|
|
177
|
+
params.set("width", widthValue);
|
|
178
|
+
if (heightValue && config.height !== undefined)
|
|
179
|
+
params.set("height", heightValue);
|
|
180
|
+
if (config.customAvatar)
|
|
181
|
+
params.set("customAvatar", config.customAvatar);
|
|
182
|
+
if (config.companyName)
|
|
183
|
+
params.set("companyName", config.companyName);
|
|
184
|
+
if (config.welcomeMessage)
|
|
185
|
+
params.set("welcomeMessage", config.welcomeMessage);
|
|
186
|
+
if (config.triggerText)
|
|
187
|
+
params.set("triggerText", config.triggerText);
|
|
188
|
+
if (config.borderRadius)
|
|
189
|
+
params.set("borderRadius", config.borderRadius);
|
|
190
|
+
if (config.avatarType)
|
|
191
|
+
params.set("avatarType", config.avatarType);
|
|
192
|
+
if (config.avatarText)
|
|
193
|
+
params.set("avatarText", config.avatarText);
|
|
194
|
+
// Boolean options
|
|
195
|
+
if (config.showBranding !== undefined)
|
|
196
|
+
params.set("showBranding", String(config.showBranding));
|
|
197
|
+
if (config.autoOpen !== undefined)
|
|
198
|
+
params.set("autoOpen", String(config.autoOpen));
|
|
199
|
+
if (config.allowMinimize !== undefined)
|
|
200
|
+
params.set("allowMinimize", String(config.allowMinimize));
|
|
201
|
+
if (config.showMinimize !== undefined)
|
|
202
|
+
params.set("showMinimize", String(config.showMinimize));
|
|
203
|
+
if (config.allowClose !== undefined)
|
|
204
|
+
params.set("allowClose", String(config.allowClose));
|
|
205
|
+
if (config.enableFileUpload !== undefined)
|
|
206
|
+
params.set("enableFileUpload", String(config.enableFileUpload));
|
|
207
|
+
if (config.showTimestamps !== undefined)
|
|
208
|
+
params.set("showTimestamps", String(config.showTimestamps));
|
|
209
|
+
if (config.enableMobile !== undefined)
|
|
210
|
+
params.set("enableMobile", String(config.enableMobile));
|
|
211
|
+
if (config.showPreChatForm !== undefined)
|
|
212
|
+
params.set("showPreChatForm", String(config.showPreChatForm));
|
|
213
|
+
if (config.showStartButton !== undefined)
|
|
214
|
+
params.set("showStartButton", String(config.showStartButton));
|
|
215
|
+
if (config.startButtonText)
|
|
216
|
+
params.set("startButtonText", config.startButtonText);
|
|
217
|
+
if (config.preChatFormFields)
|
|
218
|
+
params.set("preChatFormFields", JSON.stringify(config.preChatFormFields));
|
|
219
|
+
chatIframe.src = `${this.getBaseUrl()}/embed/chat?${params.toString()}`;
|
|
220
|
+
// Chat iframe styling - initially hidden
|
|
221
|
+
chatIframe.style.cssText = `
|
|
222
|
+
position: absolute;
|
|
223
|
+
top: 0;
|
|
224
|
+
left: 0;
|
|
225
|
+
border: none;
|
|
226
|
+
width: 100%;
|
|
227
|
+
height: 100%;
|
|
228
|
+
box-sizing: border-box;
|
|
229
|
+
border-radius: ${isMobile ? "0" : "16px"};
|
|
230
|
+
transition: border-radius 0.3s ease, box-shadow 0.3s ease;
|
|
231
|
+
pointer-events: auto;
|
|
232
|
+
box-shadow: ${isMobile ? "none" : "0 8px 32px rgba(0,0,0,0.15)"};
|
|
233
|
+
display: none;
|
|
234
|
+
`;
|
|
235
|
+
chatIframe.setAttribute("allow", "clipboard-write");
|
|
236
|
+
chatIframe.setAttribute("title", "BuniAI Chat Widget");
|
|
237
|
+
container.appendChild(chatIframe);
|
|
238
|
+
chatIframe.onload = () => {
|
|
239
|
+
// Set visibility hidden after iframe loads to allow content initialization
|
|
240
|
+
chatIframe.style.visibility = "hidden";
|
|
241
|
+
this.setupPostMessageAPI(chatIframe);
|
|
242
|
+
};
|
|
268
243
|
this.widgetElement = container;
|
|
269
|
-
this.
|
|
270
|
-
this.
|
|
271
|
-
this.
|
|
244
|
+
this.triggerIframe = triggerIframe;
|
|
245
|
+
this.chatIframe = chatIframe;
|
|
246
|
+
this.state.isMinimized = true;
|
|
247
|
+
this.state.isLoaded = true;
|
|
272
248
|
resolve();
|
|
273
249
|
};
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
250
|
+
// Trigger the load event
|
|
251
|
+
triggerIframe.src = "about:blank";
|
|
252
|
+
// Set up communication with trigger iframe
|
|
253
|
+
window.addEventListener("message", (event) => {
|
|
254
|
+
var _a;
|
|
255
|
+
// Check if message is from trigger iframe
|
|
256
|
+
if (event.data.type === "trigger_clicked" &&
|
|
257
|
+
event.source === triggerIframe.contentWindow) {
|
|
258
|
+
this.openChat();
|
|
259
|
+
}
|
|
260
|
+
// Check if message is connection_ready from chat iframe
|
|
261
|
+
if (event.data.type === "connection_ready" &&
|
|
262
|
+
event.source === ((_a = this.chatIframe) === null || _a === void 0 ? void 0 : _a.contentWindow)) {
|
|
263
|
+
// Connection is ready, show the trigger button
|
|
264
|
+
if (container && !config.hideDefaultTrigger) {
|
|
265
|
+
container.style.display = "block";
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
});
|
|
279
269
|
});
|
|
280
270
|
}
|
|
271
|
+
buildTriggerHTML(primaryColor, text, showText, customAvatar, avatarType, avatarText) {
|
|
272
|
+
const avatarContent = customAvatar
|
|
273
|
+
? `<img src="${customAvatar}" alt="Avatar" style="width: 32px; height: 32px; border-radius: 50%;" />`
|
|
274
|
+
: avatarType === "text" && avatarText
|
|
275
|
+
? `<div style="width: 32px; height: 32px; border-radius: 50%; background: rgba(255,255,255,0.3); display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 600; color: white;">${avatarText.substring(0, 2).toUpperCase()}</div>`
|
|
276
|
+
: `<svg width="28" height="28" viewBox="0 0 24 24" fill="white"><path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1 0-.9-2-2zm0 14H6l-2 2V4h16v12z"/></svg>`;
|
|
277
|
+
return `<!DOCTYPE html>
|
|
278
|
+
<html>
|
|
279
|
+
<head>
|
|
280
|
+
<meta charset="UTF-8">
|
|
281
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
282
|
+
<style>
|
|
283
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
284
|
+
body {
|
|
285
|
+
width: 100%;
|
|
286
|
+
height: 100%;
|
|
287
|
+
display: flex;
|
|
288
|
+
align-items: center;
|
|
289
|
+
justify-content: center;
|
|
290
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
291
|
+
overflow: hidden;
|
|
292
|
+
}
|
|
293
|
+
.trigger {
|
|
294
|
+
display: flex;
|
|
295
|
+
align-items: center;
|
|
296
|
+
justify-content: center;
|
|
297
|
+
gap: ${showText ? "12px" : "0"};
|
|
298
|
+
padding: ${showText ? "10px 20px" : "10px"};
|
|
299
|
+
background: ${primaryColor};
|
|
300
|
+
color: white;
|
|
301
|
+
border-radius: ${showText ? "26px" : "50%"};
|
|
302
|
+
cursor: pointer;
|
|
303
|
+
transition: all 0.3s ease;
|
|
304
|
+
box-shadow: 0 4px 16px rgba(0,0,0,0.15);
|
|
305
|
+
animation: pulse 2s infinite;
|
|
306
|
+
${showText ? "" : "width: 52px; height: 52px;"}
|
|
307
|
+
}
|
|
308
|
+
.trigger:hover {
|
|
309
|
+
transform: translateY(-2px);
|
|
310
|
+
filter: brightness(1.1);
|
|
311
|
+
box-shadow: 0 6px 24px ${primaryColor}99;
|
|
312
|
+
}
|
|
313
|
+
.trigger:active {
|
|
314
|
+
transform: translateY(0);
|
|
315
|
+
}
|
|
316
|
+
.avatar {
|
|
317
|
+
display: flex;
|
|
318
|
+
align-items: center;
|
|
319
|
+
justify-content: center;
|
|
320
|
+
flex-shrink: 0;
|
|
321
|
+
}
|
|
322
|
+
.text {
|
|
323
|
+
font-size: 14px;
|
|
324
|
+
font-weight: 600;
|
|
325
|
+
white-space: nowrap;
|
|
326
|
+
}
|
|
327
|
+
.badge {
|
|
328
|
+
position: absolute;
|
|
329
|
+
top: -4px;
|
|
330
|
+
right: -4px;
|
|
331
|
+
background: #f44336;
|
|
332
|
+
color: white;
|
|
333
|
+
border-radius: 10px;
|
|
334
|
+
padding: 2px 6px;
|
|
335
|
+
font-size: 11px;
|
|
336
|
+
font-weight: 600;
|
|
337
|
+
min-width: 18px;
|
|
338
|
+
text-align: center;
|
|
339
|
+
display: none;
|
|
340
|
+
animation: pulse 2s infinite;
|
|
341
|
+
}
|
|
342
|
+
.badge.show {
|
|
343
|
+
display: block;
|
|
344
|
+
}
|
|
345
|
+
@keyframes pulse {
|
|
346
|
+
0%, 100% {
|
|
347
|
+
transform: scale(1);
|
|
348
|
+
box-shadow: 0 4px 16px rgba(0,0,0,0.15);
|
|
349
|
+
}
|
|
350
|
+
50% {
|
|
351
|
+
transform: scale(1.02);
|
|
352
|
+
box-shadow: 0 6px 24px ${primaryColor}99;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
</style>
|
|
356
|
+
</head>
|
|
357
|
+
<body>
|
|
358
|
+
<div style="position: relative;">
|
|
359
|
+
<div class="trigger" onclick="handleClick()">
|
|
360
|
+
<div class="avatar">${avatarContent}</div>
|
|
361
|
+
${showText ? `<span class="text">${text}</span>` : ""}
|
|
362
|
+
</div>
|
|
363
|
+
<div class="badge" id="badge">0</div>
|
|
364
|
+
</div>
|
|
365
|
+
<script>
|
|
366
|
+
function handleClick() {
|
|
367
|
+
window.parent.postMessage({ type: 'trigger_clicked' }, '*');
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// Listen for unread count updates
|
|
371
|
+
window.addEventListener('message', function(event) {
|
|
372
|
+
if (event.data.type === 'updateUnreadCount') {
|
|
373
|
+
const badge = document.getElementById('badge');
|
|
374
|
+
const count = event.data.count || 0;
|
|
375
|
+
badge.textContent = count;
|
|
376
|
+
if (count > 0) {
|
|
377
|
+
badge.classList.add('show');
|
|
378
|
+
} else {
|
|
379
|
+
badge.classList.remove('show');
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
});
|
|
383
|
+
</script>
|
|
384
|
+
</body>
|
|
385
|
+
</html>`;
|
|
386
|
+
}
|
|
387
|
+
async openChat() {
|
|
388
|
+
if (!this.chatIframe || !this.widgetElement || !this.triggerIframe)
|
|
389
|
+
return;
|
|
390
|
+
if (this.state.isOpen)
|
|
391
|
+
return; // Already open
|
|
392
|
+
const config = this.options.config || {};
|
|
393
|
+
const isMobile = window.innerWidth <= 768;
|
|
394
|
+
const isTablet = window.innerWidth > 768 && window.innerWidth <= 1024;
|
|
395
|
+
const ensureUnits = (value, defaultValue) => {
|
|
396
|
+
if (!value)
|
|
397
|
+
return defaultValue;
|
|
398
|
+
const str = String(value);
|
|
399
|
+
if (str.match(/^[\d.]+\s*(px|em|rem|%|vh|vw)$/))
|
|
400
|
+
return str;
|
|
401
|
+
if (str.match(/^[\d.]+$/))
|
|
402
|
+
return `${str}px`;
|
|
403
|
+
return str;
|
|
404
|
+
};
|
|
405
|
+
const widthValue = ensureUnits(config.width, "350px");
|
|
406
|
+
const heightValue = ensureUnits(config.height, "650px");
|
|
407
|
+
// Calculate chat dimensions
|
|
408
|
+
const chatWidth = isMobile
|
|
409
|
+
? "100vw"
|
|
410
|
+
: isTablet
|
|
411
|
+
? "min(calc(100vw - 3rem), 370px)"
|
|
412
|
+
: widthValue;
|
|
413
|
+
const chatHeight = isMobile
|
|
414
|
+
? "100vh"
|
|
415
|
+
: isTablet
|
|
416
|
+
? "min(calc(100vh - 3rem), 620px)"
|
|
417
|
+
: heightValue;
|
|
418
|
+
// Resize container for chat
|
|
419
|
+
this.widgetElement.style.cssText = `
|
|
420
|
+
position: fixed;
|
|
421
|
+
pointer-events: none;
|
|
422
|
+
z-index: 999999;
|
|
423
|
+
width: ${chatWidth};
|
|
424
|
+
height: ${chatHeight};
|
|
425
|
+
${isMobile ? "max-width: 100vw; max-height: 100vh;" : ""}
|
|
426
|
+
transition: width 0.3s ease, height 0.3s ease, border-radius 0.3s ease;
|
|
427
|
+
${this.getPositionStyles(config.position || "bottom-right", false)}
|
|
428
|
+
display: block;
|
|
429
|
+
overflow: visible;
|
|
430
|
+
box-sizing: border-box;
|
|
431
|
+
`;
|
|
432
|
+
// Hide trigger, show chat
|
|
433
|
+
this.triggerIframe.style.display = "none";
|
|
434
|
+
this.chatIframe.style.display = "block";
|
|
435
|
+
this.chatIframe.style.visibility = "visible";
|
|
436
|
+
this.state.isMinimized = false;
|
|
437
|
+
this.state.isOpen = true;
|
|
438
|
+
this.emit("maximized", { timestamp: Date.now() });
|
|
439
|
+
}
|
|
440
|
+
closeChat() {
|
|
441
|
+
if (!this.chatIframe || !this.widgetElement || !this.triggerIframe)
|
|
442
|
+
return;
|
|
443
|
+
const config = this.options.config || {};
|
|
444
|
+
const showTriggerText = config.showTriggerText !== false;
|
|
445
|
+
const hasTriggerText = !!config.triggerText;
|
|
446
|
+
// Hide chat iframe
|
|
447
|
+
this.chatIframe.style.display = "none";
|
|
448
|
+
this.chatIframe.style.visibility = "hidden";
|
|
449
|
+
// Resize container back to trigger size
|
|
450
|
+
const triggerWidth = showTriggerText && hasTriggerText ? "auto" : "52px";
|
|
451
|
+
const triggerHeight = "52px";
|
|
452
|
+
const triggerMinWidth = showTriggerText && hasTriggerText ? "auto" : "";
|
|
453
|
+
this.widgetElement.style.cssText = `
|
|
454
|
+
position: fixed;
|
|
455
|
+
pointer-events: none;
|
|
456
|
+
z-index: 999999;
|
|
457
|
+
width: ${triggerWidth};
|
|
458
|
+
height: ${triggerHeight};
|
|
459
|
+
${triggerMinWidth ? `min-width: ${triggerMinWidth};` : ""}
|
|
460
|
+
transition: width 0.3s ease, height 0.3s ease, border-radius 0.3s ease;
|
|
461
|
+
${this.getPositionStyles(config.position || "bottom-right", true)}
|
|
462
|
+
display: block;
|
|
463
|
+
overflow: hidden;
|
|
464
|
+
box-sizing: border-box;
|
|
465
|
+
`;
|
|
466
|
+
// Show trigger again
|
|
467
|
+
this.triggerIframe.style.display = "block";
|
|
468
|
+
this.state.isMinimized = true;
|
|
469
|
+
this.state.isOpen = false;
|
|
470
|
+
this.emit("minimized", { timestamp: Date.now() });
|
|
471
|
+
}
|
|
281
472
|
getPositionStyles(position, isMinimized = false) {
|
|
282
473
|
// Responsive positioning following mobile-first best practices
|
|
283
474
|
const viewportWidth = window.innerWidth;
|
|
284
|
-
const isExtraSmall = viewportWidth <= 375;
|
|
285
475
|
const isMobile = viewportWidth <= 768;
|
|
286
476
|
const isTablet = viewportWidth > 768 && viewportWidth <= 1024;
|
|
287
477
|
// For extra small devices (Galaxy S8+, iPhone SE, etc.), use minimal or no margins
|
|
@@ -292,13 +482,9 @@ class BuniChatWidget {
|
|
|
292
482
|
// Minimized button always needs some space from edges
|
|
293
483
|
margin = isMobile ? "12px" : "20px";
|
|
294
484
|
}
|
|
295
|
-
else if (isExtraSmall) {
|
|
296
|
-
// Full screen on extra small devices (no margins)
|
|
297
|
-
margin = "0";
|
|
298
|
-
}
|
|
299
485
|
else if (isMobile) {
|
|
300
|
-
//
|
|
301
|
-
margin = "
|
|
486
|
+
// Full screen on all mobile devices (no margins)
|
|
487
|
+
margin = "0";
|
|
302
488
|
}
|
|
303
489
|
else if (isTablet) {
|
|
304
490
|
// Medium margins on tablets
|
|
@@ -308,18 +494,9 @@ class BuniChatWidget {
|
|
|
308
494
|
// Larger margins on desktop for floating effect
|
|
309
495
|
margin = "24px";
|
|
310
496
|
}
|
|
311
|
-
// On
|
|
312
|
-
if (
|
|
313
|
-
|
|
314
|
-
case "bottom-right":
|
|
315
|
-
case "bottom-left":
|
|
316
|
-
return `bottom: 0; left: 0; right: 0;`;
|
|
317
|
-
case "top-right":
|
|
318
|
-
case "top-left":
|
|
319
|
-
return `top: 0; left: 0; right: 0;`;
|
|
320
|
-
default:
|
|
321
|
-
return `bottom: 0; left: 0; right: 0;`;
|
|
322
|
-
}
|
|
497
|
+
// On mobile screens when not minimized, position at edges for full coverage
|
|
498
|
+
if (isMobile && !isMinimized) {
|
|
499
|
+
return `top: 0; left: 0; right: 0; bottom: 0;`;
|
|
323
500
|
}
|
|
324
501
|
// Standard positioning for larger screens or minimized state
|
|
325
502
|
switch (position) {
|
|
@@ -338,7 +515,7 @@ class BuniChatWidget {
|
|
|
338
515
|
setupPostMessageAPI(iframe) {
|
|
339
516
|
// Listen for messages from the iframe
|
|
340
517
|
window.addEventListener("message", (event) => {
|
|
341
|
-
var _a
|
|
518
|
+
var _a;
|
|
342
519
|
// Verify origin for security
|
|
343
520
|
if (event.origin !== this.getBaseUrl()) {
|
|
344
521
|
return;
|
|
@@ -369,60 +546,15 @@ class BuniChatWidget {
|
|
|
369
546
|
}
|
|
370
547
|
break;
|
|
371
548
|
case "minimized":
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
// Resize container to trigger button size when minimized
|
|
375
|
-
this.widgetElement.style.width = data.dimensions.width;
|
|
376
|
-
this.widgetElement.style.height = data.dimensions.height;
|
|
377
|
-
this.widgetElement.style.overflow = "hidden";
|
|
378
|
-
if (data.dimensions.minWidth) {
|
|
379
|
-
this.widgetElement.style.minWidth = data.dimensions.minWidth;
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
if (this.iframe) {
|
|
383
|
-
// Use circular border for icon-only, rounded for text button
|
|
384
|
-
this.iframe.style.borderRadius =
|
|
385
|
-
((_a = data.dimensions) === null || _a === void 0 ? void 0 : _a.width) === ((_b = data.dimensions) === null || _b === void 0 ? void 0 : _b.height)
|
|
386
|
-
? "50%"
|
|
387
|
-
: "26px";
|
|
388
|
-
}
|
|
389
|
-
this.emit("minimized", data);
|
|
549
|
+
// User clicked minimize in chat - close chat and show trigger
|
|
550
|
+
this.closeChat();
|
|
390
551
|
break;
|
|
391
|
-
case "
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
const config = this.options.config || {};
|
|
397
|
-
if (isMobile) {
|
|
398
|
-
// On mobile, enforce responsive sizing
|
|
399
|
-
this.widgetElement.style.width = "min(calc(100vw - 2rem), 370px)";
|
|
400
|
-
this.widgetElement.style.height =
|
|
401
|
-
"min(calc(100vh - 2rem), 680px)";
|
|
402
|
-
this.widgetElement.style.maxWidth = "370px";
|
|
403
|
-
this.widgetElement.style.maxHeight = "680px";
|
|
404
|
-
}
|
|
405
|
-
else {
|
|
406
|
-
// On desktop, respect custom dimensions
|
|
407
|
-
const ensureUnits = (value, defaultValue) => {
|
|
408
|
-
if (!value)
|
|
409
|
-
return defaultValue;
|
|
410
|
-
const str = String(value);
|
|
411
|
-
if (str.match(/^[\d.]+\s*(px|em|rem|%|vh|vw)$/))
|
|
412
|
-
return str;
|
|
413
|
-
if (str.match(/^[\d.]+$/))
|
|
414
|
-
return `${str}px`;
|
|
415
|
-
return str;
|
|
416
|
-
};
|
|
417
|
-
this.widgetElement.style.width = ensureUnits(config.width, "350px");
|
|
418
|
-
this.widgetElement.style.height = ensureUnits(config.height, "650px");
|
|
419
|
-
}
|
|
420
|
-
this.widgetElement.style.overflow = "visible";
|
|
421
|
-
}
|
|
422
|
-
if (this.iframe) {
|
|
423
|
-
this.iframe.style.borderRadius = "12px";
|
|
552
|
+
case "new_unread_message":
|
|
553
|
+
// Update unread count in trigger
|
|
554
|
+
this.state.unreadCount++;
|
|
555
|
+
if ((_a = this.triggerIframe) === null || _a === void 0 ? void 0 : _a.contentWindow) {
|
|
556
|
+
this.triggerIframe.contentWindow.postMessage({ type: "updateUnreadCount", count: this.state.unreadCount }, "*");
|
|
424
557
|
}
|
|
425
|
-
this.emit("maximized", data);
|
|
426
558
|
break;
|
|
427
559
|
case "customer_data_updated":
|
|
428
560
|
this.customerData = data;
|
|
@@ -443,8 +575,8 @@ class BuniChatWidget {
|
|
|
443
575
|
}
|
|
444
576
|
postMessageToWidget(type, data) {
|
|
445
577
|
var _a;
|
|
446
|
-
if (
|
|
447
|
-
|
|
578
|
+
if ((_a = this.chatIframe) === null || _a === void 0 ? void 0 : _a.contentWindow) {
|
|
579
|
+
this.chatIframe.contentWindow.postMessage({ type, data }, this.getBaseUrl());
|
|
448
580
|
}
|
|
449
581
|
}
|
|
450
582
|
getBaseUrl() {
|
|
@@ -457,44 +589,49 @@ class BuniChatWidget {
|
|
|
457
589
|
this.widgetElement.remove();
|
|
458
590
|
this.widgetElement = null;
|
|
459
591
|
}
|
|
592
|
+
this.triggerIframe = null;
|
|
593
|
+
this.chatIframe = null;
|
|
460
594
|
this.eventListeners.clear();
|
|
461
595
|
this.state.isLoaded = false;
|
|
462
596
|
this.customerData = null;
|
|
463
597
|
this.sessionVariables = null;
|
|
464
598
|
}
|
|
465
599
|
show() {
|
|
466
|
-
// Show the
|
|
467
|
-
if (this.widgetElement
|
|
600
|
+
// Show the widget container if it was hidden (hideDefaultTrigger mode)
|
|
601
|
+
if (this.widgetElement) {
|
|
468
602
|
this.widgetElement.style.display = "block";
|
|
469
603
|
}
|
|
470
|
-
|
|
471
|
-
this.state.isOpen
|
|
472
|
-
|
|
473
|
-
|
|
604
|
+
// Open chat if not already open
|
|
605
|
+
if (!this.chatIframe && !this.state.isOpen) {
|
|
606
|
+
this.openChat();
|
|
607
|
+
}
|
|
474
608
|
}
|
|
475
609
|
hide() {
|
|
476
610
|
var _a;
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
611
|
+
// Close chat if open
|
|
612
|
+
if (this.chatIframe) {
|
|
613
|
+
this.closeChat();
|
|
614
|
+
}
|
|
615
|
+
// If hideDefaultTrigger is enabled, completely hide the container
|
|
616
|
+
if (((_a = this.options.config) === null || _a === void 0 ? void 0 : _a.hideDefaultTrigger) && this.widgetElement) {
|
|
481
617
|
this.widgetElement.style.display = "none";
|
|
482
618
|
}
|
|
483
619
|
this.state.isOpen = false;
|
|
484
620
|
this.emit("visibility_changed", { visibility: "hidden" });
|
|
485
621
|
}
|
|
486
622
|
toggle() {
|
|
487
|
-
this.
|
|
623
|
+
if (this.chatIframe || this.state.isOpen) {
|
|
624
|
+
this.closeChat();
|
|
625
|
+
}
|
|
626
|
+
else {
|
|
627
|
+
this.openChat();
|
|
628
|
+
}
|
|
488
629
|
}
|
|
489
630
|
minimize() {
|
|
490
|
-
this.
|
|
491
|
-
this.state.isMinimized = true;
|
|
492
|
-
this.emit("minimized", { timestamp: Date.now() });
|
|
631
|
+
this.closeChat();
|
|
493
632
|
}
|
|
494
633
|
maximize() {
|
|
495
|
-
this.
|
|
496
|
-
this.state.isMinimized = false;
|
|
497
|
-
this.emit("maximized", { timestamp: Date.now() });
|
|
634
|
+
this.openChat();
|
|
498
635
|
}
|
|
499
636
|
setCustomerData(data) {
|
|
500
637
|
this.customerData = { ...this.customerData, ...data };
|