TypeScript 87.7%
CSS 12.3%
1/**2 * Author: Simon-Pierre Boucher3 * Contact: contact@spboucher.ai4 * Project: Groupe Ka / Ka Maps5 *6 * <KaSpotlightMap> — la carte « fiche » : une seule propriété, caméra 3D7 * serrée sur l'adresse, et le bâtiment concerné mis en évidence (empreinte8 * 3D du featureset « buildings » de Mapbox Standard, coloré via9 * `buildingColor`). Fond réaliste par défaut (pleine couleur, repères 3D).10 * Gestes coopératifs : la fiche reste défilable au-dessus de la carte.11 */1213import { useEffect, useRef, type CSSProperties, type ReactElement, type ReactNode } from "react";14import type { KaBasemapOptions } from "../styles/kaBaseStyle.js";15import type { KaMapMode, KaMapTheme } from "../theming/tokens.js";16import type { MapProperty } from "../types/index.js";17import { KaMapView, useKaMap } from "./KaMapView.js";1819/** Rouge signal — l'immeuble de la fiche ressort du premier coup d'œil. */20const DEFAULT_BUILDING_COLOR = "#e03131";2122const DEFAULT_ZOOM = 17.1;23const DEFAULT_PITCH = 62;2425function SpotlightBridge({26 property,27 color,28 zoom,29 pitch,30}: {31 property: MapProperty;32 color: string;33 zoom: number;34 pitch: number;35}) {36 const map = useKaMap();37 const firstRun = useRef(true);3839 useEffect(() => {40 if (!map) return;41 const at = { lng: property.longitude, lat: property.latitude };42 // Premier rendu : la caméra est déjà posée par le constructeur ;43 // navigations suivantes (fiche → fiche) : glissement doux.44 if (firstRun.current) firstRun.current = false;45 else map.flyTo(at, { zoom, pitch });46 map.focusBuilding(at, { color });47 return () => map.focusBuilding(null);48 // eslint-disable-next-line react-hooks/exhaustive-deps49 }, [map, property.id, property.longitude, property.latitude, color]);5051 return null;52}5354export interface KaSpotlightMapProps {55 theme: KaMapTheme;56 mapboxToken: string;57 /** La propriété de la fiche — pastille de prix + bâtiment en évidence. */58 property: MapProperty;59 mode?: KaMapMode;60 className?: string;61 style?: CSSProperties;62 /** Couleur de l'empreinte 3D du bâtiment. Défaut : rouge signal. */63 buildingColor?: string;64 zoom?: number;65 pitch?: number;66 /** Surcharge du fond (défaut spotlight : pleine couleur + repères 3D). */67 basemap?: KaBasemapOptions;68 children?: ReactNode;69}7071export function KaSpotlightMap({72 theme,73 mapboxToken,74 property,75 mode,76 className,77 style,78 buildingColor = DEFAULT_BUILDING_COLOR,79 zoom = DEFAULT_ZOOM,80 pitch = DEFAULT_PITCH,81 basemap,82 children,83}: KaSpotlightMapProps): ReactElement {84 const properties = useRef<MapProperty[]>([]);85 if (properties.current[0]?.id !== property.id) properties.current = [property];8687 return (88 <KaMapView89 theme={theme}90 mapboxToken={mapboxToken}91 mode={mode}92 className={className}93 style={style}94 properties={properties.current}95 center={{ lat: property.latitude, lng: property.longitude }}96 zoom={zoom}97 pitch={pitch}98 minZoom={11}99 cooperativeGestures100 basemap={{101 theme: "default",102 showLandmarks: true,103 colorBuildingSelect: buildingColor,104 ...basemap,105 }}106 >107 <SpotlightBridge108 property={property}109 color={buildingColor}110 zoom={zoom}111 pitch={pitch}112 />113 {children}114 </KaMapView>115 );116}117