@mailwoman/react 9.3.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.
Files changed (159) hide show
  1. package/fonts.css +59 -0
  2. package/lib/common/About.tsx +89 -0
  3. package/lib/common/KindBadge.tsx +2 -7
  4. package/lib/common/confidence-tiers.ts +50 -0
  5. package/lib/common/text-tokens.ts +88 -0
  6. package/lib/index.ts +30 -28
  7. package/lib/map/CompareToggle.tsx +2 -2
  8. package/lib/map/{GeocoderDemo.tsx → Geocoder.tsx} +40 -40
  9. package/lib/map/{DemoControls.tsx → GeocoderControls.tsx} +16 -17
  10. package/lib/map/{DemoMap.tsx → MapCanvas.tsx} +15 -15
  11. package/lib/map/PlaceMarker.tsx +1 -1
  12. package/lib/map/ResolvedPlaceLayers.tsx +3 -3
  13. package/lib/map/ResultCamera.tsx +1 -1
  14. package/lib/map/ResultPanel.tsx +2 -2
  15. package/lib/map/VersionPicker.tsx +3 -3
  16. package/lib/map/fake-runtime.ts +122 -0
  17. package/lib/map/index.ts +16 -16
  18. package/lib/map/map-debug.ts +51 -0
  19. package/lib/map/place-render.ts +3 -2
  20. package/lib/map/types.ts +41 -39
  21. package/lib/map/{useDemoGeocode.ts → useGeocode.ts} +8 -8
  22. package/lib/pipeline/CandidatePicker.tsx +1 -1
  23. package/lib/pipeline/ComponentTable.tsx +1 -2
  24. package/lib/pipeline/ConfidenceCell.tsx +7 -19
  25. package/lib/pipeline/FailureDiagnostic.tsx +56 -0
  26. package/lib/pipeline/ResolvedPlace.tsx +17 -4
  27. package/lib/pipeline/SpanHighlight.tsx +97 -0
  28. package/lib/pipeline/TimingPanel.tsx +65 -0
  29. package/lib/pipeline/TreeView.tsx +55 -0
  30. package/lib/pipeline/copy.ts +1 -1
  31. package/lib/pipeline/types.ts +2 -75
  32. package/lib/pipeline/useParsePipeline.ts +2 -1
  33. package/lib/poi/types.ts +2 -1
  34. package/lib/runtime/{useDemoRuntime.ts → useReleaseRuntime.ts} +22 -24
  35. package/out/common/About.d.ts +12 -0
  36. package/out/common/About.d.ts.map +1 -0
  37. package/out/common/About.js +5 -0
  38. package/out/common/About.js.map +1 -0
  39. package/out/common/KindBadge.d.ts +2 -9
  40. package/out/common/KindBadge.d.ts.map +1 -1
  41. package/out/common/KindBadge.js.map +1 -1
  42. package/out/common/confidence-tiers.d.ts +36 -0
  43. package/out/common/confidence-tiers.d.ts.map +1 -0
  44. package/out/common/confidence-tiers.js +42 -0
  45. package/out/common/confidence-tiers.js.map +1 -0
  46. package/out/common/text-tokens.d.ts +46 -0
  47. package/out/common/text-tokens.d.ts.map +1 -0
  48. package/out/common/text-tokens.js +52 -0
  49. package/out/common/text-tokens.js.map +1 -0
  50. package/out/index.d.ts +14 -5
  51. package/out/index.d.ts.map +1 -1
  52. package/out/index.js +8 -2
  53. package/out/index.js.map +1 -1
  54. package/out/map/CompareToggle.d.ts +2 -2
  55. package/out/map/CompareToggle.d.ts.map +1 -1
  56. package/out/map/{GeocoderDemo.d.ts → Geocoder.d.ts} +17 -17
  57. package/out/map/Geocoder.d.ts.map +1 -0
  58. package/out/map/{GeocoderDemo.js → Geocoder.js} +25 -25
  59. package/out/map/Geocoder.js.map +1 -0
  60. package/out/map/{DemoControls.d.ts → GeocoderControls.d.ts} +16 -17
  61. package/out/map/GeocoderControls.d.ts.map +1 -0
  62. package/out/map/{DemoControls.js → GeocoderControls.js} +2 -2
  63. package/out/map/GeocoderControls.js.map +1 -0
  64. package/out/map/{DemoMap.d.ts → MapCanvas.d.ts} +15 -15
  65. package/out/map/MapCanvas.d.ts.map +1 -0
  66. package/out/map/{DemoMap.js → MapCanvas.js} +2 -2
  67. package/out/map/MapCanvas.js.map +1 -0
  68. package/out/map/PlaceMarker.d.ts +1 -1
  69. package/out/map/ResolvedPlaceLayers.d.ts +3 -3
  70. package/out/map/ResultCamera.d.ts +1 -1
  71. package/out/map/ResultCamera.js +1 -1
  72. package/out/map/ResultPanel.d.ts +2 -2
  73. package/out/map/ResultPanel.d.ts.map +1 -1
  74. package/out/map/ResultPanel.js.map +1 -1
  75. package/out/map/VersionPicker.d.ts +3 -3
  76. package/out/map/VersionPicker.d.ts.map +1 -1
  77. package/out/map/fake-runtime.d.ts +38 -0
  78. package/out/map/fake-runtime.d.ts.map +1 -0
  79. package/out/map/fake-runtime.js +107 -0
  80. package/out/map/fake-runtime.js.map +1 -0
  81. package/out/map/index.d.ts +10 -10
  82. package/out/map/index.d.ts.map +1 -1
  83. package/out/map/index.js +6 -6
  84. package/out/map/index.js.map +1 -1
  85. package/out/map/map-debug.d.ts +31 -0
  86. package/out/map/map-debug.d.ts.map +1 -0
  87. package/out/map/map-debug.js +31 -0
  88. package/out/map/map-debug.js.map +1 -0
  89. package/out/map/place-render.d.ts +2 -2
  90. package/out/map/place-render.d.ts.map +1 -1
  91. package/out/map/place-render.js +1 -1
  92. package/out/map/place-render.js.map +1 -1
  93. package/out/map/types.d.ts +41 -39
  94. package/out/map/types.d.ts.map +1 -1
  95. package/out/map/types.js +5 -5
  96. package/out/map/{useDemoGeocode.d.ts → useGeocode.d.ts} +9 -9
  97. package/out/map/useGeocode.d.ts.map +1 -0
  98. package/out/map/{useDemoGeocode.js → useGeocode.js} +4 -4
  99. package/out/map/useGeocode.js.map +1 -0
  100. package/out/pipeline/CandidatePicker.d.ts +1 -1
  101. package/out/pipeline/CandidatePicker.d.ts.map +1 -1
  102. package/out/pipeline/CandidatePicker.js.map +1 -1
  103. package/out/pipeline/ComponentTable.d.ts +1 -1
  104. package/out/pipeline/ComponentTable.d.ts.map +1 -1
  105. package/out/pipeline/ComponentTable.js.map +1 -1
  106. package/out/pipeline/ConfidenceCell.d.ts +2 -2
  107. package/out/pipeline/ConfidenceCell.d.ts.map +1 -1
  108. package/out/pipeline/ConfidenceCell.js +4 -16
  109. package/out/pipeline/ConfidenceCell.js.map +1 -1
  110. package/out/pipeline/FailureDiagnostic.d.ts +15 -0
  111. package/out/pipeline/FailureDiagnostic.d.ts.map +1 -0
  112. package/out/pipeline/FailureDiagnostic.js +21 -0
  113. package/out/pipeline/FailureDiagnostic.js.map +1 -0
  114. package/out/pipeline/ResolvedPlace.d.ts +1 -1
  115. package/out/pipeline/ResolvedPlace.d.ts.map +1 -1
  116. package/out/pipeline/ResolvedPlace.js +4 -10
  117. package/out/pipeline/ResolvedPlace.js.map +1 -1
  118. package/out/pipeline/SpanHighlight.d.ts +23 -0
  119. package/out/pipeline/SpanHighlight.d.ts.map +1 -0
  120. package/out/pipeline/SpanHighlight.js +31 -0
  121. package/out/pipeline/SpanHighlight.js.map +1 -0
  122. package/out/pipeline/TimingPanel.d.ts +16 -0
  123. package/out/pipeline/TimingPanel.d.ts.map +1 -0
  124. package/out/pipeline/TimingPanel.js +20 -0
  125. package/out/pipeline/TimingPanel.js.map +1 -0
  126. package/out/pipeline/TreeView.d.ts +17 -0
  127. package/out/pipeline/TreeView.d.ts.map +1 -0
  128. package/out/pipeline/TreeView.js +15 -0
  129. package/out/pipeline/TreeView.js.map +1 -0
  130. package/out/pipeline/copy.d.ts +1 -1
  131. package/out/pipeline/copy.d.ts.map +1 -1
  132. package/out/pipeline/types.d.ts +2 -68
  133. package/out/pipeline/types.d.ts.map +1 -1
  134. package/out/pipeline/types.js +1 -1
  135. package/out/pipeline/useParsePipeline.d.ts +2 -1
  136. package/out/pipeline/useParsePipeline.d.ts.map +1 -1
  137. package/out/pipeline/useParsePipeline.js.map +1 -1
  138. package/out/poi/types.d.ts +2 -1
  139. package/out/poi/types.d.ts.map +1 -1
  140. package/out/runtime/{useDemoRuntime.d.ts → useReleaseRuntime.d.ts} +18 -20
  141. package/out/runtime/useReleaseRuntime.d.ts.map +1 -0
  142. package/out/runtime/{useDemoRuntime.js → useReleaseRuntime.js} +4 -4
  143. package/out/runtime/useReleaseRuntime.js.map +1 -0
  144. package/package.json +139 -29
  145. package/styleframe.config.ts +321 -0
  146. package/styles.css +1074 -664
  147. package/tokens/index.css +115 -0
  148. package/tokens/tokens.json +521 -0
  149. package/tokens/tokens.resolver.json +185 -0
  150. package/out/map/DemoControls.d.ts.map +0 -1
  151. package/out/map/DemoControls.js.map +0 -1
  152. package/out/map/DemoMap.d.ts.map +0 -1
  153. package/out/map/DemoMap.js.map +0 -1
  154. package/out/map/GeocoderDemo.d.ts.map +0 -1
  155. package/out/map/GeocoderDemo.js.map +0 -1
  156. package/out/map/useDemoGeocode.d.ts.map +0 -1
  157. package/out/map/useDemoGeocode.js.map +0 -1
  158. package/out/runtime/useDemoRuntime.d.ts.map +0 -1
  159. package/out/runtime/useDemoRuntime.js.map +0 -1
@@ -3,22 +3,21 @@
3
3
  * @license AGPL-3.0
4
4
  * @author Teffen Ellis, et al.
5
5
  *
6
- * `<DemoControls>` — the geocoder demo's floating control panel, assembled from the demo-specific units
6
+ * `<GeocoderControls>` — the geocoder's floating control panel, assembled from the geocoder-specific units
7
7
  * (VersionPicker / CompareToggle / BackendControl / PlaceAutocomplete / ResultPanel) and the REUSED
8
- * pipeline units (QueryForm / PresetChips / LoadingIndicator). It is the presentational composition the
9
- * `_app.tsx` control `<section>` (`:1222-1514`) becomes it reads the injected {@link DemoRuntime} for
10
- * ready/version/backend/loading state and threads the {@link useDemoGeocode} + {@link usePlaceAutocomplete}
11
- * + {@link useCompareState} hooks into the controls. Host-specific visualizers arrive via {@link DemoPanels}.
8
+ * pipeline units (QueryForm / PresetChips / LoadingIndicator). It reads the injected {@link GeocoderRuntime}
9
+ * for ready/version/backend/loading state and threads the {@link useGeocode} + {@link usePlaceAutocomplete}
10
+ * + {@link useCompareState} hooks into the controls. Host-specific visualizers arrive via {@link GeocoderPanels}.
12
11
  *
13
- * NODE-SAFE: pure React + the shared/demo units, no maplibre. It rides `@mailwoman/react/map` as a
14
- * demo-specific control, not for WebGL.
12
+ * NODE-SAFE: pure React + the shared/geocoder units, no maplibre. It rides `@mailwoman/react/map` as a
13
+ * geocoder-specific control, not for WebGL.
15
14
  */
16
15
 
17
16
  import type { ReactNode } from "react"
18
17
 
19
- import type { DemoPanels, DemoRuntime } from "#map/types"
18
+ import type { GeocoderPanels, GeocoderRuntime } from "#map/types"
20
19
  import type { UseCompareState } from "#map/useCompareState"
21
- import type { UseDemoGeocode } from "#map/useDemoGeocode"
20
+ import type { UseGeocode } from "#map/useGeocode"
22
21
  import type { UsePlaceAutocomplete } from "#map/usePlaceAutocomplete"
23
22
 
24
23
  import { LoadingIndicator } from "../common/LoadingIndicator.tsx"
@@ -30,15 +29,15 @@ import { PlaceAutocomplete } from "./PlaceAutocomplete.tsx"
30
29
  import { ResultPanel } from "./ResultPanel.tsx"
31
30
  import { VersionPicker } from "./VersionPicker.tsx"
32
31
 
33
- export interface DemoControlsProps {
32
+ export interface GeocoderControlsProps {
34
33
  /**
35
- * The injected demo runtime.
34
+ * The injected geocoder runtime.
36
35
  */
37
- runtime: DemoRuntime
36
+ runtime: GeocoderRuntime
38
37
  /**
39
38
  * The parse+resolve state machine.
40
39
  */
41
- geocode: UseDemoGeocode
40
+ geocode: UseGeocode
42
41
  /**
43
42
  * The place-autocomplete combobox state.
44
43
  */
@@ -50,7 +49,7 @@ export interface DemoControlsProps {
50
49
  /**
51
50
  * Host-injected panels (about, release blurb, compare, permalink, extras, failure).
52
51
  */
53
- panels: DemoPanels
52
+ panels: GeocoderPanels
54
53
  /**
55
54
  * Example chips.
56
55
  */
@@ -60,7 +59,7 @@ export interface DemoControlsProps {
60
59
  */
61
60
  placeholder: string
62
61
  /**
63
- * Select a model version (the composed demo also clears a now-colliding compare selection).
62
+ * Select a model version (the composed geocoder also clears a now-colliding compare selection).
64
63
  */
65
64
  onSelectVersion: (version: string) => void
66
65
  /**
@@ -72,7 +71,7 @@ export interface DemoControlsProps {
72
71
  /**
73
72
  * The floating control panel.
74
73
  */
75
- export function DemoControls({
74
+ export function GeocoderControls({
76
75
  runtime,
77
76
  geocode,
78
77
  autocomplete,
@@ -82,7 +81,7 @@ export function DemoControls({
82
81
  placeholder,
83
82
  onSelectVersion,
84
83
  onForceWASMChange,
85
- }: DemoControlsProps): ReactNode {
84
+ }: GeocoderControlsProps): ReactNode {
86
85
  const versions = runtime.availableVersions ?? []
87
86
  const { busy, result, selectedCandidate } = geocode
88
87
  const loading = runtime.loading
@@ -3,7 +3,7 @@
3
3
  * @license AGPL-3.0
4
4
  * @author Teffen Ellis, et al.
5
5
  *
6
- * `<DemoMap>` — the declarative map shell for the geocoder demo, over `react-map-gl/maplibre` (v8).
6
+ * `<MapCanvas>` — the declarative map shell for the geocoder demo, over `react-map-gl/maplibre` (v8).
7
7
  * Phase 1 is the shell only: a `<Map>` that takes a host-composed `mapStyle`, an initial (or
8
8
  * controlled) view state, and a `children` slot for the overlays/markers that land in later phases.
9
9
  * No overlay/marker/camera logic lives here yet.
@@ -15,10 +15,10 @@
15
15
  * the root barrel.
16
16
  *
17
17
  * CSS: the package imports no CSS from its modules (the node-safe invariant), so a host that renders
18
- * `<DemoMap>` must import `maplibre-gl/dist/maplibre-gl.css` itself (plus `@mailwoman/react/styles.css`
19
- * for the `.mw-demo-map` container). `<DemoMap>` is intrinsically a client component — a host that
18
+ * `<MapCanvas>` must import `maplibre-gl/dist/maplibre-gl.css` itself (plus `@mailwoman/react/styles.css`
19
+ * for the `.mw-demo-map` container). `<MapCanvas>` is intrinsically a client component — a host that
20
20
  * server-renders should wrap it in a client boundary (the package's `ClientOnly`), exactly as the
21
- * composed `GeocoderDemo` will in a later phase.
21
+ * composed `Geocoder` will in a later phase.
22
22
  */
23
23
 
24
24
  import type { CSSProperties, ReactNode, Ref } from "react"
@@ -26,23 +26,23 @@ import { Map } from "react-map-gl/maplibre"
26
26
  import type { MapProps, MapRef, ViewStateChangeEvent } from "react-map-gl/maplibre"
27
27
 
28
28
  /**
29
- * The style a `<DemoMap>` renders — a style URL or an inline/composed `StyleSpecification`.
29
+ * The style a `<MapCanvas>` renders — a style URL or an inline/composed `StyleSpecification`.
30
30
  */
31
- export type DemoMapStyle = NonNullable<MapProps["mapStyle"]>
31
+ export type MapCanvasStyle = NonNullable<MapProps["mapStyle"]>
32
32
 
33
33
  /**
34
- * Override for the `<Map>` props `<DemoMap>` does not surface explicitly (e.g. `minZoom`, `attributionControl`,
35
- * `maplibreLogo`). The controlled fields DemoMap owns are omitted so they can't be set twice.
34
+ * Override for the `<Map>` props `<MapCanvas>` does not surface explicitly (e.g. `minZoom`, `attributionControl`,
35
+ * `maplibreLogo`). The controlled fields MapCanvas owns are omitted so they can't be set twice.
36
36
  */
37
- export type DemoMapExtraProps = Partial<
37
+ export type MapCanvasExtraProps = Partial<
38
38
  Omit<MapProps, "mapStyle" | "initialViewState" | "viewState" | "onMove" | "children" | "style" | "ref">
39
39
  >
40
40
 
41
- export interface DemoMapProps {
41
+ export interface MapCanvasProps {
42
42
  /**
43
43
  * The map style — host-composed `StyleSpecification` or a style URL.
44
44
  */
45
- mapStyle: DemoMapStyle
45
+ mapStyle: MapCanvasStyle
46
46
  /**
47
47
  * Uncontrolled initial camera. Use this OR `viewState`, not both.
48
48
  */
@@ -76,9 +76,9 @@ export interface DemoMapProps {
76
76
  */
77
77
  style?: CSSProperties
78
78
  /**
79
- * Remaining `<Map>` props DemoMap does not surface explicitly.
79
+ * Remaining `<Map>` props MapCanvas does not surface explicitly.
80
80
  */
81
- mapProps?: DemoMapExtraProps
81
+ mapProps?: MapCanvasExtraProps
82
82
  }
83
83
 
84
84
  const FILL: CSSProperties = { width: "100%", height: "100%" }
@@ -87,7 +87,7 @@ const FILL: CSSProperties = { width: "100%", height: "100%" }
87
87
  * The controlled-viewport map shell. Renders a sized wrapper around a `react-map-gl/maplibre` `<Map>`; everything
88
88
  * host-specific (the composed `mapStyle`, the initial center) is injected, and overlays ride in as `children`.
89
89
  */
90
- export function DemoMap({
90
+ export function MapCanvas({
91
91
  mapStyle,
92
92
  initialViewState,
93
93
  viewState,
@@ -98,7 +98,7 @@ export function DemoMap({
98
98
  className,
99
99
  style,
100
100
  mapProps,
101
- }: DemoMapProps): ReactNode {
101
+ }: MapCanvasProps): ReactNode {
102
102
  const wrapperClassName = className ? `mw-demo-map ${className}` : "mw-demo-map"
103
103
 
104
104
  return (
@@ -6,7 +6,7 @@
6
6
  * `<PlaceMarker>` — the resolved-place pin, as a declarative `react-map-gl/maplibre` `<Marker>`. This
7
7
  * replaces the old imperative `new maplibre.Marker(...).setLngLat(...).addTo(map)` (+ the manual
8
8
  * `markerRef.current.remove()` teardown) from the demo's redraw effect: mounting/unmounting the marker
9
- * is now React's job, keyed on the resolved candidate. Renders as a child of `<DemoMap>`.
9
+ * is now React's job, keyed on the resolved candidate. Renders as a child of `<MapCanvas>`.
10
10
  *
11
11
  * NODE-IMPORT SAFETY: imports `react-map-gl/maplibre` at module scope, so it is reachable ONLY through
12
12
  * the `@mailwoman/react/map` subpath, never the package root.
@@ -3,10 +3,10 @@
3
3
  * @license AGPL-3.0
4
4
  * @author Teffen Ellis, et al.
5
5
  *
6
- * `<ResolvedPlaceLayers>` — the drop-in that renders a whole {@link MapPlaceRenderSpec} as `<DemoMap>`
6
+ * `<ResolvedPlaceLayers>` — the drop-in that renders a whole {@link MapPlaceRenderSpec} as `<MapCanvas>`
7
7
  * children: the marker(s), the outline, and (optionally) the camera move. This is the declarative
8
8
  * replacement for the demo's imperative marker/bbox/camera redraw effect — a consumer computes the spec
9
- * with `useMapPlaceRender(place)` and drops `<ResolvedPlaceLayers spec={spec} />` inside `<DemoMap>`.
9
+ * with `useMapPlaceRender(place)` and drops `<ResolvedPlaceLayers spec={spec} />` inside `<MapCanvas>`.
10
10
  *
11
11
  * `spec = null` (no result / no candidate) renders nothing, which also unmounts the previous marker +
12
12
  * outline — the teardown the old effect did by hand (`markerRef.remove()`, `clearBbox`) is now just
@@ -28,7 +28,7 @@ export interface ResolvedPlaceLayersProps {
28
28
  spec: MapPlaceRenderSpec | null
29
29
  /**
30
30
  * Apply the computed camera target via {@link ResultCamera}. @default true. Set false when the consumer drives the
31
- * camera itself (e.g. a controlled `<DemoMap viewState>` fed by {@link cameraToViewState}).
31
+ * camera itself (e.g. a controlled `<MapCanvas viewState>` fed by {@link cameraToViewState}).
32
32
  */
33
33
  applyCamera?: boolean
34
34
  /**
@@ -11,7 +11,7 @@
11
11
  * `useMap()` (exactly as `DashboardMap`/`GeoJSONClipboardLayer` reach the map), never a threaded handle.
12
12
  *
13
13
  * A consumer that prefers a hard, declarative jump can instead feed the target through
14
- * {@link cameraToViewState} into a controlled `<DemoMap viewState>` and skip this component — the
14
+ * {@link cameraToViewState} into a controlled `<MapCanvas viewState>` and skip this component — the
15
15
  * `center` case has that declarative path; only `bounds` strictly requires this. Renders nothing.
16
16
  *
17
17
  * `target` is expected to be the STABLE, memoized `camera` off a `useMapPlaceRender` spec, so listing it
@@ -7,17 +7,17 @@
7
7
  * presentational units (it does not re-implement any of them): `KindBadge`, `ComponentTable`,
8
8
  * `ResolvedPlace`, `CandidatePicker`, plus the `CopyButton` + `buildParsePayload` copy affordance. This
9
9
  * is the standalone, story-testable unit the demo's floating panel renders (the map analogue of the
10
- * result block PipelineExplorer inlines), so `GeocoderDemo` composes ONE panel instead of duplicating
10
+ * result block PipelineExplorer inlines), so `Geocoder` composes ONE panel instead of duplicating
11
11
  * the marker/table/candidate glue. Heavy host visualizers (span highlight, tree, timing) slot in via
12
12
  * `extras`; the no-resolve diagnostic via `failure`.
13
13
  *
14
14
  * NODE-SAFE: pure React + the shared units, no maplibre.
15
15
  */
16
16
 
17
+ import type { ParseResult, ResolvedPlaceView } from "@mailwoman/core/pipeline/client-result"
17
18
  import type { ReactNode } from "react"
18
19
 
19
20
  import { buildParsePayload } from "#pipeline/copy"
20
- import type { ParseResult, ResolvedPlaceView } from "#pipeline/types"
21
21
 
22
22
  import { CopyButton } from "../common/CopyButton.tsx"
23
23
  import { KindBadge } from "../common/KindBadge.tsx"
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * `<VersionPicker>` — the model-version `<select>` from the demo's control panel (`_app.tsx:1230-1254`),
7
7
  * as a dumb presentational unit: the available bundles + current selection come in as props, the choice
8
- * goes out through `onSelect`. No load state, no manifest fetch — the host (via `useDemoRuntime`) owns
8
+ * goes out through `onSelect`. No load state, no manifest fetch — the host (via `useReleaseRuntime`) owns
9
9
  * that. Renders nothing when there is fewer than two versions to choose between.
10
10
  *
11
11
  * NODE-SAFE: pure React + a `<select>`, no maplibre. It rides the `@mailwoman/react/map` subpath only
@@ -14,13 +14,13 @@
14
14
 
15
15
  import type { ReactNode } from "react"
16
16
 
17
- import type { DemoVersionOption } from "#map/types"
17
+ import type { VersionOption } from "#map/types"
18
18
 
19
19
  export interface VersionPickerProps {
20
20
  /**
21
21
  * The selectable model bundles.
22
22
  */
23
- versions: ReadonlyArray<DemoVersionOption>
23
+ versions: ReadonlyArray<VersionOption>
24
24
  /**
25
25
  * The currently-selected version tag.
26
26
  */
@@ -0,0 +1,122 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ *
6
+ * A fake geocoder runtime: canned parse + resolve, an offline stub map style, canned autocomplete, a version list.
7
+ * No network, no ONNX, no maplibre at run time — everything is data. It is what the stories and component tests
8
+ * mount, and what a host mounts to show the UI without the model.
9
+ */
10
+
11
+ import type { ParseResult } from "@mailwoman/core/pipeline/client-result"
12
+
13
+ import type { ResolvedMapPlace } from "#map/place-render"
14
+ import type { GeocoderRuntime, Suggestion } from "#map/types"
15
+ import type { PipelineRuntime } from "#pipeline/types"
16
+
17
+ import type { MapCanvasStyle } from "./MapCanvas.tsx"
18
+
19
+ /**
20
+ * An offline stub map style — one solid `background` layer, zero sources, zero network. Safe for headless Storybook.
21
+ */
22
+ export const STUB_MAP_STYLE: MapCanvasStyle = {
23
+ version: 8,
24
+ name: "demo-runtime-stub",
25
+ sources: {},
26
+ layers: [{ id: "background", type: "background", paint: { "background-color": "#dfe7ee" } }],
27
+ }
28
+
29
+ /**
30
+ * Canned place-autocomplete suggestions — a synchronous fake for the FST prefix-walk.
31
+ */
32
+ export const FAKE_SUGGESTIONS: Suggestion[] = [
33
+ { value: "New York", placetype: "locality" },
34
+ { value: "New Orleans", placetype: "locality" },
35
+ { value: "Newark", placetype: "locality" },
36
+ ]
37
+
38
+ /**
39
+ * A fake DEMO runtime — the map analogue of {@link makePipelineRuntime}. It composes the pipeline fake (canned
40
+ * parse+resolve) with the map surface: the offline stub style, a version list, a backend, an injected autocomplete, and
41
+ * a `resolveMapPlace` that hands the selected candidate a bbox so the declarative overlays draw a marker + outline. No
42
+ * network, no ONNX, no maplibre-at-runtime — everything is data. `runParseWithBias` delegates to the base parse (the
43
+ * bias is ignored by the fake but present so the parameter is exercised).
44
+ */
45
+ export function makeFakeGeocoderRuntime(overrides: Partial<GeocoderRuntime> = {}): GeocoderRuntime {
46
+ const base = makePipelineRuntime()
47
+
48
+ return {
49
+ ...base,
50
+ mapStyle: STUB_MAP_STYLE,
51
+ initialCenter: [-74.006, 40.7128],
52
+ initialZoom: 3,
53
+ overlays: [],
54
+ runParseWithBias: (input, _bias, hooks) => base.runParse(input, hooks),
55
+ autocomplete: async (query: string) =>
56
+ FAKE_SUGGESTIONS.filter((s) => s.value.toLowerCase().startsWith(query.toLowerCase())),
57
+ availableVersions: [
58
+ { version: "v7.2.0", label: "v7.2.0 (latest)" },
59
+ { version: "v7.1.0", label: "v7.1.0" },
60
+ { version: "v6.4.0", label: "v6.4.0" },
61
+ ],
62
+ selectedVersion: "v7.2.0",
63
+ selectVersion: () => {},
64
+ activeBackend: "webgpu (28 MB int8)",
65
+ forceWASM: false,
66
+ setForceWASM: () => {},
67
+ // Enrich the selected candidate with a bbox so an outline renders (case 4: bbox → approximate circle + fit).
68
+ resolveMapPlace: (candidate): ResolvedMapPlace => ({
69
+ ...candidate,
70
+ bbox: {
71
+ minLat: candidate.lat - 0.15,
72
+ maxLat: candidate.lat + 0.15,
73
+ minLon: candidate.lon - 0.15,
74
+ maxLon: candidate.lon + 0.15,
75
+ },
76
+ }),
77
+ ...overrides,
78
+ }
79
+ }
80
+
81
+ /**
82
+ * A fixed, fully-populated parse+resolve result — the shared fixture behind the pipeline runtime + the result panel.
83
+ */
84
+ export function makeFakeParseResult(input = "350 5th Ave, New York, NY 10118"): ParseResult {
85
+ return {
86
+ input,
87
+ tree: { roots: [{ tag: "locality", value: "New York" }] },
88
+ nodes: [
89
+ { tag: "house_number", value: "350", confidence: 0.97, start: 0, end: 3 },
90
+ { tag: "street", value: "5th Ave", confidence: 0.88, start: 4, end: 11 },
91
+ { tag: "locality", value: "New York", confidence: 0.71 },
92
+ ],
93
+ kindResult: { kind: "structured_address", confidence: 0.95, alternatives: [] },
94
+ timing: { shape: 0.4, classify: 12.1, resolve: 4.2 },
95
+ resolved: { id: 85_977_539, name: "New York", placetype: "locality", lat: 40.7128, lon: -74.006, score: 0.82 },
96
+ candidates: [
97
+ { id: 85_977_539, name: "New York", placetype: "locality", lat: 40.7128, lon: -74.006, score: 0.82 },
98
+ { id: 101_715_829, name: "New York", placetype: "region", lat: 43, lon: -75, score: 0.55 },
99
+ ],
100
+ fstActive: true,
101
+ fstProvenance: { builtAt: "2026-07-01T00:00:00Z", stateCount: 51, placeCount: 94_000, importanceMatches: 12_000 },
102
+ }
103
+ }
104
+
105
+ /**
106
+ * A fake parse+resolve runtime that returns a fixed, fully-populated result.
107
+ */
108
+ export function makePipelineRuntime(overrides: Partial<PipelineRuntime> = {}): PipelineRuntime {
109
+ return {
110
+ ready: true,
111
+ parseStageLabels: ["Analyzing input shape…", "Running neural classifier…", "Resolving in gazetteer…"],
112
+ errorMessage: null,
113
+ loading: null,
114
+ runParse: async (input, { onStage }): Promise<ParseResult> => {
115
+ onStage(1)
116
+ onStage(2)
117
+
118
+ return makeFakeParseResult(input)
119
+ },
120
+ ...overrides,
121
+ }
122
+ }
package/lib/map/index.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  * @license AGPL-3.0
4
4
  * @author Teffen Ellis, et al.
5
5
  *
6
- * `@mailwoman/react/map` — the geocoder-demo map surface, kept behind its OWN subpath so `maplibre-gl`
6
+ * `@mailwoman/react/map` — the geocoder map surface, kept behind its OWN subpath so `maplibre-gl`
7
7
  * / `react-map-gl` (WebGL + DOM at import) never enter the package-root graph. Importing this subpath
8
8
  * pulls the map deps; importing `@mailwoman/react` (root) does not. Consumers who only want the
9
9
  * parse/POI explorers never pay for maplibre.
@@ -12,20 +12,20 @@
12
12
  * `maplibre-gl/dist/maplibre-gl.css` + `@mailwoman/react/styles.css` itself.
13
13
  */
14
14
 
15
- export { DemoMap } from "./DemoMap.tsx"
16
- export type { DemoMapExtraProps, DemoMapProps, DemoMapStyle } from "./DemoMap.tsx"
15
+ export { MapCanvas } from "./MapCanvas.tsx"
16
+ export type { MapCanvasExtraProps, MapCanvasProps, MapCanvasStyle } from "./MapCanvas.tsx"
17
17
 
18
18
  export type {
19
- DemoBackend,
20
- DemoCompareContext,
21
- DemoPanels,
22
- DemoResultContext,
23
- DemoRuntime,
24
- DemoVersionOption,
19
+ CompareContext,
20
+ GeocoderPanels,
21
+ GeocoderRuntime,
22
+ InferenceBackend,
25
23
  LngLatTuple,
26
24
  MapBias,
27
25
  OverlaySpec,
26
+ ResultContext,
28
27
  Suggestion,
28
+ VersionOption,
29
29
  } from "#map/types"
30
30
 
31
31
  // ── Pure geometry + render spec (node-safe; no react-map-gl at runtime) ──────
@@ -47,23 +47,23 @@ export type { ResultCameraProps } from "./ResultCamera.tsx"
47
47
  export { ResultOverlay } from "./ResultOverlay.tsx"
48
48
  export type { ResultOverlayProps } from "./ResultOverlay.tsx"
49
49
 
50
- // ── Demo controls + composed demo (phase 4) ─────────────────────────────────
50
+ // ── Geocoder controls + the composed geocoder ────────────────────────────────
51
51
  export { BackendControl } from "./BackendControl.tsx"
52
52
  export type { BackendControlProps } from "./BackendControl.tsx"
53
53
  export { CompareToggle } from "./CompareToggle.tsx"
54
54
  export type { CompareToggleProps } from "./CompareToggle.tsx"
55
- export { DemoControls } from "./DemoControls.tsx"
56
- export type { DemoControlsProps } from "./DemoControls.tsx"
57
- export { GeocoderDemo } from "./GeocoderDemo.tsx"
58
- export type { GeocoderDemoProps } from "./GeocoderDemo.tsx"
55
+ export { Geocoder } from "./Geocoder.tsx"
56
+ export type { GeocoderProps } from "./Geocoder.tsx"
57
+ export { GeocoderControls } from "./GeocoderControls.tsx"
58
+ export type { GeocoderControlsProps } from "./GeocoderControls.tsx"
59
59
  export { PlaceAutocomplete } from "./PlaceAutocomplete.tsx"
60
60
  export type { PlaceAutocompleteProps } from "./PlaceAutocomplete.tsx"
61
61
  export { ResultPanel } from "./ResultPanel.tsx"
62
62
  export type { ResultPanelProps } from "./ResultPanel.tsx"
63
63
  export { useCompareState } from "#map/useCompareState"
64
64
  export type { UseCompareState } from "#map/useCompareState"
65
- export { useDemoGeocode } from "#map/useDemoGeocode"
66
- export type { UseDemoGeocode, UseDemoGeocodeOptions } from "#map/useDemoGeocode"
65
+ export { useGeocode } from "#map/useGeocode"
66
+ export type { UseGeocode, UseGeocodeOptions } from "#map/useGeocode"
67
67
  export { usePlaceAutocomplete } from "#map/usePlaceAutocomplete"
68
68
 
69
69
  export type {
@@ -0,0 +1,51 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ * @file The bare MapLibre control both debug panels portal into.
6
+ *
7
+ * `DashboardMap`'s inspector and the demo page's `_debug.tsx` panel each need an `IControl` whose
8
+ * only job is to own a container element for `createPortal`. The class was duplicated in both;
9
+ * the position and container class are the only differences, so they are parameters here.
10
+ */
11
+
12
+ import type { ControlPosition } from "maplibre-gl"
13
+ import type { IControl, MapInstance } from "react-map-gl/maplibre"
14
+
15
+ export interface DebugControlBaseOptions {
16
+ /**
17
+ * Class applied to the portal container.
18
+ */
19
+ className?: string
20
+ /**
21
+ * Where MapLibre docks the control. @default "bottom-left"
22
+ */
23
+ position?: ControlPosition
24
+ }
25
+
26
+ export class DebugControlBase implements IControl {
27
+ public readonly container: HTMLElement
28
+ readonly #position: ControlPosition
29
+
30
+ constructor({ className, position = "bottom-left" }: DebugControlBaseOptions = {}) {
31
+ this.container = document.createElement("div")
32
+
33
+ if (className) {
34
+ this.container.classList.add(className)
35
+ }
36
+
37
+ this.#position = position
38
+ }
39
+
40
+ public onAdd(_map: MapInstance): HTMLElement {
41
+ return this.container
42
+ }
43
+
44
+ public onRemove(_map: MapInstance): void {
45
+ this.container.remove()
46
+ }
47
+
48
+ public getDefaultPosition(): ControlPosition {
49
+ return this.#position
50
+ }
51
+ }
@@ -19,9 +19,10 @@
19
19
  * 5. bare point → no outline, fly to zoom 12
20
20
  */
21
21
 
22
+ import type { ResolvedPlaceView } from "@mailwoman/core/pipeline/client-result"
23
+
22
24
  import { approxCircleGeometry, bboxToBounds, geomBounds, radiusCircleGeometry } from "#map/geometry"
23
25
  import type { BoundsTuple, PlaceBBox, PlaceGeometry } from "#map/geometry"
24
- import type { ResolvedPlaceView } from "#pipeline/types"
25
26
 
26
27
  /**
27
28
  * `[longitude, latitude]`.
@@ -167,7 +168,7 @@ export function computeMapPlaceRenderSpec(place: ResolvedMapPlace): MapPlaceRend
167
168
  }
168
169
 
169
170
  /**
170
- * The DECLARATIVE camera path: reshape a `center` target into a `viewState` patch a controlled `<DemoMap viewState>`
171
+ * The DECLARATIVE camera path: reshape a `center` target into a `viewState` patch a controlled `<MapCanvas viewState>`
171
172
  * can apply directly (a hard jump, no animation). Returns `null` for a `bounds` target — fitting a box to the viewport
172
173
  * needs the map's pixel dimensions, which only the live map has, so that case is applied imperatively by
173
174
  * `<ResultCamera>`. Pure + node-testable.