@sjvair/monitor-map 4.3.0 → 5.0.0-beta.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 (254) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +59 -138
  3. package/dist/lib/MonitorDetailPanel.svelte +23 -20
  4. package/dist/lib/MonitorMapLayout.svelte +147 -77
  5. package/dist/lib/components/DataBox.svelte +4 -1
  6. package/dist/lib/components/ui/range-calendar/range-calendar.svelte.d.ts +1 -1
  7. package/dist/lib/config.svelte.d.ts +7 -0
  8. package/dist/lib/config.svelte.js +10 -0
  9. package/dist/lib/core.d.ts +2 -2
  10. package/dist/lib/core.js +2 -1
  11. package/dist/lib/data-chart/DataChart.svelte +40 -25
  12. package/dist/lib/data-chart/DateRange.d.ts +13 -4
  13. package/dist/lib/data-chart/DateRange.js +50 -14
  14. package/dist/lib/data-chart/chart-utils.js +5 -7
  15. package/dist/lib/data-chart/level-colors.d.ts +3 -4
  16. package/dist/lib/data-chart/level-colors.js +7 -4
  17. package/dist/lib/data-chart/pacific-time.d.ts +9 -0
  18. package/dist/lib/data-chart/pacific-time.js +25 -0
  19. package/dist/lib/data-chart/tooltip.js +2 -2
  20. package/{src/lib/ev-stations/components/EvStationTooltip.svelte → dist/lib/ev-stations/EvPopup.svelte} +6 -5
  21. package/dist/lib/ev-stations/EvPopup.svelte.d.ts +7 -0
  22. package/dist/lib/ev-stations/ev-plugin.svelte.d.ts +14 -0
  23. package/dist/lib/ev-stations/ev-plugin.svelte.js +71 -0
  24. package/dist/lib/ev-stations/ev-station-icons.d.ts +1 -4
  25. package/dist/lib/ev-stations/ev-station-icons.js +1 -13
  26. package/dist/lib/ev-stations/ev-stations.d.ts +7 -0
  27. package/dist/lib/ev-stations/ev-stations.js +53 -0
  28. package/dist/lib/ev-stations/ev-store.svelte.d.ts +21 -0
  29. package/dist/lib/ev-stations/ev-store.svelte.js +83 -0
  30. package/dist/lib/ev-stations/station-popup.svelte.d.ts +14 -0
  31. package/dist/lib/ev-stations/station-popup.svelte.js +54 -0
  32. package/dist/lib/ev-stations/types.d.ts +0 -29
  33. package/dist/lib/ev-stations/zip-codes.d.ts +11 -0
  34. package/dist/lib/ev-stations/zip-codes.js +28 -16
  35. package/dist/lib/index.d.ts +8 -56
  36. package/dist/lib/index.js +7 -46
  37. package/dist/lib/legend/Legend.svelte +18 -19
  38. package/dist/lib/legend/Legend.svelte.d.ts +2 -2
  39. package/dist/lib/levels.d.ts +7 -0
  40. package/dist/lib/levels.js +19 -0
  41. package/dist/lib/map/MapShell.svelte +17 -24
  42. package/dist/lib/map/MapShell.svelte.d.ts +4 -4
  43. package/dist/lib/map/basemaps.d.ts +25 -0
  44. package/dist/lib/map/basemaps.js +66 -0
  45. package/dist/lib/map/live-map.svelte.d.ts +3 -0
  46. package/dist/lib/map/live-map.svelte.js +22 -0
  47. package/dist/lib/map/sync-plugins.svelte.d.ts +19 -0
  48. package/dist/lib/map/sync-plugins.svelte.js +52 -0
  49. package/dist/lib/monitors/components/MonitorSubscriptionManager.svelte +66 -61
  50. package/dist/lib/monitors/filtered-source.svelte.d.ts +9 -0
  51. package/dist/lib/monitors/filtered-source.svelte.js +28 -0
  52. package/dist/lib/monitors/monitors.svelte.d.ts +25 -35
  53. package/dist/lib/monitors/monitors.svelte.js +35 -218
  54. package/dist/lib/monitors/retry-load.d.ts +8 -0
  55. package/dist/lib/monitors/retry-load.js +11 -0
  56. package/dist/lib/monitors/types.d.ts +1 -41
  57. package/dist/lib/options/map-option-defaults.d.ts +25 -36
  58. package/dist/lib/options/map-option-defaults.js +12 -30
  59. package/dist/lib/options/map-options.svelte.d.ts +13 -0
  60. package/dist/lib/options/map-options.svelte.js +26 -0
  61. package/dist/lib/options/menus/LayersMenu.svelte +8 -20
  62. package/dist/lib/options/menus/LayersMenu.svelte.d.ts +17 -2
  63. package/dist/lib/options/menus/MonitorsMenu.svelte +34 -18
  64. package/dist/lib/options/menus/OverlaysMenu.svelte +2 -2
  65. package/dist/lib/options/menus/PollutantMenu.svelte +4 -9
  66. package/dist/lib/options/menus/SettingsMenu.svelte +32 -25
  67. package/dist/lib/options/menus/SettingsMenu.svelte.d.ts +5 -16
  68. package/dist/lib/options/plugin-order.d.ts +8 -0
  69. package/dist/lib/options/plugin-order.js +36 -0
  70. package/dist/lib/options/pollutant-param.d.ts +7 -5
  71. package/dist/lib/options/pollutant-param.js +9 -5
  72. package/dist/lib/options/row-icons.d.ts +8 -0
  73. package/dist/lib/options/row-icons.js +15 -0
  74. package/dist/lib/options/rows/MarkerIcon.svelte +5 -5
  75. package/dist/lib/options/rows/MarkerIcon.svelte.d.ts +1 -2
  76. package/dist/lib/search/Search.svelte +20 -33
  77. package/dist/lib/search/Search.svelte.d.ts +5 -1
  78. package/dist/lib/search/search-pin.svelte.d.ts +11 -0
  79. package/dist/lib/search/search-pin.svelte.js +28 -0
  80. package/dist/lib/search/service.d.ts +7 -2
  81. package/dist/lib/search/service.js +17 -10
  82. package/dist/lib/stores.svelte.d.ts +8 -0
  83. package/dist/lib/stores.svelte.js +9 -0
  84. package/dist/lib/wind/wind-plugin.d.ts +11 -0
  85. package/dist/lib/wind/wind-plugin.js +25 -0
  86. package/package.json +12 -10
  87. package/src/lib/MonitorDetailPanel.svelte +23 -20
  88. package/src/lib/MonitorMapLayout.svelte +147 -77
  89. package/src/lib/components/DataBox.svelte +4 -1
  90. package/src/lib/config.svelte.ts +16 -0
  91. package/src/lib/core.ts +2 -2
  92. package/src/lib/data-chart/DataChart.svelte +40 -25
  93. package/src/lib/data-chart/DateRange.ts +58 -15
  94. package/src/lib/data-chart/chart-utils.ts +6 -7
  95. package/src/lib/data-chart/level-colors.ts +8 -9
  96. package/src/lib/data-chart/pacific-time.ts +31 -0
  97. package/src/lib/data-chart/tooltip.ts +2 -2
  98. package/{dist/lib/ev-stations/components/EvStationTooltip.svelte → src/lib/ev-stations/EvPopup.svelte} +6 -5
  99. package/src/lib/ev-stations/ev-plugin.svelte.ts +86 -0
  100. package/src/lib/ev-stations/ev-station-icons.ts +1 -17
  101. package/src/lib/ev-stations/ev-stations.ts +72 -0
  102. package/src/lib/ev-stations/ev-store.svelte.ts +117 -0
  103. package/src/lib/ev-stations/station-popup.svelte.ts +64 -0
  104. package/src/lib/ev-stations/types.ts +0 -34
  105. package/src/lib/ev-stations/zip-codes.ts +29 -16
  106. package/src/lib/index.ts +8 -99
  107. package/src/lib/legend/Legend.svelte +18 -19
  108. package/src/lib/levels.ts +24 -0
  109. package/src/lib/map/MapShell.svelte +17 -24
  110. package/src/lib/map/basemaps.ts +76 -0
  111. package/src/lib/map/live-map.svelte.ts +24 -0
  112. package/src/lib/map/sync-plugins.svelte.ts +69 -0
  113. package/src/lib/monitors/components/MonitorSubscriptionManager.svelte +66 -61
  114. package/src/lib/monitors/filtered-source.svelte.ts +38 -0
  115. package/src/lib/monitors/monitors.svelte.ts +58 -261
  116. package/src/lib/monitors/retry-load.ts +14 -0
  117. package/src/lib/monitors/types.ts +1 -47
  118. package/src/lib/options/map-option-defaults.ts +30 -53
  119. package/src/lib/options/map-options.svelte.ts +30 -0
  120. package/src/lib/options/menus/LayersMenu.svelte +8 -20
  121. package/src/lib/options/menus/MonitorsMenu.svelte +34 -18
  122. package/src/lib/options/menus/OverlaysMenu.svelte +2 -2
  123. package/src/lib/options/menus/PollutantMenu.svelte +4 -9
  124. package/src/lib/options/menus/SettingsMenu.svelte +32 -25
  125. package/src/lib/options/plugin-order.ts +38 -0
  126. package/src/lib/options/pollutant-param.ts +14 -9
  127. package/src/lib/options/row-icons.ts +17 -0
  128. package/src/lib/options/rows/MarkerIcon.svelte +5 -5
  129. package/src/lib/search/Search.svelte +20 -33
  130. package/src/lib/search/search-pin.svelte.ts +35 -0
  131. package/src/lib/search/service.ts +34 -15
  132. package/src/lib/stores.svelte.ts +15 -0
  133. package/src/lib/wind/wind-plugin.ts +33 -0
  134. package/dist/lib/collocation-sites/CollocationTooltip.svelte +0 -98
  135. package/dist/lib/collocation-sites/CollocationTooltip.svelte.d.ts +0 -7
  136. package/dist/lib/collocation-sites/collocations-icon-manager.svelte.d.ts +0 -7
  137. package/dist/lib/collocation-sites/collocations-icon-manager.svelte.js +0 -18
  138. package/dist/lib/collocation-sites/collocations-map-integration.svelte.d.ts +0 -21
  139. package/dist/lib/collocation-sites/collocations-map-integration.svelte.js +0 -113
  140. package/dist/lib/collocation-sites/collocations.svelte.d.ts +0 -10
  141. package/dist/lib/collocation-sites/collocations.svelte.js +0 -21
  142. package/dist/lib/collocation-sites/types.d.ts +0 -8
  143. package/dist/lib/collocation-sites/types.js +0 -1
  144. package/dist/lib/ev-stations/components/EvStationClusterTooltip.svelte +0 -16
  145. package/dist/lib/ev-stations/components/EvStationClusterTooltip.svelte.d.ts +0 -7
  146. package/dist/lib/ev-stations/components/EvStationTooltip.svelte.d.ts +0 -7
  147. package/dist/lib/ev-stations/ev-stations-cluster-renderer.d.ts +0 -19
  148. package/dist/lib/ev-stations/ev-stations-cluster-renderer.js +0 -131
  149. package/dist/lib/ev-stations/ev-stations-map-integration.svelte.d.ts +0 -31
  150. package/dist/lib/ev-stations/ev-stations-map-integration.svelte.js +0 -226
  151. package/dist/lib/ev-stations/ev-stations.svelte.d.ts +0 -10
  152. package/dist/lib/ev-stations/ev-stations.svelte.js +0 -57
  153. package/dist/lib/hms/hms-fire-icon-manager.d.ts +0 -13
  154. package/dist/lib/hms/hms-fire-icon-manager.js +0 -39
  155. package/dist/lib/hms/hms-fire-map-integration.svelte.d.ts +0 -23
  156. package/dist/lib/hms/hms-fire-map-integration.svelte.js +0 -94
  157. package/dist/lib/hms/hms-smoke-map-integration.svelte.d.ts +0 -39
  158. package/dist/lib/hms/hms-smoke-map-integration.svelte.js +0 -87
  159. package/dist/lib/hms/hms.svelte.d.ts +0 -20
  160. package/dist/lib/hms/hms.svelte.js +0 -237
  161. package/dist/lib/legend/LegendBar.svelte +0 -45
  162. package/dist/lib/legend/LegendBar.svelte.d.ts +0 -7
  163. package/dist/lib/legend/legend-data.d.ts +0 -40
  164. package/dist/lib/legend/legend-data.js +0 -65
  165. package/dist/lib/map/Map.svelte +0 -13
  166. package/dist/lib/map/Map.svelte.d.ts +0 -8
  167. package/dist/lib/map/basemap.d.ts +0 -14
  168. package/dist/lib/map/basemap.js +0 -10
  169. package/dist/lib/map/icons.d.ts +0 -7
  170. package/dist/lib/map/icons.js +0 -33
  171. package/dist/lib/map/integrations/base-layer-seperator.d.ts +0 -9
  172. package/dist/lib/map/integrations/base-layer-seperator.js +0 -11
  173. package/dist/lib/map/integrations/click-manager.d.ts +0 -14
  174. package/dist/lib/map/integrations/click-manager.js +0 -52
  175. package/dist/lib/map/integrations/integrations-manager.d.ts +0 -8
  176. package/dist/lib/map/integrations/integrations-manager.js +0 -20
  177. package/dist/lib/map/integrations/map-display-option.svelte.d.ts +0 -7
  178. package/dist/lib/map/integrations/map-display-option.svelte.js +0 -10
  179. package/dist/lib/map/integrations/map-geojson-integration.svelte.d.ts +0 -32
  180. package/dist/lib/map/integrations/map-geojson-integration.svelte.js +0 -60
  181. package/dist/lib/map/integrations/map-icon-manager.d.ts +0 -15
  182. package/dist/lib/map/integrations/map-icon-manager.js +0 -52
  183. package/dist/lib/map/integrations/map-integration.svelte.d.ts +0 -6
  184. package/dist/lib/map/integrations/map-integration.svelte.js +0 -2
  185. package/dist/lib/map/integrations/map-layer-integration.svelte.d.ts +0 -11
  186. package/dist/lib/map/integrations/map-layer-integration.svelte.js +0 -40
  187. package/dist/lib/map/integrations/tooltip.svelte.d.ts +0 -36
  188. package/dist/lib/map/integrations/tooltip.svelte.js +0 -131
  189. package/dist/lib/map/integrations/types.d.ts +0 -14
  190. package/dist/lib/map/integrations/types.js +0 -1
  191. package/dist/lib/map/map-manager.svelte.d.ts +0 -20
  192. package/dist/lib/map/map-manager.svelte.js +0 -63
  193. package/dist/lib/map/map-style-state.svelte.d.ts +0 -23
  194. package/dist/lib/map/map-style-state.svelte.js +0 -86
  195. package/dist/lib/map/utils.d.ts +0 -7
  196. package/dist/lib/map/utils.js +0 -36
  197. package/dist/lib/monitors/components/MonitorClusterTooltip.svelte +0 -112
  198. package/dist/lib/monitors/components/MonitorClusterTooltip.svelte.d.ts +0 -7
  199. package/dist/lib/monitors/components/MonitorTooltip.svelte +0 -61
  200. package/dist/lib/monitors/components/MonitorTooltip.svelte.d.ts +0 -7
  201. package/dist/lib/monitors/monitor-utils.d.ts +0 -4
  202. package/dist/lib/monitors/monitor-utils.js +0 -41
  203. package/dist/lib/monitors/monitors-cluster-renderer.d.ts +0 -33
  204. package/dist/lib/monitors/monitors-cluster-renderer.js +0 -221
  205. package/dist/lib/monitors/monitors-icon-manager.svelte.d.ts +0 -15
  206. package/dist/lib/monitors/monitors-icon-manager.svelte.js +0 -78
  207. package/dist/lib/monitors/monitors-map-integration.svelte.d.ts +0 -43
  208. package/dist/lib/monitors/monitors-map-integration.svelte.js +0 -301
  209. package/dist/lib/options/reset-map-options.d.ts +0 -2
  210. package/dist/lib/options/reset-map-options.js +0 -24
  211. package/dist/lib/reactivity.svelte.d.ts +0 -0
  212. package/dist/lib/reactivity.svelte.js +0 -83
  213. package/dist/lib/wind/wind.svelte.d.ts +0 -10
  214. package/dist/lib/wind/wind.svelte.js +0 -13
  215. package/src/lib/collocation-sites/CollocationTooltip.svelte +0 -98
  216. package/src/lib/collocation-sites/collocations-icon-manager.svelte.ts +0 -21
  217. package/src/lib/collocation-sites/collocations-map-integration.svelte.ts +0 -136
  218. package/src/lib/collocation-sites/collocations.svelte.ts +0 -27
  219. package/src/lib/collocation-sites/types.ts +0 -10
  220. package/src/lib/ev-stations/components/EvStationClusterTooltip.svelte +0 -16
  221. package/src/lib/ev-stations/ev-stations-cluster-renderer.ts +0 -162
  222. package/src/lib/ev-stations/ev-stations-map-integration.svelte.ts +0 -248
  223. package/src/lib/ev-stations/ev-stations.svelte.ts +0 -84
  224. package/src/lib/hms/hms-fire-icon-manager.ts +0 -48
  225. package/src/lib/hms/hms-fire-map-integration.svelte.ts +0 -109
  226. package/src/lib/hms/hms-smoke-map-integration.svelte.ts +0 -105
  227. package/src/lib/hms/hms.svelte.ts +0 -270
  228. package/src/lib/legend/LegendBar.svelte +0 -45
  229. package/src/lib/legend/legend-data.ts +0 -101
  230. package/src/lib/map/Map.svelte +0 -13
  231. package/src/lib/map/basemap.ts +0 -24
  232. package/src/lib/map/icons.ts +0 -42
  233. package/src/lib/map/integrations/base-layer-seperator.ts +0 -17
  234. package/src/lib/map/integrations/click-manager.ts +0 -64
  235. package/src/lib/map/integrations/integrations-manager.ts +0 -25
  236. package/src/lib/map/integrations/map-display-option.svelte.ts +0 -13
  237. package/src/lib/map/integrations/map-geojson-integration.svelte.ts +0 -77
  238. package/src/lib/map/integrations/map-icon-manager.ts +0 -67
  239. package/src/lib/map/integrations/map-integration.svelte.ts +0 -8
  240. package/src/lib/map/integrations/map-layer-integration.svelte.ts +0 -49
  241. package/src/lib/map/integrations/tooltip.svelte.ts +0 -153
  242. package/src/lib/map/integrations/types.ts +0 -24
  243. package/src/lib/map/map-manager.svelte.ts +0 -83
  244. package/src/lib/map/map-style-state.svelte.ts +0 -94
  245. package/src/lib/map/utils.ts +0 -53
  246. package/src/lib/monitors/components/MonitorClusterTooltip.svelte +0 -112
  247. package/src/lib/monitors/components/MonitorTooltip.svelte +0 -61
  248. package/src/lib/monitors/monitor-utils.ts +0 -57
  249. package/src/lib/monitors/monitors-cluster-renderer.ts +0 -285
  250. package/src/lib/monitors/monitors-icon-manager.svelte.ts +0 -98
  251. package/src/lib/monitors/monitors-map-integration.svelte.ts +0 -318
  252. package/src/lib/options/reset-map-options.ts +0 -28
  253. package/src/lib/reactivity.svelte.ts +0 -82
  254. package/src/lib/wind/wind.svelte.ts +0 -20
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Central California Asthma Collaborative (SJVAir)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,27 +1,43 @@
1
1
  # @sjvair/monitor-map
2
2
 
3
- SJVAir's interactive air quality monitor map, built with Svelte 5, Vite, and MapTiler
4
- SDK. It ships two ways:
3
+ SJVAir's interactive air quality monitor map, built with Svelte 5, Vite and
4
+ `@sjvair/map-sdk`. It ships two ways:
5
5
 
6
6
  - **A code-split widget** (`npm run build`), embedded via a `<div id="SJVAirMonitorMap">`
7
7
  in a Django template on sjvair.com.
8
8
  - **A component library** (`npm run build:lib`, published to npm as
9
- `@sjvair/monitor-map`), imported by the `sjvair-mobile` Capacitor app and by other SJVAir
10
- projects (e.g. `data-dashboard`) that want to embed the map or reuse its map-display
11
- logic against their own data.
9
+ `@sjvair/monitor-map`), imported by the `sjvair-mobile` Capacitor app.
12
10
 
13
11
  ## Installation
14
12
 
15
13
  ```bash
16
- npm install @sjvair/monitor-map
14
+ npm install @sjvair/monitor-map "@sjvair/sdk@npm:@jsr/sjvair__sdk@^5.0.0-beta.3"
15
+ ```
16
+
17
+ `@sjvair/sdk` (5.x) is a peer dependency, so the host and the map share one copy and the host's
18
+ `setOrigin` covers both. It is published on JSR, so the host's `.npmrc` needs
19
+ `@jsr:registry=https://npm.jsr.io` (and `allow-remote=root` on npm 12). `@sjvair/map-sdk` and
20
+ `@maptiler/sdk` are ordinary dependencies.
21
+
22
+ The 5.0 betas are on the `next` dist-tag: `npm install @sjvair/monitor-map@next`.
23
+
24
+ ## Keys
25
+
26
+ The library reads no keys. Call `configureMonitorMap` once at startup, before the map or the EV
27
+ layer is used:
28
+
29
+ ```ts
30
+ import { configureMonitorMap } from "@sjvair/monitor-map/core";
31
+
32
+ configureMonitorMap({ maptilerKey: "...", nrelKey: "..." });
17
33
  ```
18
34
 
19
35
  ## Usage
20
36
 
21
37
  ### Full-page map, via `sv-router`
22
38
 
23
- The default integration path mounts a complete map (all integrations: monitors,
24
- collocation sites, wind, HMS smoke/fire, EV stations) as a route in a host app that
39
+ The default integration path mounts a complete map (monitors, collocation sites,
40
+ wind, HMS smoke/fire, EV stations) as a route in a host app that
25
41
  uses `sv-router`:
26
42
 
27
43
  ```ts
@@ -108,135 +124,33 @@ note that it has no current readings; an unknown id gets "Monitor not found."
108
124
 
109
125
  ### Cancelling requests
110
126
 
111
- `monitorsManager.init()` and `update()`, `collocationSitesManager.init()` and `update()`,
112
- `hmsManager.init()`, `loadSmoke()` and `loadFire()`, and `evStationsManager.loadLvl2Stations()`
113
- and `loadLvl3Stations()` take `{ signal }` (an `AbortSignal`). Aborting rejects that call with
114
- the signal's reason (a call that is a no-op, such as `update()` before init or `init()` once
115
- initialized, resolves as before). The panel, chart and subscription status cancel their own superseded
116
- requests when the selection changes; that work resolves quietly. A `monitorsManager.init()`
117
- run is shared: aborting your signal stops only your wait, and the run itself is cancelled only
118
- when every caller waiting on it has aborted.
119
-
120
- A host that depends on `@sjvair/sdk` directly must use `^4.7.0`, so npm installs one copy. A
121
- nested copy ignores the host's `setOrigin`.
122
-
123
- ### Embedding `MapShell` directly, with a reduced integration set
124
-
125
- `MonitorMapLayout` is an opinionated wrapper around the lower-level `MapShell`
126
- component: it wires up every integration, every manager, and the full options toolbar and
127
- legend. A host that only wants some of that — say, just the monitors integration, with no
128
- EV stations/wind/HMS — should compose `MapShell` directly instead:
129
-
130
- ```svelte
131
- <script>
132
- import {
133
- MapShell,
134
- MonitorsMenu,
135
- OptionsGroup,
136
- PollutantMenu,
137
- monitorsMapIntegration,
138
- monitorsManager
139
- } from "@sjvair/monitor-map";
140
-
141
- let failed = $state(false);
142
- function load() {
143
- failed = false;
144
- monitorsManager.init().catch(() => (failed = true));
145
- }
146
- load();
147
- </script>
148
-
149
- <MapShell
150
- integrations={[monitorsMapIntegration]}
151
- ready={monitorsManager.initialized}
152
- panelOpen={false}
153
- routerEscapeHatch={false}
154
- >
155
- {#snippet menu()}
156
- <OptionsGroup>
157
- <PollutantMenu />
158
- <MonitorsMenu />
159
- </OptionsGroup>
160
- {/snippet}
161
- {#snippet loadError()}
162
- {#if failed}
163
- <button onclick={load}>Couldn't load air monitors. Try again</button>
164
- {/if}
165
- {/snippet}
166
- </MapShell>
167
- ```
168
-
169
- The `menu` snippet renders inside the options toolbar; compose `OptionsGroup` with the
170
- exported menus (`PollutantMenu`, `MonitorsMenu`, `LayersMenu`, `OverlaysMenu`,
171
- `SettingsMenu`), or `OptionsMenu` with the row components for a custom data source. The
172
- optional `loadError` snippet renders on the load screen, under the logo, which stays up
173
- until `ready` is true; use it to show a failed initial load with a retry.
174
-
175
- See `src/lib/MonitorMapLayout.svelte` for the reference example of wiring a manager, an
176
- integration list, and menu/overlay content into `MapShell`.
177
-
178
- **`routerEscapeHatch`**: `MapShell` defaults to `routerEscapeHatch={true}`, which
179
- intercepts clicks and forces full-page navigation for links outside the map's own
180
- routes — correct for a full-page map, wrong for a map embedded alongside a host app's
181
- own navigation. A host with its own routing (like `data-dashboard`) **must** pass
182
- `routerEscapeHatch={false}`, which also skips `useMonitorMapRouter()` entirely, so no
183
- `provideMonitorMapRouter(...)` ancestor is required. Pass `basePath` if you need the
184
- escape-hatch's "known route" prefix without going through `provideMonitorMapRouter`.
185
-
186
- Mount at most one `MapShell` per app instance — its underlying map/load-screen/
187
- integration-registration state is module-level singleton state shared across the whole
188
- page.
189
-
190
- ## Extending
191
-
192
- ### Adding a new map feature
193
-
194
- Map features are a plugin system built on a few abstract base classes, exported from the
195
- package root:
196
-
197
- - `MapIntegration` — base apply/remove lifecycle
198
- - `MapLayerIntegration` — adds MapTiler layer management
199
- - `MapGeoJSONIntegration` — adds GeoJSON data-source management, plus a
200
- `MapIconManager` for sprite icons (this is `src/lib/map/integrations/
201
- map-geojson-integration.svelte.ts`'s `MapIconLayerIntegration`, exported under this
202
- name)
203
-
204
- Extend one of these rather than manipulating the MapTiler map instance directly. Look
205
- at `src/lib/monitors/monitors-map-integration.svelte.ts` or `src/lib/wind/wind.svelte.ts`
206
- as reference implementations.
207
-
208
- ### Reusing the monitors map display with different data (`MonitorsDataSource`)
209
-
210
- `MonitorsMapIntegration` (and the icon-generation base class behind
211
- `MonitorsIconManager`/`CollocationIconManager`) don't hardcode the live `monitorsManager`
212
- singleton — they accept a `MonitorsDataSource` via their constructor:
213
-
214
- ```ts
215
- export interface MonitorsDataSource {
216
- readonly meta: MonitorsMeta | null;
217
- readonly pollutant: "pm25" | "o3" | null;
218
- readonly latest: XMap<string, MonitorLatestType<"pm25" | "o3">> | null;
219
- readonly levels: Array<SJVAirEntryLevel> | null;
220
- }
221
- ```
222
-
223
- `monitorsManager` (auto-polling, always-current readings) is the default when no data
224
- source is given, so existing consumers are unaffected. A host app that wants the same
225
- clustering/icon-rendering/filtering/tooltip logic driven by different data — for
226
- example, `data-dashboard`'s Monitors tab, which colors monitors by the **average of
227
- historical summary data over a selected date range** rather than a live reading —
228
- implements its own `MonitorsDataSource` (no polling, populated from
229
- `getMonitorSummariesDaily`/etc.) and constructs its own instance:
230
-
231
- ```ts
232
- import { MonitorsMapIntegration, type MonitorsDataSource } from "@sjvair/monitor-map";
233
-
234
- const myDataSource: MonitorsDataSource = /* ... */;
235
- const monitorsMapIntegration = new MonitorsMapIntegration(myDataSource);
236
- ```
237
-
238
- This reuses all of the existing map-rendering work instead of forking it — see
239
- `CLAUDE.md`'s "Monitor Data Flow" section for more detail.
127
+ `monitorsManager.init()` takes `{ signal }` (an `AbortSignal`). Aborting rejects that call with
128
+ the signal's reason. The run is shared: aborting your signal stops only your wait, and the run
129
+ itself is cancelled only when every caller waiting on it has aborted. The panel, chart and
130
+ subscription status cancel their own superseded requests; that work resolves quietly.
131
+
132
+ ## Migrating from 4.x
133
+
134
+ - **Keys:** pass the MapTiler and NREL keys with `configureMonitorMap({ maptilerKey, nrelKey })`
135
+ (from `@sjvair/monitor-map` or `/core`). The library no longer reads them from the build
136
+ environment.
137
+ - **`@sjvair/sdk` is a peer dependency** (`^5.0.0-beta.3` for the betas): install it in the host.
138
+ `@sjvair/map-sdk` and `@maptiler/sdk` are ordinary dependencies; add neither.
139
+ - **Svelte `^5.57.0`:** the `svelte` peer range was `^5.0.0`.
140
+ - **`meta` is SDK 5.0's:** `meta.levels` is gone; read `meta.scale`.
141
+ - **`/routes`** is unchanged: `monitorMapRoutes` with the map at `/` and a monitor at
142
+ `/monitor/:id`, lazy as before.
143
+ - **`/core`** keeps `provideMonitorMapRouter`, `useMonitorMapRouter`, `ROUTER_KEY`,
144
+ `MonitorMapRouterApi` and `monitorsManager` (`init(pollutant?, { autoUpdate?, signal? })`,
145
+ `initialized`, `meta`, `list`), and adds `configureMonitorMap` and `monitorMapConfig`.
146
+ - **Tailwind:** add `@source "../node_modules/@sjvair/map-sdk/dist";` and
147
+ `@import "@sjvair/map-sdk/theme.css";` beside the existing monitor-map `@source`. The host
148
+ defines the theme tokens map-sdk needs (`--background` to `--radius`, plus `--popover` and
149
+ `--accent`).
150
+ - **Removed exports:** everything from `.` except `monitorMapRoutes`, the router context,
151
+ `monitorsManager`, `configureMonitorMap` and `monitorMapConfig` (and their types). That includes
152
+ `MapShell`, the options menus, the integration classes, `MonitorsDataSource` and the other
153
+ managers.
240
154
 
241
155
  ## Development
242
156
 
@@ -251,11 +165,18 @@ npm run lint # Prettier check + ESLint
251
165
  npm run format # Auto-format with Prettier
252
166
  npm test # Vitest (specs in tests/**)
253
167
  npm run test:bundle # build:lib, then check the light entries keep maplibre off the eager path
168
+ npm run map-sdk:pack # Optional: pack ../map-sdk into vendor/ to try an unreleased map-sdk
254
169
  ```
255
170
 
171
+ `@sjvair/map-sdk` is the published npm version, pinned exactly in `package.json`. To try an
172
+ unreleased map-sdk, run `npm run map-sdk:pack`, then `npm install` the tarball path it prints;
173
+ do not commit that change.
174
+
256
175
  ## Publishing
257
176
 
258
177
  Publishing to npm (`@sjvair/monitor-map`) happens via GitHub Actions
259
178
  (`.github/workflows/release-package.yml`) whenever a GitHub Release is published (or the
260
179
  workflow is triggered manually). The workflow runs `npm test` and `npm run test:bundle`
261
- before publishing. Bump `version` in `package.json` before cutting the release.
180
+ before publishing. Bump `version` in `package.json` before cutting the release. A version with a
181
+ `-` (such as `5.0.0-beta.0`) is published to the `next` dist-tag, not `latest`; mark its GitHub
182
+ Release as a pre-release.
@@ -1,18 +1,17 @@
1
1
  <script lang="ts">
2
2
  import { untrack, type ComponentProps } from "svelte";
3
- import type { SJVAirEntryLevel } from "@sjvair/sdk";
4
3
  import DataBox from "./components/DataBox.svelte";
5
4
  import LoadError from "./LoadError.svelte";
6
5
  import MonitorWidgetModal from "./monitors/components/MonitorWidgetModal.svelte";
7
6
  import MonitorSubscriptionManager from "./monitors/components/MonitorSubscriptionManager.svelte";
8
7
  import DataChart from "./data-chart/DataChart.svelte";
9
- import { monitorsManager } from "./";
8
+ import { monitorsManager } from "./monitors/monitors.svelte.js";
10
9
  import { MonitorDetailsState } from "./monitors/monitor-details.svelte";
11
- import { choosePanelPollutant } from "./monitors/panel-pollutant";
10
+ import { choosePanelPollutant, PANEL_POLLUTANTS } from "./monitors/panel-pollutant";
12
11
  import { useMonitorMapRouter } from "./router-context";
13
12
  import { fetchTempByCoords } from "./weather";
14
13
  import { Colors, valueToColor } from "./colors";
15
- import { getCurrentLevel } from "./monitors/monitor-utils";
14
+ import { NEUTRAL_LEVEL_COLOR, readingDisplay, readingLevel } from "./levels";
16
15
 
17
16
  type TempDataBox = Pick<ComponentProps<typeof DataBox>, "color" | "value">;
18
17
 
@@ -28,6 +27,10 @@
28
27
  // current reading for the map's pollutant.
29
28
  const details = new MonitorDetailsState();
30
29
  const meta = $derived(monitorsManager.meta);
30
+ // The map's pollutant, when it is one the panel can show.
31
+ const mapPollutant = $derived(
32
+ PANEL_POLLUTANTS.find((p) => p === monitorsManager.pollutant) ?? null
33
+ );
31
34
  // Shown only once the metadata is in too; labels and levels come from it.
32
35
  const monitor = $derived(details.status === "ready" && meta ? details.monitor : null);
33
36
 
@@ -42,14 +45,15 @@
42
45
  // Bumped whenever the map's readings are replaced, i.e. its 2-minute refresh ran. The data
43
46
  // box follows it; the chart decides for itself whether its date range can have new entries.
44
47
  let refreshTick = $state(0);
45
- let seenLatest = untrack(() => monitorsManager.latest);
48
+ let seenLatest = untrack(() => monitorsManager.store.latest);
46
49
 
47
50
  $effect(() => {
48
- const latest = monitorsManager.latest;
49
- // Null while a pollutant change is loading; wait for the readings that follow.
50
- if (!latest || latest === seenLatest) return;
51
+ const latest = monitorsManager.store.latest;
52
+ // Empty before the first load and while a pollutant change is loading; wait for the
53
+ // readings that follow.
54
+ if (latest.size === 0 || latest === seenLatest) return;
51
55
  // The first readings of a cold load arrive alongside this panel's own request.
52
- const first = seenLatest === null;
56
+ const first = seenLatest.size === 0;
53
57
  seenLatest = latest;
54
58
  if (first) return;
55
59
  untrack(() => {
@@ -59,14 +63,13 @@
59
63
  });
60
64
 
61
65
  const panel = $derived(
62
- monitor && meta ? choosePanelPollutant(monitorsManager.pollutant, monitor, meta) : null
66
+ monitor && meta ? choosePanelPollutant(mapPollutant, monitor, meta) : null
63
67
  );
64
68
  const reading = $derived(
65
69
  monitor && panel?.pollutant && panel.hasReading ? monitor.latest[panel.pollutant] : undefined
66
70
  );
67
71
  // Set when the panel shows a different pollutant than the map is coloring by.
68
72
  const pollutantNote = $derived.by(() => {
69
- const mapPollutant = monitorsManager.pollutant;
70
73
  if (!meta || !panel?.pollutant || !panel.hasReading || !mapPollutant) return;
71
74
  if (panel.pollutant === mapPollutant) return;
72
75
  const shown = meta.entryType(panel.pollutant).label;
@@ -81,18 +84,15 @@
81
84
  if (!monitor || !meta || !panel?.pollutant || !reading) return;
82
85
 
83
86
  const entryType = meta.entryType(panel.pollutant);
84
- const level: SJVAirEntryLevel | undefined = getCurrentLevel(
85
- reading.value,
86
- entryType.asIter.levels!
87
- );
87
+ const level = readingLevel(reading.value, entryType.scale);
88
88
 
89
89
  const updateDuration = meta.monitorType(monitor.type).expected_interval;
90
90
 
91
91
  return {
92
- color: level?.color ?? "",
92
+ color: level?.color ?? NEUTRAL_LEVEL_COLOR,
93
93
  header: entryType.label,
94
94
  subheading: `(${updateDuration} avg)`,
95
- value: Math.round(parseInt(reading.value, 10)).toString()
95
+ value: readingDisplay(reading.value)
96
96
  };
97
97
  });
98
98
 
@@ -201,9 +201,12 @@
201
201
  </div>
202
202
  {/if}
203
203
 
204
- <div class="tall:block hidden">
205
- <MonitorWidgetModal monitorId={monitor.id} />
206
- </div>
204
+ <!-- The widget shows current readings, and errors for an inactive monitor. -->
205
+ {#if panel.hasReading}
206
+ <div class="tall:block hidden">
207
+ <MonitorWidgetModal monitorId={monitor.id} />
208
+ </div>
209
+ {/if}
207
210
  <!-- eslint-disable-next-line @typescript-eslint/no-explicit-any -->
208
211
  {#if (globalThis as any).USER?.is_authenticated}
209
212
  <MonitorSubscriptionManager monitorId={monitor.id} />