feat(search): extended search, sort options, live tag filter, result count #183

Merged
marcel merged 26 commits from feat/issue-180-extended-search-sort into main 2026-04-06 19:18:12 +02:00
2 changed files with 24 additions and 2 deletions
Showing only changes of commit eeb78c98ec - Show all commits

View File

@@ -6,9 +6,10 @@ import { clickOutside } from '$lib/actions/clickOutside';
interface Props {
tags?: string[];
allowCreation?: boolean;
onTextInput?: (text: string) => void;
}
let { tags = $bindable([]), allowCreation = true }: Props = $props();
let { tags = $bindable([]), allowCreation = true, onTextInput }: Props = $props();
let inputVal = $state('');
let suggestions: string[] = $state([]);
@@ -101,7 +102,7 @@ function handleKeydown(e: KeyboardEvent) {
<input
type="text"
bind:value={inputVal}
oninput={() => fetchSuggestions(inputVal)}
oninput={() => { fetchSuggestions(inputVal); onTextInput?.(inputVal); }}
onkeydown={handleKeydown}
onfocus={() => fetchSuggestions(inputVal)}
placeholder={tags.length === 0

View File

@@ -208,3 +208,24 @@ describe('TagInput autocomplete', () => {
await expect.element(page.getByRole('option', { name: 'Familie' })).not.toBeInTheDocument();
});
});
// ─── onTextInput callback ──────────────────────────────────────────────────────
describe('TagInput onTextInput callback', () => {
it('calls onTextInput with the current value on every input event', async () => {
mockFetchEmpty();
const onTextInput = vi.fn();
render(TagInput, { tags: [], allowCreation: false, onTextInput });
const input = page.getByRole('textbox');
await input.fill('fa');
await expect.poll(() => onTextInput.mock.calls.length).toBeGreaterThan(0);
expect(onTextInput).toHaveBeenCalledWith('fa');
});
it('does not throw when onTextInput is not provided', async () => {
mockFetchEmpty();
render(TagInput, { tags: [], allowCreation: false });
const input = page.getByRole('textbox');
await expect(input.fill('fa')).resolves.not.toThrow();
});
});