@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/lib/poi/usePOISearch.ts
CHANGED
|
@@ -2,11 +2,6 @@
|
|
|
2
2
|
* @copyright Sister Software
|
|
3
3
|
* @license AGPL-3.0
|
|
4
4
|
* @author Teffen Ellis, et al.
|
|
5
|
-
*
|
|
6
|
-
* `usePOISearch` — the headless core of the POI explorer. Owns the taxonomy-runtime load, the
|
|
7
|
-
* debounced classify → subject → OverpassQL derivation, and the "Search live" state machine. The
|
|
8
|
-
* runtime loader and the live-search probe are both INJECTABLE, so stories/tests drive it with mocks
|
|
9
|
-
* and no network or db. Presentation is entirely the caller's concern.
|
|
10
5
|
*/
|
|
11
6
|
|
|
12
7
|
import { matchPOISubject } from "@mailwoman/kind-classifier"
|
|
@@ -19,58 +14,73 @@ import { useDebouncedValue } from "#common/useDebouncedValue"
|
|
|
19
14
|
import { loadPOIRuntime } from "#poi/runtime"
|
|
20
15
|
import type { LiveSearchState, LoadPOIRuntime, POIExplorerResult, POILiveSearch, POIRuntime } from "#poi/types"
|
|
21
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Options for {@link usePOISearch}.
|
|
19
|
+
*/
|
|
22
20
|
export interface UsePOISearchOptions {
|
|
23
21
|
/**
|
|
24
|
-
* The current query text
|
|
22
|
+
* The current query text, owned and updated by the caller.
|
|
25
23
|
*/
|
|
26
24
|
text: string
|
|
25
|
+
|
|
27
26
|
/**
|
|
28
|
-
*
|
|
27
|
+
* The loader that the hook calls once on mount.
|
|
28
|
+
* It defaults to `loadPOIRuntime`.
|
|
29
29
|
*/
|
|
30
30
|
loadRuntime?: LoadPOIRuntime
|
|
31
|
+
|
|
31
32
|
/**
|
|
32
|
-
*
|
|
33
|
+
* The live-search probe.
|
|
34
|
+
* Live search is unavailable when it is absent.
|
|
33
35
|
*/
|
|
34
36
|
runLiveSearch?: POILiveSearch
|
|
37
|
+
|
|
35
38
|
/**
|
|
36
|
-
* Whether the
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* live search is unaffected either way.
|
|
39
|
+
* Whether the probe can search for brand subjects by Wikidata ID, defaulting to
|
|
40
|
+
* false. enable it only for a server-side backend, since fetching every row for
|
|
41
|
+
* a brand over an HTTP range-request database is too slow.
|
|
40
42
|
*/
|
|
41
43
|
brandLiveSearch?: boolean
|
|
44
|
+
|
|
42
45
|
/**
|
|
43
|
-
*
|
|
46
|
+
* The delay in milliseconds before the text is classified.
|
|
47
|
+
* Defaults to 250.
|
|
44
48
|
*/
|
|
45
49
|
debounceMs?: number
|
|
46
50
|
}
|
|
47
51
|
|
|
52
|
+
/**
|
|
53
|
+
* The state that {@link usePOISearch} returns.
|
|
54
|
+
*/
|
|
48
55
|
export interface UsePOISearch {
|
|
49
56
|
/**
|
|
50
57
|
* True once the taxonomy runtime has loaded.
|
|
51
58
|
*/
|
|
52
59
|
runtimeReady: boolean
|
|
60
|
+
|
|
53
61
|
/**
|
|
54
|
-
* The
|
|
62
|
+
* The classification for the current debounced text, `null` for empty text
|
|
63
|
+
* and while classification is pending.
|
|
55
64
|
*/
|
|
56
65
|
result: POIExplorerResult | null
|
|
66
|
+
|
|
57
67
|
/**
|
|
58
|
-
*
|
|
68
|
+
* The live-search state for the current debounced text, `idle` until a search runs.
|
|
59
69
|
*/
|
|
60
70
|
liveSearch: LiveSearchState
|
|
71
|
+
|
|
61
72
|
/**
|
|
62
|
-
* Whether a
|
|
73
|
+
* Whether a probe is wired and the subject supports live search with a non-empty place anchor.
|
|
63
74
|
*/
|
|
64
75
|
canSearchLive: boolean
|
|
76
|
+
|
|
65
77
|
/**
|
|
66
|
-
*
|
|
78
|
+
* Starts a live search for the current subject.
|
|
79
|
+
* It starts no search when `canSearchLive` is false.
|
|
67
80
|
*/
|
|
68
81
|
searchLive: () => Promise<void>
|
|
69
82
|
}
|
|
70
83
|
|
|
71
|
-
/**
|
|
72
|
-
* Compute the OverpassQL export for a matched subject, capturing any emitter error rather than throwing.
|
|
73
|
-
*/
|
|
74
84
|
function buildOverpass(
|
|
75
85
|
runtime: POIRuntime,
|
|
76
86
|
categoryID: string,
|
|
@@ -95,6 +105,12 @@ function buildOverpass(
|
|
|
95
105
|
}
|
|
96
106
|
}
|
|
97
107
|
|
|
108
|
+
/**
|
|
109
|
+
* Classifies debounced query text as a POI category or brand request and runs live searches on demand.
|
|
110
|
+
*
|
|
111
|
+
* Each result is keyed to the query that produced it, live search requires a non-empty anchor.
|
|
112
|
+
* Brands need `brandLiveSearch` plus a Wikidata ID.
|
|
113
|
+
*/
|
|
98
114
|
export function usePOISearch({
|
|
99
115
|
text,
|
|
100
116
|
loadRuntime = loadPOIRuntime,
|
|
@@ -103,25 +119,14 @@ export function usePOISearch({
|
|
|
103
119
|
debounceMs = 250,
|
|
104
120
|
}: UsePOISearchOptions): UsePOISearch {
|
|
105
121
|
const [runtime, setRuntime] = useState<POIRuntime | null>(null)
|
|
106
|
-
|
|
107
|
-
* The classify result KEYED BY the query that produced it. The visible result is derived during render
|
|
108
|
-
* (`storedResult.query === trimmedText ? … : null`), so a new query invalidates the old answer by derivation — the
|
|
109
|
-
* effect never writes state synchronously to "reset", which is the react(set-state-in-effect) shape the lint bump
|
|
110
|
-
* rightly flags.
|
|
111
|
-
*/
|
|
122
|
+
|
|
112
123
|
const [storedResult, setStoredResult] = useState<{ query: string; value: POIExplorerResult } | null>(null)
|
|
113
|
-
|
|
114
|
-
* Live-search state, keyed the same way: launched FOR a query, visible only while that query stands.
|
|
115
|
-
*/
|
|
124
|
+
|
|
116
125
|
const [storedLive, setStoredLive] = useState<{ query: string; state: LiveSearchState } | null>(null)
|
|
117
126
|
|
|
118
127
|
const debouncedText = useDebouncedValue(text, debounceMs)
|
|
119
128
|
const trimmedText = debouncedText.trim()
|
|
120
129
|
|
|
121
|
-
// The load fires exactly ONCE on mount regardless of whether the caller passes a fresh `loadRuntime`
|
|
122
|
-
// closure each render (an inline `async () => …` would otherwise retrigger the effect → reload →
|
|
123
|
-
// re-render loop). `useEffectEvent` reads the LATEST closure without joining the dependency list —
|
|
124
|
-
// the runtime is a load-once resource.
|
|
125
130
|
const loadRuntimeEvent = useEffectEvent(() => loadRuntime())
|
|
126
131
|
|
|
127
132
|
useEffect(() => {
|
|
@@ -138,9 +143,6 @@ export function usePOISearch({
|
|
|
138
143
|
}
|
|
139
144
|
}, [])
|
|
140
145
|
|
|
141
|
-
// Classify the debounced query and derive the subject + OverpassQL (async, so it lives in an effect).
|
|
142
|
-
// Every state write below happens after an await — invalidation on query change is handled by the
|
|
143
|
-
// key derivation above, not by a synchronous reset here.
|
|
144
146
|
useEffect(() => {
|
|
145
147
|
if (!runtime) return
|
|
146
148
|
|
|
@@ -164,8 +166,6 @@ export function usePOISearch({
|
|
|
164
166
|
return
|
|
165
167
|
}
|
|
166
168
|
|
|
167
|
-
// Brand subject: the lexicon carries the brand's canonical name as `categoryID` + its Wikidata QID. No category
|
|
168
|
-
// record, no OverpassQL (brands are searched by QID against the layer's `brand_wikidata` index, not OSM tags).
|
|
169
169
|
if ((matched.match.kind ?? "category") === "brand") {
|
|
170
170
|
setStoredResult({
|
|
171
171
|
query: trimmed,
|
|
@@ -215,16 +215,11 @@ export function usePOISearch({
|
|
|
215
215
|
}
|
|
216
216
|
}, [trimmedText, runtime])
|
|
217
217
|
|
|
218
|
-
// Derived visibility: an answer stands only while its query does. A new query reads as null/idle
|
|
219
|
-
// with no reset write anywhere.
|
|
220
218
|
const result = storedResult?.query === trimmedText ? storedResult.value : null
|
|
221
219
|
const liveSearch: LiveSearchState = storedLive?.query === trimmedText ? storedLive.state : { status: "idle" }
|
|
222
220
|
|
|
223
221
|
const subject = result?.subject
|
|
224
222
|
|
|
225
|
-
// A subject is live-searchable when a probe is wired, it has an anchor, and: a CATEGORY that isn't build-local, or a
|
|
226
|
-
// BRAND with a QID AND a brand-capable probe (`brandLiveSearch`). Brands without a QID / without a brand probe show
|
|
227
|
-
// the intent + QID chip but no live affordance.
|
|
228
223
|
const subjectLiveCapable =
|
|
229
224
|
subject !== undefined &&
|
|
230
225
|
(subject.kind === "brand" ? brandLiveSearch && subject.wikidata !== undefined : !subject.buildLocal)
|
|
@@ -251,7 +246,7 @@ export function usePOISearch({
|
|
|
251
246
|
}
|
|
252
247
|
: {
|
|
253
248
|
categoryID: subject.category.id,
|
|
254
|
-
|
|
249
|
+
|
|
255
250
|
overtureCategoryIDs: runtime.lookup.resolveOvertureCategories(subject.category.id),
|
|
256
251
|
anchor: subject.remainder,
|
|
257
252
|
}
|
package/lib/poi.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
* @file POI explorer components, hooks, runtime and interfaces.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export { AbstainPanel } from "./poi/AbstainPanel.tsx"
|
|
9
|
+
export type { AbstainPanelProps } from "./poi/AbstainPanel.tsx"
|
|
10
|
+
export { LiveResultsBlock } from "./poi/LiveResultsBlock.tsx"
|
|
11
|
+
export type { LiveResultsBlockProps } from "./poi/LiveResultsBlock.tsx"
|
|
12
|
+
export { OverpassBlock } from "./poi/OverpassBlock.tsx"
|
|
13
|
+
export type { OverpassBlockProps } from "./poi/OverpassBlock.tsx"
|
|
14
|
+
export { POIExplorer } from "./poi/POIExplorer.tsx"
|
|
15
|
+
export type { POIExplorerProps } from "./poi/POIExplorer.tsx"
|
|
16
|
+
export { QueryInput } from "./poi/QueryInput.tsx"
|
|
17
|
+
export type { QueryInputProps } from "./poi/QueryInput.tsx"
|
|
18
|
+
export { formatDistance, loadPOIRuntime, POI_DEFAULT_TEXT, POI_PRESETS } from "#poi/runtime"
|
|
19
|
+
export { SubjectPanel } from "./poi/SubjectPanel.tsx"
|
|
20
|
+
export type { SubjectPanelProps } from "./poi/SubjectPanel.tsx"
|
|
21
|
+
|
|
22
|
+
export type {
|
|
23
|
+
CategoryRecord,
|
|
24
|
+
LiveSearchState,
|
|
25
|
+
LoadPOIRuntime,
|
|
26
|
+
POIBrandSubject,
|
|
27
|
+
POICategorySubject,
|
|
28
|
+
POIExplorerResult,
|
|
29
|
+
POILiveSearch,
|
|
30
|
+
POILiveSearchResult,
|
|
31
|
+
POIRuntime,
|
|
32
|
+
POISearchHit,
|
|
33
|
+
POISubject,
|
|
34
|
+
POISubjectBase,
|
|
35
|
+
TaxonomyLookup,
|
|
36
|
+
} from "#poi/types"
|
|
37
|
+
|
|
38
|
+
export { usePOISearch } from "#poi/usePOISearch"
|
|
39
|
+
export type { UsePOISearch, UsePOISearchOptions } from "#poi/usePOISearch"
|
|
@@ -2,172 +2,195 @@
|
|
|
2
2
|
* @copyright Sister Software
|
|
3
3
|
* @license AGPL-3.0
|
|
4
4
|
* @author Teffen Ellis, et al.
|
|
5
|
-
*
|
|
6
|
-
* `useReleaseRuntime` — the headless load-orchestration hook shared by every mailwoman browser surface (the
|
|
7
|
-
* inline doc-embeds via `RuntimeEmbed`, and the geocoder). It owns the version-selection state
|
|
8
|
-
* machine, the per-version load SEQUENCING, cancellation, and the ready / loading / error state — but
|
|
9
|
-
* NOTHING model- or map-specific. The actual asset fetchers (the ONNX classifier factory, the httpvfs
|
|
10
|
-
* WOF opener, the FST fetch, the releases.json fetch) are INJECTED by the host as async functions, so
|
|
11
|
-
* this module imports only React: no `onnxruntime-web`, no `sql.js-httpvfs`, no `maplibre-gl`, no
|
|
12
|
-
* `fetch`-specific plumbing. That keeps it node-import-safe and root-exportable from
|
|
13
|
-
* `@mailwoman/react` — the exact interface `PipelineRuntime` established, generalized to the loader itself.
|
|
14
|
-
*
|
|
15
|
-
* The hook is generic over `TAssets` (the opaque bundle the host's `loadAssets` returns — classifier,
|
|
16
|
-
* FST, WOF lookup, calibrator, …) and `TRelease` (the host's release-manifest entry). The package
|
|
17
|
-
* never inspects either; it just holds, reveals, and re-loads them across version/backend switches.
|
|
18
5
|
*/
|
|
19
6
|
|
|
20
7
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react"
|
|
21
8
|
|
|
22
9
|
/**
|
|
23
|
-
* The minimal
|
|
10
|
+
* The minimal fields of a release-manifest entry.
|
|
11
|
+
* Hosts can add their own fields.
|
|
24
12
|
*/
|
|
25
13
|
export interface ReleaseBase {
|
|
26
|
-
/**
|
|
27
|
-
* The version tag this entry describes (matched against `selectedVersion`).
|
|
28
|
-
*/
|
|
29
14
|
version: string
|
|
15
|
+
|
|
30
16
|
/**
|
|
31
|
-
*
|
|
17
|
+
* The version picker's display label, falling back to `version`.
|
|
32
18
|
*/
|
|
33
19
|
label?: string
|
|
34
20
|
}
|
|
35
21
|
|
|
36
22
|
/**
|
|
37
|
-
* The releases manifest the host fetches
|
|
23
|
+
* The releases manifest that the host fetches.
|
|
38
24
|
*/
|
|
39
25
|
export interface ReleaseManifest<TRelease extends ReleaseBase = ReleaseBase> {
|
|
40
26
|
/**
|
|
41
|
-
* The version
|
|
27
|
+
* The version that the hook selects when the manifest first loads.
|
|
42
28
|
*/
|
|
43
29
|
defaultVersion: string
|
|
44
|
-
|
|
45
|
-
* Every selectable release.
|
|
46
|
-
*/
|
|
30
|
+
|
|
47
31
|
releases: TRelease[]
|
|
48
32
|
}
|
|
49
33
|
|
|
50
34
|
/**
|
|
51
|
-
* The progress
|
|
52
|
-
*
|
|
53
|
-
*
|
|
35
|
+
* The abort signal and progress setters that the hook passes to a host's `loadAssets`.
|
|
36
|
+
*
|
|
37
|
+
* The setters stop affecting state after abort or supersession.
|
|
38
|
+
* The hook sets the final ready or error state.
|
|
54
39
|
*/
|
|
55
40
|
export interface AssetsLoadContext {
|
|
56
41
|
/**
|
|
57
|
-
*
|
|
42
|
+
* The signal aborts when a version or backend switch supersedes this load or when the component unmounts.
|
|
58
43
|
*/
|
|
59
44
|
signal: AbortSignal
|
|
45
|
+
|
|
60
46
|
/**
|
|
61
|
-
* Whether
|
|
47
|
+
* Whether this load should use the CPU WASM backend instead of WebGPU.
|
|
62
48
|
*/
|
|
63
49
|
forceWASM: boolean
|
|
50
|
+
|
|
64
51
|
/**
|
|
65
|
-
*
|
|
52
|
+
* Sets the progress line, such as `Loading v7 model (~28 MB)…`.
|
|
66
53
|
*/
|
|
67
54
|
setProgress: (progress: string) => void
|
|
68
|
-
|
|
69
|
-
* Set the staged-loader step labels (e.g. `["Loading classifier", "Loading FST gazetteer"]`).
|
|
70
|
-
*/
|
|
55
|
+
|
|
71
56
|
setStepLabels: (labels: string[]) => void
|
|
57
|
+
|
|
72
58
|
/**
|
|
73
|
-
*
|
|
59
|
+
* Sets the zero-based index of the current loader step.
|
|
74
60
|
*/
|
|
75
61
|
setStepIndex: (index: number) => void
|
|
62
|
+
|
|
76
63
|
/**
|
|
77
|
-
*
|
|
64
|
+
* Reports the backend that the neural runtime resolved to, such as `webgpu (27 MB int8)`.
|
|
78
65
|
*/
|
|
79
66
|
setBackend: (backend: string) => void
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Reports the fraction of the current download received so far, in [0, 1], or `null`
|
|
70
|
+
* when no download is in progress or the response declares no length.
|
|
71
|
+
*
|
|
72
|
+
* The step index cannot show it because the model is fetched before the first step begins.
|
|
73
|
+
*/
|
|
74
|
+
setByteFraction: (fraction: number | null) => void
|
|
80
75
|
}
|
|
81
76
|
|
|
82
77
|
/**
|
|
83
|
-
* The
|
|
78
|
+
* The host's manifest loader, asset loader and optional asset disposer for {@link useReleaseRuntime}.
|
|
84
79
|
*/
|
|
85
80
|
export interface ReleaseRuntimeConfig<TAssets, TRelease extends ReleaseBase = ReleaseBase> {
|
|
86
81
|
/**
|
|
87
|
-
*
|
|
88
|
-
*
|
|
82
|
+
* Fetches the releases manifest once on mount.
|
|
83
|
+
*
|
|
84
|
+
* It returns `null` when the manifest is unavailable.
|
|
85
|
+
* The hook reports a rejection through `errorMessage`.
|
|
89
86
|
*/
|
|
90
87
|
loadManifest: (signal: AbortSignal) => Promise<ReleaseManifest<TRelease> | null>
|
|
88
|
+
|
|
91
89
|
/**
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
* `errorMessage
|
|
90
|
+
* Loads the asset bundle for one release and reports progress through `ctx`;
|
|
91
|
+
* the hook calls it on every version or `forceWASM` change, reports a rejection through
|
|
92
|
+
* `errorMessage`, and disposes a result that resolves after `ctx.signal` aborts.
|
|
95
93
|
*/
|
|
96
94
|
loadAssets: (release: TRelease, ctx: AssetsLoadContext) => Promise<TAssets>
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Releases resources the garbage collector does not own, such as an ONNX
|
|
98
|
+
* session's WASM heap or a GPU buffer.
|
|
99
|
+
*
|
|
100
|
+
* The hook calls it when replacing a bundle.
|
|
101
|
+
* It also calls it if a bundle resolves after abort or when unmounting.
|
|
102
|
+
*
|
|
103
|
+
* Without this function, each reload leaves the model resident.
|
|
104
|
+
*/
|
|
105
|
+
disposeAssets?: (assets: TAssets) => void | Promise<void>
|
|
106
|
+
|
|
97
107
|
/**
|
|
98
|
-
* The progress line shown before the manifest arrives.
|
|
108
|
+
* The progress line shown before the manifest arrives.
|
|
109
|
+
* Defaults to `Loading releases…`.
|
|
99
110
|
*/
|
|
100
111
|
initialProgress?: string
|
|
101
112
|
}
|
|
102
113
|
|
|
103
114
|
/**
|
|
104
|
-
* The
|
|
115
|
+
* The release-loading state that {@link useReleaseRuntime} returns.
|
|
105
116
|
*
|
|
106
|
-
*
|
|
107
|
-
* `<Geocoder>` consumes). A host builds a {@link GeocoderRuntime} by pairing this loader state (assets + backend +
|
|
108
|
-
* version) with the map surface (style, overlays, bias, parse) — see the map subpath's `GeocoderRuntime`.
|
|
117
|
+
* A host pairs it with its map surface to build a `GeocoderRuntime`.
|
|
109
118
|
*/
|
|
110
119
|
export interface ReleaseLoaderState<TAssets, TRelease extends ReleaseBase = ReleaseBase> {
|
|
111
120
|
/**
|
|
112
|
-
* The releases manifest,
|
|
121
|
+
* The releases manifest, `null` until it loads or when none is available.
|
|
113
122
|
*/
|
|
114
123
|
manifest: ReleaseManifest<TRelease> | null
|
|
124
|
+
|
|
115
125
|
/**
|
|
116
|
-
* The
|
|
126
|
+
* The selected version, `null` before the manifest loads.
|
|
117
127
|
*/
|
|
118
128
|
selectedVersion: string | null
|
|
129
|
+
|
|
119
130
|
/**
|
|
120
|
-
* The
|
|
131
|
+
* The manifest entry that matches `selectedVersion`, or `null` when none matches.
|
|
121
132
|
*/
|
|
122
133
|
selectedRelease: TRelease | null
|
|
134
|
+
|
|
123
135
|
/**
|
|
124
|
-
* The
|
|
136
|
+
* The asset bundle for the selected version, `null` while it loads.
|
|
125
137
|
*/
|
|
126
138
|
assets: TAssets | null
|
|
127
|
-
|
|
128
|
-
* Whether the asset bundle is loaded and ready to use.
|
|
129
|
-
*/
|
|
139
|
+
|
|
130
140
|
ready: boolean
|
|
141
|
+
|
|
131
142
|
/**
|
|
132
|
-
*
|
|
143
|
+
* The load progress line, empty once loading finishes or fails.
|
|
133
144
|
*/
|
|
134
145
|
loadingProgress: string
|
|
146
|
+
|
|
135
147
|
/**
|
|
136
|
-
*
|
|
148
|
+
* The zero-based loader step index, `-1` before the first step.
|
|
137
149
|
*/
|
|
138
150
|
loadingStepIndex: number
|
|
151
|
+
|
|
152
|
+
loadingStepLabels: string[]
|
|
153
|
+
|
|
139
154
|
/**
|
|
140
|
-
*
|
|
155
|
+
* The fraction of the current download received so far, in [0, 1], or `null`
|
|
156
|
+
* when no download is in progress or the length is unknown.
|
|
141
157
|
*/
|
|
142
|
-
|
|
158
|
+
loadingByteFraction: number | null
|
|
159
|
+
|
|
143
160
|
/**
|
|
144
|
-
* A
|
|
161
|
+
* A manifest or asset load error, separate from any parse error a consumer tracks.
|
|
145
162
|
*/
|
|
146
163
|
errorMessage: string | null
|
|
164
|
+
|
|
147
165
|
/**
|
|
148
|
-
* The backend the neural runtime resolved to
|
|
166
|
+
* The backend the neural runtime resolved to, such as `webgpu (27 MB int8)`;
|
|
167
|
+
* it is `""` before the backend is known.
|
|
149
168
|
*/
|
|
150
169
|
activeBackend: string
|
|
170
|
+
|
|
151
171
|
/**
|
|
152
|
-
* Whether the CPU
|
|
172
|
+
* Whether the CPU WASM backend is forced instead of WebGPU.
|
|
153
173
|
*/
|
|
154
174
|
forceWASM: boolean
|
|
175
|
+
|
|
155
176
|
/**
|
|
156
|
-
*
|
|
177
|
+
* Switches to another version, clearing any error and reloading the asset bundle.
|
|
157
178
|
*/
|
|
158
179
|
selectVersion: (version: string) => void
|
|
180
|
+
|
|
159
181
|
/**
|
|
160
|
-
*
|
|
182
|
+
* Forces or releases the CPU WASM backend.
|
|
183
|
+
* Either change reloads the asset bundle.
|
|
161
184
|
*/
|
|
162
185
|
setForceWASM: (forceWASM: boolean) => void
|
|
163
186
|
}
|
|
164
187
|
|
|
165
188
|
/**
|
|
166
|
-
*
|
|
189
|
+
* Loads the release manifest on mount and the selected release's assets whenever
|
|
190
|
+
* the version or `forceWASM` changes.
|
|
167
191
|
*
|
|
168
|
-
*
|
|
169
|
-
*
|
|
170
|
-
* `loadAssets` resolves (so `ready` flips exactly once per load), and consumers wait on `ready`.
|
|
192
|
+
* Each reload aborts the previous load and disposes the old assets.
|
|
193
|
+
* `ready` becomes true after the new assets load.
|
|
171
194
|
*/
|
|
172
195
|
export function useReleaseRuntime<TAssets, TRelease extends ReleaseBase = ReleaseBase>(
|
|
173
196
|
config: ReleaseRuntimeConfig<TAssets, TRelease>
|
|
@@ -182,25 +205,24 @@ export function useReleaseRuntime<TAssets, TRelease extends ReleaseBase = Releas
|
|
|
182
205
|
const [loadingStepLabels, setLoadingStepLabels] = useState<string[]>([])
|
|
183
206
|
const [errorMessage, setErrorMessage] = useState<string | null>(null)
|
|
184
207
|
const [activeBackend, setActiveBackend] = useState<string>("")
|
|
208
|
+
const [loadingByteFraction, setLoadingByteFraction] = useState<number | null>(null)
|
|
185
209
|
const [forceWASM, setForceWASMState] = useState(false)
|
|
186
210
|
|
|
187
|
-
// Latest-ref the injected loaders: a host that re-creates them each render (an inline arrow) must NOT retrigger the
|
|
188
|
-
// load effects, which key ONLY on version/backend. The effects read `.current` at run time.
|
|
189
211
|
const loadManifestRef = useRef(config.loadManifest)
|
|
190
212
|
const loadAssetsRef = useRef(config.loadAssets)
|
|
213
|
+
const disposeAssetsRef = useRef(config.disposeAssets)
|
|
214
|
+
|
|
215
|
+
const liveAssetsRef = useRef<TAssets | null>(null)
|
|
191
216
|
|
|
192
|
-
// Latest manifest for the version-load effect, so it can resolve the release WITHOUT depending on `manifest`
|
|
193
|
-
// identity — which would double-fire the load the instant the manifest first arrives (the selection transition
|
|
194
|
-
// null → defaultVersion already fires it once).
|
|
195
217
|
const manifestRef = useRef<ReleaseManifest<TRelease> | null>(null)
|
|
196
218
|
|
|
197
219
|
useEffect(() => {
|
|
198
220
|
loadManifestRef.current = config.loadManifest
|
|
199
221
|
loadAssetsRef.current = config.loadAssets
|
|
222
|
+
disposeAssetsRef.current = config.disposeAssets
|
|
200
223
|
manifestRef.current = manifest
|
|
201
|
-
}, [config.loadAssets, config.loadManifest, manifest])
|
|
224
|
+
}, [config.disposeAssets, config.loadAssets, config.loadManifest, manifest])
|
|
202
225
|
|
|
203
|
-
// Mount: fetch the manifest, then select the default version.
|
|
204
226
|
useEffect(() => {
|
|
205
227
|
const controller = new AbortController()
|
|
206
228
|
|
|
@@ -223,7 +245,6 @@ export function useReleaseRuntime<TAssets, TRelease extends ReleaseBase = Releas
|
|
|
223
245
|
return () => controller.abort()
|
|
224
246
|
}, [])
|
|
225
247
|
|
|
226
|
-
// Load the per-version asset bundle when the version (or the backend force) changes.
|
|
227
248
|
useEffect(() => {
|
|
228
249
|
if (!selectedVersion) return
|
|
229
250
|
|
|
@@ -242,10 +263,19 @@ export function useReleaseRuntime<TAssets, TRelease extends ReleaseBase = Releas
|
|
|
242
263
|
|
|
243
264
|
void (async () => {
|
|
244
265
|
try {
|
|
266
|
+
const outgoing = liveAssetsRef.current
|
|
267
|
+
|
|
268
|
+
liveAssetsRef.current = null
|
|
269
|
+
|
|
270
|
+
if (outgoing) {
|
|
271
|
+
await disposeAssetsRef.current?.(outgoing)
|
|
272
|
+
}
|
|
273
|
+
|
|
245
274
|
setAssets(null)
|
|
246
275
|
setLoadingStepIndex(-1)
|
|
247
276
|
setLoadingStepLabels([])
|
|
248
277
|
setActiveBackend("")
|
|
278
|
+
setLoadingByteFraction(null)
|
|
249
279
|
|
|
250
280
|
const ctx: AssetsLoadContext = {
|
|
251
281
|
signal,
|
|
@@ -254,13 +284,21 @@ export function useReleaseRuntime<TAssets, TRelease extends ReleaseBase = Releas
|
|
|
254
284
|
setStepLabels: (labels) => guard(() => setLoadingStepLabels(labels)),
|
|
255
285
|
setStepIndex: (index) => guard(() => setLoadingStepIndex(index)),
|
|
256
286
|
setBackend: (backend) => guard(() => setActiveBackend(backend)),
|
|
287
|
+
setByteFraction: (fraction) => guard(() => setLoadingByteFraction(fraction)),
|
|
257
288
|
}
|
|
258
289
|
|
|
259
290
|
const loaded = await loadAssetsRef.current(release, ctx)
|
|
260
291
|
|
|
261
|
-
if (signal.aborted)
|
|
292
|
+
if (signal.aborted) {
|
|
293
|
+
await disposeAssetsRef.current?.(loaded)
|
|
294
|
+
|
|
295
|
+
return
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
liveAssetsRef.current = loaded
|
|
262
299
|
setAssets(loaded)
|
|
263
300
|
setLoadingProgress("")
|
|
301
|
+
setLoadingByteFraction(null)
|
|
264
302
|
} catch (error) {
|
|
265
303
|
if (signal.aborted) return
|
|
266
304
|
setErrorMessage(error instanceof Error ? error.message : String(error))
|
|
@@ -271,6 +309,18 @@ export function useReleaseRuntime<TAssets, TRelease extends ReleaseBase = Releas
|
|
|
271
309
|
return () => controller.abort()
|
|
272
310
|
}, [selectedVersion, forceWASM])
|
|
273
311
|
|
|
312
|
+
useEffect(() => {
|
|
313
|
+
return () => {
|
|
314
|
+
const live = liveAssetsRef.current
|
|
315
|
+
|
|
316
|
+
liveAssetsRef.current = null
|
|
317
|
+
|
|
318
|
+
if (live) {
|
|
319
|
+
void disposeAssetsRef.current?.(live)
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}, [])
|
|
323
|
+
|
|
274
324
|
const selectVersion = useCallback((version: string) => {
|
|
275
325
|
setSelectedVersion(version)
|
|
276
326
|
setErrorMessage(null)
|
|
@@ -292,6 +342,7 @@ export function useReleaseRuntime<TAssets, TRelease extends ReleaseBase = Releas
|
|
|
292
342
|
loadingProgress,
|
|
293
343
|
loadingStepIndex,
|
|
294
344
|
loadingStepLabels,
|
|
345
|
+
loadingByteFraction,
|
|
295
346
|
errorMessage,
|
|
296
347
|
activeBackend,
|
|
297
348
|
forceWASM,
|
package/lib/runtime.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
* @file Node-safe release-runtime exports.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export { useReleaseRuntime } from "#runtime/useReleaseRuntime"
|
|
9
|
+
|
|
10
|
+
export type {
|
|
11
|
+
AssetsLoadContext,
|
|
12
|
+
ReleaseBase,
|
|
13
|
+
ReleaseLoaderState,
|
|
14
|
+
ReleaseManifest,
|
|
15
|
+
ReleaseRuntimeConfig,
|
|
16
|
+
} from "#runtime/useReleaseRuntime"
|