diff --git a/src/lib/components/SearchInline.svelte b/src/lib/components/SearchInline.svelte index 66e20e4..40e0155 100644 --- a/src/lib/components/SearchInline.svelte +++ b/src/lib/components/SearchInline.svelte @@ -2,17 +2,11 @@ import { goto } from "$app/navigation"; import type { SearchResult } from "$lib/search"; import { createSearchState } from "$lib/searchState.svelte"; - import { registerInlineSearch } from "$lib/searchModal.svelte"; import SearchResults from "$lib/components/SearchResults.svelte"; const search = createSearchState(); let open = $state(false); - let inputEl = $state(null); - - // Route the global "/" shortcut and the sidebar/menu triggers here while - // this input is on screen - $effect(() => registerInlineSearch(() => inputEl?.focus())); function onInput() { search.schedule(); @@ -61,8 +55,8 @@ /> void) | null = null; - export const searchModal = { get open() { return open; }, }; -export function registerInlineSearch(focus: () => void): () => void { - inlineFocus = focus; - return () => { - if (inlineFocus === focus) inlineFocus = null; - }; -} - +// When the page hosts an inline search input (the homepage), every search +// trigger focuses it instead of opening the modal, so a modal input never +// opens on top of an inline one. Resolved through the DOM rather than a +// registration callback: it needs no lifecycle bookkeeping and stays correct +// even if HMR instantiates this module twice in dev. export function openSearch() { - if (inlineFocus) inlineFocus(); + const inline = document.querySelector( + "[data-search-inline]", + ); + if (inline) inline.focus(); else open = true; }