fix(person-typeahead): add resetKey prop to clear term on navigation reset
When the user types in the sender/receiver typeahead without selecting a person and then clicks ×-reset (navigating back to /documents), the manually-typed term was not cleared because initialName stayed '' between navigations — the existing $effect tracking initialName never fired. Adding `resetKey` (incremented by the page on every navigation) forces the effect to re-run via `void resetKey`, clearing searchTerm=initialName even when initialName is unchanged. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -21,6 +21,7 @@ interface Props {
|
|||||||
restrictToCorrespondentsOf?: string;
|
restrictToCorrespondentsOf?: string;
|
||||||
excludePersonId?: string;
|
excludePersonId?: string;
|
||||||
badge?: 'additive' | 'replace';
|
badge?: 'additive' | 'replace';
|
||||||
|
resetKey?: number;
|
||||||
onchange?: (value: string) => void;
|
onchange?: (value: string) => void;
|
||||||
onfocused?: () => void;
|
onfocused?: () => void;
|
||||||
}
|
}
|
||||||
@@ -39,6 +40,7 @@ let {
|
|||||||
restrictToCorrespondentsOf,
|
restrictToCorrespondentsOf,
|
||||||
excludePersonId,
|
excludePersonId,
|
||||||
badge,
|
badge,
|
||||||
|
resetKey = 0,
|
||||||
onchange,
|
onchange,
|
||||||
onfocused
|
onfocused
|
||||||
}: Props = $props();
|
}: Props = $props();
|
||||||
@@ -48,8 +50,11 @@ let {
|
|||||||
// eslint-disable-next-line svelte/prefer-writable-derived
|
// eslint-disable-next-line svelte/prefer-writable-derived
|
||||||
let searchTerm = $state(initialName);
|
let searchTerm = $state(initialName);
|
||||||
|
|
||||||
// Sync display text when the selected person changes externally (e.g. swap, navigation).
|
// Sync display text when initialName changes OR when resetKey increments (navigation reset).
|
||||||
|
// resetKey is incremented by the page on every SvelteKit navigation so that a manually-typed
|
||||||
|
// term that was never committed (no person selected) gets cleared even if initialName stays ''.
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
|
void resetKey;
|
||||||
searchTerm = initialName;
|
searchTerm = initialName;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -270,6 +270,30 @@ describe('PersonTypeahead – correspondent mode', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ─── resetKey ─────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
describe('PersonTypeahead – resetKey', () => {
|
||||||
|
it('clears a manually-typed term when resetKey changes even if initialName stays empty', async () => {
|
||||||
|
mockFetchWithPersons([]);
|
||||||
|
const { rerender } = render(PersonTypeahead, {
|
||||||
|
name: 'senderId',
|
||||||
|
label: 'Absender',
|
||||||
|
initialName: '',
|
||||||
|
resetKey: 0
|
||||||
|
});
|
||||||
|
const input = page.getByPlaceholder('Namen tippen...');
|
||||||
|
|
||||||
|
// User types something without selecting a person
|
||||||
|
await input.fill('Max');
|
||||||
|
await waitForDebounce();
|
||||||
|
await expect.element(input).toHaveValue('Max');
|
||||||
|
|
||||||
|
// Navigation resets: initialName stays '', but resetKey increments
|
||||||
|
await rerender({ name: 'senderId', label: 'Absender', initialName: '', resetKey: 1 });
|
||||||
|
await expect.element(input).toHaveValue('');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// ─── Click outside ────────────────────────────────────────────────────────────
|
// ─── Click outside ────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
describe('PersonTypeahead – click outside', () => {
|
describe('PersonTypeahead – click outside', () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user