/** * High-contrast mode toggle with localStorage persistence. */ import { warnOnce, resolveHost } from '../core/app-dom.js'; import { createUiStorage } from '../core/app-ui-storage.js'; const STORAGE_KEY = 'contrast-mode'; const setContrast = (contrast) => { const root = document.documentElement; root.dataset.contrast = contrast === 'high' ? 'high' : 'normal'; }; const setIcon = (button, contrast) => { const icon = button.querySelector('i'); if (!icon) { return; } icon.classList.remove('bi-circle-half', 'bi-highlights'); icon.classList.add(contrast === 'high' ? 'bi-highlights' : 'bi-circle-half'); }; const setPressedState = (button, contrast) => { button.setAttribute('aria-pressed', contrast === 'high' ? 'true' : 'false'); }; export function initContrastToggle(root = document, options = {}) { const selector = String(options.selector || '[data-contrast-toggle]').trim() || '[data-contrast-toggle]'; const storage = createUiStorage({ namespace: options.storageNamespace || 'app-ui', version: options.storageVersion || 'v1', scope: options.storageScope || 'contrast', }); const scopedStorageKey = storage.buildKey('state', options.storageKey || STORAGE_KEY); const host = resolveHost(root); const button = host.matches?.(selector) ? host : host.querySelector(selector); if (!(button instanceof HTMLElement)) { warnOnce('UI_EL_MISSING', `Missing contrast toggle: ${selector}`, { module: 'contrast-toggle' }); return { destroy: () => {} }; } if (button.dataset.contrastToggleBound === '1') { return { destroy: () => { delete button.dataset.contrastToggleBound; }, }; } button.dataset.contrastToggleBound = '1'; const getCurrent = () => (document.documentElement.dataset.contrast === 'high' ? 'high' : 'normal'); const current = getCurrent(); setIcon(button, current); setPressedState(button, current); const onClick = () => { const next = getCurrent() === 'high' ? 'normal' : 'high'; setContrast(next); setIcon(button, next); setPressedState(button, next); storage.setItem(scopedStorageKey, next); }; button.addEventListener('click', onClick); const destroy = () => { button.removeEventListener('click', onClick); delete button.dataset.contrastToggleBound; }; return { destroy }; }