UNPKG

react-native-unit-components

Version:

Unit React Native components

107 lines (89 loc) 2.99 kB
import type { EventMap, SharedEvent } from './EventBus.types'; // Type-safe callback that receives the correct data type for the event key export type EventCallback<K extends keyof EventMap> = (data: EventMap[K]) => void; class EventBus { private debug = false; private listeners = new Map<SharedEvent['key'], Set<(data: unknown) => void>>(); private eventQueue: SharedEvent[] = []; private isProcessing = false; /** * Subscribe to an event * @returns Unsubscribe function */ on<K extends keyof EventMap>(eventKey: K, callback: EventCallback<K>): () => void { if (!this.listeners.has(eventKey)) { this.listeners.set(eventKey, new Set()); } this.listeners.get(eventKey)!.add(callback as (data: unknown) => void); if (this.debug) { console.log(`[EventBus] Subscribed to: ${eventKey} (${this.listenerCount(eventKey)} listeners)`); } // Return unsubscribe function return () => { const callbacks = this.listeners.get(eventKey); if (callbacks) { callbacks.delete(callback as (data: unknown) => void); if (callbacks.size === 0) { this.listeners.delete(eventKey); } } }; } /** * Emit an event - queues it for processing to ensure all events are delivered */ emit<K extends keyof EventMap>(eventKey: K, data: EventMap[K]): void { const event = { key: eventKey, data } as SharedEvent; if (this.debug) { console.log(`[EventBus] Emitting: ${eventKey} (${this.listenerCount(eventKey)} listeners)`); } this.eventQueue.push(event); this.processQueue(); } /** * Process events from queue sequentially * This ensures rapid successive events are all delivered */ private processQueue(): void { if (this.isProcessing || this.eventQueue.length === 0) { return; } this.isProcessing = true; // Process all queued events synchronously to ensure immediate delivery while (this.eventQueue.length > 0) { const event = this.eventQueue.shift()!; const callbacks = this.listeners.get(event.key); if (callbacks && callbacks.size > 0) { // Process all listeners for this event callbacks.forEach(callback => { try { callback(event.data); } catch (error) { console.error(`Error in event listener for ${event.key}:`, error); } }); } } this.isProcessing = false; } /** * Remove all listeners for an event */ off<K extends keyof EventMap>(eventKey: K): void { this.listeners.delete(eventKey); } /** * Get number of listeners for an event (useful for debugging) */ listenerCount<K extends keyof EventMap>(eventKey: K): number { return this.listeners.get(eventKey)?.size ?? 0; } /** * Enable or disable debug logging */ setDebug(enabled: boolean): void { this.debug = enabled; } } // Singleton instance export const eventBus = new EventBus();