// from https://raw.githubusercontent.com/ueberdosis/tiptap/develop/packages/core/src/EventEmitter.ts (MIT) type StringKeyOf = Extract; type CallbackType< T extends Record, EventName extends StringKeyOf > = T[EventName] extends any[] ? T[EventName] : [T[EventName]]; type CallbackFunction< T extends Record, EventName extends StringKeyOf > = (...props: CallbackType) => any; export class EventEmitter> { // eslint-disable-next-line @typescript-eslint/ban-types private callbacks: { [key: string]: Function[] } = {}; public on>( event: EventName, fn: CallbackFunction ) { if (!this.callbacks[event]) { this.callbacks[event] = []; } this.callbacks[event].push(fn); return () => this.off(event, fn); } protected emit>( event: EventName, ...args: CallbackType ) { const callbacks = this.callbacks[event]; if (callbacks) { callbacks.forEach((callback) => callback.apply(this, args)); } } public off>( event: EventName, fn?: CallbackFunction ) { const callbacks = this.callbacks[event]; if (callbacks) { if (fn) { this.callbacks[event] = callbacks.filter((callback) => callback !== fn); } else { delete this.callbacks[event]; } } } protected removeAllListeners(): void { this.callbacks = {}; } }