From 50da33ea4d0ce34536900b84c74e575766411a4c Mon Sep 17 00:00:00 2001 From: Ben Schlegel <31989404+benschlegel@users.noreply.github.com> Date: Sun, 3 Sep 2023 18:32:46 +0200 Subject: [PATCH] feat(search): add arrow key navigation (#442) * feat(search): add arrow navigation * chore: format * refactor: simplify arrow navigation * chore: remove comment * feat: rework arrow navigation to work without state * feat: make pressing enter work with arrow navigation * fix: remove unused css class * chore: correct comment * refactor(search): use optional chaining --- quartz/components/scripts/search.inline.ts | 29 +++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/quartz/components/scripts/search.inline.ts b/quartz/components/scripts/search.inline.ts index 4b9e372b..a1c3e6ca 100644 --- a/quartz/components/scripts/search.inline.ts +++ b/quartz/components/scripts/search.inline.ts @@ -82,6 +82,7 @@ document.addEventListener("nav", async (e: unknown) => { const searchIcon = document.getElementById("search-icon") const searchBar = document.getElementById("search-bar") as HTMLInputElement | null const results = document.getElementById("results-container") + const resultCards = document.getElementsByClassName("result-card") const idDataMap = Object.keys(data) as FullSlug[] function hideSearch() { @@ -122,9 +123,31 @@ document.addEventListener("nav", async (e: unknown) => { // add "#" prefix for tag search if (searchBar) searchBar.value = "#" } else if (e.key === "Enter") { - const anchor = document.getElementsByClassName("result-card")[0] as HTMLInputElement | null - if (anchor) { - anchor.click() + // If result has focus, navigate to that one, otherwise pick first result + if (results?.contains(document.activeElement)) { + const active = document.activeElement as HTMLInputElement + active.click() + } else { + const anchor = document.getElementsByClassName("result-card")[0] as HTMLInputElement | null + anchor?.click() + } + } else if (e.key === "ArrowDown") { + e.preventDefault() + // When first pressing ArrowDown, results wont contain the active element, so focus first element + if (!results?.contains(document.activeElement)) { + const firstResult = resultCards[0] as HTMLInputElement | null + firstResult?.focus() + } else { + // If an element in results-container already has focus, focus next one + const nextResult = document.activeElement?.nextElementSibling as HTMLInputElement | null + nextResult?.focus() + } + } else if (e.key === "ArrowUp") { + e.preventDefault() + if (results?.contains(document.activeElement)) { + // If an element in results-container already has focus, focus previous one + const prevResult = document.activeElement?.previousElementSibling as HTMLInputElement | null + prevResult?.focus() } } }