Files
breadcrumb-the-shire/web/js/components/app-async-flash.js
2026-02-04 23:31:53 +01:00

90 lines
2.3 KiB
JavaScript

/**
* Async Flash Messages & Loading State
* Renders flash messages into #async-messages for JS-triggered notifications
* Provides loading cursor state management
*/
/**
* Set global loading state (cursor + pointer-events)
* @param {boolean} loading - Whether to show loading state
*/
export function setLoading(loading) {
if (loading) {
document.body.classList.add('is-loading');
} else {
document.body.classList.remove('is-loading');
}
}
/**
* Execute an async function with loading state
* @param {Function} fn - Async function to execute
* @returns {Promise<any>} - Result of the function
*/
export async function withLoading(fn) {
setLoading(true);
try {
return await fn();
} finally {
setLoading(false);
}
}
const defaultTimeouts = {
success: 10000,
info: 10000,
warning: 10000,
error: 0
};
/**
* Show an async flash message
* @param {string} type - Message type: 'success', 'info', 'warning', 'error'
* @param {string} message - The message text
* @param {number} [timeout] - Auto-dismiss timeout in ms (0 = no auto-dismiss)
*/
export function showAsyncFlash(type, message, timeout) {
const container = document.getElementById('async-messages');
if (!container) {
console.warn('async-messages container not found');
return null;
}
const effectiveTimeout = timeout ?? defaultTimeouts[type] ?? 5000;
const notice = document.createElement('div');
notice.className = 'notice';
notice.setAttribute('data-variant', type);
const messageSpan = document.createElement('span');
messageSpan.textContent = message;
notice.appendChild(messageSpan);
const closeButton = document.createElement('button');
closeButton.type = 'button';
closeButton.className = 'contrast outline small';
closeButton.innerHTML = '<i class="bi bi-x"></i>';
closeButton.addEventListener('click', () => notice.remove());
notice.appendChild(closeButton);
container.appendChild(notice);
if (effectiveTimeout > 0) {
notice.style.setProperty('--flash-timeout', `${effectiveTimeout}ms`);
notice.classList.add('flash-timed');
setTimeout(() => notice.remove(), effectiveTimeout);
}
return notice;
}
/**
* Clear all async flash messages
*/
export function clearAsyncFlash() {
const container = document.getElementById('async-messages');
if (container) {
container.innerHTML = '';
}
}