diff --git a/index.html b/index.html index 9be3e96..8ff117d 100644 --- a/index.html +++ b/index.html @@ -40,6 +40,28 @@ + + + + Search + + + + + Back + + + + + Sort + + + + + + + + Search diff --git a/script.js b/script.js index 51b30c0..13cce9c 100644 --- a/script.js +++ b/script.js @@ -64,9 +64,24 @@ function ensureViewEl(view) { if (!view || !view.el) throw new Error('Invalid view'); view.el.classList.add('ux-view'); + if (view.kind) view.el.dataset.uxKind = view.kind; return view.el; } + function assertKind(view, expected) { + if (!view) throw new Error('Missing view'); + if (view.kind && view.kind !== expected) { + throw new Error(`Expected view kind "${expected}" but received "${view.kind}"`); + } + } + + async function closeAllOverlays({ restoreFocus = false } = {}) { + while (overlayStack.length) { + const shouldRestore = restoreFocus && overlayStack.length === 1; + await closeTop({ restoreFocus: shouldRestore }); + } + } + function syncOverlayVisibility() { const topIndex = overlayStack.length - 1; overlayStack.forEach((entry, idx) => { @@ -104,6 +119,8 @@ } async function replace(view) { + assertKind(view, 'base'); + await closeAllOverlays({ restoreFocus: false }); const el = ensureViewEl(view); const prev = currentBase; if (prev) { @@ -122,6 +139,7 @@ } async function openOverlay(view) { + assertKind(view, 'overlay'); const el = ensureViewEl(view); el.classList.add('ux-view--overlay'); const lastFocus = document.activeElement; @@ -134,7 +152,7 @@ if (typeof view.onShow === 'function') view.onShow(); } - async function closeTop() { + async function closeTop({ restoreFocus = true } = {}) { const top = overlayStack[overlayStack.length - 1]; if (!top) return; if (top.isClosing) return; @@ -146,7 +164,9 @@ if (typeof view.destroy === 'function') view.destroy(); overlayStack.pop(); syncOverlayVisibility(); - if (lastFocus && typeof lastFocus.focus === 'function') lastFocus.focus(); + if (restoreFocus && lastFocus && typeof lastFocus.focus === 'function') { + lastFocus.focus(); + } } window.addEventListener('keydown', (e) => { @@ -156,7 +176,7 @@ } }); - return { replace, openOverlay, closeTop }; + return { replace, openOverlay, closeTop, closeAllOverlays }; })(); // --- IndexedDB helpers (minimal, no external deps) --- @@ -722,35 +742,8 @@ const $form = el.querySelector('[data-ref="form"]'); const $q = el.querySelector('[data-ref="q"]'); const $results = el.querySelector('[data-ref="results"]'); - - // Back + sort toolbar keeps controls grouped for accessibility. - const $toolbar = document.createElement('div'); - $toolbar.className = 'level mb-4 is-mobile'; - const $toolbarLeft = document.createElement('div'); - $toolbarLeft.className = 'level-left'; - const $toolbarLeftItem = document.createElement('div'); - $toolbarLeftItem.className = 'level-item'; - const $backBtn = document.createElement('button'); - $backBtn.type = 'button'; - $backBtn.className = 'button is-small is-text'; - $backBtn.textContent = 'Back to menu'; - $toolbarLeftItem.appendChild($backBtn); - $toolbarLeft.appendChild($toolbarLeftItem); - const $toolbarRight = document.createElement('div'); - $toolbarRight.className = 'level-right'; - const $toolbarRightItem = document.createElement('div'); - $toolbarRightItem.className = 'level-item'; - const $sortLabel = document.createElement('span'); - $sortLabel.className = 'is-size-7 has-text-grey mr-2'; - $sortLabel.textContent = 'Sort'; - const $sortButtons = document.createElement('div'); - $sortButtons.className = 'buttons has-addons is-small'; - $toolbarRightItem.appendChild($sortLabel); - $toolbarRightItem.appendChild($sortButtons); - $toolbarRight.appendChild($toolbarRightItem); - $toolbar.appendChild($toolbarLeft); - $toolbar.appendChild($toolbarRight); - $form.insertAdjacentElement('afterend', $toolbar); + const $backBtn = el.querySelector('[data-action="back"]'); + const $sortButtons = el.querySelector('[data-ref="sort-buttons"]'); const $status = document.createElement('p'); $status.className = 'has-text-grey'; @@ -796,6 +789,8 @@ { key: 'alpha', label: 'A–Z' }, ]; + if (!$backBtn) throw new Error('Missing back button'); + if (!$sortButtons) throw new Error('Missing sort container'); sortOptions.forEach((opt) => { const btn = document.createElement('button'); btn.type = 'button';