@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
@@ -0,0 +1,34 @@
1
+ import { type GeoJsonBbox, type GeoJsonGeometry, type GeoJsonPosition } from "@trackunit/geo-json-utils";
2
+ import type { FitBoundsOptions, MapApi } from "../../core/types";
3
+ /**
4
+ * Compute a bounding box from an array of positions.
5
+ * Returns null if the array is empty.
6
+ *
7
+ * @param positions - Array of [longitude, latitude] positions
8
+ * @returns GeoJsonBbox as [minLon, minLat, maxLon, maxLat] or null
9
+ */
10
+ export declare const computeBoundsFromPositions: (positions: ReadonlyArray<GeoJsonPosition>) => GeoJsonBbox | null;
11
+ /**
12
+ * For a GeoJSON bbox `[minLon, minLat, maxLon, maxLat]`, returns the **larger**
13
+ * of the east–west extent and the north–south extent, in **degrees**.
14
+ *
15
+ * Used when choosing `fitBounds` padding so padding follows the longer geographic
16
+ * axis (a very thin box still gets a sensible scale).
17
+ */
18
+ export declare const maxLongitudeLatitudeSpanDegrees: (bbox: GeoJsonBbox) => number;
19
+ /**
20
+ * Compute dynamic fitBounds options based on the geographic span of a bounding box.
21
+ * Smaller shapes get more padding and a maxZoom cap to avoid over-zooming;
22
+ * larger shapes get less padding.
23
+ */
24
+ export declare const computeFitPadding: (maxSpanDegrees: number) => FitBoundsOptions;
25
+ /**
26
+ * Compute bounds from a geometry and fit the map viewport with span-based dynamic padding.
27
+ * No-op if the geometry yields no positions (e.g. empty GeometryCollection).
28
+ */
29
+ export declare const fitFeatureBounds: (api: MapApi, geometry: GeoJsonGeometry) => void;
30
+ /**
31
+ * Merge multiple bounding boxes into one that encompasses all of them.
32
+ * Ignores null entries. Returns null if all inputs are null.
33
+ */
34
+ export declare const mergeBounds: (boxes: ReadonlyArray<GeoJsonBbox | null>) => GeoJsonBbox | null;
@@ -0,0 +1,14 @@
1
+ import { type GeoJsonBbox, type GeoJsonFeatureCollection } from "@trackunit/geo-json-utils";
2
+ /**
3
+ * Count features in `collection` whose geometry overlaps (or touches) `bounds`.
4
+ *
5
+ * Returns the total feature count when `bounds` is null (e.g. before the map
6
+ * has reported its first viewport). For Point features this is equivalent to
7
+ * the previous marker-only point-in-bounds check; for non-Point features it is
8
+ * a cheap bbox-vs-bbox intersection — full geometry clipping is intentionally
9
+ * avoided since this runs every adaptive resolution pass.
10
+ *
11
+ * Shared by both the marker adaptive resolution system and the shape label
12
+ * resolution system so the two never disagree on what "in viewport" means.
13
+ */
14
+ export declare const countFeaturesInViewport: (collection: GeoJsonFeatureCollection, bounds: Readonly<GeoJsonBbox> | null) => number;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Create a getter that lazily computes and caches a value.
3
+ * The getter calls `compute` on first invocation and returns
4
+ * the cached result on subsequent calls.
5
+ *
6
+ * Designed for use with `useMemo`:
7
+ * ```ts
8
+ * const getBounds = useMemo(
9
+ * () => createLazyGetter(() => computeBounds(data)),
10
+ * [data]
11
+ * );
12
+ * ```
13
+ * When `useMemo` re-runs (deps changed), a fresh getter with an
14
+ * empty cache is created, discarding the old one.
15
+ */
16
+ export declare const createLazyGetter: <TValue>(compute: () => TValue) => (() => TValue);
@@ -0,0 +1,18 @@
1
+ import type { DomPortalDescriptor, DomRenderState, MapTheme } from "@trackunit/react-map-adapter-shared";
2
+ import type { UseLayersReturn } from "../useLayers";
3
+ export declare const EMPTY_PORTALS: ReadonlyArray<DomPortalDescriptor>;
4
+ /** No-op subscribe for when a marker/cluster portal store is not available */
5
+ export declare const noopSubscribe: (_callback: () => void) => (() => void);
6
+ /** Empty snapshot for when a marker/cluster portal store is not available */
7
+ export declare const emptySnapshot: () => ReadonlyArray<DomPortalDescriptor>;
8
+ export declare const DEFAULT_RENDER_STATE: DomRenderState;
9
+ /** Delay before clearing hover state to prevent flickering from rapid mouseleave/mouseenter pairs */
10
+ export declare const HOVER_END_DEBOUNCE_MS = 100;
11
+ /**
12
+ * Compute `DomRenderState` for a given feature ID by checking
13
+ * whether it matches the current selected/hovered entity.
14
+ *
15
+ * `isMounting` is always `false` until slice 6 (SAGA-424) wires
16
+ * `useMarkerMountBridge`.
17
+ */
18
+ export declare const computeItemRenderState: (featureId: string, interaction: UseLayersReturn["interaction"], theme?: MapTheme, labelVisible?: boolean) => DomRenderState;
@@ -0,0 +1,17 @@
1
+ import { type ClusterRenderConfig, type DomRenderState, type RenderConfig } from "@trackunit/react-map-adapter-shared";
2
+ import type { LayerHandle, MarkerLayerHandle } from "../types";
3
+ export declare const findMarkersLayerHandle: (handles: ReadonlyArray<LayerHandle>, sourceId: string) => MarkerLayerHandle | undefined;
4
+ /**
5
+ * Resolves the CSS `z-index` for a marker/cluster DOM portal container.
6
+ *
7
+ * When `resolveDomPortalStacking` is omitted on the active render config,
8
+ * falls back to the pre–stacking-hierarchy behavior: `circle` geometry with
9
+ * interaction-only phases.
10
+ *
11
+ * Accepts both marker `RenderConfig` and cluster `ClusterRenderConfig`. The
12
+ * `DomRenderState` passed in is the marker-shaped state computed by `<Layers>`
13
+ * for z-index purposes (clusters use the same hovered/selected phase
14
+ * vocabulary even though their render callback ultimately receives a simpler
15
+ * `ClusterRenderState`).
16
+ */
17
+ export declare const resolveMarkerPortalContainerZIndex: (renderConfig: RenderConfig<unknown> | ClusterRenderConfig<unknown, unknown>, sourceData: unknown, itemState: DomRenderState) => number;
@@ -0,0 +1,13 @@
1
+ import type { Entity } from "@trackunit/react-map-adapter-shared";
2
+ import type { MapApi } from "../../core/types";
3
+ import type { LayerHandle } from "../types";
4
+ /**
5
+ * Creates a dblclick handler that fits the viewport to the double-clicked
6
+ * entity's bounds. Behaviour per entity type:
7
+ *
8
+ * - **shape**: fit to the individual feature's geometry
9
+ * - **marker**: panTo + zoom to a close level
10
+ * - **cluster**: fit to bounds of contained markers when any resolve from loaded handles; if none (e.g. server cluster), fit to `bbox` when present on the entity
11
+ * - **route**: fit to the route layer's bounds
12
+ */
13
+ export declare const useDblClickFit: (api: MapApi | undefined, handles: ReadonlyArray<LayerHandle>) => ((entity: Entity) => void) | undefined;
@@ -0,0 +1,21 @@
1
+ import type { Entity, LayerPort } from "@trackunit/react-map-adapter-shared";
2
+ type UseEntityInteractionConfig = Readonly<{
3
+ layerPort: LayerPort | null;
4
+ hover: (entity: Entity | null) => void;
5
+ select: (entity: Entity | null) => void;
6
+ dblClick?: (entity: Entity) => void;
7
+ }>;
8
+ /**
9
+ * Subscribes to entity interaction events (click, dblclick, hover-start,
10
+ * hover-end) from the map adapter and dispatches to the provided callbacks.
11
+ *
12
+ * Hover-end is debounced to prevent flickering from rapid mouseleave/mouseenter
13
+ * pairs when the cursor moves within a marker's DOM tree.
14
+ *
15
+ * @returns A stable callback to guard/unguard against adapter hover events.
16
+ * Call with `true` when a DOM-path hover begins (cancels pending timers and
17
+ * suppresses adapter hover-start/hover-end). Call with `false` when the DOM
18
+ * hover ends, allowing adapter events to flow again.
19
+ */
20
+ export declare const useEntityInteraction: ({ layerPort, hover, select, dblClick, }: UseEntityInteractionConfig) => ((active: boolean) => void);
21
+ export {};
@@ -0,0 +1,19 @@
1
+ import { fitFeatureBounds } from "./computeBounds";
2
+ export type FitFeatureBoundsHelpers = Readonly<{
3
+ fitFeatureBounds: typeof fitFeatureBounds;
4
+ }>;
5
+ /**
6
+ * Build-your-own hook: stable reference to the `fitFeatureBounds` map action.
7
+ *
8
+ * Returns the `fitFeatureBounds` helper for consumers who need to programmatically
9
+ * zoom/fit the viewport to a GeoJSON geometry — for example in click handlers that
10
+ * should navigate to a selected shape or annotation.
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * const { fitFeatureBounds } = useFitFeatureBounds();
15
+ * // On click:
16
+ * fitFeatureBounds(api, feature.geometry);
17
+ * ```
18
+ */
19
+ export declare const useFitFeatureBounds: () => FitFeatureBoundsHelpers;
@@ -0,0 +1,18 @@
1
+ import type { LayerPort, MapInteractionState, MapLayer } from "@trackunit/react-map-adapter-shared";
2
+ import { type RefObject } from "react";
3
+ import type { LayerHandle } from "../types";
4
+ export type UseLayerHandleSyncReturn = Readonly<{
5
+ renderedSourceIds: RefObject<Set<string>>;
6
+ hasSourceReadiness: boolean;
7
+ readyRevision: number;
8
+ }>;
9
+ /**
10
+ * Syncs layer handles and interaction state to the map adapter via `LayerPort.setSnapshot`.
11
+ *
12
+ * Computes a full `LayerSnapshot` from the current handles and interaction state
13
+ * and pushes it to the adapter on every change. The adapter owns the diff.
14
+ *
15
+ * Also manages `onSourceReady` subscriptions for shape layers so edge labels
16
+ * can defer rendering until the parent shape source has finished drawing.
17
+ */
18
+ export declare const useLayerHandleSync: (layerPort: LayerPort | null, handles: ReadonlyArray<LayerHandle>, interaction: MapInteractionState, decorationLayers?: ReadonlyArray<MapLayer>) => UseLayerHandleSyncReturn;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Result of the `useLayerReady` hook.
3
+ * Provides the `ready` promise, `loadsData` flag, and current `isLoading` state
4
+ * for use in layer handles.
5
+ */
6
+ export type LayerReadyResult = Readonly<{
7
+ /** Resolves when initial data is available. Stable reference across renders. */
8
+ ready: Promise<void>;
9
+ /** Whether this layer fetches its own data (true when `loading` arg is provided). */
10
+ loadsData: boolean;
11
+ /** Current loading state. */
12
+ isLoading: boolean;
13
+ }>;
14
+ /**
15
+ * Shared hook that tracks initial data readiness for a layer.
16
+ *
17
+ * - `loading: undefined` -> not a data-loading layer; ready immediately.
18
+ * - `loading: false` -> data-loading layer with data already available; ready immediately.
19
+ * - `loading: true` -> data-loading layer still waiting; ready is a deferred promise
20
+ * that resolves on the first `true -> false` transition.
21
+ *
22
+ * Once resolved, the promise stays resolved. Subsequent `true -> false` cycles
23
+ * do NOT re-pend -- this hook tracks *initial* readiness only.
24
+ */
25
+ export declare const useLayerReady: (loading?: boolean) => LayerReadyResult;
@@ -0,0 +1,41 @@
1
+ import type { RenderMedium } from "@trackunit/react-map-adapter-shared";
2
+ export type UseMarkerMountBridgeReturn = Readonly<{
3
+ mountingIds: ReadonlySet<string>;
4
+ }>;
5
+ /**
6
+ * Pure transition detector — returns the subset of `currentMediums` whose
7
+ * medium is `"dom"` and whose previous medium was `"symbol"`. Exported for
8
+ * unit tests; the React hook below is the consumer.
9
+ */
10
+ export declare const computeMountingFeatureIds: (currentMediums: ReadonlyMap<string, RenderMedium>, previousMediums: ReadonlyMap<string, RenderMedium>, existingIds: ReadonlySet<string>) => Set<string>;
11
+ /**
12
+ * State-machine hook tracking `symbol → dom` transitions for adaptive markers
13
+ * (ADR-0009 §"Mounting bridge").
14
+ *
15
+ * On the commit where a feature's medium first appears as `"dom"` (after
16
+ * having been `"symbol"`), its id is included in `mountingIds`. On the next
17
+ * commit, `mountingIds` is empty again. `<Layers>` uses this signal to
18
+ * synthesize a first-commit render state with `isMounting: true` and
19
+ * `selected`/`hovered: false` so consumer-side CSS animations can morph from
20
+ * a small "default" footprint into the resting hover/select form.
21
+ *
22
+ * The hook is purely a state machine — it does not touch the DOM or the map
23
+ * adapter. The caller decides what `currentMediums` reflects; in `<Layers>`'s
24
+ * case it is derived from the published DOM portal descriptors so that the
25
+ * transition is detected at the moment the portal first renders, with
26
+ * non-portal adaptive features defaulting to `"symbol"`.
27
+ *
28
+ * Per-feature `previousMedium` is intentionally not exposed in the public
29
+ * render state — only `isMounting` (Q5 of the SAGA-414 design grilling).
30
+ *
31
+ * The two-pass mechanism is owned here: an internal mount store holds the
32
+ * `previousMediums` map and the active `mountingIds` set, and notifies
33
+ * subscribers via `useSyncExternalStore` rather than a React `setState` (so
34
+ * the cascading-render guard rail does not block the legitimate two-pass
35
+ * pattern). The detection layout effect calls `advance`; the passive clear
36
+ * effect calls `clear` after the browser has had a chance to paint the
37
+ * populated set once.
38
+ */
39
+ export declare const useMarkerMountBridge: (features: ReadonlyArray<{
40
+ id: string;
41
+ }>, currentMediums: ReadonlyMap<string, RenderMedium>) => UseMarkerMountBridgeReturn;
@@ -0,0 +1,34 @@
1
+ import { type GeoJsonBbox, type GeoJsonFeature } from "@trackunit/geo-json-utils";
2
+ import type { MapApi } from "../../core/types";
3
+ /**
4
+ * Shared map view state consumed by adaptive rendering systems (marker render
5
+ * medium selection and shape label resolution). Combines high-frequency camera
6
+ * values with low-frequency tile size, so viewport reading is defined once.
7
+ */
8
+ export type ViewportContext = Readonly<{
9
+ zoom: number;
10
+ bounds: Readonly<GeoJsonBbox> | null;
11
+ tileSize: number;
12
+ /**
13
+ * Returns `true` when the current viewport bounds are fully contained inside
14
+ * the given feature's geometry. Useful for suppressing edge labels and
15
+ * triggering annotation fallbacks when the user has zoomed into a shape.
16
+ *
17
+ * Returns `false` when bounds are not yet available or the feature has no
18
+ * polygon geometry.
19
+ */
20
+ isViewportInsideFeature: (feature: GeoJsonFeature) => boolean;
21
+ }>;
22
+ /**
23
+ * Reads `zoom` and `bounds` from the camera channel and `tileSize` from
24
+ * `api.state`, returning a stable `ViewportContext` reference that only changes
25
+ * when one of the underlying values changes. Falls back to sensible defaults
26
+ * while `api` is initializing.
27
+ *
28
+ * Stability matters because the result flows into `useMemo` deps in both
29
+ * `useAdaptiveMarkerResolution` and `useShapeDecorations` — if a new object
30
+ * came back every render the downstream resolution work would re-run for no
31
+ * reason. Bounds are projected to primitive deps so a fresh bbox array with
32
+ * equal values does not invalidate the memo.
33
+ */
34
+ export declare const useViewportContext: (api: MapApi | undefined) => ViewportContext;
@@ -0,0 +1,29 @@
1
+ import type { Icon } from "@trackunit/react-components";
2
+ import type { ComponentProps } from "react";
3
+ export type MapFocusTierDisplay = Readonly<{
4
+ /** Icon name for the marker icon slot and future legend. */
5
+ iconName?: ComponentProps<typeof Icon>["name"];
6
+ /** Hex color driving the marker (symbol + DOM) and future chart slice. */
7
+ color?: string;
8
+ /** Optional static label override used by future focus controls. */
9
+ label?: string;
10
+ }>;
11
+ export type MapFocusTier<TAsset> = Readonly<{
12
+ match: (asset: TAsset) => boolean;
13
+ /** Absent means this tier has no visual representation. */
14
+ display?: MapFocusTierDisplay;
15
+ }>;
16
+ /**
17
+ * Configurable policy driving marker expansion, icon, and color from a
18
+ * single asset property. Tiers are evaluated in order; first match wins.
19
+ */
20
+ export type MapFocus<TAsset> = Readonly<{
21
+ /**
22
+ * Stable id used by feature state (for example persisted user preference)
23
+ * instead of serializing predicate functions.
24
+ */
25
+ id: string;
26
+ tiers: ReadonlyArray<MapFocusTier<TAsset>>;
27
+ }>;
28
+ export { buildExpandedIds } from "./buildExpandedIds";
29
+ export { useExpandedIds } from "./useExpandedIds";
@@ -0,0 +1,39 @@
1
+ import { type GeoJsonPosition } from "@trackunit/geo-json-utils";
2
+ import type { ControlConfig } from "../../controls/types";
3
+ import type { FitParticipation, RouteLayerHandle, RouteStyle } from "../types";
4
+ export type UseRouteOptions = Readonly<{
5
+ /** Unique ID for this layer */
6
+ id: string;
7
+ /** Human-readable name */
8
+ name: string;
9
+ /** Ordered waypoints that define the route */
10
+ waypoints: ReadonlyArray<GeoJsonPosition>;
11
+ /** Route styling */
12
+ style: RouteStyle;
13
+ /** Whether the route is interactive (clickable/hoverable). Default: true */
14
+ interactive?: boolean;
15
+ /** Optional controls to contribute to the map UI */
16
+ controls?: ReadonlyArray<ControlConfig>;
17
+ /** Whether the layer is currently loading its initial data. Omit for static (non-loading) layers. */
18
+ loading?: boolean;
19
+ /** Controls whether this layer's bounds are included in fit-to-content operations. Default: `"all"` */
20
+ fitParticipation?: FitParticipation;
21
+ }>;
22
+ export type UseRouteReturn = RouteLayerHandle;
23
+ /**
24
+ * `useRoute` -- creates a route layer handle from an array of waypoints.
25
+ *
26
+ * Converts the waypoints to a GeoJSON LineString internally.
27
+ * Routes need at least 2 waypoints to be rendered.
28
+ *
29
+ * @example
30
+ * ```tsx
31
+ * const route = useRoute({
32
+ * id: "delivery-route",
33
+ * name: "Delivery Route",
34
+ * waypoints: [[-73.98, 40.75], [-73.97, 40.76], [-73.96, 40.77]],
35
+ * style: { color: "blue", width: 3, showDirectionArrows: true },
36
+ * });
37
+ * ```
38
+ */
39
+ export declare const useRoute: (options: UseRouteOptions) => UseRouteReturn;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Measure the rendered pixel width of label text using an off-screen probe
3
+ * styled with the same CSS classes as shape edge labels (`cvaShapeLabel`).
4
+ *
5
+ * Shape edge labels and other layout utilities that need a DOM-measured width use this.
6
+ *
7
+ * Results are cached per label text. In environments where DOM measurement is
8
+ * unavailable or returns zero (SSR, jsdom), falls back to a character-count
9
+ * estimate (label.length * 6 + 16).
10
+ */
11
+ export declare const measureLabelWidth: (label: string) => number;
@@ -0,0 +1,131 @@
1
+ import type { GeoJsonBbox, GeoJsonFeature, GeoJsonFeatureCollection, GeoJsonPosition } from "@trackunit/geo-json-utils";
2
+ import type { AdaptiveMarkerResolution, ClusterConfig, ClusterRenderConfig, RenderConfig, RouteStyle, ShapeInteractiveMode, ShapeStyle } from "@trackunit/react-map-adapter-shared";
3
+ import type { ControlConfig } from "../controls/types";
4
+ import type { ShapeDecoration } from "./useShapes/shapeDecorations";
5
+ import type { ShapeLabelResolutionContext } from "./useShapes/shapeLabelResolution";
6
+ export type { AdaptiveMarkerResolution, AdaptiveRenderConfig, AdaptiveRenderState, AdaptiveResolutionContext, CircleSymbolDescriptor, ClientClusterConfig, ClusterConfig, ClusterDomRenderConfig, ClusterInfo, ClusterRenderConfig, ClusterRenderState, ClusterSymbolRenderConfig, ClusterSymbolStyle, CommonRenderState, DomPortalStackingInput, DomPortalStackingResolver, DomPortalStackingResult, DomRenderConfig, DomRenderState, GeoJsonFeature, GeoJsonFeatureCollection, GeoJsonGeometry, MarkerAnchor, MarkerDomPortalStackGeometry, MarkerDomPortalStackPhase, PixelOffset, RenderConfig, RenderMedium, ResolutionContext, RouteStyle, ServerClusterConfig, ShapeInteractiveMode, ShapeStyle, ShapeStyleOverrides, SymbolDescriptor, SymbolRenderConfig, SymbolRenderState, } from "@trackunit/react-map-adapter-shared";
7
+ export { computeMarkerDomPortalZIndex } from "@trackunit/react-map-adapter-shared";
8
+ /**
9
+ * Controls whether a layer's bounds are included in fit-to-content operations.
10
+ *
11
+ * - `"all"` — participates in initial auto-fit, manual `fitNow()`, and future always-fit mode.
12
+ * - `"initial"` — only participates in the initial auto-fit on first load.
13
+ * - `"none"` — never participates in any fit operation.
14
+ */
15
+ export type FitParticipation = "all" | "initial" | "none";
16
+ /**
17
+ * Metadata common to all layer types.
18
+ * Every layer hook returns an object extending this shape.
19
+ */
20
+ export type LayerMeta = Readonly<{
21
+ /** Unique identifier for this layer */
22
+ id: string;
23
+ /** Human-readable name */
24
+ name: string;
25
+ /** Whether this layer fetches its own data */
26
+ loadsData: boolean;
27
+ /** Whether data is currently loading */
28
+ loading: boolean;
29
+ /** Resolves when initial data is available (or immediately if loadsData is false) */
30
+ ready: Promise<void>;
31
+ /**
32
+ * Lazily compute bounding box of all features.
33
+ * Cached internally until source data reference changes.
34
+ */
35
+ getBounds: () => GeoJsonBbox | null;
36
+ /** Summary counts -- always cheap (derived from .length). Semantics depend on layer type. */
37
+ counts: Readonly<Record<string, number>>;
38
+ /** Controls this layer wants to contribute to the map UI */
39
+ controls: ReadonlyArray<ControlConfig>;
40
+ /**
41
+ * Controls whether this layer's bounds are included in fit-to-content operations.
42
+ * Default: `"all"`.
43
+ */
44
+ fitParticipation: FitParticipation;
45
+ }>;
46
+ /**
47
+ * Marker layer handle -- returned by `useMarkers`.
48
+ * Contains all data and configuration needed to render markers and clusters.
49
+ */
50
+ export interface MarkerLayerHandle extends LayerMeta {
51
+ readonly layerType: "markers";
52
+ /** GeoJSON points for all positioned markers */
53
+ readonly features: GeoJsonFeatureCollection;
54
+ /** Marker render configuration */
55
+ readonly markerRender: RenderConfig<unknown>;
56
+ /** Cluster configuration, if clustering is enabled */
57
+ readonly clusterConfig: ClusterConfig<unknown> | null;
58
+ /** Cluster render configuration, if clustering is enabled */
59
+ readonly clusterRender: ClusterRenderConfig<unknown, unknown> | null;
60
+ /** Server-side cluster features (GeoJSON points), if using server-side clustering */
61
+ readonly clusterFeatures: GeoJsonFeatureCollection | null;
62
+ /**
63
+ * Per-cluster `memberItems` cross-referenced from the hook's `data` array via
64
+ * `getMarkerIds`. Keyed by cluster ID. `null` value when any member ID is
65
+ * missing from the data index. Null map when server clustering is not in
66
+ * use. Consumed by `<Layers>` to build `ClusterRenderState<TItem>` for DOM
67
+ * cluster portals.
68
+ */
69
+ readonly clusterMemberItems: ReadonlyMap<string, ReadonlyArray<unknown> | null> | null;
70
+ /**
71
+ * Filled by `<Layers>` when `markerRender.mode === "adaptive"` — per-feature
72
+ * resolved display modes for the map adapter (plan §8).
73
+ */
74
+ readonly adaptiveResolution?: AdaptiveMarkerResolution;
75
+ }
76
+ /**
77
+ * Shape layer handle -- returned by `useShapes`.
78
+ * Contains GeoJSON features (polygons, multipolygons, lines) with styling.
79
+ */
80
+ export interface ShapeLayerHandle extends LayerMeta {
81
+ readonly layerType: "shapes";
82
+ /** GeoJSON features for all shapes */
83
+ readonly features: GeoJsonFeatureCollection;
84
+ /** Base shape style (static value). When per-feature styling is used, this is `{}`. */
85
+ readonly style: ShapeStyle;
86
+ /** Resolves shape style for static and viewport-aware rendering passes. */
87
+ readonly resolveStyle: (feature: GeoJsonFeature, ctx?: ShapeLabelResolutionContext) => ShapeStyle;
88
+ /** Per-feature resolved styles, keyed by `String(feature.id)`. */
89
+ readonly featureStyles?: ReadonlyMap<string, ShapeStyle>;
90
+ /** Which parts of the shape respond to interaction */
91
+ readonly interactive: ShapeInteractiveMode;
92
+ /**
93
+ * Returns all decorations for a feature, including auto-generated ones
94
+ * (e.g. multi-geometry "+" badges). Merging of custom and auto decorations
95
+ * is handled by `useShapes` at construction time.
96
+ */
97
+ readonly getDecorations: (feature: GeoJsonFeature) => ReadonlyArray<ShapeDecoration>;
98
+ }
99
+ /**
100
+ * Route layer handle -- returned by `useRoute`.
101
+ * Contains a polyline with waypoints and styling.
102
+ */
103
+ export interface RouteLayerHandle extends LayerMeta {
104
+ readonly layerType: "route";
105
+ /** GeoJSON LineString feature for the route */
106
+ readonly features: GeoJsonFeatureCollection;
107
+ /** Waypoint positions (original input) */
108
+ readonly waypoints: ReadonlyArray<GeoJsonPosition>;
109
+ /** Route style */
110
+ readonly style: RouteStyle;
111
+ /** Whether route is interactive (clickable/hoverable). Default: false */
112
+ readonly interactive: boolean;
113
+ }
114
+ /**
115
+ * Image overlay handle -- returned by `useImageOverlay`.
116
+ * Contains a georeferenced image to display on the map.
117
+ */
118
+ export interface ImageOverlayHandle extends LayerMeta {
119
+ readonly layerType: "image-overlay";
120
+ /** URL of the image to display */
121
+ readonly url: string;
122
+ /** Geographic bounds the image covers */
123
+ readonly imageBounds: GeoJsonBbox;
124
+ /** Opacity from 0 to 1 */
125
+ readonly opacity: number;
126
+ }
127
+ /**
128
+ * Discriminated union of all layer handle types.
129
+ * Discriminated on `layerType`.
130
+ */
131
+ export type LayerHandle = MarkerLayerHandle | ShapeLayerHandle | RouteLayerHandle | ImageOverlayHandle;
@@ -0,0 +1,20 @@
1
+ import type { MapFocus } from "./mapFocus";
2
+ /**
3
+ * Stateful wrapper around `buildExpandedIds` that feeds the previous result
4
+ * back as `previousIds`, producing hysteresis: markers that were expanded
5
+ * stay expanded across incremental data updates (e.g. pan/zoom refetches).
6
+ *
7
+ * Memory rules:
8
+ * - A marker no longer in `items` is naturally forgotten (not a candidate).
9
+ * - When `focus.id` changes the memory is reset entirely.
10
+ *
11
+ * Callers replace a bare `useMemo(() => buildExpandedIds(...))` with this
12
+ * hook — the signature is identical except `previousIds` is managed
13
+ * internally.
14
+ *
15
+ * State is kept via the render-phase setState pattern (React docs §derived
16
+ * state): calling setState during render causes React to discard the current
17
+ * render and immediately re-render with the updated state, so callers never
18
+ * observe a stale value. This avoids reading/writing a ref during render.
19
+ */
20
+ export declare const useExpandedIds: <TAsset>(items: ReadonlyArray<TAsset>, getId: (item: TAsset) => string, focus: MapFocus<TAsset>, limit: number, getPosition?: (item: TAsset) => readonly [number, number, ...Array<number>]) => ReadonlySet<string>;
@@ -0,0 +1,57 @@
1
+ import type { MapApi } from "../core/types";
2
+ import type { LayerHandle } from "./types";
3
+ /**
4
+ * Options for the `useFitToContent` hook.
5
+ */
6
+ export type FitToContentOptions = Readonly<{
7
+ /** Skip the automatic initial fit entirely. Default: false */
8
+ disabled?: boolean;
9
+ /** Padding in pixels around the fitted bounds. Default: 50 */
10
+ padding?: number;
11
+ /** Maximum zoom level after fitting. Default: 18 */
12
+ maxZoom?: number;
13
+ /** Timeout in ms before fitting with whatever data is available. Default: 10000 */
14
+ timeout?: number;
15
+ }>;
16
+ /**
17
+ * Return type of the `useFitToContent` hook.
18
+ */
19
+ export type FitToContentResult = Readonly<{
20
+ /** True once the initial fit has been performed (or skipped due to empty bounds). */
21
+ hasFitted: boolean;
22
+ /** True while waiting for participating layers to load before the initial fit. */
23
+ isWaiting: boolean;
24
+ /** Manually trigger a fit-to-content. Animates. Only includes `fitParticipation: "all"` layers. */
25
+ fitNow: () => void;
26
+ }>;
27
+ /**
28
+ * `useFitToContent` -- orchestrates a one-time viewport fit once all
29
+ * participating layers have loaded their initial data.
30
+ *
31
+ * Only layers with `fitParticipation !== "none"` are waited on and included
32
+ * in the initial fit. `fitNow()` only includes `fitParticipation: "all"` layers.
33
+ *
34
+ * A configurable timeout (default 10s) ensures the map fits to whatever
35
+ * data is available if some layers are slow.
36
+ *
37
+ * When using this hook alongside an adapter's `initialViewport`, note that the
38
+ * initial viewport serves as a loading-state viewport and will be overridden
39
+ * once layer data arrives and the fit is performed.
40
+ *
41
+ * @example
42
+ * ```tsx
43
+ * const markers = useMarkers({ id: "fleet", ..., loading: isLoading });
44
+ * const shapes = useShapes({ id: "zones", ..., fitParticipation: "none" });
45
+ * const layers = useLayers(api, [markers, shapes]);
46
+ *
47
+ * const { hasFitted, isWaiting, fitNow } = useFitToContent(api, layers.handles);
48
+ *
49
+ * return (
50
+ * <Map>
51
+ * <Layers api={api} layers={layers} />
52
+ * {hasFitted ? <button onClick={fitNow}>Re-fit</button> : null}
53
+ * </Map>
54
+ * );
55
+ * ```
56
+ */
57
+ export declare const useFitToContent: (api: MapApi, handles: ReadonlyArray<LayerHandle>, options?: FitToContentOptions) => FitToContentResult;
@@ -0,0 +1,58 @@
1
+ import type { GeoJsonBbox } from "@trackunit/geo-json-utils";
2
+ import { type Entity, type MapInteractionState } from "@trackunit/react-map-adapter-shared";
3
+ import type { ControlConfig } from "../controls/types";
4
+ import type { MapApi } from "../core/types";
5
+ import type { LayerHandle } from "./types";
6
+ /**
7
+ * Return type of `useLayers`.
8
+ */
9
+ export type UseLayersReturn = Readonly<{
10
+ /** Shared interaction state across all layers */
11
+ interaction: MapInteractionState;
12
+ /** Select an entity (or null to clear selection). Works across all layer types. */
13
+ select: (entity: Entity | null) => void;
14
+ /** Hover an entity (or null to clear hover). Works across all layer types. */
15
+ hover: (entity: Entity | null) => void;
16
+ /** Clear all interaction state (selection and hover) */
17
+ clearAll: () => void;
18
+ /**
19
+ * Lazily compute combined bounds of all layers.
20
+ * Calls each layer's getBounds() and merges the results.
21
+ */
22
+ getBounds: () => GeoJsonBbox | null;
23
+ /** True while any layer is loading */
24
+ loading: boolean;
25
+ /** Resolves when ALL layers have their initial data */
26
+ ready: Promise<void>;
27
+ /** Aggregated controls from all layers */
28
+ controls: ReadonlyArray<ControlConfig>;
29
+ /** Layer handles (passed to Layers component for rendering) */
30
+ handles: ReadonlyArray<LayerHandle>;
31
+ }>;
32
+ /**
33
+ * `useLayers` -- aggregates layer handles and manages shared interaction state.
34
+ *
35
+ * This is the central hook that ties all layers together:
36
+ * - Shared hover/select interaction via a reducer (cross-layer, single entity at a time)
37
+ * - Combined bounds across all layers (lazy, cached)
38
+ * - Loading/ready coordination
39
+ * - Aggregated controls
40
+ *
41
+ * @example
42
+ * ```tsx
43
+ * const fleet = useMarkers({ ... });
44
+ * const shapes = useShapes({ ... });
45
+ * const layers = useLayers(api, [fleet, shapes]);
46
+ *
47
+ * // layers.interaction.selectedEntity
48
+ * // layers.getBounds()
49
+ * // layers.ready
50
+ *
51
+ * return (
52
+ * <Map>
53
+ * <Layers api={api} layers={layers} />
54
+ * </Map>
55
+ * );
56
+ * ```
57
+ */
58
+ export declare const useLayers: (api: MapApi, layers: ReadonlyArray<LayerHandle>) => UseLayersReturn;