import { ReadonlySignal } from '@preact/signals-core'; /** * `kerfjs/timing` — the small timing primitives every app hand-rolls. * * kerf already replaced most imperative bookkeeping — `delegate` for listeners, * `mount`/`effect` for render, `defineStore` for state — but debouncing and * throttling still get written by hand as `let timer; clearTimeout(timer); * timer = setTimeout(fn, ms)`. This subpath blesses that with disposer-shaped * ergonomics (`.cancel()` / `.flush()`), plus `debouncedSignal` so a trailing * value composes inside the reactive graph instead of beside it. * * import { debounce, throttle, debouncedSignal } from 'kerfjs/timing'; * * const save = debounce(() => persist(state), 300); * input.addEventListener('input', save); // save.cancel() on teardown * * const query = signal(''); * const debouncedQuery = debouncedSignal(query, 250); // trails query by 250ms * * Tree-shakeable and tiny — `debounce`/`throttle` are dependency-free; only * `debouncedSignal` pulls in signals (no render core). */ /** A debounced function: call it like the original, plus `cancel()` / `flush()`. */ interface Debounced { (...args: A): void; /** Drop any pending trailing call without invoking it. */ cancel(): void; /** Invoke the pending trailing call now (if any) and clear the timer. */ flush(): void; } /** A throttled function: call it like the original, plus `cancel()` / `flush()`. */ interface Throttled { (...args: A): void; /** Drop any pending trailing call and reset the rate window. */ cancel(): void; /** Invoke the pending trailing call now (if any). */ flush(): void; } /** * Trailing-edge debounce: `fn` runs `ms` after calls STOP, with the most recent * arguments. Every call within the quiet window resets the timer. `cancel()` * drops a pending call; `flush()` runs it immediately. */ declare function debounce(fn: (...args: A) => void, ms: number): Debounced; /** * Leading-plus-trailing throttle: `fn` runs immediately on the first call, then * at most once per `ms`. Calls during a cooldown collapse to a single trailing * call at the window's end (with the latest arguments). `cancel()` drops a * pending trailing call and resets the window; `flush()` runs it now. */ declare function throttle(fn: (...args: A) => void, ms: number): Throttled; /** * A read-only signal that trails `source` by `ms` (trailing-edge). Writes to * `source` reschedule; the derived value updates once writes go quiet, so it * composes with `computed()`/`effect()`/`mount()` like any signal. * * Holds a live subscription to `source` for its lifetime (like a module-scope * `effect`) — intended for app-lifetime signals, not throwaway ones. For a * disposable variant, drive your own `effect` with {@link debounce}. */ declare function debouncedSignal(source: ReadonlySignal, ms: number): ReadonlySignal; export { type Debounced, type Throttled, debounce, debouncedSignal, throttle };