compote-ui
Version:
An opinionated UI component library for Svelte, built on top of [Ark UI](https://ark-ui.com) with additional components and features not available in the core Ark UI library.
57 lines (56 loc) • 2.26 kB
JavaScript
export class DebouncedFilterEdits {
// Raw, not deep: `base` must stay the exact filter value it is compared against — a deep
// $state would proxy an array base (a range) and `Object.is` would never match it again.
#pending = $state.raw({});
// Timer handles are bookkeeping, never rendered — a reactive map would only add overhead.
// eslint-disable-next-line svelte/prefer-svelte-reactivity
#timers = new Map();
#delay;
constructor(delay = 300) {
this.#delay = delay;
}
/** The pending edit for `id`, or undefined when there is none or it went stale. */
get(id, current) {
const pending = this.#pending[id];
return pending && Object.is(pending.base, current) ? pending.value : undefined;
}
/**
* Records an edit against the filter's `current` value: `update` receives the live
* pending edit (undefined when there is none or it went stale) and returns the new one.
* After the delay, `commit` runs with it — unless `read()` shows the filter changed.
*/
edit(id, current, update, read, commit) {
this.#pending = {
...this.#pending,
[id]: { value: update(this.get(id, current)), base: current }
};
clearTimeout(this.#timers.get(id));
this.#timers.set(id, setTimeout(() => {
this.#timers.delete(id);
const pending = this.#pending[id];
this.#remove(id);
if (pending && Object.is(read(), pending.base))
commit(pending.value);
}, this.#delay));
}
/** Drops the pending edit for `id` without committing it. */
cancel(id) {
clearTimeout(this.#timers.get(id));
this.#timers.delete(id);
this.#remove(id);
}
/** Drops every pending edit without committing. */
cancelAll() {
for (const timer of this.#timers.values())
clearTimeout(timer);
this.#timers.clear();
this.#pending = {};
}
#remove(id) {
if (!(id in this.#pending))
return;
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- dropped from the record
const { [id]: _removed, ...rest } = this.#pending;
this.#pending = rest;
}
}