All files / blong-browser/src/lib eventBus.ts

94.2% Statements 65/69
100% Branches 2/2
50% Functions 1/2
94.2% Lines 65/69

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 701x 1x 1x 1x 1x 1x         1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x  
/**
 * blongEvents — typed event bus for blong-browser.
 *
 * A thin wrapper around the native browser `EventTarget` API, typed for the
 * events that blong-browser emits internally. Using `EventTarget` means zero extra
 * dependencies and native browser performance.
 *
 * ## Events
 *
 * | Type               | Fired when                                      |
 * |--------------------|-------------------------------------------------|
 * | `action:before`    | Before any dispatch call                        |
 * | `action:success`   | After a dispatch call resolves successfully     |
 * | `action:error`     | After a dispatch call rejects                   |
 *
 * ## Usage
 *
 * ```ts
 * import {blongEvents} from '@feasibleone/blong-browser';
 *
 * // Subscribe
 * const off = blongEvents.on('action:success', ({method, result}) => {
 *     console.log(method, result);
 * });
 *
 * // Unsubscribe
 * off();
 * ```
 */
 
/** All event payloads emitted by blong-browser */
export interface BlongEventMap {
    /** Emitted before every dispatch call */
    'action:before': {method: string; params: unknown};
    /** Emitted after a dispatch call resolves */
    'action:success': {method: string; params: unknown; result: unknown};
    /** Emitted after a dispatch call rejects */
    'action:error': {method: string; params: unknown; error: unknown};
}
 
type BlongEventType = keyof BlongEventMap;
type BlongListener<K extends BlongEventType> = (detail: BlongEventMap[K]) => void;
 
class BlongEventBus extends EventTarget {
    /**
     * Subscribe to an event. Returns an `off` function that removes the listener.
     *
     * @example
     * const off = blongEvents.on('action:success', ({method, result}) => { ... });
     * // later:
     * off();
     */
    on<K extends BlongEventType>(type: K, listener: BlongListener<K>): () => void {
        const handler = (e: Event) => listener((e as CustomEvent<BlongEventMap[K]>).detail);
        this.addEventListener(type, handler);
        return () => this.removeEventListener(type, handler);
    }
 
    /**
     * Emit an event with a typed payload. Called internally by blong-browser — user
     * code rarely needs to call this directly.
     */
    emit<K extends BlongEventType>(type: K, detail: BlongEventMap[K]): void {
        this.dispatchEvent(new CustomEvent(type, {detail}));
    }
}
 
/** Singleton event bus — import and subscribe from anywhere */
export const blongEvents = new BlongEventBus();