@uiness/map 0.0.0-stage → 0.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 +153 -2
- package/dist/index.cjs +744 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +230 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +230 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +724 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +69 -3
package/README.md
CHANGED
|
@@ -1,3 +1,154 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<img src="https://raw.githubusercontent.com/Matias-Obezzi/uiness/main/assets/logo.png" alt="" width="72" height="72" />
|
|
4
|
+
|
|
5
|
+
</div>
|
|
6
|
+
|
|
7
|
+
# @uiness/map
|
|
8
|
+
|
|
9
|
+
Maps for React with zero runtime dependencies. OpenStreetMap by default, any XYZ tile service by passing an object, and the same `<Map>`, `<Marker>` and `<Popup>` on Google Maps or Apple Maps.
|
|
10
|
+
|
|
11
|
+
[Documentation](https://uiness.vercel.app/docs/map) · [Registry](https://uiness.vercel.app/docs/installation) · [GitHub](https://github.com/Matias-Obezzi/uiness)
|
|
12
|
+
|
|
13
|
+
- Drag or touch to pan, pinch to zoom, the wheel zooms with Ctrl or ⌘ held and scrolls the page otherwise, double click to zoom in (Shift to zoom out).
|
|
14
|
+
- Keyboard when focused: arrows pan, `+` and `-` zoom.
|
|
15
|
+
- Controlled or uncontrolled `center` and `zoom`.
|
|
16
|
+
- The tile service's attribution is shown in the corner, as OpenStreetMap requires.
|
|
17
|
+
- `useMap()` gives `project` and `unproject`, to lay anything over the map.
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pnpm add @uiness/map
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
```tsx
|
|
26
|
+
import { Map, Marker, Popup, ZoomControl } from '@uiness/map'
|
|
27
|
+
|
|
28
|
+
function Office() {
|
|
29
|
+
const [open, setOpen] = useState(false)
|
|
30
|
+
return (
|
|
31
|
+
<Map defaultCenter={[-58.3816, -34.6037]} defaultZoom={13} style={{ height: 400 }}>
|
|
32
|
+
<Marker lngLat={[-58.3816, -34.6037]} label="Office" onClick={() => setOpen((o) => !o)} />
|
|
33
|
+
{open && (
|
|
34
|
+
<Popup lngLat={[-58.3816, -34.6037]} onClose={() => setOpen(false)}>
|
|
35
|
+
We are here
|
|
36
|
+
</Popup>
|
|
37
|
+
)}
|
|
38
|
+
<ZoomControl />
|
|
39
|
+
</Map>
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Coordinates are `[lng, lat]`, the GeoJSON order. The map fills its box and has no height of its own, so give it one.
|
|
45
|
+
|
|
46
|
+
### `<Map>` props
|
|
47
|
+
|
|
48
|
+
| Prop | Default | Description |
|
|
49
|
+
| --- | --- | --- |
|
|
50
|
+
| `center`, `zoom` | | Controlled view. Fractional zoom levels are fine. |
|
|
51
|
+
| `defaultCenter`, `defaultZoom` | `[0, 20]`, `2` | Starting view when uncontrolled. |
|
|
52
|
+
| `onViewChange` | | `({ center, zoom }) => void` on every move. |
|
|
53
|
+
| `minZoom`, `maxZoom` | `0`, the provider's | Zoom range. |
|
|
54
|
+
| `wheelZoom` | `'modifier'` | When the wheel zooms: `'modifier'` (Ctrl, ⌘ or a trackpad pinch), `'always'` or `'never'`. Tiles only. |
|
|
55
|
+
| `provider` | `providers.osm` | Where the tiles come from. |
|
|
56
|
+
| `engine` | | Draw with another platform instead, see below. |
|
|
57
|
+
|
|
58
|
+
Every other prop goes to the `<section>` that holds the map. Its accessible name is `"Map"` unless you pass `aria-label`.
|
|
59
|
+
|
|
60
|
+
`<Marker lngLat>` takes any children as the pin, its bottom center on the coordinate. With `onClick` it is a button, so give it a `label`. `<Popup lngLat>` is rendered while it should be open; `onClose` adds a close button and closes on Escape; `closeIcon` replaces its default `×`. `<Popup>` and `<ZoomControl>` drop their default look when you pass a `className`.
|
|
61
|
+
|
|
62
|
+
### Tile providers
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
import { providers } from '@uiness/map'
|
|
66
|
+
|
|
67
|
+
<Map provider={providers.cartoDark} />
|
|
68
|
+
|
|
69
|
+
<Map
|
|
70
|
+
provider={{
|
|
71
|
+
url: 'https://tiles.example.com/{z}/{x}/{y}.png',
|
|
72
|
+
attribution: '© Example',
|
|
73
|
+
maxZoom: 18,
|
|
74
|
+
subdomains: ['a', 'b'], // for {s} in the url
|
|
75
|
+
}}
|
|
76
|
+
/>
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Presets: `osm`, `cartoLight`, `cartoDark`, `openTopoMap`. CARTO needs a key: `{ ...providers.cartoDark, url: providers.cartoDark.url + '?key=YOUR_KEY' }`. The public OpenStreetMap tile servers are for light use only, read their [tile usage policy](https://operations.osmfoundation.org/policies/tiles/) before you ship.
|
|
80
|
+
|
|
81
|
+
### Your own overlays
|
|
82
|
+
|
|
83
|
+
```tsx
|
|
84
|
+
import { useMap } from '@uiness/map'
|
|
85
|
+
|
|
86
|
+
function Label({ lngLat, children }) {
|
|
87
|
+
const map = useMap()
|
|
88
|
+
const [x, y] = map.project(lngLat)
|
|
89
|
+
return <div style={{ position: 'absolute', left: x, top: y }}>{children}</div>
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
`useMap()` also returns `center`, `zoom`, `size` and `setView({ center?, zoom? })`.
|
|
94
|
+
|
|
95
|
+
### Google Maps and Apple Maps
|
|
96
|
+
|
|
97
|
+
```tsx
|
|
98
|
+
import { appleMaps, googleMaps, Map, Marker } from '@uiness/map'
|
|
99
|
+
|
|
100
|
+
// Once, outside the component: a new engine mounts a new map.
|
|
101
|
+
const google = googleMaps({ apiKey: 'YOUR_KEY' })
|
|
102
|
+
const apple = appleMaps({ token: 'YOUR_MAPKIT_TOKEN' })
|
|
103
|
+
|
|
104
|
+
<Map engine={google} defaultCenter={[2.35, 48.85]} defaultZoom={12}>
|
|
105
|
+
<Marker lngLat={[2.35, 48.85]} />
|
|
106
|
+
</Map>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Each engine loads the platform's official script the first time a map mounts, from your key or token, and tears its map down on unmount. `googleMaps()` sets `gestureHandling: 'cooperative'`, the same Ctrl or ⌘ rule as `wheelZoom`, pass `options: { gestureHandling: 'greedy' }` to always zoom. MapKit JS has no equivalent, and `wheelZoom` is not read when an `engine` is set. The platform does the panning and zooming; markers, popups and controls are the same React elements, placed with the platform's projection.
|
|
110
|
+
|
|
111
|
+
### Writing an engine
|
|
112
|
+
|
|
113
|
+
An engine is a function that draws into an element and returns four methods:
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
import type { MapEngine } from '@uiness/map'
|
|
117
|
+
|
|
118
|
+
const myEngine: MapEngine = async (container, view, onMove) => {
|
|
119
|
+
const map = new SomeSdk.Map(container, { center: view.center, zoom: view.zoom })
|
|
120
|
+
map.on('move', () => onMove({ center: map.getCenter(), zoom: map.getZoom() }))
|
|
121
|
+
return {
|
|
122
|
+
setView: ({ center, zoom }) => map.jumpTo({ center, zoom }),
|
|
123
|
+
project: (lngLat) => map.project(lngLat), // [x, y] from the container's top left
|
|
124
|
+
unproject: (point) => map.unproject(point), // [lng, lat]
|
|
125
|
+
destroy: () => map.remove(),
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Call `onMove` on every move while it happens, so markers follow. `loadScript(src, callbackName, attributes?)` is exported to load an SDK once.
|
|
131
|
+
|
|
132
|
+
## License
|
|
133
|
+
|
|
134
|
+
MIT
|
|
135
|
+
|
|
136
|
+
## With the uiness registry
|
|
137
|
+
|
|
138
|
+
Prefer components that already follow your theme? uiness is also a registry for the shadcn CLI. Register it once in `components.json`:
|
|
139
|
+
|
|
140
|
+
```json
|
|
141
|
+
{
|
|
142
|
+
"registries": {
|
|
143
|
+
"@uiness": "https://uiness.vercel.app/r/{name}.json"
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Then add the item:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
npx shadcn@latest add @uiness/map
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
The `map` item installs this package and a thin wrapper in `components/ui` that connects it to your theme tokens.
|