/** * Offline indicator UI. * * Mounts a small fixed badge in the corner of the page that appears when the * browser reports `navigator.onLine === false` and hides when back online. * Listens to `online` and `offline` window events so it reacts immediately. * * Usage: * import { mountOfflineIndicator } from '../lib/offline-indicator.js'; * mountOfflineIndicator(); */ const BADGE_ID = 'atmos-offline-badge'; let mounted = false; let onlineHandler: (() => void) | null = null; let offlineHandler: (() => void) | null = null; function ensureBadge(): HTMLElement | null { if (typeof document === 'undefined') return null; let badge = document.getElementById(BADGE_ID); if (badge) return badge; badge = document.createElement('div'); badge.id = BADGE_ID; badge.className = 'offline-badge'; badge.setAttribute('role', 'status'); badge.setAttribute('aria-live', 'polite'); badge.innerHTML = 'Offline'; badge.style.display = 'none'; document.body.appendChild(badge); return badge; } function update(): void { const badge = ensureBadge(); if (!badge) return; const online = typeof navigator !== 'undefined' ? navigator.onLine !== false : true; badge.style.display = online ? 'none' : 'flex'; } /** * Mount the offline indicator. Safe to call multiple times — only wires * listeners once. Returns an unmount function for tests. */ export function mountOfflineIndicator(): () => void { if (mounted) return unmountOfflineIndicator; mounted = true; ensureBadge(); update(); if (typeof window !== 'undefined') { onlineHandler = () => update(); offlineHandler = () => update(); window.addEventListener('online', onlineHandler); window.addEventListener('offline', offlineHandler); } return unmountOfflineIndicator; } /** Remove the badge and its listeners. Exposed for tests. */ export function unmountOfflineIndicator(): void { if (!mounted) return; mounted = false; if (typeof window !== 'undefined') { if (onlineHandler) window.removeEventListener('online', onlineHandler); if (offlineHandler) window.removeEventListener('offline', offlineHandler); } onlineHandler = null; offlineHandler = null; const badge = typeof document !== 'undefined' ? document.getElementById(BADGE_ID) : null; if (badge) badge.remove(); } /** Returns true if the browser reports offline. Stable wrapper for tests. */ export function isOffline(): boolean { return typeof navigator !== 'undefined' && navigator.onLine === false; }