import type { Fn } from '@mpxjs/mpxuse-shared' import { onScopeDispose } from '@mpxjs/core' import { events } from './internal' export type EventBusListener = (event: T, payload?: P) => void export type EventBusEvents = EventBusListener[] // eslint-disable-next-line @typescript-eslint/no-unused-vars export type EventBusKey = symbol export type EventBusIdentifier = EventBusKey | string | number export interface UseEventBusReturn { /** * Subscribe to an event. When calling emit, the listeners will execute. * @param listener watch listener. * @returns a stop function to remove the current callback. */ on: (listener: EventBusListener) => Fn /** * Similar to `on`, but only fires once * @param listener watch listener. * @returns a stop function to remove the current callback. */ once: (listener: EventBusListener) => Fn /** * Emit an event, the corresponding event listeners will execute. * @param event data sent. */ emit: (event?: T, payload?: P) => void /** * Remove the corresponding listener. * @param listener watch listener. */ off: (listener: EventBusListener) => void /** * Clear all events */ reset: () => void } export function useEventBus(key: EventBusIdentifier): UseEventBusReturn { const offs: Fn[] = [] onScopeDispose(() => offs.map(item => item())) function on(listener: EventBusListener) { const listeners = events.get(key) || [] listeners.push(listener) events.set(key, listeners) const _off = () => off(listener) offs.push(_off) return _off } function once(listener: EventBusListener) { function _listener(...args: any[]) { off(_listener) // @ts-expect-error cast listener(...args) } return on(_listener) } function off(listener: EventBusListener): void { const listeners = events.get(key) if (!listeners) return const index = listeners.indexOf(listener) if (index > -1) listeners.splice(index, 1) if (!listeners.length) events.delete(key) } function reset() { events.delete(key) } function emit(event?: T, payload?: P) { events.get(key)?.forEach(v => v(event, payload)) } return { on, once, off, emit, reset } }