aumera-on-screen-widget 0.0.7 → 0.0.9
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/df-btn.js +159 -13
- package/package.json +1 -1
package/df-btn.js
CHANGED
|
@@ -34,7 +34,10 @@ if (!config.orgId) {
|
|
|
34
34
|
background-color: ${config.background || "#FEFFFF"};
|
|
35
35
|
border-radius: 24px;
|
|
36
36
|
cursor: pointer;
|
|
37
|
-
transition:
|
|
37
|
+
transition: none;
|
|
38
|
+
transform-origin: ${
|
|
39
|
+
config.position === "left" ? "bottom left" : "bottom right"
|
|
40
|
+
};
|
|
38
41
|
position: fixed;
|
|
39
42
|
bottom: 0px;
|
|
40
43
|
${config.position === "left" ? "left: 0px;" : "right: 0px;"}
|
|
@@ -130,7 +133,10 @@ if (!config.orgId) {
|
|
|
130
133
|
max-height: 75vh;
|
|
131
134
|
width: ${config.width || "414px"};
|
|
132
135
|
max-width: 414px;
|
|
133
|
-
transition:
|
|
136
|
+
transition: none;
|
|
137
|
+
transform-origin: ${
|
|
138
|
+
config.position === "left" ? "bottom left" : "bottom right"
|
|
139
|
+
};
|
|
134
140
|
${config.position === "left" ? "float: left;" : "float: right;"}
|
|
135
141
|
opacity: 1;
|
|
136
142
|
border-radius: 0 0 16px 16px;
|
|
@@ -160,20 +166,27 @@ if (!config.orgId) {
|
|
|
160
166
|
.df-btn.df-maximized {
|
|
161
167
|
width: 100vw !important;
|
|
162
168
|
height: 100vh !important;
|
|
169
|
+
height: 100dvh !important; /* Dynamic viewport height for mobile */
|
|
163
170
|
top: 0 !important;
|
|
164
|
-
left: 0 !important;
|
|
165
|
-
right: 0 !important;
|
|
171
|
+
${config.position === "left" ? "left: 0 !important;" : ""}
|
|
172
|
+
${config.position === "right" ? "right: 0 !important;" : ""}
|
|
166
173
|
bottom: 0 !important;
|
|
167
174
|
margin: 0 !important;
|
|
168
175
|
border-radius: 0 !important;
|
|
169
|
-
|
|
176
|
+
/* Handle safe areas on mobile devices */
|
|
177
|
+
padding-bottom: env(safe-area-inset-bottom, 0);
|
|
170
178
|
}
|
|
171
179
|
.df-btn.df-maximized .df-btn-content {
|
|
172
180
|
width: 100vw !important;
|
|
181
|
+
max-width: 100vw !important;
|
|
173
182
|
height: calc(100vh - 56px) !important;
|
|
183
|
+
height: calc(100dvh - env(safe-area-inset-bottom, 0px)) !important; /* Account for safe area */
|
|
184
|
+
max-height: calc(100vh - 56px) !important;
|
|
185
|
+
max-height: calc(100dvh - env(safe-area-inset-bottom, 0px)) !important;
|
|
174
186
|
opacity: 1 !important;
|
|
187
|
+
float: none !important;
|
|
175
188
|
display: block !important;
|
|
176
|
-
|
|
189
|
+
border-radius: 0 !important;
|
|
177
190
|
}
|
|
178
191
|
.df-btn.df-closed .df-btn-content {
|
|
179
192
|
width: 0 !important;
|
|
@@ -190,6 +203,17 @@ if (!config.orgId) {
|
|
|
190
203
|
justify-content: center;
|
|
191
204
|
}
|
|
192
205
|
|
|
206
|
+
/* Animation classes for FLIP */
|
|
207
|
+
.df-animating {
|
|
208
|
+
transition: transform .45s cubic-bezier(.4, 0, .2, 1);
|
|
209
|
+
will-change: transform;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.df-content-animating {
|
|
213
|
+
transition: opacity .45s cubic-bezier(.4, 0, .2, 1);
|
|
214
|
+
will-change: opacity;
|
|
215
|
+
}
|
|
216
|
+
|
|
193
217
|
@media screen and (max-width: 720px){
|
|
194
218
|
.df-btn {
|
|
195
219
|
border-radius: 28px;
|
|
@@ -197,13 +221,16 @@ if (!config.orgId) {
|
|
|
197
221
|
|
|
198
222
|
.df-btn:not(.df-closed) {
|
|
199
223
|
margin: 0px;
|
|
200
|
-
border-radius: 0px
|
|
224
|
+
border-radius: 0px;
|
|
225
|
+
padding-bottom: env(safe-area-inset-bottom, 0);
|
|
201
226
|
}
|
|
202
227
|
|
|
203
228
|
.df-btn:not(.df-closed) > .df-btn-content {
|
|
204
229
|
width: 100vw;
|
|
205
230
|
max-height: 100vh;
|
|
231
|
+
max-height: 100dvh;
|
|
206
232
|
height: calc(100vh - 56px);
|
|
233
|
+
height: calc(100dvh - 56px - env(safe-area-inset-bottom, 0px));
|
|
207
234
|
padding-bottom: 0px
|
|
208
235
|
}
|
|
209
236
|
|
|
@@ -272,6 +299,8 @@ if (!config.orgId) {
|
|
|
272
299
|
// Get the detected language
|
|
273
300
|
const detectedLang = getLanguage();
|
|
274
301
|
|
|
302
|
+
// Check if mobile device - removed unused variable
|
|
303
|
+
|
|
275
304
|
document.write(`
|
|
276
305
|
<button class="df-btn df-closed" onclick="dfToggle()">
|
|
277
306
|
${
|
|
@@ -282,7 +311,7 @@ if (!config.orgId) {
|
|
|
282
311
|
<div class="df-btn-header">
|
|
283
312
|
<div class="df-btn-text">${config.openText || "Chat"}</div>
|
|
284
313
|
</div>
|
|
285
|
-
<iframe class="df-btn-content" src="https://chat.
|
|
314
|
+
<iframe class="df-btn-content" src="https://chat.aumera.ai/${detectedLang}/?orgId=${
|
|
286
315
|
config.orgId
|
|
287
316
|
}" allow="microphone *"></iframe>
|
|
288
317
|
</button>
|
|
@@ -291,7 +320,6 @@ if (!config.orgId) {
|
|
|
291
320
|
let dfToggled = false;
|
|
292
321
|
let inactivityTimer = null;
|
|
293
322
|
let shakeInterval = null;
|
|
294
|
-
let maximized = false;
|
|
295
323
|
|
|
296
324
|
const startInactivityTimer = () => {
|
|
297
325
|
// Only start inactivity timer if button is closed
|
|
@@ -352,6 +380,9 @@ if (!config.orgId) {
|
|
|
352
380
|
if (btnText) btnText.innerText = "";
|
|
353
381
|
// remove right padding from df-btn-text
|
|
354
382
|
btnText.style.paddingRight = "0";
|
|
383
|
+
|
|
384
|
+
// Only add maximize/minimize button on desktop
|
|
385
|
+
|
|
355
386
|
// Add maximize/minimize button (right)
|
|
356
387
|
const maxBtn = document.createElement("div");
|
|
357
388
|
maxBtn.className = "maximize-minimize-btn";
|
|
@@ -369,6 +400,7 @@ if (!config.orgId) {
|
|
|
369
400
|
e.stopPropagation();
|
|
370
401
|
maximizeMinimize();
|
|
371
402
|
});
|
|
403
|
+
|
|
372
404
|
// Add close button (left)
|
|
373
405
|
const closeBtn = document.createElement("div");
|
|
374
406
|
closeBtn.className = "close-btn";
|
|
@@ -393,8 +425,56 @@ if (!config.orgId) {
|
|
|
393
425
|
function maximizeMinimize() {
|
|
394
426
|
const btn = document.querySelector(".df-btn");
|
|
395
427
|
if (!btn) return;
|
|
428
|
+
const content = btn.querySelector(".df-btn-content");
|
|
429
|
+
if (!content) return;
|
|
430
|
+
|
|
431
|
+
// FIRST: Capture current positions
|
|
432
|
+
const firstBtn = btn.getBoundingClientRect();
|
|
433
|
+
|
|
434
|
+
// Toggle the maximized state (instant layout change)
|
|
396
435
|
btn.classList.toggle("df-maximized");
|
|
397
|
-
|
|
436
|
+
|
|
437
|
+
// LAST: Capture new positions
|
|
438
|
+
const lastBtn = btn.getBoundingClientRect();
|
|
439
|
+
|
|
440
|
+
// INVERT: Calculate the delta and apply transform to invert to original position
|
|
441
|
+
const btnDeltaX = firstBtn.left - lastBtn.left;
|
|
442
|
+
const btnDeltaY = firstBtn.top - lastBtn.top;
|
|
443
|
+
const btnScaleX = firstBtn.width / Math.max(lastBtn.width, 0.0001);
|
|
444
|
+
const btnScaleY = firstBtn.height / Math.max(lastBtn.height, 0.0001);
|
|
445
|
+
|
|
446
|
+
// Apply inverted transform
|
|
447
|
+
btn.style.transform = `translate(${btnDeltaX}px, ${btnDeltaY}px) scale(${btnScaleX}, ${btnScaleY})`;
|
|
448
|
+
|
|
449
|
+
// Optional: Soften iframe reflow with opacity
|
|
450
|
+
content.classList.add("df-content-animating");
|
|
451
|
+
content.style.opacity = "0.95";
|
|
452
|
+
|
|
453
|
+
// Force reflow to ensure the inverted state is applied
|
|
454
|
+
btn.getBoundingClientRect();
|
|
455
|
+
|
|
456
|
+
// PLAY: Add animation class and clear transform to animate to identity
|
|
457
|
+
btn.classList.add("df-animating");
|
|
458
|
+
btn.style.transform = "";
|
|
459
|
+
|
|
460
|
+
// Cleanup after animation ends
|
|
461
|
+
const onTransitionEnd = (e) => {
|
|
462
|
+
if (e.target !== btn) return;
|
|
463
|
+
btn.classList.remove("df-animating");
|
|
464
|
+
content.classList.remove("df-content-animating");
|
|
465
|
+
content.style.opacity = "";
|
|
466
|
+
updateHeaderButtons();
|
|
467
|
+
};
|
|
468
|
+
|
|
469
|
+
btn.addEventListener("transitionend", onTransitionEnd, { once: true });
|
|
470
|
+
|
|
471
|
+
// Fallback cleanup in case transition doesn't fire
|
|
472
|
+
setTimeout(() => {
|
|
473
|
+
btn.classList.remove("df-animating");
|
|
474
|
+
content.classList.remove("df-content-animating");
|
|
475
|
+
content.style.opacity = "";
|
|
476
|
+
updateHeaderButtons();
|
|
477
|
+
}, 500);
|
|
398
478
|
}
|
|
399
479
|
|
|
400
480
|
function dfToggle() {
|
|
@@ -418,14 +498,80 @@ if (!config.orgId) {
|
|
|
418
498
|
// Remove onclick from button, handle open/close in JS
|
|
419
499
|
const btn = document.querySelector(".df-btn");
|
|
420
500
|
btn.onclick = null;
|
|
421
|
-
|
|
501
|
+
|
|
502
|
+
// Check if mobile for later use
|
|
503
|
+
const isMobile = window.innerWidth <= 768;
|
|
504
|
+
|
|
505
|
+
btn.addEventListener("click", () => {
|
|
422
506
|
// Only toggle if chat is closed (popover mode)
|
|
423
507
|
if (btn.classList.contains("df-closed")) {
|
|
424
|
-
|
|
508
|
+
const isMobile = window.innerWidth <= 768;
|
|
509
|
+
|
|
510
|
+
if (isMobile) {
|
|
511
|
+
// On mobile, apply FLIP animation for open+maximize
|
|
512
|
+
const content = btn.querySelector(".df-btn-content");
|
|
513
|
+
|
|
514
|
+
// FIRST: Capture current (closed) position
|
|
515
|
+
const firstBtn = btn.getBoundingClientRect();
|
|
516
|
+
|
|
517
|
+
// Open and maximize instantly
|
|
518
|
+
btn.classList.remove("df-closed");
|
|
519
|
+
btn.classList.add("df-maximized");
|
|
520
|
+
|
|
521
|
+
// LAST: Capture final position
|
|
522
|
+
const lastBtn = btn.getBoundingClientRect();
|
|
523
|
+
|
|
524
|
+
// INVERT
|
|
525
|
+
const btnDeltaX = firstBtn.left - lastBtn.left;
|
|
526
|
+
const btnDeltaY = firstBtn.top - lastBtn.top;
|
|
527
|
+
const btnScaleX = firstBtn.width / Math.max(lastBtn.width, 0.0001);
|
|
528
|
+
const btnScaleY = firstBtn.height / Math.max(lastBtn.height, 0.0001);
|
|
529
|
+
|
|
530
|
+
btn.style.transform = `translate(${btnDeltaX}px, ${btnDeltaY}px) scale(${btnScaleX}, ${btnScaleY})`;
|
|
531
|
+
|
|
532
|
+
if (content) {
|
|
533
|
+
content.classList.add("df-content-animating");
|
|
534
|
+
content.style.opacity = "0.95";
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
// Force reflow
|
|
538
|
+
btn.getBoundingClientRect();
|
|
539
|
+
|
|
540
|
+
// PLAY
|
|
541
|
+
btn.classList.add("df-animating");
|
|
542
|
+
btn.style.transform = "";
|
|
543
|
+
|
|
544
|
+
// Cleanup
|
|
545
|
+
const onTransitionEnd = () => {
|
|
546
|
+
btn.classList.remove("df-animating");
|
|
547
|
+
if (content) {
|
|
548
|
+
content.classList.remove("df-content-animating");
|
|
549
|
+
content.style.opacity = "";
|
|
550
|
+
}
|
|
551
|
+
updateHeaderButtons();
|
|
552
|
+
};
|
|
553
|
+
|
|
554
|
+
btn.addEventListener("transitionend", onTransitionEnd, { once: true });
|
|
555
|
+
|
|
556
|
+
setTimeout(() => {
|
|
557
|
+
btn.classList.remove("df-animating");
|
|
558
|
+
if (content) {
|
|
559
|
+
content.classList.remove("df-content-animating");
|
|
560
|
+
content.style.opacity = "";
|
|
561
|
+
}
|
|
562
|
+
updateHeaderButtons();
|
|
563
|
+
}, 500);
|
|
564
|
+
} else {
|
|
565
|
+
// Desktop: just toggle open
|
|
566
|
+
dfToggle();
|
|
567
|
+
}
|
|
425
568
|
}
|
|
426
569
|
// If open, do nothing (let header buttons handle maximize/minimize/close)
|
|
427
570
|
});
|
|
428
571
|
|
|
429
572
|
// Start the inactivity timer when the page loads (button is initially closed)
|
|
430
|
-
|
|
573
|
+
// But not on mobile since it starts open
|
|
574
|
+
if (!isMobile) {
|
|
575
|
+
startInactivityTimer();
|
|
576
|
+
}
|
|
431
577
|
}
|