/**
* @fileoverview Toast Notification Component for Rantii
* @author retoor <retoor@molodetz.nl>
* @description Non-intrusive notification messages for user feedback
* @keywords toast, notification, alert, message, feedback
*/
import { BaseComponent } from './base-component.js';
class ToastNotification extends BaseComponent {
static get observedAttributes() {
return ['type', 'message', 'duration'];
}
init() {
this.autoHideTimer = null;
this.render();
}
render() {
const type = this.getAttr('type') || 'info';
const message = this.getAttr('message') || '';
this.addClass('toast', `toast-${type}`);
this.setHtml(`
<div class="toast-content">
<span class="toast-icon">${this.getIcon(type)}</span>
<span class="toast-message">${message}</span>
<button class="toast-close" aria-label="Close">
<svg viewBox="0 0 24 24" width="18" height="18">
<path fill="currentColor" d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/>
</svg>
</button>
</div>
`);
this.bindEvents();
this.startAutoHide();
}
getIcon(type) {
const icons = {
success: `<svg viewBox="0 0 24 24" width="20" height="20"><path fill="currentColor" d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>`,
error: `<svg viewBox="0 0 24 24" width="20" height="20"><path fill="currentColor" d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"/></svg>`,
warning: `<svg viewBox="0 0 24 24" width="20" height="20"><path fill="currentColor" d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"/></svg>`,
info: `<svg viewBox="0 0 24 24" width="20" height="20"><path fill="currentColor" d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/></svg>`
};
return icons[type] || icons.info;
}
bindEvents() {
const closeBtn = this.$('.toast-close');
if (closeBtn) {
this.on(closeBtn, 'click', () => this.dismiss());
}
}
startAutoHide() {
const duration = parseInt(this.getAttr('duration') || '4000', 10);
if (duration > 0) {
this.autoHideTimer = setTimeout(() => this.dismiss(), duration);
}
}
dismiss() {
if (this.autoHideTimer) {
clearTimeout(this.autoHideTimer);
}
this.addClass('toast-hiding');
setTimeout(() => {
this.emit('toast-dismissed');
this.remove();
}, 300);
}
show(message, type = 'info', duration = 4000) {
this.setAttr('message', message);
this.setAttr('type', type);
this.setAttr('duration', duration.toString());
this.render();
}
}
customElements.define('toast-notification', ToastNotification);
class ToastContainer extends BaseComponent {
init() {
this.addClass('toast-container');
}
show(message, type = 'info', duration = 4000) {
const toast = document.createElement('toast-notification');
toast.setAttribute('message', message);
toast.setAttribute('type', type);
toast.setAttribute('duration', duration.toString());
this.appendChild(toast);
return toast;
}
success(message, duration = 4000) {
return this.show(message, 'success', duration);
}
error(message, duration = 5000) {
return this.show(message, 'error', duration);
}
warning(message, duration = 4000) {
return this.show(message, 'warning', duration);
}
info(message, duration = 4000) {
return this.show(message, 'info', duration);
}
clearAll() {
this.innerHTML = '';
}
}
customElements.define('toast-container', ToastContainer);
export { ToastNotification, ToastContainer };