import './core/app-telemetry.js'; import { createComponentRuntime } from './core/app-component-runtime.js'; import { resolveHost } from './core/app-dom.js'; import { initFlashAutoDismiss } from './components/app-flash-auto-dismiss.js'; import { initPasswordHints } from './components/app-password-hints.js'; import { initPasswordToggles } from './components/app-password-toggle.js'; const initLoginErrorFocus = (root = document, config = {}) => { const host = resolveHost(root); const selector = String(config.selector || '.notice[data-variant="error"][role="alert"][tabindex="-1"]').trim() || '.notice[data-variant="error"][role="alert"][tabindex="-1"]'; const errorNotice = host.querySelector(selector); if (errorNotice instanceof HTMLElement) { errorNotice.focus(); } return { destroy: () => {} }; }; const initLoginSubmitLock = (root = document, config = {}) => { const host = resolveHost(root); const selector = String(config.selector || 'form[data-login-submit-lock="1"]').trim() || 'form[data-login-submit-lock="1"]'; const forms = Array.from(host.querySelectorAll(selector)).filter( (form) => form instanceof HTMLFormElement ); if (!forms.length) { return { destroy: () => {} }; } const cleanupFns = []; forms.forEach((form) => { if (form.dataset.loginSubmitLockBound === '1') { return; } form.dataset.loginSubmitLockBound = '1'; const onSubmit = () => { if (form.dataset.submitted === '1') { return; } form.dataset.submitted = '1'; form.setAttribute('aria-busy', 'true'); const submitButton = form.querySelector('button[type="submit"]'); if (!(submitButton instanceof HTMLButtonElement)) { return; } submitButton.disabled = true; submitButton.setAttribute('aria-busy', 'true'); submitButton.dataset.submitState = 'loading'; }; form.addEventListener('submit', onSubmit); cleanupFns.push(() => { form.removeEventListener('submit', onSubmit); delete form.dataset.loginSubmitLockBound; }); }); return { destroy: () => { cleanupFns.forEach((cleanup) => cleanup()); }, }; }; const runtime = createComponentRuntime({ root: document, configId: 'login-components', }); runtime.register('flash-auto-dismiss', initFlashAutoDismiss, { selector: '[data-app-component="flash-auto-dismiss"]', configPath: 'components.flashAutoDismiss', defaultConfig: { selector: '.notice[data-flash-timeout]', }, }); runtime.register('password-hints', initPasswordHints, { scope: 'global', configPath: 'components.passwordHints', }); runtime.register('password-toggle', initPasswordToggles, { scope: 'global', configPath: 'components.passwordToggle', }); runtime.register('login-error-focus', initLoginErrorFocus, { scope: 'global', configPath: 'components.loginErrorFocus', }); runtime.register('login-submit-lock', initLoginSubmitLock, { scope: 'global', configPath: 'components.loginSubmitLock', }); runtime.mountAll();