Route search triggers to the inline input via the DOM

This commit is contained in:
dtonon 2026-07-28 12:03:45 +01:00
parent a5237a5e75
commit fecfbaab8b
2 changed files with 10 additions and 20 deletions

View file

@ -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<HTMLInputElement | null>(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 @@
/>
</svg>
<input
bind:this={inputEl}
bind:value={search.query}
data-search-inline
type="search"
placeholder="Search"
role="combobox"

View file

@ -1,25 +1,21 @@
let open = $state(false);
// When a page hosts an inline search input (the homepage), it registers a
// focus function here and every search trigger routes to it instead of the
// modal, so a modal input never opens on top of an inline one.
let inlineFocus: (() => 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<HTMLInputElement>(
"[data-search-inline]",
);
if (inline) inline.focus();
else open = true;
}