Automerge backed Markdown editor for the Atmosphere
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192/** * Generic debouncer for coalescing rapid calls. * * Calls the callback with the most recent arguments after the delay expires. * If call() is invoked again before the delay expires, the timer resets. */export class Debouncer<T extends unknown[] = unknown[]> { private timer: ReturnType<typeof setTimeout> | null = null private pendingArgs: T | null = null private disposed = false private executing = false
constructor( private readonly callback: (...args: T) => void, private readonly delayMs: number ) {}
/** * Schedule a debounced call with the given arguments. * Resets the timer if already pending. */ call(...args: T): void { if (this.disposed) return this.pendingArgs = args this.clearTimer() this.timer = setTimeout(() => { this.timer = null const savedArgs = this.pendingArgs this.pendingArgs = null if (savedArgs !== null) { this.executing = true try { this.callback(...savedArgs) } finally { this.executing = false } } }, this.delayMs) }
private clearTimer(): void { if (this.timer !== null) { clearTimeout(this.timer) this.timer = null } }
/** * Immediately invoke the callback with pending arguments. * Clears the pending state. */ flush(): void { if (this.disposed) return this.clearTimer() const args = this.pendingArgs this.pendingArgs = null if (args !== null) { this.callback(...args) } }
/** * Cancel any pending call without invoking the callback. */ cancel(): void { this.clearTimer() this.pendingArgs = null }
/** * Check if there is a pending debounced call or if the callback is currently executing. */ isPending(): boolean { return this.pendingArgs !== null || this.executing }
/** * Cancel and mark as disposed. Future calls are ignored. */ dispose(): void { this.cancel() this.disposed = true }
/** * Check if the debouncer has been disposed. */ isDisposed(): boolean { return this.disposed }}