@mailwoman/react 9.4.0 → 10.1.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 +17 -16
- package/fonts.css +97 -22
- package/lib/common/About.tsx +87 -71
- package/lib/common/ClientOnly.tsx +2 -14
- package/lib/common/CopyButton.tsx +3 -1
- package/lib/common/LoadingIndicator.tsx +4 -2
- package/lib/common/PresetChips.tsx +9 -8
- package/lib/common/confidence-tiers.ts +7 -6
- package/lib/common/cx.ts +3 -1
- package/lib/common/text-tokens.ts +7 -4
- package/lib/common/useBuildInfo.ts +54 -0
- package/lib/common/useClipboard.ts +2 -11
- package/lib/common.ts +22 -0
- package/lib/index.ts +27 -112
- package/lib/map/AppIdentity.tsx +85 -0
- package/lib/map/BackendControl.tsx +16 -13
- package/lib/map/CompareToggle.tsx +11 -33
- package/lib/map/DebugInfo.tsx +88 -0
- package/lib/map/Geocoder.tsx +92 -58
- package/lib/map/GeocoderControls.tsx +582 -127
- package/lib/map/GraticuleLayer.tsx +54 -0
- package/lib/map/MapCanvas.tsx +23 -12
- package/lib/map/MapChipRow.tsx +73 -0
- package/lib/map/MapCompass.tsx +68 -0
- package/lib/map/MapControlStack.tsx +97 -0
- package/lib/map/MapFooter.tsx +101 -0
- package/lib/map/MapProgressBar.tsx +55 -0
- package/lib/map/MapSearchBar.tsx +82 -0
- package/lib/map/MapSheet.tsx +71 -0
- package/lib/map/OverlayLayers.tsx +1 -1
- package/lib/map/PlaceAutocomplete.tsx +10 -21
- package/lib/map/PlaceMarker.tsx +4 -2
- package/lib/map/ResolvedPlaceLayers.tsx +5 -14
- package/lib/map/ResultCamera.tsx +8 -31
- package/lib/map/ResultOverlay.tsx +2 -12
- package/lib/map/ResultPanel.tsx +1 -20
- package/lib/map/VersionPicker.tsx +10 -19
- package/lib/map/fake-runtime.ts +10 -12
- package/lib/map/geometry.ts +14 -47
- package/lib/map/graticule.ts +80 -0
- package/lib/map/map-debug.ts +1 -1
- package/lib/map/place-render.ts +28 -60
- package/lib/map/types.ts +65 -97
- package/lib/map/useCompareState.ts +5 -4
- package/lib/map/useGeocode.ts +7 -5
- package/lib/map/useMapBearing.ts +56 -0
- package/lib/map/useMapLabelPick.ts +114 -0
- package/lib/map/useMapPlaceRender.ts +2 -6
- package/lib/map/usePlaceAutocomplete.ts +44 -50
- package/lib/map.ts +95 -0
- package/lib/pipeline/CandidatePicker.tsx +13 -5
- package/lib/pipeline/ConfidenceCell.tsx +1 -1
- package/lib/pipeline/FailureDiagnostic.tsx +8 -2
- package/lib/pipeline/QueryForm.tsx +5 -2
- package/lib/pipeline/ResolvedPlace.tsx +1 -1
- package/lib/pipeline/SpanHighlight.tsx +7 -5
- package/lib/pipeline/TimingPanel.tsx +1 -1
- package/lib/pipeline/TreeView.tsx +1 -1
- package/lib/pipeline/copy.ts +22 -25
- package/lib/pipeline/presets.ts +15 -13
- package/lib/pipeline/types.ts +21 -14
- package/lib/pipeline/useParsePipeline.ts +38 -24
- package/lib/pipeline.ts +36 -0
- package/lib/poi/AbstainPanel.tsx +1 -1
- package/lib/poi/LiveResultsBlock.tsx +2 -1
- package/lib/poi/POIExplorer.tsx +24 -15
- package/lib/poi/QueryInput.tsx +1 -1
- package/lib/poi/SubjectPanel.tsx +4 -3
- package/lib/poi/runtime.ts +5 -16
- package/lib/poi/types.ts +39 -27
- package/lib/poi/usePOISearch.ts +39 -44
- package/lib/poi.ts +39 -0
- package/lib/runtime/useReleaseRuntime.ts +125 -74
- package/lib/runtime.ts +16 -0
- package/lib/search/SearchModal.tsx +317 -0
- package/lib/search/search.css +144 -0
- package/lib/search/types.ts +67 -0
- package/lib/search.ts +11 -0
- package/out/common/About.d.ts +13 -4
- package/out/common/About.d.ts.map +1 -1
- package/out/common/About.js +5 -2
- package/out/common/About.js.map +1 -1
- package/out/common/ClientOnly.d.ts +2 -11
- package/out/common/ClientOnly.d.ts.map +1 -1
- package/out/common/ClientOnly.js +1 -13
- package/out/common/ClientOnly.js.map +1 -1
- package/out/common/CopyButton.d.ts +3 -1
- package/out/common/CopyButton.d.ts.map +1 -1
- package/out/common/CopyButton.js.map +1 -1
- package/out/common/LoadingIndicator.d.ts +4 -2
- package/out/common/LoadingIndicator.d.ts.map +1 -1
- package/out/common/LoadingIndicator.js.map +1 -1
- package/out/common/PresetChips.d.ts +9 -8
- package/out/common/PresetChips.d.ts.map +1 -1
- package/out/common/PresetChips.js.map +1 -1
- package/out/common/confidence-tiers.d.ts +7 -6
- package/out/common/confidence-tiers.d.ts.map +1 -1
- package/out/common/confidence-tiers.js +7 -6
- package/out/common/confidence-tiers.js.map +1 -1
- package/out/common/cx.d.ts +3 -1
- package/out/common/cx.d.ts.map +1 -1
- package/out/common/cx.js +3 -1
- package/out/common/cx.js.map +1 -1
- package/out/common/text-tokens.d.ts +4 -3
- package/out/common/text-tokens.d.ts.map +1 -1
- package/out/common/text-tokens.js +6 -3
- package/out/common/text-tokens.js.map +1 -1
- package/out/common/useBuildInfo.d.ts +27 -0
- package/out/common/useBuildInfo.d.ts.map +1 -0
- package/out/common/useBuildInfo.js +32 -0
- package/out/common/useBuildInfo.js.map +1 -0
- package/out/common/useClipboard.d.ts +1 -3
- package/out/common/useClipboard.d.ts.map +1 -1
- package/out/common/useClipboard.js +2 -11
- package/out/common/useClipboard.js.map +1 -1
- package/out/common.d.ts +22 -0
- package/out/common.d.ts.map +1 -0
- package/out/common.js +15 -0
- package/out/common.js.map +1 -0
- package/out/index.d.ts +26 -71
- package/out/index.d.ts.map +1 -1
- package/out/index.js +21 -47
- package/out/index.js.map +1 -1
- package/out/map/AppIdentity.d.ts +42 -0
- package/out/map/AppIdentity.d.ts.map +1 -0
- package/out/map/AppIdentity.js +16 -0
- package/out/map/AppIdentity.js.map +1 -0
- package/out/map/BackendControl.d.ts +9 -10
- package/out/map/BackendControl.d.ts.map +1 -1
- package/out/map/BackendControl.js +2 -2
- package/out/map/BackendControl.js.map +1 -1
- package/out/map/CompareToggle.d.ts +8 -31
- package/out/map/CompareToggle.d.ts.map +1 -1
- package/out/map/CompareToggle.js +5 -2
- package/out/map/CompareToggle.js.map +1 -1
- package/out/map/DebugInfo.d.ts +34 -0
- package/out/map/DebugInfo.d.ts.map +1 -0
- package/out/map/DebugInfo.js +39 -0
- package/out/map/DebugInfo.js.map +1 -0
- package/out/map/Geocoder.d.ts +47 -26
- package/out/map/Geocoder.d.ts.map +1 -1
- package/out/map/Geocoder.js +34 -50
- package/out/map/Geocoder.js.map +1 -1
- package/out/map/GeocoderControls.d.ts +23 -33
- package/out/map/GeocoderControls.d.ts.map +1 -1
- package/out/map/GeocoderControls.js +277 -16
- package/out/map/GeocoderControls.js.map +1 -1
- package/out/map/GraticuleLayer.d.ts +28 -0
- package/out/map/GraticuleLayer.d.ts.map +1 -0
- package/out/map/GraticuleLayer.js +25 -0
- package/out/map/GraticuleLayer.js.map +1 -0
- package/out/map/MapCanvas.d.ts +23 -12
- package/out/map/MapCanvas.d.ts.map +1 -1
- package/out/map/MapCanvas.js +5 -2
- package/out/map/MapCanvas.js.map +1 -1
- package/out/map/MapChipRow.d.ts +43 -0
- package/out/map/MapChipRow.d.ts.map +1 -0
- package/out/map/MapChipRow.js +12 -0
- package/out/map/MapChipRow.js.map +1 -0
- package/out/map/MapCompass.d.ts +33 -0
- package/out/map/MapCompass.d.ts.map +1 -0
- package/out/map/MapCompass.js +15 -0
- package/out/map/MapCompass.js.map +1 -0
- package/out/map/MapControlStack.d.ts +56 -0
- package/out/map/MapControlStack.d.ts.map +1 -0
- package/out/map/MapControlStack.js +18 -0
- package/out/map/MapControlStack.js.map +1 -0
- package/out/map/MapFooter.d.ts +27 -0
- package/out/map/MapFooter.d.ts.map +1 -0
- package/out/map/MapFooter.js +37 -0
- package/out/map/MapFooter.js.map +1 -0
- package/out/map/MapProgressBar.d.ts +31 -0
- package/out/map/MapProgressBar.d.ts.map +1 -0
- package/out/map/MapProgressBar.js +8 -0
- package/out/map/MapProgressBar.js.map +1 -0
- package/out/map/MapSearchBar.d.ts +48 -0
- package/out/map/MapSearchBar.d.ts.map +1 -0
- package/out/map/MapSearchBar.js +12 -0
- package/out/map/MapSearchBar.js.map +1 -0
- package/out/map/MapSheet.d.ts +35 -0
- package/out/map/MapSheet.d.ts.map +1 -0
- package/out/map/MapSheet.js +29 -0
- package/out/map/MapSheet.js.map +1 -0
- package/out/map/OverlayLayers.d.ts +1 -1
- package/out/map/OverlayLayers.js +2 -2
- package/out/map/PlaceAutocomplete.d.ts +10 -21
- package/out/map/PlaceAutocomplete.d.ts.map +1 -1
- package/out/map/PlaceAutocomplete.js +2 -1
- package/out/map/PlaceAutocomplete.js.map +1 -1
- package/out/map/PlaceMarker.d.ts +4 -2
- package/out/map/PlaceMarker.d.ts.map +1 -1
- package/out/map/PlaceMarker.js +3 -1
- package/out/map/PlaceMarker.js.map +1 -1
- package/out/map/ResolvedPlaceLayers.d.ts +5 -14
- package/out/map/ResolvedPlaceLayers.d.ts.map +1 -1
- package/out/map/ResolvedPlaceLayers.js +2 -2
- package/out/map/ResolvedPlaceLayers.js.map +1 -1
- package/out/map/ResultCamera.d.ts +8 -31
- package/out/map/ResultCamera.d.ts.map +1 -1
- package/out/map/ResultCamera.js +3 -28
- package/out/map/ResultCamera.js.map +1 -1
- package/out/map/ResultOverlay.d.ts +2 -12
- package/out/map/ResultOverlay.d.ts.map +1 -1
- package/out/map/ResultOverlay.js +1 -2
- package/out/map/ResultOverlay.js.map +1 -1
- package/out/map/ResultPanel.d.ts +1 -20
- 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 +7 -19
- package/out/map/VersionPicker.d.ts.map +1 -1
- package/out/map/VersionPicker.js +5 -2
- package/out/map/VersionPicker.js.map +1 -1
- package/out/map/fake-runtime.d.ts +9 -11
- package/out/map/fake-runtime.d.ts.map +1 -1
- package/out/map/fake-runtime.js +9 -12
- package/out/map/fake-runtime.js.map +1 -1
- package/out/map/geometry.d.ts +13 -34
- package/out/map/geometry.d.ts.map +1 -1
- package/out/map/geometry.js +9 -34
- package/out/map/geometry.js.map +1 -1
- package/out/map/graticule.d.ts +17 -0
- package/out/map/graticule.d.ts.map +1 -0
- package/out/map/graticule.js +67 -0
- package/out/map/graticule.js.map +1 -0
- package/out/map/map-debug.d.ts +1 -1
- package/out/map/map-debug.d.ts.map +1 -1
- package/out/map/map-debug.js +1 -1
- package/out/map/map-debug.js.map +1 -1
- package/out/map/place-render.d.ts +23 -43
- package/out/map/place-render.d.ts.map +1 -1
- package/out/map/place-render.js +4 -39
- package/out/map/place-render.js.map +1 -1
- package/out/map/types.d.ts +67 -95
- package/out/map/types.d.ts.map +1 -1
- package/out/map/types.js +1 -10
- package/out/map/types.js.map +1 -1
- package/out/map/useCompareState.d.ts +5 -4
- package/out/map/useCompareState.d.ts.map +1 -1
- package/out/map/useCompareState.js +3 -3
- package/out/map/useCompareState.js.map +1 -1
- package/out/map/useGeocode.d.ts +5 -3
- package/out/map/useGeocode.d.ts.map +1 -1
- package/out/map/useGeocode.js +4 -4
- package/out/map/useGeocode.js.map +1 -1
- package/out/map/useMapBearing.d.ts +28 -0
- package/out/map/useMapBearing.d.ts.map +1 -0
- package/out/map/useMapBearing.js +30 -0
- package/out/map/useMapBearing.js.map +1 -0
- package/out/map/useMapLabelPick.d.ts +13 -0
- package/out/map/useMapLabelPick.d.ts.map +1 -0
- package/out/map/useMapLabelPick.js +95 -0
- package/out/map/useMapLabelPick.js.map +1 -0
- package/out/map/useMapPlaceRender.d.ts +2 -6
- package/out/map/useMapPlaceRender.d.ts.map +1 -1
- package/out/map/useMapPlaceRender.js +2 -6
- package/out/map/useMapPlaceRender.js.map +1 -1
- package/out/map/usePlaceAutocomplete.d.ts +30 -28
- package/out/map/usePlaceAutocomplete.d.ts.map +1 -1
- package/out/map/usePlaceAutocomplete.js +6 -33
- package/out/map/usePlaceAutocomplete.js.map +1 -1
- package/out/map.d.ts +69 -0
- package/out/map.d.ts.map +1 -0
- package/out/map.js +46 -0
- package/out/map.js.map +1 -0
- package/out/pipeline/CandidatePicker.d.ts +12 -2
- package/out/pipeline/CandidatePicker.d.ts.map +1 -1
- package/out/pipeline/CandidatePicker.js +2 -2
- package/out/pipeline/CandidatePicker.js.map +1 -1
- package/out/pipeline/ConfidenceCell.d.ts +1 -1
- package/out/pipeline/ConfidenceCell.js +1 -1
- package/out/pipeline/FailureDiagnostic.d.ts +8 -2
- package/out/pipeline/FailureDiagnostic.d.ts.map +1 -1
- package/out/pipeline/FailureDiagnostic.js +3 -0
- package/out/pipeline/FailureDiagnostic.js.map +1 -1
- package/out/pipeline/PipelineExplorer.js +1 -1
- package/out/pipeline/QueryForm.d.ts +5 -2
- package/out/pipeline/QueryForm.d.ts.map +1 -1
- package/out/pipeline/QueryForm.js +1 -1
- package/out/pipeline/QueryForm.js.map +1 -1
- package/out/pipeline/ResolvedPlace.js +1 -1
- package/out/pipeline/SpanHighlight.d.ts +4 -3
- package/out/pipeline/SpanHighlight.d.ts.map +1 -1
- package/out/pipeline/SpanHighlight.js +3 -2
- package/out/pipeline/SpanHighlight.js.map +1 -1
- package/out/pipeline/TimingPanel.d.ts +1 -1
- package/out/pipeline/TimingPanel.js +1 -1
- package/out/pipeline/TreeView.d.ts +1 -1
- package/out/pipeline/copy.d.ts +1 -1
- package/out/pipeline/copy.d.ts.map +1 -1
- package/out/pipeline/copy.js +4 -3
- package/out/pipeline/copy.js.map +1 -1
- package/out/pipeline/presets.d.ts +5 -4
- package/out/pipeline/presets.d.ts.map +1 -1
- package/out/pipeline/presets.js +15 -13
- package/out/pipeline/presets.js.map +1 -1
- package/out/pipeline/types.d.ts +21 -14
- package/out/pipeline/types.d.ts.map +1 -1
- package/out/pipeline/types.js +2 -4
- package/out/pipeline/types.js.map +1 -1
- package/out/pipeline/useParsePipeline.d.ts +15 -7
- package/out/pipeline/useParsePipeline.d.ts.map +1 -1
- package/out/pipeline/useParsePipeline.js +10 -7
- package/out/pipeline/useParsePipeline.js.map +1 -1
- package/out/pipeline.d.ts +33 -0
- package/out/pipeline.d.ts.map +1 -0
- package/out/pipeline.js +21 -0
- package/out/pipeline.js.map +1 -0
- package/out/poi/AbstainPanel.d.ts +1 -1
- package/out/poi/LiveResultsBlock.d.ts +2 -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/POIExplorer.d.ts +22 -12
- package/out/poi/POIExplorer.d.ts.map +1 -1
- package/out/poi/POIExplorer.js +10 -9
- package/out/poi/POIExplorer.js.map +1 -1
- package/out/poi/QueryInput.d.ts +1 -1
- package/out/poi/SubjectPanel.d.ts +2 -2
- package/out/poi/SubjectPanel.d.ts.map +1 -1
- package/out/poi/SubjectPanel.js +3 -2
- package/out/poi/SubjectPanel.js.map +1 -1
- package/out/poi/runtime.d.ts +5 -14
- package/out/poi/runtime.d.ts.map +1 -1
- package/out/poi/runtime.js +5 -16
- package/out/poi/runtime.js.map +1 -1
- package/out/poi/types.d.ts +39 -27
- package/out/poi/types.d.ts.map +1 -1
- package/out/poi/types.js +2 -4
- package/out/poi/types.js.map +1 -1
- package/out/poi/usePOISearch.d.ts +28 -17
- package/out/poi/usePOISearch.d.ts.map +1 -1
- package/out/poi/usePOISearch.js +6 -32
- package/out/poi/usePOISearch.js.map +1 -1
- package/out/poi.d.ts +23 -0
- package/out/poi.d.ts.map +1 -0
- package/out/poi.js +15 -0
- package/out/poi.js.map +1 -0
- package/out/runtime/useReleaseRuntime.d.ts +64 -65
- package/out/runtime/useReleaseRuntime.d.ts.map +1 -1
- package/out/runtime/useReleaseRuntime.js +31 -26
- package/out/runtime/useReleaseRuntime.js.map +1 -1
- package/out/runtime.d.ts +9 -0
- package/out/runtime.d.ts.map +1 -0
- package/out/runtime.js +8 -0
- package/out/runtime.js.map +1 -0
- package/out/search/SearchModal.d.ts +33 -0
- package/out/search/SearchModal.d.ts.map +1 -0
- package/out/search/SearchModal.js +187 -0
- package/out/search/SearchModal.js.map +1 -0
- package/out/search/types.d.ts +64 -0
- package/out/search/types.d.ts.map +1 -0
- package/out/search/types.js +13 -0
- package/out/search/types.js.map +1 -0
- package/out/search.d.ts +11 -0
- package/out/search.d.ts.map +1 -0
- package/out/search.js +9 -0
- package/out/search.js.map +1 -0
- package/package.json +132 -133
- package/styles.css +1340 -202
- package/tokens/index.css +26 -7
- package/tokens/tokens.json +121 -6
- package/tokens/tokens.resolver.json +1 -1
- package/lib/map/index.ts +0 -76
- package/out/map/index.d.ts +0 -52
- package/out/map/index.d.ts.map +0 -1
- package/out/map/index.js +0 -36
- package/out/map/index.js.map +0 -1
- package/styleframe.config.ts +0 -321
- package/vitest.node.config.ts +0 -20
package/README.md
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
# @mailwoman/react
|
|
2
2
|
|
|
3
|
-
React components
|
|
4
|
-
parse/geocode/POI explorers from the docs site
|
|
3
|
+
This package provides React components and headless hooks for [mailwoman](https://mailwoman.ai). It
|
|
4
|
+
packages the parse/geocode/POI explorers from the docs site as smaller parts for use in any React app.
|
|
5
5
|
|
|
6
6
|
## What's in the box
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
The package contains two composed explorers, plus the small presentational units and headless hooks
|
|
9
|
+
they are built from:
|
|
9
10
|
|
|
10
|
-
- **`POIExplorer`**
|
|
11
|
+
- **`POIExplorer`** is a self-contained POI-intent tester (classify → subject → OverpassQL). The intent
|
|
11
12
|
path runs entirely offline over `@mailwoman/kind-classifier`, `@mailwoman/poi-taxonomy`, and
|
|
12
|
-
`@mailwoman/query-shape
|
|
13
|
-
`runLiveSearch` probe, so the httpvfs/worker implementation never enters this package's graph.
|
|
14
|
-
- **`PipelineExplorer`**
|
|
13
|
+
`@mailwoman/query-shape`, without weights or network access. A live poi.db search is opt-in through an
|
|
14
|
+
injected `runLiveSearch` probe, so the httpvfs/worker implementation never enters this package's graph.
|
|
15
|
+
- **`PipelineExplorer`** is a parse and resolve tester driven by an **injected `PipelineRuntime`**. The
|
|
15
16
|
host supplies `runParse` (compute shape → classify → resolve) and the heavy visualizers as `panels`,
|
|
16
|
-
|
|
17
|
+
which keeps onnxruntime-web, sqlite-wasm, and node builtins out of this package entirely.
|
|
17
18
|
|
|
18
|
-
The headless hooks
|
|
19
|
+
The headless hooks, `usePOISearch` and `useParsePipeline`, own the state machines. The presentational
|
|
19
20
|
units (`QueryInput`, `SubjectPanel`, `OverpassBlock`, `LiveResultsBlock`, `ComponentTable`,
|
|
20
21
|
`ResolvedPlace`, `CandidatePicker`, `KindBadge`, `LoadingIndicator`, …) are pure and prop-driven.
|
|
21
22
|
|
|
@@ -26,17 +27,17 @@ import { POIExplorer, PipelineExplorer } from "@mailwoman/react"
|
|
|
26
27
|
import "@mailwoman/react/styles.css"
|
|
27
28
|
```
|
|
28
29
|
|
|
29
|
-
|
|
30
|
-
Infima
|
|
31
|
-
so the bare package import stays
|
|
30
|
+
The stylesheet ships as a standalone file (`@mailwoman/react/styles.css`). It is plain CSS with a `mw-`
|
|
31
|
+
prefix and reads Infima tokens, so it renders correctly both inside Docusaurus and standalone. No
|
|
32
|
+
component imports CSS, so the bare package import stays safe to load in Node.
|
|
32
33
|
|
|
33
34
|
## Development
|
|
34
35
|
|
|
35
|
-
- `yarn workspace @mailwoman/react storybook`
|
|
36
|
-
explorers, with mocked runtimes
|
|
37
|
-
- `yarn workspace @mailwoman/react test:browser`
|
|
36
|
+
- `yarn workspace @mailwoman/react storybook` runs Storybook (Vite) for every unit and the composed
|
|
37
|
+
explorers, with mocked runtimes that need no network or database.
|
|
38
|
+
- `yarn workspace @mailwoman/react test:browser` runs the Vitest browser-mode component and hook tests
|
|
38
39
|
(Playwright / headless Chromium).
|
|
39
40
|
|
|
40
41
|
## License
|
|
41
42
|
|
|
42
|
-
AGPL-3.0-only OR LicenseRef-Commercial
|
|
43
|
+
AGPL-3.0-only OR LicenseRef-Commercial. See the [mailwoman repository](https://github.com/sister-software/mailwoman).
|
package/fonts.css
CHANGED
|
@@ -1,59 +1,134 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The brand
|
|
2
|
+
* The brand typefaces, served from the same origin every app already preconnects to.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* `--font-weight-semibold: 600` matches the 700 face by the CSS weight-matching rules rather than
|
|
4
|
+
* The token layer binds five faces: Bliss Pro regular, medium and bold for running text and headings, Bliss Pro
|
|
5
|
+
* italic for a caption, and the variable Fira Code face (weights 300 to 700) for the `code`, `number` and `glyph`
|
|
6
|
+
* roles. Bliss Pro's figures are proportional and it has no `tnum` feature, so `number` sets in Fira Code. Bliss Pro
|
|
7
|
+
* provides no 600, so `--font-weight-semibold: 600` matches the 700 face by the CSS weight-matching rules rather than
|
|
8
|
+
* being synthesized.
|
|
9
|
+
*
|
|
10
|
+
* Each Bliss Pro face is split by `unicode-range` into a Latin file and an extended file (Latin Extended-A, Greek,
|
|
11
|
+
* Cyrillic, math), and the browser downloads the extended file only when a page uses one of its codepoints.
|
|
12
|
+
* "Bliss Pro Fallback" scales Arial to Bliss Pro's average advance and vertical metrics, so text keeps its line
|
|
13
|
+
* breaks when the web font swaps in.
|
|
8
14
|
*
|
|
9
15
|
* A rule never names a family here — it names a scale role from `tokens.css`, which names one of the five face
|
|
10
16
|
* roles. Replacing the typeface is an edit to `--font-family-*` in `styleframe.config.ts` plus this file.
|
|
11
17
|
*/
|
|
12
18
|
|
|
13
19
|
@font-face {
|
|
14
|
-
font-family: "
|
|
20
|
+
font-family: "Bliss Pro Fallback";
|
|
21
|
+
src: local("Arial");
|
|
22
|
+
size-adjust: 92%;
|
|
23
|
+
ascent-override: 103.6%;
|
|
24
|
+
descent-override: 26.2%;
|
|
25
|
+
line-gap-override: 0%;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@font-face {
|
|
29
|
+
font-family: "Bliss Pro Web";
|
|
15
30
|
font-display: swap;
|
|
16
31
|
font-weight: 400;
|
|
17
32
|
font-style: normal;
|
|
18
|
-
src: url("https://public.mailwoman.ai/fonts/
|
|
33
|
+
src: url("https://public.mailwoman.ai/fonts/BlissPro/WOFF2/BlissPro-Latin.woff2") format("woff2");
|
|
34
|
+
unicode-range:
|
|
35
|
+
U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC,
|
|
36
|
+
U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD, U+FB01-FB02;
|
|
19
37
|
}
|
|
20
38
|
|
|
21
39
|
@font-face {
|
|
22
|
-
font-family: "
|
|
40
|
+
font-family: "Bliss Pro Web";
|
|
23
41
|
font-display: swap;
|
|
24
|
-
font-weight:
|
|
42
|
+
font-weight: 400;
|
|
25
43
|
font-style: normal;
|
|
26
|
-
src: url("https://public.mailwoman.ai/fonts/
|
|
44
|
+
src: url("https://public.mailwoman.ai/fonts/BlissPro/WOFF2/BlissPro-Extended.woff2") format("woff2");
|
|
45
|
+
unicode-range:
|
|
46
|
+
U+0100-0129, U+012B-012C, U+012E-0130, U+0132-0137, U+0139-0148, U+014A-0151, U+0154-017E, U+0192, U+01FA-01FF,
|
|
47
|
+
U+0218-0219, U+02C7, U+02D8-02D9, U+02DB, U+02DD, U+0315, U+0326, U+0386, U+0388-038A, U+038C, U+038E-0393,
|
|
48
|
+
U+0395-03A1, U+03A3-03CE, U+0400-045F, U+0462-0463, U+0472-0475, U+0490-0491, U+1E80-1E85, U+1EF2-1EF3, U+2070,
|
|
49
|
+
U+2074-2089, U+208D-208E, U+2113, U+2116-2117, U+212E, U+2153-2154, U+215B-215E, U+2202, U+2206, U+220F, U+2211,
|
|
50
|
+
U+221A, U+221E, U+222B, U+2248, U+2260, U+2264-2265, U+25CA;
|
|
27
51
|
}
|
|
28
52
|
|
|
29
53
|
@font-face {
|
|
30
|
-
font-family: "
|
|
54
|
+
font-family: "Bliss Pro Web";
|
|
31
55
|
font-display: swap;
|
|
32
|
-
font-weight:
|
|
33
|
-
font-style:
|
|
34
|
-
src: url("https://public.mailwoman.ai/fonts/
|
|
56
|
+
font-weight: 400;
|
|
57
|
+
font-style: italic;
|
|
58
|
+
src: url("https://public.mailwoman.ai/fonts/BlissPro/WOFF2/BlissPro-Italic-Latin.woff2") format("woff2");
|
|
59
|
+
unicode-range:
|
|
60
|
+
U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC,
|
|
61
|
+
U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD, U+FB01-FB02;
|
|
35
62
|
}
|
|
36
63
|
|
|
37
64
|
@font-face {
|
|
38
|
-
font-family: "
|
|
65
|
+
font-family: "Bliss Pro Web";
|
|
39
66
|
font-display: swap;
|
|
40
67
|
font-weight: 400;
|
|
41
68
|
font-style: italic;
|
|
42
|
-
src: url("https://public.mailwoman.ai/fonts/
|
|
69
|
+
src: url("https://public.mailwoman.ai/fonts/BlissPro/WOFF2/BlissPro-Italic-Extended.woff2") format("woff2");
|
|
70
|
+
unicode-range:
|
|
71
|
+
U+0100-0129, U+012B-012C, U+012E-0130, U+0132-0137, U+0139-0148, U+014A-0151, U+0154-017E, U+0192, U+01FA-01FF,
|
|
72
|
+
U+0218-0219, U+02C7, U+02D8-02D9, U+02DB, U+02DD, U+0315, U+0326, U+0386, U+0388-038A, U+038C, U+038E-0393,
|
|
73
|
+
U+0395-03A1, U+03A3-03CE, U+0400-045F, U+0462-0463, U+0472-0475, U+0490-0491, U+1E80-1E85, U+1EF2-1EF3, U+2070,
|
|
74
|
+
U+2074-2089, U+208D-208E, U+2113, U+2116-2117, U+212E, U+2153-2154, U+215B-215E, U+2202, U+2206, U+220F, U+2211,
|
|
75
|
+
U+221A, U+221E, U+222B, U+2248, U+2260, U+2264-2265, U+25CA;
|
|
43
76
|
}
|
|
44
77
|
|
|
45
78
|
@font-face {
|
|
46
|
-
font-family: "
|
|
79
|
+
font-family: "Bliss Pro Web";
|
|
47
80
|
font-display: swap;
|
|
48
|
-
font-weight:
|
|
81
|
+
font-weight: 500;
|
|
82
|
+
font-style: normal;
|
|
83
|
+
src: url("https://public.mailwoman.ai/fonts/BlissPro/WOFF2/BlissPro-Medium-Latin.woff2") format("woff2");
|
|
84
|
+
unicode-range:
|
|
85
|
+
U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC,
|
|
86
|
+
U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD, U+FB01-FB02;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
@font-face {
|
|
90
|
+
font-family: "Bliss Pro Web";
|
|
91
|
+
font-display: swap;
|
|
92
|
+
font-weight: 500;
|
|
93
|
+
font-style: normal;
|
|
94
|
+
src: url("https://public.mailwoman.ai/fonts/BlissPro/WOFF2/BlissPro-Medium-Extended.woff2") format("woff2");
|
|
95
|
+
unicode-range:
|
|
96
|
+
U+0100-0129, U+012B-012C, U+012E-0130, U+0132-0137, U+0139-0148, U+014A-0151, U+0154-017E, U+0192, U+01FA-01FF,
|
|
97
|
+
U+0218-0219, U+02C7, U+02D8-02D9, U+02DB, U+02DD, U+0315, U+0326, U+0386, U+0388-038A, U+038C, U+038E-0393,
|
|
98
|
+
U+0395-03A1, U+03A3-03CE, U+0400-045F, U+0462-0463, U+0472-0475, U+0490-0491, U+1E80-1E85, U+1EF2-1EF3, U+2070,
|
|
99
|
+
U+2074-2089, U+208D-208E, U+2113, U+2116-2117, U+212E, U+2153-2154, U+215B-215E, U+2202, U+2206, U+220F, U+2211,
|
|
100
|
+
U+221A, U+221E, U+222B, U+2248, U+2260, U+2264-2265, U+25CA;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
@font-face {
|
|
104
|
+
font-family: "Bliss Pro Web";
|
|
105
|
+
font-display: swap;
|
|
106
|
+
font-weight: 700;
|
|
107
|
+
font-style: normal;
|
|
108
|
+
src: url("https://public.mailwoman.ai/fonts/BlissPro/WOFF2/BlissPro-Bold-Latin.woff2") format("woff2");
|
|
109
|
+
unicode-range:
|
|
110
|
+
U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC,
|
|
111
|
+
U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD, U+FB01-FB02;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
@font-face {
|
|
115
|
+
font-family: "Bliss Pro Web";
|
|
116
|
+
font-display: swap;
|
|
117
|
+
font-weight: 700;
|
|
49
118
|
font-style: normal;
|
|
50
|
-
src: url("https://public.mailwoman.ai/fonts/
|
|
119
|
+
src: url("https://public.mailwoman.ai/fonts/BlissPro/WOFF2/BlissPro-Bold-Extended.woff2") format("woff2");
|
|
120
|
+
unicode-range:
|
|
121
|
+
U+0100-0129, U+012B-012C, U+012E-0130, U+0132-0137, U+0139-0148, U+014A-0151, U+0154-017E, U+0192, U+01FA-01FF,
|
|
122
|
+
U+0218-0219, U+02C7, U+02D8-02D9, U+02DB, U+02DD, U+0315, U+0326, U+0386, U+0388-038A, U+038C, U+038E-0393,
|
|
123
|
+
U+0395-03A1, U+03A3-03CE, U+0400-045F, U+0462-0463, U+0472-0475, U+0490-0491, U+1E80-1E85, U+1EF2-1EF3, U+2070,
|
|
124
|
+
U+2074-2089, U+208D-208E, U+2113, U+2116-2117, U+212E, U+2153-2154, U+215B-215E, U+2202, U+2206, U+220F, U+2211,
|
|
125
|
+
U+221A, U+221E, U+222B, U+2248, U+2260, U+2264-2265, U+25CA;
|
|
51
126
|
}
|
|
52
127
|
|
|
53
128
|
@font-face {
|
|
54
|
-
font-family: "
|
|
129
|
+
font-family: "Fira Code Web";
|
|
55
130
|
font-display: swap;
|
|
56
|
-
font-weight:
|
|
131
|
+
font-weight: 300 700;
|
|
57
132
|
font-style: normal;
|
|
58
|
-
src: url("https://public.mailwoman.ai/fonts/
|
|
133
|
+
src: url("https://public.mailwoman.ai/fonts/FiraCode/WOFF2/FiraCode-VF.woff2") format("woff2");
|
|
59
134
|
}
|
package/lib/common/About.tsx
CHANGED
|
@@ -3,87 +3,103 @@
|
|
|
3
3
|
* @license AGPL-3.0
|
|
4
4
|
* @author Teffen Ellis, et al.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* gazetteer resolver, the byte-range database and the FST prior. Prose about the product a host places above or
|
|
8
|
-
* beside the geocoder; it renders nothing live.
|
|
6
|
+
* `About` — the explainer for the browser geocoder: the neural model, the confidence colors, the gazetteer resolver, the byte-range database and the FST prior. It renders no live content.
|
|
9
7
|
*/
|
|
10
8
|
|
|
11
9
|
import type { ReactNode } from "react"
|
|
12
10
|
|
|
13
|
-
export
|
|
11
|
+
export interface AboutProps {
|
|
12
|
+
/**
|
|
13
|
+
* Wraps the prose in its own `<details>` disclosure.
|
|
14
|
+
*
|
|
15
|
+
* Set false where the host is already the disclosure, because a summary repeating
|
|
16
|
+
* an About 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> (< 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'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>sqlite-wasm</strong> over a read-only HTTP file system. It range-requests only the pages a lookup
|
|
77
|
+
touches. Therefore, your browser fetches 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
|
+
"Springfield" or "Cook County" that the FST can match exactly. These "FST prior"
|
|
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
|
+
|
|
14
96
|
return (
|
|
15
97
|
<details className="mw-about">
|
|
16
98
|
<summary className="mw-about__summary">
|
|
17
99
|
<span className="mw-about__icon">ℹ️</span>
|
|
18
100
|
About this geocoder
|
|
19
101
|
</summary>
|
|
20
|
-
|
|
21
|
-
<section className="mw-about__section">
|
|
22
|
-
<h3 className="mw-about__heading">Neural model</h3>
|
|
23
|
-
<p>
|
|
24
|
-
A ~29M-parameter BERT-style encoder classifies each token into one of 33 BIO labels covering 16 address
|
|
25
|
-
components (street, house number, unit, locality, region, postcode, venue, country, intersection, etc.). It
|
|
26
|
-
runs entirely in your browser via <strong>onnxruntime-web</strong> (WebGPU with WASM SIMD fallback). The
|
|
27
|
-
model ships as a 37.6 MB int8-quantized ONNX bundle; fp32 weights are also available for higher accuracy.
|
|
28
|
-
</p>
|
|
29
|
-
</section>
|
|
30
|
-
|
|
31
|
-
<section className="mw-about__section">
|
|
32
|
-
<h3 className="mw-about__heading">Confidence colors</h3>
|
|
33
|
-
<p>
|
|
34
|
-
Every classified span carries a confidence score between 0 and 1. The colors in the results table give you a
|
|
35
|
-
quick visual read:
|
|
36
|
-
</p>
|
|
37
|
-
<ul className="mw-about__legend">
|
|
38
|
-
<li className="mw-about__item">
|
|
39
|
-
<span className="mw-about__swatch mw-about__swatch--high" />
|
|
40
|
-
<strong>Green</strong> (≥ 0.8) — high confidence. The model is nearly certain.
|
|
41
|
-
</li>
|
|
42
|
-
<li className="mw-about__item">
|
|
43
|
-
<span className="mw-about__swatch mw-about__swatch--mid" />
|
|
44
|
-
<strong>Amber</strong> (0.5–0.8) — moderate confidence. Worth verifying.
|
|
45
|
-
</li>
|
|
46
|
-
<li className="mw-about__item">
|
|
47
|
-
<span className="mw-about__swatch mw-about__swatch--low" />
|
|
48
|
-
<strong>Red</strong> (< 0.5) — low confidence. The model is unsure — likely wrong.
|
|
49
|
-
</li>
|
|
50
|
-
</ul>
|
|
51
|
-
<p>
|
|
52
|
-
These are raw model scores. For calibrated probabilities, the library ships a per-locale isotonic calibrator
|
|
53
|
-
(<code>calibration.json</code>) that maps the raw scores to well-calibrated probability estimates.
|
|
54
|
-
</p>
|
|
55
|
-
</section>
|
|
56
|
-
|
|
57
|
-
<section className="mw-about__section">
|
|
58
|
-
<h3 className="mw-about__heading">WOF resolver</h3>
|
|
59
|
-
<p>
|
|
60
|
-
After classification, the resolver queries a <strong>Who's On First</strong> (WOF) SQLite gazetteer to
|
|
61
|
-
match the parsed components — locality, region, and postcode — against real-world places with coordinates.
|
|
62
|
-
The cascade tries postcode first (most precise), then locality, then the raw input text. The result is a
|
|
63
|
-
sorted list of candidate places with WOF IDs, placetypes, lat/lon, and bounding boxes.
|
|
64
|
-
</p>
|
|
65
|
-
</section>
|
|
66
|
-
|
|
67
|
-
<section className="mw-about__section">
|
|
68
|
-
<h3 className="mw-about__heading">Byte-range gazetteer</h3>
|
|
69
|
-
<p>
|
|
70
|
-
The gazetteer is a multi-gigabyte SQLite file served from a public bucket. It loads via{" "}
|
|
71
|
-
<strong>sql.js-httpvfs</strong>, which range-requests only the pages a lookup touches, so your browser
|
|
72
|
-
fetches a few hundred kilobytes per session instead of the whole file.
|
|
73
|
-
</p>
|
|
74
|
-
</section>
|
|
75
|
-
|
|
76
|
-
<section className="mw-about__section">
|
|
77
|
-
<h3 className="mw-about__heading">FST prior</h3>
|
|
78
|
-
<p>
|
|
79
|
-
A <strong>finite-state transducer</strong> (FST) built from ~94K US place names runs before the neural
|
|
80
|
-
classifier. It pre-annotates known locality, region, and postcode spans in the input — places like
|
|
81
|
-
"Springfield" or "Cook County" that the FST can match exactly. These "FST
|
|
82
|
-
prior" hits feed the classifier as strong hints, improving locality and region recall on addresses
|
|
83
|
-
where the neural model alone might miss them. The FST is active whenever the selected release includes it.
|
|
84
|
-
</p>
|
|
85
|
-
</section>
|
|
86
|
-
</div>
|
|
102
|
+
{body}
|
|
87
103
|
</details>
|
|
88
104
|
)
|
|
89
105
|
}
|
|
@@ -3,30 +3,18 @@
|
|
|
3
3
|
* @license AGPL-3.0
|
|
4
4
|
* @author Teffen Ellis, et al.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* this is the framework-agnostic equivalent so the components stay usable in any React app (Next,
|
|
8
|
-
* Remix, Docusaurus). It renders `fallback` on the server and the first client paint, then swaps to
|
|
9
|
-
* `children()` once mounted — keeping timers, clipboard, and dynamic imports off the server render.
|
|
10
|
-
*
|
|
11
|
-
* The mount flag comes from `useSyncExternalStore` with a constant snapshot pair — `false` on the
|
|
12
|
-
* server, `true` in the browser — which is the store-shaped statement of exactly this boundary. The
|
|
13
|
-
* earlier `useState(false)` + `useEffect(() => setMounted(true))` said the same thing with a
|
|
14
|
-
* render-cascade the react(set-state-in-effect) rule rightly flags: the second render was the
|
|
15
|
-
* mechanism, not an accident, and the store form gets the same second paint without a set-state.
|
|
6
|
+
* `ClientOnly` — a portable SSR boundary that renders `fallback` on the server and first client paint. It swaps to `children()` after mounting, keeping timers, clipboard and dynamic imports off the server render.
|
|
16
7
|
*/
|
|
17
8
|
|
|
18
9
|
import { type ReactNode, useSyncExternalStore } from "react"
|
|
19
10
|
|
|
20
|
-
/**
|
|
21
|
-
* The boundary never changes after mount, so nothing ever notifies.
|
|
22
|
-
*/
|
|
23
11
|
function subscribeNever(): () => void {
|
|
24
12
|
return () => {}
|
|
25
13
|
}
|
|
26
14
|
|
|
27
15
|
export interface ClientOnlyProps {
|
|
28
16
|
/**
|
|
29
|
-
* Rendered once mounted in the browser
|
|
17
|
+
* Rendered once mounted in the browser, as a thunk so its browser-only imports never run on the server.
|
|
30
18
|
*/
|
|
31
19
|
children: () => ReactNode
|
|
32
20
|
/**
|
|
@@ -13,7 +13,9 @@ import { useClipboard } from "#common/useClipboard"
|
|
|
13
13
|
|
|
14
14
|
export interface CopyButtonProps {
|
|
15
15
|
/**
|
|
16
|
-
* The text to copy.
|
|
16
|
+
* The text to copy.
|
|
17
|
+
*
|
|
18
|
+
* If a thunk, it's evaluated at click time (so callers can copy the latest value).
|
|
17
19
|
*/
|
|
18
20
|
value: string | (() => string)
|
|
19
21
|
/**
|
|
@@ -21,7 +21,8 @@ export interface LoadingIndicatorProps extends React.HTMLAttributes<HTMLDivEleme
|
|
|
21
21
|
*/
|
|
22
22
|
mode?: LoadingMode
|
|
23
23
|
/**
|
|
24
|
-
* Optional label
|
|
24
|
+
* Optional label.
|
|
25
|
+
* In staged mode it renders above the step list.
|
|
25
26
|
*/
|
|
26
27
|
label?: string
|
|
27
28
|
/**
|
|
@@ -37,7 +38,8 @@ export interface LoadingIndicatorProps extends React.HTMLAttributes<HTMLDivEleme
|
|
|
37
38
|
*/
|
|
38
39
|
steps?: string[]
|
|
39
40
|
/**
|
|
40
|
-
* 0-based index of the active step
|
|
41
|
+
* 0-based index of the active step.
|
|
42
|
+
* Earlier steps are complete, later ones pending. @default -1
|
|
41
43
|
*/
|
|
42
44
|
activeStep?: number
|
|
43
45
|
}
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* @license AGPL-3.0
|
|
4
4
|
* @author Teffen Ellis, et al.
|
|
5
5
|
*
|
|
6
|
-
* `PresetChips`
|
|
7
|
-
* renders a
|
|
6
|
+
* `PresetChips` is the "Try:" row of example buttons shared by both explorers. Presentational: it
|
|
7
|
+
* renders a labeled list and calls `onPick` with the chosen preset's value.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import type { ReactNode } from "react"
|
|
@@ -13,10 +13,10 @@ export interface Preset {
|
|
|
13
13
|
label: string
|
|
14
14
|
value: string
|
|
15
15
|
/**
|
|
16
|
-
* ISO country code for the placetype-pair country pin
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
16
|
+
* ISO country code for the placetype-pair country pin.
|
|
17
|
+
*
|
|
18
|
+
* A host that wires the pair prior hands this to `selectPairIndexForText`
|
|
19
|
+
* when the input still equals this preset's text.
|
|
20
20
|
*/
|
|
21
21
|
country?: string
|
|
22
22
|
}
|
|
@@ -26,11 +26,12 @@ export interface PresetChipsProps {
|
|
|
26
26
|
onPick: (value: string) => void
|
|
27
27
|
disabled?: boolean
|
|
28
28
|
/**
|
|
29
|
-
*
|
|
29
|
+
* The label shown before the choices. @default "Try:"
|
|
30
30
|
*/
|
|
31
31
|
caption?: string
|
|
32
32
|
/**
|
|
33
|
-
* Optional trailing content rendered inside the chip row after the presets
|
|
33
|
+
* Optional trailing content rendered inside the chip row after the presets
|
|
34
|
+
* (e.g. an inline permalink button).
|
|
34
35
|
*/
|
|
35
36
|
trailing?: ReactNode
|
|
36
37
|
}
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
* @copyright Sister Software
|
|
3
3
|
* @license AGPL-3.0
|
|
4
4
|
* @author Teffen Ellis, et al.
|
|
5
|
-
* @file Confidence banding shared by every component that
|
|
5
|
+
* @file Confidence banding shared by every component that colors a span by confidence.
|
|
6
6
|
*
|
|
7
|
-
* It is a presentation choice
|
|
8
|
-
* bounds only decide which
|
|
7
|
+
* It is a presentation choice rather than a model one: the parser emits a continuous confidence and these
|
|
8
|
+
* bounds only decide which color a span is drawn in, so they live here rather than anywhere the
|
|
9
9
|
* pipeline can see them.
|
|
10
10
|
*/
|
|
11
11
|
|
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
export const HIGH_CONFIDENCE_MIN = 0.8
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
|
-
* At or above this the span is drawn as medium-confidence
|
|
18
|
+
* At or above this the span is drawn as medium-confidence.
|
|
19
|
+
* Below it, low.
|
|
19
20
|
*/
|
|
20
21
|
export const MID_CONFIDENCE_MIN = 0.5
|
|
21
22
|
|
|
@@ -40,8 +41,8 @@ export function confidenceTier(confidence: number): ConfidenceTier {
|
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
/**
|
|
43
|
-
* {@link confidenceTier} for a possibly-absent confidence: an unmeasured span is drawn as `mid`
|
|
44
|
-
* older model that emits no confidence never reads as uniformly wrong.
|
|
44
|
+
* {@link confidenceTier} for a possibly-absent confidence: an unmeasured span is drawn as `mid`
|
|
45
|
+
* rather than `low`, so an older model that emits no confidence never reads as uniformly wrong.
|
|
45
46
|
*/
|
|
46
47
|
export function confidenceTierOrMid(confidence?: number): ConfidenceTier {
|
|
47
48
|
if (confidence == null) return "mid"
|
package/lib/common/cx.ts
CHANGED
|
@@ -11,7 +11,9 @@
|
|
|
11
11
|
export type ClassValue = string | number | false | null | undefined | Record<string, boolean>
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
* Join truthy class tokens
|
|
14
|
+
* Join truthy class tokens.
|
|
15
|
+
*
|
|
16
|
+
* Object entries contribute their key when the value is truthy.
|
|
15
17
|
*/
|
|
16
18
|
export function cx(...values: ClassValue[]): string {
|
|
17
19
|
const out: string[] = []
|
|
@@ -16,7 +16,7 @@ export interface WordToken {
|
|
|
16
16
|
*/
|
|
17
17
|
text: string
|
|
18
18
|
/**
|
|
19
|
-
*
|
|
19
|
+
* Whitespace before this word.
|
|
20
20
|
*/
|
|
21
21
|
whitespace: string
|
|
22
22
|
/**
|
|
@@ -36,7 +36,9 @@ export function tokenizeWords(input: string): WordToken[] {
|
|
|
36
36
|
const words: WordToken[] = []
|
|
37
37
|
let i = 0
|
|
38
38
|
|
|
39
|
-
// `charAt` answers "" past the end
|
|
39
|
+
// `charAt` answers "" past the end.
|
|
40
|
+
// It no whitespace test matches.
|
|
41
|
+
// Therefore, both walks stop at the input's length.
|
|
40
42
|
while (i < input.length) {
|
|
41
43
|
let ws = ""
|
|
42
44
|
|
|
@@ -68,8 +70,9 @@ export interface CharSpan {
|
|
|
68
70
|
}
|
|
69
71
|
|
|
70
72
|
/**
|
|
71
|
-
* Per-word index of the most specific (shortest) span covering it, or `-1` when no span overlaps the word.
|
|
72
|
-
*
|
|
73
|
+
* Per-word index of the most specific (shortest) span covering it, or `-1` when no span overlaps the word.
|
|
74
|
+
*
|
|
75
|
+
* A word is covered when any part of it falls within the span.
|
|
73
76
|
*/
|
|
74
77
|
export function shortestSpanOwners(words: readonly CharSpan[], spans: readonly CharSpan[]): number[] {
|
|
75
78
|
return words.map((word) => {
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* `useBuildInfo()` — reads the deployment's own `build.json`, resolving a failed fetch to `null` because a dev server has no such file and the page must not show an error strip.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { useEffect, useState } from "react"
|
|
10
|
+
|
|
11
|
+
export interface BuildInfoRecord {
|
|
12
|
+
/**
|
|
13
|
+
* The deployment's name: `mailwoman-earth`, `mailwoman-moon`, `mailwoman-mars`.
|
|
14
|
+
*/
|
|
15
|
+
app: string
|
|
16
|
+
revision: string
|
|
17
|
+
/**
|
|
18
|
+
* The same revision, full length — what a commit URL wants.
|
|
19
|
+
*/
|
|
20
|
+
commit?: string
|
|
21
|
+
/**
|
|
22
|
+
* ISO-8601 seconds, `Z` suffix.
|
|
23
|
+
*/
|
|
24
|
+
buildTime: string
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* The deployment record, or `null` while it loads and whenever it cannot be read.
|
|
29
|
+
*/
|
|
30
|
+
export function useBuildInfo(url = "/build.json"): BuildInfoRecord | null {
|
|
31
|
+
const [info, setInfo] = useState<BuildInfoRecord | null>(null)
|
|
32
|
+
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
const controller = new AbortController()
|
|
35
|
+
|
|
36
|
+
void (async () => {
|
|
37
|
+
try {
|
|
38
|
+
const response = await fetch(url, { signal: controller.signal })
|
|
39
|
+
|
|
40
|
+
if (!response.ok) return
|
|
41
|
+
|
|
42
|
+
const record = (await response.json()) as BuildInfoRecord
|
|
43
|
+
|
|
44
|
+
if (!controller.signal.aborted && record?.revision) {
|
|
45
|
+
setInfo(record)
|
|
46
|
+
}
|
|
47
|
+
} catch {}
|
|
48
|
+
})()
|
|
49
|
+
|
|
50
|
+
return () => controller.abort()
|
|
51
|
+
}, [url])
|
|
52
|
+
|
|
53
|
+
return info
|
|
54
|
+
}
|