diff options
| author | Martin Kagamino Lehoux <martin@lehoux.net> | 2026-08-21 16:13:12 +0200 |
|---|---|---|
| committer | Martin Kagamino Lehoux <martin@lehoux.net> | 2026-08-21 16:13:12 +0200 |
| commit | 07a83b2e3db40f4a380092d6566500799b340dcd (patch) | |
| tree | 25bbe37ec3c459b48bcc14bf10eb8ad75836ef20 /src/lib/components/fuzzy-search.ts | |
| parent | 8f95ffb13be709036916d604849f8fde7e777a8f (diff) | |
feat: fuzzy autocomplete for add-item input
Replace the native <datalist> with a custom fuzzysort-driven component
(FuzzyAutocomplete) with keyboard nav and highlighted matches, preserving
exact-match auto-add. Extract a unit-tested fuzzy-search helper, and gitignore
.juggler/. Fix the dev DB boot failure caused by a sibling project's ambient
DATABASE_URL leaking in by overriding it (file:./data.db) in mise.toml.
Diffstat (limited to 'src/lib/components/fuzzy-search.ts')
| -rw-r--r-- | src/lib/components/fuzzy-search.ts | 25 |
1 files changed, 25 insertions, 0 deletions
diff --git a/src/lib/components/fuzzy-search.ts b/src/lib/components/fuzzy-search.ts new file mode 100644 index 0000000..31597b0 --- /dev/null +++ b/src/lib/components/fuzzy-search.ts @@ -0,0 +1,25 @@ +import fuzzysort, { type KeyResult } from 'fuzzysort'; + +export type FuzzyItem = { id: number; name: string }; + +export const FUZZ_LIMIT = 8; +export const FUZZ_THRESHOLD = 0.2; + +export type FuzzyMatch = KeyResult<FuzzyItem>; + +/** Fuzzy-match `items` against `query`, ranked best-first. Empty/whitespace + * query returns no matches. Results carry `.score`, `.target`, `.highlight()` + * and `.obj` (the matched item). */ +export function matchItems( + items: FuzzyItem[], + query: string, + { + limit = FUZZ_LIMIT, + threshold = FUZZ_THRESHOLD, + }: { limit?: number; threshold?: number } = {}, +): FuzzyMatch[] { + const q = query.trim(); + if (q === '') return []; + const snap = fuzzysort.snapshot(items, { key: 'name' }); + return Array.from(fuzzysort.go(q, snap, { limit, threshold })); +} |
