UNPKG

@ussebastian/kitdigital

Version:

Kit Digital de la Universidad San Sebastián

138 lines (119 loc) 4.52 kB
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(); } }