@elabs-ai/components-maps 4.1.0 → 5.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/README.md +1 -1
- package/dist/chunk-2FPB53NG.js +36 -0
- package/dist/chunk-2FPB53NG.js.map +1 -0
- package/dist/chunk-2VVJRT66.js +37 -0
- package/dist/chunk-2VVJRT66.js.map +1 -0
- package/dist/chunk-3HXFONRP.js +2 -0
- package/dist/chunk-3HXFONRP.js.map +1 -0
- package/dist/chunk-3SJN3IYT.js +2 -0
- package/dist/chunk-3SJN3IYT.js.map +1 -0
- package/dist/chunk-4DANBD5B.js +55 -0
- package/dist/chunk-4DANBD5B.js.map +1 -0
- package/dist/chunk-5PDVG53B.js +2 -0
- package/dist/chunk-5PDVG53B.js.map +1 -0
- package/dist/chunk-643R7IJC.js +2 -0
- package/dist/chunk-643R7IJC.js.map +1 -0
- package/dist/chunk-B3ZDBQ6I.js +164 -0
- package/dist/chunk-B3ZDBQ6I.js.map +1 -0
- package/dist/chunk-BGCE3RR5.js +35 -0
- package/dist/chunk-BGCE3RR5.js.map +1 -0
- package/dist/chunk-C4VI37TD.js +485 -0
- package/dist/chunk-C4VI37TD.js.map +1 -0
- package/dist/chunk-CJJT6AEI.js +179 -0
- package/dist/chunk-CJJT6AEI.js.map +1 -0
- package/dist/chunk-D2RCPTRO.js +2 -0
- package/dist/chunk-D2RCPTRO.js.map +1 -0
- package/dist/chunk-DTV7JZVN.js +2 -0
- package/dist/chunk-DTV7JZVN.js.map +1 -0
- package/dist/chunk-E65Z3MSV.js +80 -0
- package/dist/chunk-E65Z3MSV.js.map +1 -0
- package/dist/chunk-E7VPNINZ.js +70 -0
- package/dist/chunk-E7VPNINZ.js.map +1 -0
- package/dist/chunk-FHV5IA6N.js +100 -0
- package/dist/chunk-FHV5IA6N.js.map +1 -0
- package/dist/chunk-FQ6V7BFZ.js +347 -0
- package/dist/chunk-FQ6V7BFZ.js.map +1 -0
- package/dist/chunk-G7JDXDJN.js +19 -0
- package/dist/chunk-G7JDXDJN.js.map +1 -0
- package/dist/chunk-GWULZOMW.js +21 -0
- package/dist/chunk-GWULZOMW.js.map +1 -0
- package/dist/chunk-GYDTTAVD.js +120 -0
- package/dist/chunk-GYDTTAVD.js.map +1 -0
- package/dist/chunk-HCOBWIM4.js +48 -0
- package/dist/chunk-HCOBWIM4.js.map +1 -0
- package/dist/chunk-IAHK5MVT.js +2 -0
- package/dist/chunk-IAHK5MVT.js.map +1 -0
- package/dist/chunk-JGJ6442I.js +235 -0
- package/dist/chunk-JGJ6442I.js.map +1 -0
- package/dist/chunk-JYFERXZT.js +18 -0
- package/dist/chunk-JYFERXZT.js.map +1 -0
- package/dist/chunk-LU2UEKFM.js +53 -0
- package/dist/chunk-LU2UEKFM.js.map +1 -0
- package/dist/chunk-LVYM6C5C.js +2 -0
- package/dist/chunk-LVYM6C5C.js.map +1 -0
- package/dist/chunk-MIMDP3EU.js +104 -0
- package/dist/chunk-MIMDP3EU.js.map +1 -0
- package/dist/chunk-NNBURJHY.js +2 -0
- package/dist/chunk-NNBURJHY.js.map +1 -0
- package/dist/chunk-NPUC3V37.js +2 -0
- package/dist/chunk-NPUC3V37.js.map +1 -0
- package/dist/chunk-OEVVNPN3.js +201 -0
- package/dist/chunk-OEVVNPN3.js.map +1 -0
- package/dist/chunk-PF3R2BXM.js +200 -0
- package/dist/chunk-PF3R2BXM.js.map +1 -0
- package/dist/chunk-Q2I5YODW.js +2 -0
- package/dist/chunk-Q2I5YODW.js.map +1 -0
- package/dist/chunk-QDWWP3N7.js +247 -0
- package/dist/chunk-QDWWP3N7.js.map +1 -0
- package/dist/chunk-QU33KPMP.js +2 -0
- package/dist/chunk-QU33KPMP.js.map +1 -0
- package/dist/chunk-RK4BUMHS.js +2 -0
- package/dist/chunk-RK4BUMHS.js.map +1 -0
- package/dist/chunk-RNSLG64F.js +26 -0
- package/dist/chunk-RNSLG64F.js.map +1 -0
- package/dist/chunk-RV673TB4.js +68 -0
- package/dist/chunk-RV673TB4.js.map +1 -0
- package/dist/chunk-S7N2WMVT.js +180 -0
- package/dist/chunk-S7N2WMVT.js.map +1 -0
- package/dist/chunk-T3Z6TCDD.js +2 -0
- package/dist/chunk-T3Z6TCDD.js.map +1 -0
- package/dist/chunk-T4TJTVVA.js +105 -0
- package/dist/chunk-T4TJTVVA.js.map +1 -0
- package/dist/chunk-UMOYRCDX.js +103 -0
- package/dist/chunk-UMOYRCDX.js.map +1 -0
- package/dist/chunk-V2REM6UT.js +185 -0
- package/dist/chunk-V2REM6UT.js.map +1 -0
- package/dist/chunk-VFBRFGID.js +89 -0
- package/dist/chunk-VFBRFGID.js.map +1 -0
- package/dist/chunk-W76NLFER.js +103 -0
- package/dist/chunk-W76NLFER.js.map +1 -0
- package/dist/chunk-WNU4IOGL.js +116 -0
- package/dist/chunk-WNU4IOGL.js.map +1 -0
- package/dist/chunk-WS4Z7ENS.js +494 -0
- package/dist/chunk-WS4Z7ENS.js.map +1 -0
- package/dist/chunk-XQT7YLJY.js +497 -0
- package/dist/chunk-XQT7YLJY.js.map +1 -0
- package/dist/chunk-Y44MEKJV.js +21 -0
- package/dist/chunk-Y44MEKJV.js.map +1 -0
- package/dist/chunk-Z4EPSOB4.js +53 -0
- package/dist/chunk-Z4EPSOB4.js.map +1 -0
- package/dist/chunk-Z5OPDBDC.js +2 -0
- package/dist/chunk-Z5OPDBDC.js.map +1 -0
- package/dist/index.d.ts +1241 -46
- package/dist/index.js +189 -1456
- package/dist/index.js.map +1 -1
- package/dist/lib/arc-math.js +8 -0
- package/dist/lib/arc-math.js.map +1 -0
- package/dist/lib/map-position.js +11 -0
- package/dist/lib/map-position.js.map +1 -0
- package/dist/lib/merge-hover-paint.js +10 -0
- package/dist/lib/merge-hover-paint.js.map +1 -0
- package/dist/lib/plan-crs.js +14 -0
- package/dist/lib/plan-crs.js.map +1 -0
- package/dist/lib/plan-patterns.js +14 -0
- package/dist/lib/plan-patterns.js.map +1 -0
- package/dist/lib/plan-regions.js +18 -0
- package/dist/lib/plan-regions.js.map +1 -0
- package/dist/lib/plan-status.js +14 -0
- package/dist/lib/plan-status.js.map +1 -0
- package/dist/lib/route-arrow.js +12 -0
- package/dist/lib/route-arrow.js.map +1 -0
- package/dist/lib/use-map-breakpoint.js +33 -0
- package/dist/lib/use-map-breakpoint.js.map +1 -0
- package/dist/lib/use-plan-projection.js +9 -0
- package/dist/lib/use-plan-projection.js.map +1 -0
- package/dist/lib/use-token-color.js +10 -0
- package/dist/lib/use-token-color.js.map +1 -0
- package/dist/lib/warn-once.js +10 -0
- package/dist/lib/warn-once.js.map +1 -0
- package/dist/map-annotation/anchor.js +14 -0
- package/dist/map-annotation/anchor.js.map +1 -0
- package/dist/map-annotation/index.js +21 -0
- package/dist/map-annotation/index.js.map +1 -0
- package/dist/map-annotation/map-annotation.js +18 -0
- package/dist/map-annotation/map-annotation.js.map +1 -0
- package/dist/map-arc/index.js +16 -0
- package/dist/map-arc/index.js.map +1 -0
- package/dist/map-arc/map-arc.js +13 -0
- package/dist/map-arc/map-arc.js.map +1 -0
- package/dist/map-canvas/index.css +11 -0
- package/dist/map-canvas/index.css.map +1 -0
- package/dist/map-canvas/index.js +20 -0
- package/dist/map-canvas/index.js.map +1 -0
- package/dist/map-canvas/map-canvas.css +11 -0
- package/dist/map-canvas/map-canvas.css.map +1 -0
- package/dist/map-canvas/map-canvas.js +17 -0
- package/dist/map-canvas/map-canvas.js.map +1 -0
- package/dist/map-canvas/map-context.js +11 -0
- package/dist/map-canvas/map-context.js.map +1 -0
- package/dist/map-canvas/use-resolved-basemap-theme.js +9 -0
- package/dist/map-canvas/use-resolved-basemap-theme.js.map +1 -0
- package/dist/map-cluster-layer/index.js +12 -0
- package/dist/map-cluster-layer/index.js.map +1 -0
- package/dist/map-cluster-layer/map-cluster-layer.js +12 -0
- package/dist/map-cluster-layer/map-cluster-layer.js.map +1 -0
- package/dist/map-controls/index.js +11 -0
- package/dist/map-controls/index.js.map +1 -0
- package/dist/map-controls/map-controls.js +11 -0
- package/dist/map-controls/map-controls.js.map +1 -0
- package/dist/map-geojson/index.js +13 -0
- package/dist/map-geojson/index.js.map +1 -0
- package/dist/map-geojson/map-geojson.js +13 -0
- package/dist/map-geojson/map-geojson.js.map +1 -0
- package/dist/map-inset/index.css +11 -0
- package/dist/map-inset/index.css.map +1 -0
- package/dist/map-inset/index.js +20 -0
- package/dist/map-inset/index.js.map +1 -0
- package/dist/map-inset/map-inset.css +11 -0
- package/dist/map-inset/map-inset.css.map +1 -0
- package/dist/map-inset/map-inset.js +20 -0
- package/dist/map-inset/map-inset.js.map +1 -0
- package/dist/map-legend/index.js +14 -0
- package/dist/map-legend/index.js.map +1 -0
- package/dist/map-legend/map-corner.js +10 -0
- package/dist/map-legend/map-corner.js.map +1 -0
- package/dist/map-legend/map-legend.js +11 -0
- package/dist/map-legend/map-legend.js.map +1 -0
- package/dist/map-marker/index.js +22 -0
- package/dist/map-marker/index.js.map +1 -0
- package/dist/map-marker/map-marker.js +22 -0
- package/dist/map-marker/map-marker.js.map +1 -0
- package/dist/map-north-arrow/index.js +11 -0
- package/dist/map-north-arrow/index.js.map +1 -0
- package/dist/map-north-arrow/map-north-arrow.js +11 -0
- package/dist/map-north-arrow/map-north-arrow.js.map +1 -0
- package/dist/map-plan/index.js +30 -0
- package/dist/map-plan/index.js.map +1 -0
- package/dist/map-plan/map-plan-legend.js +10 -0
- package/dist/map-plan/map-plan-legend.js.map +1 -0
- package/dist/map-plan/map-plan-overlay.js +13 -0
- package/dist/map-plan/map-plan-overlay.js.map +1 -0
- package/dist/map-plan/map-plan-status.js +9 -0
- package/dist/map-plan/map-plan-status.js.map +1 -0
- package/dist/map-plan/map-plan-table.js +10 -0
- package/dist/map-plan/map-plan-table.js.map +1 -0
- package/dist/map-plan/use-plan-selection.js +9 -0
- package/dist/map-plan/use-plan-selection.js.map +1 -0
- package/dist/map-plan-image/index.js +11 -0
- package/dist/map-plan-image/index.js.map +1 -0
- package/dist/map-plan-image/map-plan-image.js +11 -0
- package/dist/map-plan-image/map-plan-image.js.map +1 -0
- package/dist/map-popup/index.js +12 -0
- package/dist/map-popup/index.js.map +1 -0
- package/dist/map-popup/map-popup.js +12 -0
- package/dist/map-popup/map-popup.js.map +1 -0
- package/dist/map-route/index.js +12 -0
- package/dist/map-route/index.js.map +1 -0
- package/dist/map-route/map-route.js +12 -0
- package/dist/map-route/map-route.js.map +1 -0
- package/dist/map-scale-bar/index.js +18 -0
- package/dist/map-scale-bar/index.js.map +1 -0
- package/dist/map-scale-bar/map-scale-bar.js +18 -0
- package/dist/map-scale-bar/map-scale-bar.js.map +1 -0
- package/package.json +5 -5
- package/src/index.ts +83 -0
- package/src/lib/arc-math.test.ts +19 -0
- package/src/lib/arc-math.ts +6 -1
- package/src/lib/map-position.ts +77 -0
- package/src/lib/merge-hover-paint.ts +44 -13
- package/src/lib/plan-crs.parity.test.ts +39 -0
- package/src/lib/plan-crs.test.ts +248 -0
- package/src/lib/plan-crs.ts +252 -0
- package/src/lib/plan-patterns.test.ts +255 -0
- package/src/lib/plan-patterns.ts +160 -0
- package/src/lib/plan-regions.test.ts +186 -0
- package/src/lib/plan-regions.ts +209 -0
- package/src/lib/plan-status.test.ts +87 -0
- package/src/lib/plan-status.ts +147 -0
- package/src/lib/route-arrow.test.ts +88 -0
- package/src/lib/route-arrow.ts +59 -0
- package/src/lib/use-map-breakpoint.test.ts +83 -0
- package/src/lib/use-map-breakpoint.ts +238 -0
- package/src/lib/use-plan-projection.ts +157 -0
- package/src/lib/warn-once.ts +21 -0
- package/src/map-annotation/anchor.ts +92 -0
- package/src/map-annotation/index.ts +15 -0
- package/src/map-annotation/map-annotation.stories.tsx +113 -0
- package/src/map-annotation/map-annotation.test.tsx +106 -0
- package/src/map-annotation/map-annotation.tsx +356 -0
- package/src/map-arc/map-arc.tsx +26 -5
- package/src/map-canvas/map-canvas.stories.tsx +211 -0
- package/src/map-canvas/map-canvas.test.tsx +421 -1
- package/src/map-canvas/map-canvas.tsx +466 -20
- package/src/map-canvas/map-context.ts +11 -0
- package/src/map-cluster-layer/map-cluster-layer.tsx +14 -1
- package/src/map-controls/map-controls.stories.tsx +16 -0
- package/src/map-controls/map-controls.test.tsx +145 -1
- package/src/map-controls/map-controls.tsx +57 -12
- package/src/map-geojson/map-geojson.stories.tsx +153 -3
- package/src/map-geojson/map-geojson.test.tsx +453 -0
- package/src/map-geojson/map-geojson.tsx +591 -51
- package/src/map-inset/index.ts +1 -0
- package/src/map-inset/map-inset.stories.tsx +61 -0
- package/src/map-inset/map-inset.test.tsx +117 -0
- package/src/map-inset/map-inset.tsx +264 -0
- package/src/map-legend/index.ts +10 -0
- package/src/map-legend/map-corner.ts +23 -0
- package/src/map-legend/map-legend.stories.tsx +171 -0
- package/src/map-legend/map-legend.test.tsx +136 -0
- package/src/map-legend/map-legend.tsx +264 -0
- package/src/map-marker/map-marker.stories.tsx +136 -4
- package/src/map-marker/map-marker.test.tsx +383 -3
- package/src/map-marker/map-marker.tsx +414 -44
- package/src/map-north-arrow/index.ts +1 -0
- package/src/map-north-arrow/map-north-arrow.stories.tsx +65 -0
- package/src/map-north-arrow/map-north-arrow.test.tsx +39 -0
- package/src/map-north-arrow/map-north-arrow.tsx +82 -0
- package/src/map-plan/index.ts +13 -0
- package/src/map-plan/map-plan-legend.test.tsx +61 -0
- package/src/map-plan/map-plan-legend.tsx +83 -0
- package/src/map-plan/map-plan-overlay.stories.tsx +260 -0
- package/src/map-plan/map-plan-overlay.test.tsx +302 -0
- package/src/map-plan/map-plan-overlay.tsx +531 -0
- package/src/map-plan/map-plan-status.test.tsx +71 -0
- package/src/map-plan/map-plan-status.tsx +77 -0
- package/src/map-plan/map-plan-table.test.tsx +86 -0
- package/src/map-plan/map-plan-table.tsx +153 -0
- package/src/map-plan/use-plan-selection.ts +78 -0
- package/src/map-plan-image/index.ts +1 -0
- package/src/map-plan-image/map-plan-image.stories.tsx +301 -0
- package/src/map-plan-image/map-plan-image.test.tsx +176 -0
- package/src/map-plan-image/map-plan-image.tsx +279 -0
- package/src/map-popup/map-popup.tsx +18 -11
- package/src/map-route/index.ts +1 -1
- package/src/map-route/map-route.test.tsx +216 -0
- package/src/map-route/map-route.tsx +105 -6
- package/src/map-scale-bar/index.ts +9 -0
- package/src/map-scale-bar/map-scale-bar.stories.tsx +63 -0
- package/src/map-scale-bar/map-scale-bar.test.tsx +65 -0
- package/src/map-scale-bar/map-scale-bar.tsx +145 -0
- package/src/test-utils/locator-fixture.ts +75 -0
- package/src/test-utils/maplibre-mock.ts +267 -20
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A hand-simplified Lake Ontario locator fixture (≈ 20 vertices a shape, WGS 84
|
|
3
|
+
* lon / lat) for the locator-furniture stories and tests — two area markers
|
|
4
|
+
* and a few places. Offline and tiny on purpose; not survey-accurate.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export const LAKE_ONTARIO: GeoJSON.Feature<GeoJSON.Polygon, { name: string }> = {
|
|
8
|
+
type: "Feature",
|
|
9
|
+
properties: { name: "Lake Ontario" },
|
|
10
|
+
geometry: {
|
|
11
|
+
type: "Polygon",
|
|
12
|
+
coordinates: [
|
|
13
|
+
[
|
|
14
|
+
[-79.8, 43.28],
|
|
15
|
+
[-79.55, 43.47],
|
|
16
|
+
[-79.38, 43.63],
|
|
17
|
+
[-79.05, 43.78],
|
|
18
|
+
[-78.86, 43.87],
|
|
19
|
+
[-78.17, 43.95],
|
|
20
|
+
[-77.55, 43.99],
|
|
21
|
+
[-77.15, 43.86],
|
|
22
|
+
[-76.82, 43.95],
|
|
23
|
+
[-76.48, 44.21],
|
|
24
|
+
[-76.24, 44.19],
|
|
25
|
+
[-76.2, 43.95],
|
|
26
|
+
[-76.46, 43.52],
|
|
27
|
+
[-76.95, 43.28],
|
|
28
|
+
[-77.6, 43.26],
|
|
29
|
+
[-78.3, 43.37],
|
|
30
|
+
[-78.9, 43.33],
|
|
31
|
+
[-79.06, 43.26],
|
|
32
|
+
[-79.56, 43.2],
|
|
33
|
+
[-79.8, 43.28],
|
|
34
|
+
],
|
|
35
|
+
],
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const GREATER_TORONTO: GeoJSON.Feature<GeoJSON.Polygon, { name: string }> = {
|
|
40
|
+
type: "Feature",
|
|
41
|
+
properties: { name: "Greater Toronto Area" },
|
|
42
|
+
geometry: {
|
|
43
|
+
type: "Polygon",
|
|
44
|
+
coordinates: [
|
|
45
|
+
[
|
|
46
|
+
[-79.8, 43.3],
|
|
47
|
+
[-79.55, 43.47],
|
|
48
|
+
[-79.38, 43.63],
|
|
49
|
+
[-79.05, 43.78],
|
|
50
|
+
[-78.86, 43.87],
|
|
51
|
+
[-78.8, 44.15],
|
|
52
|
+
[-79.3, 44.28],
|
|
53
|
+
[-79.85, 44.08],
|
|
54
|
+
[-80.05, 43.72],
|
|
55
|
+
[-79.8, 43.3],
|
|
56
|
+
],
|
|
57
|
+
],
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/** West, south, east, north of both areas — the locator's data extent. */
|
|
62
|
+
export const LOCATOR_BOUNDS: [[number, number], [number, number]] = [
|
|
63
|
+
[-80.05, 43.2],
|
|
64
|
+
[-76.2, 44.28],
|
|
65
|
+
];
|
|
66
|
+
|
|
67
|
+
/** Places the locator labels, west → east. */
|
|
68
|
+
export const LOCATOR_PLACES = {
|
|
69
|
+
toronto: { longitude: -79.38, latitude: 43.65 },
|
|
70
|
+
hamilton: { longitude: -79.87, latitude: 43.25 },
|
|
71
|
+
rochester: { longitude: -77.61, latitude: 43.16 },
|
|
72
|
+
kingston: { longitude: -76.48, latitude: 44.23 },
|
|
73
|
+
lakeLabel: { longitude: -77.9, latitude: 43.62 },
|
|
74
|
+
gtaLabel: { longitude: -79.45, latitude: 43.93 },
|
|
75
|
+
} as const;
|
|
@@ -13,16 +13,112 @@
|
|
|
13
13
|
|
|
14
14
|
type Handler = (...args: any[]) => void;
|
|
15
15
|
|
|
16
|
+
export class MockHandler {
|
|
17
|
+
enabled = true;
|
|
18
|
+
enable() {
|
|
19
|
+
this.enabled = true;
|
|
20
|
+
}
|
|
21
|
+
disable() {
|
|
22
|
+
this.enabled = false;
|
|
23
|
+
}
|
|
24
|
+
isEnabled() {
|
|
25
|
+
return this.enabled;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* One persistent instance per source id, so a component that subscribes to its
|
|
31
|
+
* own source (`source.on("error", …)`) or updates it in place
|
|
32
|
+
* (`setCoordinates`/`updateImage`) can be asserted against. The spec fields are
|
|
33
|
+
* spread onto the instance, so reads like `source.type` still work.
|
|
34
|
+
*/
|
|
35
|
+
export class MockSource {
|
|
36
|
+
static instances: MockSource[] = [];
|
|
37
|
+
|
|
38
|
+
id: string;
|
|
39
|
+
spec: Record<string, any>;
|
|
40
|
+
handlers = new Map<string, Set<Handler>>();
|
|
41
|
+
setDataCalls: unknown[] = [];
|
|
42
|
+
coordinatesCalls: unknown[] = [];
|
|
43
|
+
updateImageCalls: unknown[] = [];
|
|
44
|
+
|
|
45
|
+
constructor(id: string, spec: Record<string, any>) {
|
|
46
|
+
this.id = id;
|
|
47
|
+
this.spec = spec;
|
|
48
|
+
Object.assign(this, spec);
|
|
49
|
+
MockSource.instances.push(this);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
setData(data: unknown) {
|
|
53
|
+
this.setDataCalls.push(data);
|
|
54
|
+
return this;
|
|
55
|
+
}
|
|
56
|
+
setCoordinates(coordinates: unknown) {
|
|
57
|
+
this.coordinatesCalls.push(coordinates);
|
|
58
|
+
return this;
|
|
59
|
+
}
|
|
60
|
+
updateImage(options: unknown) {
|
|
61
|
+
this.updateImageCalls.push(options);
|
|
62
|
+
return this;
|
|
63
|
+
}
|
|
64
|
+
async getClusterExpansionZoom() {
|
|
65
|
+
return 2;
|
|
66
|
+
}
|
|
67
|
+
on(event: string, handler: Handler) {
|
|
68
|
+
if (!this.handlers.has(event)) this.handlers.set(event, new Set());
|
|
69
|
+
this.handlers.get(event)!.add(handler);
|
|
70
|
+
return this;
|
|
71
|
+
}
|
|
72
|
+
off(event: string, handler: Handler) {
|
|
73
|
+
this.handlers.get(event)?.delete(handler);
|
|
74
|
+
return this;
|
|
75
|
+
}
|
|
76
|
+
/** Fire an event on this source — e.g. a failed image fetch. */
|
|
77
|
+
emit(event: string, ...args: unknown[]) {
|
|
78
|
+
this.handlers.get(event)?.forEach((handler) => {
|
|
79
|
+
handler(...args);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
16
84
|
export class MockMap {
|
|
17
85
|
static instances: MockMap[] = [];
|
|
18
86
|
|
|
19
87
|
handlers = new Map<string, Set<Handler>>();
|
|
20
88
|
container: HTMLElement;
|
|
21
89
|
removed = false;
|
|
22
|
-
sources = new Map<string,
|
|
90
|
+
sources = new Map<string, MockSource>();
|
|
23
91
|
layers = new Map<string, any>();
|
|
24
92
|
canvas = document.createElement("canvas");
|
|
93
|
+
/** Starts with MapLibre's interactive class, as a real interactive map's does. */
|
|
94
|
+
canvasContainer = Object.assign(document.createElement("div"), {
|
|
95
|
+
className: "maplibregl-canvas-container maplibregl-interactive",
|
|
96
|
+
});
|
|
25
97
|
zoomToCalls: unknown[] = [];
|
|
98
|
+
images = new Map<string, unknown>();
|
|
99
|
+
center = { lng: 0, lat: 0 };
|
|
100
|
+
zoom = 1;
|
|
101
|
+
bearing = 0;
|
|
102
|
+
|
|
103
|
+
/** Gesture handlers, each with an `enabled` flag static mode flips. */
|
|
104
|
+
scrollZoom = new MockHandler();
|
|
105
|
+
boxZoom = new MockHandler();
|
|
106
|
+
dragRotate = new MockHandler();
|
|
107
|
+
dragPan = new MockHandler();
|
|
108
|
+
keyboard = new MockHandler();
|
|
109
|
+
doubleClickZoom = new MockHandler();
|
|
110
|
+
touchZoomRotate = new MockHandler();
|
|
111
|
+
touchPitch = new MockHandler();
|
|
112
|
+
addLayerCalls: unknown[] = [];
|
|
113
|
+
paint = new Map<string, unknown>();
|
|
114
|
+
layout = new Map<string, unknown>();
|
|
115
|
+
featureStateCalls: unknown[] = [];
|
|
116
|
+
/** `[id, image, options]` per `addImage` — the pattern registration asserts `pixelRatio`. */
|
|
117
|
+
addImageCalls: [string, unknown, unknown][] = [];
|
|
118
|
+
updateImageCalls: [string, unknown][] = [];
|
|
119
|
+
minZoom: number | undefined;
|
|
120
|
+
maxZoom: number | undefined;
|
|
121
|
+
maxBounds: unknown;
|
|
26
122
|
|
|
27
123
|
/** The full options object the component constructed the map with. */
|
|
28
124
|
options: Record<string, any>;
|
|
@@ -30,6 +126,10 @@ export class MockMap {
|
|
|
30
126
|
constructor(options: { container: HTMLElement } & Record<string, any>) {
|
|
31
127
|
this.container = options.container;
|
|
32
128
|
this.options = options;
|
|
129
|
+
// What MapLibre would measure: the box's height rule at construction time,
|
|
130
|
+
// and whether that rule could still be mid-transition when it measured.
|
|
131
|
+
this.aspectAtConstruction = options.container.style.aspectRatio;
|
|
132
|
+
this.transitionAtConstruction = options.container.style.transitionProperty;
|
|
33
133
|
MockMap.instances.push(this);
|
|
34
134
|
}
|
|
35
135
|
|
|
@@ -55,18 +155,47 @@ export class MockMap {
|
|
|
55
155
|
return this;
|
|
56
156
|
}
|
|
57
157
|
|
|
158
|
+
/** Manually re-fire an event's handlers — e.g. a second `styledata` after a style reload. */
|
|
159
|
+
emit(event: string, layerId?: string, ...args: unknown[]) {
|
|
160
|
+
this.handlers.get(this.key(event, layerId))?.forEach((handler) => {
|
|
161
|
+
handler(...args);
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
|
|
58
165
|
remove() {
|
|
59
166
|
this.removed = true;
|
|
60
167
|
}
|
|
61
168
|
|
|
62
169
|
getCenter() {
|
|
63
|
-
return
|
|
170
|
+
return this.center;
|
|
64
171
|
}
|
|
65
172
|
getZoom() {
|
|
66
|
-
return
|
|
173
|
+
return this.zoom;
|
|
67
174
|
}
|
|
68
175
|
getBearing() {
|
|
69
|
-
return
|
|
176
|
+
return this.bearing;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* A flat equirectangular stand-in: 1° = 10 px from the container's top-left.
|
|
180
|
+
* Accepts both shapes MapLibre's own `project` does — a `[lng, lat]` pair
|
|
181
|
+
* and a `LngLat`.
|
|
182
|
+
*/
|
|
183
|
+
project(lngLat: [number, number] | { lng: number; lat: number }) {
|
|
184
|
+
const [lng, lat] = Array.isArray(lngLat) ? lngLat : [lngLat.lng, lngLat.lat];
|
|
185
|
+
return { x: (lng + 180) * 10, y: (90 - lat) * 10 };
|
|
186
|
+
}
|
|
187
|
+
/** Inverse of {@link project} — the same flat equirectangular stand-in. */
|
|
188
|
+
unproject(point: [number, number] | { x: number; y: number }) {
|
|
189
|
+
const [x, y] = Array.isArray(point) ? point : [point.x, point.y];
|
|
190
|
+
return { lng: x / 10 - 180, lat: 90 - y / 10 };
|
|
191
|
+
}
|
|
192
|
+
getBounds() {
|
|
193
|
+
return {
|
|
194
|
+
getWest: () => -10,
|
|
195
|
+
getSouth: () => -10,
|
|
196
|
+
getEast: () => 10,
|
|
197
|
+
getNorth: () => 10,
|
|
198
|
+
};
|
|
70
199
|
}
|
|
71
200
|
getPitch() {
|
|
72
201
|
return 0;
|
|
@@ -74,9 +203,19 @@ export class MockMap {
|
|
|
74
203
|
isMoving() {
|
|
75
204
|
return false;
|
|
76
205
|
}
|
|
77
|
-
jumpTo()
|
|
206
|
+
/** Every `jumpTo(options)` the wrapper asked for, in order. */
|
|
207
|
+
jumpToCalls: any[] = [];
|
|
208
|
+
jumpTo(options?: any) {
|
|
209
|
+
this.jumpToCalls.push(options);
|
|
210
|
+
}
|
|
78
211
|
easeTo() {}
|
|
79
212
|
flyTo() {}
|
|
213
|
+
/** Every `fitBounds(bounds, options)` the wrapper asked for, in order. */
|
|
214
|
+
fitBoundsCalls: { bounds: unknown; options: unknown }[] = [];
|
|
215
|
+
fitBounds(bounds: unknown, options?: unknown) {
|
|
216
|
+
this.fitBoundsCalls.push({ bounds, options });
|
|
217
|
+
return this;
|
|
218
|
+
}
|
|
80
219
|
zoomTo(zoom: number, options?: unknown) {
|
|
81
220
|
this.zoomToCalls.push([zoom, options]);
|
|
82
221
|
}
|
|
@@ -89,19 +228,39 @@ export class MockMap {
|
|
|
89
228
|
getCanvas() {
|
|
90
229
|
return this.canvas;
|
|
91
230
|
}
|
|
231
|
+
aspectAtConstruction = "";
|
|
232
|
+
transitionAtConstruction = "";
|
|
233
|
+
resizeCount = 0;
|
|
234
|
+
resize() {
|
|
235
|
+
this.resizeCount += 1;
|
|
236
|
+
return this;
|
|
237
|
+
}
|
|
238
|
+
getCanvasContainer() {
|
|
239
|
+
return this.canvasContainer;
|
|
240
|
+
}
|
|
241
|
+
/** `[id, image, options]` per call — the pattern registration asserts `pixelRatio`. */
|
|
242
|
+
addImage(id: string, image: unknown, options?: unknown) {
|
|
243
|
+
this.addImageCalls.push([id, image, options]);
|
|
244
|
+
this.images.set(id, image);
|
|
245
|
+
}
|
|
246
|
+
hasImage(id: string) {
|
|
247
|
+
return this.images.has(id);
|
|
248
|
+
}
|
|
249
|
+
removeImage(id: string) {
|
|
250
|
+
this.images.delete(id);
|
|
251
|
+
}
|
|
92
252
|
addSource(id: string, source: any) {
|
|
93
|
-
this.sources.set(id, source);
|
|
253
|
+
this.sources.set(id, new MockSource(id, source));
|
|
94
254
|
}
|
|
95
255
|
getSource(id: string) {
|
|
96
|
-
|
|
97
|
-
if (!source) return undefined;
|
|
98
|
-
return { ...source, setData: () => {}, getClusterExpansionZoom: async () => 2 };
|
|
256
|
+
return this.sources.get(id);
|
|
99
257
|
}
|
|
100
258
|
removeSource(id: string) {
|
|
101
259
|
this.sources.delete(id);
|
|
102
260
|
}
|
|
103
|
-
addLayer(layer: { id: string }) {
|
|
261
|
+
addLayer(layer: { id: string } & Record<string, any>, beforeId?: string) {
|
|
104
262
|
this.layers.set(layer.id, layer);
|
|
263
|
+
this.addLayerCalls.push([layer, beforeId]);
|
|
105
264
|
}
|
|
106
265
|
getLayer(id: string) {
|
|
107
266
|
return this.layers.get(id);
|
|
@@ -109,11 +268,55 @@ export class MockMap {
|
|
|
109
268
|
removeLayer(id: string) {
|
|
110
269
|
this.layers.delete(id);
|
|
111
270
|
}
|
|
112
|
-
setPaintProperty() {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
271
|
+
setPaintProperty(layerId: string, name: string, value: unknown) {
|
|
272
|
+
this.paint.set(`${layerId}:${name}`, value);
|
|
273
|
+
}
|
|
274
|
+
/** Layout properties the wrapper set, keyed `<layerId>:<property>`. */
|
|
275
|
+
layoutProperties = new Map<string, unknown>();
|
|
276
|
+
setLayoutProperty(layerId: string, property: string, value: unknown) {
|
|
277
|
+
this.layoutProperties.set(`${layerId}:${property}`, value);
|
|
278
|
+
this.layout.set(`${layerId}:${property}`, value);
|
|
279
|
+
}
|
|
280
|
+
getLayoutProperty(layerId: string, property: string) {
|
|
281
|
+
return this.layoutProperties.get(`${layerId}:${property}`);
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* The style the map is showing. Like MapLibre's own, it lists every layer
|
|
285
|
+
* the map holds — a test describes a basemap's symbol layers by adding them
|
|
286
|
+
* with `addLayer`.
|
|
287
|
+
*/
|
|
288
|
+
getStyle() {
|
|
289
|
+
return { layers: [...this.layers.values()] };
|
|
290
|
+
}
|
|
291
|
+
/** Observable feature-state, keyed by feature id — the hover highlight. */
|
|
292
|
+
featureStates = new Map<string | number, Record<string, unknown>>();
|
|
293
|
+
setFeatureState(target: { source: string; id: string | number }, state: Record<string, unknown>) {
|
|
294
|
+
this.featureStateCalls.push([target, state]);
|
|
295
|
+
this.featureStates.set(target.id, { ...this.featureStates.get(target.id), ...state });
|
|
296
|
+
}
|
|
297
|
+
/** What the next `queryRenderedFeatures` should return; set it per test. */
|
|
298
|
+
queryRenderedFeaturesResult: any[] = [];
|
|
299
|
+
queryRenderedFeaturesCalls: unknown[] = [];
|
|
300
|
+
queryRenderedFeatures(geometry?: unknown, options?: unknown) {
|
|
301
|
+
this.queryRenderedFeaturesCalls.push([geometry, options]);
|
|
302
|
+
return this.queryRenderedFeaturesResult;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Camera limits — a plan map clamps pan and zoom to its extent.
|
|
306
|
+
setMinZoom(zoom: number) {
|
|
307
|
+
this.minZoom = zoom;
|
|
308
|
+
}
|
|
309
|
+
setMaxZoom(zoom: number) {
|
|
310
|
+
this.maxZoom = zoom;
|
|
311
|
+
}
|
|
312
|
+
setMaxBounds(bounds: unknown) {
|
|
313
|
+
this.maxBounds = bounds;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/** A canvas-generated tile re-registered in place, `[id, image]` per call. */
|
|
317
|
+
updateImage(id: string, image: unknown) {
|
|
318
|
+
this.updateImageCalls.push([id, image]);
|
|
319
|
+
this.images.set(id, image);
|
|
117
320
|
}
|
|
118
321
|
}
|
|
119
322
|
|
|
@@ -124,14 +327,20 @@ export class MockMarker {
|
|
|
124
327
|
addedTo: MockMap | null = null;
|
|
125
328
|
popup: unknown = null;
|
|
126
329
|
lngLat = { lng: 0, lat: 0 };
|
|
330
|
+
/** The full options object the component constructed the marker with. */
|
|
331
|
+
options: Record<string, any>;
|
|
127
332
|
|
|
128
|
-
constructor(options: { element?: HTMLElement } = {}) {
|
|
333
|
+
constructor(options: { element?: HTMLElement } & Record<string, any> = {}) {
|
|
129
334
|
this.element = options.element ?? document.createElement("div");
|
|
335
|
+
this.options = options;
|
|
130
336
|
MockMarker.instances.push(this);
|
|
131
337
|
}
|
|
132
338
|
|
|
133
|
-
|
|
134
|
-
|
|
339
|
+
/** Accepts both shapes MapLibre does: a `[lng, lat]` pair and a `LngLat`. */
|
|
340
|
+
setLngLat(lngLat: [number, number] | { lng: number; lat: number }) {
|
|
341
|
+
this.lngLat = Array.isArray(lngLat)
|
|
342
|
+
? { lng: lngLat[0], lat: lngLat[1] }
|
|
343
|
+
: { lng: lngLat.lng, lat: lngLat.lat };
|
|
135
344
|
return this;
|
|
136
345
|
}
|
|
137
346
|
getLngLat() {
|
|
@@ -193,6 +402,8 @@ export class MockPopup {
|
|
|
193
402
|
static instances: MockPopup[] = [];
|
|
194
403
|
|
|
195
404
|
content: HTMLElement | null = null;
|
|
405
|
+
/** Whether the popup is currently on a map — what `addTo`/`remove` toggle. */
|
|
406
|
+
open = false;
|
|
196
407
|
|
|
197
408
|
constructor() {
|
|
198
409
|
MockPopup.instances.push(this);
|
|
@@ -215,13 +426,15 @@ export class MockPopup {
|
|
|
215
426
|
return this;
|
|
216
427
|
}
|
|
217
428
|
addTo() {
|
|
429
|
+
this.open = true;
|
|
218
430
|
return this;
|
|
219
431
|
}
|
|
220
432
|
remove() {
|
|
433
|
+
this.open = false;
|
|
221
434
|
return this;
|
|
222
435
|
}
|
|
223
436
|
isOpen() {
|
|
224
|
-
return
|
|
437
|
+
return this.open;
|
|
225
438
|
}
|
|
226
439
|
on() {
|
|
227
440
|
return this;
|
|
@@ -231,19 +444,53 @@ export class MockPopup {
|
|
|
231
444
|
}
|
|
232
445
|
}
|
|
233
446
|
|
|
447
|
+
/**
|
|
448
|
+
* The real Web Mercator transform, so a plan coordinate system behaves under
|
|
449
|
+
* test exactly as it does in a browser.
|
|
450
|
+
*/
|
|
451
|
+
export class MockMercatorCoordinate {
|
|
452
|
+
constructor(
|
|
453
|
+
public x: number,
|
|
454
|
+
public y: number,
|
|
455
|
+
public z = 0,
|
|
456
|
+
) {}
|
|
457
|
+
|
|
458
|
+
static fromLngLat(lngLat: { lng: number; lat: number } | [number, number], altitude = 0) {
|
|
459
|
+
const [lng, lat] = Array.isArray(lngLat) ? lngLat : [lngLat.lng, lngLat.lat];
|
|
460
|
+
const x = (180 + lng) / 360;
|
|
461
|
+
const y =
|
|
462
|
+
(180 - (180 / Math.PI) * Math.log(Math.tan(Math.PI / 4 + (lat * Math.PI) / 360))) / 360;
|
|
463
|
+
return new MockMercatorCoordinate(x, y, altitude);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
toLngLat() {
|
|
467
|
+
const lng = this.x * 360 - 180;
|
|
468
|
+
const y2 = 180 - this.y * 360;
|
|
469
|
+
const lat = (360 / Math.PI) * (Math.atan(Math.exp((y2 * Math.PI) / 180)) - Math.PI / 4);
|
|
470
|
+
return { lng, lat };
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
234
474
|
/** Reset the per-class instance registries between tests. */
|
|
235
475
|
export function resetMaplibreMock() {
|
|
236
476
|
MockMap.instances = [];
|
|
237
477
|
MockMarker.instances = [];
|
|
238
478
|
MockPopup.instances = [];
|
|
479
|
+
MockSource.instances = [];
|
|
239
480
|
}
|
|
240
481
|
|
|
241
482
|
/** The module shape to return from `vi.mock("maplibre-gl", ...)`. */
|
|
242
483
|
export function createMaplibreMock() {
|
|
243
484
|
return {
|
|
244
|
-
default: {
|
|
485
|
+
default: {
|
|
486
|
+
Map: MockMap,
|
|
487
|
+
Marker: MockMarker,
|
|
488
|
+
Popup: MockPopup,
|
|
489
|
+
MercatorCoordinate: MockMercatorCoordinate,
|
|
490
|
+
},
|
|
245
491
|
Map: MockMap,
|
|
246
492
|
Marker: MockMarker,
|
|
247
493
|
Popup: MockPopup,
|
|
494
|
+
MercatorCoordinate: MockMercatorCoordinate,
|
|
248
495
|
};
|
|
249
496
|
}
|