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