TypeScript 87.7%
CSS 12.3%
1/**2 * Author: Simon-Pierre Boucher3 * Contact: contact@spboucher.ai4 * Project: Groupe Ka / Ka Maps5 *6 * Tiny typed event hub. All MapLibre listeners are centralized in KaMap7 * and re-emitted here so app components never attach raw map listeners8 * (and cleanup happens in exactly one place).9 */1011export type KaEventMap = {12 /** Camera settled after user interaction or animation.13 * `byUser` distingue le geste (drag, molette, pincement, boutons de14 * navigation) d'un mouvement programmé (fitBounds, easeTo interne) —15 * c'est ce qui permet de « respecter l'intention de l'utilisateur ». */16 moveend: { center: { lat: number; lng: number }; zoom: number; byUser: boolean };17 /** Viewport diverged from the last searched area. */18 searchAreaDirty: { dirty: boolean };19 /** A property was selected (click) or deselected (null). */20 select: { propertyId: string | null; origin: "map" | "app" };21 /** Hover changed (desktop only). */22 hover: { propertyId: string | null };23 /** A cluster was clicked; the map is easing to expansion zoom. */24 clusterExpand: { count: number };25 /** Data finished loading into the property source. */26 data: { count: number; totalCount?: number };27 /** Loading state of the bounds query pipeline. */28 loading: { loading: boolean };29 /** Non-fatal error (tiles, query…) the app may surface. */30 error: { scope: "tiles" | "query" | "style"; error: unknown };31 /** Le spotlight bâtiment (focusBuilding) a trouvé son empreinte 3D. */32 buildingFocus: { found: boolean };33 /** Outil de dessin : état courant (en cours de tracé et/ou polygone posé).34 * `polygon` est un anneau [lng, lat][] fermé implicitement (≥ 3 sommets). */35 draw: { polygon: [number, number][] | null; drawing: boolean };36 /** Survol d'une bulle de cluster — fourchette de prix + position écran. */37 clusterHover: {38 info: { count: number; min: number | null; max: number | null; x: number; y: number } | null;39 };40};4142type Handler<T> = (payload: T) => void;4344export class KaEventHub {45 private handlers = new Map<keyof KaEventMap, Set<Handler<never>>>();4647 on<K extends keyof KaEventMap>(48 event: K,49 handler: Handler<KaEventMap[K]>,50 ): () => void {51 let set = this.handlers.get(event);52 if (!set) {53 set = new Set();54 this.handlers.set(event, set);55 }56 set.add(handler as Handler<never>);57 return () => set?.delete(handler as Handler<never>);58 }5960 emit<K extends keyof KaEventMap>(event: K, payload: KaEventMap[K]): void {61 const set = this.handlers.get(event);62 if (!set) return;63 for (const handler of set) (handler as Handler<KaEventMap[K]>)(payload);64 }6566 clear(): void {67 this.handlers.clear();68 }69}70