@mailwoman/react 10.1.0 → 10.2.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 -0
- package/lib/common/About.tsx +3 -3
- package/lib/common/CopyButton.tsx +6 -2
- package/lib/common/LoadingIndicator.tsx +10 -4
- package/lib/common/PresetChips.tsx +3 -1
- package/lib/common/confidence-tiers.ts +1 -1
- package/lib/common/text-tokens.ts +3 -9
- package/lib/index.ts +0 -1
- package/lib/map/AppIdentity.tsx +6 -2
- package/lib/map/DebugInfo.tsx +3 -16
- package/lib/map/Geocoder.tsx +9 -8
- package/lib/map/GeocoderControls.tsx +1 -13
- package/lib/map/GraticuleLayer.tsx +3 -1
- package/lib/map/MapCanvas.tsx +3 -1
- package/lib/map/MapChipRow.tsx +1 -1
- package/lib/map/MapCompass.tsx +3 -1
- package/lib/map/MapControlStack.tsx +3 -1
- package/lib/map/MapFooter.tsx +3 -1
- package/lib/map/OverlayLayers.tsx +13 -2
- package/lib/map/PlaceAutocomplete.tsx +3 -1
- package/lib/map/PlaceMarker.tsx +6 -2
- package/lib/map/ResolvedPlaceLayers.tsx +13 -5
- package/lib/map/ResultCamera.tsx +3 -1
- package/lib/map/ResultOverlay.tsx +12 -4
- package/lib/map/VersionPicker.tsx +1 -1
- package/lib/map/fake-runtime.ts +36 -7
- package/lib/map/map-debug.ts +3 -1
- package/lib/map/place-render.ts +3 -3
- package/lib/map/types.ts +2 -15
- package/lib/map/useMapPlaceRender.ts +1 -1
- package/lib/map/usePlaceAutocomplete.ts +2 -2
- package/lib/map.ts +0 -3
- package/lib/pipeline/ConfidenceCell.tsx +1 -1
- package/lib/pipeline/PipelineExplorer.tsx +6 -3
- package/lib/pipeline/ResolvedPlace.tsx +1 -1
- package/lib/pipeline/TreeView.tsx +1 -1
- package/lib/pipeline/types.ts +0 -4
- package/lib/poi/POIExplorer.tsx +6 -3
- package/lib/poi/runtime.ts +9 -0
- package/lib/poi/types.ts +27 -28
- package/lib/poi/usePOISearch.ts +55 -41
- package/lib/poi.ts +1 -0
- package/lib/runtime/useReleaseRuntime.ts +14 -33
- package/lib/search/SearchModal.tsx +227 -66
- package/lib/search/search.css +160 -22
- package/lib/search/types.ts +2 -1
- package/out/common/About.d.ts +1 -1
- package/out/common/About.js +1 -1
- package/out/common/About.js.map +1 -1
- package/out/common/CopyButton.d.ts +6 -2
- package/out/common/CopyButton.d.ts.map +1 -1
- package/out/common/CopyButton.js.map +1 -1
- package/out/common/LoadingIndicator.d.ts +10 -4
- package/out/common/LoadingIndicator.d.ts.map +1 -1
- package/out/common/LoadingIndicator.js.map +1 -1
- package/out/common/PresetChips.d.ts +3 -1
- package/out/common/PresetChips.d.ts.map +1 -1
- package/out/common/PresetChips.js.map +1 -1
- package/out/common/confidence-tiers.d.ts +1 -1
- package/out/common/confidence-tiers.d.ts.map +1 -1
- package/out/common/confidence-tiers.js.map +1 -1
- package/out/common/text-tokens.d.ts +2 -8
- package/out/common/text-tokens.d.ts.map +1 -1
- package/out/common/text-tokens.js.map +1 -1
- package/out/index.d.ts +1 -1
- package/out/index.d.ts.map +1 -1
- package/out/map/AppIdentity.d.ts +6 -2
- package/out/map/AppIdentity.d.ts.map +1 -1
- package/out/map/AppIdentity.js.map +1 -1
- package/out/map/DebugInfo.d.ts +2 -9
- package/out/map/DebugInfo.d.ts.map +1 -1
- package/out/map/DebugInfo.js +3 -6
- package/out/map/DebugInfo.js.map +1 -1
- package/out/map/Geocoder.d.ts +4 -4
- package/out/map/Geocoder.d.ts.map +1 -1
- package/out/map/Geocoder.js +4 -2
- package/out/map/Geocoder.js.map +1 -1
- package/out/map/GeocoderControls.d.ts +2 -3
- package/out/map/GeocoderControls.d.ts.map +1 -1
- package/out/map/GeocoderControls.js +2 -3
- package/out/map/GeocoderControls.js.map +1 -1
- package/out/map/GraticuleLayer.d.ts +3 -1
- package/out/map/GraticuleLayer.d.ts.map +1 -1
- package/out/map/GraticuleLayer.js.map +1 -1
- package/out/map/MapCanvas.d.ts +3 -1
- package/out/map/MapCanvas.d.ts.map +1 -1
- package/out/map/MapCanvas.js.map +1 -1
- package/out/map/MapChipRow.d.ts +1 -1
- package/out/map/MapCompass.d.ts +3 -1
- package/out/map/MapCompass.d.ts.map +1 -1
- package/out/map/MapCompass.js.map +1 -1
- package/out/map/MapControlStack.d.ts +3 -1
- package/out/map/MapControlStack.d.ts.map +1 -1
- package/out/map/MapControlStack.js.map +1 -1
- package/out/map/MapFooter.d.ts +3 -1
- package/out/map/MapFooter.d.ts.map +1 -1
- package/out/map/MapFooter.js.map +1 -1
- package/out/map/OverlayLayers.d.ts +7 -1
- package/out/map/OverlayLayers.d.ts.map +1 -1
- package/out/map/OverlayLayers.js +2 -2
- package/out/map/OverlayLayers.js.map +1 -1
- package/out/map/PlaceAutocomplete.d.ts +3 -1
- package/out/map/PlaceAutocomplete.d.ts.map +1 -1
- package/out/map/PlaceAutocomplete.js.map +1 -1
- package/out/map/PlaceMarker.d.ts +6 -2
- package/out/map/PlaceMarker.d.ts.map +1 -1
- package/out/map/PlaceMarker.js.map +1 -1
- package/out/map/ResolvedPlaceLayers.d.ts +13 -5
- package/out/map/ResolvedPlaceLayers.d.ts.map +1 -1
- package/out/map/ResolvedPlaceLayers.js.map +1 -1
- package/out/map/ResultCamera.d.ts +3 -1
- package/out/map/ResultCamera.d.ts.map +1 -1
- package/out/map/ResultCamera.js.map +1 -1
- package/out/map/ResultOverlay.d.ts +12 -4
- package/out/map/ResultOverlay.d.ts.map +1 -1
- package/out/map/ResultOverlay.js.map +1 -1
- package/out/map/VersionPicker.d.ts +1 -1
- package/out/map/fake-runtime.d.ts.map +1 -1
- package/out/map/fake-runtime.js +36 -7
- package/out/map/fake-runtime.js.map +1 -1
- package/out/map/map-debug.d.ts +3 -1
- package/out/map/map-debug.d.ts.map +1 -1
- package/out/map/map-debug.js.map +1 -1
- package/out/map/place-render.d.ts +3 -3
- package/out/map/place-render.d.ts.map +1 -1
- package/out/map/types.d.ts +2 -14
- package/out/map/types.d.ts.map +1 -1
- package/out/map/useMapPlaceRender.d.ts +1 -1
- package/out/map/useMapPlaceRender.d.ts.map +1 -1
- package/out/map/useMapPlaceRender.js.map +1 -1
- package/out/map/usePlaceAutocomplete.d.ts +2 -2
- package/out/map.d.ts +1 -3
- package/out/map.d.ts.map +1 -1
- package/out/map.js +0 -1
- package/out/map.js.map +1 -1
- package/out/pipeline/ConfidenceCell.d.ts +1 -1
- package/out/pipeline/ConfidenceCell.d.ts.map +1 -1
- package/out/pipeline/PipelineExplorer.d.ts +6 -2
- package/out/pipeline/PipelineExplorer.d.ts.map +1 -1
- package/out/pipeline/PipelineExplorer.js +1 -1
- package/out/pipeline/PipelineExplorer.js.map +1 -1
- package/out/pipeline/ResolvedPlace.d.ts +1 -1
- package/out/pipeline/ResolvedPlace.d.ts.map +1 -1
- package/out/pipeline/TreeView.js.map +1 -1
- package/out/pipeline/types.d.ts +0 -4
- package/out/pipeline/types.d.ts.map +1 -1
- package/out/poi/POIExplorer.d.ts +1 -1
- package/out/poi/POIExplorer.d.ts.map +1 -1
- package/out/poi/POIExplorer.js +2 -2
- package/out/poi/POIExplorer.js.map +1 -1
- package/out/poi/runtime.d.ts.map +1 -1
- package/out/poi/runtime.js +9 -0
- package/out/poi/runtime.js.map +1 -1
- package/out/poi/types.d.ts +24 -28
- package/out/poi/types.d.ts.map +1 -1
- package/out/poi/usePOISearch.d.ts +4 -2
- package/out/poi/usePOISearch.d.ts.map +1 -1
- package/out/poi/usePOISearch.js +42 -32
- package/out/poi/usePOISearch.js.map +1 -1
- package/out/poi.d.ts +1 -1
- package/out/poi.d.ts.map +1 -1
- package/out/poi.js.map +1 -1
- package/out/runtime/useReleaseRuntime.d.ts +13 -23
- package/out/runtime/useReleaseRuntime.d.ts.map +1 -1
- package/out/runtime/useReleaseRuntime.js +2 -8
- package/out/runtime/useReleaseRuntime.js.map +1 -1
- package/out/search/SearchModal.d.ts +10 -3
- package/out/search/SearchModal.d.ts.map +1 -1
- package/out/search/SearchModal.js +83 -15
- package/out/search/SearchModal.js.map +1 -1
- package/out/search/types.d.ts +2 -1
- package/out/search/types.d.ts.map +1 -1
- package/package.json +19 -29
- package/lib/map/BackendControl.tsx +0 -50
- package/out/map/BackendControl.d.ts +0 -31
- package/out/map/BackendControl.d.ts.map +0 -1
- package/out/map/BackendControl.js +0 -8
- package/out/map/BackendControl.js.map +0 -1
package/lib/map/place-render.ts
CHANGED
|
@@ -29,17 +29,17 @@ export interface ResolvedMapPlace extends ResolvedPlaceView {
|
|
|
29
29
|
* The place's bounding box.
|
|
30
30
|
* Postcodes located by an anchor centroid have none.
|
|
31
31
|
*/
|
|
32
|
-
bbox
|
|
32
|
+
bbox: LatLonBounds | null
|
|
33
33
|
|
|
34
34
|
/**
|
|
35
35
|
* The street-level tier, set only for results from address points or interpolation.
|
|
36
36
|
*/
|
|
37
|
-
tier
|
|
37
|
+
tier: PlaceTier | null
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
40
|
* The uncertainty radius in meters of a street-level result, drawn as a circle when `tier` is set.
|
|
41
41
|
*/
|
|
42
|
-
uncertaintyM
|
|
42
|
+
uncertaintyM: number | null
|
|
43
43
|
|
|
44
44
|
/**
|
|
45
45
|
* The admin polygon, if the host has already fetched it.
|
package/lib/map/types.ts
CHANGED
|
@@ -42,7 +42,7 @@ export interface OverlaySpec {
|
|
|
42
42
|
source: SourceSpecification
|
|
43
43
|
layers: LayerSpecification[]
|
|
44
44
|
/**
|
|
45
|
-
* @
|
|
45
|
+
* @defaultValue `true`
|
|
46
46
|
*/
|
|
47
47
|
visible?: boolean
|
|
48
48
|
label?: string
|
|
@@ -81,11 +81,6 @@ export interface VersionOption {
|
|
|
81
81
|
label?: string
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
/**
|
|
85
|
-
* Which neural backend the geocoder is currently running on.
|
|
86
|
-
*/
|
|
87
|
-
export type InferenceBackend = "webgpu" | "wasm"
|
|
88
|
-
|
|
89
84
|
/**
|
|
90
85
|
* The injected geocoder runtime extends {@link PipelineRuntime} with the map.
|
|
91
86
|
* It also supplies version and backend controls.
|
|
@@ -148,17 +143,9 @@ export interface GeocoderRuntime extends PipelineRuntime {
|
|
|
148
143
|
*/
|
|
149
144
|
selectVersion?: (version: string) => void
|
|
150
145
|
/**
|
|
151
|
-
* The
|
|
146
|
+
* The neural runtime's backend and model size (e.g. `wasm (28 MB int8)`); free-form for the label.
|
|
152
147
|
*/
|
|
153
148
|
activeBackend?: string
|
|
154
|
-
/**
|
|
155
|
-
* Whether the CPU/wasm backend is currently forced (the controlled value for the backend toggle).
|
|
156
|
-
*/
|
|
157
|
-
forceWASM?: boolean
|
|
158
|
-
/**
|
|
159
|
-
* Force the wasm backend (opt out of WebGPU), for the backend toggle.
|
|
160
|
-
*/
|
|
161
|
-
setForceWASM?: (forceWASM: boolean) => void
|
|
162
149
|
}
|
|
163
150
|
|
|
164
151
|
/**
|
|
@@ -14,6 +14,6 @@ import type { MapPlaceRenderSpec, ResolvedMapPlace } from "#map/place-render"
|
|
|
14
14
|
/**
|
|
15
15
|
* Memoize the render spec for a resolved place; `null` in → `null` out (no geometry to draw).
|
|
16
16
|
*/
|
|
17
|
-
export function useMapPlaceRender(place: ResolvedMapPlace | null
|
|
17
|
+
export function useMapPlaceRender(place: ResolvedMapPlace | null): MapPlaceRenderSpec | null {
|
|
18
18
|
return useMemo(() => (place ? computeMapPlaceRenderSpec(place) : null), [place])
|
|
19
19
|
}
|
|
@@ -32,12 +32,12 @@ export interface UsePlaceAutocompleteOptions {
|
|
|
32
32
|
autocomplete?: (query: string) => Promise<Suggestion[]>
|
|
33
33
|
|
|
34
34
|
/**
|
|
35
|
-
* @
|
|
35
|
+
* @defaultValue `2`
|
|
36
36
|
*/
|
|
37
37
|
minChars?: number
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
|
-
* @
|
|
40
|
+
* @defaultValue `150`
|
|
41
41
|
*/
|
|
42
42
|
debounceMs?: number
|
|
43
43
|
}
|
package/lib/map.ts
CHANGED
|
@@ -38,7 +38,6 @@ export type {
|
|
|
38
38
|
CompareContext,
|
|
39
39
|
GeocoderPanels,
|
|
40
40
|
GeocoderRuntime,
|
|
41
|
-
InferenceBackend,
|
|
42
41
|
LngLatTuple,
|
|
43
42
|
MapBias,
|
|
44
43
|
OverlaySpec,
|
|
@@ -67,8 +66,6 @@ export { ResultOverlay } from "./map/ResultOverlay.tsx"
|
|
|
67
66
|
export type { ResultOverlayProps } from "./map/ResultOverlay.tsx"
|
|
68
67
|
|
|
69
68
|
// ── Geocoder controls + the composed geocoder ────────────────────────────────
|
|
70
|
-
export { BackendControl } from "./map/BackendControl.tsx"
|
|
71
|
-
export type { BackendControlProps } from "./map/BackendControl.tsx"
|
|
72
69
|
export { CompareToggle } from "./map/CompareToggle.tsx"
|
|
73
70
|
export type { CompareToggleProps } from "./map/CompareToggle.tsx"
|
|
74
71
|
export { Geocoder } from "./map/Geocoder.tsx"
|
|
@@ -11,7 +11,7 @@ import { confidenceTierOrMid } from "#common/confidence-tiers"
|
|
|
11
11
|
import { cx } from "#common/cx"
|
|
12
12
|
|
|
13
13
|
export interface ConfidenceCellProps {
|
|
14
|
-
confidence?: number
|
|
14
|
+
confidence?: number | null
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
export function ConfidenceCell({ confidence }: ConfidenceCellProps) {
|
|
@@ -32,11 +32,15 @@ export interface PipelineExplorerProps {
|
|
|
32
32
|
*/
|
|
33
33
|
runtime: PipelineRuntime
|
|
34
34
|
/**
|
|
35
|
-
* Address to pre-fill.
|
|
35
|
+
* Address to pre-fill.
|
|
36
|
+
*
|
|
37
|
+
* @defaultValue the White House
|
|
36
38
|
*/
|
|
37
39
|
defaultAddress?: string
|
|
38
40
|
/**
|
|
39
|
-
* Example chips.
|
|
41
|
+
* Example chips.
|
|
42
|
+
*
|
|
43
|
+
* @defaultValue the built-in address presets
|
|
40
44
|
*/
|
|
41
45
|
presets?: ReadonlyArray<Preset>
|
|
42
46
|
/**
|
|
@@ -62,7 +66,6 @@ function PipelineExplorerInner({ runtime, defaultAddress, presets, panels }: Pip
|
|
|
62
66
|
{panels.header}
|
|
63
67
|
{panels.releaseInfo}
|
|
64
68
|
{panels.versionControl}
|
|
65
|
-
{panels.backendControl}
|
|
66
69
|
|
|
67
70
|
<QueryForm
|
|
68
71
|
value={text}
|
|
@@ -12,7 +12,7 @@ import { Fragment, type ReactNode } from "react"
|
|
|
12
12
|
|
|
13
13
|
export interface ResolvedPlaceProps {
|
|
14
14
|
place: ResolvedPlaceView
|
|
15
|
-
dualRoles?: DualRoleView[]
|
|
15
|
+
dualRoles?: DualRoleView[] | null
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
export function ResolvedPlace({ place, dualRoles }: ResolvedPlaceProps): ReactNode {
|
|
@@ -47,7 +47,7 @@ function renderNode(node: TreeNode, path: string): ReactNode {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
export function TreeView({ tree }: TreeViewProps): ReactNode {
|
|
50
|
-
const roots = (tree as { roots?: unknown[] } | null
|
|
50
|
+
const roots = (tree as { roots?: unknown[] } | null)?.roots
|
|
51
51
|
|
|
52
52
|
if (!Array.isArray(roots) || !roots.length) return null
|
|
53
53
|
|
package/lib/pipeline/types.ts
CHANGED
|
@@ -73,10 +73,6 @@ export interface PipelinePanels {
|
|
|
73
73
|
* Model-version selector, wired to the host's bundle state.
|
|
74
74
|
*/
|
|
75
75
|
versionControl?: ReactNode
|
|
76
|
-
/**
|
|
77
|
-
* Backend indicator + wasm toggle.
|
|
78
|
-
*/
|
|
79
|
-
backendControl?: ReactNode
|
|
80
76
|
/**
|
|
81
77
|
* One-line release blurb.
|
|
82
78
|
*/
|
package/lib/poi/POIExplorer.tsx
CHANGED
|
@@ -30,7 +30,7 @@ export interface POIExplorerProps {
|
|
|
30
30
|
/**
|
|
31
31
|
* The example chips.
|
|
32
32
|
*
|
|
33
|
-
* @
|
|
33
|
+
* @defaultValue POI_PRESETS
|
|
34
34
|
*/
|
|
35
35
|
presets?: ReadonlyArray<Preset>
|
|
36
36
|
/**
|
|
@@ -80,7 +80,7 @@ function POIExplorerInner({
|
|
|
80
80
|
const showLiveBlock = Boolean(
|
|
81
81
|
runLiveSearch &&
|
|
82
82
|
subject &&
|
|
83
|
-
(subject.kind === "brand" ? brandLiveSearch && subject.wikidata !==
|
|
83
|
+
(subject.kind === "brand" ? brandLiveSearch && subject.wikidata !== null : !subject.buildLocal)
|
|
84
84
|
)
|
|
85
85
|
|
|
86
86
|
return (
|
|
@@ -96,7 +96,10 @@ function POIExplorerInner({
|
|
|
96
96
|
<>
|
|
97
97
|
<SubjectPanel subject={subject} />
|
|
98
98
|
{subject.kind === "category" ? (
|
|
99
|
-
<OverpassBlock
|
|
99
|
+
<OverpassBlock
|
|
100
|
+
overpassQL={result.overpassQL ?? undefined}
|
|
101
|
+
overpassError={result.overpassError ?? undefined}
|
|
102
|
+
/>
|
|
100
103
|
) : null}
|
|
101
104
|
|
|
102
105
|
{showLiveBlock ? (
|
package/lib/poi/runtime.ts
CHANGED
|
@@ -34,6 +34,11 @@ export async function loadPOIRuntime(): Promise<POIRuntime> {
|
|
|
34
34
|
categoryID: match.category.id,
|
|
35
35
|
matchedPhrase: match.matchedPhrase,
|
|
36
36
|
confidence: match.confidence,
|
|
37
|
+
mechanism: "exact",
|
|
38
|
+
inputPhrase: phrase,
|
|
39
|
+
wikidata: null,
|
|
40
|
+
reading: "preference",
|
|
41
|
+
countryScope: null,
|
|
37
42
|
}))
|
|
38
43
|
}
|
|
39
44
|
|
|
@@ -43,6 +48,10 @@ export async function loadPOIRuntime(): Promise<POIRuntime> {
|
|
|
43
48
|
wikidata: match.brand.wikidata,
|
|
44
49
|
matchedPhrase: match.matchedPhrase,
|
|
45
50
|
confidence: match.confidence,
|
|
51
|
+
mechanism: "exact",
|
|
52
|
+
inputPhrase: phrase,
|
|
53
|
+
reading: "preference",
|
|
54
|
+
countryScope: null,
|
|
46
55
|
}))
|
|
47
56
|
}
|
|
48
57
|
|
package/lib/poi/types.ts
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import type { QueryKindResult } from "@mailwoman/core/pipeline"
|
|
11
|
+
import type { POIDistanceHit } from "@mailwoman/core/resolver"
|
|
11
12
|
import type { POIPhraseLookup, createKindClassifier } from "@mailwoman/kind-classifier"
|
|
12
13
|
import type { createPOITaxonomyLookup } from "@mailwoman/poi-taxonomy/table"
|
|
13
14
|
|
|
@@ -67,9 +68,9 @@ export interface POIBrandSubject extends POISubjectBase {
|
|
|
67
68
|
name: string
|
|
68
69
|
/**
|
|
69
70
|
* The brand's Wikidata QID.
|
|
70
|
-
* It is
|
|
71
|
+
* It is `null` when the lexicon had no QID for the brand.
|
|
71
72
|
*/
|
|
72
|
-
wikidata
|
|
73
|
+
wikidata: string | null
|
|
73
74
|
}
|
|
74
75
|
|
|
75
76
|
/**
|
|
@@ -84,22 +85,15 @@ export type POISubject = POICategorySubject | POIBrandSubject
|
|
|
84
85
|
*/
|
|
85
86
|
export interface POIExplorerResult {
|
|
86
87
|
kindResult: QueryKindResult
|
|
87
|
-
subject
|
|
88
|
-
overpassQL
|
|
89
|
-
overpassError
|
|
88
|
+
subject: POISubject | null
|
|
89
|
+
overpassQL: string | null
|
|
90
|
+
overpassError: string | null
|
|
90
91
|
}
|
|
91
92
|
|
|
92
93
|
/**
|
|
93
94
|
* One live poi.db hit, as the results list renders it.
|
|
94
95
|
*/
|
|
95
|
-
export
|
|
96
|
-
name: string
|
|
97
|
-
lat: number
|
|
98
|
-
lon: number
|
|
99
|
-
distanceM: number
|
|
100
|
-
country: string
|
|
101
|
-
confidence: number
|
|
102
|
-
}
|
|
96
|
+
export type POISearchHit = POIDistanceHit
|
|
103
97
|
|
|
104
98
|
/**
|
|
105
99
|
* The result of an injected live search.
|
|
@@ -112,28 +106,33 @@ export type POILiveSearchResult =
|
|
|
112
106
|
| { status: "unplaced"; anchor: string }
|
|
113
107
|
| { status: "unavailable" }
|
|
114
108
|
|
|
109
|
+
/**
|
|
110
|
+
* What a live search looks for near `anchor`: a taxonomy category with its Overture
|
|
111
|
+
* leaf categories, or a chain brand identified by its Wikidata QID.
|
|
112
|
+
*/
|
|
113
|
+
export type POILiveSearchRequest =
|
|
114
|
+
| {
|
|
115
|
+
kind: "category"
|
|
116
|
+
categoryID: string
|
|
117
|
+
overtureCategoryIDs: string[]
|
|
118
|
+
anchor: string
|
|
119
|
+
}
|
|
120
|
+
| {
|
|
121
|
+
kind: "brand"
|
|
122
|
+
brandName: string
|
|
123
|
+
wikidata: string
|
|
124
|
+
anchor: string
|
|
125
|
+
}
|
|
126
|
+
|
|
115
127
|
/**
|
|
116
128
|
* The injected live-search function.
|
|
117
129
|
*
|
|
118
|
-
* It probes the published poi.db for the
|
|
119
|
-
* categories and the anchor text.
|
|
130
|
+
* It probes the published poi.db for the request's subject and the anchor text.
|
|
120
131
|
* The explorer runs intent-only when this function is absent.
|
|
121
132
|
*
|
|
122
|
-
* For a brand subject, `brandWikidata` contains the QID and the probe fetches by it.
|
|
123
|
-
* In that case `categoryID` holds the brand name and `overtureCategoryIDs` is empty.
|
|
124
|
-
*
|
|
125
133
|
* A probe that cannot serve brands should leave `usePOISearch`'s `brandLiveSearch` option unset.
|
|
126
134
|
*/
|
|
127
|
-
export type POILiveSearch = (
|
|
128
|
-
categoryID: string
|
|
129
|
-
overtureCategoryIDs: string[]
|
|
130
|
-
anchor: string
|
|
131
|
-
/**
|
|
132
|
-
* The brand's Wikidata QID.
|
|
133
|
-
* It is present only when the subject is a chain brand.
|
|
134
|
-
*/
|
|
135
|
-
brandWikidata?: string
|
|
136
|
-
}) => Promise<POILiveSearchResult>
|
|
135
|
+
export type POILiveSearch = (request: POILiveSearchRequest) => Promise<POILiveSearchResult>
|
|
137
136
|
|
|
138
137
|
/**
|
|
139
138
|
* The state of a "Search live" request.
|
package/lib/poi/usePOISearch.ts
CHANGED
|
@@ -12,7 +12,14 @@ import { useCallback, useEffect, useEffectEvent, useState } from "react"
|
|
|
12
12
|
|
|
13
13
|
import { useDebouncedValue } from "#common/useDebouncedValue"
|
|
14
14
|
import { loadPOIRuntime } from "#poi/runtime"
|
|
15
|
-
import type {
|
|
15
|
+
import type {
|
|
16
|
+
LiveSearchState,
|
|
17
|
+
LoadPOIRuntime,
|
|
18
|
+
POIExplorerResult,
|
|
19
|
+
POILiveSearch,
|
|
20
|
+
POILiveSearchRequest,
|
|
21
|
+
POIRuntime,
|
|
22
|
+
} from "#poi/types"
|
|
16
23
|
|
|
17
24
|
/**
|
|
18
25
|
* Options for {@link usePOISearch}.
|
|
@@ -25,7 +32,8 @@ export interface UsePOISearchOptions {
|
|
|
25
32
|
|
|
26
33
|
/**
|
|
27
34
|
* The loader that the hook calls once on mount.
|
|
28
|
-
*
|
|
35
|
+
*
|
|
36
|
+
* @defaultValue `loadPOIRuntime`
|
|
29
37
|
*/
|
|
30
38
|
loadRuntime?: LoadPOIRuntime
|
|
31
39
|
|
|
@@ -44,7 +52,8 @@ export interface UsePOISearchOptions {
|
|
|
44
52
|
|
|
45
53
|
/**
|
|
46
54
|
* The delay in milliseconds before the text is classified.
|
|
47
|
-
*
|
|
55
|
+
*
|
|
56
|
+
* @defaultValue `250`
|
|
48
57
|
*/
|
|
49
58
|
debounceMs?: number
|
|
50
59
|
}
|
|
@@ -83,25 +92,26 @@ export interface UsePOISearch {
|
|
|
83
92
|
|
|
84
93
|
function buildOverpass(
|
|
85
94
|
runtime: POIRuntime,
|
|
86
|
-
categoryID: string
|
|
87
|
-
|
|
88
|
-
remainder: string
|
|
89
|
-
): { overpassQL?: string; overpassError?: string } {
|
|
95
|
+
categoryID: string
|
|
96
|
+
): { overpassQL: string | null; overpassError: string | null } {
|
|
90
97
|
const category = runtime.lookup.getPOICategory(categoryID)
|
|
91
98
|
|
|
92
99
|
if (!category) {
|
|
93
|
-
return {}
|
|
100
|
+
return { overpassQL: null, overpassError: null }
|
|
94
101
|
}
|
|
95
102
|
|
|
96
103
|
const intent: OverpassIntentLike = {
|
|
97
|
-
subject: { kind: "category", categoryIDs: [categoryID]
|
|
98
|
-
|
|
104
|
+
subject: { kind: "category", categoryIDs: [categoryID] },
|
|
105
|
+
anchor: null,
|
|
99
106
|
}
|
|
100
107
|
|
|
101
108
|
try {
|
|
102
|
-
return {
|
|
109
|
+
return {
|
|
110
|
+
overpassQL: emitOverpassQL(intent, category.osmTag ? { osmTags: [category.osmTag] } : {}),
|
|
111
|
+
overpassError: null,
|
|
112
|
+
}
|
|
103
113
|
} catch (error) {
|
|
104
|
-
return { overpassError: error instanceof Error ? error.message : String(error) }
|
|
114
|
+
return { overpassQL: null, overpassError: error instanceof Error ? error.message : String(error) }
|
|
105
115
|
}
|
|
106
116
|
}
|
|
107
117
|
|
|
@@ -158,10 +168,10 @@ export function usePOISearch({
|
|
|
158
168
|
runtime.classify(input, shape).then((kindResult) => {
|
|
159
169
|
if (cancelled) return
|
|
160
170
|
|
|
161
|
-
const matched = kindResult.kind === "poi_query" ? matchPOISubject(trimmed,
|
|
171
|
+
const matched = kindResult.kind === "poi_query" ? matchPOISubject(trimmed, null, runtime.lexicon) : null
|
|
162
172
|
|
|
163
173
|
if (!matched) {
|
|
164
|
-
setStoredResult({ query: trimmed, value: { kindResult } })
|
|
174
|
+
setStoredResult({ query: trimmed, value: { kindResult, subject: null, overpassQL: null, overpassError: null } })
|
|
165
175
|
|
|
166
176
|
return
|
|
167
177
|
}
|
|
@@ -174,11 +184,13 @@ export function usePOISearch({
|
|
|
174
184
|
subject: {
|
|
175
185
|
kind: "brand",
|
|
176
186
|
name: matched.match.categoryID,
|
|
177
|
-
|
|
187
|
+
wikidata: matched.match.wikidata || null,
|
|
178
188
|
matchedPhrase: matched.match.matchedPhrase,
|
|
179
189
|
confidence: matched.match.confidence,
|
|
180
190
|
remainder: matched.remainder,
|
|
181
191
|
},
|
|
192
|
+
overpassQL: null,
|
|
193
|
+
overpassError: null,
|
|
182
194
|
},
|
|
183
195
|
})
|
|
184
196
|
|
|
@@ -188,7 +200,7 @@ export function usePOISearch({
|
|
|
188
200
|
const category = runtime.lookup.getPOICategory(matched.match.categoryID)
|
|
189
201
|
|
|
190
202
|
if (!category) {
|
|
191
|
-
setStoredResult({ query: trimmed, value: { kindResult } })
|
|
203
|
+
setStoredResult({ query: trimmed, value: { kindResult, subject: null, overpassQL: null, overpassError: null } })
|
|
192
204
|
|
|
193
205
|
return
|
|
194
206
|
}
|
|
@@ -205,7 +217,7 @@ export function usePOISearch({
|
|
|
205
217
|
remainder: matched.remainder,
|
|
206
218
|
buildLocal: runtime.lookup.requiresBuildLocalLayer(category),
|
|
207
219
|
},
|
|
208
|
-
...buildOverpass(runtime, matched.match.categoryID
|
|
220
|
+
...buildOverpass(runtime, matched.match.categoryID),
|
|
209
221
|
},
|
|
210
222
|
})
|
|
211
223
|
})
|
|
@@ -218,11 +230,10 @@ export function usePOISearch({
|
|
|
218
230
|
const result = storedResult?.query === trimmedText ? storedResult.value : null
|
|
219
231
|
const liveSearch: LiveSearchState = storedLive?.query === trimmedText ? storedLive.state : { status: "idle" }
|
|
220
232
|
|
|
221
|
-
const subject = result?.subject
|
|
233
|
+
const subject = result?.subject ?? null
|
|
222
234
|
|
|
223
235
|
const subjectLiveCapable =
|
|
224
|
-
subject !==
|
|
225
|
-
(subject.kind === "brand" ? brandLiveSearch && subject.wikidata !== undefined : !subject.buildLocal)
|
|
236
|
+
subject !== null && (subject.kind === "brand" ? brandLiveSearch && subject.wikidata !== null : !subject.buildLocal)
|
|
226
237
|
|
|
227
238
|
const canSearchLive = Boolean(
|
|
228
239
|
runLiveSearch && runtime && subject && subjectLiveCapable && subject.remainder.trim().length > 0
|
|
@@ -231,34 +242,37 @@ export function usePOISearch({
|
|
|
231
242
|
const searchLive = useCallback(async () => {
|
|
232
243
|
if (!runLiveSearch || !runtime || !subject || !subject.remainder.trim()) return
|
|
233
244
|
|
|
234
|
-
|
|
245
|
+
let request: POILiveSearchRequest
|
|
246
|
+
|
|
247
|
+
if (subject.kind === "brand") {
|
|
248
|
+
if (!brandLiveSearch || !subject.wikidata) return
|
|
249
|
+
request = { kind: "brand", brandName: subject.name, wikidata: subject.wikidata, anchor: subject.remainder }
|
|
250
|
+
} else {
|
|
251
|
+
if (subject.buildLocal) return
|
|
252
|
+
|
|
253
|
+
request = {
|
|
254
|
+
kind: "category",
|
|
255
|
+
categoryID: subject.category.id,
|
|
256
|
+
overtureCategoryIDs: runtime.lookup.resolveOvertureCategories(subject.category.id),
|
|
257
|
+
anchor: subject.remainder,
|
|
258
|
+
}
|
|
259
|
+
}
|
|
235
260
|
|
|
236
261
|
setStoredLive({ query: trimmedText, state: { status: "loading" } })
|
|
237
262
|
|
|
238
263
|
try {
|
|
239
|
-
const
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
: {
|
|
248
|
-
categoryID: subject.category.id,
|
|
249
|
-
|
|
250
|
-
overtureCategoryIDs: runtime.lookup.resolveOvertureCategories(subject.category.id),
|
|
251
|
-
anchor: subject.remainder,
|
|
252
|
-
}
|
|
253
|
-
)
|
|
254
|
-
|
|
255
|
-
if (outcome.status === "success") {
|
|
264
|
+
const response = await runLiveSearch(request)
|
|
265
|
+
|
|
266
|
+
if (response.status === "success") {
|
|
267
|
+
setStoredLive({
|
|
268
|
+
query: trimmedText,
|
|
269
|
+
state: { status: "success", hits: response.hits, centerName: response.centerName },
|
|
270
|
+
})
|
|
271
|
+
} else if (response.status === "unplaced") {
|
|
256
272
|
setStoredLive({
|
|
257
273
|
query: trimmedText,
|
|
258
|
-
state: { status: "
|
|
274
|
+
state: { status: "error", message: `couldn't place "${response.anchor}"` },
|
|
259
275
|
})
|
|
260
|
-
} else if (outcome.status === "unplaced") {
|
|
261
|
-
setStoredLive({ query: trimmedText, state: { status: "error", message: `couldn't place "${outcome.anchor}"` } })
|
|
262
276
|
} else {
|
|
263
277
|
setStoredLive({
|
|
264
278
|
query: trimmedText,
|
package/lib/poi.ts
CHANGED
|
@@ -39,15 +39,10 @@ export interface ReleaseManifest<TRelease extends ReleaseBase = ReleaseBase> {
|
|
|
39
39
|
*/
|
|
40
40
|
export interface AssetsLoadContext {
|
|
41
41
|
/**
|
|
42
|
-
* The signal aborts when a version
|
|
42
|
+
* The signal aborts when a version switch supersedes this load or when the component unmounts.
|
|
43
43
|
*/
|
|
44
44
|
signal: AbortSignal
|
|
45
45
|
|
|
46
|
-
/**
|
|
47
|
-
* Whether this load should use the CPU WASM backend instead of WebGPU.
|
|
48
|
-
*/
|
|
49
|
-
forceWASM: boolean
|
|
50
|
-
|
|
51
46
|
/**
|
|
52
47
|
* Sets the progress line, such as `Loading v7 model (~28 MB)…`.
|
|
53
48
|
*/
|
|
@@ -61,7 +56,7 @@ export interface AssetsLoadContext {
|
|
|
61
56
|
setStepIndex: (index: number) => void
|
|
62
57
|
|
|
63
58
|
/**
|
|
64
|
-
* Reports the
|
|
59
|
+
* Reports the neural runtime's backend and model size, such as `wasm (27 MB int8)`.
|
|
65
60
|
*/
|
|
66
61
|
setBackend: (backend: string) => void
|
|
67
62
|
|
|
@@ -87,9 +82,12 @@ export interface ReleaseRuntimeConfig<TAssets, TRelease extends ReleaseBase = Re
|
|
|
87
82
|
loadManifest: (signal: AbortSignal) => Promise<ReleaseManifest<TRelease> | null>
|
|
88
83
|
|
|
89
84
|
/**
|
|
90
|
-
* Loads the asset bundle for one release and reports progress through `ctx
|
|
91
|
-
*
|
|
92
|
-
*
|
|
85
|
+
* Loads the asset bundle for one release and reports progress through `ctx`.
|
|
86
|
+
*
|
|
87
|
+
* The hook calls it on every version change.
|
|
88
|
+
* It reports a rejection through `errorMessage`.
|
|
89
|
+
*
|
|
90
|
+
* It disposes a result that resolves after `ctx.signal` aborts.
|
|
93
91
|
*/
|
|
94
92
|
loadAssets: (release: TRelease, ctx: AssetsLoadContext) => Promise<TAssets>
|
|
95
93
|
|
|
@@ -106,7 +104,8 @@ export interface ReleaseRuntimeConfig<TAssets, TRelease extends ReleaseBase = Re
|
|
|
106
104
|
|
|
107
105
|
/**
|
|
108
106
|
* The progress line shown before the manifest arrives.
|
|
109
|
-
*
|
|
107
|
+
*
|
|
108
|
+
* @defaultValue `"Loading releases…"`
|
|
110
109
|
*/
|
|
111
110
|
initialProgress?: string
|
|
112
111
|
}
|
|
@@ -163,31 +162,19 @@ export interface ReleaseLoaderState<TAssets, TRelease extends ReleaseBase = Rele
|
|
|
163
162
|
errorMessage: string | null
|
|
164
163
|
|
|
165
164
|
/**
|
|
166
|
-
* The
|
|
167
|
-
* it is `""` before the
|
|
165
|
+
* The neural runtime's backend and model size, such as `wasm (27 MB int8)`;
|
|
166
|
+
* it is `""` before the model loads.
|
|
168
167
|
*/
|
|
169
168
|
activeBackend: string
|
|
170
169
|
|
|
171
|
-
/**
|
|
172
|
-
* Whether the CPU WASM backend is forced instead of WebGPU.
|
|
173
|
-
*/
|
|
174
|
-
forceWASM: boolean
|
|
175
|
-
|
|
176
170
|
/**
|
|
177
171
|
* Switches to another version, clearing any error and reloading the asset bundle.
|
|
178
172
|
*/
|
|
179
173
|
selectVersion: (version: string) => void
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Forces or releases the CPU WASM backend.
|
|
183
|
-
* Either change reloads the asset bundle.
|
|
184
|
-
*/
|
|
185
|
-
setForceWASM: (forceWASM: boolean) => void
|
|
186
174
|
}
|
|
187
175
|
|
|
188
176
|
/**
|
|
189
|
-
* Loads the release manifest on mount and the selected release's assets whenever
|
|
190
|
-
* the version or `forceWASM` changes.
|
|
177
|
+
* Loads the release manifest on mount and the selected release's assets whenever the version changes.
|
|
191
178
|
*
|
|
192
179
|
* Each reload aborts the previous load and disposes the old assets.
|
|
193
180
|
* `ready` becomes true after the new assets load.
|
|
@@ -206,7 +193,6 @@ export function useReleaseRuntime<TAssets, TRelease extends ReleaseBase = Releas
|
|
|
206
193
|
const [errorMessage, setErrorMessage] = useState<string | null>(null)
|
|
207
194
|
const [activeBackend, setActiveBackend] = useState<string>("")
|
|
208
195
|
const [loadingByteFraction, setLoadingByteFraction] = useState<number | null>(null)
|
|
209
|
-
const [forceWASM, setForceWASMState] = useState(false)
|
|
210
196
|
|
|
211
197
|
const loadManifestRef = useRef(config.loadManifest)
|
|
212
198
|
const loadAssetsRef = useRef(config.loadAssets)
|
|
@@ -279,7 +265,6 @@ export function useReleaseRuntime<TAssets, TRelease extends ReleaseBase = Releas
|
|
|
279
265
|
|
|
280
266
|
const ctx: AssetsLoadContext = {
|
|
281
267
|
signal,
|
|
282
|
-
forceWASM,
|
|
283
268
|
setProgress: (progress) => guard(() => setLoadingProgress(progress)),
|
|
284
269
|
setStepLabels: (labels) => guard(() => setLoadingStepLabels(labels)),
|
|
285
270
|
setStepIndex: (index) => guard(() => setLoadingStepIndex(index)),
|
|
@@ -307,7 +292,7 @@ export function useReleaseRuntime<TAssets, TRelease extends ReleaseBase = Releas
|
|
|
307
292
|
})()
|
|
308
293
|
|
|
309
294
|
return () => controller.abort()
|
|
310
|
-
}, [selectedVersion
|
|
295
|
+
}, [selectedVersion])
|
|
311
296
|
|
|
312
297
|
useEffect(() => {
|
|
313
298
|
return () => {
|
|
@@ -326,8 +311,6 @@ export function useReleaseRuntime<TAssets, TRelease extends ReleaseBase = Releas
|
|
|
326
311
|
setErrorMessage(null)
|
|
327
312
|
}, [])
|
|
328
313
|
|
|
329
|
-
const setForceWASM = useCallback((next: boolean) => setForceWASMState(next), [])
|
|
330
|
-
|
|
331
314
|
const selectedRelease = useMemo(
|
|
332
315
|
() => manifest?.releases.find((r) => r.version === selectedVersion) ?? null,
|
|
333
316
|
[manifest, selectedVersion]
|
|
@@ -345,8 +328,6 @@ export function useReleaseRuntime<TAssets, TRelease extends ReleaseBase = Releas
|
|
|
345
328
|
loadingByteFraction,
|
|
346
329
|
errorMessage,
|
|
347
330
|
activeBackend,
|
|
348
|
-
forceWASM,
|
|
349
331
|
selectVersion,
|
|
350
|
-
setForceWASM,
|
|
351
332
|
}
|
|
352
333
|
}
|