@trackunit/react-map 0.1.30 → 0.1.31
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 +49 -51
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -1,30 +1,59 @@
|
|
|
1
1
|
# @trackunit/react-map
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Provider-agnostic, hook-first map library for React applications. Switch between Google Maps and Mapbox without touching your application code.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
[x]Both Google Maps and Mapbox adapters are implemented.
|
|
5
|
+
## Design principles
|
|
7
6
|
|
|
8
|
-
|
|
7
|
+
- **Provider behind an adapter.** Google Maps or Mapbox is passed in as adapter config. Swapping providers is a one-line change; your components, events, and tests are untouched.
|
|
8
|
+
- **Hook-first, TanStack-style.** State, actions, and the renderable component are co-located at the call site via `useMap(adapter)`. No context tree to set up; no provider-specific types leaking into your code.
|
|
9
|
+
- **Resolver props — you decide.** Where choices are genuinely the consumer's — which markers render as DOM vs symbol, what style a hovered shape gets — the library hands you a fully-described context object and takes a small decision back. It never makes the heuristic call behind your back.
|
|
10
|
+
- **Defaults, but always composable.** Every resolver ships a sensible default that is exported for composition. Use it as-is, wrap it, or replace it entirely.
|
|
11
|
+
- **Atomic components.** `MapMarker`, `ClusterMarker`, `MapMarkerIcon`, and `Panel` are usable stand-alone, even outside a map.
|
|
12
|
+
- **Strong types.** Discriminated unions, exhaustive switches, and typed resolver contracts catch mistakes at compile time.
|
|
13
|
+
- **No vendor leakage.** All provider-specific types and APIs belong inside adapters. Nothing outside an adapter may import from `mapbox-gl` or `@vis.gl/react-google-maps`.
|
|
14
|
+
- **Self-contained, portable layers.** A well-designed layer hook owns its own data loading, controls, and settings so it can be dropped into any map without surrounding setup. Concretely, layers should accept a pre-built `filters` object as a prop rather than fetching raw data — the hook owns the query internally and the caller owns the filter shape.
|
|
9
15
|
|
|
10
|
-
|
|
16
|
+
## Three layers of abstraction
|
|
11
17
|
|
|
12
|
-
|
|
18
|
+
The library is intentionally split into three tiers. **Reach for the highest-level tier that satisfies your needs, and only drop down a layer when you need more control.** Starting at a lower tier than necessary means reinventing abstractions the higher tiers already provide.
|
|
13
19
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
20
|
+
### Tier 1 — `useMap` and `MapApi`
|
|
21
|
+
|
|
22
|
+
The foundation. Full control over camera, events, controls, panels, annotations, and the adapter surface. Maximum flexibility; you invent everything yourself.
|
|
23
|
+
|
|
24
|
+
Use this when you are building something structurally novel or need to escape a constraint in a higher-level hook.
|
|
25
|
+
|
|
26
|
+
### Tier 2 — Layer hooks (`useMarkers`, `useShapes`, …)
|
|
27
|
+
|
|
28
|
+
The everyday workhorse. Layer hooks give a high-productivity path to common map features without giving anything away. They surface full library behaviour with sensible defaults you can override one decision at a time via resolver props.
|
|
29
|
+
|
|
30
|
+
The atomic building blocks these compose are exported for reuse too: the output components (`MapMarker`, `ClusterMarker`, `MapMarkerIcon`) and helper hooks (`useAdaptiveMarkerHelpers`, `useShapeLabelHelpers`, …) that surface the default resolver heuristics. This is where almost all map feature work should live.
|
|
31
|
+
|
|
32
|
+
### Tier 3 — Your domain layer hooks
|
|
33
|
+
|
|
34
|
+
The top tier is your own domain hooks — built on top of Tier 2 primitives. Highly opinionated hooks that own data fetching, display logic, controls, and interaction end-to-end. Closed by design — no customization knobs. If you need something similar but with different behaviour, drop to Tier 2 and compose from the atomic pieces.
|
|
35
|
+
|
|
36
|
+
Every finished, map-ready layer is a Tier 3 hook, so the tier you pick is really your starting point: use a ready-made domain hook as-is, or assemble your own from Tier 2 primitives.
|
|
37
|
+
|
|
38
|
+
**This library exports generic primitives only.** Domain hooks belong in the domain library that serves them — not in `@trackunit/react-map`. Trackunit's own asset and site layer hooks are reference implementations that will be published separately. If you build a domain layer that would be valuable beyond your own app, consider publishing it as its own package too.
|
|
19
39
|
|
|
20
40
|
## Installation
|
|
21
41
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
42
|
+
```bash
|
|
43
|
+
npm install @trackunit/react-map
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Map providers live in separate adapter packages — install whichever one(s) you use alongside it:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# Google Maps
|
|
50
|
+
npm install @trackunit/react-map-adapter-google
|
|
51
|
+
|
|
52
|
+
# Mapbox
|
|
53
|
+
npm install @trackunit/react-map-adapter-mapbox
|
|
54
|
+
```
|
|
26
55
|
|
|
27
|
-
|
|
56
|
+
Always import providers from the adapter package, never from `@trackunit/react-map`:
|
|
28
57
|
- Google Maps: `@trackunit/react-map-adapter-google` (`googleMapsAdapter`, `GoogleApiProvider`, …)
|
|
29
58
|
- Mapbox: `@trackunit/react-map-adapter-mapbox` (`mapboxAdapter`, …)
|
|
30
59
|
|
|
@@ -229,42 +258,11 @@ Maps include built-in accessibility features:
|
|
|
229
258
|
|
|
230
259
|
## Architecture
|
|
231
260
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
Implementation detail in this repo is split between **[CONTEXT.md](CONTEXT.md)** (domain language and how concepts relate) and **[docs/adr/](docs/adr/)** (short architecture decision records).
|
|
235
|
-
|
|
236
|
-
| Document | What it covers |
|
|
237
|
-
|----------|---------------|
|
|
238
|
-
| [CONTEXT.md](CONTEXT.md) | Glossary: Adapter, Layer Hook, Layer Handle, Layer Port, Entity, Control Config, Annotation, Decoration, and relationships between them |
|
|
239
|
-
| [ADR 0001 — Hook-first map API](docs/adr/0001-hook-first-api.md) | `useMap(adapter)` tuple as the primary API; tuple vs object vs component-first |
|
|
240
|
-
| [ADR 0002 — Adapter factory pattern](docs/adr/0002-adapter-factory-pattern.md) | Adapter factories, `defineAdapter`, `derive`, keeping provider knowledge at the call site |
|
|
241
|
-
| [ADR 0003 — Controls as data](docs/adr/0003-controls-as-data.md) | Control configs as data, discriminated union, middleware pipeline, presentational renderers |
|
|
242
|
-
| [ADR 0004 — Declarative LayerPort snapshot](docs/adr/0004-layer-port-declarative-snapshot.md) | `LayerPort.setSnapshot`, single write path, adapter-owned diffing |
|
|
243
|
-
| [ADR 0005 — Annotation store on MapApi](docs/adr/0005-annotation-store-on-map-api.md) | `MapApi.annotations`, explicit `api` at call sites, renderer claims |
|
|
244
|
-
| [ADR 0006 — Adapters own DOM marker positioning](docs/adr/0006-marker-anchor-ownership.md) | Marker anchors owned by the adapter; no competing transforms in DOM content |
|
|
245
|
-
| [ADR 0007 — Antimeridian shapes merged in adapters](docs/adr/0007-antimeridian-merge-in-adapters.md) | Merging split GeoJSON at render time inside adapters, not in app state |
|
|
246
|
-
| [ADR 0008 — Map panel store on MapApi](docs/adr/0008-map-panel-store-on-map-api.md) | `MapApi.panels`, `usePanel`, `PanelOrchestrator`, menu presentation via panels |
|
|
247
|
-
| [ADR 0009 — Declarative MarkerState](docs/adr/0009-declarative-marker-state.md) | State-driven union prop over imperative marker API |
|
|
248
|
-
| [ADR 0010 — Unified marker render tree](docs/adr/0010-unified-marker-render-tree.md) | Always-mounted slots animated via CSS; no separate circle/pill components |
|
|
249
|
-
| [ADR 0011 — Stick mode anchor-zero + transform animation](docs/adr/0011-stick-anchor-zero-transform-animation.md) | Zero-size anchor container; CSS three-function transform; no JS width measurement |
|
|
250
|
-
| [ADR 0012 — Fixed size ladder with locked pill tier](docs/adr/0012-marker-size-ladder-fixed-pill-tier.md) | Five-tier `MarkerDomSize` enum; pill layout fixed to `md` tier |
|
|
251
|
-
| [ADR 0013 — GpsArrowNorth icon](docs/adr/0013-gps-arrow-north-icon.md) | North-facing SVG variant eliminates `heading - 45` magic offset at call sites |
|
|
252
|
-
| [ADR 0020 — Map state is split by update frequency](docs/adr/0020-map-state-channels.md) | `MapStatus` on `api.state`, `CameraState` via `useCameraState(api)`, and separate adapter notification channels |
|
|
253
|
-
| [@trackunit/react-map-adapter-google README](../map-adapter-google/README.md) | Google Maps adapter: exports, `GoogleApiProvider`, multiple maps |
|
|
254
|
-
| [@trackunit/react-map-adapter-mapbox README](../map-adapter-mapbox/README.md) | Mapbox adapter: exports, configuration, typical usage |
|
|
255
|
-
|
|
256
|
-
## Testing
|
|
257
|
-
|
|
258
|
-
```bash
|
|
259
|
-
# Run all tests
|
|
260
|
-
yarn nx test react-map
|
|
261
|
+
`@trackunit/react-map` is built in independently-useful layers: provider **adapters**, the **`useMap`** foundation and `MapApi`, **layer hooks** (`useMarkers`, `useShapes`, …), and **atomic components** (`MapMarker`, `ClusterMarker`, …). Each tier is usable and testable on its own — see the design principles and three-tier model above.
|
|
261
262
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
# Run linting
|
|
266
|
-
yarn nx lint react-map
|
|
267
|
-
```
|
|
263
|
+
Provider integrations ship as separate packages:
|
|
264
|
+
- `@trackunit/react-map-adapter-google` — Google Maps
|
|
265
|
+
- `@trackunit/react-map-adapter-mapbox` — Mapbox
|
|
268
266
|
|
|
269
267
|
## Adding New Providers
|
|
270
268
|
|
package/package.json
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trackunit/react-map",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.31",
|
|
4
4
|
"repository": "https://github.com/Trackunit/manager",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
6
6
|
"engines": {
|
|
7
7
|
"node": ">=24.x"
|
|
8
8
|
},
|
|
9
9
|
"dependencies": {
|
|
10
|
-
"@trackunit/react-components": "2.1.
|
|
10
|
+
"@trackunit/react-components": "2.1.40",
|
|
11
11
|
"@trackunit/css-class-variance-utilities": "1.13.43",
|
|
12
|
-
"@trackunit/react-form-components": "2.1.
|
|
13
|
-
"@trackunit/react-core-hooks": "1.17.
|
|
12
|
+
"@trackunit/react-form-components": "2.1.42",
|
|
13
|
+
"@trackunit/react-core-hooks": "1.17.53",
|
|
14
14
|
"@trackunit/geo-json-utils": "1.14.46",
|
|
15
|
-
"@trackunit/i18n-library-translation": "2.0.
|
|
16
|
-
"@trackunit/react-modal": "2.1.
|
|
15
|
+
"@trackunit/i18n-library-translation": "2.0.41",
|
|
16
|
+
"@trackunit/react-modal": "2.1.44",
|
|
17
17
|
"react-minimal-pie-chart": "^8.4.0",
|
|
18
18
|
"@trackunit/react-map-adapter-shared": "0.0.27",
|
|
19
19
|
"@trackunit/react-map-color-utils": "0.0.12",
|