@mailwoman/react 8.5.0 → 9.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/map/DemoControls.tsx +2 -2
- package/map/PlaceAutocomplete.tsx +8 -8
- package/map/ResolvedPlaceLayers.tsx +3 -3
- package/map/ResultCamera.tsx +21 -1
- package/map/usePlaceAutocomplete.ts +6 -6
- package/out/map/DemoControls.js +1 -1
- package/out/map/PlaceAutocomplete.d.ts +5 -5
- package/out/map/PlaceAutocomplete.js +2 -2
- package/out/map/ResolvedPlaceLayers.d.ts +2 -2
- package/out/map/ResolvedPlaceLayers.js +2 -2
- package/out/map/ResultCamera.d.ts +17 -0
- package/out/map/ResultCamera.d.ts.map +1 -1
- package/out/map/ResultCamera.js +19 -1
- package/out/map/ResultCamera.js.map +1 -1
- package/out/map/usePlaceAutocomplete.d.ts +2 -2
- package/out/map/usePlaceAutocomplete.js +4 -4
- package/package.json +11 -11
package/map/DemoControls.tsx
CHANGED
|
@@ -133,8 +133,8 @@ export function DemoControls({
|
|
|
133
133
|
activeIndex={autocomplete.activeIndex}
|
|
134
134
|
onPick={autocomplete.pick}
|
|
135
135
|
onHover={autocomplete.setActiveIndex}
|
|
136
|
-
|
|
137
|
-
|
|
136
|
+
listboxID={autocomplete.listboxID}
|
|
137
|
+
optionID={autocomplete.optionID}
|
|
138
138
|
/>
|
|
139
139
|
|
|
140
140
|
<PresetChips
|
|
@@ -35,13 +35,13 @@ export interface PlaceAutocompleteProps {
|
|
|
35
35
|
*/
|
|
36
36
|
onHover?: (index: number) => void
|
|
37
37
|
/**
|
|
38
|
-
* The listbox element id — pass `
|
|
38
|
+
* The listbox element id — pass `listboxID` from the hook (matches the input's `aria-controls`).
|
|
39
39
|
*/
|
|
40
|
-
|
|
40
|
+
listboxID: string
|
|
41
41
|
/**
|
|
42
|
-
* Build the option element id — pass `
|
|
42
|
+
* Build the option element id — pass `optionID` from the hook.
|
|
43
43
|
*/
|
|
44
|
-
|
|
44
|
+
optionID: (index: number) => string
|
|
45
45
|
/**
|
|
46
46
|
* Leading label. @default "Did you mean:"
|
|
47
47
|
*/
|
|
@@ -56,19 +56,19 @@ export function PlaceAutocomplete({
|
|
|
56
56
|
activeIndex,
|
|
57
57
|
onPick,
|
|
58
58
|
onHover,
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
listboxID,
|
|
60
|
+
optionID,
|
|
61
61
|
caption = "Did you mean:",
|
|
62
62
|
}: PlaceAutocompleteProps): ReactNode {
|
|
63
63
|
if (!suggestions.length) return null
|
|
64
64
|
|
|
65
65
|
return (
|
|
66
|
-
<div className="mw-demo-suggest" id={
|
|
66
|
+
<div className="mw-demo-suggest" id={listboxID} role="listbox" aria-label="Place suggestions">
|
|
67
67
|
<span className="mw-demo-suggest__label">{caption}</span>
|
|
68
68
|
{suggestions.map((s, i) => (
|
|
69
69
|
<button
|
|
70
70
|
key={`${s.value}-${i}`}
|
|
71
|
-
id={
|
|
71
|
+
id={optionID(i)}
|
|
72
72
|
type="button"
|
|
73
73
|
role="option"
|
|
74
74
|
aria-selected={i === activeIndex}
|
|
@@ -37,7 +37,7 @@ export interface ResolvedPlaceLayersProps {
|
|
|
37
37
|
/**
|
|
38
38
|
* Source/layer id prefix for the outline. @default "mw-result"
|
|
39
39
|
*/
|
|
40
|
-
|
|
40
|
+
outlineID?: string
|
|
41
41
|
/**
|
|
42
42
|
* Marker color. @default the house pink.
|
|
43
43
|
*/
|
|
@@ -51,7 +51,7 @@ export function ResolvedPlaceLayers({
|
|
|
51
51
|
spec,
|
|
52
52
|
applyCamera = true,
|
|
53
53
|
animateCamera = true,
|
|
54
|
-
|
|
54
|
+
outlineID,
|
|
55
55
|
markerColor,
|
|
56
56
|
}: ResolvedPlaceLayersProps): ReactNode {
|
|
57
57
|
if (!spec) return null
|
|
@@ -66,7 +66,7 @@ export function ResolvedPlaceLayers({
|
|
|
66
66
|
color={markerColor}
|
|
67
67
|
/>
|
|
68
68
|
))}
|
|
69
|
-
<ResultOverlay outline={spec.outline} id={
|
|
69
|
+
<ResultOverlay outline={spec.outline} id={outlineID} color={markerColor} />
|
|
70
70
|
{applyCamera ? <ResultCamera target={spec.camera} animate={animateCamera} /> : null}
|
|
71
71
|
</>
|
|
72
72
|
)
|
package/map/ResultCamera.tsx
CHANGED
|
@@ -19,11 +19,31 @@
|
|
|
19
19
|
* value-key dance, no dependency-lint suppression.
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
+
import type { FitBoundsOptions } from "maplibre-gl"
|
|
22
23
|
import { type ReactNode, useEffect } from "react"
|
|
23
24
|
import { useMap } from "react-map-gl/maplibre"
|
|
24
25
|
|
|
25
26
|
import type { MapCameraTarget } from "./place-render.ts"
|
|
26
27
|
|
|
28
|
+
/**
|
|
29
|
+
* The `fitBounds` options for a `bounds` target — and the reason this is a named function rather than an object literal
|
|
30
|
+
* at the call site.
|
|
31
|
+
*
|
|
32
|
+
* `duration` is present ONLY on the non-animated path, and its ABSENCE on the animated one is load-bearing. maplibre's
|
|
33
|
+
* `Camera.flyTo` (which `fitBounds` funnels into via `_fitInternal`) branches on `'duration' in options`, not on the
|
|
34
|
+
* value: an explicitly-passed `duration: undefined` therefore survives the key test and is coerced with `+undefined` →
|
|
35
|
+
* `NaN`. Every ease frame then computes `k = easing(elapsed / NaN)` → `NaN`, the flight-path math yields a `NaN` world
|
|
36
|
+
* coordinate, and the FIRST frame throws `Invalid LngLat object: (NaN, NaN)` out of the RAF loop — before the map has
|
|
37
|
+
* moved at all, and with no `move` event to notice it by.
|
|
38
|
+
*
|
|
39
|
+
* Measured 2026-08-05 against maplibre-gl 5.24.0, same bounds and same map: `{padding: 40, duration: undefined}` →
|
|
40
|
+
* `map._easeOptions.duration = NaN` + the throw; `{padding: 40}` → `3937.7 ms` + a normal flight. So pass the key or
|
|
41
|
+
* don't — never pass it holding `undefined`.
|
|
42
|
+
*/
|
|
43
|
+
export function fitBoundsOptionsFor(padding: number, animate: boolean): FitBoundsOptions {
|
|
44
|
+
return animate ? { padding } : { padding, duration: 0 }
|
|
45
|
+
}
|
|
46
|
+
|
|
27
47
|
export interface ResultCameraProps {
|
|
28
48
|
/**
|
|
29
49
|
* The camera target to animate to. `null` leaves the camera untouched (no result yet).
|
|
@@ -57,7 +77,7 @@ export function ResultCamera({ target, animate = true }: ResultCameraProps): Rea
|
|
|
57
77
|
return
|
|
58
78
|
}
|
|
59
79
|
|
|
60
|
-
instance.fitBounds(target.bounds,
|
|
80
|
+
instance.fitBounds(target.bounds, fitBoundsOptionsFor(target.padding, animate))
|
|
61
81
|
}, [map, target, animate])
|
|
62
82
|
|
|
63
83
|
return null
|
|
@@ -87,15 +87,15 @@ export interface UsePlaceAutocomplete {
|
|
|
87
87
|
/**
|
|
88
88
|
* The listbox element id (matches `inputProps["aria-controls"]`).
|
|
89
89
|
*/
|
|
90
|
-
|
|
90
|
+
listboxID: string
|
|
91
91
|
/**
|
|
92
92
|
* Build the option element id for suggestion `index`.
|
|
93
93
|
*/
|
|
94
|
-
|
|
94
|
+
optionID: (index: number) => string
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
const LISTBOX_ID = "mw-demo-suggest-list"
|
|
98
|
-
const
|
|
98
|
+
const optionID = (index: number) => `mw-demo-suggest-${index}`
|
|
99
99
|
|
|
100
100
|
/**
|
|
101
101
|
* Extract the locality segment being typed — the text after the last comma, trimmed.
|
|
@@ -220,10 +220,10 @@ export function usePlaceAutocomplete({
|
|
|
220
220
|
"aria-expanded": suggestions.length > 0,
|
|
221
221
|
"aria-controls": LISTBOX_ID,
|
|
222
222
|
"aria-autocomplete": "list",
|
|
223
|
-
"aria-activedescendant": activeIndex >= 0 ?
|
|
223
|
+
"aria-activedescendant": activeIndex >= 0 ? optionID(activeIndex) : undefined,
|
|
224
224
|
autoComplete: "off",
|
|
225
225
|
},
|
|
226
|
-
|
|
227
|
-
|
|
226
|
+
listboxID: LISTBOX_ID,
|
|
227
|
+
optionID,
|
|
228
228
|
}
|
|
229
229
|
}
|
package/out/map/DemoControls.js
CHANGED
|
@@ -15,7 +15,7 @@ export function DemoControls({ runtime, geocode, autocomplete, compare, panels,
|
|
|
15
15
|
const { busy, result, selectedCandidate } = geocode;
|
|
16
16
|
const loading = runtime.loading;
|
|
17
17
|
const errorMessage = geocode.parseError ?? runtime.errorMessage ?? null;
|
|
18
|
-
return (_jsxs("section", { className: "mw-demo-controls", children: [panels.header, panels.releaseInfo, _jsx(VersionPicker, { versions: versions, selected: runtime.selectedVersion ?? null, onSelect: onSelectVersion, disabled: busy }), _jsx(BackendControl, { activeBackend: runtime.activeBackend, forceWASM: runtime.forceWASM ?? false, onForceWASMChange: onForceWASMChange }), _jsx(CompareToggle, { versions: versions, primaryVersion: runtime.selectedVersion ?? null, compareMode: compare.compareMode, onCompareModeChange: compare.setCompareMode, compareVersion: compare.compareVersion, onCompareVersionChange: compare.setCompareVersion, disabled: busy }), _jsx(QueryForm, { value: geocode.text, onChange: geocode.setText, onSubmit: geocode.submit, disabled: !runtime.ready, busy: busy, placeholder: placeholder, onKeyDown: autocomplete.onInputKeyDown, inputProps: autocomplete.inputProps }), panels.bias, _jsx(PlaceAutocomplete, { suggestions: autocomplete.suggestions, activeIndex: autocomplete.activeIndex, onPick: autocomplete.pick, onHover: autocomplete.setActiveIndex,
|
|
18
|
+
return (_jsxs("section", { className: "mw-demo-controls", children: [panels.header, panels.releaseInfo, _jsx(VersionPicker, { versions: versions, selected: runtime.selectedVersion ?? null, onSelect: onSelectVersion, disabled: busy }), _jsx(BackendControl, { activeBackend: runtime.activeBackend, forceWASM: runtime.forceWASM ?? false, onForceWASMChange: onForceWASMChange }), _jsx(CompareToggle, { versions: versions, primaryVersion: runtime.selectedVersion ?? null, compareMode: compare.compareMode, onCompareModeChange: compare.setCompareMode, compareVersion: compare.compareVersion, onCompareVersionChange: compare.setCompareVersion, disabled: busy }), _jsx(QueryForm, { value: geocode.text, onChange: geocode.setText, onSubmit: geocode.submit, disabled: !runtime.ready, busy: busy, placeholder: placeholder, onKeyDown: autocomplete.onInputKeyDown, inputProps: autocomplete.inputProps }), panels.bias, _jsx(PlaceAutocomplete, { suggestions: autocomplete.suggestions, activeIndex: autocomplete.activeIndex, onPick: autocomplete.pick, onHover: autocomplete.setActiveIndex, listboxID: autocomplete.listboxID, optionID: autocomplete.optionID }), _jsx(PresetChips, { presets: presets, disabled: !runtime.ready || busy, onPick: (value) => {
|
|
19
19
|
geocode.setText(value);
|
|
20
20
|
geocode.reset();
|
|
21
21
|
}, trailing: panels.permalink ? panels.permalink(geocode.text) : null }), loading && !runtime.ready ? (_jsx(LoadingIndicator, { mode: "staged", steps: loading.stepLabels.length ? loading.stepLabels : undefined, activeStep: loading.stepIndex, label: loading.progress })) : null, errorMessage ? _jsx("p", { className: "mw-error", children: errorMessage }) : null, panels.aboveResult ? panels.aboveResult({ result }) : null, busy ? (_jsx("div", { className: "mw-result", children: _jsx(LoadingIndicator, { mode: "staged", steps: runtime.parseStageLabels, activeStep: geocode.parseStage }) })) : result ? (panels.result ? (panels.result({
|
|
@@ -31,13 +31,13 @@ export interface PlaceAutocompleteProps {
|
|
|
31
31
|
*/
|
|
32
32
|
onHover?: (index: number) => void;
|
|
33
33
|
/**
|
|
34
|
-
* The listbox element id — pass `
|
|
34
|
+
* The listbox element id — pass `listboxID` from the hook (matches the input's `aria-controls`).
|
|
35
35
|
*/
|
|
36
|
-
|
|
36
|
+
listboxID: string;
|
|
37
37
|
/**
|
|
38
|
-
* Build the option element id — pass `
|
|
38
|
+
* Build the option element id — pass `optionID` from the hook.
|
|
39
39
|
*/
|
|
40
|
-
|
|
40
|
+
optionID: (index: number) => string;
|
|
41
41
|
/**
|
|
42
42
|
* Leading label. @default "Did you mean:"
|
|
43
43
|
*/
|
|
@@ -46,5 +46,5 @@ export interface PlaceAutocompleteProps {
|
|
|
46
46
|
/**
|
|
47
47
|
* The suggestion listbox.
|
|
48
48
|
*/
|
|
49
|
-
export declare function PlaceAutocomplete({ suggestions, activeIndex, onPick, onHover,
|
|
49
|
+
export declare function PlaceAutocomplete({ suggestions, activeIndex, onPick, onHover, listboxID, optionID, caption, }: PlaceAutocompleteProps): ReactNode;
|
|
50
50
|
//# sourceMappingURL=PlaceAutocomplete.d.ts.map
|
|
@@ -3,9 +3,9 @@ import { cx } from "../common/cx.js";
|
|
|
3
3
|
/**
|
|
4
4
|
* The suggestion listbox.
|
|
5
5
|
*/
|
|
6
|
-
export function PlaceAutocomplete({ suggestions, activeIndex, onPick, onHover,
|
|
6
|
+
export function PlaceAutocomplete({ suggestions, activeIndex, onPick, onHover, listboxID, optionID, caption = "Did you mean:", }) {
|
|
7
7
|
if (!suggestions.length)
|
|
8
8
|
return null;
|
|
9
|
-
return (_jsxs("div", { className: "mw-demo-suggest", id:
|
|
9
|
+
return (_jsxs("div", { className: "mw-demo-suggest", id: listboxID, role: "listbox", "aria-label": "Place suggestions", children: [_jsx("span", { className: "mw-demo-suggest__label", children: caption }), suggestions.map((s, i) => (_jsx("button", { id: optionID(i), type: "button", role: "option", "aria-selected": i === activeIndex, className: cx("mw-chip", { "mw-chip--active": i === activeIndex }), onMouseEnter: () => onHover?.(i), onClick: () => onPick(s.value), title: s.placetype, children: s.label ?? s.value }, `${s.value}-${i}`)))] }));
|
|
10
10
|
}
|
|
11
11
|
//# sourceMappingURL=PlaceAutocomplete.js.map
|
|
@@ -31,7 +31,7 @@ export interface ResolvedPlaceLayersProps {
|
|
|
31
31
|
/**
|
|
32
32
|
* Source/layer id prefix for the outline. @default "mw-result"
|
|
33
33
|
*/
|
|
34
|
-
|
|
34
|
+
outlineID?: string;
|
|
35
35
|
/**
|
|
36
36
|
* Marker color. @default the house pink.
|
|
37
37
|
*/
|
|
@@ -40,5 +40,5 @@ export interface ResolvedPlaceLayersProps {
|
|
|
40
40
|
/**
|
|
41
41
|
* Render the marker(s), outline, and (optional) camera move for one resolved place.
|
|
42
42
|
*/
|
|
43
|
-
export declare function ResolvedPlaceLayers({ spec, applyCamera, animateCamera,
|
|
43
|
+
export declare function ResolvedPlaceLayers({ spec, applyCamera, animateCamera, outlineID, markerColor, }: ResolvedPlaceLayersProps): ReactNode;
|
|
44
44
|
//# sourceMappingURL=ResolvedPlaceLayers.d.ts.map
|
|
@@ -5,9 +5,9 @@ import { ResultOverlay } from "./ResultOverlay.js";
|
|
|
5
5
|
/**
|
|
6
6
|
* Render the marker(s), outline, and (optional) camera move for one resolved place.
|
|
7
7
|
*/
|
|
8
|
-
export function ResolvedPlaceLayers({ spec, applyCamera = true, animateCamera = true,
|
|
8
|
+
export function ResolvedPlaceLayers({ spec, applyCamera = true, animateCamera = true, outlineID, markerColor, }) {
|
|
9
9
|
if (!spec)
|
|
10
10
|
return null;
|
|
11
|
-
return (_jsxs(_Fragment, { children: [spec.markers.map(([longitude, latitude], index) => (_jsx(PlaceMarker, { longitude: longitude, latitude: latitude, color: markerColor }, `${longitude},${latitude},${index}`))), _jsx(ResultOverlay, { outline: spec.outline, id:
|
|
11
|
+
return (_jsxs(_Fragment, { children: [spec.markers.map(([longitude, latitude], index) => (_jsx(PlaceMarker, { longitude: longitude, latitude: latitude, color: markerColor }, `${longitude},${latitude},${index}`))), _jsx(ResultOverlay, { outline: spec.outline, id: outlineID, color: markerColor }), applyCamera ? _jsx(ResultCamera, { target: spec.camera, animate: animateCamera }) : null] }));
|
|
12
12
|
}
|
|
13
13
|
//# sourceMappingURL=ResolvedPlaceLayers.js.map
|
|
@@ -18,8 +18,25 @@
|
|
|
18
18
|
* as the effect dependency re-runs the camera move exactly when the resolved place changes — no
|
|
19
19
|
* value-key dance, no dependency-lint suppression.
|
|
20
20
|
*/
|
|
21
|
+
import type { FitBoundsOptions } from "maplibre-gl";
|
|
21
22
|
import { type ReactNode } from "react";
|
|
22
23
|
import type { MapCameraTarget } from "./place-render.ts";
|
|
24
|
+
/**
|
|
25
|
+
* The `fitBounds` options for a `bounds` target — and the reason this is a named function rather than an object literal
|
|
26
|
+
* at the call site.
|
|
27
|
+
*
|
|
28
|
+
* `duration` is present ONLY on the non-animated path, and its ABSENCE on the animated one is load-bearing. maplibre's
|
|
29
|
+
* `Camera.flyTo` (which `fitBounds` funnels into via `_fitInternal`) branches on `'duration' in options`, not on the
|
|
30
|
+
* value: an explicitly-passed `duration: undefined` therefore survives the key test and is coerced with `+undefined` →
|
|
31
|
+
* `NaN`. Every ease frame then computes `k = easing(elapsed / NaN)` → `NaN`, the flight-path math yields a `NaN` world
|
|
32
|
+
* coordinate, and the FIRST frame throws `Invalid LngLat object: (NaN, NaN)` out of the RAF loop — before the map has
|
|
33
|
+
* moved at all, and with no `move` event to notice it by.
|
|
34
|
+
*
|
|
35
|
+
* Measured 2026-08-05 against maplibre-gl 5.24.0, same bounds and same map: `{padding: 40, duration: undefined}` →
|
|
36
|
+
* `map._easeOptions.duration = NaN` + the throw; `{padding: 40}` → `3937.7 ms` + a normal flight. So pass the key or
|
|
37
|
+
* don't — never pass it holding `undefined`.
|
|
38
|
+
*/
|
|
39
|
+
export declare function fitBoundsOptionsFor(padding: number, animate: boolean): FitBoundsOptions;
|
|
23
40
|
export interface ResultCameraProps {
|
|
24
41
|
/**
|
|
25
42
|
* The camera target to animate to. `null` leaves the camera untouched (no result yet).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ResultCamera.d.ts","sourceRoot":"","sources":["../../map/ResultCamera.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,KAAK,SAAS,EAAa,MAAM,OAAO,CAAA;AAGjD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAExD,MAAM,WAAW,iBAAiB;IACjC;;OAEG;IACH,MAAM,EAAE,eAAe,GAAG,IAAI,CAAA;IAC9B;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;CACjB;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,EAAE,MAAM,EAAE,OAAc,EAAE,EAAE,iBAAiB,GAAG,SAAS,CAsBrF"}
|
|
1
|
+
{"version":3,"file":"ResultCamera.d.ts","sourceRoot":"","sources":["../../map/ResultCamera.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AACnD,OAAO,EAAE,KAAK,SAAS,EAAa,MAAM,OAAO,CAAA;AAGjD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAExD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,gBAAgB,CAEvF;AAED,MAAM,WAAW,iBAAiB;IACjC;;OAEG;IACH,MAAM,EAAE,eAAe,GAAG,IAAI,CAAA;IAC9B;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;CACjB;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,EAAE,MAAM,EAAE,OAAc,EAAE,EAAE,iBAAiB,GAAG,SAAS,CAsBrF"}
|
package/out/map/ResultCamera.js
CHANGED
|
@@ -20,6 +20,24 @@
|
|
|
20
20
|
*/
|
|
21
21
|
import { useEffect } from "react";
|
|
22
22
|
import { useMap } from "react-map-gl/maplibre";
|
|
23
|
+
/**
|
|
24
|
+
* The `fitBounds` options for a `bounds` target — and the reason this is a named function rather than an object literal
|
|
25
|
+
* at the call site.
|
|
26
|
+
*
|
|
27
|
+
* `duration` is present ONLY on the non-animated path, and its ABSENCE on the animated one is load-bearing. maplibre's
|
|
28
|
+
* `Camera.flyTo` (which `fitBounds` funnels into via `_fitInternal`) branches on `'duration' in options`, not on the
|
|
29
|
+
* value: an explicitly-passed `duration: undefined` therefore survives the key test and is coerced with `+undefined` →
|
|
30
|
+
* `NaN`. Every ease frame then computes `k = easing(elapsed / NaN)` → `NaN`, the flight-path math yields a `NaN` world
|
|
31
|
+
* coordinate, and the FIRST frame throws `Invalid LngLat object: (NaN, NaN)` out of the RAF loop — before the map has
|
|
32
|
+
* moved at all, and with no `move` event to notice it by.
|
|
33
|
+
*
|
|
34
|
+
* Measured 2026-08-05 against maplibre-gl 5.24.0, same bounds and same map: `{padding: 40, duration: undefined}` →
|
|
35
|
+
* `map._easeOptions.duration = NaN` + the throw; `{padding: 40}` → `3937.7 ms` + a normal flight. So pass the key or
|
|
36
|
+
* don't — never pass it holding `undefined`.
|
|
37
|
+
*/
|
|
38
|
+
export function fitBoundsOptionsFor(padding, animate) {
|
|
39
|
+
return animate ? { padding } : { padding, duration: 0 };
|
|
40
|
+
}
|
|
23
41
|
/**
|
|
24
42
|
* Drive the live map to `target`. No DOM of its own — it is a behavior mounted as a `<Map>` child.
|
|
25
43
|
*/
|
|
@@ -38,7 +56,7 @@ export function ResultCamera({ target, animate = true }) {
|
|
|
38
56
|
}
|
|
39
57
|
return;
|
|
40
58
|
}
|
|
41
|
-
instance.fitBounds(target.bounds,
|
|
59
|
+
instance.fitBounds(target.bounds, fitBoundsOptionsFor(target.padding, animate));
|
|
42
60
|
}, [map, target, animate]);
|
|
43
61
|
return null;
|
|
44
62
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ResultCamera.js","sourceRoot":"","sources":["../../map/ResultCamera.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;
|
|
1
|
+
{"version":3,"file":"ResultCamera.js","sourceRoot":"","sources":["../../map/ResultCamera.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAGH,OAAO,EAAkB,SAAS,EAAE,MAAM,OAAO,CAAA;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAA;AAI9C;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAe,EAAE,OAAgB;IACpE,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAA;AACxD,CAAC;AAcD;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI,EAAqB;IACzE,MAAM,GAAG,GAAG,MAAM,EAAE,CAAA;IAEpB,SAAS,CAAC,GAAG,EAAE;QACd,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,CAAA;QAEtC,IAAI,CAAC,QAAQ,IAAI,CAAC,MAAM;YAAE,OAAM;QAEhC,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC9B,IAAI,OAAO,EAAE,CAAC;gBACb,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAA;YAC7D,CAAC;iBAAM,CAAC;gBACP,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAA;YAC9D,CAAC;YAED,OAAM;QACP,CAAC;QAED,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAA;IAChF,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IAE1B,OAAO,IAAI,CAAA;AACZ,CAAC"}
|
|
@@ -81,11 +81,11 @@ export interface UsePlaceAutocomplete {
|
|
|
81
81
|
/**
|
|
82
82
|
* The listbox element id (matches `inputProps["aria-controls"]`).
|
|
83
83
|
*/
|
|
84
|
-
|
|
84
|
+
listboxID: string;
|
|
85
85
|
/**
|
|
86
86
|
* Build the option element id for suggestion `index`.
|
|
87
87
|
*/
|
|
88
|
-
|
|
88
|
+
optionID: (index: number) => string;
|
|
89
89
|
}
|
|
90
90
|
export declare function usePlaceAutocomplete({ text, setText, autocomplete, minChars, debounceMs, }: UsePlaceAutocompleteOptions): UsePlaceAutocomplete;
|
|
91
91
|
//# sourceMappingURL=usePlaceAutocomplete.d.ts.map
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
18
18
|
import { useDebouncedValue } from "../common/useDebouncedValue.js";
|
|
19
19
|
const LISTBOX_ID = "mw-demo-suggest-list";
|
|
20
|
-
const
|
|
20
|
+
const optionID = (index) => `mw-demo-suggest-${index}`;
|
|
21
21
|
/**
|
|
22
22
|
* Extract the locality segment being typed — the text after the last comma, trimmed.
|
|
23
23
|
*/
|
|
@@ -116,11 +116,11 @@ export function usePlaceAutocomplete({ text, setText, autocomplete, minChars = 2
|
|
|
116
116
|
"aria-expanded": suggestions.length > 0,
|
|
117
117
|
"aria-controls": LISTBOX_ID,
|
|
118
118
|
"aria-autocomplete": "list",
|
|
119
|
-
"aria-activedescendant": activeIndex >= 0 ?
|
|
119
|
+
"aria-activedescendant": activeIndex >= 0 ? optionID(activeIndex) : undefined,
|
|
120
120
|
autoComplete: "off",
|
|
121
121
|
},
|
|
122
|
-
|
|
123
|
-
|
|
122
|
+
listboxID: LISTBOX_ID,
|
|
123
|
+
optionID,
|
|
124
124
|
};
|
|
125
125
|
}
|
|
126
126
|
//# sourceMappingURL=usePlaceAutocomplete.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mailwoman/react",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "9.0.0",
|
|
4
4
|
"description": "React components + headless hooks for mailwoman — parse/geocode/POI explorers, Storybook-tested, Docusaurus-independent.",
|
|
5
5
|
"license": "AGPL-3.0-only OR LicenseRef-Commercial",
|
|
6
6
|
"repository": {
|
|
@@ -67,26 +67,26 @@
|
|
|
67
67
|
"test:node": "vitest run --config vitest.node.config.ts"
|
|
68
68
|
},
|
|
69
69
|
"dependencies": {
|
|
70
|
-
"@mailwoman/kind-classifier": "
|
|
71
|
-
"@mailwoman/poi-taxonomy": "
|
|
72
|
-
"@mailwoman/query-shape": "
|
|
70
|
+
"@mailwoman/kind-classifier": "9.0.0",
|
|
71
|
+
"@mailwoman/poi-taxonomy": "9.0.0",
|
|
72
|
+
"@mailwoman/query-shape": "9.0.0"
|
|
73
73
|
},
|
|
74
74
|
"devDependencies": {
|
|
75
|
-
"@storybook/addon-docs": "^10.5.
|
|
76
|
-
"@storybook/react-vite": "^10.5.
|
|
75
|
+
"@storybook/addon-docs": "^10.5.5",
|
|
76
|
+
"@storybook/react-vite": "^10.5.5",
|
|
77
77
|
"@types/react": "^19.2.17",
|
|
78
78
|
"@types/react-dom": "^19.2.3",
|
|
79
|
-
"@vitejs/plugin-react": "^6.0.
|
|
79
|
+
"@vitejs/plugin-react": "^6.0.5",
|
|
80
80
|
"@vitest/browser": "4.1.10",
|
|
81
81
|
"@vitest/browser-playwright": "4.1.10",
|
|
82
82
|
"maplibre-gl": "^5.24.0",
|
|
83
|
-
"playwright": "^1.62.
|
|
83
|
+
"playwright": "^1.62.1",
|
|
84
84
|
"react": "^19.2.8",
|
|
85
85
|
"react-dom": "^19.2.8",
|
|
86
|
-
"react-map-gl": "^8.1.
|
|
87
|
-
"storybook": "^10.5.
|
|
86
|
+
"react-map-gl": "^8.1.2",
|
|
87
|
+
"storybook": "^10.5.5",
|
|
88
88
|
"typescript": "^6.0.3",
|
|
89
|
-
"vite": "^8.
|
|
89
|
+
"vite": "^8.2.0",
|
|
90
90
|
"vitest": "4.1.10"
|
|
91
91
|
},
|
|
92
92
|
"peerDependencies": {
|