@mailwoman/react 10.0.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.
Files changed (376) hide show
  1. package/README.md +17 -16
  2. package/fonts.css +97 -22
  3. package/lib/common/About.tsx +7 -7
  4. package/lib/common/ClientOnly.tsx +2 -14
  5. package/lib/common/CopyButton.tsx +3 -1
  6. package/lib/common/LoadingIndicator.tsx +4 -2
  7. package/lib/common/PresetChips.tsx +9 -8
  8. package/lib/common/confidence-tiers.ts +7 -6
  9. package/lib/common/cx.ts +3 -1
  10. package/lib/common/text-tokens.ts +7 -4
  11. package/lib/common/useBuildInfo.ts +54 -0
  12. package/lib/common/useClipboard.ts +2 -11
  13. package/lib/common.ts +22 -0
  14. package/lib/index.ts +27 -17
  15. package/lib/map/AppIdentity.tsx +85 -0
  16. package/lib/map/BackendControl.tsx +9 -10
  17. package/lib/map/CompareToggle.tsx +8 -31
  18. package/lib/map/DebugInfo.tsx +88 -0
  19. package/lib/map/Geocoder.tsx +60 -46
  20. package/lib/map/GeocoderControls.tsx +430 -134
  21. package/lib/map/GraticuleLayer.tsx +54 -0
  22. package/lib/map/MapCanvas.tsx +23 -12
  23. package/lib/map/MapChipRow.tsx +4 -8
  24. package/lib/map/MapCompass.tsx +15 -24
  25. package/lib/map/MapControlStack.tsx +8 -9
  26. package/lib/map/MapFooter.tsx +2 -16
  27. package/lib/map/MapProgressBar.tsx +10 -13
  28. package/lib/map/MapSearchBar.tsx +31 -17
  29. package/lib/map/MapSheet.tsx +24 -15
  30. package/lib/map/OverlayLayers.tsx +1 -1
  31. package/lib/map/PlaceAutocomplete.tsx +10 -21
  32. package/lib/map/PlaceMarker.tsx +4 -2
  33. package/lib/map/ResolvedPlaceLayers.tsx +5 -14
  34. package/lib/map/ResultCamera.tsx +8 -31
  35. package/lib/map/ResultOverlay.tsx +2 -12
  36. package/lib/map/ResultPanel.tsx +1 -20
  37. package/lib/map/VersionPicker.tsx +10 -19
  38. package/lib/map/fake-runtime.ts +10 -12
  39. package/lib/map/geometry.ts +14 -47
  40. package/lib/map/graticule.ts +80 -0
  41. package/lib/map/map-debug.ts +1 -1
  42. package/lib/map/place-render.ts +28 -60
  43. package/lib/map/types.ts +58 -104
  44. package/lib/map/useCompareState.ts +5 -4
  45. package/lib/map/useGeocode.ts +7 -5
  46. package/lib/map/useMapBearing.ts +13 -13
  47. package/lib/map/useMapLabelPick.ts +21 -30
  48. package/lib/map/useMapPlaceRender.ts +2 -6
  49. package/lib/map/usePlaceAutocomplete.ts +44 -50
  50. package/lib/map.ts +95 -0
  51. package/lib/pipeline/CandidatePicker.tsx +13 -5
  52. package/lib/pipeline/ConfidenceCell.tsx +1 -1
  53. package/lib/pipeline/FailureDiagnostic.tsx +8 -2
  54. package/lib/pipeline/QueryForm.tsx +5 -2
  55. package/lib/pipeline/ResolvedPlace.tsx +1 -1
  56. package/lib/pipeline/SpanHighlight.tsx +7 -5
  57. package/lib/pipeline/TimingPanel.tsx +1 -1
  58. package/lib/pipeline/TreeView.tsx +1 -1
  59. package/lib/pipeline/copy.ts +22 -25
  60. package/lib/pipeline/presets.ts +15 -13
  61. package/lib/pipeline/types.ts +21 -14
  62. package/lib/pipeline/useParsePipeline.ts +16 -13
  63. package/lib/pipeline.ts +36 -0
  64. package/lib/poi/AbstainPanel.tsx +1 -1
  65. package/lib/poi/LiveResultsBlock.tsx +2 -1
  66. package/lib/poi/POIExplorer.tsx +24 -15
  67. package/lib/poi/QueryInput.tsx +1 -1
  68. package/lib/poi/SubjectPanel.tsx +4 -3
  69. package/lib/poi/runtime.ts +5 -16
  70. package/lib/poi/types.ts +39 -27
  71. package/lib/poi/usePOISearch.ts +39 -44
  72. package/lib/poi.ts +39 -0
  73. package/lib/runtime/useReleaseRuntime.ts +125 -74
  74. package/lib/search/SearchModal.tsx +317 -0
  75. package/lib/search/search.css +144 -0
  76. package/lib/search/types.ts +67 -0
  77. package/lib/search.ts +11 -0
  78. package/out/common/About.d.ts +5 -5
  79. package/out/common/About.d.ts.map +1 -1
  80. package/out/common/About.js +1 -1
  81. package/out/common/About.js.map +1 -1
  82. package/out/common/ClientOnly.d.ts +2 -11
  83. package/out/common/ClientOnly.d.ts.map +1 -1
  84. package/out/common/ClientOnly.js +1 -13
  85. package/out/common/ClientOnly.js.map +1 -1
  86. package/out/common/CopyButton.d.ts +3 -1
  87. package/out/common/CopyButton.d.ts.map +1 -1
  88. package/out/common/CopyButton.js.map +1 -1
  89. package/out/common/LoadingIndicator.d.ts +4 -2
  90. package/out/common/LoadingIndicator.d.ts.map +1 -1
  91. package/out/common/LoadingIndicator.js.map +1 -1
  92. package/out/common/PresetChips.d.ts +9 -8
  93. package/out/common/PresetChips.d.ts.map +1 -1
  94. package/out/common/PresetChips.js.map +1 -1
  95. package/out/common/confidence-tiers.d.ts +7 -6
  96. package/out/common/confidence-tiers.d.ts.map +1 -1
  97. package/out/common/confidence-tiers.js +7 -6
  98. package/out/common/confidence-tiers.js.map +1 -1
  99. package/out/common/cx.d.ts +3 -1
  100. package/out/common/cx.d.ts.map +1 -1
  101. package/out/common/cx.js +3 -1
  102. package/out/common/cx.js.map +1 -1
  103. package/out/common/text-tokens.d.ts +4 -3
  104. package/out/common/text-tokens.d.ts.map +1 -1
  105. package/out/common/text-tokens.js +6 -3
  106. package/out/common/text-tokens.js.map +1 -1
  107. package/out/common/useBuildInfo.d.ts +27 -0
  108. package/out/common/useBuildInfo.d.ts.map +1 -0
  109. package/out/common/useBuildInfo.js +32 -0
  110. package/out/common/useBuildInfo.js.map +1 -0
  111. package/out/common/useClipboard.d.ts +1 -3
  112. package/out/common/useClipboard.d.ts.map +1 -1
  113. package/out/common/useClipboard.js +2 -11
  114. package/out/common/useClipboard.js.map +1 -1
  115. package/out/common.d.ts +22 -0
  116. package/out/common.d.ts.map +1 -0
  117. package/out/common.js +15 -0
  118. package/out/common.js.map +1 -0
  119. package/out/index.d.ts +26 -16
  120. package/out/index.d.ts.map +1 -1
  121. package/out/index.js +21 -15
  122. package/out/index.js.map +1 -1
  123. package/out/map/AppIdentity.d.ts +42 -0
  124. package/out/map/AppIdentity.d.ts.map +1 -0
  125. package/out/map/AppIdentity.js +16 -0
  126. package/out/map/AppIdentity.js.map +1 -0
  127. package/out/map/BackendControl.d.ts +9 -10
  128. package/out/map/BackendControl.d.ts.map +1 -1
  129. package/out/map/BackendControl.js +1 -1
  130. package/out/map/BackendControl.js.map +1 -1
  131. package/out/map/CompareToggle.d.ts +8 -31
  132. package/out/map/CompareToggle.d.ts.map +1 -1
  133. package/out/map/CompareToggle.js +4 -1
  134. package/out/map/CompareToggle.js.map +1 -1
  135. package/out/map/DebugInfo.d.ts +34 -0
  136. package/out/map/DebugInfo.d.ts.map +1 -0
  137. package/out/map/DebugInfo.js +39 -0
  138. package/out/map/DebugInfo.js.map +1 -0
  139. package/out/map/Geocoder.d.ts +41 -30
  140. package/out/map/Geocoder.d.ts.map +1 -1
  141. package/out/map/Geocoder.js +20 -36
  142. package/out/map/Geocoder.js.map +1 -1
  143. package/out/map/GeocoderControls.d.ts +14 -42
  144. package/out/map/GeocoderControls.d.ts.map +1 -1
  145. package/out/map/GeocoderControls.js +250 -38
  146. package/out/map/GeocoderControls.js.map +1 -1
  147. package/out/map/GraticuleLayer.d.ts +28 -0
  148. package/out/map/GraticuleLayer.d.ts.map +1 -0
  149. package/out/map/GraticuleLayer.js +25 -0
  150. package/out/map/GraticuleLayer.js.map +1 -0
  151. package/out/map/MapCanvas.d.ts +23 -12
  152. package/out/map/MapCanvas.d.ts.map +1 -1
  153. package/out/map/MapCanvas.js +5 -2
  154. package/out/map/MapCanvas.js.map +1 -1
  155. package/out/map/MapChipRow.d.ts +4 -8
  156. package/out/map/MapChipRow.d.ts.map +1 -1
  157. package/out/map/MapChipRow.js.map +1 -1
  158. package/out/map/MapCompass.d.ts +11 -20
  159. package/out/map/MapCompass.d.ts.map +1 -1
  160. package/out/map/MapCompass.js +5 -1
  161. package/out/map/MapCompass.js.map +1 -1
  162. package/out/map/MapControlStack.d.ts +8 -9
  163. package/out/map/MapControlStack.d.ts.map +1 -1
  164. package/out/map/MapControlStack.js +4 -1
  165. package/out/map/MapControlStack.js.map +1 -1
  166. package/out/map/MapFooter.d.ts +2 -15
  167. package/out/map/MapFooter.d.ts.map +1 -1
  168. package/out/map/MapFooter.js +0 -14
  169. package/out/map/MapFooter.js.map +1 -1
  170. package/out/map/MapProgressBar.d.ts +10 -13
  171. package/out/map/MapProgressBar.d.ts.map +1 -1
  172. package/out/map/MapProgressBar.js.map +1 -1
  173. package/out/map/MapSearchBar.d.ts +16 -17
  174. package/out/map/MapSearchBar.d.ts.map +1 -1
  175. package/out/map/MapSearchBar.js +6 -0
  176. package/out/map/MapSearchBar.js.map +1 -1
  177. package/out/map/MapSheet.d.ts +15 -12
  178. package/out/map/MapSheet.d.ts.map +1 -1
  179. package/out/map/MapSheet.js +8 -12
  180. package/out/map/MapSheet.js.map +1 -1
  181. package/out/map/OverlayLayers.d.ts +1 -1
  182. package/out/map/OverlayLayers.js +1 -1
  183. package/out/map/PlaceAutocomplete.d.ts +10 -21
  184. package/out/map/PlaceAutocomplete.d.ts.map +1 -1
  185. package/out/map/PlaceAutocomplete.js +2 -1
  186. package/out/map/PlaceAutocomplete.js.map +1 -1
  187. package/out/map/PlaceMarker.d.ts +4 -2
  188. package/out/map/PlaceMarker.d.ts.map +1 -1
  189. package/out/map/PlaceMarker.js +3 -1
  190. package/out/map/PlaceMarker.js.map +1 -1
  191. package/out/map/ResolvedPlaceLayers.d.ts +5 -14
  192. package/out/map/ResolvedPlaceLayers.d.ts.map +1 -1
  193. package/out/map/ResolvedPlaceLayers.js +1 -1
  194. package/out/map/ResolvedPlaceLayers.js.map +1 -1
  195. package/out/map/ResultCamera.d.ts +8 -31
  196. package/out/map/ResultCamera.d.ts.map +1 -1
  197. package/out/map/ResultCamera.js +3 -28
  198. package/out/map/ResultCamera.js.map +1 -1
  199. package/out/map/ResultOverlay.d.ts +2 -12
  200. package/out/map/ResultOverlay.d.ts.map +1 -1
  201. package/out/map/ResultOverlay.js +1 -2
  202. package/out/map/ResultOverlay.js.map +1 -1
  203. package/out/map/ResultPanel.d.ts +1 -20
  204. package/out/map/ResultPanel.d.ts.map +1 -1
  205. package/out/map/ResultPanel.js.map +1 -1
  206. package/out/map/VersionPicker.d.ts +7 -19
  207. package/out/map/VersionPicker.d.ts.map +1 -1
  208. package/out/map/VersionPicker.js +5 -2
  209. package/out/map/VersionPicker.js.map +1 -1
  210. package/out/map/fake-runtime.d.ts +9 -11
  211. package/out/map/fake-runtime.d.ts.map +1 -1
  212. package/out/map/fake-runtime.js +9 -12
  213. package/out/map/fake-runtime.js.map +1 -1
  214. package/out/map/geometry.d.ts +13 -34
  215. package/out/map/geometry.d.ts.map +1 -1
  216. package/out/map/geometry.js +9 -34
  217. package/out/map/geometry.js.map +1 -1
  218. package/out/map/graticule.d.ts +17 -0
  219. package/out/map/graticule.d.ts.map +1 -0
  220. package/out/map/graticule.js +67 -0
  221. package/out/map/graticule.js.map +1 -0
  222. package/out/map/map-debug.d.ts +1 -1
  223. package/out/map/map-debug.js +1 -1
  224. package/out/map/place-render.d.ts +23 -43
  225. package/out/map/place-render.d.ts.map +1 -1
  226. package/out/map/place-render.js +4 -39
  227. package/out/map/place-render.js.map +1 -1
  228. package/out/map/types.d.ts +58 -102
  229. package/out/map/types.d.ts.map +1 -1
  230. package/out/map/types.js +1 -10
  231. package/out/map/types.js.map +1 -1
  232. package/out/map/useCompareState.d.ts +5 -4
  233. package/out/map/useCompareState.d.ts.map +1 -1
  234. package/out/map/useCompareState.js +3 -3
  235. package/out/map/useCompareState.js.map +1 -1
  236. package/out/map/useGeocode.d.ts +5 -3
  237. package/out/map/useGeocode.d.ts.map +1 -1
  238. package/out/map/useGeocode.js +4 -4
  239. package/out/map/useGeocode.js.map +1 -1
  240. package/out/map/useMapBearing.d.ts +11 -11
  241. package/out/map/useMapBearing.d.ts.map +1 -1
  242. package/out/map/useMapBearing.js +6 -11
  243. package/out/map/useMapBearing.js.map +1 -1
  244. package/out/map/useMapLabelPick.d.ts +4 -14
  245. package/out/map/useMapLabelPick.d.ts.map +1 -1
  246. package/out/map/useMapLabelPick.js +21 -30
  247. package/out/map/useMapLabelPick.js.map +1 -1
  248. package/out/map/useMapPlaceRender.d.ts +2 -6
  249. package/out/map/useMapPlaceRender.d.ts.map +1 -1
  250. package/out/map/useMapPlaceRender.js +2 -6
  251. package/out/map/useMapPlaceRender.js.map +1 -1
  252. package/out/map/usePlaceAutocomplete.d.ts +30 -28
  253. package/out/map/usePlaceAutocomplete.d.ts.map +1 -1
  254. package/out/map/usePlaceAutocomplete.js +6 -33
  255. package/out/map/usePlaceAutocomplete.js.map +1 -1
  256. package/out/map.d.ts +69 -0
  257. package/out/map.d.ts.map +1 -0
  258. package/out/map.js +46 -0
  259. package/out/map.js.map +1 -0
  260. package/out/pipeline/CandidatePicker.d.ts +12 -2
  261. package/out/pipeline/CandidatePicker.d.ts.map +1 -1
  262. package/out/pipeline/CandidatePicker.js +1 -1
  263. package/out/pipeline/CandidatePicker.js.map +1 -1
  264. package/out/pipeline/ConfidenceCell.d.ts +1 -1
  265. package/out/pipeline/ConfidenceCell.js +1 -1
  266. package/out/pipeline/FailureDiagnostic.d.ts +8 -2
  267. package/out/pipeline/FailureDiagnostic.d.ts.map +1 -1
  268. package/out/pipeline/FailureDiagnostic.js +3 -0
  269. package/out/pipeline/FailureDiagnostic.js.map +1 -1
  270. package/out/pipeline/QueryForm.d.ts +5 -2
  271. package/out/pipeline/QueryForm.d.ts.map +1 -1
  272. package/out/pipeline/QueryForm.js.map +1 -1
  273. package/out/pipeline/SpanHighlight.d.ts +4 -3
  274. package/out/pipeline/SpanHighlight.d.ts.map +1 -1
  275. package/out/pipeline/SpanHighlight.js +3 -2
  276. package/out/pipeline/SpanHighlight.js.map +1 -1
  277. package/out/pipeline/TimingPanel.d.ts +1 -1
  278. package/out/pipeline/TreeView.d.ts +1 -1
  279. package/out/pipeline/copy.d.ts +1 -1
  280. package/out/pipeline/copy.d.ts.map +1 -1
  281. package/out/pipeline/copy.js +4 -3
  282. package/out/pipeline/copy.js.map +1 -1
  283. package/out/pipeline/presets.d.ts +5 -4
  284. package/out/pipeline/presets.d.ts.map +1 -1
  285. package/out/pipeline/presets.js +15 -13
  286. package/out/pipeline/presets.js.map +1 -1
  287. package/out/pipeline/types.d.ts +21 -14
  288. package/out/pipeline/types.d.ts.map +1 -1
  289. package/out/pipeline/types.js +2 -4
  290. package/out/pipeline/types.js.map +1 -1
  291. package/out/pipeline/useParsePipeline.d.ts +14 -9
  292. package/out/pipeline/useParsePipeline.d.ts.map +1 -1
  293. package/out/pipeline/useParsePipeline.js +7 -8
  294. package/out/pipeline/useParsePipeline.js.map +1 -1
  295. package/out/pipeline.d.ts +33 -0
  296. package/out/pipeline.d.ts.map +1 -0
  297. package/out/pipeline.js +21 -0
  298. package/out/pipeline.js.map +1 -0
  299. package/out/poi/AbstainPanel.d.ts +1 -1
  300. package/out/poi/LiveResultsBlock.d.ts +2 -1
  301. package/out/poi/LiveResultsBlock.d.ts.map +1 -1
  302. package/out/poi/LiveResultsBlock.js.map +1 -1
  303. package/out/poi/POIExplorer.d.ts +22 -12
  304. package/out/poi/POIExplorer.d.ts.map +1 -1
  305. package/out/poi/POIExplorer.js +9 -8
  306. package/out/poi/POIExplorer.js.map +1 -1
  307. package/out/poi/QueryInput.d.ts +1 -1
  308. package/out/poi/SubjectPanel.d.ts +2 -2
  309. package/out/poi/SubjectPanel.d.ts.map +1 -1
  310. package/out/poi/SubjectPanel.js +2 -1
  311. package/out/poi/SubjectPanel.js.map +1 -1
  312. package/out/poi/runtime.d.ts +5 -14
  313. package/out/poi/runtime.d.ts.map +1 -1
  314. package/out/poi/runtime.js +5 -16
  315. package/out/poi/runtime.js.map +1 -1
  316. package/out/poi/types.d.ts +39 -27
  317. package/out/poi/types.d.ts.map +1 -1
  318. package/out/poi/types.js +2 -4
  319. package/out/poi/types.js.map +1 -1
  320. package/out/poi/usePOISearch.d.ts +28 -17
  321. package/out/poi/usePOISearch.d.ts.map +1 -1
  322. package/out/poi/usePOISearch.js +6 -32
  323. package/out/poi/usePOISearch.js.map +1 -1
  324. package/out/poi.d.ts +23 -0
  325. package/out/poi.d.ts.map +1 -0
  326. package/out/poi.js +15 -0
  327. package/out/poi.js.map +1 -0
  328. package/out/runtime/useReleaseRuntime.d.ts +64 -65
  329. package/out/runtime/useReleaseRuntime.d.ts.map +1 -1
  330. package/out/runtime/useReleaseRuntime.js +31 -26
  331. package/out/runtime/useReleaseRuntime.js.map +1 -1
  332. package/out/{runtime/index.d.ts → runtime.d.ts} +1 -1
  333. package/out/runtime.d.ts.map +1 -0
  334. package/out/{runtime/index.js → runtime.js} +1 -1
  335. package/out/runtime.js.map +1 -0
  336. package/out/search/SearchModal.d.ts +33 -0
  337. package/out/search/SearchModal.d.ts.map +1 -0
  338. package/out/search/SearchModal.js +187 -0
  339. package/out/search/SearchModal.js.map +1 -0
  340. package/out/search/types.d.ts +64 -0
  341. package/out/search/types.d.ts.map +1 -0
  342. package/out/search/types.js +13 -0
  343. package/out/search/types.js.map +1 -0
  344. package/out/search.d.ts +11 -0
  345. package/out/search.d.ts.map +1 -0
  346. package/out/search.js +9 -0
  347. package/out/search.js.map +1 -0
  348. package/package.json +60 -142
  349. package/styles.css +482 -266
  350. package/tokens/index.css +24 -6
  351. package/tokens/tokens.json +114 -6
  352. package/lib/common/index.ts +0 -22
  353. package/lib/map/index.ts +0 -95
  354. package/lib/pipeline/index.ts +0 -36
  355. package/lib/poi/index.ts +0 -39
  356. package/out/common/index.d.ts +0 -22
  357. package/out/common/index.d.ts.map +0 -1
  358. package/out/common/index.js +0 -15
  359. package/out/common/index.js.map +0 -1
  360. package/out/map/index.d.ts +0 -69
  361. package/out/map/index.d.ts.map +0 -1
  362. package/out/map/index.js +0 -46
  363. package/out/map/index.js.map +0 -1
  364. package/out/pipeline/index.d.ts +0 -33
  365. package/out/pipeline/index.d.ts.map +0 -1
  366. package/out/pipeline/index.js +0 -21
  367. package/out/pipeline/index.js.map +0 -1
  368. package/out/poi/index.d.ts +0 -23
  369. package/out/poi/index.d.ts.map +0 -1
  370. package/out/poi/index.js +0 -15
  371. package/out/poi/index.js.map +0 -1
  372. package/out/runtime/index.d.ts.map +0 -1
  373. package/out/runtime/index.js.map +0 -1
  374. package/styleframe.config.ts +0 -329
  375. package/vitest.node.config.ts +0 -20
  376. /package/lib/{runtime/index.ts → runtime.ts} +0 -0
@@ -0,0 +1,85 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ *
6
+ * Renders the footer identity with the app name, an optional documentation link and the build
7
+ * commit. This component does not depend on the map.
8
+ */
9
+
10
+ import type { ReactNode } from "react"
11
+
12
+ import { useBuildInfo } from "#common/useBuildInfo"
13
+
14
+ /**
15
+ * The number of commit characters shown in the footer.
16
+ */
17
+ const DISPLAYED_LENGTH = 6
18
+
19
+ /**
20
+ * Props for {@link AppIdentity}.
21
+ */
22
+ export interface AppIdentityProps {
23
+ /**
24
+ * The app's display name, such as `Mailwoman Earth`.
25
+ */
26
+ name: ReactNode
27
+ /**
28
+ * The documentation link's target.
29
+ * The link is omitted when this is unset.
30
+ */
31
+ docsURL?: string
32
+ /**
33
+ * The documentation link's text. @default "Developer Documentation"
34
+ */
35
+ docsLabel?: string
36
+ /**
37
+ * The URL of the build record. @default "/build.json"
38
+ */
39
+ buildInfoURL?: string
40
+ /**
41
+ * Builds the commit link.
42
+ * Without it, the commit is shown as plain text.
43
+ */
44
+ commitHref?: (commit: string) => string
45
+ }
46
+
47
+ /**
48
+ * Renders the app name, documentation link and short build commit.
49
+ * The commit is omitted when no build record loads.
50
+ */
51
+ export function AppIdentity({
52
+ name,
53
+ docsURL,
54
+ docsLabel = "Developer Documentation",
55
+ buildInfoURL,
56
+ commitHref,
57
+ }: AppIdentityProps): ReactNode {
58
+ const build = useBuildInfo(buildInfoURL)
59
+ const commit = build?.commit
60
+
61
+ return (
62
+ <>
63
+ <strong>{name}</strong>
64
+ {docsURL ? (
65
+ <>
66
+ {" "}
67
+ <a href={docsURL}>{docsLabel}</a>
68
+ </>
69
+ ) : null}
70
+ {commit ? (
71
+ <>
72
+ {" ("}
73
+ {commitHref ? (
74
+ <a href={commitHref(commit)} title={`Built from ${commit}`}>
75
+ <code>{commit.slice(0, DISPLAYED_LENGTH)}</code>
76
+ </a>
77
+ ) : (
78
+ <code title={`Built from ${commit}`}>{commit.slice(0, DISPLAYED_LENGTH)}</code>
79
+ )}
80
+ {")"}
81
+ </>
82
+ ) : null}
83
+ </>
84
+ )
85
+ }
@@ -3,33 +3,32 @@
3
3
  * @license AGPL-3.0
4
4
  * @author Teffen Ellis, et al.
5
5
  *
6
- * `<BackendControl>` — the neural-backend indicator + "Force WASM" checkbox from the demo's control
7
- * panel (`_app.tsx:1255-1280`), as a dumb presentational unit. It shows which backend the runtime
8
- * resolved to (WebGPU / WASM, with the int8 size the host formats into the label) and lets the visitor
9
- * opt out of WebGPU. Props in, one boolean event out — the host re-loads the bundle on the toggle.
10
- *
11
- * NODE-SAFE: pure React, no maplibre.
6
+ * Shows the active inference backend and a checkbox that forces WASM. The host applies the change.
12
7
  */
13
8
 
14
9
  import type { ReactNode } from "react"
15
10
 
11
+ /**
12
+ * Props for {@link BackendControl}.
13
+ */
16
14
  export interface BackendControlProps {
17
15
  /**
18
- * The backend the runtime resolved to (e.g. `webgpu (28 MB int8)`); empty before it is known.
16
+ * The backend the runtime chose, such as `webgpu (28 MB int8)`.
17
+ * It is empty until known.
19
18
  */
20
19
  activeBackend?: string
21
20
  /**
22
- * Whether the CPU/WASM backend is currently forced.
21
+ * Whether the WASM backend is forced.
23
22
  */
24
23
  forceWASM: boolean
25
24
  /**
26
- * Fired when the visitor toggles the "Force WASM" checkbox.
25
+ * Called when the visitor toggles the "Force WASM" checkbox.
27
26
  */
28
27
  onForceWASMChange: (forceWASM: boolean) => void
29
28
  }
30
29
 
31
30
  /**
32
- * The backend indicator + WASM opt-out.
31
+ * Renders the backend indicator and the "Force WASM" checkbox.
33
32
  */
34
33
  export function BackendControl({ activeBackend, forceWASM, onForceWASMChange }: BackendControlProps): ReactNode {
35
34
  return (
@@ -3,55 +3,32 @@
3
3
  * @license AGPL-3.0
4
4
  * @author Teffen Ellis, et al.
5
5
  *
6
- * `<CompareToggle>` — the "Compare" checkbox plus the compare-version `<select>` from the demo's
7
- * control panel (`_app.tsx:1281-1339`), as a dumb presentational unit. Turning it on reveals a second
8
- * version picker (the primary version filtered out); the actual second parse is a host concern the
9
- * composed demo surfaces through `panels.compare`. Props in, two events out.
10
- *
11
- * NODE-SAFE: pure React, no maplibre.
6
+ * Renders a compare-mode checkbox and a selector for the second model version, leaving the comparison itself to the host.
12
7
  */
13
8
 
14
9
  import type { ReactNode } from "react"
15
10
 
16
11
  import type { VersionOption } from "#map/types"
17
12
 
13
+ /**
14
+ * Props for {@link CompareToggle}.
15
+ */
18
16
  export interface CompareToggleProps {
19
- /**
20
- * The selectable model bundles (the primary version is filtered out of the compare list).
21
- */
22
17
  versions: ReadonlyArray<VersionOption>
23
- /**
24
- * The primary version, excluded from the compare options.
25
- */
26
18
  primaryVersion: string | null
27
- /**
28
- * Whether compare mode is on.
29
- */
30
19
  compareMode: boolean
31
- /**
32
- * Fired when the visitor flips compare mode.
33
- */
34
20
  onCompareModeChange: (compareMode: boolean) => void
35
- /**
36
- * The version chosen to compare against, or `null` when none is chosen.
37
- */
38
21
  compareVersion: string | null
39
- /**
40
- * Fired with the chosen compare version (or `null` when the empty option is picked).
41
- */
42
22
  onCompareVersionChange: (version: string | null) => void
43
- /**
44
- * Disable the compare-version select (e.g. while a parse or compare load runs).
45
- */
46
23
  disabled?: boolean
47
- /**
48
- * A status line rendered under the select (e.g. the compare backend, or a "Loading…" line).
49
- */
50
24
  status?: ReactNode
51
25
  }
52
26
 
53
27
  /**
54
- * The compare toggle + (when on) the compare-version selector. Renders `null` with fewer than two versions.
28
+ * Renders the compare checkbox.
29
+ *
30
+ * In compare mode, it also renders the version selector. and no control at all
31
+ * when fewer than two versions exist.
55
32
  */
56
33
  export function CompareToggle({
57
34
  versions,
@@ -0,0 +1,88 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ *
6
+ * Display and log build, model and runtime details for bug reports.
7
+ * Report the actual execution backend because successful loading does not imply WebGPU ran.
8
+ */
9
+
10
+ import { type ReactNode, useEffect, useMemo } from "react"
11
+
12
+ import { useBuildInfo } from "#common/useBuildInfo"
13
+
14
+ export interface DebugInfoProps {
15
+ /**
16
+ * The backend the runtime resolved to (e.g. `webgpu (28 MB int8)`); empty before it is known.
17
+ */
18
+ activeBackend?: string
19
+ /**
20
+ * Whether the CPU/wasm backend is currently forced.
21
+ *
22
+ * This explains a `wasm` backend that would otherwise indicate a WebGPU failure.
23
+ */
24
+ forceWASM?: boolean
25
+ /**
26
+ * The model version the runtime loaded.
27
+ *
28
+ * The training series.
29
+ * It differs from the npm version.
30
+ */
31
+ selectedVersion?: string | null
32
+ /**
33
+ * Whether the asset bundle finished loading.
34
+ */
35
+ ready?: boolean
36
+ }
37
+
38
+ /**
39
+ * One row of the record, as a label and a value.
40
+ */
41
+ function Row({ label, value }: { label: string; value: string }): ReactNode {
42
+ return (
43
+ <div className="mw-debug-info__row">
44
+ <span className="mw-debug-info__label">{label}</span>
45
+ <code className="mw-debug-info__value">{value}</code>
46
+ </div>
47
+ )
48
+ }
49
+
50
+ export function DebugInfo({ activeBackend, forceWASM, selectedVersion, ready }: DebugInfoProps): ReactNode {
51
+ const build = useBuildInfo()
52
+
53
+ // Memoized on the primitives it reads, so the log below fires when a value changes
54
+ // rather than on every render.
55
+ // A record rebuilt each render would be a new object each time and log continuously.
56
+ const record = useMemo(
57
+ () => ({
58
+ app: build?.app ?? "—",
59
+ commit: build?.commit ?? build?.revision ?? "—",
60
+ buildTime: build?.buildTime ?? "—",
61
+ model: selectedVersion ?? "—",
62
+ backend: activeBackend || (ready ? "unknown" : "loading…"),
63
+ forceWASM: Boolean(forceWASM),
64
+ webgpuInBrowser: typeof navigator !== "undefined" && "gpu" in navigator,
65
+ userAgent: typeof navigator !== "undefined" ? navigator.userAgent : "—",
66
+ }),
67
+ [build?.app, build?.commit, build?.revision, build?.buildTime, selectedVersion, activeBackend, forceWASM, ready]
68
+ )
69
+
70
+ useEffect(() => {
71
+ // eslint-disable-next-line no-console -- this is the feature: the record has to reach the console a reporter copies.
72
+ console.info("[mailwoman] debug info", record)
73
+ }, [record])
74
+
75
+ return (
76
+ <div className="mw-debug-info">
77
+ <Row label="Build" value={record.app} />
78
+ <Row label="Commit" value={record.commit.slice(0, 12)} />
79
+ <Row label="Built" value={record.buildTime} />
80
+ <Row label="Model" value={record.model} />
81
+ <Row label="Backend" value={record.backend} />
82
+ {/* A browser with no WebGPU at all explains a `wasm` backend that is otherwise indistinguishable from a
83
+ WebGPU session that threw. */}
84
+ <Row label="WebGPU available" value={record.webgpuInBrowser ? "yes" : "no"} />
85
+ <Row label="Force WASM" value={record.forceWASM ? "on" : "off"} />
86
+ </div>
87
+ )
88
+ }
@@ -2,21 +2,6 @@
2
2
  * @copyright Sister Software
3
3
  * @license AGPL-3.0
4
4
  * @author Teffen Ellis, et al.
5
- *
6
- * `<Geocoder>` — the WHOLE geocoder, composed. It is the map analogue of `PipelineExplorer`
7
- * and takes the SAME DI shape: an injected {@link GeocoderRuntime} (the host owns ONNX / httpvfs / R2 /
8
- * the composed map style) plus a {@link GeocoderPanels} bag (the host's ModelVisualizer / VersionCompare /
9
- * About / Permalink). Everything here is composition + a `ClientOnly` boundary:
10
- *
11
- * - the floating {@link GeocoderControls} panel (version / compare / backend / query+autocomplete / result),
12
- * - the declarative {@link MapCanvas} with the phase-2 overlays ({@link OverlayLayers}) and the
13
- * resolved-place marker/outline/camera ({@link ResolvedPlaceLayers}) driven by the parse state,
14
- * - the hooks that wire them: {@link useGeocode} (parse + viewport bias + map place),
15
- * {@link usePlaceAutocomplete}, {@link useCompareState}.
16
- *
17
- * Because it pulls {@link MapCanvas} (→ `react-map-gl` → `maplibre-gl`, WebGL + DOM at import), it lives on
18
- * the `@mailwoman/react/map` subpath ONLY — never the package root. The whole thing renders in Storybook
19
- * over a fake runtime (offline stub style + canned geocode) with no network, no ONNX, no gazetteer.
20
5
  */
21
6
 
22
7
  import { type ReactNode, useCallback, useEffect, useRef, useState } from "react"
@@ -31,46 +16,69 @@ import { usePlaceAutocomplete } from "#map/usePlaceAutocomplete"
31
16
  import { ClientOnly } from "../common/ClientOnly.tsx"
32
17
  import type { Preset } from "../common/PresetChips.tsx"
33
18
  import { GeocoderControls } from "./GeocoderControls.tsx"
19
+ import { GraticuleLayer } from "./GraticuleLayer.tsx"
34
20
  import { MapCanvas } from "./MapCanvas.tsx"
35
21
  import { OverlayLayers } from "./OverlayLayers.tsx"
36
22
  import { ResolvedPlaceLayers } from "./ResolvedPlaceLayers.tsx"
37
23
 
24
+ /**
25
+ * Props for {@linkcode Geocoder}.
26
+ */
38
27
  export interface GeocoderProps {
39
28
  /**
40
- * The injected geocoder runtime (map style + overlays + parse + version/backend).
29
+ * The geocoder runtime supplies the map style and overlays.
30
+ *
31
+ * It also supplies the parser and version and backend controls.
41
32
  */
42
33
  runtime: GeocoderRuntime
43
34
  /**
44
- * Host-injected panels (about, release blurb, compare, permalink, debug drawer, map controls, …).
35
+ * Panels supplied by the host.
45
36
  */
46
37
  panels?: GeocoderPanels
47
38
  /**
48
- * Address to pre-fill.
39
+ * The address that pre-fills the search field.
40
+ * It is not run automatically.
49
41
  */
50
42
  defaultAddress?: string
51
43
  /**
52
- * Example chips. @default the empty set (host supplies its own).
44
+ * A query to run once when the runtime is ready, such as a permalink's `?q=` value.
45
+ *
46
+ * Unlike {@link GeocoderProps.defaultAddress}, this query is submitted,
47
+ * so a shared link reproduces its result.
48
+ */
49
+ initialQuery?: string | null
50
+ /**
51
+ * The example chips.
52
+ *
53
+ * @default []
53
54
  */
54
55
  presets?: ReadonlyArray<Preset>
55
56
  /**
56
- * Open the developer disclosure on mount — the model version, the backend readout and compare. Collapsed by default
57
- * so the address field is the first thing a visitor meets. @default false
57
+ * Whether the developer panel starts open.
58
+ *
59
+ * @default false
58
60
  */
59
61
  developer?: boolean
60
62
  /**
61
- * Fired with the query each time one is submitted. The host writes it into its own URL — this package never touches
62
- * `location`, because which parameter carries a query is the app's decision.
63
+ * Called with each user-submitted query.
64
+ *
65
+ * The host decides how to write the query to its URL.
66
+ * This package never touches `location`.
63
67
  */
64
68
  onSubmitQuery?: (query: string) => void
65
69
  /**
66
- * Only hint the viewport bias once the visitor has zoomed past the global view — a whole-globe center is noise.
67
- * Matches the `map.getZoom() >= 4` threshold. @default 4
70
+ * The minimum map zoom at which the viewport is sent as a location bias.
71
+ *
72
+ * @default 4
68
73
  */
69
74
  minBiasZoom?: number
70
75
  /**
71
- * Fly/fit the map to the resolved place on each result (via {@link ResolvedPlaceLayers}). @default true. Set false
72
- * for a host that drives the camera itself (a controlled `<MapCanvas viewState>`), or to keep a headless test
73
- * deterministic — the marker + outline still render, only the animated camera move is skipped.
76
+ * Whether the map moves to each resolved place.
77
+ *
78
+ * Set it to false when the host controls the camera or a test needs a fixed view.
79
+ * The marker and outline render either way.
80
+ *
81
+ * @default true
74
82
  */
75
83
  applyResultCamera?: boolean
76
84
  }
@@ -80,6 +88,7 @@ interface GeocoderInnerProps extends Required<
80
88
  > {
81
89
  panels: GeocoderPanels
82
90
  presets: ReadonlyArray<Preset>
91
+ initialQuery: string | null
83
92
  onSubmitQuery?: (query: string) => void
84
93
  }
85
94
 
@@ -91,23 +100,25 @@ function GeocoderInner({
91
100
  minBiasZoom,
92
101
  applyResultCamera,
93
102
  developer,
103
+ initialQuery,
94
104
  onSubmitQuery,
95
105
  }: GeocoderInnerProps): ReactNode {
96
106
  const mapRef = useRef<MapRef>(null)
97
- // The chrome sits OUTSIDE `<MapCanvas>`, so it cannot take the handle from `useMap()`. A ref alone does not
98
- // re-render the compass or the layer control when the map arrives, so the same poll that publishes the test
99
- // handle also puts it in state — one poll, two consumers.
107
+ // The controls render outside `<MapCanvas>` and cannot call `useMap()`.
108
+ // The map is kept in state so they re-render when it loads.
100
109
  const [map, setMap] = useState<ReturnType<MapRef["getMap"]> | null>(null)
101
110
 
102
- // The map announces itself; nothing polls for it. `onLoad` carries the instance, so the compass and the layer
103
- // control render on the frame the map is ready rather than up to an interval later.
104
- //
105
- // TEST INJECTION POINT: the e2e viewport-bias suite drives the REAL map (pan + zoom past the bias threshold)
106
- // before submitting, and a browser test cannot reach a React ref — so the same handle is republished on
107
- // `globalThis.__mailwomanMapCanvas`, and cleared on unmount so a torn-down geocoder leaves no stale handle.
111
+ // The graticule is inserted before the first non-background layer, so it draws under the data layers.
112
+ const [baseLayerID, setBaseLayerID] = useState<string | undefined>(undefined)
113
+
108
114
  const onMapLoad = useCallback((event: { target: ReturnType<MapRef["getMap"]> }) => {
115
+ // Browser tests read the map from this global.
109
116
  ;(globalThis as { __mailwomanMapCanvas?: ReturnType<MapRef["getMap"]> }).__mailwomanMapCanvas = event.target
110
117
  setMap(event.target)
118
+
119
+ const layers = event.target.getStyle()?.layers ?? []
120
+
121
+ setBaseLayerID(layers.find((layer) => layer.type !== "background")?.id)
111
122
  }, [])
112
123
 
113
124
  useEffect(
@@ -118,8 +129,6 @@ function GeocoderInner({
118
129
  []
119
130
  )
120
131
 
121
- // Read the viewport bias at submit time — through the map handle, never a threaded state value, so granting/zooming
122
- // mid-session doesn't re-create the parse callback. Below the min-bias zoom, a whole-globe center is noise → null.
123
132
  const getBias = useCallback((): MapBias | null => {
124
133
  const live = mapRef.current?.getMap()
125
134
 
@@ -165,10 +174,11 @@ function GeocoderInner({
165
174
  zoom: runtime.initialZoom ?? 3,
166
175
  }}
167
176
  style={{ width: "100%", height: "100%" }}
168
- // One compact attribution pill (the map's own default is a wide, always-open "MapLibre | © …" bar), no
169
- // maplibre wordmark logo.
177
+ // The attribution is compact.
178
+ // The MapLibre logo is hidden.
170
179
  mapProps={{ attributionControl: { compact: true }, maplibreLogo: false, onLoad: onMapLoad }}
171
180
  >
181
+ <GraticuleLayer beforeID={baseLayerID} />
172
182
  <OverlayLayers overlays={runtime.overlays} />
173
183
  <ResolvedPlaceLayers spec={spec} applyCamera={applyResultCamera} />
174
184
  {panels.mapControls}
@@ -183,26 +193,28 @@ function GeocoderInner({
183
193
  panels={panels}
184
194
  presets={presets}
185
195
  placeholder={defaultAddress}
196
+ initialQuery={initialQuery}
186
197
  map={map}
187
198
  onSubmitQuery={onSubmitQuery}
188
199
  onSelectVersion={onSelectVersion}
189
200
  onForceWASMChange={onForceWASMChange}
190
201
  developer={developer}
191
202
  />
192
-
193
203
  {panels.debugDrawer ? panels.debugDrawer({ result: geocode.result }) : null}
194
204
  </div>
195
205
  )
196
206
  }
197
207
 
198
- /**
199
- * Stable empty defaults — a fresh `{}`/`[]` per render would churn every downstream memo dep.
200
- */
208
+ // These defaults are module constants so each render sees the same reference and memo dependencies stay stable.
201
209
  const NO_PANELS: GeocoderPanels = {}
202
210
  const NO_PRESETS: ReadonlyArray<Preset> = []
203
211
 
204
212
  /**
205
- * The composed geocoder, behind a `ClientOnly` SSR boundary (the map is intrinsically a client component).
213
+ * Renders the map and search controls as one geocoder.
214
+ * It also renders host panels.
215
+ *
216
+ * It renders only on the client because MapLibre needs browser APIs.
217
+ * Import it from `@mailwoman/react/map`.
206
218
  */
207
219
  export function Geocoder({
208
220
  runtime,
@@ -212,6 +224,7 @@ export function Geocoder({
212
224
  minBiasZoom = 4,
213
225
  applyResultCamera = true,
214
226
  developer = false,
227
+ initialQuery = null,
215
228
  onSubmitQuery,
216
229
  }: GeocoderProps): ReactNode {
217
230
  return (
@@ -231,6 +244,7 @@ export function Geocoder({
231
244
  minBiasZoom={minBiasZoom}
232
245
  applyResultCamera={applyResultCamera}
233
246
  developer={developer}
247
+ initialQuery={initialQuery}
234
248
  onSubmitQuery={onSubmitQuery}
235
249
  />
236
250
  )}