shadcn-map 0.1.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 (37) hide show
  1. package/dist/components/ClusterLayer.svelte +511 -0
  2. package/dist/components/ClusterLayer.svelte.d.ts +29 -0
  3. package/dist/components/DetailsPanel.svelte +180 -0
  4. package/dist/components/DetailsPanel.svelte.d.ts +18 -0
  5. package/dist/components/Map.svelte +321 -0
  6. package/dist/components/Map.svelte.d.ts +63 -0
  7. package/dist/components/Marker.svelte +594 -0
  8. package/dist/components/Marker.svelte.d.ts +34 -0
  9. package/dist/components/Popup.svelte +228 -0
  10. package/dist/components/Popup.svelte.d.ts +18 -0
  11. package/dist/components/controls/GeolocateControl.svelte +141 -0
  12. package/dist/components/controls/GeolocateControl.svelte.d.ts +22 -0
  13. package/dist/components/controls/NavigationControl.svelte +50 -0
  14. package/dist/components/controls/NavigationControl.svelte.d.ts +12 -0
  15. package/dist/components/controls/ScaleControl.svelte +49 -0
  16. package/dist/components/controls/ScaleControl.svelte.d.ts +12 -0
  17. package/dist/components/controls/index.d.ts +6 -0
  18. package/dist/components/controls/index.js +3 -0
  19. package/dist/components/index.d.ts +13 -0
  20. package/dist/components/index.js +7 -0
  21. package/dist/context.svelte.d.ts +37 -0
  22. package/dist/context.svelte.js +96 -0
  23. package/dist/index.d.ts +6 -0
  24. package/dist/index.js +4 -0
  25. package/dist/styles/colors.d.ts +54 -0
  26. package/dist/styles/colors.js +53 -0
  27. package/dist/styles/dark.d.ts +7 -0
  28. package/dist/styles/dark.js +168 -0
  29. package/dist/styles/index.d.ts +3 -0
  30. package/dist/styles/index.js +3 -0
  31. package/dist/styles/light.d.ts +7 -0
  32. package/dist/styles/light.js +168 -0
  33. package/dist/theme.d.ts +2 -0
  34. package/dist/theme.js +34 -0
  35. package/dist/types.d.ts +56 -0
  36. package/dist/types.js +1 -0
  37. package/package.json +72 -0
@@ -0,0 +1,228 @@
1
+ <script lang='ts' module>
2
+ import type { Snippet } from 'svelte'
3
+
4
+ export interface PopupProps {
5
+ /** Popup position [lng, lat] */
6
+ lngLat: [number, number]
7
+ /** Whether popup is visible */
8
+ open?: boolean
9
+ /** Close callback */
10
+ onclose?: () => void
11
+ /** Additional CSS classes */
12
+ class?: string
13
+ /** Offset from anchor point (number = uniform, array = [x, y], or 'auto' for auto-detected) */
14
+ offset?: number | [number, number] | 'auto'
15
+ /** Children */
16
+ children?: Snippet
17
+ }
18
+ </script>
19
+
20
+ <script lang='ts'>
21
+ import maplibregl from 'maplibre-gl'
22
+ import { onMount } from 'svelte'
23
+ import { getMapContext } from '../context.svelte'
24
+
25
+ const {
26
+ lngLat,
27
+ open = true,
28
+ onclose,
29
+ class: className = '',
30
+ offset = 'auto',
31
+ children,
32
+ }: PopupProps = $props()
33
+
34
+ const ctx = getMapContext()
35
+
36
+ let popup: maplibregl.Popup | null = null
37
+ let contentElement: HTMLDivElement
38
+ let programmaticClose = false
39
+ let lastActiveMarkerId: string | null = null
40
+
41
+ const sizeOffsets: Record<'sm' | 'md' | 'lg', [number, number]> = {
42
+ sm: [0, -12],
43
+ md: [0, -16],
44
+ lg: [0, -20],
45
+ }
46
+
47
+ const markerAtLocation = $derived.by(() => {
48
+ for (const marker of ctx.markers.values()) {
49
+ const lngDiff = Math.abs(marker.lngLat[0] - lngLat[0])
50
+ const latDiff = Math.abs(marker.lngLat[1] - lngLat[1])
51
+ if (lngDiff < 0.000001 && latDiff < 0.000001) {
52
+ return marker
53
+ }
54
+ }
55
+ return null
56
+ })
57
+
58
+ const detectedMarkerSize = $derived(markerAtLocation?.size ?? 'md')
59
+
60
+ const computedOffset = $derived.by((): number | [number, number] => {
61
+ if (offset !== 'auto') {
62
+ return offset
63
+ }
64
+ return sizeOffsets[detectedMarkerSize]
65
+ })
66
+
67
+ function handleClose() {
68
+ if (!programmaticClose) {
69
+ ctx.setActivePopupMarker(null)
70
+ onclose?.()
71
+ }
72
+ }
73
+
74
+ function closePopup() {
75
+ if (!popup) {
76
+ return
77
+ }
78
+ programmaticClose = true
79
+ popup.remove()
80
+ queueMicrotask(() => {
81
+ programmaticClose = false
82
+ })
83
+ }
84
+
85
+ onMount(() => {
86
+ const map = ctx.map
87
+ if (!map || !contentElement) {
88
+ return
89
+ }
90
+
91
+ popup = new maplibregl.Popup({
92
+ closeButton: true,
93
+ closeOnClick: true,
94
+ offset: computedOffset,
95
+ anchor: 'bottom',
96
+ className: 'shadcn-map-popup',
97
+ })
98
+
99
+ popup.setDOMContent(contentElement)
100
+ popup.setLngLat(lngLat)
101
+ popup.on('close', handleClose)
102
+
103
+ if (open) {
104
+ popup.addTo(map)
105
+ }
106
+
107
+ return () => {
108
+ // If this popup is being unmounted while open, MapLibre won't necessarily emit a "close"
109
+ // event (we detach the listener before remove). Ensure the marker active state is cleared.
110
+ if (lastActiveMarkerId && ctx.activePopupMarkerId === lastActiveMarkerId) {
111
+ ctx.setActivePopupMarker(null)
112
+ }
113
+ popup?.off('close', handleClose)
114
+ popup?.remove()
115
+ popup = null
116
+ }
117
+ })
118
+
119
+ $effect(() => {
120
+ if (popup) {
121
+ popup.setLngLat(lngLat)
122
+ }
123
+ })
124
+
125
+ $effect(() => {
126
+ if (popup) {
127
+ popup.setOffset(computedOffset)
128
+ }
129
+ })
130
+
131
+ $effect(() => {
132
+ const map = ctx.map
133
+ if (!popup || !map) {
134
+ return
135
+ }
136
+
137
+ if (open) {
138
+ if (!popup.isOpen()) {
139
+ popup.addTo(map)
140
+ }
141
+ if (markerAtLocation) {
142
+ ctx.setActivePopupMarker(markerAtLocation.id)
143
+ lastActiveMarkerId = markerAtLocation.id
144
+ }
145
+ }
146
+ else if (popup.isOpen()) {
147
+ closePopup()
148
+ }
149
+ })
150
+
151
+ $effect(() => {
152
+ if (!open) {
153
+ if (markerAtLocation && ctx.activePopupMarkerId === markerAtLocation.id) {
154
+ ctx.setActivePopupMarker(null)
155
+ }
156
+ }
157
+ })
158
+ </script>
159
+
160
+ <div bind:this={contentElement} class='shadcn-popup-content {className}'>
161
+ {#if children}
162
+ {@render children()}
163
+ {/if}
164
+ </div>
165
+
166
+ <style>
167
+ .shadcn-popup-content {
168
+ display: grid;
169
+ gap: 6px;
170
+ }
171
+
172
+ :global(.shadcn-map-popup) {
173
+ z-index: 20 !important;
174
+ }
175
+
176
+ :global(.shadcn-map-popup .maplibregl-popup-content) {
177
+ background: oklch(var(--card));
178
+ color: oklch(var(--card-foreground));
179
+ border: 1px solid oklch(var(--border));
180
+ border-radius: 10px;
181
+ box-shadow: 0 12px 24px rgba(0, 0, 0, 0.25);
182
+ padding: 10px 12px;
183
+ font-size: 13px;
184
+ }
185
+
186
+ :global(.shadcn-map-popup .maplibregl-popup-close-button) {
187
+ color: oklch(var(--muted-foreground));
188
+ font-size: 16px;
189
+ padding: 2px 6px;
190
+ }
191
+
192
+ :global(.shadcn-map-popup .maplibregl-popup-close-button:hover) {
193
+ background: oklch(var(--muted));
194
+ color: oklch(var(--foreground));
195
+ }
196
+
197
+ :global(.shadcn-map-popup.maplibregl-popup-anchor-bottom .maplibregl-popup-tip) {
198
+ border-top-color: oklch(var(--card));
199
+ }
200
+
201
+ :global(.shadcn-map-popup.maplibregl-popup-anchor-top .maplibregl-popup-tip) {
202
+ border-bottom-color: oklch(var(--card));
203
+ }
204
+
205
+ :global(.shadcn-map-popup.maplibregl-popup-anchor-left .maplibregl-popup-tip) {
206
+ border-right-color: oklch(var(--card));
207
+ }
208
+
209
+ :global(.shadcn-map-popup.maplibregl-popup-anchor-right .maplibregl-popup-tip) {
210
+ border-left-color: oklch(var(--card));
211
+ }
212
+
213
+ :global(.shadcn-map-popup.maplibregl-popup-anchor-bottom-left .maplibregl-popup-tip) {
214
+ border-top-color: oklch(var(--card));
215
+ }
216
+
217
+ :global(.shadcn-map-popup.maplibregl-popup-anchor-bottom-right .maplibregl-popup-tip) {
218
+ border-top-color: oklch(var(--card));
219
+ }
220
+
221
+ :global(.shadcn-map-popup.maplibregl-popup-anchor-top-left .maplibregl-popup-tip) {
222
+ border-bottom-color: oklch(var(--card));
223
+ }
224
+
225
+ :global(.shadcn-map-popup.maplibregl-popup-anchor-top-right .maplibregl-popup-tip) {
226
+ border-bottom-color: oklch(var(--card));
227
+ }
228
+ </style>
@@ -0,0 +1,18 @@
1
+ import type { Snippet } from 'svelte';
2
+ export interface PopupProps {
3
+ /** Popup position [lng, lat] */
4
+ lngLat: [number, number];
5
+ /** Whether popup is visible */
6
+ open?: boolean;
7
+ /** Close callback */
8
+ onclose?: () => void;
9
+ /** Additional CSS classes */
10
+ class?: string;
11
+ /** Offset from anchor point (number = uniform, array = [x, y], or 'auto' for auto-detected) */
12
+ offset?: number | [number, number] | 'auto';
13
+ /** Children */
14
+ children?: Snippet;
15
+ }
16
+ declare const Popup: import("svelte").Component<PopupProps, {}, "">;
17
+ type Popup = ReturnType<typeof Popup>;
18
+ export default Popup;
@@ -0,0 +1,141 @@
1
+ <script lang='ts' module>
2
+ import type { ControlPosition } from '../../types'
3
+
4
+ export interface GeolocateControlProps {
5
+ /** Control position on map */
6
+ position?: ControlPosition
7
+ /** Zoom level to fly to when locating */
8
+ zoom?: number
9
+ /** High accuracy geolocation (may be slower / use more battery) */
10
+ enableHighAccuracy?: boolean
11
+ /** Maximum cached position age in ms */
12
+ maximumAge?: number
13
+ /** Timeout in ms */
14
+ timeout?: number
15
+ /** Called with found coordinates */
16
+ onlocate?: (lngLat: [number, number]) => void
17
+ /** Called when geolocation fails */
18
+ onerror?: (error: GeolocationPositionError | Error) => void
19
+ /** Accessible label */
20
+ ariaLabel?: string
21
+ }
22
+ </script>
23
+
24
+ <script lang='ts'>
25
+ import type { Map as MapLibreMap } from 'maplibre-gl'
26
+ import { onMount } from 'svelte'
27
+ import { getMapContext } from '../../context.svelte'
28
+
29
+ const {
30
+ position = 'bottom-right',
31
+ zoom = 14,
32
+ enableHighAccuracy = true,
33
+ maximumAge = 30_000,
34
+ timeout = 10_000,
35
+ onlocate,
36
+ onerror,
37
+ ariaLabel = 'Go to my location',
38
+ }: GeolocateControlProps = $props()
39
+
40
+ const ctx = getMapContext()
41
+
42
+ type ControlLike = {
43
+ onAdd(map: MapLibreMap): HTMLElement
44
+ onRemove(map: MapLibreMap): void
45
+ }
46
+
47
+ let control: ControlLike | null = null
48
+ let mountedMap: MapLibreMap | null = null
49
+
50
+ function handleClick() {
51
+ if (typeof navigator === 'undefined' || !navigator.geolocation) {
52
+ onerror?.(new Error('Geolocation is not available in this environment.'))
53
+ return
54
+ }
55
+
56
+ navigator.geolocation.getCurrentPosition(
57
+ (pos) => {
58
+ const lngLat: [number, number] = [pos.coords.longitude, pos.coords.latitude]
59
+ ctx.flyTo(lngLat, { zoom })
60
+ onlocate?.(lngLat)
61
+ },
62
+ (err) => {
63
+ onerror?.(err)
64
+ },
65
+ { enableHighAccuracy, maximumAge, timeout },
66
+ )
67
+ }
68
+
69
+ onMount(() => {
70
+ const map = ctx.map
71
+ if (!map) {
72
+ return
73
+ }
74
+
75
+ control = {
76
+ onAdd() {
77
+ const container = document.createElement('div')
78
+ container.className = 'maplibregl-ctrl maplibregl-ctrl-group shadcn-geolocate'
79
+
80
+ const button = document.createElement('button')
81
+ button.type = 'button'
82
+ button.className = 'maplibregl-ctrl-icon shadcn-geolocate-btn'
83
+ button.setAttribute('aria-label', ariaLabel)
84
+
85
+ // Simple target icon (SVG) so we don't require icon libraries.
86
+ button.innerHTML = `
87
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor"
88
+ stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
89
+ <circle cx="12" cy="12" r="7"></circle>
90
+ <circle cx="12" cy="12" r="1.5" fill="currentColor" stroke="none"></circle>
91
+ <path d="M12 2v3"></path>
92
+ <path d="M12 19v3"></path>
93
+ <path d="M2 12h3"></path>
94
+ <path d="M19 12h3"></path>
95
+ </svg>
96
+ `
97
+
98
+ button.addEventListener('click', handleClick)
99
+ container.appendChild(button)
100
+ return container
101
+ },
102
+ onRemove(mapInstance) {
103
+ // MapLibre removes the container element automatically.
104
+ void mapInstance
105
+ },
106
+ }
107
+
108
+ mountedMap = map
109
+ map.addControl(control as any, position)
110
+
111
+ return () => {
112
+ if (control && mountedMap) {
113
+ mountedMap.removeControl(control as any)
114
+ }
115
+ control = null
116
+ mountedMap = null
117
+ }
118
+ })
119
+ </script>
120
+
121
+ <style>
122
+ /* Geolocate button base styles */
123
+ :global(.shadcn-map .shadcn-geolocate-btn) {
124
+ display: flex;
125
+ align-items: center;
126
+ justify-content: center;
127
+ background-image: none !important;
128
+ background-color: transparent !important;
129
+ }
130
+
131
+ :global(.shadcn-map .shadcn-geolocate-btn svg) {
132
+ display: block;
133
+ }
134
+
135
+ /* Dark mode: override the filter: invert(1) from Map.svelte since we use inline SVG with currentColor.
136
+ * Also explicitly set color so the SVG stroke inherits the light foreground. */
137
+ :global(.dark .shadcn-map .shadcn-geolocate-btn.maplibregl-ctrl-icon) {
138
+ filter: none !important;
139
+ color: var(--map-ui-foreground);
140
+ }
141
+ </style>
@@ -0,0 +1,22 @@
1
+ import type { ControlPosition } from '../../types';
2
+ export interface GeolocateControlProps {
3
+ /** Control position on map */
4
+ position?: ControlPosition;
5
+ /** Zoom level to fly to when locating */
6
+ zoom?: number;
7
+ /** High accuracy geolocation (may be slower / use more battery) */
8
+ enableHighAccuracy?: boolean;
9
+ /** Maximum cached position age in ms */
10
+ maximumAge?: number;
11
+ /** Timeout in ms */
12
+ timeout?: number;
13
+ /** Called with found coordinates */
14
+ onlocate?: (lngLat: [number, number]) => void;
15
+ /** Called when geolocation fails */
16
+ onerror?: (error: GeolocationPositionError | Error) => void;
17
+ /** Accessible label */
18
+ ariaLabel?: string;
19
+ }
20
+ declare const GeolocateControl: import("svelte").Component<GeolocateControlProps, {}, "">;
21
+ type GeolocateControl = ReturnType<typeof GeolocateControl>;
22
+ export default GeolocateControl;
@@ -0,0 +1,50 @@
1
+ <script lang='ts' module>
2
+ import type { ControlPosition } from '../../types'
3
+
4
+ export interface NavigationControlProps {
5
+ /** Control position on map */
6
+ position?: ControlPosition
7
+ /** Show compass */
8
+ showCompass?: boolean
9
+ /** Show zoom buttons */
10
+ showZoom?: boolean
11
+ }
12
+ </script>
13
+
14
+ <script lang='ts'>
15
+ import maplibregl from 'maplibre-gl'
16
+ import { onMount } from 'svelte'
17
+ import { getMapContext } from '../../context.svelte'
18
+
19
+ const {
20
+ position = 'top-right',
21
+ showCompass = true,
22
+ showZoom = true,
23
+ }: NavigationControlProps = $props()
24
+
25
+ const ctx = getMapContext()
26
+
27
+ let control: maplibregl.NavigationControl | null = null
28
+
29
+ onMount(() => {
30
+ const map = ctx.map
31
+ if (!map)
32
+ return
33
+
34
+ control = new maplibregl.NavigationControl({
35
+ showCompass,
36
+ showZoom,
37
+ visualizePitch: true,
38
+ })
39
+
40
+ map.addControl(control, position)
41
+
42
+ return () => {
43
+ const currentMap = ctx.map
44
+ if (control && currentMap) {
45
+ currentMap.removeControl(control)
46
+ }
47
+ control = null
48
+ }
49
+ })
50
+ </script>
@@ -0,0 +1,12 @@
1
+ import type { ControlPosition } from '../../types';
2
+ export interface NavigationControlProps {
3
+ /** Control position on map */
4
+ position?: ControlPosition;
5
+ /** Show compass */
6
+ showCompass?: boolean;
7
+ /** Show zoom buttons */
8
+ showZoom?: boolean;
9
+ }
10
+ declare const NavigationControl: import("svelte").Component<NavigationControlProps, {}, "">;
11
+ type NavigationControl = ReturnType<typeof NavigationControl>;
12
+ export default NavigationControl;
@@ -0,0 +1,49 @@
1
+ <script lang='ts' module>
2
+ import type { ControlPosition } from '../../types'
3
+
4
+ export interface ScaleControlProps {
5
+ /** Control position on map */
6
+ position?: ControlPosition
7
+ /** Unit of measurement */
8
+ unit?: 'imperial' | 'metric' | 'nautical'
9
+ /** Maximum width in pixels */
10
+ maxWidth?: number
11
+ }
12
+ </script>
13
+
14
+ <script lang='ts'>
15
+ import maplibregl from 'maplibre-gl'
16
+ import { onMount } from 'svelte'
17
+ import { getMapContext } from '../../context.svelte'
18
+
19
+ const {
20
+ position = 'bottom-left',
21
+ unit = 'metric',
22
+ maxWidth = 100,
23
+ }: ScaleControlProps = $props()
24
+
25
+ const ctx = getMapContext()
26
+
27
+ let control: maplibregl.ScaleControl | null = null
28
+
29
+ onMount(() => {
30
+ const map = ctx.map
31
+ if (!map)
32
+ return
33
+
34
+ control = new maplibregl.ScaleControl({
35
+ maxWidth,
36
+ unit,
37
+ })
38
+
39
+ map.addControl(control, position)
40
+
41
+ return () => {
42
+ const currentMap = ctx.map
43
+ if (control && currentMap) {
44
+ currentMap.removeControl(control)
45
+ }
46
+ control = null
47
+ }
48
+ })
49
+ </script>
@@ -0,0 +1,12 @@
1
+ import type { ControlPosition } from '../../types';
2
+ export interface ScaleControlProps {
3
+ /** Control position on map */
4
+ position?: ControlPosition;
5
+ /** Unit of measurement */
6
+ unit?: 'imperial' | 'metric' | 'nautical';
7
+ /** Maximum width in pixels */
8
+ maxWidth?: number;
9
+ }
10
+ declare const ScaleControl: import("svelte").Component<ScaleControlProps, {}, "">;
11
+ type ScaleControl = ReturnType<typeof ScaleControl>;
12
+ export default ScaleControl;
@@ -0,0 +1,6 @@
1
+ export { default as GeolocateControl } from './GeolocateControl.svelte';
2
+ export type { GeolocateControlProps } from './GeolocateControl.svelte';
3
+ export { default as NavigationControl } from './NavigationControl.svelte';
4
+ export type { NavigationControlProps } from './NavigationControl.svelte';
5
+ export { default as ScaleControl } from './ScaleControl.svelte';
6
+ export type { ScaleControlProps } from './ScaleControl.svelte';
@@ -0,0 +1,3 @@
1
+ export { default as GeolocateControl } from './GeolocateControl.svelte';
2
+ export { default as NavigationControl } from './NavigationControl.svelte';
3
+ export { default as ScaleControl } from './ScaleControl.svelte';
@@ -0,0 +1,13 @@
1
+ export { default as ClusterLayer } from './ClusterLayer.svelte';
2
+ export type { ClusterLayerProps, ClusterPoint } from './ClusterLayer.svelte';
3
+ export { NavigationControl, ScaleControl } from './controls';
4
+ export type { GeolocateControlProps, NavigationControlProps, ScaleControlProps } from './controls';
5
+ export { GeolocateControl } from './controls';
6
+ export { default as DetailsPanel } from './DetailsPanel.svelte';
7
+ export type { DetailsPanelProps } from './DetailsPanel.svelte';
8
+ export { default as Map } from './Map.svelte';
9
+ export type { MapProps } from './Map.svelte';
10
+ export { default as Marker } from './Marker.svelte';
11
+ export type { MarkerProps } from './Marker.svelte';
12
+ export { default as Popup } from './Popup.svelte';
13
+ export type { PopupProps } from './Popup.svelte';
@@ -0,0 +1,7 @@
1
+ export { default as ClusterLayer } from './ClusterLayer.svelte';
2
+ export { NavigationControl, ScaleControl } from './controls';
3
+ export { GeolocateControl } from './controls';
4
+ export { default as DetailsPanel } from './DetailsPanel.svelte';
5
+ export { default as Map } from './Map.svelte';
6
+ export { default as Marker } from './Marker.svelte';
7
+ export { default as Popup } from './Popup.svelte';
@@ -0,0 +1,37 @@
1
+ import type maplibregl from 'maplibre-gl';
2
+ export interface MarkerRegistration {
3
+ id: string;
4
+ lngLat: [number, number];
5
+ clusterable: boolean;
6
+ size?: 'sm' | 'md' | 'lg';
7
+ }
8
+ export interface FlyToOptions {
9
+ zoom?: number;
10
+ duration?: number;
11
+ easing?: (t: number) => number;
12
+ }
13
+ export interface LngLatBounds {
14
+ sw: [number, number];
15
+ ne: [number, number];
16
+ }
17
+ export interface MapContextStore {
18
+ readonly map: maplibregl.Map | null;
19
+ readonly loaded: boolean;
20
+ readonly markers: Map<string, MarkerRegistration>;
21
+ readonly clusteredMarkerIds: Set<string>;
22
+ readonly clusteredVersion: number;
23
+ readonly activePopupMarkerId: string | null;
24
+ setMap: (map: maplibregl.Map | null) => void;
25
+ setLoaded: (loaded: boolean) => void;
26
+ registerMarker: (registration: MarkerRegistration) => void;
27
+ updateMarker: (id: string, updates: Partial<MarkerRegistration>) => void;
28
+ unregisterMarker: (id: string) => void;
29
+ setClusteredMarkers: (ids: Set<string>) => void;
30
+ setActivePopupMarker: (id: string | null) => void;
31
+ flyTo: (lngLat: [number, number], options?: FlyToOptions) => void;
32
+ getBounds: () => LngLatBounds | null;
33
+ getCenter: () => [number, number] | null;
34
+ getZoom: () => number | null;
35
+ }
36
+ export declare function createMapContext(): MapContextStore;
37
+ export declare function getMapContext(): MapContextStore;