@rxxuzi/gumi
Version:
Clean & minimal design system with delightful interactions
125 lines • 4.34 kB
JavaScript
// toast.ts
// Beautiful toast notifications
import * as dom from '../core/dom';
export class Toast {
/**
* Show a toast notification
*/
static show(message, options = {}) {
const config = {
type: 'info',
duration: 4000,
position: 'top-right',
...options
};
const id = `toast-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
// Create container if needed
this.createContainer(config.position);
// Create toast element
const toast = dom.createElement('div', {
className: `gumi-toast ${config.type} entering`,
html: `
${this.getIcon(config.type)}
<span>${message}</span>
`
});
// Store reference
this.toasts.set(id, toast);
// Add to container
this.container.appendChild(toast);
// Auto-remove after duration
setTimeout(() => {
this.remove(id);
}, config.duration);
// Click to dismiss
dom.on(toast, 'click', () => {
this.remove(id);
});
// Trigger custom event
dom.trigger(document.body, 'gumi-toast-show', {
id,
message,
type: config.type
});
return id;
}
/**
* Remove a specific toast
*/
static remove(id) {
const toast = this.toasts.get(id);
if (!toast)
return;
dom.removeClass(toast, 'entering');
dom.addClass(toast, 'exiting');
setTimeout(() => {
if (toast.parentNode) {
toast.parentNode.removeChild(toast);
}
this.toasts.delete(id);
}, 200);
dom.trigger(document.body, 'gumi-toast-hide', { id });
}
/**
* Remove all toasts
*/
static removeAll() {
Array.from(this.toasts.keys()).forEach(id => this.remove(id));
}
/**
* Create container for toasts
*/
static createContainer(position) {
if (this.container)
return;
this.container = dom.createElement('div', {
className: `gumi-toast-container ${position}`
});
document.body.appendChild(this.container);
}
/**
* Get icon for toast type
*/
static getIcon(type) {
const icons = {
success: `<svg class="toast-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M9 12l2 2 4-4"></path>
<circle cx="12" cy="12" r="9"></circle>
</svg>`,
error: `<svg class="toast-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="9"></circle>
<line x1="15" y1="9" x2="9" y2="15"></line>
<line x1="9" y1="9" x2="15" y2="15"></line>
</svg>`,
warning: `<svg class="toast-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"></path>
<line x1="12" y1="9" x2="12" y2="13"></line>
<line x1="12" y1="17" x2="12.01" y2="17"></line>
</svg>`,
info: `<svg class="toast-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="9"></circle>
<line x1="12" y1="8" x2="12" y2="12"></line>
<line x1="12" y1="16" x2="12.01" y2="16"></line>
</svg>`
};
return icons[type] || icons.info;
}
/**
* Helper methods for different toast types
*/
static success(message, options = {}) {
return this.show(message, { ...options, type: 'success' });
}
static error(message, options = {}) {
return this.show(message, { ...options, type: 'error' });
}
static warning(message, options = {}) {
return this.show(message, { ...options, type: 'warning' });
}
static info(message, options = {}) {
return this.show(message, { ...options, type: 'info' });
}
}
Toast.container = null;
Toast.toasts = new Map();
//# sourceMappingURL=toast.js.map