import { useEffect, useState } from 'react'; import { useRuntimeConfig } from '@/config/context'; import { cn } from '@/lib/utils'; import { getMap } from './map-view'; import { useMapPrefStore } from './map-pref-store'; import { BASEMAP_STYLES, ensureGoogleProtocol, type BasemapDescriptor } from './styles'; /** * Floating basemap-picker control, top-right of the map. * * Reads the persisted choice from `useMapPrefStore` and applies it to the * map via `map.setStyle(...)`. Style swap fires the `mapReady` gate which * coordinates the unmount/remount of every other `Map*` component on the * map (sprites, sources, layers all get re-applied). */ export function BasemapSwitcher() { const cfg = useRuntimeConfig(); const current = useMapPrefStore((s) => s.basemapId); const setBasemap = useMapPrefStore((s) => s.setBasemap); const [switching, setSwitching] = useState(null); const available = BASEMAP_STYLES.filter((d) => d.available(cfg)); // Bootstrap: apply the persisted basemap once at mount. The singleton // boots with OSM as a bootstrap; this flips to the user's saved choice. // No `switching` UI state needed here — there's nothing to indicate to // the user during the very first style swap. useEffect(() => { const descriptor = available.find((d) => d.id === current); if (!descriptor) return; void (async () => { if (descriptor.id === 'google-satellite') { await ensureGoogleProtocol(); } getMap().setStyle(descriptor.buildStyle(cfg)); })(); // Run-once on mount. The user-driven onClick path handles subsequent // changes; depending on `available` / `cfg` here would re-run the // bootstrap unnecessarily. // eslint-disable-next-line react-hooks/exhaustive-deps }, []); async function onClick(descriptor: BasemapDescriptor): Promise { if (current === descriptor.id) return; setBasemap(descriptor.id); setSwitching(descriptor.id); try { if (descriptor.id === 'google-satellite') { await ensureGoogleProtocol(); } getMap().setStyle(descriptor.buildStyle(cfg)); } finally { setSwitching(null); } } return (
{available.map((d) => { const isActive = current === d.id; const isPending = switching === d.id; return ( ); })}
); }