@trackunit/react-map 0.0.4-alpha-9d327375fc1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (224) hide show
  1. package/README.md +296 -0
  2. package/index.cjs.js +9851 -0
  3. package/index.d.ts +1 -0
  4. package/index.esm.js +9752 -0
  5. package/package.json +34 -0
  6. package/src/annotations/getDescriptorContentKey.d.ts +14 -0
  7. package/src/annotations/mapAnnotations.d.ts +76 -0
  8. package/src/annotations/useMapAnnotation.d.ts +16 -0
  9. package/src/annotations/useMapAnnotations.d.ts +17 -0
  10. package/src/appearance/AppearancePreview.d.ts +27 -0
  11. package/src/appearance/AppearancePreviewGrid.d.ts +29 -0
  12. package/src/appearance/appearanceTypes.d.ts +84 -0
  13. package/src/appearance/useMapAppearanceControls.d.ts +29 -0
  14. package/src/clusters/ClusterMarker.d.ts +41 -0
  15. package/src/clusters/ClusterStick.d.ts +97 -0
  16. package/src/clusters/formatClusterCount.d.ts +11 -0
  17. package/src/clusters/stories/ClusterMarkerCompactFormatsDemo.d.ts +7 -0
  18. package/src/clusters/stories/ClusterMarkerCountOnlyDemo.d.ts +7 -0
  19. package/src/clusters/stories/ClusterMarkerDefaultDemo.d.ts +12 -0
  20. package/src/clusters/stories/ClusterMarkerPlaygroundDemo.d.ts +10 -0
  21. package/src/clusters/stories/ClusterMarkerStateDemo.d.ts +9 -0
  22. package/src/clusters/stories/ClusterMarkerWithSegmentsDemo.d.ts +7 -0
  23. package/src/clusters/stories/ClusterMarkerWithSticksDemo.d.ts +10 -0
  24. package/src/clusters/useClusterCountFormat.d.ts +19 -0
  25. package/src/controls/AnnotationRenderer.d.ts +17 -0
  26. package/src/controls/AnnotationStack.d.ts +21 -0
  27. package/src/controls/ControlRenderer.d.ts +20 -0
  28. package/src/controls/Controls.d.ts +15 -0
  29. package/src/controls/annotationButtonClasses.d.ts +13 -0
  30. package/src/controls/collapseControls.d.ts +37 -0
  31. package/src/controls/defineControlStack.d.ts +10 -0
  32. package/src/controls/deriveResponsiveMode.d.ts +19 -0
  33. package/src/controls/longitudeToGlobeIcon.d.ts +3 -0
  34. package/src/controls/renderers/boolean/BooleanButton.d.ts +16 -0
  35. package/src/controls/renderers/boolean/MenuBooleanItem.d.ts +20 -0
  36. package/src/controls/renderers/boolean/MenuCheckbox.d.ts +14 -0
  37. package/src/controls/renderers/boolean/MenuToggle.d.ts +14 -0
  38. package/src/controls/renderers/button/Button.d.ts +14 -0
  39. package/src/controls/renderers/button/MenuButton.d.ts +16 -0
  40. package/src/controls/renderers/custom/Custom.d.ts +22 -0
  41. package/src/controls/renderers/menu/Menu.d.ts +23 -0
  42. package/src/controls/renderers/menu/Modal.d.ts +21 -0
  43. package/src/controls/renderers/menu/SectionHeader.d.ts +14 -0
  44. package/src/controls/renderers/menu/Separator.d.ts +11 -0
  45. package/src/controls/renderers/radio-group/MenuRadioGroup.d.ts +15 -0
  46. package/src/controls/renderers/radio-group/RadioGroup.d.ts +19 -0
  47. package/src/controls/renderers/radio-group/RadioGroupField.d.ts +17 -0
  48. package/src/controls/renderers/search/MenuSearch.d.ts +15 -0
  49. package/src/controls/renderers/search/Search.d.ts +14 -0
  50. package/src/controls/renderers/select/MenuSelect.d.ts +15 -0
  51. package/src/controls/renderers/select/Select.d.ts +14 -0
  52. package/src/controls/renderers/stepper/MenuStepper.d.ts +17 -0
  53. package/src/controls/renderers/stepper/Stepper.d.ts +18 -0
  54. package/src/controls/renderers/toggle-group/MenuToggleGroup.d.ts +17 -0
  55. package/src/controls/renderers/toggle-group/ToggleGroup.d.ts +15 -0
  56. package/src/controls/renderers/toggle-group/ToggleGroupField.d.ts +19 -0
  57. package/src/controls/renderingRules.d.ts +26 -0
  58. package/src/controls/types.d.ts +395 -0
  59. package/src/controls/useAnimatedPresence.d.ts +15 -0
  60. package/src/controls/useAnnotationPresence.d.ts +16 -0
  61. package/src/controls/useControlStack.d.ts +21 -0
  62. package/src/controls/useControlsConfig.d.ts +27 -0
  63. package/src/controls/usePopoverPlacement.d.ts +33 -0
  64. package/src/core/LoadingIndicatorPill.d.ts +9 -0
  65. package/src/core/MapLoadingState.d.ts +17 -0
  66. package/src/core/SafeAreaLayoutContext.d.ts +5 -0
  67. package/src/core/__testHelpers.d.ts +23 -0
  68. package/src/core/createMapComponent.d.ts +32 -0
  69. package/src/core/loadingIndicator.d.ts +21 -0
  70. package/src/core/padWithInsets.d.ts +5 -0
  71. package/src/core/types.d.ts +208 -0
  72. package/src/core/useCameraIdle.d.ts +2 -0
  73. package/src/core/useCameraState.d.ts +3 -0
  74. package/src/core/useMap.d.ts +57 -0
  75. package/src/core/useMapAdapterState.d.ts +14 -0
  76. package/src/core/useMapKeyboardNavigation.d.ts +38 -0
  77. package/src/core/usePreviewMap.d.ts +43 -0
  78. package/src/index.d.ts +69 -0
  79. package/src/interactions/interactionReducer.d.ts +31 -0
  80. package/src/layers/Layers.d.ts +32 -0
  81. package/src/layers/__testHelpers.d.ts +24 -0
  82. package/src/layers/buildExpandedIds.d.ts +17 -0
  83. package/src/layers/image-overlay/useImageOverlay.d.ts +39 -0
  84. package/src/layers/internal/MapLayerContext.d.ts +24 -0
  85. package/src/layers/internal/adaptiveMarkerResolution.d.ts +33 -0
  86. package/src/layers/internal/computeBounds.d.ts +34 -0
  87. package/src/layers/internal/countFeaturesInViewport.d.ts +14 -0
  88. package/src/layers/internal/createLazyGetter.d.ts +16 -0
  89. package/src/layers/internal/layerHelpers.d.ts +18 -0
  90. package/src/layers/internal/markerPortalZIndex.d.ts +17 -0
  91. package/src/layers/internal/useDblClickFit.d.ts +13 -0
  92. package/src/layers/internal/useEntityInteraction.d.ts +21 -0
  93. package/src/layers/internal/useFitFeatureBounds.d.ts +19 -0
  94. package/src/layers/internal/useLayerHandleSync.d.ts +18 -0
  95. package/src/layers/internal/useLayerReady.d.ts +25 -0
  96. package/src/layers/internal/useMarkerMountBridge.d.ts +41 -0
  97. package/src/layers/internal/useViewportContext.d.ts +34 -0
  98. package/src/layers/mapFocus.d.ts +29 -0
  99. package/src/layers/routes/useRoute.d.ts +39 -0
  100. package/src/layers/shared/measureLabelWidth.d.ts +11 -0
  101. package/src/layers/types.d.ts +131 -0
  102. package/src/layers/useExpandedIds.d.ts +20 -0
  103. package/src/layers/useFitToContent.d.ts +57 -0
  104. package/src/layers/useLayers.d.ts +58 -0
  105. package/src/layers/useMarkers/adaptiveHelpers.d.ts +156 -0
  106. package/src/layers/useMarkers/resolveServerClusters.d.ts +26 -0
  107. package/src/layers/useMarkers/useAdaptiveMarkerHelpers.d.ts +38 -0
  108. package/src/layers/useMarkers/useMarkers.d.ts +127 -0
  109. package/src/layers/useShapes/InteractiveDecoration.d.ts +23 -0
  110. package/src/layers/useShapes/MultiGeometryPlusBadge.d.ts +17 -0
  111. package/src/layers/useShapes/MultiPartBadge.d.ts +11 -0
  112. package/src/layers/useShapes/ShapeAnnotationLabel.d.ts +30 -0
  113. package/src/layers/useShapes/ShapeIcon.d.ts +21 -0
  114. package/src/layers/useShapes/ShapeLabelPill.d.ts +25 -0
  115. package/src/layers/useShapes/buildShapeLabelResolutionContext.d.ts +23 -0
  116. package/src/layers/useShapes/decorationFactories.d.ts +47 -0
  117. package/src/layers/useShapes/edge/ShapeEdgeLabel.d.ts +13 -0
  118. package/src/layers/useShapes/edge/computeEdgeAutoPlacement.d.ts +69 -0
  119. package/src/layers/useShapes/edge/computeEdgeProperties.d.ts +21 -0
  120. package/src/layers/useShapes/edge/edgeInsetsForFeature.d.ts +27 -0
  121. package/src/layers/useShapes/edge/edgeReservations.d.ts +36 -0
  122. package/src/layers/useShapes/edge/findBestEdgePosition.d.ts +247 -0
  123. package/src/layers/useShapes/extractMultiParts.d.ts +25 -0
  124. package/src/layers/useShapes/findBestVisibleVertex.d.ts +18 -0
  125. package/src/layers/useShapes/multiPartDecorations.d.ts +19 -0
  126. package/src/layers/useShapes/shapeDecorations.d.ts +154 -0
  127. package/src/layers/useShapes/shapeFeatureBuilders.d.ts +25 -0
  128. package/src/layers/useShapes/shapeLabelPolicy.d.ts +42 -0
  129. package/src/layers/useShapes/shapeLabelResolution.d.ts +45 -0
  130. package/src/layers/useShapes/shapeSyntheticMarkerRender.d.ts +16 -0
  131. package/src/layers/useShapes/useShapeDecorations.d.ts +56 -0
  132. package/src/layers/useShapes/useShapeLabelHelpers.d.ts +29 -0
  133. package/src/layers/useShapes/useShapes.d.ts +50 -0
  134. package/src/markers/MapMarker.d.ts +115 -0
  135. package/src/markers/MapMarkerIcon.d.ts +21 -0
  136. package/src/markers/animation/applyStickFrame.d.ts +15 -0
  137. package/src/markers/animation/spring.d.ts +45 -0
  138. package/src/markers/animation/stickFrame.d.ts +82 -0
  139. package/src/markers/animation/usePillBackgroundPaint.d.ts +15 -0
  140. package/src/markers/animation/useStickAnimation.d.ts +21 -0
  141. package/src/markers/animation/useStickTween.d.ts +28 -0
  142. package/src/markers/geometry/stickPositioning.d.ts +69 -0
  143. package/src/markers/geometry/useDirectionIndicator.d.ts +8 -0
  144. package/src/markers/internal/MapMarkerStickSurface.d.ts +47 -0
  145. package/src/markers/model/mapMarkerDomPortalStacking.d.ts +22 -0
  146. package/src/markers/model/markerDomTypes.d.ts +68 -0
  147. package/src/markers/model/markerResolvers.d.ts +34 -0
  148. package/src/markers/model/markerSizeMap.d.ts +82 -0
  149. package/src/markers/model/markerTuningParams.d.ts +60 -0
  150. package/src/markers/model/useMarkerStateResolvers.d.ts +25 -0
  151. package/src/markers/shared/MarkerAnimatedSurface.d.ts +20 -0
  152. package/src/markers/shared/MarkerDiscContent.d.ts +11 -0
  153. package/src/markers/shared/mapMarkerVariants.d.ts +35 -0
  154. package/src/markers/shared/markerColors.d.ts +55 -0
  155. package/src/markers/shared/useMarkerColors.d.ts +23 -0
  156. package/src/markers/stories/demoes/AnimationCircleVsPillDemo.d.ts +7 -0
  157. package/src/markers/stories/demoes/CircleIconGuidanceDemo.d.ts +2 -0
  158. package/src/markers/stories/demoes/DefaultDemo.d.ts +14 -0
  159. package/src/markers/stories/demoes/DirectionBehaviorDemo.d.ts +2 -0
  160. package/src/markers/stories/demoes/PillLabelLengthsDemo.d.ts +2 -0
  161. package/src/markers/stories/demoes/StatesDemo.d.ts +7 -0
  162. package/src/markers/stories/demoes/StickModeDemo.d.ts +2 -0
  163. package/src/markers/stories/demoes/StickModePlaygroundDemo.d.ts +10 -0
  164. package/src/markers/stories/helpers/AbsoluteGridPicker.d.ts +17 -0
  165. package/src/markers/stories/helpers/InlineLabel.d.ts +4 -0
  166. package/src/markers/stories/helpers/InlineSlider.d.ts +11 -0
  167. package/src/markers/stories/helpers/LabeledMarker.d.ts +7 -0
  168. package/src/markers/stories/helpers/MarkerRow.d.ts +4 -0
  169. package/src/markers/stories/helpers/SectionHeader.d.ts +4 -0
  170. package/src/markers/stories/helpers/StatesMarkerCell.d.ts +15 -0
  171. package/src/markers/stories/helpers/ThemedPreview.d.ts +10 -0
  172. package/src/markers/stories/helpers/mapMarkerStoryConstants.d.ts +4 -0
  173. package/src/panel/Panel.d.ts +60 -0
  174. package/src/panel/PanelOrchestrator.d.ts +24 -0
  175. package/src/panel/preload/preloadInitiators.d.ts +44 -0
  176. package/src/panel/preload/useHoverPreloadInitiator.d.ts +8 -0
  177. package/src/panel/preload/usePanelPreload.d.ts +46 -0
  178. package/src/panel/preload/useProximityPreloadInitiator.d.ts +13 -0
  179. package/src/panel/store/panels.d.ts +76 -0
  180. package/src/panel/storyHelpers.d.ts +9 -0
  181. package/src/panel/usePanel.d.ts +81 -0
  182. package/src/panel/utils/autoPan.d.ts +78 -0
  183. package/src/panel/utils/panelShellConstants.d.ts +8 -0
  184. package/src/panel/utils/useAutoPanResolver.d.ts +23 -0
  185. package/src/panel/utils/useWheelForwarding.d.ts +18 -0
  186. package/src/stories/InteractionDisplay.d.ts +9 -0
  187. package/src/stories/PositionDisplay.d.ts +9 -0
  188. package/src/stories/_storyCoordUtils.d.ts +8 -0
  189. package/src/testing/mockMapApi.d.ts +29 -0
  190. package/src/translation.d.ts +30 -0
  191. package/translation.cjs.js +30 -0
  192. package/translation.cjs10.js +30 -0
  193. package/translation.cjs11.js +30 -0
  194. package/translation.cjs12.js +30 -0
  195. package/translation.cjs13.js +30 -0
  196. package/translation.cjs14.js +30 -0
  197. package/translation.cjs15.js +30 -0
  198. package/translation.cjs16.js +30 -0
  199. package/translation.cjs17.js +30 -0
  200. package/translation.cjs2.js +30 -0
  201. package/translation.cjs3.js +30 -0
  202. package/translation.cjs4.js +30 -0
  203. package/translation.cjs5.js +30 -0
  204. package/translation.cjs6.js +30 -0
  205. package/translation.cjs7.js +30 -0
  206. package/translation.cjs8.js +30 -0
  207. package/translation.cjs9.js +30 -0
  208. package/translation.esm.js +28 -0
  209. package/translation.esm10.js +28 -0
  210. package/translation.esm11.js +28 -0
  211. package/translation.esm12.js +28 -0
  212. package/translation.esm13.js +28 -0
  213. package/translation.esm14.js +28 -0
  214. package/translation.esm15.js +28 -0
  215. package/translation.esm16.js +28 -0
  216. package/translation.esm17.js +28 -0
  217. package/translation.esm2.js +28 -0
  218. package/translation.esm3.js +28 -0
  219. package/translation.esm4.js +28 -0
  220. package/translation.esm5.js +28 -0
  221. package/translation.esm6.js +28 -0
  222. package/translation.esm7.js +28 -0
  223. package/translation.esm8.js +28 -0
  224. package/translation.esm9.js +28 -0
package/README.md ADDED
@@ -0,0 +1,296 @@
1
+ # @trackunit/react-map
2
+
3
+ Contains core map components.
4
+
5
+ Checklist:
6
+ [x]Both Google Maps and Mapbox adapters are implemented.
7
+
8
+ -----
9
+
10
+ Provider-agnostic map library for React applications. Switch between Google Maps and Mapbox seamlessly without code changes.
11
+
12
+ ## Features
13
+
14
+ - **Provider Agnostic**: Use Google Maps or Mapbox with the same API
15
+ - **Type Safe**: Full TypeScript support with zero type assertions
16
+ - **Reactive**: Automatic state updates using `useSyncExternalStore`
17
+ - **Accessible**: ARIA labels and keyboard navigation built-in
18
+ - **Extensible**: Easy to add new map providers
19
+
20
+ ## Installation
21
+
22
+ The library is part of the monorepo. Dependencies are:
23
+ - `@vis.gl/react-google-maps` - Google Maps integration
24
+ - `mapbox-gl` - Mapbox GL JS integration
25
+ - `@trackunit/geo-json-utils` - GeoJSON type definitions
26
+
27
+ Import map providers from the adapter packages, not from `@trackunit/react-map`:
28
+ - Google Maps: `@trackunit/react-map-adapter-google` (`googleMapsAdapter`, `GoogleApiProvider`, …)
29
+ - Mapbox: `@trackunit/react-map-adapter-mapbox` (`mapboxAdapter`, …)
30
+
31
+ ## Usage
32
+
33
+ ### Google Maps
34
+
35
+ ```tsx
36
+ import { useCameraState, useMap } from "@trackunit/react-map";
37
+ import { googleMapsAdapter } from "@trackunit/react-map-adapter-google";
38
+
39
+ const MyMap = () => {
40
+ const [Map, api] = useMap(googleMapsAdapter({
41
+ apiKey: process.env.GOOGLE_MAPS_API_KEY,
42
+ theme: "light",
43
+ language: "en",
44
+ }));
45
+
46
+ const { center, zoom } = useCameraState(api);
47
+
48
+ return (
49
+ <div className="relative h-full">
50
+ <p>Center: {center[0]}, {center[1]}</p>
51
+ <p>Zoom: {zoom}</p>
52
+ <Map className="h-full w-full">
53
+ {/* Children render inside the map */}
54
+ </Map>
55
+ </div>
56
+ );
57
+ };
58
+ ```
59
+
60
+ ### Mapbox
61
+
62
+ ```tsx
63
+ import { useCameraState, useMap } from "@trackunit/react-map";
64
+ import { mapboxAdapter } from "@trackunit/react-map-adapter-mapbox";
65
+
66
+ const MyMap = () => {
67
+ const [Map, api] = useMap(mapboxAdapter({
68
+ accessToken: process.env.MAPBOX_ACCESS_TOKEN,
69
+ theme: "dark",
70
+ language: "en",
71
+ }));
72
+
73
+ const { center, zoom } = useCameraState(api);
74
+
75
+ return (
76
+ <div className="relative h-full">
77
+ <p>Center: {center[0]}, {center[1]}</p>
78
+ <p>Zoom: {zoom}</p>
79
+ <Map className="h-full w-full">
80
+ {/* Same children work with both Google and Mapbox! */}
81
+ </Map>
82
+ </div>
83
+ );
84
+ };
85
+ ```
86
+
87
+ ## API
88
+
89
+ ### `useMap(adapter)`
90
+
91
+ Returns a tuple `[Map, api]`:
92
+
93
+ - `Map` - React component to render the map
94
+ - `api.state` - Map status (isReady, initializationFailed, appearance, rasterResolution)
95
+ - `useCameraState(api)` - Reactive camera state (center, zoom, bounds, isIdle — changes at up to 60fps)
96
+ - `api.actions.setCenter(position)` - Set map center (returns promise)
97
+ - `api.actions.setZoom(zoom)` - Set zoom level (returns promise)
98
+ - `api.actions.zoomBy(delta)` - Adjust zoom by delta (returns promise)
99
+ - `api.actions.fitBounds(bounds, options)` - Fit map to bounds (returns promise)
100
+ - `api.actions.panTo(position)` - Pan to position with animation (returns promise)
101
+ - `api.on(event, handler)` - Subscribe to map events (returns unsubscribe function)
102
+
103
+ ### Coordinates
104
+
105
+ All coordinates use GeoJSON format: `[longitude, latitude]`
106
+
107
+ ```tsx
108
+ const berlin: GeoJsonPosition = [13.405, 52.52]; // [lng, lat]
109
+ ```
110
+
111
+ ### Bounding Boxes
112
+
113
+ All bounding boxes use GeoJSON format: `[minLng, minLat, maxLng, maxLat]`
114
+
115
+ ```tsx
116
+ const europeBounds: GeoJsonBbox = [-10, 35, 40, 70];
117
+ ```
118
+
119
+ ### Map Actions
120
+
121
+ All actions return promises that resolve when the map finishes moving:
122
+
123
+ ```tsx
124
+ await api.actions.setCenter([13.405, 52.52]);
125
+ await api.actions.setZoom(12);
126
+ await api.actions.fitBounds([-10, 35, 40, 70], { padding: 50, maxZoom: 15 });
127
+ ```
128
+
129
+ ### Map State
130
+
131
+ `api.state` contains low-frequency MapStatus (readiness, initialization failure, appearance, raster resolution). For CameraState that changes during panning/zooming, use `useCameraState(api)`:
132
+
133
+ ```tsx
134
+ // Initialization state — rarely changes
135
+ const { isReady, appearance } = api.state;
136
+
137
+ // Camera state — changes at up to 60fps during panning
138
+ const { center, zoom, bounds, isIdle } = useCameraState(api);
139
+
140
+ // Only re-renders when zoom changes (opt-in)
141
+ const { zoom } = useCameraState(api);
142
+ useEffect(() => {
143
+ console.log("Zoom changed:", zoom);
144
+ }, [zoom]);
145
+ ```
146
+
147
+ ### Map Events
148
+
149
+ Subscribe to map events with type-safe handlers:
150
+
151
+ ```tsx
152
+ useEffect(() => {
153
+ const unsubscribe = api.on("click", (e) => {
154
+ console.log("Clicked at:", e.position);
155
+ });
156
+
157
+ return unsubscribe;
158
+ }, [api.on]);
159
+ ```
160
+
161
+ Available events:
162
+ - `idle` - Map finished moving
163
+ - `movestart` - Map started moving
164
+ - `moveend` - Map finished moving (includes final state)
165
+ - `click` - Map clicked (includes position and original event)
166
+
167
+ ## Switching Providers
168
+
169
+ To switch providers, only change the adapter configuration:
170
+
171
+ ```tsx
172
+ // Before: Google Maps
173
+ const [Map, api] = useMap(googleMapsAdapter({ apiKey: "..." }));
174
+
175
+ // After: Mapbox
176
+ const [Map, api] = useMap(mapboxAdapter({ accessToken: "..." }));
177
+
178
+ // Everything else stays the same!
179
+ ```
180
+
181
+ ## Configuration Options
182
+
183
+ ### Google Maps Config
184
+
185
+ ```tsx
186
+ type GoogleMapsConfig = {
187
+ apiKey: string; // Required
188
+ theme?: "light" | "dark"; // Default: "light"
189
+ language?: string; // Map labels language
190
+ initialViewport?: InitialViewport; // Initial view: center+zoom or bounds
191
+ restrictBounds?: GeoJsonBbox | null; // Default: no restriction; null = no restriction
192
+ };
193
+ ```
194
+
195
+ ### Mapbox Config
196
+
197
+ ```tsx
198
+ type MapboxConfig = {
199
+ accessToken: string; // Required
200
+ theme?: "light" | "dark"; // Default: "light"
201
+ language?: string; // Map labels language
202
+ initialViewport?: InitialViewport; // Initial view: center+zoom or bounds
203
+ restrictBounds?: GeoJsonBbox | null; // Default: no restriction; null = no restriction
204
+ };
205
+ ```
206
+
207
+ `restrictBounds` controls panning/zoom bounds. GeoJSON format: `[minLng, minLat, maxLng, maxLat]`.
208
+ - `undefined` (default): no restriction (infinite horizontal scroll)
209
+ - `null`: no restriction (infinite horizontal scroll)
210
+ - `GeoJsonBbox`: restrict to custom region (e.g. Europe: `[-10, 35, 40, 70]`)
211
+
212
+ Invalid bboxes are validated with `geoJsonBboxSchema`; on failure, a console warning is emitted and no restriction is applied (fallback to `null`).
213
+
214
+ `InitialViewport` is a discriminated union:
215
+ - `{ type: "center"; center: [lng, lat]; zoom?: number }` — center with optional zoom
216
+ - `{ type: "bounds"; bounds: GeoJsonBbox; padding?: number; maxZoom?: number }` — fit to bounds
217
+
218
+ ## Accessibility
219
+
220
+ Maps include built-in accessibility features:
221
+
222
+ - ARIA labels and roles
223
+ - Keyboard navigation:
224
+ - Arrow keys: Pan map (100px)
225
+ - +/-: Zoom in/out (1 level)
226
+ - Home: Reset to default view
227
+ - Tab: Focus map
228
+ - Escape: Deselect/close popups
229
+
230
+ ## Architecture
231
+
232
+ For the high-level architecture, motivation, design principles, and rollout strategy, see the **[Map 2026 Design Doc](https://github.com/niceideas/design-docs/blob/main/docs/202602-Manager-Map2026/202602-Manager-Map2026.md)** in the design-docs repo.
233
+
234
+ Implementation detail in this repo is split between **[CONTEXT.md](CONTEXT.md)** (domain language and how concepts relate) and **[docs/adr/](docs/adr/)** (short architecture decision records).
235
+
236
+ | Document | What it covers |
237
+ |----------|---------------|
238
+ | [CONTEXT.md](CONTEXT.md) | Glossary: Adapter, Layer Hook, Layer Handle, Layer Port, Entity, Control Config, Annotation, Decoration, and relationships between them |
239
+ | [ADR 0001 — Hook-first map API](docs/adr/0001-hook-first-api.md) | `useMap(adapter)` tuple as the primary API; tuple vs object vs component-first |
240
+ | [ADR 0002 — Adapter factory pattern](docs/adr/0002-adapter-factory-pattern.md) | Adapter factories, `defineAdapter`, `derive`, keeping provider knowledge at the call site |
241
+ | [ADR 0003 — Controls as data](docs/adr/0003-controls-as-data.md) | Control configs as data, discriminated union, middleware pipeline, presentational renderers |
242
+ | [ADR 0004 — Declarative LayerPort snapshot](docs/adr/0004-layer-port-declarative-snapshot.md) | `LayerPort.setSnapshot`, single write path, adapter-owned diffing |
243
+ | [ADR 0005 — Annotation store on MapApi](docs/adr/0005-annotation-store-on-map-api.md) | `MapApi.annotations`, explicit `api` at call sites, renderer claims |
244
+ | [ADR 0006 — Adapters own DOM marker positioning](docs/adr/0006-marker-anchor-ownership.md) | Marker anchors owned by the adapter; no competing transforms in DOM content |
245
+ | [ADR 0007 — Antimeridian shapes merged in adapters](docs/adr/0007-antimeridian-merge-in-adapters.md) | Merging split GeoJSON at render time inside adapters, not in app state |
246
+ | [ADR 0008 — Map panel store on MapApi](docs/adr/0008-map-panel-store-on-map-api.md) | `MapApi.panels`, `usePanel`, `PanelOrchestrator`, menu presentation via panels |
247
+ | [ADR 0009 — Declarative MarkerState](docs/adr/0009-declarative-marker-state.md) | State-driven union prop over imperative marker API |
248
+ | [ADR 0010 — Unified marker render tree](docs/adr/0010-unified-marker-render-tree.md) | Always-mounted slots animated via CSS; no separate circle/pill components |
249
+ | [ADR 0011 — Stick mode anchor-zero + transform animation](docs/adr/0011-stick-anchor-zero-transform-animation.md) | Zero-size anchor container; CSS three-function transform; no JS width measurement |
250
+ | [ADR 0012 — Fixed size ladder with locked pill tier](docs/adr/0012-marker-size-ladder-fixed-pill-tier.md) | Five-tier `MarkerDomSize` enum; pill layout fixed to `md` tier |
251
+ | [ADR 0013 — GpsArrowNorth icon](docs/adr/0013-gps-arrow-north-icon.md) | North-facing SVG variant eliminates `heading - 45` magic offset at call sites |
252
+ | [ADR 0020 — Map state is split by update frequency](docs/adr/0020-map-state-channels.md) | `MapStatus` on `api.state`, `CameraState` via `useCameraState(api)`, and separate adapter notification channels |
253
+ | [@trackunit/react-map-adapter-google README](../map-adapter-google/README.md) | Google Maps adapter: exports, `GoogleApiProvider`, multiple maps |
254
+ | [@trackunit/react-map-adapter-mapbox README](../map-adapter-mapbox/README.md) | Mapbox adapter: exports, configuration, typical usage |
255
+
256
+ ## Testing
257
+
258
+ ```bash
259
+ # Run all tests
260
+ yarn nx test react-map
261
+
262
+ # Run type checking
263
+ yarn nx run react-map:tsc-validate
264
+
265
+ # Run linting
266
+ yarn nx lint react-map
267
+ ```
268
+
269
+ ## Adding New Providers
270
+
271
+ To add a new map provider:
272
+
273
+ 1. Create adapter instance implementing `AdapterInstance<TConfig>`
274
+ 2. Create type converters (GeoJSON ↔ provider types)
275
+ 3. Create renderer component
276
+ 4. Create adapter factory using `defineAdapter()`
277
+ 5. Export from `index.ts`
278
+
279
+ Example structure:
280
+ ```
281
+ src/adapters/leaflet/
282
+ ├── leafletAdapter.ts
283
+ ├── LeafletAdapterInstance.ts
284
+ ├── LeafletRenderer.tsx
285
+ ├── leafletTypeConverters.ts
286
+ └── constants.ts
287
+ ```
288
+
289
+ For more info and a full guide on Iris App SDK Development, please visit our [Developer Hub](https://developers.trackunit.com/).
290
+
291
+ ## Trackunit
292
+
293
+ This package was developed by Trackunit ApS.
294
+ Trackunit is the leading SaaS-based IoT solution for the construction industry, offering an ecosystem of hardware, fleet management software & telematics.
295
+
296
+ ![The Trackunit logo](https://trackunit.com/wp-content/uploads/2022/03/top-logo.svg)