//@ts-check /** * @template T * @typedef {(args:T) => void} Listener */ /** * @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>} */ const listeners = new Set(); let enabled = true /** * * @param {Listener} 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} 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