@mailwoman/react 9.2.0 → 9.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/fonts.css +59 -0
- package/lib/common/About.tsx +89 -0
- package/{common → lib/common}/CopyButton.tsx +1 -1
- package/{common → lib/common}/KindBadge.tsx +2 -7
- package/{common → lib/common}/LoadingIndicator.tsx +1 -1
- package/lib/common/confidence-tiers.ts +50 -0
- package/lib/common/text-tokens.ts +88 -0
- package/{index.ts → lib/index.ts} +44 -42
- package/{map → lib/map}/CompareToggle.tsx +2 -2
- package/{map/GeocoderDemo.tsx → lib/map/Geocoder.tsx} +45 -44
- package/{map/DemoControls.tsx → lib/map/GeocoderControls.tsx} +19 -19
- package/{map/DemoMap.tsx → lib/map/MapCanvas.tsx} +16 -16
- package/{map → lib/map}/OverlayLayers.tsx +3 -3
- package/{map → lib/map}/PlaceAutocomplete.tsx +2 -2
- package/{map → lib/map}/PlaceMarker.tsx +1 -1
- package/{map → lib/map}/ResolvedPlaceLayers.tsx +5 -4
- package/{map → lib/map}/ResultCamera.tsx +3 -3
- package/{map → lib/map}/ResultOverlay.tsx +2 -2
- package/{map → lib/map}/ResultPanel.tsx +4 -3
- package/{map → lib/map}/VersionPicker.tsx +3 -3
- package/lib/map/fake-runtime.ts +122 -0
- package/{map → lib/map}/index.ts +26 -26
- package/lib/map/map-debug.ts +51 -0
- package/{map → lib/map}/place-render.ts +5 -4
- package/{map → lib/map}/types.ts +51 -46
- package/{map/useDemoGeocode.ts → lib/map/useGeocode.ts} +11 -11
- package/{map → lib/map}/useMapPlaceRender.ts +2 -2
- package/{map → lib/map}/usePlaceAutocomplete.ts +2 -2
- package/{pipeline → lib/pipeline}/CandidatePicker.tsx +2 -2
- package/{pipeline → lib/pipeline}/ComponentTable.tsx +1 -1
- package/lib/pipeline/ConfidenceCell.tsx +31 -0
- package/lib/pipeline/FailureDiagnostic.tsx +56 -0
- package/{pipeline → lib/pipeline}/PipelineExplorer.tsx +5 -4
- package/{pipeline → lib/pipeline}/QueryForm.tsx +2 -2
- package/{pipeline → lib/pipeline}/ResolvedPlace.tsx +17 -4
- package/lib/pipeline/SpanHighlight.tsx +97 -0
- package/lib/pipeline/TimingPanel.tsx +65 -0
- package/lib/pipeline/TreeView.tsx +55 -0
- package/{pipeline → lib/pipeline}/copy.ts +1 -1
- package/{pipeline → lib/pipeline}/presets.ts +2 -1
- package/{pipeline → lib/pipeline}/types.ts +2 -75
- package/{pipeline → lib/pipeline}/useParsePipeline.ts +2 -1
- package/{poi → lib/poi}/LiveResultsBlock.tsx +2 -2
- package/{poi → lib/poi}/POIExplorer.tsx +4 -3
- package/{poi → lib/poi}/SubjectPanel.tsx +1 -1
- package/{poi → lib/poi}/runtime.ts +3 -3
- package/{poi → lib/poi}/types.ts +3 -2
- package/{poi → lib/poi}/usePOISearch.ts +5 -5
- package/{runtime/useDemoRuntime.ts → lib/runtime/useReleaseRuntime.ts} +24 -26
- package/out/common/About.d.ts +12 -0
- package/out/common/About.d.ts.map +1 -0
- package/out/common/About.js +5 -0
- package/out/common/About.js.map +1 -0
- package/out/common/ClientOnly.d.ts.map +1 -1
- package/out/common/ClientOnly.js.map +1 -1
- package/out/common/CopyButton.d.ts.map +1 -1
- package/out/common/CopyButton.js +1 -1
- package/out/common/CopyButton.js.map +1 -1
- package/out/common/KindBadge.d.ts +2 -9
- package/out/common/KindBadge.d.ts.map +1 -1
- package/out/common/KindBadge.js.map +1 -1
- package/out/common/LoadingIndicator.d.ts.map +1 -1
- package/out/common/LoadingIndicator.js +1 -1
- package/out/common/LoadingIndicator.js.map +1 -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 +36 -0
- package/out/common/confidence-tiers.d.ts.map +1 -0
- package/out/common/confidence-tiers.js +42 -0
- package/out/common/confidence-tiers.js.map +1 -0
- package/out/common/cx.d.ts.map +1 -1
- package/out/common/cx.js.map +1 -1
- package/out/common/text-tokens.d.ts +46 -0
- package/out/common/text-tokens.d.ts.map +1 -0
- package/out/common/text-tokens.js +52 -0
- package/out/common/text-tokens.js.map +1 -0
- package/out/common/useClipboard.d.ts.map +1 -1
- package/out/common/useClipboard.js.map +1 -1
- package/out/common/useDebouncedValue.d.ts.map +1 -1
- package/out/common/useDebouncedValue.js.map +1 -1
- package/out/index.d.ts +27 -18
- package/out/index.d.ts.map +1 -1
- package/out/index.js +16 -10
- package/out/index.js.map +1 -1
- package/out/map/BackendControl.d.ts.map +1 -1
- package/out/map/BackendControl.js.map +1 -1
- package/out/map/CompareToggle.d.ts +2 -2
- package/out/map/CompareToggle.d.ts.map +1 -1
- package/out/map/CompareToggle.js.map +1 -1
- package/out/map/{GeocoderDemo.d.ts → Geocoder.d.ts} +17 -17
- package/out/map/Geocoder.d.ts.map +1 -0
- package/out/map/{GeocoderDemo.js → Geocoder.js} +30 -30
- package/out/map/Geocoder.js.map +1 -0
- package/out/map/GeocoderControls.d.ts +63 -0
- package/out/map/GeocoderControls.d.ts.map +1 -0
- package/out/map/{DemoControls.js → GeocoderControls.js} +2 -2
- package/out/map/GeocoderControls.js.map +1 -0
- package/out/map/{DemoMap.d.ts → MapCanvas.d.ts} +16 -16
- package/out/map/MapCanvas.d.ts.map +1 -0
- package/out/map/{DemoMap.js → MapCanvas.js} +2 -2
- package/out/map/MapCanvas.js.map +1 -0
- package/out/map/OverlayLayers.d.ts +3 -3
- 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 +1 -1
- package/out/map/PlaceAutocomplete.d.ts.map +1 -1
- package/out/map/PlaceAutocomplete.js +1 -1
- package/out/map/PlaceAutocomplete.js.map +1 -1
- package/out/map/PlaceMarker.d.ts +1 -1
- package/out/map/PlaceMarker.d.ts.map +1 -1
- package/out/map/PlaceMarker.js.map +1 -1
- package/out/map/ResolvedPlaceLayers.d.ts +4 -4
- package/out/map/ResolvedPlaceLayers.d.ts.map +1 -1
- package/out/map/ResolvedPlaceLayers.js.map +1 -1
- package/out/map/ResultCamera.d.ts +3 -3
- package/out/map/ResultCamera.d.ts.map +1 -1
- package/out/map/ResultCamera.js +2 -2
- package/out/map/ResultCamera.js.map +1 -1
- package/out/map/ResultOverlay.d.ts +2 -2
- package/out/map/ResultOverlay.d.ts.map +1 -1
- package/out/map/ResultOverlay.js.map +1 -1
- package/out/map/ResultPanel.d.ts +2 -2
- package/out/map/ResultPanel.d.ts.map +1 -1
- package/out/map/ResultPanel.js +1 -1
- package/out/map/ResultPanel.js.map +1 -1
- package/out/map/VersionPicker.d.ts +3 -3
- package/out/map/VersionPicker.d.ts.map +1 -1
- package/out/map/VersionPicker.js.map +1 -1
- package/out/map/fake-runtime.d.ts +38 -0
- package/out/map/fake-runtime.d.ts.map +1 -0
- package/out/map/fake-runtime.js +107 -0
- package/out/map/fake-runtime.js.map +1 -0
- package/out/map/geometry.d.ts.map +1 -1
- package/out/map/geometry.js.map +1 -1
- package/out/map/index.d.ts +19 -19
- package/out/map/index.d.ts.map +1 -1
- package/out/map/index.js +11 -11
- package/out/map/index.js.map +1 -1
- package/out/map/map-debug.d.ts +31 -0
- package/out/map/map-debug.d.ts.map +1 -0
- package/out/map/map-debug.js +31 -0
- package/out/map/map-debug.js.map +1 -0
- package/out/map/place-render.d.ts +3 -3
- package/out/map/place-render.d.ts.map +1 -1
- package/out/map/place-render.js +2 -2
- package/out/map/place-render.js.map +1 -1
- package/out/map/types.d.ts +50 -46
- package/out/map/types.d.ts.map +1 -1
- package/out/map/types.js +6 -6
- package/out/map/types.js.map +1 -1
- package/out/map/useCompareState.d.ts.map +1 -1
- package/out/map/useCompareState.js.map +1 -1
- package/out/map/{useDemoGeocode.d.ts → useGeocode.d.ts} +11 -11
- package/out/map/useGeocode.d.ts.map +1 -0
- package/out/map/{useDemoGeocode.js → useGeocode.js} +5 -5
- package/out/map/useGeocode.js.map +1 -0
- package/out/map/useMapPlaceRender.d.ts +1 -1
- package/out/map/useMapPlaceRender.d.ts.map +1 -1
- package/out/map/useMapPlaceRender.js +1 -1
- package/out/map/useMapPlaceRender.js.map +1 -1
- package/out/map/usePlaceAutocomplete.d.ts +1 -1
- package/out/map/usePlaceAutocomplete.d.ts.map +1 -1
- package/out/map/usePlaceAutocomplete.js +1 -1
- package/out/map/usePlaceAutocomplete.js.map +1 -1
- package/out/pipeline/CandidatePicker.d.ts +1 -1
- package/out/pipeline/CandidatePicker.d.ts.map +1 -1
- package/out/pipeline/CandidatePicker.js +1 -1
- package/out/pipeline/CandidatePicker.js.map +1 -1
- package/out/pipeline/ComponentTable.d.ts +1 -1
- package/out/pipeline/ComponentTable.d.ts.map +1 -1
- package/out/pipeline/ComponentTable.js.map +1 -1
- package/out/pipeline/ConfidenceCell.d.ts +2 -2
- package/out/pipeline/ConfidenceCell.d.ts.map +1 -1
- package/out/pipeline/ConfidenceCell.js +5 -17
- package/out/pipeline/ConfidenceCell.js.map +1 -1
- package/out/pipeline/FailureDiagnostic.d.ts +15 -0
- package/out/pipeline/FailureDiagnostic.d.ts.map +1 -0
- package/out/pipeline/FailureDiagnostic.js +21 -0
- package/out/pipeline/FailureDiagnostic.js.map +1 -0
- package/out/pipeline/PipelineExplorer.d.ts +1 -1
- package/out/pipeline/PipelineExplorer.d.ts.map +1 -1
- package/out/pipeline/PipelineExplorer.js +3 -3
- package/out/pipeline/PipelineExplorer.js.map +1 -1
- package/out/pipeline/QueryForm.d.ts +2 -2
- package/out/pipeline/QueryForm.d.ts.map +1 -1
- package/out/pipeline/QueryForm.js.map +1 -1
- package/out/pipeline/ResolvedPlace.d.ts +1 -1
- package/out/pipeline/ResolvedPlace.d.ts.map +1 -1
- package/out/pipeline/ResolvedPlace.js +4 -10
- package/out/pipeline/ResolvedPlace.js.map +1 -1
- package/out/pipeline/SpanHighlight.d.ts +23 -0
- package/out/pipeline/SpanHighlight.d.ts.map +1 -0
- package/out/pipeline/SpanHighlight.js +31 -0
- package/out/pipeline/SpanHighlight.js.map +1 -0
- package/out/pipeline/TimingPanel.d.ts +16 -0
- package/out/pipeline/TimingPanel.d.ts.map +1 -0
- package/out/pipeline/TimingPanel.js +20 -0
- package/out/pipeline/TimingPanel.js.map +1 -0
- package/out/pipeline/TreeView.d.ts +17 -0
- package/out/pipeline/TreeView.d.ts.map +1 -0
- package/out/pipeline/TreeView.js +15 -0
- package/out/pipeline/TreeView.js.map +1 -0
- package/out/pipeline/copy.d.ts +1 -1
- package/out/pipeline/copy.d.ts.map +1 -1
- package/out/pipeline/copy.js.map +1 -1
- package/out/pipeline/presets.d.ts.map +1 -1
- package/out/pipeline/presets.js +2 -1
- package/out/pipeline/presets.js.map +1 -1
- package/out/pipeline/types.d.ts +2 -68
- package/out/pipeline/types.d.ts.map +1 -1
- package/out/pipeline/types.js +1 -1
- package/out/pipeline/types.js.map +1 -1
- package/out/pipeline/useParsePipeline.d.ts +2 -1
- package/out/pipeline/useParsePipeline.d.ts.map +1 -1
- package/out/pipeline/useParsePipeline.js.map +1 -1
- package/out/poi/AbstainPanel.d.ts.map +1 -1
- package/out/poi/AbstainPanel.js.map +1 -1
- package/out/poi/LiveResultsBlock.d.ts +1 -1
- package/out/poi/LiveResultsBlock.d.ts.map +1 -1
- package/out/poi/LiveResultsBlock.js +1 -1
- package/out/poi/LiveResultsBlock.js.map +1 -1
- package/out/poi/OverpassBlock.d.ts.map +1 -1
- package/out/poi/OverpassBlock.js.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/QueryInput.d.ts.map +1 -1
- package/out/poi/QueryInput.js.map +1 -1
- package/out/poi/SubjectPanel.d.ts +1 -1
- package/out/poi/SubjectPanel.d.ts.map +1 -1
- package/out/poi/SubjectPanel.js.map +1 -1
- package/out/poi/runtime.d.ts +1 -1
- package/out/poi/runtime.d.ts.map +1 -1
- package/out/poi/runtime.js.map +1 -1
- package/out/poi/types.d.ts +3 -2
- package/out/poi/types.d.ts.map +1 -1
- package/out/poi/types.js +1 -1
- package/out/poi/types.js.map +1 -1
- package/out/poi/usePOISearch.d.ts +1 -1
- package/out/poi/usePOISearch.d.ts.map +1 -1
- package/out/poi/usePOISearch.js +4 -4
- package/out/poi/usePOISearch.js.map +1 -1
- package/out/runtime/{useDemoRuntime.d.ts → useReleaseRuntime.d.ts} +20 -22
- package/out/runtime/useReleaseRuntime.d.ts.map +1 -0
- package/out/runtime/{useDemoRuntime.js → useReleaseRuntime.js} +6 -6
- package/out/runtime/useReleaseRuntime.js.map +1 -0
- package/package.json +221 -34
- package/styleframe.config.ts +321 -0
- package/styles.css +1074 -664
- package/tokens/index.css +115 -0
- package/tokens/tokens.json +521 -0
- package/tokens/tokens.resolver.json +185 -0
- package/out/map/DemoControls.d.ts +0 -64
- package/out/map/DemoControls.d.ts.map +0 -1
- package/out/map/DemoControls.js.map +0 -1
- package/out/map/DemoMap.d.ts.map +0 -1
- package/out/map/DemoMap.js.map +0 -1
- package/out/map/GeocoderDemo.d.ts.map +0 -1
- package/out/map/GeocoderDemo.js.map +0 -1
- package/out/map/useDemoGeocode.d.ts.map +0 -1
- package/out/map/useDemoGeocode.js.map +0 -1
- package/out/runtime/useDemoRuntime.d.ts.map +0 -1
- package/out/runtime/useDemoRuntime.js.map +0 -1
- package/pipeline/ConfidenceCell.tsx +0 -43
- /package/{common → lib/common}/ClientOnly.tsx +0 -0
- /package/{common → lib/common}/PresetChips.tsx +0 -0
- /package/{common → lib/common}/cx.ts +0 -0
- /package/{common → lib/common}/useClipboard.ts +0 -0
- /package/{common → lib/common}/useDebouncedValue.ts +0 -0
- /package/{map → lib/map}/BackendControl.tsx +0 -0
- /package/{map → lib/map}/geometry.ts +0 -0
- /package/{map → lib/map}/useCompareState.ts +0 -0
- /package/{poi → lib/poi}/AbstainPanel.tsx +0 -0
- /package/{poi → lib/poi}/OverpassBlock.tsx +0 -0
- /package/{poi → lib/poi}/QueryInput.tsx +0 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* `ConfidenceCell` — a compact confidence bar + value for the component table. The fill colour follows the shared
|
|
7
|
+
* confidence tiers. Presentational.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { confidenceTierOrMid } from "#common/confidence-tiers"
|
|
11
|
+
import { cx } from "#common/cx"
|
|
12
|
+
|
|
13
|
+
export interface ConfidenceCellProps {
|
|
14
|
+
confidence?: number
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function ConfidenceCell({ confidence }: ConfidenceCellProps) {
|
|
18
|
+
if (confidence == null) return <span className="mw-conf__dash">—</span>
|
|
19
|
+
|
|
20
|
+
const pct = Math.max(0, Math.min(1, confidence)) * 100
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<div className="mw-conf">
|
|
24
|
+
<div
|
|
25
|
+
className={cx("mw-conf__bar", `mw-conf__bar--${confidenceTierOrMid(confidence)}`)}
|
|
26
|
+
style={{ width: `${pct}%` }}
|
|
27
|
+
/>
|
|
28
|
+
<span className="mw-conf__value">{confidence.toFixed(2)}</span>
|
|
29
|
+
</div>
|
|
30
|
+
)
|
|
31
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* `FailureDiagnostic` — what to say when nothing resolved. It reads the parsed components and names the missing
|
|
7
|
+
* piece a person can add (a city, a state), so the answer is a next step rather than "no hit".
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { ParsedComponent } from "@mailwoman/core/pipeline/client-result"
|
|
11
|
+
import type { ReactNode } from "react"
|
|
12
|
+
|
|
13
|
+
export interface FailureDiagnosticProps {
|
|
14
|
+
nodes: ParsedComponent[]
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function FailureDiagnostic({ nodes }: FailureDiagnosticProps): ReactNode {
|
|
18
|
+
const hasLocality = nodes.some((n) => n.tag === "locality")
|
|
19
|
+
const hasPostcode = nodes.some((n) => n.tag === "postcode")
|
|
20
|
+
const hasRegion = nodes.some((n) => n.tag === "region")
|
|
21
|
+
|
|
22
|
+
const hints: string[] = []
|
|
23
|
+
|
|
24
|
+
if (!hasLocality && !hasPostcode) {
|
|
25
|
+
hints.push(
|
|
26
|
+
"The parser found no city or postcode in this input. Try adding one — e.g. append ', Chicago, IL 60613'."
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (hasPostcode && !hasLocality) {
|
|
31
|
+
hints.push(
|
|
32
|
+
"Only a postcode was extracted. WOF ships placeholder coordinates (0, 0) for about 22% of US postcodes, and the cascade drops those."
|
|
33
|
+
)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (hasLocality && !hasRegion) {
|
|
37
|
+
hints.push(
|
|
38
|
+
"No state in the parse. US localities share names across states (Springfield, Portland, …); add a state to disambiguate."
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (!hints.length) {
|
|
43
|
+
hints.push("The parsed components look reasonable, but the gazetteer does not index this entry.")
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<div className="mw-failure">
|
|
48
|
+
<h2>No gazetteer hit</h2>
|
|
49
|
+
<ul>
|
|
50
|
+
{hints.map((hint, i) => (
|
|
51
|
+
<li key={i}>{hint}</li>
|
|
52
|
+
))}
|
|
53
|
+
</ul>
|
|
54
|
+
</div>
|
|
55
|
+
)
|
|
56
|
+
}
|
|
@@ -11,6 +11,11 @@
|
|
|
11
11
|
|
|
12
12
|
import type { ReactNode } from "react"
|
|
13
13
|
|
|
14
|
+
import { buildParsePayload } from "#pipeline/copy"
|
|
15
|
+
import { PIPELINE_DEFAULT_ADDRESS, PIPELINE_PRESETS } from "#pipeline/presets"
|
|
16
|
+
import type { PipelinePanels, PipelineRuntime } from "#pipeline/types"
|
|
17
|
+
import { useParsePipeline } from "#pipeline/useParsePipeline"
|
|
18
|
+
|
|
14
19
|
import { ClientOnly } from "../common/ClientOnly.tsx"
|
|
15
20
|
import { CopyButton } from "../common/CopyButton.tsx"
|
|
16
21
|
import { KindBadge } from "../common/KindBadge.tsx"
|
|
@@ -18,12 +23,8 @@ import { LoadingIndicator } from "../common/LoadingIndicator.tsx"
|
|
|
18
23
|
import { PresetChips, type Preset } from "../common/PresetChips.tsx"
|
|
19
24
|
import { CandidatePicker } from "./CandidatePicker.tsx"
|
|
20
25
|
import { ComponentTable } from "./ComponentTable.tsx"
|
|
21
|
-
import { buildParsePayload } from "./copy.ts"
|
|
22
|
-
import { PIPELINE_DEFAULT_ADDRESS, PIPELINE_PRESETS } from "./presets.ts"
|
|
23
26
|
import { QueryForm } from "./QueryForm.tsx"
|
|
24
27
|
import { ResolvedPlace } from "./ResolvedPlace.tsx"
|
|
25
|
-
import type { PipelinePanels, PipelineRuntime } from "./types.ts"
|
|
26
|
-
import { useParsePipeline } from "./useParsePipeline.ts"
|
|
27
28
|
|
|
28
29
|
export interface PipelineExplorerProps {
|
|
29
30
|
/**
|
|
@@ -19,11 +19,11 @@ export interface QueryFormProps {
|
|
|
19
19
|
busy?: boolean
|
|
20
20
|
placeholder?: string
|
|
21
21
|
/**
|
|
22
|
-
* Keydown on the input — the
|
|
22
|
+
* Keydown on the input — the hook a combobox (the demo's place-autocomplete) needs for arrow/Enter/Esc nav.
|
|
23
23
|
*/
|
|
24
24
|
onKeyDown?: (event: KeyboardEvent<HTMLInputElement>) => void
|
|
25
25
|
/**
|
|
26
|
-
*
|
|
26
|
+
* Override for extra `<input>` attributes (aria-combobox props, `autoComplete`, …). Merged last.
|
|
27
27
|
*/
|
|
28
28
|
inputProps?: InputHTMLAttributes<HTMLInputElement>
|
|
29
29
|
}
|
|
@@ -7,10 +7,9 @@
|
|
|
7
7
|
* optional dual-role note. Presentational.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
import type { DualRoleView, ResolvedPlaceView } from "@mailwoman/core/pipeline/client-result"
|
|
10
11
|
import { Fragment, type ReactNode } from "react"
|
|
11
12
|
|
|
12
|
-
import type { DualRoleView, ResolvedPlaceView } from "./types.ts"
|
|
13
|
-
|
|
14
13
|
export interface ResolvedPlaceProps {
|
|
15
14
|
place: ResolvedPlaceView
|
|
16
15
|
dualRoles?: DualRoleView[]
|
|
@@ -25,8 +24,22 @@ export function ResolvedPlace({ place, dualRoles }: ResolvedPlaceProps): ReactNo
|
|
|
25
24
|
<dd>{place.name}</dd>
|
|
26
25
|
<dt>placetype</dt>
|
|
27
26
|
<dd>{place.placetype}</dd>
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
{place.tier ? (
|
|
28
|
+
// A street-tier answer is not a gazetteer place: it carries a precision instead of an id.
|
|
29
|
+
<>
|
|
30
|
+
<dt>precision</dt>
|
|
31
|
+
<dd>
|
|
32
|
+
{place.tier === "address_point"
|
|
33
|
+
? "📍 exact address point (≤10 m)"
|
|
34
|
+
: `≈ interpolated · ±${place.uncertaintyM ?? "?"} m`}
|
|
35
|
+
</dd>
|
|
36
|
+
</>
|
|
37
|
+
) : (
|
|
38
|
+
<>
|
|
39
|
+
<dt>WOF id</dt>
|
|
40
|
+
<dd>{place.id}</dd>
|
|
41
|
+
</>
|
|
42
|
+
)}
|
|
30
43
|
<dt>coords</dt>
|
|
31
44
|
<dd>
|
|
32
45
|
{place.lat.toFixed(4)}, {place.lon.toFixed(4)}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* `SpanHighlight` — a displaCy-style span ribbon over the raw input: each tagged span is a column with the text on
|
|
7
|
+
* top, tinted by its confidence tier, and the tag beneath. Gaps (delimiters, unparsed characters) fall through as
|
|
8
|
+
* plain text, so a dropped span is visible as a literal break in the colour.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { ParsedComponent } from "@mailwoman/core/pipeline/client-result"
|
|
12
|
+
import type { ReactNode } from "react"
|
|
13
|
+
|
|
14
|
+
import { confidenceTierOrMid } from "#common/confidence-tiers"
|
|
15
|
+
import { shortestSpanOwners } from "#common/text-tokens"
|
|
16
|
+
|
|
17
|
+
export interface SpanHighlightProps {
|
|
18
|
+
/**
|
|
19
|
+
* The raw text handed to the parser — `nodes[].start/end` index into this.
|
|
20
|
+
*/
|
|
21
|
+
input: string
|
|
22
|
+
/**
|
|
23
|
+
* Flattened parse nodes; only those with numeric `start`/`end` are rendered.
|
|
24
|
+
*/
|
|
25
|
+
nodes: ParsedComponent[]
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface Segment {
|
|
29
|
+
text: string
|
|
30
|
+
node: ParsedComponent | null
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
type Span = ParsedComponent & { start: number; end: number }
|
|
34
|
+
|
|
35
|
+
export function SpanHighlight({ input, nodes }: SpanHighlightProps): ReactNode {
|
|
36
|
+
if (!input) return null
|
|
37
|
+
|
|
38
|
+
// Keep only well-formed spans that index into the input.
|
|
39
|
+
const spans = nodes.filter(
|
|
40
|
+
(n): n is Span =>
|
|
41
|
+
typeof n.start === "number" &&
|
|
42
|
+
typeof n.end === "number" &&
|
|
43
|
+
n.start >= 0 &&
|
|
44
|
+
n.end > n.start &&
|
|
45
|
+
n.end <= input.length
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
if (!spans.length) return null
|
|
49
|
+
|
|
50
|
+
// Per-character owner: the most specific (shortest) span covering it, the same rule the word-level panels apply
|
|
51
|
+
// per word. The leaf always wins whatever nesting the tree hands over, so every character renders once.
|
|
52
|
+
const characters = Array.from({ length: input.length }, (_, i) => ({ start: i, end: i + 1 }))
|
|
53
|
+
const owner = shortestSpanOwners(characters, spans)
|
|
54
|
+
|
|
55
|
+
// Coalesce runs of the same owner into segments.
|
|
56
|
+
const segments: Segment[] = []
|
|
57
|
+
let from = 0
|
|
58
|
+
|
|
59
|
+
for (let i = 1; i <= input.length; i++) {
|
|
60
|
+
if (i === input.length || owner[i] !== owner[from]) {
|
|
61
|
+
const ownerIndex = owner[from] ?? -1
|
|
62
|
+
|
|
63
|
+
segments.push({ text: input.slice(from, i), node: ownerIndex === -1 ? null : (spans[ownerIndex] ?? null) })
|
|
64
|
+
|
|
65
|
+
from = i
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return (
|
|
70
|
+
<div className="mw-spans">
|
|
71
|
+
<div className="mw-spans__legend">
|
|
72
|
+
<span>confidence</span>
|
|
73
|
+
<span className="mw-spans__swatch mw-spans__swatch--low" /> low
|
|
74
|
+
<span className="mw-spans__swatch mw-spans__swatch--mid" /> mid
|
|
75
|
+
<span className="mw-spans__swatch mw-spans__swatch--high" /> high
|
|
76
|
+
</div>
|
|
77
|
+
<div className="mw-spans__track">
|
|
78
|
+
{segments.map((seg, i) =>
|
|
79
|
+
seg.node ? (
|
|
80
|
+
<span
|
|
81
|
+
key={i}
|
|
82
|
+
className={`mw-spans__seg mw-spans__seg--${confidenceTierOrMid(seg.node.confidence)}`}
|
|
83
|
+
title={`${seg.node.tag}${seg.node.confidence != null ? ` · ${seg.node.confidence.toFixed(2)}` : ""}`}
|
|
84
|
+
>
|
|
85
|
+
<span className="mw-spans__text">{seg.text}</span>
|
|
86
|
+
<span className="mw-spans__tag">{seg.node.tag}</span>
|
|
87
|
+
</span>
|
|
88
|
+
) : (
|
|
89
|
+
<span key={i} className="mw-spans__gap">
|
|
90
|
+
{seg.text}
|
|
91
|
+
</span>
|
|
92
|
+
)
|
|
93
|
+
)}
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
)
|
|
97
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* `TimingPanel` — the per-stage timing breakdown: a stacked bar sized by each stage's wall-clock, plus a legend.
|
|
7
|
+
* Stage colours are distinct hues, never the confidence red/amber/green, because they encode the pipeline stage and
|
|
8
|
+
* not quality.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { StageTiming } from "@mailwoman/core/pipeline/client-result"
|
|
12
|
+
import type { ReactNode } from "react"
|
|
13
|
+
|
|
14
|
+
export interface TimingPanelProps {
|
|
15
|
+
timing: StageTiming
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const STAGES: ReadonlyArray<{ key: keyof StageTiming; label: string }> = [
|
|
19
|
+
{ key: "shape", label: "shape + kind" },
|
|
20
|
+
{ key: "classify", label: "classify" },
|
|
21
|
+
{ key: "resolve", label: "resolve" },
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
function formatMilliseconds(ms: number): string {
|
|
25
|
+
return ms >= 100 ? `${Math.round(ms)} ms` : `${ms.toFixed(1)} ms`
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function TimingPanel({ timing }: TimingPanelProps): ReactNode {
|
|
29
|
+
const present = STAGES.flatMap((stage) => {
|
|
30
|
+
const ms = timing[stage.key]
|
|
31
|
+
|
|
32
|
+
return typeof ms === "number" ? [{ ...stage, ms }] : []
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
const total = present.reduce((sum, stage) => sum + stage.ms, 0)
|
|
36
|
+
|
|
37
|
+
if (total <= 0) return null
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<div className="mw-timing">
|
|
41
|
+
<div className="mw-timing__heading">
|
|
42
|
+
Timing <span className="mw-timing__total">{formatMilliseconds(total)} total</span>
|
|
43
|
+
</div>
|
|
44
|
+
<div className="mw-timing__bar">
|
|
45
|
+
{present.map((stage) => (
|
|
46
|
+
// The rendered width is floored so a sub-millisecond stage stays visible as a sliver.
|
|
47
|
+
<div
|
|
48
|
+
key={stage.key}
|
|
49
|
+
className={`mw-timing__seg mw-timing__seg--${stage.key}`}
|
|
50
|
+
style={{ width: `${Math.max((stage.ms / total) * 100, 1.5)}%` }}
|
|
51
|
+
title={`${stage.label}: ${formatMilliseconds(stage.ms)}`}
|
|
52
|
+
/>
|
|
53
|
+
))}
|
|
54
|
+
</div>
|
|
55
|
+
<div className="mw-timing__legend">
|
|
56
|
+
{present.map((stage) => (
|
|
57
|
+
<span key={stage.key} className="mw-timing__item">
|
|
58
|
+
<span className={`mw-timing__swatch mw-timing__seg--${stage.key}`} />
|
|
59
|
+
{stage.label} <span className="mw-timing__ms">{formatMilliseconds(stage.ms)}</span>
|
|
60
|
+
</span>
|
|
61
|
+
))}
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
)
|
|
65
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* `TreeView` — the parse's containment tree as nested lists with a guide rail per level. The tag tint follows the
|
|
7
|
+
* confidence tier; the value and score render in monospace.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { ReactNode } from "react"
|
|
11
|
+
|
|
12
|
+
import { confidenceTierOrMid } from "#common/confidence-tiers"
|
|
13
|
+
|
|
14
|
+
interface TreeNode {
|
|
15
|
+
tag?: string
|
|
16
|
+
value?: unknown
|
|
17
|
+
confidence?: number
|
|
18
|
+
children?: TreeNode[]
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface TreeViewProps {
|
|
22
|
+
/**
|
|
23
|
+
* The parser's `AddressTree` (`result.tree`): the view reads `.roots` and recurses `.children`.
|
|
24
|
+
*/
|
|
25
|
+
tree: unknown
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function renderNode(node: TreeNode, path: string): ReactNode {
|
|
29
|
+
if (typeof node.tag !== "string") return null
|
|
30
|
+
|
|
31
|
+
const kids = Array.isArray(node.children) ? node.children : []
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<li key={path} className="mw-tree__node">
|
|
35
|
+
<span className="mw-tree__row">
|
|
36
|
+
<span className={`mw-tree__tag mw-tree__tag--${confidenceTierOrMid(node.confidence)}`}>{node.tag}</span>
|
|
37
|
+
{node.value != null && String(node.value) !== "" ? (
|
|
38
|
+
<span className="mw-tree__value">{String(node.value)}</span>
|
|
39
|
+
) : null}
|
|
40
|
+
{typeof node.confidence === "number" ? (
|
|
41
|
+
<span className="mw-tree__conf">{node.confidence.toFixed(2)}</span>
|
|
42
|
+
) : null}
|
|
43
|
+
</span>
|
|
44
|
+
{kids.length ? <ul className="mw-tree__children">{kids.map((c, i) => renderNode(c, `${path}.${i}`))}</ul> : null}
|
|
45
|
+
</li>
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function TreeView({ tree }: TreeViewProps): ReactNode {
|
|
50
|
+
const roots = (tree as { roots?: unknown[] } | null | undefined)?.roots
|
|
51
|
+
|
|
52
|
+
if (!Array.isArray(roots) || !roots.length) return null
|
|
53
|
+
|
|
54
|
+
return <ul className="mw-tree mw-tree__children">{(roots as TreeNode[]).map((n, i) => renderNode(n, String(i)))}</ul>
|
|
55
|
+
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* pretty-printed. Pure; shared by the explorer's copy button.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import type { ParseResult, ResolvedPlaceView } from "
|
|
10
|
+
import type { ParseResult, ResolvedPlaceView } from "@mailwoman/core/pipeline/client-result"
|
|
11
11
|
|
|
12
12
|
export function buildParsePayload(result: ParseResult, selected: ResolvedPlaceView | null): string {
|
|
13
13
|
return JSON.stringify(
|
|
@@ -30,6 +30,7 @@ export const PIPELINE_PRESETS: ReadonlyArray<Preset> = [
|
|
|
30
30
|
{ label: "Space Needle", value: "400 Broad St, Seattle, WA 98109", country: "us" },
|
|
31
31
|
{ label: "ZIP only", value: "90210", country: "us" },
|
|
32
32
|
{ label: "Berlin (native order)", value: "Straußstraße 27, 12623 Berlin", country: "de" },
|
|
33
|
+
{ label: "Berlin city-state (int'l order)", value: "5 Hauptstraße, Berlin, Berlin 10115", country: "de" },
|
|
33
34
|
{ label: "Paris (street fall-through)", value: "181 Rue du Chevaleret, Paris", country: "fr" },
|
|
34
35
|
// GB dependent_locality (placetype-pair-prior arc) — "Henbury" flips to dependent_locality via the en-gb pair-index
|
|
35
36
|
// prior; the UK postcode is also structurally detectable (parity with docs EXAMPLE_ADDRESSES).
|
|
@@ -40,7 +41,7 @@ export const PIPELINE_PRESETS: ReadonlyArray<Preset> = [
|
|
|
40
41
|
},
|
|
41
42
|
// NZ dependent_locality (en-nz pair-prior arc) — Plimmerton is a suburb (dependent_locality) of Porirua. Postcode
|
|
42
43
|
// DELIBERATELY OMITTED: a trailing "Porirua 5026" folds "porirua 5026" in segment mode and misses the index's bare
|
|
43
|
-
// "porirua" key (tracked as #1308). The `country: "nz"` pin is
|
|
44
|
+
// "porirua" key (tracked as #1308). The `country: "nz"` pin is required — locale-hint can't structurally detect
|
|
44
45
|
// NZ (4-digit postcode isn't distinctive), so only the pin selects the nz index; free-typed NZ stays unfired.
|
|
45
46
|
{ label: "Plimmerton (NZ dependent_locality)", value: "35 Steyne Avenue, Plimmerton, Porirua", country: "nz" },
|
|
46
47
|
]
|
|
@@ -5,86 +5,13 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Types for the pipeline (parse + resolve) explorer. The model/gazetteer runtime is INJECTED as a
|
|
7
7
|
* {@link PipelineRuntime}: this package owns the UI state machine + presentation, while the host
|
|
8
|
-
* (the docs site's
|
|
8
|
+
* (the docs site's RuntimeEmbed, or any app) owns loading ONNX/WOF and executing a parse. That keeps
|
|
9
9
|
* onnxruntime-web, sql.js-httpvfs, and node builtins entirely out of this package's browser graph.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
+
import type { ParseResult } from "@mailwoman/core/pipeline/client-result"
|
|
12
13
|
import type { ReactNode } from "react"
|
|
13
14
|
|
|
14
|
-
import type { KindBadgeResult } from "../common/KindBadge.tsx"
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* One decoded component, as the table + span views render it. Offsets index into `ParseResult.input`.
|
|
18
|
-
*/
|
|
19
|
-
export interface ParsedComponent {
|
|
20
|
-
tag: string
|
|
21
|
-
value?: unknown
|
|
22
|
-
confidence?: number
|
|
23
|
-
start?: number
|
|
24
|
-
end?: number
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* A resolved gazetteer place, projected to what the "Resolved place" panel + copy payload need.
|
|
29
|
-
*/
|
|
30
|
-
export interface ResolvedPlaceView {
|
|
31
|
-
id: number
|
|
32
|
-
name: string
|
|
33
|
-
placetype: string
|
|
34
|
-
lat: number
|
|
35
|
-
lon: number
|
|
36
|
-
score: number
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* An additional admin role a resolved place also fulfils (the dual-role / city-state relation, #402).
|
|
41
|
-
*/
|
|
42
|
-
export interface DualRoleView {
|
|
43
|
-
id: number
|
|
44
|
-
name: string
|
|
45
|
-
placetype: string
|
|
46
|
-
relationshipType: string
|
|
47
|
-
role: string
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Per-stage wall-clock (ms) for one parse. `resolve` is absent when the lookup is skipped.
|
|
52
|
-
*/
|
|
53
|
-
export interface StageTiming {
|
|
54
|
-
shape: number
|
|
55
|
-
classify: number
|
|
56
|
-
resolve?: number
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* FST gazetteer-prior provenance, as the "FST prior" disclosure renders it.
|
|
61
|
-
*/
|
|
62
|
-
export interface FSTProvenance {
|
|
63
|
-
builtAt: string
|
|
64
|
-
stateCount: number
|
|
65
|
-
placeCount: number
|
|
66
|
-
importanceMatches: number
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* The presentational projection of one parse+resolve. The host's `runParse` produces it.
|
|
71
|
-
*/
|
|
72
|
-
export interface ParseResult {
|
|
73
|
-
input: string
|
|
74
|
-
/**
|
|
75
|
-
* Opaque hierarchy — handed straight to a host-injected tree/visualizer panel.
|
|
76
|
-
*/
|
|
77
|
-
tree: unknown
|
|
78
|
-
nodes: ParsedComponent[]
|
|
79
|
-
kindResult?: KindBadgeResult
|
|
80
|
-
timing?: StageTiming
|
|
81
|
-
resolved: ResolvedPlaceView | null
|
|
82
|
-
candidates: ResolvedPlaceView[]
|
|
83
|
-
fstActive: boolean
|
|
84
|
-
fstProvenance?: FSTProvenance | null
|
|
85
|
-
dualRoles?: DualRoleView[]
|
|
86
|
-
}
|
|
87
|
-
|
|
88
15
|
/**
|
|
89
16
|
* Bundle-load progress surfaced before the runtime is `ready`.
|
|
90
17
|
*/
|
|
@@ -9,9 +9,10 @@
|
|
|
9
9
|
* contract and shapes the UI state.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
+
import type { ParseResult, ResolvedPlaceView } from "@mailwoman/core/pipeline/client-result"
|
|
12
13
|
import { useCallback, useState } from "react"
|
|
13
14
|
|
|
14
|
-
import type {
|
|
15
|
+
import type { PipelineRuntime } from "#pipeline/types"
|
|
15
16
|
|
|
16
17
|
export interface UseParsePipelineOptions {
|
|
17
18
|
runtime: PipelineRuntime
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
|
|
11
11
|
import type { ReactNode } from "react"
|
|
12
12
|
|
|
13
|
-
import { formatDistance } from "
|
|
14
|
-
import type { LiveSearchState } from "
|
|
13
|
+
import { formatDistance } from "#poi/runtime"
|
|
14
|
+
import type { LiveSearchState } from "#poi/types"
|
|
15
15
|
|
|
16
16
|
export interface LiveResultsBlockProps {
|
|
17
17
|
/**
|
|
@@ -11,6 +11,10 @@
|
|
|
11
11
|
|
|
12
12
|
import { type ReactNode, useState } from "react"
|
|
13
13
|
|
|
14
|
+
import { POI_DEFAULT_TEXT, POI_PRESETS } from "#poi/runtime"
|
|
15
|
+
import type { LoadPOIRuntime, POILiveSearch } from "#poi/types"
|
|
16
|
+
import { usePOISearch } from "#poi/usePOISearch"
|
|
17
|
+
|
|
14
18
|
import { ClientOnly } from "../common/ClientOnly.tsx"
|
|
15
19
|
import { KindBadge } from "../common/KindBadge.tsx"
|
|
16
20
|
import { PresetChips, type Preset } from "../common/PresetChips.tsx"
|
|
@@ -18,10 +22,7 @@ import { AbstainPanel } from "./AbstainPanel.tsx"
|
|
|
18
22
|
import { LiveResultsBlock } from "./LiveResultsBlock.tsx"
|
|
19
23
|
import { OverpassBlock } from "./OverpassBlock.tsx"
|
|
20
24
|
import { QueryInput } from "./QueryInput.tsx"
|
|
21
|
-
import { POI_DEFAULT_TEXT, POI_PRESETS } from "./runtime.ts"
|
|
22
25
|
import { SubjectPanel } from "./SubjectPanel.tsx"
|
|
23
|
-
import type { LoadPOIRuntime, POILiveSearch } from "./types.ts"
|
|
24
|
-
import { usePOISearch } from "./usePOISearch.ts"
|
|
25
26
|
|
|
26
27
|
export interface POIExplorerProps {
|
|
27
28
|
/**
|
|
@@ -13,7 +13,7 @@ import { createKindClassifier } from "@mailwoman/kind-classifier"
|
|
|
13
13
|
import type { POIPhraseLookup } from "@mailwoman/kind-classifier"
|
|
14
14
|
import { createPOIBrandLookup, createPOITaxonomyLookup } from "@mailwoman/poi-taxonomy/table"
|
|
15
15
|
|
|
16
|
-
import type { POIRuntime } from "
|
|
16
|
+
import type { POIRuntime } from "#poi/types"
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* Build the POI runtime, dynamically importing the taxonomy + brand JSON so the tables land in their own chunk. A
|
|
@@ -31,8 +31,8 @@ export async function loadPOIRuntime(): Promise<POIRuntime> {
|
|
|
31
31
|
import("@mailwoman/poi-taxonomy/data/brands.json").then((m) => m.default),
|
|
32
32
|
])
|
|
33
33
|
|
|
34
|
-
const lookup = createPOITaxonomyLookup(table as
|
|
35
|
-
const brands = createPOIBrandLookup(brandTable as
|
|
34
|
+
const lookup = createPOITaxonomyLookup(table as Parameters<typeof createPOITaxonomyLookup>[0])
|
|
35
|
+
const brands = createPOIBrandLookup(brandTable as Parameters<typeof createPOIBrandLookup>[0])
|
|
36
36
|
|
|
37
37
|
// Adapt the taxonomy + brand lookups to the `POIPhraseLookup` shape the classifier expects: categories first, brands
|
|
38
38
|
// on a category miss.
|
package/{poi → lib/poi}/types.ts
RENAMED
|
@@ -5,11 +5,12 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Types for the POI explorer. The intent path (classification → subject → OverpassQL) is fully
|
|
7
7
|
* self-contained over the pure `@mailwoman/*` packages; the live poi.db path is expressed only as an
|
|
8
|
-
* INJECTED async function ({@link POILiveSearch}) so the httpvfs/worker
|
|
8
|
+
* INJECTED async function ({@link POILiveSearch}) so the httpvfs/worker implementation stays out of this
|
|
9
9
|
* package's browser graph (it lives in the docs site, which knows where the layer is served).
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import type {
|
|
12
|
+
import type { QueryKindResult } from "@mailwoman/core/pipeline"
|
|
13
|
+
import type { POIPhraseLookup, createKindClassifier } from "@mailwoman/kind-classifier"
|
|
13
14
|
import type { createPOITaxonomyLookup } from "@mailwoman/poi-taxonomy/table"
|
|
14
15
|
|
|
15
16
|
export type TaxonomyLookup = ReturnType<typeof createPOITaxonomyLookup>
|
|
@@ -15,9 +15,9 @@ import type { OverpassIntentLike } from "@mailwoman/poi-taxonomy/overpass"
|
|
|
15
15
|
import { computeQueryShape } from "@mailwoman/query-shape"
|
|
16
16
|
import { useCallback, useEffect, useEffectEvent, useState } from "react"
|
|
17
17
|
|
|
18
|
-
import { useDebouncedValue } from "
|
|
19
|
-
import { loadPOIRuntime } from "
|
|
20
|
-
import type { LiveSearchState, LoadPOIRuntime, POIExplorerResult, POILiveSearch, POIRuntime } from "
|
|
18
|
+
import { useDebouncedValue } from "#common/useDebouncedValue"
|
|
19
|
+
import { loadPOIRuntime } from "#poi/runtime"
|
|
20
|
+
import type { LiveSearchState, LoadPOIRuntime, POIExplorerResult, POILiveSearch, POIRuntime } from "#poi/types"
|
|
21
21
|
|
|
22
22
|
export interface UsePOISearchOptions {
|
|
23
23
|
/**
|
|
@@ -84,12 +84,12 @@ function buildOverpass(
|
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
const intent: OverpassIntentLike = {
|
|
87
|
-
subject: { kind: "category", categoryID, matched: matchedPhrase },
|
|
87
|
+
subject: { kind: "category", categoryIDs: [categoryID], matched: matchedPhrase },
|
|
88
88
|
...(remainder ? { anchor: { text: remainder } } : {}),
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
try {
|
|
92
|
-
return { overpassQL: emitOverpassQL(intent, category.osmTag ? {
|
|
92
|
+
return { overpassQL: emitOverpassQL(intent, category.osmTag ? { osmTags: [category.osmTag] } : {}) }
|
|
93
93
|
} catch (error) {
|
|
94
94
|
return { overpassError: error instanceof Error ? error.message : String(error) }
|
|
95
95
|
}
|