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 };