import type { Emitter, EventType, Handler, WildcardHandler } from 'mitt' import create from 'mitt' import { useCallback, useEffect, useRef, useState } from 'react' const merge = >(...args: Array): T => { return Object.assign({}, ...args) } type _Events = Record type UseSubscribeOption = { /** * Whether the subscription is enabled. * @default true */ enabled: boolean } type ExtendedOn = { ( type: Key, handler: Handler, options?: UseSubscribeOption, ): void (type: '*', handler: WildcardHandler, option?: UseSubscribeOption): void } type UseMittReturn = { useSubscribe: ExtendedOn emit: Emitter['emit'] } const defaultSubscribeOption: UseSubscribeOption = { enabled: true, } function useMitt(mitt?: Emitter): UseMittReturn { const [internalEmitter] = useState(() => create()) const emitterRef = useRef(mitt ?? internalEmitter) useEffect(() => { if (!mitt || emitterRef.current === mitt) return emitterRef.current.off('*') emitterRef.current = mitt }, [mitt]) const emit = useCallback((type: Key, event?: Events[Key]) => { emitterRef.current.emit(type, event as Events[Key]) }, []) as Emitter['emit'] const useSubscribe: ExtendedOn = ( type: string, handler: any, option?: UseSubscribeOption, ) => { const { enabled } = merge(defaultSubscribeOption, option) useEffect(() => { if (enabled) { const emitter = mitt ?? emitterRef.current emitter.on(type, handler) return () => emitter.off(type, handler) } }) } return { emit, useSubscribe, } } export { useMitt }