@mailwoman/react 7.4.0 → 7.6.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/common/PresetChips.tsx +4 -1
- package/index.ts +31 -0
- package/map/BackendControl.tsx +39 -0
- package/map/CompareToggle.tsx +81 -0
- package/map/DemoControls.tsx +173 -0
- package/map/DemoMap.tsx +98 -0
- package/map/GeocoderDemo.tsx +178 -0
- package/map/OverlayLayers.tsx +46 -0
- package/map/PlaceAutocomplete.tsx +69 -0
- package/map/PlaceMarker.tsx +40 -0
- package/map/ResolvedPlaceLayers.tsx +63 -0
- package/map/ResultCamera.tsx +60 -0
- package/map/ResultOverlay.tsx +61 -0
- package/map/ResultPanel.tsx +84 -0
- package/map/VersionPicker.tsx +62 -0
- package/map/geometry.ts +135 -0
- package/map/index.ts +73 -0
- package/map/place-render.ts +157 -0
- package/map/types.ts +207 -0
- package/map/useCompareState.ts +45 -0
- package/map/useDemoGeocode.ts +67 -0
- package/map/useMapPlaceRender.ts +21 -0
- package/map/usePlaceAutocomplete.ts +195 -0
- package/out/common/PresetChips.d.ts +3 -1
- package/out/common/PresetChips.d.ts.map +1 -1
- package/out/common/PresetChips.js +2 -2
- package/out/common/PresetChips.js.map +1 -1
- package/out/index.d.ts +4 -1
- package/out/index.d.ts.map +1 -1
- package/out/index.js +2 -0
- package/out/index.js.map +1 -1
- package/out/map/BackendControl.d.ts +24 -0
- package/out/map/BackendControl.d.ts.map +1 -0
- package/out/map/BackendControl.js +6 -0
- package/out/map/BackendControl.js.map +1 -0
- package/out/map/CompareToggle.d.ts +35 -0
- package/out/map/CompareToggle.d.ts.map +1 -0
- package/out/map/CompareToggle.js +9 -0
- package/out/map/CompareToggle.js.map +1 -0
- package/out/map/DemoControls.d.ts +44 -0
- package/out/map/DemoControls.d.ts.map +1 -0
- package/out/map/DemoControls.js +28 -0
- package/out/map/DemoControls.js.map +1 -0
- package/out/map/DemoMap.d.ts +59 -0
- package/out/map/DemoMap.d.ts.map +1 -0
- package/out/map/DemoMap.js +12 -0
- package/out/map/DemoMap.js.map +1 -0
- package/out/map/GeocoderDemo.d.ts +47 -0
- package/out/map/GeocoderDemo.d.ts.map +1 -0
- package/out/map/GeocoderDemo.js +73 -0
- package/out/map/GeocoderDemo.js.map +1 -0
- package/out/map/OverlayLayers.d.ts +23 -0
- package/out/map/OverlayLayers.d.ts.map +1 -0
- package/out/map/OverlayLayers.js +27 -0
- package/out/map/OverlayLayers.js.map +1 -0
- package/out/map/PlaceAutocomplete.d.ts +34 -0
- package/out/map/PlaceAutocomplete.d.ts.map +1 -0
- package/out/map/PlaceAutocomplete.js +9 -0
- package/out/map/PlaceAutocomplete.js.map +1 -0
- package/out/map/PlaceMarker.d.ts +27 -0
- package/out/map/PlaceMarker.d.ts.map +1 -0
- package/out/map/PlaceMarker.js +9 -0
- package/out/map/PlaceMarker.js.map +1 -0
- package/out/map/ResolvedPlaceLayers.d.ts +34 -0
- package/out/map/ResolvedPlaceLayers.d.ts.map +1 -0
- package/out/map/ResolvedPlaceLayers.js +11 -0
- package/out/map/ResolvedPlaceLayers.js.map +1 -0
- package/out/map/ResultCamera.d.ts +34 -0
- package/out/map/ResultCamera.d.ts.map +1 -0
- package/out/map/ResultCamera.js +43 -0
- package/out/map/ResultCamera.js.map +1 -0
- package/out/map/ResultOverlay.d.ts +34 -0
- package/out/map/ResultOverlay.d.ts.map +1 -0
- package/out/map/ResultOverlay.js +18 -0
- package/out/map/ResultOverlay.js.map +1 -0
- package/out/map/ResultPanel.d.ts +34 -0
- package/out/map/ResultPanel.d.ts.map +1 -0
- package/out/map/ResultPanel.js +12 -0
- package/out/map/ResultPanel.js.map +1 -0
- package/out/map/VersionPicker.d.ts +30 -0
- package/out/map/VersionPicker.d.ts.map +1 -0
- package/out/map/VersionPicker.js +8 -0
- package/out/map/VersionPicker.js.map +1 -0
- package/out/map/geometry.d.ts +55 -0
- package/out/map/geometry.d.ts.map +1 -0
- package/out/map/geometry.js +99 -0
- package/out/map/geometry.js.map +1 -0
- package/out/map/index.d.ts +52 -0
- package/out/map/index.d.ts.map +1 -0
- package/out/map/index.js +36 -0
- package/out/map/index.js.map +1 -0
- package/out/map/place-render.d.ts +85 -0
- package/out/map/place-render.d.ts.map +1 -0
- package/out/map/place-render.js +98 -0
- package/out/map/place-render.js.map +1 -0
- package/out/map/types.d.ts +193 -0
- package/out/map/types.d.ts.map +1 -0
- package/out/map/types.js +18 -0
- package/out/map/types.js.map +1 -0
- package/out/map/useCompareState.d.ts +25 -0
- package/out/map/useCompareState.d.ts.map +1 -0
- package/out/map/useCompareState.js +27 -0
- package/out/map/useCompareState.js.map +1 -0
- package/out/map/useDemoGeocode.d.ts +36 -0
- package/out/map/useDemoGeocode.d.ts.map +1 -0
- package/out/map/useDemoGeocode.js +44 -0
- package/out/map/useDemoGeocode.js.map +1 -0
- package/out/map/useMapPlaceRender.d.ts +15 -0
- package/out/map/useMapPlaceRender.d.ts.map +1 -0
- package/out/map/useMapPlaceRender.js +18 -0
- package/out/map/useMapPlaceRender.js.map +1 -0
- package/out/map/usePlaceAutocomplete.d.ts +61 -0
- package/out/map/usePlaceAutocomplete.d.ts.map +1 -0
- package/out/map/usePlaceAutocomplete.js +122 -0
- package/out/map/usePlaceAutocomplete.js.map +1 -0
- package/out/pipeline/QueryForm.d.ts +6 -2
- package/out/pipeline/QueryForm.d.ts.map +1 -1
- package/out/pipeline/QueryForm.js +2 -2
- package/out/pipeline/QueryForm.js.map +1 -1
- package/out/poi/LiveResultsBlock.d.ts +3 -3
- package/out/poi/LiveResultsBlock.d.ts.map +1 -1
- package/out/poi/LiveResultsBlock.js +2 -2
- package/out/poi/LiveResultsBlock.js.map +1 -1
- package/out/poi/POIExplorer.d.ts +7 -1
- package/out/poi/POIExplorer.d.ts.map +1 -1
- package/out/poi/POIExplorer.js +17 -5
- package/out/poi/POIExplorer.js.map +1 -1
- package/out/poi/SubjectPanel.d.ts +3 -2
- package/out/poi/SubjectPanel.d.ts.map +1 -1
- package/out/poi/SubjectPanel.js +8 -1
- package/out/poi/SubjectPanel.js.map +1 -1
- package/out/poi/runtime.d.ts +13 -4
- package/out/poi/runtime.d.ts.map +1 -1
- package/out/poi/runtime.js +36 -12
- package/out/poi/runtime.js.map +1 -1
- package/out/poi/types.d.ts +31 -4
- package/out/poi/types.d.ts.map +1 -1
- package/out/poi/usePOISearch.d.ts +8 -1
- package/out/poi/usePOISearch.d.ts.map +1 -1
- package/out/poi/usePOISearch.js +47 -12
- package/out/poi/usePOISearch.js.map +1 -1
- package/out/runtime/useDemoRuntime.d.ts +113 -0
- package/out/runtime/useDemoRuntime.d.ts.map +1 -0
- package/out/runtime/useDemoRuntime.js +135 -0
- package/out/runtime/useDemoRuntime.js.map +1 -0
- package/package.json +31 -10
- package/pipeline/QueryForm.tsx +17 -2
- package/poi/LiveResultsBlock.tsx +4 -4
- package/poi/POIExplorer.tsx +39 -8
- package/poi/SubjectPanel.tsx +47 -12
- package/poi/runtime.ts +35 -10
- package/poi/types.ts +34 -4
- package/poi/usePOISearch.ts +62 -11
- package/runtime/useDemoRuntime.ts +245 -0
- package/styles.css +166 -0
- package/vitest.node.config.ts +20 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* Pure map geometry for the geocoder demo — the resolved-place outline math, lifted verbatim from the
|
|
7
|
+
* docs demo's `_map-helpers.ts`. Zero imports: no React, no `react-map-gl`, no `maplibre-gl`, no DOM.
|
|
8
|
+
* Every function takes plain numbers and returns plain GeoJSON, so the whole module runs (and is
|
|
9
|
+
* tested) under bare node — see `geometry.node.test.ts`.
|
|
10
|
+
*
|
|
11
|
+
* WHY NOT `@mailwoman/spatial`: the only truly-spatial primitive here is the bbox half-diagonal (a
|
|
12
|
+
* great-circle-ish distance). `@mailwoman/spatial` exposes `haversineKm`, but ONLY via its root barrel,
|
|
13
|
+
* which pulls `@mailwoman/core` + `h3-js` + `wkx` — a heavy, partly node-only graph — into what must
|
|
14
|
+
* stay a lightweight, browser-only map bundle (the `@mailwoman/react/map` subpath). The original
|
|
15
|
+
* `_map-helpers.ts` made the same call: a planar `kmPerDeg` approximation, local, no dependency. We
|
|
16
|
+
* preserve it so the ported behavior is byte-identical and the browser graph stays clean.
|
|
17
|
+
*/
|
|
18
|
+
/** A GeoJSON Polygon / MultiPolygon — what the polygon DB stores and the map draws as the place outline. */
|
|
19
|
+
export type PlaceGeometry = {
|
|
20
|
+
type: "Polygon";
|
|
21
|
+
coordinates: number[][][];
|
|
22
|
+
} | {
|
|
23
|
+
type: "MultiPolygon";
|
|
24
|
+
coordinates: number[][][][];
|
|
25
|
+
};
|
|
26
|
+
/** A place bounding box in the demo's object form (the WOF points DB carries only these four numbers). */
|
|
27
|
+
export interface PlaceBBox {
|
|
28
|
+
minLat: number;
|
|
29
|
+
maxLat: number;
|
|
30
|
+
minLon: number;
|
|
31
|
+
maxLon: number;
|
|
32
|
+
}
|
|
33
|
+
/** A `[west, south, east, north]` → `[[minLon, minLat], [maxLon, maxLat]]` pair, the shape `fitBounds` wants. */
|
|
34
|
+
export type BoundsTuple = [[number, number], [number, number]];
|
|
35
|
+
/**
|
|
36
|
+
* Approximate-extent circle for places without a crisp polygon: centered on the place point, radius from the bbox
|
|
37
|
+
* half-diagonal (clamped 0.5–50 km). 64-point ring with latitude correction — visually a circle anywhere outside the
|
|
38
|
+
* poles. With no bbox (anchor-centroid postcodes carry no extent) it defaults to a ~ZIP-sized 3 km radius.
|
|
39
|
+
*/
|
|
40
|
+
export declare function approxCircleGeometry(lat: number, lon: number, bbox?: PlaceBBox): PlaceGeometry;
|
|
41
|
+
/**
|
|
42
|
+
* A circle of an EXACT radius in meters — for the street-level uncertainty (#377): a 10 m situs floor or a calibrated
|
|
43
|
+
* interp radius. Unlike {@link approxCircleGeometry} (clamped to a ~ZIP-sized 0.5 km floor for admin fallbacks), this
|
|
44
|
+
* honors small radii so an exact building reads as a tight dot (an ~8 m floor keeps a 10 m situs circle visible).
|
|
45
|
+
*/
|
|
46
|
+
export declare function radiusCircleGeometry(lat: number, lon: number, radiusM: number): PlaceGeometry;
|
|
47
|
+
/**
|
|
48
|
+
* Bounding box of a Polygon / MultiPolygon, for `fitBounds`. Walks the nested coordinate arrays, so it handles both a
|
|
49
|
+
* single-ring polygon and a multi-part polygon uniformly. Antimeridian-crossing geometry is NOT normalized (the naive
|
|
50
|
+
* min/max is returned) — matching the ported behavior; callers that need a wrapped bbox must handle it upstream.
|
|
51
|
+
*/
|
|
52
|
+
export declare function geomBounds(geometry: PlaceGeometry): PlaceBBox;
|
|
53
|
+
/** Reshape a {@link PlaceBBox} into the `[[minLon, minLat], [maxLon, maxLat]]` pair `fitBounds` expects. */
|
|
54
|
+
export declare function bboxToBounds(bbox: PlaceBBox): BoundsTuple;
|
|
55
|
+
//# sourceMappingURL=geometry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"geometry.d.ts","sourceRoot":"","sources":["../../map/geometry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAKH,4GAA4G;AAC5G,MAAM,MAAM,aAAa,GACtB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,CAAA;CAAE,GAC9C;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,CAAA;CAAE,CAAA;AAExD,0GAA0G;AAC1G,MAAM,WAAW,SAAS;IACzB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;CACd;AAED,iHAAiH;AACjH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;AAqB9D;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,SAAS,GAAG,aAAa,CAO9F;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,aAAa,CAI7F;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,aAAa,GAAG,SAAS,CAwC7D;AAED,4GAA4G;AAC5G,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,GAAG,WAAW,CAKzD"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* Pure map geometry for the geocoder demo — the resolved-place outline math, lifted verbatim from the
|
|
7
|
+
* docs demo's `_map-helpers.ts`. Zero imports: no React, no `react-map-gl`, no `maplibre-gl`, no DOM.
|
|
8
|
+
* Every function takes plain numbers and returns plain GeoJSON, so the whole module runs (and is
|
|
9
|
+
* tested) under bare node — see `geometry.node.test.ts`.
|
|
10
|
+
*
|
|
11
|
+
* WHY NOT `@mailwoman/spatial`: the only truly-spatial primitive here is the bbox half-diagonal (a
|
|
12
|
+
* great-circle-ish distance). `@mailwoman/spatial` exposes `haversineKm`, but ONLY via its root barrel,
|
|
13
|
+
* which pulls `@mailwoman/core` + `h3-js` + `wkx` — a heavy, partly node-only graph — into what must
|
|
14
|
+
* stay a lightweight, browser-only map bundle (the `@mailwoman/react/map` subpath). The original
|
|
15
|
+
* `_map-helpers.ts` made the same call: a planar `kmPerDeg` approximation, local, no dependency. We
|
|
16
|
+
* preserve it so the ported behavior is byte-identical and the browser graph stays clean.
|
|
17
|
+
*/
|
|
18
|
+
/** Mean km per degree of latitude (WGS84 average). */
|
|
19
|
+
const KM_PER_DEG_LAT = 111.32;
|
|
20
|
+
/** Km per degree of longitude at a given latitude — the meridians converge toward the poles. */
|
|
21
|
+
function kmPerDegLon(lat) {
|
|
22
|
+
return KM_PER_DEG_LAT * Math.cos((lat * Math.PI) / 180);
|
|
23
|
+
}
|
|
24
|
+
/** A closed 64-segment (65-point) GeoJSON ring of `radiusKm` around `[lon, lat]`, with latitude correction. */
|
|
25
|
+
function circleRing(lat, lon, radiusKm) {
|
|
26
|
+
const perLon = kmPerDegLon(lat);
|
|
27
|
+
const ring = [];
|
|
28
|
+
for (let i = 0; i <= 64; i++) {
|
|
29
|
+
const theta = (2 * Math.PI * i) / 64;
|
|
30
|
+
ring.push([lon + (radiusKm * Math.cos(theta)) / perLon, lat + (radiusKm * Math.sin(theta)) / KM_PER_DEG_LAT]);
|
|
31
|
+
}
|
|
32
|
+
return ring;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Approximate-extent circle for places without a crisp polygon: centered on the place point, radius from the bbox
|
|
36
|
+
* half-diagonal (clamped 0.5–50 km). 64-point ring with latitude correction — visually a circle anywhere outside the
|
|
37
|
+
* poles. With no bbox (anchor-centroid postcodes carry no extent) it defaults to a ~ZIP-sized 3 km radius.
|
|
38
|
+
*/
|
|
39
|
+
export function approxCircleGeometry(lat, lon, bbox) {
|
|
40
|
+
const halfDiagKm = bbox
|
|
41
|
+
? Math.hypot((bbox.maxLat - bbox.minLat) * KM_PER_DEG_LAT, (bbox.maxLon - bbox.minLon) * kmPerDegLon(lat)) / 2
|
|
42
|
+
: 3;
|
|
43
|
+
const radiusKm = Math.min(50, Math.max(0.5, halfDiagKm));
|
|
44
|
+
return { type: "Polygon", coordinates: [circleRing(lat, lon, radiusKm)] };
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* A circle of an EXACT radius in meters — for the street-level uncertainty (#377): a 10 m situs floor or a calibrated
|
|
48
|
+
* interp radius. Unlike {@link approxCircleGeometry} (clamped to a ~ZIP-sized 0.5 km floor for admin fallbacks), this
|
|
49
|
+
* honors small radii so an exact building reads as a tight dot (an ~8 m floor keeps a 10 m situs circle visible).
|
|
50
|
+
*/
|
|
51
|
+
export function radiusCircleGeometry(lat, lon, radiusM) {
|
|
52
|
+
const radiusKm = Math.max(0.008, radiusM / 1000);
|
|
53
|
+
return { type: "Polygon", coordinates: [circleRing(lat, lon, radiusKm)] };
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Bounding box of a Polygon / MultiPolygon, for `fitBounds`. Walks the nested coordinate arrays, so it handles both a
|
|
57
|
+
* single-ring polygon and a multi-part polygon uniformly. Antimeridian-crossing geometry is NOT normalized (the naive
|
|
58
|
+
* min/max is returned) — matching the ported behavior; callers that need a wrapped bbox must handle it upstream.
|
|
59
|
+
*/
|
|
60
|
+
export function geomBounds(geometry) {
|
|
61
|
+
let minLon = Infinity;
|
|
62
|
+
let minLat = Infinity;
|
|
63
|
+
let maxLon = -Infinity;
|
|
64
|
+
let maxLat = -Infinity;
|
|
65
|
+
const visit = (node) => {
|
|
66
|
+
if (Array.isArray(node) && typeof node[0] === "number" && typeof node[1] === "number") {
|
|
67
|
+
const lon = node[0];
|
|
68
|
+
const lat = node[1];
|
|
69
|
+
if (lon < minLon) {
|
|
70
|
+
minLon = lon;
|
|
71
|
+
}
|
|
72
|
+
if (lon > maxLon) {
|
|
73
|
+
maxLon = lon;
|
|
74
|
+
}
|
|
75
|
+
if (lat < minLat) {
|
|
76
|
+
minLat = lat;
|
|
77
|
+
}
|
|
78
|
+
if (lat > maxLat) {
|
|
79
|
+
maxLat = lat;
|
|
80
|
+
}
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
if (Array.isArray(node)) {
|
|
84
|
+
for (const child of node) {
|
|
85
|
+
visit(child);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
visit(geometry.coordinates);
|
|
90
|
+
return { minLon, minLat, maxLon, maxLat };
|
|
91
|
+
}
|
|
92
|
+
/** Reshape a {@link PlaceBBox} into the `[[minLon, minLat], [maxLon, maxLat]]` pair `fitBounds` expects. */
|
|
93
|
+
export function bboxToBounds(bbox) {
|
|
94
|
+
return [
|
|
95
|
+
[bbox.minLon, bbox.minLat],
|
|
96
|
+
[bbox.maxLon, bbox.maxLat],
|
|
97
|
+
];
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=geometry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"geometry.js","sourceRoot":"","sources":["../../map/geometry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* `@mailwoman/react/map` — the geocoder-demo map surface, kept behind its OWN subpath so `maplibre-gl`
|
|
7
|
+
* / `react-map-gl` (WebGL + DOM at import) never enter the package-root graph. Importing this subpath
|
|
8
|
+
* pulls the map deps; importing `@mailwoman/react` (root) does not. Consumers who only want the
|
|
9
|
+
* parse/POI explorers never pay for maplibre.
|
|
10
|
+
*
|
|
11
|
+
* The host must supply `maplibre-gl` + `react-map-gl` (peer deps) and import
|
|
12
|
+
* `maplibre-gl/dist/maplibre-gl.css` + `@mailwoman/react/styles.css` itself.
|
|
13
|
+
*/
|
|
14
|
+
export { DemoMap } from "./DemoMap.tsx";
|
|
15
|
+
export type { DemoMapExtraProps, DemoMapProps, DemoMapStyle } from "./DemoMap.tsx";
|
|
16
|
+
export type { DemoBackend, DemoCompareContext, DemoPanels, DemoResultContext, DemoRuntime, DemoVersionOption, LngLatTuple, MapBias, OverlaySpec, Suggestion, } from "./types.ts";
|
|
17
|
+
export { approxCircleGeometry, bboxToBounds, geomBounds, radiusCircleGeometry } from "./geometry.ts";
|
|
18
|
+
export type { BoundsTuple, PlaceBBox, PlaceGeometry } from "./geometry.ts";
|
|
19
|
+
export { cameraToViewState, computeMapPlaceRenderSpec } from "./place-render.ts";
|
|
20
|
+
export type { LngLat, MapCameraTarget, MapPlaceRenderSpec, PlaceTier, ResolvedMapPlace } from "./place-render.ts";
|
|
21
|
+
export { useMapPlaceRender } from "./useMapPlaceRender.ts";
|
|
22
|
+
export { OverlayLayers } from "./OverlayLayers.tsx";
|
|
23
|
+
export type { OverlayLayersProps } from "./OverlayLayers.tsx";
|
|
24
|
+
export { PlaceMarker } from "./PlaceMarker.tsx";
|
|
25
|
+
export type { PlaceMarkerProps } from "./PlaceMarker.tsx";
|
|
26
|
+
export { ResolvedPlaceLayers } from "./ResolvedPlaceLayers.tsx";
|
|
27
|
+
export type { ResolvedPlaceLayersProps } from "./ResolvedPlaceLayers.tsx";
|
|
28
|
+
export { ResultCamera } from "./ResultCamera.tsx";
|
|
29
|
+
export type { ResultCameraProps } from "./ResultCamera.tsx";
|
|
30
|
+
export { ResultOverlay } from "./ResultOverlay.tsx";
|
|
31
|
+
export type { ResultOverlayProps } from "./ResultOverlay.tsx";
|
|
32
|
+
export { BackendControl } from "./BackendControl.tsx";
|
|
33
|
+
export type { BackendControlProps } from "./BackendControl.tsx";
|
|
34
|
+
export { CompareToggle } from "./CompareToggle.tsx";
|
|
35
|
+
export type { CompareToggleProps } from "./CompareToggle.tsx";
|
|
36
|
+
export { DemoControls } from "./DemoControls.tsx";
|
|
37
|
+
export type { DemoControlsProps } from "./DemoControls.tsx";
|
|
38
|
+
export { GeocoderDemo } from "./GeocoderDemo.tsx";
|
|
39
|
+
export type { GeocoderDemoProps } from "./GeocoderDemo.tsx";
|
|
40
|
+
export { PlaceAutocomplete } from "./PlaceAutocomplete.tsx";
|
|
41
|
+
export type { PlaceAutocompleteProps } from "./PlaceAutocomplete.tsx";
|
|
42
|
+
export { ResultPanel } from "./ResultPanel.tsx";
|
|
43
|
+
export type { ResultPanelProps } from "./ResultPanel.tsx";
|
|
44
|
+
export { useCompareState } from "./useCompareState.ts";
|
|
45
|
+
export type { UseCompareState } from "./useCompareState.ts";
|
|
46
|
+
export { useDemoGeocode } from "./useDemoGeocode.ts";
|
|
47
|
+
export type { UseDemoGeocode, UseDemoGeocodeOptions } from "./useDemoGeocode.ts";
|
|
48
|
+
export { usePlaceAutocomplete } from "./usePlaceAutocomplete.ts";
|
|
49
|
+
export type { AutocompleteInputProps, UsePlaceAutocomplete, UsePlaceAutocompleteOptions, } from "./usePlaceAutocomplete.ts";
|
|
50
|
+
export { VersionPicker } from "./VersionPicker.tsx";
|
|
51
|
+
export type { VersionPickerProps } from "./VersionPicker.tsx";
|
|
52
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../map/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AACvC,YAAY,EAAE,iBAAiB,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAClF,YAAY,EACX,WAAW,EACX,kBAAkB,EAClB,UAAU,EACV,iBAAiB,EACjB,WAAW,EACX,iBAAiB,EACjB,WAAW,EACX,OAAO,EACP,WAAW,EACX,UAAU,GACV,MAAM,YAAY,CAAA;AAGnB,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAA;AACpG,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAC1E,OAAO,EAAE,iBAAiB,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAA;AAChF,YAAY,EAAE,MAAM,EAAE,eAAe,EAAE,kBAAkB,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AACjH,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAG1D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,YAAY,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAA;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAA;AAC/D,YAAY,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAA;AACzE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,YAAY,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,YAAY,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAA;AAG7D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AACrD,YAAY,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAA;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,YAAY,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAA;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,YAAY,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,YAAY,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAC3D,YAAY,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAA;AACrE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AACtD,YAAY,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AACpD,YAAY,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAChF,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAA;AAChE,YAAY,EACX,sBAAsB,EACtB,oBAAoB,EACpB,2BAA2B,GAC3B,MAAM,2BAA2B,CAAA;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,YAAY,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAA"}
|
package/out/map/index.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* `@mailwoman/react/map` — the geocoder-demo map surface, kept behind its OWN subpath so `maplibre-gl`
|
|
7
|
+
* / `react-map-gl` (WebGL + DOM at import) never enter the package-root graph. Importing this subpath
|
|
8
|
+
* pulls the map deps; importing `@mailwoman/react` (root) does not. Consumers who only want the
|
|
9
|
+
* parse/POI explorers never pay for maplibre.
|
|
10
|
+
*
|
|
11
|
+
* The host must supply `maplibre-gl` + `react-map-gl` (peer deps) and import
|
|
12
|
+
* `maplibre-gl/dist/maplibre-gl.css` + `@mailwoman/react/styles.css` itself.
|
|
13
|
+
*/
|
|
14
|
+
export { DemoMap } from "./DemoMap.js";
|
|
15
|
+
// ── Pure geometry + render spec (node-safe; no react-map-gl at runtime) ──────
|
|
16
|
+
export { approxCircleGeometry, bboxToBounds, geomBounds, radiusCircleGeometry } from "./geometry.js";
|
|
17
|
+
export { cameraToViewState, computeMapPlaceRenderSpec } from "./place-render.js";
|
|
18
|
+
export { useMapPlaceRender } from "./useMapPlaceRender.js";
|
|
19
|
+
// ── Declarative overlays (react-map-gl `<Marker>`/`<Source>`/`<Layer>`) ──────
|
|
20
|
+
export { OverlayLayers } from "./OverlayLayers.js";
|
|
21
|
+
export { PlaceMarker } from "./PlaceMarker.js";
|
|
22
|
+
export { ResolvedPlaceLayers } from "./ResolvedPlaceLayers.js";
|
|
23
|
+
export { ResultCamera } from "./ResultCamera.js";
|
|
24
|
+
export { ResultOverlay } from "./ResultOverlay.js";
|
|
25
|
+
// ── Demo controls + composed demo (phase 4) ─────────────────────────────────
|
|
26
|
+
export { BackendControl } from "./BackendControl.js";
|
|
27
|
+
export { CompareToggle } from "./CompareToggle.js";
|
|
28
|
+
export { DemoControls } from "./DemoControls.js";
|
|
29
|
+
export { GeocoderDemo } from "./GeocoderDemo.js";
|
|
30
|
+
export { PlaceAutocomplete } from "./PlaceAutocomplete.js";
|
|
31
|
+
export { ResultPanel } from "./ResultPanel.js";
|
|
32
|
+
export { useCompareState } from "./useCompareState.js";
|
|
33
|
+
export { useDemoGeocode } from "./useDemoGeocode.js";
|
|
34
|
+
export { usePlaceAutocomplete } from "./usePlaceAutocomplete.js";
|
|
35
|
+
export { VersionPicker } from "./VersionPicker.js";
|
|
36
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../map/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,cAAe,CAAA;AAevC,gFAAgF;AAChF,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAA;AAEpG,OAAO,EAAE,iBAAiB,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAA;AAEhF,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAE1D,gFAAgF;AAChF,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAqB,CAAA;AAEnD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAmB,CAAA;AAE/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA2B,CAAA;AAE/D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAoB,CAAA;AAEjD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAqB,CAAA;AAGnD,+EAA+E;AAC/E,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAsB,CAAA;AAErD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAqB,CAAA;AAEnD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAoB,CAAA;AAEjD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAoB,CAAA;AAEjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAyB,CAAA;AAE3D,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAmB,CAAA;AAE/C,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAEtD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAEpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAA;AAMhE,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAqB,CAAA"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* `computeMapPlaceRenderSpec` — the PURE core that replaces the docs demo's ~100-line imperative
|
|
7
|
+
* marker/bbox/camera redraw effect (`_app.tsx:601-705`). It takes an ALREADY-RESOLVED place (the async
|
|
8
|
+
* polygon-DB fetch is a host/runtime concern — a later phase — so a crisp polygon arrives pre-fetched
|
|
9
|
+
* as `place.geometry`) and returns a declarative render spec: the marker position(s), the outline
|
|
10
|
+
* geometry to draw, and the camera target. No map instance, no DOM, no `react-map-gl` — so it is
|
|
11
|
+
* node-testable (see `place-render.node.test.ts`). The declarative components in this folder render
|
|
12
|
+
* the spec; a controlled-viewport consumer applies the camera.
|
|
13
|
+
*
|
|
14
|
+
* The decision cascade is a faithful, side-effect-free transcription of the imperative effect:
|
|
15
|
+
* 1. street tier (situs / interp) → exact-radius circle, fly to a tight zoom
|
|
16
|
+
* 2. crisp admin polygon (pre-fetched) → draw the polygon, fit its bounds
|
|
17
|
+
* 3. anchor-centroid postcode (no bbox) → ~3 km "around here" circle, fly to zoom 11
|
|
18
|
+
* 4. bbox with real extent → bbox-sized approximate circle, fit the bbox
|
|
19
|
+
* 5. bare point → no outline, fly to zoom 12
|
|
20
|
+
*/
|
|
21
|
+
import type { ResolvedPlaceView } from "../pipeline/types.ts";
|
|
22
|
+
import type { BoundsTuple, PlaceBBox, PlaceGeometry } from "./geometry.ts";
|
|
23
|
+
/** `[longitude, latitude]`. */
|
|
24
|
+
export type LngLat = [number, number];
|
|
25
|
+
/** The street-level resolution tier (#377): `address_point` = exact building; `interpolated` = TIGER estimate. */
|
|
26
|
+
export type PlaceTier = "address_point" | "interpolated";
|
|
27
|
+
/**
|
|
28
|
+
* The resolved-place shape the map render consumes — the pipeline {@link ResolvedPlaceView} plus the map-only extras the
|
|
29
|
+
* demo's `ResolvedHit` carries (bbox, street tier + uncertainty), and an optional PRE-FETCHED crisp polygon. Extending
|
|
30
|
+
* `ResolvedPlaceView` keeps the map render aligned with the shared parse result; the extras are additive.
|
|
31
|
+
*/
|
|
32
|
+
export interface ResolvedMapPlace extends ResolvedPlaceView {
|
|
33
|
+
/** The place's bounding box, when the gazetteer carries one (admin places). Absent for anchor-centroid postcodes. */
|
|
34
|
+
bbox?: PlaceBBox;
|
|
35
|
+
/** Street-level tier, when this hit came from the situs/interp tier rather than the WOF admin cascade. */
|
|
36
|
+
tier?: PlaceTier;
|
|
37
|
+
/** Honest uncertainty radius in meters for a street-level tier (10 m situs floor; calibrated interp). */
|
|
38
|
+
uncertaintyM?: number;
|
|
39
|
+
/**
|
|
40
|
+
* The crisp admin polygon, when the host has ALREADY fetched it from the sibling polygon DB. Its presence drives the
|
|
41
|
+
* polygon path; the async fetch itself stays out of this pure function (a runtime concern in a later phase).
|
|
42
|
+
*/
|
|
43
|
+
geometry?: PlaceGeometry;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* The camera target the render computes. `center` (fly to a point at a zoom) HAS a declarative equivalent — a consumer
|
|
47
|
+
* can feed it to a controlled `viewState` (see {@link cameraToViewState}). `bounds` (fit a box with pixel padding) does
|
|
48
|
+
* NOT — `fitBounds` needs the map's pixel dimensions, so it is applied imperatively by `<ResultCamera>`.
|
|
49
|
+
*/
|
|
50
|
+
export type MapCameraTarget = {
|
|
51
|
+
kind: "center";
|
|
52
|
+
center: LngLat;
|
|
53
|
+
zoom: number;
|
|
54
|
+
} | {
|
|
55
|
+
kind: "bounds";
|
|
56
|
+
bounds: BoundsTuple;
|
|
57
|
+
padding: number;
|
|
58
|
+
};
|
|
59
|
+
/** The declarative render spec for one resolved place — the pure output of {@link computeMapPlaceRenderSpec}. */
|
|
60
|
+
export interface MapPlaceRenderSpec {
|
|
61
|
+
/** Marker position(s) as `[lon, lat]`. Single-element today; an array leaves room for multi-marker later. */
|
|
62
|
+
markers: LngLat[];
|
|
63
|
+
/** The outline geometry (polygon / circle) to draw, or `null` when the place renders as a bare point. */
|
|
64
|
+
outline: PlaceGeometry | null;
|
|
65
|
+
/** The camera target — animate or fit to this. */
|
|
66
|
+
camera: MapCameraTarget;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Map a resolved place to its declarative render spec. Pure — same input, same output, no side effects. The `place`
|
|
70
|
+
* arrives fully resolved (crisp polygon pre-fetched into `place.geometry` when available), so this is the honest
|
|
71
|
+
* inverse of the old redraw effect with the imperative map mutation and the async DB load removed.
|
|
72
|
+
*/
|
|
73
|
+
export declare function computeMapPlaceRenderSpec(place: ResolvedMapPlace): MapPlaceRenderSpec;
|
|
74
|
+
/**
|
|
75
|
+
* The DECLARATIVE camera path: reshape a `center` target into a `viewState` patch a controlled `<DemoMap viewState>`
|
|
76
|
+
* can apply directly (a hard jump, no animation). Returns `null` for a `bounds` target — fitting a box to the viewport
|
|
77
|
+
* needs the map's pixel dimensions, which only the live map has, so that case is applied imperatively by
|
|
78
|
+
* `<ResultCamera>`. Pure + node-testable.
|
|
79
|
+
*/
|
|
80
|
+
export declare function cameraToViewState(camera: MapCameraTarget): {
|
|
81
|
+
longitude: number;
|
|
82
|
+
latitude: number;
|
|
83
|
+
zoom: number;
|
|
84
|
+
} | null;
|
|
85
|
+
//# sourceMappingURL=place-render.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"place-render.d.ts","sourceRoot":"","sources":["../../map/place-render.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAE7D,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAE1E,+BAA+B;AAC/B,MAAM,MAAM,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;AAErC,kHAAkH;AAClH,MAAM,MAAM,SAAS,GAAG,eAAe,GAAG,cAAc,CAAA;AAExD;;;;GAIG;AACH,MAAM,WAAW,gBAAiB,SAAQ,iBAAiB;IAC1D,qHAAqH;IACrH,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,0GAA0G;IAC1G,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,yGAAyG;IACzG,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;;OAGG;IACH,QAAQ,CAAC,EAAE,aAAa,CAAA;CACxB;AAED;;;;GAIG;AACH,MAAM,MAAM,eAAe,GACxB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AAE3D,iHAAiH;AACjH,MAAM,WAAW,kBAAkB;IAClC,6GAA6G;IAC7G,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,yGAAyG;IACzG,OAAO,EAAE,aAAa,GAAG,IAAI,CAAA;IAC7B,kDAAkD;IAClD,MAAM,EAAE,eAAe,CAAA;CACvB;AAgBD;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,gBAAgB,GAAG,kBAAkB,CAsDrF;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAChC,MAAM,EAAE,eAAe,GACrB;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAI9D"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* `computeMapPlaceRenderSpec` — the PURE core that replaces the docs demo's ~100-line imperative
|
|
7
|
+
* marker/bbox/camera redraw effect (`_app.tsx:601-705`). It takes an ALREADY-RESOLVED place (the async
|
|
8
|
+
* polygon-DB fetch is a host/runtime concern — a later phase — so a crisp polygon arrives pre-fetched
|
|
9
|
+
* as `place.geometry`) and returns a declarative render spec: the marker position(s), the outline
|
|
10
|
+
* geometry to draw, and the camera target. No map instance, no DOM, no `react-map-gl` — so it is
|
|
11
|
+
* node-testable (see `place-render.node.test.ts`). The declarative components in this folder render
|
|
12
|
+
* the spec; a controlled-viewport consumer applies the camera.
|
|
13
|
+
*
|
|
14
|
+
* The decision cascade is a faithful, side-effect-free transcription of the imperative effect:
|
|
15
|
+
* 1. street tier (situs / interp) → exact-radius circle, fly to a tight zoom
|
|
16
|
+
* 2. crisp admin polygon (pre-fetched) → draw the polygon, fit its bounds
|
|
17
|
+
* 3. anchor-centroid postcode (no bbox) → ~3 km "around here" circle, fly to zoom 11
|
|
18
|
+
* 4. bbox with real extent → bbox-sized approximate circle, fit the bbox
|
|
19
|
+
* 5. bare point → no outline, fly to zoom 12
|
|
20
|
+
*/
|
|
21
|
+
import { approxCircleGeometry, bboxToBounds, geomBounds, radiusCircleGeometry } from "./geometry.js";
|
|
22
|
+
/** Zoom levels the imperative effect flew to, kept named so the cascade reads as intent, not magic numbers. */
|
|
23
|
+
const ZOOM = {
|
|
24
|
+
addressPoint: 17,
|
|
25
|
+
interpolated: 15,
|
|
26
|
+
postcode: 11,
|
|
27
|
+
point: 12,
|
|
28
|
+
};
|
|
29
|
+
/** Padding (px) `fitBounds` insets a fitted box by, matching the ported effect. */
|
|
30
|
+
const FIT_PADDING = 40;
|
|
31
|
+
/** The minimum lat/lon span (degrees) a bbox must exceed to be treated as a real extent rather than a point. */
|
|
32
|
+
const MIN_EXTENT_DEG = 0.001;
|
|
33
|
+
/**
|
|
34
|
+
* Map a resolved place to its declarative render spec. Pure — same input, same output, no side effects. The `place`
|
|
35
|
+
* arrives fully resolved (crisp polygon pre-fetched into `place.geometry` when available), so this is the honest
|
|
36
|
+
* inverse of the old redraw effect with the imperative map mutation and the async DB load removed.
|
|
37
|
+
*/
|
|
38
|
+
export function computeMapPlaceRenderSpec(place) {
|
|
39
|
+
const markers = [[place.lon, place.lat]];
|
|
40
|
+
// 1. Street tier (#377): the honest uncertainty circle (exact meter radius) + a tight zoom. Takes precedence over
|
|
41
|
+
// the admin polygon/bbox paths — a precise point gets no admin boundary.
|
|
42
|
+
if (place.tier && place.uncertaintyM != null) {
|
|
43
|
+
return {
|
|
44
|
+
markers,
|
|
45
|
+
outline: radiusCircleGeometry(place.lat, place.lon, place.uncertaintyM),
|
|
46
|
+
camera: {
|
|
47
|
+
kind: "center",
|
|
48
|
+
center: [place.lon, place.lat],
|
|
49
|
+
zoom: place.tier === "address_point" ? ZOOM.addressPoint : ZOOM.interpolated,
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
// 2. Crisp admin polygon (host pre-fetched it from the polygon DB) — draw the real boundary and fit it.
|
|
54
|
+
if (place.geometry) {
|
|
55
|
+
return {
|
|
56
|
+
markers,
|
|
57
|
+
outline: place.geometry,
|
|
58
|
+
camera: { kind: "bounds", bounds: bboxToBounds(geomBounds(place.geometry)), padding: FIT_PADDING },
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
// 3. Anchor-centroid postcode: no bbox, no polygon — a default ~3 km circle says "approximately here" without
|
|
62
|
+
// inventing a boundary.
|
|
63
|
+
if (!place.bbox && place.placetype === "postcode") {
|
|
64
|
+
return {
|
|
65
|
+
markers,
|
|
66
|
+
outline: approxCircleGeometry(place.lat, place.lon),
|
|
67
|
+
camera: { kind: "center", center: [place.lon, place.lat], zoom: ZOOM.postcode },
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
// 4. A bbox with real extent — draw an approximate CIRCLE sized from the bbox (a rectangle would read as a wrong,
|
|
71
|
+
// real boundary) and fit the bbox.
|
|
72
|
+
const bbox = place.bbox;
|
|
73
|
+
if (bbox && Math.max(bbox.maxLat - bbox.minLat, bbox.maxLon - bbox.minLon) > MIN_EXTENT_DEG) {
|
|
74
|
+
return {
|
|
75
|
+
markers,
|
|
76
|
+
outline: approxCircleGeometry(place.lat, place.lon, bbox),
|
|
77
|
+
camera: { kind: "bounds", bounds: bboxToBounds(bbox), padding: FIT_PADDING },
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
// 5. A bare point (no tier, no polygon, no meaningful bbox) — just a marker and a mid zoom.
|
|
81
|
+
return {
|
|
82
|
+
markers,
|
|
83
|
+
outline: null,
|
|
84
|
+
camera: { kind: "center", center: [place.lon, place.lat], zoom: ZOOM.point },
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* The DECLARATIVE camera path: reshape a `center` target into a `viewState` patch a controlled `<DemoMap viewState>`
|
|
89
|
+
* can apply directly (a hard jump, no animation). Returns `null` for a `bounds` target — fitting a box to the viewport
|
|
90
|
+
* needs the map's pixel dimensions, which only the live map has, so that case is applied imperatively by
|
|
91
|
+
* `<ResultCamera>`. Pure + node-testable.
|
|
92
|
+
*/
|
|
93
|
+
export function cameraToViewState(camera) {
|
|
94
|
+
if (camera.kind !== "center")
|
|
95
|
+
return null;
|
|
96
|
+
return { longitude: camera.center[0], latitude: camera.center[1], zoom: camera.zoom };
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=place-render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"place-render.js","sourceRoot":"","sources":["../../map/place-render.ts"],"names":[],"mappings":"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"}
|