| 57 | } |
| 58 | |
| 59 | on<T extends EditorEventName>( |
| 60 | eventName: T, |
| 61 | handler: EditorEventHandler<T>, |
| 62 | options?: AddEventListenerOptions & { target?: EventTarget }, |
| 63 | ): EditorEventSubscription { |
| 64 | const target = options?.target ?? window; |
| 65 | const prefixedEventName = this.prefixEventName(eventName); |
| 66 | const abortController = new AbortController(); |
| 67 | |
| 68 | const wrappedHandler = (event: Event) => { |
| 69 | const customEvent = event as CustomEvent<EditorEventMap[T]>; |
| 70 | const result = handler(customEvent.detail); |
| 71 | |
| 72 | if (result instanceof Promise) { |
| 73 | result.catch((error) => { |
| 74 | console.error( |
| 75 | `Error in async event handler for ${prefixedEventName}:`, |
| 76 | { event: customEvent.detail, error }, |
| 77 | ); |
| 78 | }); |
| 79 | } |
| 80 | }; |
| 81 | |
| 82 | target.addEventListener(prefixedEventName, wrappedHandler, { |
| 83 | ...options, |
| 84 | signal: abortController.signal, |
| 85 | }); |
| 86 | |
| 87 | return { |
| 88 | unsubscribe: () => { |
| 89 | abortController.abort(); |
| 90 | }, |
| 91 | }; |
| 92 | } |
| 93 | } |
| 94 | |
| 95 | export const editorEventBus = new EditorEventBus(); |