@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 CHANGED
@@ -1,3 +1,154 @@
1
- # Temporary Holding Version
1
+ <div align="center">
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
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.