@elabs-ai/components-maps 4.0.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.
- package/LICENSE +21 -0
- package/README.md +121 -0
- package/dist/index.css +11 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.ts +442 -0
- package/dist/index.js +1475 -0
- package/dist/index.js.map +1 -0
- package/package.json +66 -0
- package/src/index.ts +37 -0
- package/src/lib/arc-math.test.ts +41 -0
- package/src/lib/arc-math.ts +45 -0
- package/src/lib/merge-hover-paint.test.ts +36 -0
- package/src/lib/merge-hover-paint.ts +21 -0
- package/src/lib/use-token-color.ts +23 -0
- package/src/map-arc/index.ts +9 -0
- package/src/map-arc/map-arc.stories.tsx +58 -0
- package/src/map-arc/map-arc.tsx +294 -0
- package/src/map-canvas/index.ts +8 -0
- package/src/map-canvas/map-canvas-webgl-fallback.test.tsx +30 -0
- package/src/map-canvas/map-canvas.stories.tsx +54 -0
- package/src/map-canvas/map-canvas.test.tsx +93 -0
- package/src/map-canvas/map-canvas.tsx +349 -0
- package/src/map-canvas/map-context.ts +32 -0
- package/src/map-canvas/maps.css +15 -0
- package/src/map-canvas/use-resolved-basemap-theme.ts +77 -0
- package/src/map-cluster-layer/index.ts +1 -0
- package/src/map-cluster-layer/map-cluster-layer.stories.tsx +56 -0
- package/src/map-cluster-layer/map-cluster-layer.tsx +292 -0
- package/src/map-controls/index.ts +1 -0
- package/src/map-controls/map-controls.stories.tsx +43 -0
- package/src/map-controls/map-controls.test.tsx +56 -0
- package/src/map-controls/map-controls.tsx +220 -0
- package/src/map-geojson/index.ts +9 -0
- package/src/map-geojson/map-geojson.stories.tsx +124 -0
- package/src/map-geojson/map-geojson.tsx +274 -0
- package/src/map-marker/index.ts +12 -0
- package/src/map-marker/map-marker.stories.tsx +71 -0
- package/src/map-marker/map-marker.test.tsx +81 -0
- package/src/map-marker/map-marker.tsx +373 -0
- package/src/map-popup/index.ts +1 -0
- package/src/map-popup/map-popup.tsx +113 -0
- package/src/map-route/index.ts +1 -0
- package/src/map-route/map-route.stories.tsx +56 -0
- package/src/map-route/map-route.tsx +143 -0
- package/src/test-utils/maplibre-mock.ts +249 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Manuel Reimitz
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
<!-- brand-ui:gen:readme:start -->
|
|
2
|
+
<!-- Generated by scripts/gen-package-readmes.mjs — do not edit inside these markers. -->
|
|
3
|
+
|
|
4
|
+
# `@elabs-ai/components-maps`
|
|
5
|
+
|
|
6
|
+
> MapLibre GL maps: MapCanvas, markers, popups, controls, routes, arcs, GeoJSON, clusters.
|
|
7
|
+
|
|
8
|
+
Part of **brand-ui**, a source-owned, token-driven React component system.
|
|
9
|
+
These packages are **private** and are not published to any registry — they are
|
|
10
|
+
consumed from this workspace. See `docs/CONSUMING.md`.
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
Inside this monorepo the packages resolve as workspace dependencies:
|
|
15
|
+
|
|
16
|
+
```json
|
|
17
|
+
"@elabs-ai/components-maps": "workspace:*"
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Set up styling (do not skip)
|
|
21
|
+
|
|
22
|
+
Components are Tailwind v4 classes backed by semantic tokens. Two lines in
|
|
23
|
+
your CSS entry, or **everything renders unstyled** — the single most common
|
|
24
|
+
mistake:
|
|
25
|
+
|
|
26
|
+
```css
|
|
27
|
+
@import "@elabs-ai/components-tokens/styles.css";
|
|
28
|
+
@source "../node_modules/@elabs-ai/components-maps/dist";
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The `@source` line is required because Tailwind ignores `node_modules`. Add
|
|
32
|
+
one per brand-ui package you render. Then wrap your app once:
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
import { ThemeProvider } from "@elabs-ai/components-tokens";
|
|
36
|
+
|
|
37
|
+
<ThemeProvider defaultTheme="light">{children}</ThemeProvider>;
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## This package specifically
|
|
41
|
+
|
|
42
|
+
- `maplibre-gl` is a peer — it owns a WebGL context and global CSS.
|
|
43
|
+
- No CSS import needed: `MapCanvas` pulls in MapLibre's stylesheet and the brand overrides itself.
|
|
44
|
+
|
|
45
|
+
## What's in it
|
|
46
|
+
|
|
47
|
+
12 exported components — including `MapArc`, `MapCanvas`, `MapClusterLayer`, `MapControls`, `MapGeoJSON`.
|
|
48
|
+
|
|
49
|
+
Don't guess the API — ask the CLI:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pnpm add -D @elabs-ai/components-cli
|
|
53
|
+
pnpm exec brand-ui search <query> # find a component
|
|
54
|
+
pnpm exec brand-ui docs <Name> # its real props, from source
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Using an AI coding agent?
|
|
58
|
+
|
|
59
|
+
For Claude Code, install the plugin from this repo's checkout:
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
/plugin marketplace add .
|
|
63
|
+
/plugin install brand-ui
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
`brand-ui docs <Name>` returns intent, composition, state→token mappings and
|
|
67
|
+
anti-patterns — tell your agent to run it instead of guessing a prop. The CLI
|
|
68
|
+
also runs as an MCP server (`brand-ui mcp`).
|
|
69
|
+
|
|
70
|
+
## Full guide
|
|
71
|
+
|
|
72
|
+
Tailwind and Next.js wiring, per-package extras, agent enablement and a
|
|
73
|
+
prompt for migrating an existing project: `docs/CONSUMING.md`.
|
|
74
|
+
|
|
75
|
+
## License
|
|
76
|
+
|
|
77
|
+
UNLICENSED — private.
|
|
78
|
+
|
|
79
|
+
<!-- brand-ui:gen:readme:end -->
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Package detail
|
|
84
|
+
|
|
85
|
+
Token-driven MapLibre GL map components for brand-ui: `MapCanvas` (theme-aware
|
|
86
|
+
basemap), `MapMarker` (+ content/label/popup/tooltip parts), `MapPopup`,
|
|
87
|
+
`MapControls`, `MapRoute`, `MapArc`, `MapGeoJSON`, `MapClusterLayer`.
|
|
88
|
+
|
|
89
|
+
```tsx
|
|
90
|
+
import { MapCanvas, MapControls, MapMarker, MapMarkerContent } from "@elabs-ai/components-maps";
|
|
91
|
+
|
|
92
|
+
<div className="h-96">
|
|
93
|
+
<MapCanvas center={[13.4, 52.52]} zoom={11}>
|
|
94
|
+
<MapMarker longitude={13.4} latitude={52.52}>
|
|
95
|
+
<MapMarkerContent />
|
|
96
|
+
</MapMarker>
|
|
97
|
+
<MapControls />
|
|
98
|
+
</MapCanvas>
|
|
99
|
+
</div>;
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
- The basemap flavor (light/dark) follows the active theme's own
|
|
103
|
+
`color-scheme` (`resolveThemeIsDark`), so a theme you authored yourself
|
|
104
|
+
resolves correctly too; pass `theme` to pin it.
|
|
105
|
+
- Default layer paints (routes, arcs, clusters, GeoJSON fills) resolve
|
|
106
|
+
semantic tokens at runtime — WebGL can't read CSS variables — and re-resolve
|
|
107
|
+
on theme change.
|
|
108
|
+
- `<MapCanvas>` imports MapLibre's CSS and the brand popup overrides itself.
|
|
109
|
+
- MapLibre's attribution control is **disabled by default**. The default Carto
|
|
110
|
+
basemap serves ODbL-licensed OpenStreetMap data that requires the credit, so
|
|
111
|
+
either display it via `<AttributionPanel>`
|
|
112
|
+
(`@elabs-ai/components-ui`) somewhere the user can reach, or
|
|
113
|
+
re-enable the in-map control with `attributionControl={{ compact: true }}`
|
|
114
|
+
(it wins through the prop spread). `styles` / `blank` avoid the requirement
|
|
115
|
+
entirely by changing the tiles.
|
|
116
|
+
- Use `blank` for tile-less data-viz canvases (choropleths, arcs, dot maps).
|
|
117
|
+
|
|
118
|
+
## Attribution
|
|
119
|
+
|
|
120
|
+
Adapted from [mapcn](https://github.com/AnmolSaini16/mapcn) (MIT License,
|
|
121
|
+
© 2025 Anmoldeep Singh). `maplibre-gl` is BSD-3-Clause.
|
package/dist/index.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/map-canvas/maps.css"],"sourcesContent":["/*\n * MapLibre popup chrome reset — @elabs-ai/components-maps popups paint their own surface\n * (bg-popover, border, shadow), so MapLibre's white bubble + tip must not\n * render underneath. Imported by <MapCanvas> alongside maplibre-gl's CSS.\n */\n.maplibregl-popup-content {\n background: transparent;\n box-shadow: none;\n padding: 0;\n border-radius: 0;\n}\n\n.maplibregl-popup-tip {\n display: none;\n}\n"],"mappings":";AAKA,CAAC;AACC,cAAY;AACZ,cAAY;AACZ,WAAS;AACT,iBAAe;AACjB;AAEA,CAAC;AACC,WAAS;AACX;","names":[]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,442 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
import MapLibreGL, { MarkerOptions, PopupOptions } from 'maplibre-gl';
|
|
4
|
+
export { LngLatBoundsLike, LngLatLike, MapLayerMouseEvent, MapMouseEvent, MapOptions, ProjectionSpecification, StyleSpecification } from 'maplibre-gl';
|
|
5
|
+
|
|
6
|
+
/** Light-or-dark flavor of the active basemap (derived from the brand theme). */
|
|
7
|
+
type BasemapTheme = "light" | "dark";
|
|
8
|
+
interface MapContextValue {
|
|
9
|
+
/** The live MapLibre map instance (`null` until the map has mounted). */
|
|
10
|
+
map: MapLibreGL.Map | null;
|
|
11
|
+
/** True once the map AND its style are fully loaded — gate layer operations on this. */
|
|
12
|
+
isLoaded: boolean;
|
|
13
|
+
/** Which basemap flavor is active. */
|
|
14
|
+
resolvedTheme: BasemapTheme;
|
|
15
|
+
/**
|
|
16
|
+
* Changes whenever the active brand theme changes. Layer components use it
|
|
17
|
+
* as a dependency key to re-resolve semantic token colors for WebGL paint.
|
|
18
|
+
*/
|
|
19
|
+
themeKey: string;
|
|
20
|
+
}
|
|
21
|
+
/** Access the map instance + load state from any descendant of `<MapCanvas>`. */
|
|
22
|
+
declare function useMap(): MapContextValue;
|
|
23
|
+
|
|
24
|
+
/** Map viewport state. */
|
|
25
|
+
interface MapViewport {
|
|
26
|
+
/** Center coordinates [longitude, latitude]. */
|
|
27
|
+
center: [number, number];
|
|
28
|
+
/** Zoom level. */
|
|
29
|
+
zoom: number;
|
|
30
|
+
/** Bearing (rotation) in degrees. */
|
|
31
|
+
bearing: number;
|
|
32
|
+
/** Pitch (tilt) in degrees. */
|
|
33
|
+
pitch: number;
|
|
34
|
+
}
|
|
35
|
+
type MapStyleOption = string | MapLibreGL.StyleSpecification;
|
|
36
|
+
/** The imperative handle exposed by `<MapCanvas ref>`: the MapLibre map itself. */
|
|
37
|
+
type MapCanvasRef = MapLibreGL.Map;
|
|
38
|
+
type MapCanvasProps = {
|
|
39
|
+
children?: ReactNode;
|
|
40
|
+
/** Additional CSS classes for the map container. */
|
|
41
|
+
className?: string;
|
|
42
|
+
/**
|
|
43
|
+
* Basemap flavor. If not provided, it is derived from the active brand theme
|
|
44
|
+
* (`data-theme` + that theme's own `color-scheme`), then a `dark`/`light` root class,
|
|
45
|
+
* then the OS preference.
|
|
46
|
+
*/
|
|
47
|
+
theme?: BasemapTheme;
|
|
48
|
+
/** Custom map styles for light and dark themes. Overrides the default Carto styles. */
|
|
49
|
+
styles?: {
|
|
50
|
+
light?: MapStyleOption;
|
|
51
|
+
dark?: MapStyleOption;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Use a transparent, tile-less basemap instead of the default Carto street
|
|
55
|
+
* basemap — a blank canvas. Used alone it renders nothing; add your own
|
|
56
|
+
* layers on top (`<MapGeoJSON>`, `<MapArc>`, markers, …). Ideal for data
|
|
57
|
+
* visualizations. Ignored when an explicit `styles` prop is provided.
|
|
58
|
+
*/
|
|
59
|
+
blank?: boolean;
|
|
60
|
+
/** Map projection type. Use `{ type: "globe" }` for a 3D globe view. */
|
|
61
|
+
projection?: MapLibreGL.ProjectionSpecification;
|
|
62
|
+
/**
|
|
63
|
+
* Controlled viewport. When provided together with `onViewportChange`, the
|
|
64
|
+
* map becomes controlled and the viewport is driven by this prop.
|
|
65
|
+
*/
|
|
66
|
+
viewport?: Partial<MapViewport>;
|
|
67
|
+
/**
|
|
68
|
+
* Callback fired continuously as the viewport changes (pan, zoom, rotate,
|
|
69
|
+
* pitch). Use standalone to observe changes, or with `viewport` for
|
|
70
|
+
* controlled mode.
|
|
71
|
+
*/
|
|
72
|
+
onViewportChange?: (viewport: MapViewport) => void;
|
|
73
|
+
/** Show a loading overlay on the map (e.g. while the app fetches map data). */
|
|
74
|
+
loading?: boolean;
|
|
75
|
+
} & Omit<MapLibreGL.MapOptions, "container" | "style">;
|
|
76
|
+
/**
|
|
77
|
+
* The root map surface — a token/theme-aware MapLibre GL canvas. Compose the
|
|
78
|
+
* other `@elabs-ai/components-maps` components (markers, popups, controls, layers) as
|
|
79
|
+
* children; they reach the map through context (`useMap`).
|
|
80
|
+
*
|
|
81
|
+
* The ref exposes the raw MapLibre `Map` instance for imperative work
|
|
82
|
+
* (`flyTo`, `fitBounds`, …).
|
|
83
|
+
*/
|
|
84
|
+
declare const MapCanvas: react.ForwardRefExoticComponent<{
|
|
85
|
+
children?: ReactNode;
|
|
86
|
+
/** Additional CSS classes for the map container. */
|
|
87
|
+
className?: string;
|
|
88
|
+
/**
|
|
89
|
+
* Basemap flavor. If not provided, it is derived from the active brand theme
|
|
90
|
+
* (`data-theme` + that theme's own `color-scheme`), then a `dark`/`light` root class,
|
|
91
|
+
* then the OS preference.
|
|
92
|
+
*/
|
|
93
|
+
theme?: BasemapTheme;
|
|
94
|
+
/** Custom map styles for light and dark themes. Overrides the default Carto styles. */
|
|
95
|
+
styles?: {
|
|
96
|
+
light?: MapStyleOption;
|
|
97
|
+
dark?: MapStyleOption;
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* Use a transparent, tile-less basemap instead of the default Carto street
|
|
101
|
+
* basemap — a blank canvas. Used alone it renders nothing; add your own
|
|
102
|
+
* layers on top (`<MapGeoJSON>`, `<MapArc>`, markers, …). Ideal for data
|
|
103
|
+
* visualizations. Ignored when an explicit `styles` prop is provided.
|
|
104
|
+
*/
|
|
105
|
+
blank?: boolean;
|
|
106
|
+
/** Map projection type. Use `{ type: "globe" }` for a 3D globe view. */
|
|
107
|
+
projection?: MapLibreGL.ProjectionSpecification;
|
|
108
|
+
/**
|
|
109
|
+
* Controlled viewport. When provided together with `onViewportChange`, the
|
|
110
|
+
* map becomes controlled and the viewport is driven by this prop.
|
|
111
|
+
*/
|
|
112
|
+
viewport?: Partial<MapViewport>;
|
|
113
|
+
/**
|
|
114
|
+
* Callback fired continuously as the viewport changes (pan, zoom, rotate,
|
|
115
|
+
* pitch). Use standalone to observe changes, or with `viewport` for
|
|
116
|
+
* controlled mode.
|
|
117
|
+
*/
|
|
118
|
+
onViewportChange?: (viewport: MapViewport) => void;
|
|
119
|
+
/** Show a loading overlay on the map (e.g. while the app fetches map data). */
|
|
120
|
+
loading?: boolean;
|
|
121
|
+
} & Omit<MapLibreGL.MapOptions, "container" | "style"> & react.RefAttributes<MapLibreGL.Map>>;
|
|
122
|
+
|
|
123
|
+
type MapMarkerProps = {
|
|
124
|
+
/** Longitude coordinate for the marker position. */
|
|
125
|
+
longitude: number;
|
|
126
|
+
/** Latitude coordinate for the marker position. */
|
|
127
|
+
latitude: number;
|
|
128
|
+
/** Marker sub-components (MapMarkerContent, MapMarkerPopup, MapMarkerTooltip, MapMarkerLabel). */
|
|
129
|
+
children: ReactNode;
|
|
130
|
+
/** Callback when the marker is clicked. */
|
|
131
|
+
onClick?: (e: MouseEvent) => void;
|
|
132
|
+
/** Callback when the mouse enters the marker. */
|
|
133
|
+
onMouseEnter?: (e: MouseEvent) => void;
|
|
134
|
+
/** Callback when the mouse leaves the marker. */
|
|
135
|
+
onMouseLeave?: (e: MouseEvent) => void;
|
|
136
|
+
/** Callback when a drag starts (requires `draggable`). */
|
|
137
|
+
onDragStart?: (lngLat: {
|
|
138
|
+
lng: number;
|
|
139
|
+
lat: number;
|
|
140
|
+
}) => void;
|
|
141
|
+
/** Callback during a drag (requires `draggable`). */
|
|
142
|
+
onDrag?: (lngLat: {
|
|
143
|
+
lng: number;
|
|
144
|
+
lat: number;
|
|
145
|
+
}) => void;
|
|
146
|
+
/** Callback when a drag ends (requires `draggable`). */
|
|
147
|
+
onDragEnd?: (lngLat: {
|
|
148
|
+
lng: number;
|
|
149
|
+
lat: number;
|
|
150
|
+
}) => void;
|
|
151
|
+
} & Omit<MarkerOptions, "element">;
|
|
152
|
+
/**
|
|
153
|
+
* A marker anchored at a lng/lat. Compose the pieces you need:
|
|
154
|
+
* `MapMarkerContent` (the visual), `MapMarkerLabel`, `MapMarkerPopup` (opens
|
|
155
|
+
* on click) and `MapMarkerTooltip` (shows on hover).
|
|
156
|
+
*/
|
|
157
|
+
declare function MapMarker({ longitude, latitude, children, onClick, onMouseEnter, onMouseLeave, onDragStart, onDrag, onDragEnd, draggable, ...markerOptions }: MapMarkerProps): react.JSX.Element;
|
|
158
|
+
interface MapMarkerContentProps {
|
|
159
|
+
/** Custom marker content. Defaults to a primary-colored dot. */
|
|
160
|
+
children?: ReactNode;
|
|
161
|
+
/** Additional CSS classes for the marker container. */
|
|
162
|
+
className?: string;
|
|
163
|
+
}
|
|
164
|
+
/** The marker's visual, portaled into the MapLibre marker element. */
|
|
165
|
+
declare function MapMarkerContent({ children, className }: MapMarkerContentProps): react.ReactPortal;
|
|
166
|
+
type MapMarkerPopupProps = {
|
|
167
|
+
/** Popup content. */
|
|
168
|
+
children: ReactNode;
|
|
169
|
+
/** Additional CSS classes for the popup container. */
|
|
170
|
+
className?: string;
|
|
171
|
+
/** Show a close button in the popup (default: false). */
|
|
172
|
+
closeButton?: boolean;
|
|
173
|
+
} & Omit<PopupOptions, "className" | "closeButton">;
|
|
174
|
+
/** A popup attached to the marker — MapLibre toggles it on marker click. */
|
|
175
|
+
declare function MapMarkerPopup({ children, className, closeButton, ...popupOptions }: MapMarkerPopupProps): react.ReactPortal;
|
|
176
|
+
type MapMarkerTooltipProps = {
|
|
177
|
+
/** Tooltip content. */
|
|
178
|
+
children: ReactNode;
|
|
179
|
+
/** Additional CSS classes for the tooltip container. */
|
|
180
|
+
className?: string;
|
|
181
|
+
} & Omit<PopupOptions, "className" | "closeButton" | "closeOnClick">;
|
|
182
|
+
/** A hover tooltip attached to the marker. */
|
|
183
|
+
declare function MapMarkerTooltip({ children, className, ...popupOptions }: MapMarkerTooltipProps): react.ReactPortal;
|
|
184
|
+
interface MapMarkerLabelProps {
|
|
185
|
+
/** Label text content. */
|
|
186
|
+
children: ReactNode;
|
|
187
|
+
/** Additional CSS classes for the label. */
|
|
188
|
+
className?: string;
|
|
189
|
+
/** Position of the label relative to the marker (default: "top"). */
|
|
190
|
+
position?: "top" | "bottom";
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* A small always-visible text label above or below the marker. Portaled into
|
|
194
|
+
* the marker element so it anchors to the marker whether composed as a sibling
|
|
195
|
+
* of `MapMarkerContent` or nested inside it (the three-theme sweep caught the
|
|
196
|
+
* sibling composition rendering the label against the map container instead).
|
|
197
|
+
*/
|
|
198
|
+
declare function MapMarkerLabel({ children, className, position }: MapMarkerLabelProps): react.ReactPortal;
|
|
199
|
+
|
|
200
|
+
type MapPopupProps = {
|
|
201
|
+
/** Longitude coordinate for the popup position. */
|
|
202
|
+
longitude: number;
|
|
203
|
+
/** Latitude coordinate for the popup position. */
|
|
204
|
+
latitude: number;
|
|
205
|
+
/** Callback when the popup is closed. */
|
|
206
|
+
onClose?: () => void;
|
|
207
|
+
/** Popup content. */
|
|
208
|
+
children: ReactNode;
|
|
209
|
+
/** Additional CSS classes for the popup container. */
|
|
210
|
+
className?: string;
|
|
211
|
+
/** Show a close button in the popup (default: false). */
|
|
212
|
+
closeButton?: boolean;
|
|
213
|
+
} & Omit<PopupOptions, "className" | "closeButton">;
|
|
214
|
+
/**
|
|
215
|
+
* A standalone popup anchored at a lng/lat (not attached to a marker) —
|
|
216
|
+
* typically rendered conditionally from app state (e.g. after a layer click).
|
|
217
|
+
*/
|
|
218
|
+
declare function MapPopup({ longitude, latitude, onClose, children, className, closeButton, ...popupOptions }: MapPopupProps): react.ReactPortal;
|
|
219
|
+
|
|
220
|
+
interface MapControlsProps {
|
|
221
|
+
/** Position of the controls on the map (default: "bottom-right"). */
|
|
222
|
+
position?: "top-left" | "top-right" | "bottom-left" | "bottom-right";
|
|
223
|
+
/** Show zoom in/out buttons (default: true). */
|
|
224
|
+
showZoom?: boolean;
|
|
225
|
+
/** Show a compass button to reset bearing/pitch (default: false). */
|
|
226
|
+
showCompass?: boolean;
|
|
227
|
+
/** Show a locate button to fly to the user's location (default: false). */
|
|
228
|
+
showLocate?: boolean;
|
|
229
|
+
/** Show a fullscreen toggle button (default: false). */
|
|
230
|
+
showFullscreen?: boolean;
|
|
231
|
+
/** Additional CSS classes for the controls container. */
|
|
232
|
+
className?: string;
|
|
233
|
+
/** Callback with user coordinates when located. */
|
|
234
|
+
onLocate?: (coords: {
|
|
235
|
+
longitude: number;
|
|
236
|
+
latitude: number;
|
|
237
|
+
}) => void;
|
|
238
|
+
/** Callback when geolocation fails or is denied. */
|
|
239
|
+
onLocateError?: (error: GeolocationPositionError) => void;
|
|
240
|
+
}
|
|
241
|
+
/** Branded zoom / compass / locate / fullscreen controls. Render inside `<MapCanvas>`. */
|
|
242
|
+
declare function MapControls({ position, showZoom, showCompass, showLocate, showFullscreen, className, onLocate, onLocateError, }: MapControlsProps): react.JSX.Element;
|
|
243
|
+
|
|
244
|
+
interface MapRouteProps {
|
|
245
|
+
/** Optional unique identifier for the route layer. */
|
|
246
|
+
id?: string;
|
|
247
|
+
/** Array of [longitude, latitude] coordinate pairs defining the route. */
|
|
248
|
+
coordinates: [number, number][];
|
|
249
|
+
/** Line color as a CSS color value. Defaults to the theme's `--primary` token. */
|
|
250
|
+
color?: string;
|
|
251
|
+
/** Line width in pixels (default: 3). */
|
|
252
|
+
width?: number;
|
|
253
|
+
/** Line opacity from 0 to 1 (default: 0.8). */
|
|
254
|
+
opacity?: number;
|
|
255
|
+
/** Dash pattern [dash length, gap length] for dashed lines. */
|
|
256
|
+
dashArray?: [number, number];
|
|
257
|
+
/** Callback when the route line is clicked. */
|
|
258
|
+
onClick?: () => void;
|
|
259
|
+
/** Callback when the mouse enters the route line. */
|
|
260
|
+
onMouseEnter?: () => void;
|
|
261
|
+
/** Callback when the mouse leaves the route line. */
|
|
262
|
+
onMouseLeave?: () => void;
|
|
263
|
+
/** Whether the route is interactive — shows a pointer cursor on hover (default: true). */
|
|
264
|
+
interactive?: boolean;
|
|
265
|
+
}
|
|
266
|
+
/** A GeoJSON line layer for routes/paths. Renders nothing itself — it draws on the map. */
|
|
267
|
+
declare function MapRoute({ id: propId, coordinates, color, width, opacity, dashArray, onClick, onMouseEnter, onMouseLeave, interactive, }: MapRouteProps): null;
|
|
268
|
+
|
|
269
|
+
/** A single arc to render inside `<MapArc data={...}>`. */
|
|
270
|
+
type MapArcDatum = {
|
|
271
|
+
/** Unique identifier for this arc. Required for hover state tracking and event payloads. */
|
|
272
|
+
id: string | number;
|
|
273
|
+
/** Start coordinate as [longitude, latitude]. */
|
|
274
|
+
from: [number, number];
|
|
275
|
+
/** End coordinate as [longitude, latitude]. */
|
|
276
|
+
to: [number, number];
|
|
277
|
+
};
|
|
278
|
+
/** Event payload passed to MapArc interaction callbacks. */
|
|
279
|
+
type MapArcEvent<T extends MapArcDatum = MapArcDatum> = {
|
|
280
|
+
/** The arc datum that was hovered or clicked. */
|
|
281
|
+
arc: T;
|
|
282
|
+
/** Longitude of the cursor at the time of the event. */
|
|
283
|
+
longitude: number;
|
|
284
|
+
/** Latitude of the cursor at the time of the event. */
|
|
285
|
+
latitude: number;
|
|
286
|
+
/** The underlying MapLibre mouse event for advanced use cases. */
|
|
287
|
+
originalEvent: MapLibreGL.MapMouseEvent;
|
|
288
|
+
};
|
|
289
|
+
type MapArcLinePaint = NonNullable<MapLibreGL.LineLayerSpecification["paint"]>;
|
|
290
|
+
type MapArcLineLayout = NonNullable<MapLibreGL.LineLayerSpecification["layout"]>;
|
|
291
|
+
type MapArcProps<T extends MapArcDatum = MapArcDatum> = {
|
|
292
|
+
/** Array of arcs to render. Each arc must have a unique `id`. */
|
|
293
|
+
data: T[];
|
|
294
|
+
/** Optional unique identifier prefix for the arc source/layers. Auto-generated if not provided. */
|
|
295
|
+
id?: string;
|
|
296
|
+
/**
|
|
297
|
+
* How far each arc bows away from a straight line. `0` renders straight
|
|
298
|
+
* lines; higher values bend further; negative values bend to the opposite
|
|
299
|
+
* side. Arcs cross the antimeridian via the shorter direction. (default: 0.2)
|
|
300
|
+
*/
|
|
301
|
+
curvature?: number;
|
|
302
|
+
/** Number of samples used to render each curve. Higher = smoother. (default: 64) */
|
|
303
|
+
samples?: number;
|
|
304
|
+
/**
|
|
305
|
+
* MapLibre paint properties for the arc layer. Merged on top of theme-aware
|
|
306
|
+
* defaults (`line-color` = the `--primary` token, `line-width: 2`,
|
|
307
|
+
* `line-opacity: 0.85`). Any value can be a MapLibre expression for
|
|
308
|
+
* per-feature styling; every field on each arc datum (besides `from`/`to`)
|
|
309
|
+
* is exposed via `["get", ...]`.
|
|
310
|
+
*/
|
|
311
|
+
paint?: MapArcLinePaint;
|
|
312
|
+
/** MapLibre layout properties for the arc layer. Defaults to rounded joins/caps. */
|
|
313
|
+
layout?: MapArcLineLayout;
|
|
314
|
+
/**
|
|
315
|
+
* Paint properties applied to the arc currently under the cursor. Each key
|
|
316
|
+
* is merged into `paint` as a `case` expression keyed on per-feature hover
|
|
317
|
+
* state, so only the hovered arc changes appearance.
|
|
318
|
+
*/
|
|
319
|
+
hoverPaint?: MapArcLinePaint;
|
|
320
|
+
/** Callback when an arc is clicked. */
|
|
321
|
+
onClick?: (e: MapArcEvent<T>) => void;
|
|
322
|
+
/**
|
|
323
|
+
* Callback fired when the hovered arc changes. Receives the cursor's
|
|
324
|
+
* lng/lat at the moment of entry, and `null` when the cursor leaves the
|
|
325
|
+
* last hovered arc.
|
|
326
|
+
*/
|
|
327
|
+
onHover?: (e: MapArcEvent<T> | null) => void;
|
|
328
|
+
/** Whether arcs respond to mouse events (default: true). */
|
|
329
|
+
interactive?: boolean;
|
|
330
|
+
/** Optional MapLibre layer id to insert the arc layers before (z-order control). */
|
|
331
|
+
beforeId?: string;
|
|
332
|
+
};
|
|
333
|
+
/**
|
|
334
|
+
* Curved great-circle-style arcs between coordinate pairs (flight paths,
|
|
335
|
+
* network links). Pairs well with `<MapCanvas blank projection={{ type: "globe" }}>`.
|
|
336
|
+
*/
|
|
337
|
+
declare function MapArc<T extends MapArcDatum = MapArcDatum>({ data, id: propId, curvature, samples, paint, layout, hoverPaint, onClick, onHover, interactive, beforeId, }: MapArcProps<T>): null;
|
|
338
|
+
|
|
339
|
+
/** Pure geometry for `<MapArc>` — kept engine-free so it can be unit-tested. */
|
|
340
|
+
/**
|
|
341
|
+
* Sample a quadratic Bézier between `from` and `to` in lng/lat space.
|
|
342
|
+
* `curvature` is how far the arc bows away from a straight line (0 = straight;
|
|
343
|
+
* negative bends to the opposite side). The destination longitude is unwrapped
|
|
344
|
+
* relative to the origin so arcs cross the antimeridian via the shorter
|
|
345
|
+
* great-circle direction — resulting longitudes may fall outside [-180, 180],
|
|
346
|
+
* which MapLibre renders correctly on the globe projection.
|
|
347
|
+
*/
|
|
348
|
+
declare function buildArcCoordinates(from: [number, number], to: [number, number], curvature: number, samples: number): [number, number][];
|
|
349
|
+
|
|
350
|
+
type MapGeoJSONData<P extends GeoJSON.GeoJsonProperties = GeoJSON.GeoJsonProperties> = GeoJSON.FeatureCollection<GeoJSON.Geometry, P> | GeoJSON.Feature<GeoJSON.Geometry, P> | GeoJSON.Geometry | string;
|
|
351
|
+
type MapFillPaint = NonNullable<MapLibreGL.FillLayerSpecification["paint"]>;
|
|
352
|
+
type MapLinePaint = NonNullable<MapLibreGL.LineLayerSpecification["paint"]>;
|
|
353
|
+
/** A rendered feature with strongly-typed `properties`. */
|
|
354
|
+
type MapGeoJSONFeature<P extends GeoJSON.GeoJsonProperties = GeoJSON.GeoJsonProperties> = Omit<MapLibreGL.MapGeoJSONFeature, "properties"> & {
|
|
355
|
+
properties: P;
|
|
356
|
+
};
|
|
357
|
+
/** Event payload passed to MapGeoJSON interaction callbacks. */
|
|
358
|
+
type MapGeoJSONEvent<P extends GeoJSON.GeoJsonProperties = GeoJSON.GeoJsonProperties> = {
|
|
359
|
+
/** The feature under the cursor, with its typed GeoJSON properties. */
|
|
360
|
+
feature: MapGeoJSONFeature<P>;
|
|
361
|
+
/** Longitude of the cursor at the time of the event. */
|
|
362
|
+
longitude: number;
|
|
363
|
+
/** Latitude of the cursor at the time of the event. */
|
|
364
|
+
latitude: number;
|
|
365
|
+
/** The underlying MapLibre mouse event for advanced use cases. */
|
|
366
|
+
originalEvent: MapLibreGL.MapLayerMouseEvent;
|
|
367
|
+
};
|
|
368
|
+
type MapGeoJSONProps<P extends GeoJSON.GeoJsonProperties = GeoJSON.GeoJsonProperties> = {
|
|
369
|
+
/** GeoJSON data (FeatureCollection, Feature, Geometry) or a URL to fetch it from. */
|
|
370
|
+
data: MapGeoJSONData<P>;
|
|
371
|
+
/** Optional unique identifier prefix for the source/layers. Auto-generated if not provided. */
|
|
372
|
+
id?: string;
|
|
373
|
+
/**
|
|
374
|
+
* Feature property to promote to the feature `id`. Required for hover
|
|
375
|
+
* feature-state (`fillHoverPaint`) and stable `onHover`/`onClick` payloads.
|
|
376
|
+
*/
|
|
377
|
+
promoteId?: string;
|
|
378
|
+
/**
|
|
379
|
+
* Paint for the polygon fill layer. Merged on top of a theme-aware neutral
|
|
380
|
+
* default (the `--border` token — a mid neutral that reads on the page
|
|
381
|
+
* surface in every theme). Pass `false` to omit the fill layer entirely
|
|
382
|
+
* (e.g. outlines only).
|
|
383
|
+
*/
|
|
384
|
+
fillPaint?: MapFillPaint | false;
|
|
385
|
+
/**
|
|
386
|
+
* Paint for the outline layer. Merged on top of a hairline default
|
|
387
|
+
* (`line-color` = the `--background` token, `line-width` = 0.5) for thin
|
|
388
|
+
* separators. Override `line-color` if your container differs, or pass
|
|
389
|
+
* `false` to omit the layer.
|
|
390
|
+
*/
|
|
391
|
+
linePaint?: MapLinePaint | false;
|
|
392
|
+
/**
|
|
393
|
+
* Paint merged onto the fill layer for the feature under the cursor, applied
|
|
394
|
+
* as a `case` expression keyed on hover feature-state. Requires `promoteId`.
|
|
395
|
+
*/
|
|
396
|
+
fillHoverPaint?: MapFillPaint;
|
|
397
|
+
/** Callback when a feature is clicked. */
|
|
398
|
+
onClick?: (e: MapGeoJSONEvent<P>) => void;
|
|
399
|
+
/** Callback fired when the hovered feature changes; `null` when the cursor leaves. */
|
|
400
|
+
onHover?: (e: MapGeoJSONEvent<P> | null) => void;
|
|
401
|
+
/** Whether features respond to mouse events (default: false). */
|
|
402
|
+
interactive?: boolean;
|
|
403
|
+
/** Optional MapLibre layer id to insert the layers before (z-order control). */
|
|
404
|
+
beforeId?: string;
|
|
405
|
+
};
|
|
406
|
+
/**
|
|
407
|
+
* Renders arbitrary GeoJSON as fill + outline layers on the map. Composes like
|
|
408
|
+
* `MapRoute` / `MapArc` — drop it inside `<MapCanvas>` (typically with `blank`)
|
|
409
|
+
* for choropleths and region/data maps. For full control over expressions and
|
|
410
|
+
* multiple layers, manage layers directly via `useMap()` instead.
|
|
411
|
+
*/
|
|
412
|
+
declare function MapGeoJSON<P extends GeoJSON.GeoJsonProperties = GeoJSON.GeoJsonProperties>({ data, id: propId, promoteId, fillPaint, linePaint, fillHoverPaint, onClick, onHover, interactive, beforeId, }: MapGeoJSONProps<P>): null;
|
|
413
|
+
|
|
414
|
+
type MapClusterLayerProps<P extends GeoJSON.GeoJsonProperties = GeoJSON.GeoJsonProperties> = {
|
|
415
|
+
/** GeoJSON FeatureCollection data or a URL to fetch GeoJSON from. */
|
|
416
|
+
data: string | GeoJSON.FeatureCollection<GeoJSON.Point, P>;
|
|
417
|
+
/** Maximum zoom level to cluster points on (default: 14). */
|
|
418
|
+
clusterMaxZoom?: number;
|
|
419
|
+
/** Radius of each cluster when clustering points, in pixels (default: 50). */
|
|
420
|
+
clusterRadius?: number;
|
|
421
|
+
/**
|
|
422
|
+
* Colors for cluster circles: [small, medium, large] based on point count.
|
|
423
|
+
* Defaults to the theme's `--success`/`--warning`/`--destructive` tokens.
|
|
424
|
+
*/
|
|
425
|
+
clusterColors?: [string, string, string];
|
|
426
|
+
/** Point-count thresholds for the color/size steps: [medium, large] (default: [100, 750]). */
|
|
427
|
+
clusterThresholds?: [number, number];
|
|
428
|
+
/** Color for unclustered individual points. Defaults to the theme's `--primary` token. */
|
|
429
|
+
pointColor?: string;
|
|
430
|
+
/** Callback when an unclustered point is clicked. */
|
|
431
|
+
onPointClick?: (feature: GeoJSON.Feature<GeoJSON.Point, P>, coordinates: [number, number]) => void;
|
|
432
|
+
/** Callback when a cluster is clicked. If not provided, zooms into the cluster. */
|
|
433
|
+
onClusterClick?: (clusterId: number, coordinates: [number, number], pointCount: number) => void;
|
|
434
|
+
};
|
|
435
|
+
/**
|
|
436
|
+
* Clustered point rendering for large point datasets. Cluster circles step
|
|
437
|
+
* through the status tokens (success → warning → destructive) as the point
|
|
438
|
+
* count grows; strokes and count labels use the page surface for contrast.
|
|
439
|
+
*/
|
|
440
|
+
declare function MapClusterLayer<P extends GeoJSON.GeoJsonProperties = GeoJSON.GeoJsonProperties>({ data, clusterMaxZoom, clusterRadius, clusterColors, clusterThresholds, pointColor, onPointClick, onClusterClick, }: MapClusterLayerProps<P>): null;
|
|
441
|
+
|
|
442
|
+
export { type BasemapTheme, MapArc, type MapArcDatum, type MapArcEvent, type MapArcLineLayout, type MapArcLinePaint, type MapArcProps, MapCanvas, type MapCanvasProps, type MapCanvasRef, MapClusterLayer, type MapClusterLayerProps, type MapContextValue, MapControls, type MapControlsProps, type MapFillPaint, MapGeoJSON, type MapGeoJSONData, type MapGeoJSONEvent, type MapGeoJSONFeature, type MapGeoJSONProps, type MapLinePaint, MapMarker, MapMarkerContent, type MapMarkerContentProps, MapMarkerLabel, type MapMarkerLabelProps, MapMarkerPopup, type MapMarkerPopupProps, type MapMarkerProps, MapMarkerTooltip, type MapMarkerTooltipProps, MapPopup, type MapPopupProps, MapRoute, type MapRouteProps, type MapStyleOption, type MapViewport, buildArcCoordinates, useMap };
|