diff --git a/.jules/bolt.md b/.jules/bolt.md index 400b475..e675cac 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -4,3 +4,8 @@ **Learning:** Asynchronous typeahead searches must implement a request ID mechanism. Without it, stale responses can overwrite newer ones, leading to correct search terms displaying incorrect results. **Action:** Always use a request ID or cancellation token pattern when implementing async search/filter operations. + +## 2024-10-26 - Svelte Input Debouncing + +**Learning:** Using `on:keyup` for debouncing search inputs is inefficient as it triggers on navigation keys (arrows, home, end) which don't change the value. It also misses paste events. +**Action:** Use a reactive statement `$: debounce(value)` to trigger debouncing only when the value actually changes. diff --git a/.jules/palette.md b/.jules/palette.md index 00f41cd..9cc85e1 100644 --- a/.jules/palette.md +++ b/.jules/palette.md @@ -1,3 +1,4 @@ ## 2024-10-24 - Accessible Icon Props and Loading Button State + **Learning:** Svelte wrapper components (like `Icon.svelte`) must spread `$$restProps` to allow passing accessibility attributes (e.g., `aria-label`) from parent components. Without this, icons remain inaccessible to screen readers. Also, persistent "Success" states on buttons can be confusing; auto-resetting them after a timeout improves clarity. **Action:** Always include `{...$$restProps}` in wrapper components and implement auto-reset logic for temporary success states in interactive elements. diff --git a/src/routes/DomainSearch.svelte b/src/routes/DomainSearch.svelte index 48c50fd..c3a90ad 100644 --- a/src/routes/DomainSearch.svelte +++ b/src/routes/DomainSearch.svelte @@ -22,11 +22,19 @@ $: invalid = domainName !== '' && !validator.validate(domainName, { raiseError: false }); $: nameSearchedLabel = nameSearched ? `${nameSearched}.${$metaNamesSdk.config.tld}` : null; - function debounce() { + function debounce(name: string) { clearTimeout(debounceTimer); - debounceTimer = setTimeout(async () => await search(), 400); + // Optimization: avoid setting timer on mount or when input is empty + if (name === '') return; + debounceTimer = setTimeout(async () => { + if (name === domainName) await search(); + }, 400); } + // Optimization: use reactive statement instead of on:keyup to avoid + // unnecessary API calls on navigation keys (arrows, etc) and handle paste events + $: debounce(domainName); + async function search(submit = false) { if (invalid) return; @@ -60,7 +68,6 @@ class="domain-input" variant="outlined" bind:value={domainName} - on:keyup={() => debounce()} bind:invalid label="Domain name" withTrailingIcon