diff --git a/public/app.js b/public/app.js index ce2e351..0f526cf 100644 --- a/public/app.js +++ b/public/app.js @@ -477,3 +477,39 @@ document.addEventListener('DOMContentLoaded', function() { el.addEventListener('click', function(e) { e.preventDefault(); openEmailChange(); }); }); }); + +// === Accessibility: Escape key closes modals, focus trapping === +(function() { + function getActiveModal() { + var modals = ['signupModal', 'recoverModal', 'emailChangeModal']; + for (var i = 0; i < modals.length; i++) { + var m = document.getElementById(modals[i]); + if (m && m.classList.contains('active')) return m; + } + return null; + } + + function closeActiveModal() { + var m = getActiveModal(); + if (!m) return; + m.classList.remove('active'); + } + + document.addEventListener('keydown', function(e) { + if (e.key === 'Escape') closeActiveModal(); + + // Focus trap inside active modal + if (e.key === 'Tab') { + var modal = getActiveModal(); + if (!modal) return; + var focusable = modal.querySelectorAll('button:not([disabled]), input:not([disabled]), a[href], [tabindex]:not([tabindex="-1"])'); + if (focusable.length === 0) return; + var first = focusable[0], last = focusable[focusable.length - 1]; + if (e.shiftKey) { + if (document.activeElement === first) { e.preventDefault(); last.focus(); } + } else { + if (document.activeElement === last) { e.preventDefault(); first.focus(); } + } + } + }); +})(); diff --git a/public/index.html b/public/index.html index 6a4f860..659e233 100644 --- a/public/index.html +++ b/public/index.html @@ -5,6 +5,15 @@