@mailwoman/react 9.3.0 → 10.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (246) hide show
  1. package/fonts.css +59 -0
  2. package/lib/common/About.tsx +105 -0
  3. package/lib/common/KindBadge.tsx +2 -7
  4. package/lib/common/confidence-tiers.ts +50 -0
  5. package/lib/common/index.ts +22 -0
  6. package/lib/common/text-tokens.ts +88 -0
  7. package/lib/index.ts +10 -103
  8. package/lib/map/BackendControl.tsx +7 -3
  9. package/lib/map/CompareToggle.tsx +5 -4
  10. package/lib/map/{GeocoderDemo.tsx → Geocoder.tsx} +81 -61
  11. package/lib/map/GeocoderControls.tsx +352 -0
  12. package/lib/map/{DemoMap.tsx → MapCanvas.tsx} +15 -15
  13. package/lib/map/MapChipRow.tsx +77 -0
  14. package/lib/map/MapCompass.tsx +77 -0
  15. package/lib/map/MapControlStack.tsx +98 -0
  16. package/lib/map/MapFooter.tsx +115 -0
  17. package/lib/map/MapProgressBar.tsx +58 -0
  18. package/lib/map/MapSearchBar.tsx +68 -0
  19. package/lib/map/MapSheet.tsx +62 -0
  20. package/lib/map/PlaceMarker.tsx +1 -1
  21. package/lib/map/ResolvedPlaceLayers.tsx +3 -3
  22. package/lib/map/ResultCamera.tsx +1 -1
  23. package/lib/map/ResultPanel.tsx +2 -2
  24. package/lib/map/VersionPicker.tsx +3 -3
  25. package/lib/map/fake-runtime.ts +122 -0
  26. package/lib/map/index.ts +35 -16
  27. package/lib/map/map-debug.ts +51 -0
  28. package/lib/map/place-render.ts +3 -2
  29. package/lib/map/types.ts +58 -42
  30. package/lib/map/{useDemoGeocode.ts → useGeocode.ts} +8 -8
  31. package/lib/map/useMapBearing.ts +56 -0
  32. package/lib/map/useMapLabelPick.ts +123 -0
  33. package/lib/pipeline/CandidatePicker.tsx +1 -1
  34. package/lib/pipeline/ComponentTable.tsx +1 -2
  35. package/lib/pipeline/ConfidenceCell.tsx +7 -19
  36. package/lib/pipeline/FailureDiagnostic.tsx +56 -0
  37. package/lib/pipeline/ResolvedPlace.tsx +17 -4
  38. package/lib/pipeline/SpanHighlight.tsx +97 -0
  39. package/lib/pipeline/TimingPanel.tsx +65 -0
  40. package/lib/pipeline/TreeView.tsx +55 -0
  41. package/lib/pipeline/copy.ts +1 -1
  42. package/lib/pipeline/index.ts +36 -0
  43. package/lib/pipeline/types.ts +2 -75
  44. package/lib/pipeline/useParsePipeline.ts +31 -19
  45. package/lib/poi/index.ts +39 -0
  46. package/lib/poi/types.ts +2 -1
  47. package/lib/runtime/index.ts +16 -0
  48. package/lib/runtime/{useDemoRuntime.ts → useReleaseRuntime.ts} +22 -24
  49. package/out/common/About.d.ts +21 -0
  50. package/out/common/About.d.ts.map +1 -0
  51. package/out/common/About.js +8 -0
  52. package/out/common/About.js.map +1 -0
  53. package/out/common/KindBadge.d.ts +2 -9
  54. package/out/common/KindBadge.d.ts.map +1 -1
  55. package/out/common/KindBadge.js.map +1 -1
  56. package/out/common/confidence-tiers.d.ts +36 -0
  57. package/out/common/confidence-tiers.d.ts.map +1 -0
  58. package/out/common/confidence-tiers.js +42 -0
  59. package/out/common/confidence-tiers.js.map +1 -0
  60. package/out/common/index.d.ts +22 -0
  61. package/out/common/index.d.ts.map +1 -0
  62. package/out/common/index.js +15 -0
  63. package/out/common/index.js.map +1 -0
  64. package/out/common/text-tokens.d.ts +46 -0
  65. package/out/common/text-tokens.d.ts.map +1 -0
  66. package/out/common/text-tokens.js +52 -0
  67. package/out/common/text-tokens.js.map +1 -0
  68. package/out/index.d.ts +5 -51
  69. package/out/index.d.ts.map +1 -1
  70. package/out/index.js +4 -30
  71. package/out/index.js.map +1 -1
  72. package/out/map/BackendControl.d.ts.map +1 -1
  73. package/out/map/BackendControl.js +1 -1
  74. package/out/map/BackendControl.js.map +1 -1
  75. package/out/map/CompareToggle.d.ts +2 -2
  76. package/out/map/CompareToggle.d.ts.map +1 -1
  77. package/out/map/CompareToggle.js +1 -1
  78. package/out/map/CompareToggle.js.map +1 -1
  79. package/out/map/Geocoder.d.ts +67 -0
  80. package/out/map/Geocoder.d.ts.map +1 -0
  81. package/out/map/Geocoder.js +98 -0
  82. package/out/map/Geocoder.js.map +1 -0
  83. package/out/map/GeocoderControls.d.ts +81 -0
  84. package/out/map/GeocoderControls.d.ts.map +1 -0
  85. package/out/map/GeocoderControls.js +79 -0
  86. package/out/map/GeocoderControls.js.map +1 -0
  87. package/out/map/{DemoMap.d.ts → MapCanvas.d.ts} +15 -15
  88. package/out/map/MapCanvas.d.ts.map +1 -0
  89. package/out/map/{DemoMap.js → MapCanvas.js} +2 -2
  90. package/out/map/MapCanvas.js.map +1 -0
  91. package/out/map/MapChipRow.d.ts +47 -0
  92. package/out/map/MapChipRow.d.ts.map +1 -0
  93. package/out/map/MapChipRow.js +12 -0
  94. package/out/map/MapChipRow.js.map +1 -0
  95. package/out/map/MapCompass.d.ts +42 -0
  96. package/out/map/MapCompass.d.ts.map +1 -0
  97. package/out/map/MapCompass.js +11 -0
  98. package/out/map/MapCompass.js.map +1 -0
  99. package/out/map/MapControlStack.d.ts +57 -0
  100. package/out/map/MapControlStack.d.ts.map +1 -0
  101. package/out/map/MapControlStack.js +15 -0
  102. package/out/map/MapControlStack.js.map +1 -0
  103. package/out/map/MapFooter.d.ts +40 -0
  104. package/out/map/MapFooter.d.ts.map +1 -0
  105. package/out/map/MapFooter.js +51 -0
  106. package/out/map/MapFooter.js.map +1 -0
  107. package/out/map/MapProgressBar.d.ts +34 -0
  108. package/out/map/MapProgressBar.d.ts.map +1 -0
  109. package/out/map/MapProgressBar.js +8 -0
  110. package/out/map/MapProgressBar.js.map +1 -0
  111. package/out/map/MapSearchBar.d.ts +49 -0
  112. package/out/map/MapSearchBar.d.ts.map +1 -0
  113. package/out/map/MapSearchBar.js +6 -0
  114. package/out/map/MapSearchBar.js.map +1 -0
  115. package/out/map/MapSheet.d.ts +32 -0
  116. package/out/map/MapSheet.d.ts.map +1 -0
  117. package/out/map/MapSheet.js +33 -0
  118. package/out/map/MapSheet.js.map +1 -0
  119. package/out/map/OverlayLayers.js +1 -1
  120. package/out/map/PlaceMarker.d.ts +1 -1
  121. package/out/map/ResolvedPlaceLayers.d.ts +3 -3
  122. package/out/map/ResolvedPlaceLayers.js +1 -1
  123. package/out/map/ResultCamera.d.ts +1 -1
  124. package/out/map/ResultCamera.js +1 -1
  125. package/out/map/ResultPanel.d.ts +2 -2
  126. package/out/map/ResultPanel.d.ts.map +1 -1
  127. package/out/map/ResultPanel.js +1 -1
  128. package/out/map/ResultPanel.js.map +1 -1
  129. package/out/map/VersionPicker.d.ts +3 -3
  130. package/out/map/VersionPicker.d.ts.map +1 -1
  131. package/out/map/fake-runtime.d.ts +38 -0
  132. package/out/map/fake-runtime.d.ts.map +1 -0
  133. package/out/map/fake-runtime.js +107 -0
  134. package/out/map/fake-runtime.js.map +1 -0
  135. package/out/map/index.d.ts +27 -10
  136. package/out/map/index.d.ts.map +1 -1
  137. package/out/map/index.js +16 -6
  138. package/out/map/index.js.map +1 -1
  139. package/out/map/map-debug.d.ts +31 -0
  140. package/out/map/map-debug.d.ts.map +1 -0
  141. package/out/map/map-debug.js +31 -0
  142. package/out/map/map-debug.js.map +1 -0
  143. package/out/map/place-render.d.ts +2 -2
  144. package/out/map/place-render.d.ts.map +1 -1
  145. package/out/map/place-render.js +1 -1
  146. package/out/map/place-render.js.map +1 -1
  147. package/out/map/types.d.ts +60 -42
  148. package/out/map/types.d.ts.map +1 -1
  149. package/out/map/types.js +5 -5
  150. package/out/map/{useDemoGeocode.d.ts → useGeocode.d.ts} +9 -9
  151. package/out/map/useGeocode.d.ts.map +1 -0
  152. package/out/map/{useDemoGeocode.js → useGeocode.js} +4 -4
  153. package/out/map/useGeocode.js.map +1 -0
  154. package/out/map/useMapBearing.d.ts +28 -0
  155. package/out/map/useMapBearing.d.ts.map +1 -0
  156. package/out/map/useMapBearing.js +35 -0
  157. package/out/map/useMapBearing.js.map +1 -0
  158. package/out/map/useMapLabelPick.d.ts +23 -0
  159. package/out/map/useMapLabelPick.d.ts.map +1 -0
  160. package/out/map/useMapLabelPick.js +104 -0
  161. package/out/map/useMapLabelPick.js.map +1 -0
  162. package/out/pipeline/CandidatePicker.d.ts +1 -1
  163. package/out/pipeline/CandidatePicker.d.ts.map +1 -1
  164. package/out/pipeline/CandidatePicker.js +1 -1
  165. package/out/pipeline/CandidatePicker.js.map +1 -1
  166. package/out/pipeline/ComponentTable.d.ts +1 -1
  167. package/out/pipeline/ComponentTable.d.ts.map +1 -1
  168. package/out/pipeline/ComponentTable.js.map +1 -1
  169. package/out/pipeline/ConfidenceCell.d.ts +2 -2
  170. package/out/pipeline/ConfidenceCell.d.ts.map +1 -1
  171. package/out/pipeline/ConfidenceCell.js +4 -16
  172. package/out/pipeline/ConfidenceCell.js.map +1 -1
  173. package/out/pipeline/FailureDiagnostic.d.ts +15 -0
  174. package/out/pipeline/FailureDiagnostic.d.ts.map +1 -0
  175. package/out/pipeline/FailureDiagnostic.js +21 -0
  176. package/out/pipeline/FailureDiagnostic.js.map +1 -0
  177. package/out/pipeline/PipelineExplorer.js +1 -1
  178. package/out/pipeline/QueryForm.js +1 -1
  179. package/out/pipeline/ResolvedPlace.d.ts +1 -1
  180. package/out/pipeline/ResolvedPlace.d.ts.map +1 -1
  181. package/out/pipeline/ResolvedPlace.js +4 -10
  182. package/out/pipeline/ResolvedPlace.js.map +1 -1
  183. package/out/pipeline/SpanHighlight.d.ts +23 -0
  184. package/out/pipeline/SpanHighlight.d.ts.map +1 -0
  185. package/out/pipeline/SpanHighlight.js +31 -0
  186. package/out/pipeline/SpanHighlight.js.map +1 -0
  187. package/out/pipeline/TimingPanel.d.ts +16 -0
  188. package/out/pipeline/TimingPanel.d.ts.map +1 -0
  189. package/out/pipeline/TimingPanel.js +20 -0
  190. package/out/pipeline/TimingPanel.js.map +1 -0
  191. package/out/pipeline/TreeView.d.ts +17 -0
  192. package/out/pipeline/TreeView.d.ts.map +1 -0
  193. package/out/pipeline/TreeView.js +15 -0
  194. package/out/pipeline/TreeView.js.map +1 -0
  195. package/out/pipeline/copy.d.ts +1 -1
  196. package/out/pipeline/copy.d.ts.map +1 -1
  197. package/out/pipeline/index.d.ts +33 -0
  198. package/out/pipeline/index.d.ts.map +1 -0
  199. package/out/pipeline/index.js +21 -0
  200. package/out/pipeline/index.js.map +1 -0
  201. package/out/pipeline/types.d.ts +2 -68
  202. package/out/pipeline/types.d.ts.map +1 -1
  203. package/out/pipeline/types.js +1 -1
  204. package/out/pipeline/useParsePipeline.d.ts +7 -3
  205. package/out/pipeline/useParsePipeline.d.ts.map +1 -1
  206. package/out/pipeline/useParsePipeline.js +6 -2
  207. package/out/pipeline/useParsePipeline.js.map +1 -1
  208. package/out/poi/LiveResultsBlock.js +1 -1
  209. package/out/poi/POIExplorer.js +1 -1
  210. package/out/poi/SubjectPanel.js +1 -1
  211. package/out/poi/index.d.ts +23 -0
  212. package/out/poi/index.d.ts.map +1 -0
  213. package/out/poi/index.js +15 -0
  214. package/out/poi/index.js.map +1 -0
  215. package/out/poi/runtime.d.ts.map +1 -1
  216. package/out/poi/types.d.ts +2 -1
  217. package/out/poi/types.d.ts.map +1 -1
  218. package/out/runtime/index.d.ts +9 -0
  219. package/out/runtime/index.d.ts.map +1 -0
  220. package/out/runtime/index.js +8 -0
  221. package/out/runtime/index.js.map +1 -0
  222. package/out/runtime/{useDemoRuntime.d.ts → useReleaseRuntime.d.ts} +18 -20
  223. package/out/runtime/useReleaseRuntime.d.ts.map +1 -0
  224. package/out/runtime/{useDemoRuntime.js → useReleaseRuntime.js} +4 -4
  225. package/out/runtime/useReleaseRuntime.js.map +1 -0
  226. package/package.json +222 -31
  227. package/styleframe.config.ts +329 -0
  228. package/styles.css +1995 -663
  229. package/tokens/index.css +116 -0
  230. package/tokens/tokens.json +528 -0
  231. package/tokens/tokens.resolver.json +185 -0
  232. package/lib/map/DemoControls.tsx +0 -194
  233. package/out/map/DemoControls.d.ts +0 -64
  234. package/out/map/DemoControls.d.ts.map +0 -1
  235. package/out/map/DemoControls.js +0 -30
  236. package/out/map/DemoControls.js.map +0 -1
  237. package/out/map/DemoMap.d.ts.map +0 -1
  238. package/out/map/DemoMap.js.map +0 -1
  239. package/out/map/GeocoderDemo.d.ts +0 -57
  240. package/out/map/GeocoderDemo.d.ts.map +0 -1
  241. package/out/map/GeocoderDemo.js +0 -98
  242. package/out/map/GeocoderDemo.js.map +0 -1
  243. package/out/map/useDemoGeocode.d.ts.map +0 -1
  244. package/out/map/useDemoGeocode.js.map +0 -1
  245. package/out/runtime/useDemoRuntime.d.ts.map +0 -1
  246. package/out/runtime/useDemoRuntime.js.map +0 -1
package/fonts.css ADDED
@@ -0,0 +1,59 @@
1
+ /**
2
+ * The brand typeface, served from the same origin every app already preconnects to.
3
+ *
4
+ * Six faces, not the twenty the family ships. Each `@font-face` is a network fetch on first paint, and the token
5
+ * layer binds only these: regular and medium for running text, bold where a heading or a chip needs weight, italic
6
+ * for a caption, and two mono weights for the `code`, `number` and `glyph` roles. Iosevka provides no 600, so
7
+ * `--font-weight-semibold: 600` matches the 700 face by the CSS weight-matching rules rather than being synthesized.
8
+ *
9
+ * A rule never names a family here — it names a scale role from `tokens.css`, which names one of the five face
10
+ * roles. Replacing the typeface is an edit to `--font-family-*` in `styleframe.config.ts` plus this file.
11
+ */
12
+
13
+ @font-face {
14
+ font-family: "Iosevka Nexus Web";
15
+ font-display: swap;
16
+ font-weight: 400;
17
+ font-style: normal;
18
+ src: url("https://public.mailwoman.ai/fonts/IoveskaNexus/WOFF2/IosevkaNexus-Regular.woff2") format("woff2");
19
+ }
20
+
21
+ @font-face {
22
+ font-family: "Iosevka Nexus Web";
23
+ font-display: swap;
24
+ font-weight: 450;
25
+ font-style: normal;
26
+ src: url("https://public.mailwoman.ai/fonts/IoveskaNexus/WOFF2/IosevkaNexus-Book.woff2") format("woff2");
27
+ }
28
+
29
+ @font-face {
30
+ font-family: "Iosevka Nexus Web";
31
+ font-display: swap;
32
+ font-weight: 700;
33
+ font-style: normal;
34
+ src: url("https://public.mailwoman.ai/fonts/IoveskaNexus/WOFF2/IosevkaNexus-Bold.woff2") format("woff2");
35
+ }
36
+
37
+ @font-face {
38
+ font-family: "Iosevka Nexus Web";
39
+ font-display: swap;
40
+ font-weight: 400;
41
+ font-style: italic;
42
+ src: url("https://public.mailwoman.ai/fonts/IoveskaNexus/WOFF2/IosevkaNexus-Italic.woff2") format("woff2");
43
+ }
44
+
45
+ @font-face {
46
+ font-family: "Iosevka Nexus Mono Web";
47
+ font-display: swap;
48
+ font-weight: 400;
49
+ font-style: normal;
50
+ src: url("https://public.mailwoman.ai/fonts/IosevkaNexusMono/WOFF2/IosevkaNexusMono-Regular.woff2") format("woff2");
51
+ }
52
+
53
+ @font-face {
54
+ font-family: "Iosevka Nexus Mono Web";
55
+ font-display: swap;
56
+ font-weight: 450;
57
+ font-style: normal;
58
+ src: url("https://public.mailwoman.ai/fonts/IosevkaNexusMono/WOFF2/IosevkaNexusMono-Book.woff2") format("woff2");
59
+ }
@@ -0,0 +1,105 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ *
6
+ * `About` — the explainer for the browser geocoder: the neural model, the confidence colours, the gazetteer
7
+ * resolver, the byte-range database and the FST prior. Prose about the product a host places above or beside the
8
+ * geocoder; it renders nothing live.
9
+ */
10
+
11
+ import type { ReactNode } from "react"
12
+
13
+ export interface AboutProps {
14
+ /**
15
+ * Wrap the prose in its own `<details>` disclosure. Set false where the host is already the disclosure — inside a
16
+ * sheet opened by an About button, a summary repeating that button's words is one control too many.
17
+ *
18
+ * @default true
19
+ */
20
+ collapsible?: boolean
21
+ }
22
+
23
+ export function About({ collapsible = true }: AboutProps = {}): ReactNode {
24
+ const body = (
25
+ <div className="mw-about__body">
26
+ <section className="mw-about__section">
27
+ <h3 className="mw-about__heading">Neural model</h3>
28
+ <p>
29
+ A ~29M-parameter BERT-style encoder classifies each token into one of 33 BIO labels covering 16 address
30
+ components (street, house number, unit, locality, region, postcode, venue, country, intersection, etc.). It
31
+ runs entirely in your browser via <strong>onnxruntime-web</strong> (WebGPU with WASM SIMD fallback). The model
32
+ ships as a 37.6 MB int8-quantized ONNX bundle; fp32 weights are also available for higher accuracy.
33
+ </p>
34
+ </section>
35
+
36
+ <section className="mw-about__section">
37
+ <h3 className="mw-about__heading">Confidence colors</h3>
38
+ <p>
39
+ Every classified span carries a confidence score between 0 and 1. The colors in the results table give you a
40
+ quick visual read:
41
+ </p>
42
+ <ul className="mw-about__legend">
43
+ <li className="mw-about__item">
44
+ <span className="mw-about__swatch mw-about__swatch--high" />
45
+ <strong>Green</strong> (≥ 0.8) — high confidence. The model is nearly certain.
46
+ </li>
47
+ <li className="mw-about__item">
48
+ <span className="mw-about__swatch mw-about__swatch--mid" />
49
+ <strong>Amber</strong> (0.5–0.8) — moderate confidence. Worth verifying.
50
+ </li>
51
+ <li className="mw-about__item">
52
+ <span className="mw-about__swatch mw-about__swatch--low" />
53
+ <strong>Red</strong> (&lt; 0.5) — low confidence. The model is unsure — likely wrong.
54
+ </li>
55
+ </ul>
56
+ <p>
57
+ These are raw model scores. For calibrated probabilities, the library ships a per-locale isotonic calibrator (
58
+ <code>calibration.json</code>) that maps the raw scores to well-calibrated probability estimates.
59
+ </p>
60
+ </section>
61
+
62
+ <section className="mw-about__section">
63
+ <h3 className="mw-about__heading">WOF resolver</h3>
64
+ <p>
65
+ After classification, the resolver queries a <strong>Who&apos;s On First</strong> (WOF) SQLite gazetteer to
66
+ match the parsed components — locality, region, and postcode — against real-world places with coordinates. The
67
+ cascade tries postcode first (most precise), then locality, then the raw input text. The result is a sorted
68
+ list of candidate places with WOF IDs, placetypes, lat/lon, and bounding boxes.
69
+ </p>
70
+ </section>
71
+
72
+ <section className="mw-about__section">
73
+ <h3 className="mw-about__heading">Byte-range gazetteer</h3>
74
+ <p>
75
+ The gazetteer is a multi-gigabyte SQLite file served from a public bucket. It loads via{" "}
76
+ <strong>sql.js-httpvfs</strong>, which range-requests only the pages a lookup touches, so your browser fetches
77
+ a few hundred kilobytes per session instead of the whole file.
78
+ </p>
79
+ </section>
80
+
81
+ <section className="mw-about__section">
82
+ <h3 className="mw-about__heading">FST prior</h3>
83
+ <p>
84
+ A <strong>finite-state transducer</strong> (FST) built from ~94K US place names runs before the neural
85
+ classifier. It pre-annotates known locality, region, and postcode spans in the input — places like
86
+ &quot;Springfield&quot; or &quot;Cook County&quot; that the FST can match exactly. These &quot;FST prior&quot;
87
+ hits feed the classifier as strong hints, improving locality and region recall on addresses where the neural
88
+ model alone might miss them. The FST is active whenever the selected release includes it.
89
+ </p>
90
+ </section>
91
+ </div>
92
+ )
93
+
94
+ if (!collapsible) return body
95
+
96
+ return (
97
+ <details className="mw-about">
98
+ <summary className="mw-about__summary">
99
+ <span className="mw-about__icon">ℹ️</span>
100
+ About this geocoder
101
+ </summary>
102
+ {body}
103
+ </details>
104
+ )
105
+ }
@@ -9,16 +9,11 @@
9
9
  * pipeline's projection satisfy it without a hard type dependency.
10
10
  */
11
11
 
12
+ import type { KindView } from "@mailwoman/core/pipeline/client-result"
12
13
  import type { ReactNode } from "react"
13
14
 
14
- export interface KindBadgeResult {
15
- kind: string
16
- confidence: number
17
- alternatives: ReadonlyArray<{ kind: string; confidence: number }>
18
- }
19
-
20
15
  export interface KindBadgeProps {
21
- kindResult: KindBadgeResult
16
+ kindResult: KindView
22
17
  }
23
18
 
24
19
  const formatPct = (n: number): string => `${Math.round(n * 100)}%`
@@ -0,0 +1,50 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ * @file Confidence banding shared by every component that colours a span by confidence.
6
+ *
7
+ * It is a presentation choice, not a model one: the parser emits a continuous confidence and these
8
+ * bounds only decide which colour a span is drawn in, so they live here rather than anywhere the
9
+ * pipeline can see them.
10
+ */
11
+
12
+ /**
13
+ * At or above this the span is drawn as high-confidence.
14
+ */
15
+ export const HIGH_CONFIDENCE_MIN = 0.8
16
+
17
+ /**
18
+ * At or above this the span is drawn as medium-confidence; below it, low.
19
+ */
20
+ export const MID_CONFIDENCE_MIN = 0.5
21
+
22
+ /**
23
+ * The banding a component applies to a span's confidence.
24
+ */
25
+ export type ConfidenceTier = "high" | "mid" | "low"
26
+
27
+ /**
28
+ * Bands a continuous confidence into the three tiers the demo styles against.
29
+ *
30
+ * @param confidence A parser confidence in `[0, 1]`.
31
+ *
32
+ * @returns The tier to style with.
33
+ */
34
+ export function confidenceTier(confidence: number): ConfidenceTier {
35
+ if (confidence >= HIGH_CONFIDENCE_MIN) return "high"
36
+
37
+ if (confidence >= MID_CONFIDENCE_MIN) return "mid"
38
+
39
+ return "low"
40
+ }
41
+
42
+ /**
43
+ * {@link confidenceTier} for a possibly-absent confidence: an unmeasured span is drawn as `mid` rather than `low`, so an
44
+ * older model that emits no confidence never reads as uniformly wrong.
45
+ */
46
+ export function confidenceTierOrMid(confidence?: number): ConfidenceTier {
47
+ if (confidence == null) return "mid"
48
+
49
+ return confidenceTier(confidence)
50
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ * @file Common React primitives.
6
+ */
7
+
8
+ export { ClientOnly } from "./ClientOnly.tsx"
9
+ export type { ClientOnlyProps } from "./ClientOnly.tsx"
10
+ export { CopyButton } from "./CopyButton.tsx"
11
+ export type { CopyButtonProps } from "./CopyButton.tsx"
12
+ export { cx } from "#common/cx"
13
+ export type { ClassValue } from "#common/cx"
14
+ export { KindBadge } from "./KindBadge.tsx"
15
+ export type { KindBadgeProps } from "./KindBadge.tsx"
16
+ export { LoadingIndicator } from "./LoadingIndicator.tsx"
17
+ export type { LoadingIndicatorProps, LoadingMode } from "./LoadingIndicator.tsx"
18
+ export { PresetChips } from "./PresetChips.tsx"
19
+ export type { Preset, PresetChipsProps } from "./PresetChips.tsx"
20
+ export { useClipboard } from "#common/useClipboard"
21
+ export type { UseClipboard } from "#common/useClipboard"
22
+ export { useDebouncedValue } from "#common/useDebouncedValue"
@@ -0,0 +1,88 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ * @file Word tokenization + span ownership shared by the word-level visualizers.
6
+ *
7
+ * A word-level panel splits the raw input on whitespace and assigns each word to its most specific
8
+ * covering span (the shortest-span owner, the same rule a character-level highlight applies per
9
+ * character). Two panels must agree for the BIO labels to line up between them, so the split and
10
+ * the owner walk live here.
11
+ */
12
+
13
+ export interface WordToken {
14
+ /**
15
+ * The word text as it appears in the input.
16
+ */
17
+ text: string
18
+ /**
19
+ * Leading whitespace before this word.
20
+ */
21
+ whitespace: string
22
+ /**
23
+ * Start offset in the input string.
24
+ */
25
+ start: number
26
+ /**
27
+ * End offset in the input string (exclusive).
28
+ */
29
+ end: number
30
+ }
31
+
32
+ /**
33
+ * Tokenize the raw input into words, preserving leading whitespace for each token.
34
+ */
35
+ export function tokenizeWords(input: string): WordToken[] {
36
+ const words: WordToken[] = []
37
+ let i = 0
38
+
39
+ // `charAt` answers "" past the end, which no whitespace test matches, so both walks stop at the input's length.
40
+ while (i < input.length) {
41
+ let ws = ""
42
+
43
+ while (/\s/.test(input.charAt(i))) {
44
+ ws += input.charAt(i)
45
+
46
+ i++
47
+ }
48
+
49
+ if (i >= input.length) break
50
+ const start = i
51
+
52
+ while (i < input.length && !/\s/.test(input.charAt(i))) {
53
+ i++
54
+ }
55
+
56
+ words.push({ text: input.slice(start, i), start, end: i, whitespace: ws })
57
+ }
58
+
59
+ return words
60
+ }
61
+
62
+ /**
63
+ * A half-open `[start, end)` character range into the input.
64
+ */
65
+ export interface CharSpan {
66
+ start: number
67
+ end: number
68
+ }
69
+
70
+ /**
71
+ * Per-word index of the most specific (shortest) span covering it, or `-1` when no span overlaps the word. A word is
72
+ * covered when any part of it falls within the span.
73
+ */
74
+ export function shortestSpanOwners(words: readonly CharSpan[], spans: readonly CharSpan[]): number[] {
75
+ return words.map((word) => {
76
+ let best = -1
77
+ let bestLen = Infinity
78
+
79
+ for (const [s, sp] of spans.entries()) {
80
+ if (word.start < sp.end && word.end > sp.start && sp.end - sp.start < bestLen) {
81
+ bestLen = sp.end - sp.start
82
+ best = s
83
+ }
84
+ }
85
+
86
+ return best
87
+ })
88
+ }
package/lib/index.ts CHANGED
@@ -16,113 +16,20 @@
16
16
  * aware) — no CSS is imported by the component modules, so the bare package import is node-safe.
17
17
  */
18
18
 
19
- // ── Common primitives ──────────────────────────────────────────────────────
20
- export { ClientOnly } from "./common/ClientOnly.tsx"
21
- export type { ClientOnlyProps } from "./common/ClientOnly.tsx"
22
- export { CopyButton } from "./common/CopyButton.tsx"
23
- export type { CopyButtonProps } from "./common/CopyButton.tsx"
24
- export { cx } from "#common/cx"
25
- export type { ClassValue } from "#common/cx"
26
- export { KindBadge } from "./common/KindBadge.tsx"
27
- export type { KindBadgeProps, KindBadgeResult } from "./common/KindBadge.tsx"
28
- export { LoadingIndicator } from "./common/LoadingIndicator.tsx"
29
- export type { LoadingIndicatorProps, LoadingMode } from "./common/LoadingIndicator.tsx"
30
- export { PresetChips } from "./common/PresetChips.tsx"
31
- export type { Preset, PresetChipsProps } from "./common/PresetChips.tsx"
32
- export { useClipboard } from "#common/useClipboard"
33
- export type { UseClipboard } from "#common/useClipboard"
34
- export { useDebouncedValue } from "#common/useDebouncedValue"
19
+ export * from "#common/index"
20
+ export * from "#poi/index"
21
+ export * from "#pipeline/index"
22
+ export * from "#runtime/index"
35
23
 
36
- // ── POI explorer ───────────────────────────────────────────────────────────
37
- export { AbstainPanel } from "./poi/AbstainPanel.tsx"
38
- export type { AbstainPanelProps } from "./poi/AbstainPanel.tsx"
39
- export { LiveResultsBlock } from "./poi/LiveResultsBlock.tsx"
40
- export type { LiveResultsBlockProps } from "./poi/LiveResultsBlock.tsx"
41
- export { OverpassBlock } from "./poi/OverpassBlock.tsx"
42
- export type { OverpassBlockProps } from "./poi/OverpassBlock.tsx"
43
- export { POIExplorer } from "./poi/POIExplorer.tsx"
44
- export type { POIExplorerProps } from "./poi/POIExplorer.tsx"
45
- export { QueryInput } from "./poi/QueryInput.tsx"
46
- export type { QueryInputProps } from "./poi/QueryInput.tsx"
47
- export { formatDistance, loadPOIRuntime, POI_DEFAULT_TEXT, POI_PRESETS } from "#poi/runtime"
48
- export { SubjectPanel } from "./poi/SubjectPanel.tsx"
49
- export type { SubjectPanelProps } from "./poi/SubjectPanel.tsx"
50
-
51
- export type {
52
- CategoryRecord,
53
- LiveSearchState,
54
- LoadPOIRuntime,
55
- POIBrandSubject,
56
- POICategorySubject,
57
- POIExplorerResult,
58
- POILiveSearch,
59
- POILiveSearchResult,
60
- POIRuntime,
61
- POISearchHit,
62
- POISubject,
63
- POISubjectBase,
64
- TaxonomyLookup,
65
- } from "#poi/types"
66
-
67
- export { usePOISearch } from "#poi/usePOISearch"
68
- export type { UsePOISearch, UsePOISearchOptions } from "#poi/usePOISearch"
69
-
70
- // ── Pipeline explorer ──────────────────────────────────────────────────────
71
- export { CandidatePicker } from "./pipeline/CandidatePicker.tsx"
72
- export type { CandidatePickerProps } from "./pipeline/CandidatePicker.tsx"
73
- export { ComponentTable } from "./pipeline/ComponentTable.tsx"
74
- export type { ComponentTableProps } from "./pipeline/ComponentTable.tsx"
75
- export { ConfidenceCell } from "./pipeline/ConfidenceCell.tsx"
76
- export type { ConfidenceCellProps } from "./pipeline/ConfidenceCell.tsx"
77
- export { buildParsePayload } from "#pipeline/copy"
78
- export { PIPELINE_DEFAULT_ADDRESS, PIPELINE_PRESETS } from "#pipeline/presets"
79
- export { PipelineExplorer } from "./pipeline/PipelineExplorer.tsx"
80
- export type { PipelineExplorerProps } from "./pipeline/PipelineExplorer.tsx"
81
- export { QueryForm } from "./pipeline/QueryForm.tsx"
82
- export type { QueryFormProps } from "./pipeline/QueryForm.tsx"
83
- export { ResolvedPlace } from "./pipeline/ResolvedPlace.tsx"
84
- export type { ResolvedPlaceProps } from "./pipeline/ResolvedPlace.tsx"
85
-
86
- export type {
87
- DualRoleView,
88
- FSTProvenance,
89
- ParsedComponent,
90
- ParseResult,
91
- PipelineLoadingState,
92
- PipelinePanels,
93
- PipelineRuntime,
94
- ResolvedPlaceView,
95
- StageTiming,
96
- } from "#pipeline/types"
97
-
98
- export { useParsePipeline } from "#pipeline/useParsePipeline"
99
- export type { UseParsePipeline, UseParsePipelineOptions } from "#pipeline/useParsePipeline"
100
-
101
- // ── Demo runtime (shared load orchestration; node-safe — no onnx/httpvfs/maplibre) ──
102
- export { useDemoRuntime } from "#runtime/useDemoRuntime"
103
-
104
- export type {
105
- DemoAssetsLoadContext,
106
- DemoLoaderState,
107
- DemoManifest,
108
- DemoReleaseBase,
109
- DemoRuntimeConfig,
110
- } from "#runtime/useDemoRuntime"
111
-
112
- // ── Map (types only from root) ──────────────────────────────────────────────
113
- // The demo-map SURFACE lives behind the `@mailwoman/react/map` subpath so `maplibre-gl` / `react-map-gl`
114
- // (WebGL + DOM at import) never enter the package-root graph — a bare `import("@mailwoman/react")` in node
115
- // must not pull them. Only the CONTRACT types are re-exported here (fully erased at compile time, so no
116
- // runtime linkage): the `DemoMap` component + hooks are import-able solely via `@mailwoman/react/map`.
117
24
  export type {
118
- DemoBackend,
119
- DemoMapExtraProps,
120
- DemoMapProps,
121
- DemoMapStyle,
122
- DemoRuntime,
123
- DemoVersionOption,
25
+ GeocoderRuntime,
26
+ InferenceBackend,
124
27
  LngLatTuple,
125
28
  MapBias,
29
+ MapCanvasExtraProps,
30
+ MapCanvasProps,
31
+ MapCanvasStyle,
126
32
  OverlaySpec,
127
33
  Suggestion,
34
+ VersionOption,
128
35
  } from "#map/index"
@@ -34,13 +34,17 @@ export interface BackendControlProps {
34
34
  export function BackendControl({ activeBackend, forceWASM, onForceWASMChange }: BackendControlProps): ReactNode {
35
35
  return (
36
36
  <div className="mw-demo-backend">
37
+ <span className="mw-map-sheet__label">Inference backend</span>
38
+
37
39
  {activeBackend ? (
38
40
  <span className="mw-demo-backend__active">
39
- Backend: <code>{activeBackend}</code>
41
+ Running on <code>{activeBackend}</code>
40
42
  </span>
41
43
  ) : null}
42
- <label className="mw-demo-backend__toggle">
43
- <input type="checkbox" checked={forceWASM} onChange={(e) => onForceWASMChange(e.target.checked)} /> Force WASM
44
+
45
+ <label className="mw-map-sheet__check mw-demo-backend__toggle">
46
+ <input type="checkbox" checked={forceWASM} onChange={(event) => onForceWASMChange(event.target.checked)} />
47
+ Force WASM
44
48
  </label>
45
49
  </div>
46
50
  )
@@ -13,13 +13,13 @@
13
13
 
14
14
  import type { ReactNode } from "react"
15
15
 
16
- import type { DemoVersionOption } from "#map/types"
16
+ import type { VersionOption } from "#map/types"
17
17
 
18
18
  export interface CompareToggleProps {
19
19
  /**
20
20
  * The selectable model bundles (the primary version is filtered out of the compare list).
21
21
  */
22
- versions: ReadonlyArray<DemoVersionOption>
22
+ versions: ReadonlyArray<VersionOption>
23
23
  /**
24
24
  * The primary version, excluded from the compare options.
25
25
  */
@@ -69,8 +69,9 @@ export function CompareToggle({
69
69
 
70
70
  return (
71
71
  <div className="mw-demo-compare">
72
- <label className="mw-demo-compare__toggle">
73
- <input type="checkbox" checked={compareMode} onChange={(e) => onCompareModeChange(e.target.checked)} /> Compare
72
+ <label className="mw-map-sheet__check mw-demo-compare__toggle">
73
+ <input type="checkbox" checked={compareMode} onChange={(event) => onCompareModeChange(event.target.checked)} />
74
+ Compare two model versions
74
75
  </label>
75
76
  {compareMode ? (
76
77
  <div className="mw-demo-control">