@tldraw/utils
Version:
tldraw infinite canvas SDK (private utilities).
158 lines (157 loc) • 5.93 kB
JavaScript
class Timers {
timeouts = /* @__PURE__ */ new Map();
intervals = /* @__PURE__ */ new Map();
rafs = /* @__PURE__ */ new Map();
/**
* Creates a new Timers instance with bound methods for safe callback usage.
* @example
* ```ts
* const timers = new Timers()
* // Methods are pre-bound, safe to use as callbacks
* element.addEventListener('click', timers.dispose)
* ```
*/
constructor() {
this.setTimeout = this.setTimeout.bind(this);
this.setInterval = this.setInterval.bind(this);
this.requestAnimationFrame = this.requestAnimationFrame.bind(this);
this.dispose = this.dispose.bind(this);
}
/**
* Creates a timeout that will be tracked under the specified context.
* @param contextId - The context identifier to group this timer under.
* @param handler - The function to execute when the timeout expires.
* @param timeout - The delay in milliseconds (default: 0).
* @param args - Additional arguments to pass to the handler.
* @returns The timer ID that can be used with clearTimeout.
* @example
* ```ts
* const timers = new Timers()
* const id = timers.setTimeout('autosave', () => save(), 5000)
* // Timer will be automatically cleared when 'autosave' context is disposed
* ```
* @public
*/
setTimeout(contextId, handler, timeout, ...args) {
const id = window.setTimeout(handler, timeout, args);
const current = this.timeouts.get(contextId) ?? [];
this.timeouts.set(contextId, [...current, id]);
return id;
}
/**
* Creates an interval that will be tracked under the specified context.
* @param contextId - The context identifier to group this timer under.
* @param handler - The function to execute repeatedly.
* @param timeout - The delay in milliseconds between executions (default: 0).
* @param args - Additional arguments to pass to the handler.
* @returns The interval ID that can be used with clearInterval.
* @example
* ```ts
* const timers = new Timers()
* const id = timers.setInterval('refresh', () => updateData(), 1000)
* // Interval will be automatically cleared when 'refresh' context is disposed
* ```
* @public
*/
setInterval(contextId, handler, timeout, ...args) {
const id = window.setInterval(handler, timeout, args);
const current = this.intervals.get(contextId) ?? [];
this.intervals.set(contextId, [...current, id]);
return id;
}
/**
* Requests an animation frame that will be tracked under the specified context.
* @param contextId - The context identifier to group this animation frame under.
* @param callback - The function to execute on the next animation frame.
* @returns The request ID that can be used with cancelAnimationFrame.
* @example
* ```ts
* const timers = new Timers()
* const id = timers.requestAnimationFrame('render', () => draw())
* // Animation frame will be automatically cancelled when 'render' context is disposed
* ```
* @public
*/
requestAnimationFrame(contextId, callback) {
const id = window.requestAnimationFrame(callback);
const current = this.rafs.get(contextId) ?? [];
this.rafs.set(contextId, [...current, id]);
return id;
}
/**
* Disposes of all timers associated with the specified context.
* Clears all timeouts, intervals, and animation frames for the given context ID.
* @param contextId - The context identifier whose timers should be cleared.
* @returns void
* @example
* ```ts
* const timers = new Timers()
* timers.setTimeout('ui', () => console.log('timeout'), 1000)
* timers.setInterval('ui', () => console.log('interval'), 500)
*
* // Clear all 'ui' context timers
* timers.dispose('ui')
* ```
* @public
*/
dispose(contextId) {
this.timeouts.get(contextId)?.forEach((id) => clearTimeout(id));
this.intervals.get(contextId)?.forEach((id) => clearInterval(id));
this.rafs.get(contextId)?.forEach((id) => cancelAnimationFrame(id));
this.timeouts.delete(contextId);
this.intervals.delete(contextId);
this.rafs.delete(contextId);
}
/**
* Disposes of all timers across all contexts.
* Clears every timeout, interval, and animation frame managed by this instance.
* @returns void
* @example
* ```ts
* const timers = new Timers()
* timers.setTimeout('ui', () => console.log('ui'), 1000)
* timers.setTimeout('background', () => console.log('bg'), 2000)
*
* // Clear everything
* timers.disposeAll()
* ```
* @public
*/
disposeAll() {
for (const contextId of this.timeouts.keys()) {
this.dispose(contextId);
}
}
/**
* Returns an object with timer methods bound to a specific context.
* Convenient for getting context-specific timer functions without repeatedly passing the contextId.
* @param contextId - The context identifier to bind the returned methods to.
* @returns An object with setTimeout, setInterval, requestAnimationFrame, and dispose methods bound to the context.
* @example
* ```ts
* const timers = new Timers()
* const uiTimers = timers.forContext('ui')
*
* // These are equivalent to calling timers.setTimeout('ui', ...)
* uiTimers.setTimeout(() => console.log('timeout'), 1000)
* uiTimers.setInterval(() => console.log('interval'), 500)
* uiTimers.requestAnimationFrame(() => console.log('frame'))
*
* // Dispose only this context
* uiTimers.dispose()
* ```
* @public
*/
forContext(contextId) {
return {
setTimeout: (handler, timeout, ...args) => this.setTimeout(contextId, handler, timeout, args),
setInterval: (handler, timeout, ...args) => this.setInterval(contextId, handler, timeout, args),
requestAnimationFrame: (callback) => this.requestAnimationFrame(contextId, callback),
dispose: () => this.dispose(contextId)
};
}
}
export {
Timers
};
//# sourceMappingURL=timers.mjs.map