Files
2026-05-27 23:29:53 +01:00

3.6 KiB

OpenSpec Change: enterprise-react-map

  • Change ID: enterprise-react-map
  • Package: @suaveplan/react-map
  • Category: react
  • Target path: react/platform/react-map
  • Status: PROPOSED
  • Date: 2026-04-24
  • Reference spec: /mnt/s/web/suaveplan/enterprise/react-map.md

Summary

Deliver @suaveplan/react-map on genesis from scratch at enterprise quality. A headless, provider-agnostic mapping layer: useMap hook owns map state (center, zoom, bounds, markers, polygons, clusters); component primitives (MapView, MapContainer, Marker, MarkerCluster, Polygon) render via a typed MapAdapter interface. Genesis adds the first concrete adapters (MapLibre GL + Leaflet), a bundled clustering algorithm, geo math helpers (haversine, boundsUnion, pointInPolygon), Storybook for every component, accessibility (keyboard pan/zoom, role="application"), i18n for ARIA labels, and Playwright E2E.


Current-state audit (genesis)

Package does not exist on genesis — fresh build.


Available workspace deps on genesis

Package Role
@suaveplan/error (workspace:^) MapError
@suaveplan/events (workspace:^) Map event bus
@suaveplan/react-translate (workspace:^) i18n for ARIA labels / tooltips
@opentelemetry/api (catalog:observability) Spans + counters
zod (catalog:forms) Config schemas
tslib (catalog:build) TS helpers

External: maplibre-gl catalog:maps (peer/optional), leaflet catalog:maps (peer/optional), React 18 peer.


Preserved public API surface

// Components
MapView, MapContainer, Marker, MarkerCluster, Polygon

// Hooks
useMap, useMapContext

// Adapters
MapAdapter, MapLibreAdapter, LeafletAdapter
createMapLibreAdapter, createLeafletAdapter

// Utils
haversine, boundsUnion, pointInPolygon, clusterMarkers, cn

// Types
LatLng, MapBounds, MapConfig, MapProps, MapContainerProps,
MarkerData, MarkerProps, MarkerClusterData, MarkerClusterProps,
PolygonData, PolygonProps, ClusterConfig, MapEventMap,
UseMapReturn, MapAdapterOptions

New additions for genesis

  1. MapError — codes: MAP_ADAPTER_INIT_FAILED, MAP_RENDER_FAILED.
  2. MapAdapter interface — typed contract enabling swap of vendor SDKs.
  3. MapLibreAdapter + LeafletAdapter — first reference implementations; peer-dep gated.
  4. Clustering algorithm — clusterMarkers(markers, config) grid/supercluster-style in src/utils/cluster.ts.
  5. Geo math — haversine, boundsUnion, pointInPolygon in src/utils/geo.ts.
  6. Storybook — stories for MapView, Marker, Polygon, MarkerCluster, MapContainer, useMap playground.
  7. Accessibility — keyboard pan/zoom (arrow keys, +/-), role="application", screen-reader marker descriptions.
  8. Playwright E2E — pan, zoom, marker click, cluster expand, polygon draw.

File layout

react/platform/react-map/
  package.json
  tsconfig.json
  vitest.config.ts
  src/
    index.ts
    types/
    components/
      map-view/ (tsx + types + md + test + stories + index)
      map-container/ (tsx + types + md + test + stories + index)
      marker/ (tsx + types + md + test + stories + index)
      marker-cluster/ (tsx + types + md + test + stories + index)
      polygon/ (tsx + types + md + test + stories + index)
    hooks/
      map-context/ (tsx + md + test + index)
      use-map/ (ts + md + test + index)
    adapters/
      adapter.types.ts
      maplibre/ (ts + md + test + index)
      leaflet/ (ts + md + test + index)
    utils/
      geo.ts + test + md
      cluster.ts + test + md
      cn.ts
  e2e/
    map.spec.ts