@ussebastian/kitdigital
Version:
Kit Digital de la Universidad San Sebastián
138 lines (119 loc) • 4.52 kB
JavaScript
export class Toast {
constructor(data, type = 'success', time = null) {
this.data = data;
this.type = type;
this.time = time;
this.closing = false; // Instance-specific closing flag
this.icons = {
success: ' <i class="uss-icon uss-icon--xl ri-checkbox-circle-line"></i>',
info: ' <i class="uss-icon uss-icon--xl ri-information-line"></i>',
warning: ' <i class="uss-icon uss-icon--xl ri-alert-line"></i>',
error: ' <i class="uss-icon uss-icon--xl ri-information-line"></i>',
};
this.selectedIcon = this.icons[type];
this.toastContainer = null;
this.getOrCreateToastContainer();
this.toastElement = this.createAndConfigureToastElement();
this.stoppedTimer = false;
this.toastContainer.addEventListener('mouseenter', () => {
this.stoppedTimer = true;
});
this.toastContainer.addEventListener('mouseleave', () => {
this.stoppedTimer = false;
});
}
setupTimer() {
const interval = setInterval(() => {
if (this.stoppedTimer) {
return;
}
this.time -= 100; // Decrement time by 100ms each interval
if (this.time <= 0) {
clearInterval(interval);
this.closeToast();
}
}, 100); // Run this interval every 100ms
}
getOrCreateToastContainer() {
this.toastContainer = document.querySelector('.uss-toast-container');
if (!this.toastContainer) {
this.toastContainer = document.createElement('div');
this.toastContainer.className = 'uss-toast-container';
document.body.appendChild(this.toastContainer);
}
}
createAndConfigureToastElement() {
const toast = document.createElement('div');
toast.className = `uss-toast uss-toast--${this.type}`;
// const icon = this.icons[this.type];
toast.innerHTML = `
${this.selectedIcon}
<div class="uss-toast__content">
<div class="uss-h6 ">${this.data.title}</div>
${this.data.description ? `<p class="mb-12 pt-4">${this.data.description}</p>` : ``}
${
this.data.action
? `<button class="uss-btn uss-btn--tertiary">${this.data.action.label}</button>`
: ``
}
</div>
`;
const actionBtn = toast.querySelector('button');
if (actionBtn) actionBtn.addEventListener('click', this.data.action.fn);
const closeButton = document.createElement('button');
closeButton.className = 'uss-toast__close-btn';
closeButton.innerHTML =
'<i class="uss-icon uss-icon--md ri-close-line" style="color: var(--text-strong)"></i>';
closeButton.onclick = () => this.closeToast();
toast.appendChild(closeButton);
return toast;
}
openToast() {
// Get toast height and show toast
this.toastContainer.prepend(this.toastElement);
const mb = 20; // margin bottom
const toastHeight = this.toastElement.offsetHeight + mb;
this.toastContainer.style.transition = `transform 0ms ease`;
this.toastContainer.style.transform = `translateY(${toastHeight}px)`;
setTimeout(() => {
this.toastContainer.style.transition = `transform 100ms ease`;
this.toastContainer.style.transform = `translateY(0px)`;
if (this.time) this.setupTimer();
}, 0);
}
async closeToast() {
if (this.closing) return;
this.stoppedTimer = true;
this.closing = true;
this.toastElement.style.transition = `all 400ms ease`;
this.toastElement.style.scale = '0.01';
this.toastElement.style.transform = `transformY(1000px)`;
this.toastElement.style.height = `${this.toastElement.offsetHeight}px`;
this.toastElement.style.margin = `0px`;
await this.animateHeightReduction(100);
setTimeout(() => {
this.toastElement.remove();
this.closing = false;
}, 250);
}
async animateHeightReduction(totalDuration) {
const initialHeight = parseInt(this.toastElement.style.height, 10);
const startTime = performance.now();
const step = (currentTime) => {
const elapsedTime = currentTime - startTime;
const progress = elapsedTime / totalDuration;
if (progress < 1) {
const newHeight = Math.max(initialHeight * (1 - progress), 0);
this.toastElement.style.height = `${newHeight}px`;
requestAnimationFrame(step);
} else {
this.toastElement.style.height = '0px';
}
};
requestAnimationFrame(step);
}
static show(data, type, time) {
const toast = new Toast(data, type, time);
toast.openToast();
}
}