From 553e703f09b92530382b81505f078655e5d5825d Mon Sep 17 00:00:00 2001 From: Alexander van Elsas <58037137+avanelsas@users.noreply.github.com> Date: Tue, 14 Jul 2026 11:34:20 +0200 Subject: [PATCH] feat(x-search-field): add opt-in debounce for input events A positive debounce attribute (milliseconds) coalesces rapid typing into a single x-search-field-input event fired once the user pauses, while local feedback like the clear button and validity stays synchronous. Absent or zero preserves the immediate per-keystroke behaviour, and a pending dispatch is cancelled on clear, reset, or disconnect. --- .../directives/x-search-field.directive.ts | 1 + adapters/react/src/x-search-field.tsx | 1 + adapters/solid/src/x-search-field.tsx | 1 + adapters/svelte/src/x-search-field.svelte | 3 + adapters/vue/src/x-search-field.ts | 1 + demo/x-search-field.html | 13 +++- docs/x-search-field.md | 15 ++++ .../components/x_search_field/model.cljs | 21 +++++- .../x_search_field/x_search_field.cljs | 44 ++++++++++- .../components/x_search_field/model_test.cljs | 28 ++++++- .../x_search_field/x_search_field_test.cljs | 74 +++++++++++++++++++ 11 files changed, 192 insertions(+), 10 deletions(-) diff --git a/adapters/angular/src/directives/x-search-field.directive.ts b/adapters/angular/src/directives/x-search-field.directive.ts index 83fff56b..5946ca24 100644 --- a/adapters/angular/src/directives/x-search-field.directive.ts +++ b/adapters/angular/src/directives/x-search-field.directive.ts @@ -24,6 +24,7 @@ export class BaredomSearchField implements OnInit, OnDestroy { @Input() set autocomplete(v: string) { this.el.autocomplete = v as any; } @Input() set disabled(v: boolean) { this.el.disabled = v as any; } @Input() set required(v: boolean) { this.el.required = v as any; } + @Input() set debounce(v: number) { this.el.debounce = v as any; } @Output() input = new EventEmitter>(); @Output() change = new EventEmitter>(); diff --git a/adapters/react/src/x-search-field.tsx b/adapters/react/src/x-search-field.tsx index 1cef5673..a8e83b5a 100644 --- a/adapters/react/src/x-search-field.tsx +++ b/adapters/react/src/x-search-field.tsx @@ -15,6 +15,7 @@ export interface XSearchFieldProps { autocomplete?: string; disabled?: boolean; required?: boolean; + debounce?: number; onInput?: (e: CustomEvent<{ name: string; value: string }>) => void; onChange?: (e: CustomEvent<{ name: string; value: string }>) => void; onSearch?: (e: CustomEvent<{ name: string; value: string }>) => void; diff --git a/adapters/solid/src/x-search-field.tsx b/adapters/solid/src/x-search-field.tsx index 0d6ef2cc..fdeba398 100644 --- a/adapters/solid/src/x-search-field.tsx +++ b/adapters/solid/src/x-search-field.tsx @@ -14,6 +14,7 @@ export interface XSearchFieldProps { autocomplete?: string; disabled?: boolean; required?: boolean; + debounce?: number; onInput?: (e: CustomEvent<{ name: string; value: string }>) => void; onChange?: (e: CustomEvent<{ name: string; value: string }>) => void; onSearch?: (e: CustomEvent<{ name: string; value: string }>) => void; diff --git a/adapters/svelte/src/x-search-field.svelte b/adapters/svelte/src/x-search-field.svelte index ed750651..6d8769e2 100644 --- a/adapters/svelte/src/x-search-field.svelte +++ b/adapters/svelte/src/x-search-field.svelte @@ -12,6 +12,7 @@ autocomplete?: string; disabled?: boolean; required?: boolean; + debounce?: number; oninput?: (e: CustomEvent<{ name: string; value: string }>) => void; onchange?: (e: CustomEvent<{ name: string; value: string }>) => void; onsearch?: (e: CustomEvent<{ name: string; value: string }>) => void; @@ -33,6 +34,7 @@ autocomplete, disabled, required, + debounce, oninput, onchange, onsearch, @@ -73,6 +75,7 @@ {autocomplete} {disabled} {required} + {debounce} class={className} {id} {...rest} diff --git a/adapters/vue/src/x-search-field.ts b/adapters/vue/src/x-search-field.ts index 36ab6de8..793480cd 100644 --- a/adapters/vue/src/x-search-field.ts +++ b/adapters/vue/src/x-search-field.ts @@ -22,6 +22,7 @@ export const XSearchField = defineComponent({ autocomplete: { type: String as PropType, default: undefined }, disabled: { type: Boolean as PropType, default: undefined }, required: { type: Boolean as PropType, default: undefined }, + debounce: { type: Number as PropType, default: undefined }, }, emits: { "input": (_e: CustomEvent<{ name: string; value: string }>) => true, diff --git a/demo/x-search-field.html b/demo/x-search-field.html index 22ec8eca..9d3dc2c8 100644 --- a/demo/x-search-field.html +++ b/demo/x-search-field.html @@ -86,7 +86,14 @@ + +

+ Set debounce > 0, then type quickly: local UI (clear button) stays instant, but + x-search-field-input is logged only once you pause. +

@@ -96,7 +103,9 @@