59 lines
1.3 KiB
JavaScript
59 lines
1.3 KiB
JavaScript
//@ts-check
|
|
|
|
/**
|
|
* @template T
|
|
* @typedef {(args:T) => void} Listener<T>
|
|
*/
|
|
/**
|
|
* @typedef {{signal?: AbortSignal, once?: boolean}} ListenerOptions
|
|
*/
|
|
|
|
/**
|
|
* Returns an event emitter for a specific signal
|
|
* The initial passed value is optional, discarded, and only used to provide
|
|
* automatic typing where applicable.
|
|
* @template T
|
|
* @param {T} [_initial]
|
|
* @returns
|
|
*/
|
|
export const makeSignal = (_initial) => {
|
|
/** @type {Set<Listener<T>>} */
|
|
const listeners = new Set();
|
|
let enabled = true
|
|
/**
|
|
*
|
|
* @param {Listener<T>} fn
|
|
* @param {ListenerOptions} [options]
|
|
*/
|
|
const connect = (fn, { once, signal } = {}) => {
|
|
if (once) {
|
|
const _bound = fn;
|
|
fn = (args) => {
|
|
listeners.delete(fn);
|
|
_bound(args);
|
|
};
|
|
}
|
|
listeners.add(fn);
|
|
const _disconnect = () => disconnect(fn);
|
|
signal && signal.addEventListener("abort", _disconnect);
|
|
return _disconnect;
|
|
};
|
|
/**
|
|
* @param {Listener<T>} fn
|
|
* @returns
|
|
*/
|
|
const disconnect = (fn) => listeners.delete(fn);
|
|
|
|
/**
|
|
* @param {T} [args]
|
|
* @returns
|
|
*/
|
|
// @ts-ignore
|
|
const emit = (args) => enabled && listeners.forEach((fn) => fn(args));
|
|
|
|
const disable = () => {enabled = false}
|
|
|
|
return { connect, disconnect, emit, disable };
|
|
};
|
|
|
|
export default makeSignal |