UNPKG

ksk-core

Version:

Core design system components and styles for Kickstart projects

223 lines (188 loc) 6.02 kB
/** * Alert JavaScript functionality * Handles dismissible alerts, animations, and accessibility */ class AlertComponent { constructor(element) { this.element = element; this.closeButton = element.querySelector('.ast-alert__close'); this.isDismissed = false; this.init(); } init() { this.setupEventListeners(); this.animateIn(); } setupEventListeners() { if (this.closeButton) { this.closeButton.addEventListener('click', (e) => { e.preventDefault(); this.dismiss(); }); // Keyboard support for close button this.closeButton.addEventListener('keydown', (e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); this.dismiss(); } }); } // Auto-dismiss after timeout (if specified) const autoDismiss = this.element.getAttribute('data-auto-dismiss'); if (autoDismiss) { const timeout = parseInt(autoDismiss) || 5000; setTimeout(() => { if (!this.isDismissed) { this.dismiss(); } }, timeout); } } animateIn() { // Add entering class for animation this.element.classList.add('ast-alert--entering'); // Use requestAnimationFrame to ensure the class is applied requestAnimationFrame(() => { this.element.classList.remove('ast-alert--entering'); this.element.classList.add('ast-alert--entered'); }); } dismiss() { if (this.isDismissed) return; this.isDismissed = true; // Custom event for dismiss const dismissEvent = new CustomEvent('alert:dismiss', { detail: { type: this.getAlertType(), element: this.element }, bubbles: true }); this.element.dispatchEvent(dismissEvent); // Animate out this.element.classList.add('ast-alert--exiting'); // Remove from DOM after animation setTimeout(() => { if (this.element.parentNode) { this.element.remove(); } }, 300); } getAlertType() { const classes = this.element.className.split(' '); const typeClass = classes.find(cls => cls.startsWith('ast-alert--') && cls !== 'ast-alert--entering' && cls !== 'ast-alert--entered' && cls !== 'ast-alert--exiting'); return typeClass ? typeClass.replace('ast-alert--', '') : 'info'; } // Public API methods show() { this.element.style.display = ''; this.animateIn(); } hide() { this.dismiss(); } updateContent(content) { const contentElement = this.element.querySelector('.ast-alert__content') || this.element; if (this.closeButton) { // Update content while preserving close button const tempDiv = document.createElement('div'); tempDiv.innerHTML = content; contentElement.innerHTML = ''; while (tempDiv.firstChild) { contentElement.appendChild(tempDiv.firstChild); } contentElement.appendChild(this.closeButton); } else { contentElement.innerHTML = content; } } } // Alert Manager for programmatic alert creation class AlertManager { constructor() { this.container = null; this.init(); } init() { // Create alert container if it doesn't exist this.container = document.getElementById('alert-container'); if (!this.container) { this.container = document.createElement('div'); this.container.id = 'alert-container'; this.container.className = 'alert-container'; this.container.setAttribute('aria-live', 'polite'); document.body.insertBefore(this.container, document.body.firstChild); } } create(options) { const { type = 'info', message = '', dismissible = true, autoDismiss = null, focus = false } = options; const alertElement = document.createElement('div'); alertElement.className = `ast-alert ast-alert--${type}`; alertElement.setAttribute('role', 'alert'); alertElement.innerHTML = message; if (dismissible) { const closeButton = document.createElement('button'); closeButton.className = 'ast-alert__close'; closeButton.setAttribute('aria-label', 'Close alert'); closeButton.innerHTML = '×'; alertElement.appendChild(closeButton); } if (autoDismiss) { alertElement.setAttribute('data-auto-dismiss', autoDismiss.toString()); } if (focus) { alertElement.setAttribute('data-focus', 'true'); } this.container.appendChild(alertElement); // Initialize the alert component const alertComponent = new AlertComponent(alertElement); alertElement.alertComponent = alertComponent; return alertComponent; } // Convenience methods info(message, options = {}) { return this.create({ ...options, type: 'info', message }); } success(message, options = {}) { return this.create({ ...options, type: 'success', message }); } warning(message, options = {}) { return this.create({ ...options, type: 'warning', message }); } error(message, options = {}) { return this.create({ ...options, type: 'error', message, focus: true }); } dismissAll() { const alerts = this.container.querySelectorAll('.ast-alert'); alerts.forEach(alert => { if (alert.alertComponent) { alert.alertComponent.dismiss(); } }); } } // Auto-initialize existing alerts if (typeof document !== 'undefined') { document.addEventListener('DOMContentLoaded', () => { const alerts = document.querySelectorAll('.ast-alert'); alerts.forEach(alert => { if (!alert.alertComponent) { alert.alertComponent = new AlertComponent(alert); } }); }); } // Auto-init function for manual initialization const initAlert = () => { const alerts = document.querySelectorAll('.ast-alert'); alerts.forEach(alert => { if (!alert.alertComponent) { alert.alertComponent = new AlertComponent(alert); } }); }; // Export both the classes and the init function export { AlertComponent, AlertManager, initAlert };