@geekles007/motion-map-components 0.2.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Tondji
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 ADDED
@@ -0,0 +1,234 @@
1
+ # React Map Components
2
+
3
+ [![npm version](https://badge.fury.io/js/@geekles%2Freact-map-components.svg)](https://www.npmjs.com/package/@geekles/react-map-components)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.4-blue.svg)](https://www.typescriptlang.org/)
6
+
7
+ Modern, lightweight React components for interactive maps built on top of Leaflet.
8
+
9
+ ## ✨ Features
10
+
11
+ - πŸ—ΊοΈ **Easy to use** - Simple, declarative API for creating maps
12
+ - πŸ“¦ **Lightweight** - Tree-shakeable, only import what you need
13
+ - 🎨 **Customizable** - Full control over styling and behavior
14
+ - πŸ“± **Responsive** - Works great on desktop and mobile
15
+ - πŸ”§ **TypeScript** - Full type support out of the box
16
+ - βš›οΈ **React 18/19** - Built for modern React with hooks
17
+
18
+ ## πŸ“¦ Installation
19
+
20
+ ```bash
21
+ # npm
22
+ npm install @geekles/react-map-components
23
+
24
+ # yarn
25
+ yarn add @geekles/react-map-components
26
+
27
+ # pnpm
28
+ pnpm add @geekles/react-map-components
29
+ ```
30
+
31
+ ## πŸš€ Quick Start
32
+
33
+ ```tsx
34
+ import { MapContainer, TileLayer, Marker, Popup } from '@geekles/react-map-components'
35
+ import '@geekles/react-map-components/styles.css'
36
+
37
+ function App() {
38
+ return (
39
+ <MapContainer
40
+ center={[51.505, -0.09]}
41
+ zoom={13}
42
+ style={{ height: '400px', width: '100%' }}
43
+ >
44
+ <TileLayer
45
+ url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
46
+ attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>'
47
+ />
48
+ <Marker position={[51.505, -0.09]}>
49
+ <Popup>
50
+ Hello! I'm a popup.
51
+ </Popup>
52
+ </Marker>
53
+ </MapContainer>
54
+ )
55
+ }
56
+ ```
57
+
58
+ ## πŸ“š Components
59
+
60
+ ### MapContainer
61
+
62
+ The main container component for your map.
63
+
64
+ ```tsx
65
+ <MapContainer
66
+ center={[lat, lng]}
67
+ zoom={13}
68
+ minZoom={1}
69
+ maxZoom={18}
70
+ scrollWheelZoom={true}
71
+ style={{ height: '100vh' }}
72
+ >
73
+ {/* children */}
74
+ </MapContainer>
75
+ ```
76
+
77
+ ### TileLayer
78
+
79
+ Add tile layers to your map.
80
+
81
+ ```tsx
82
+ <TileLayer
83
+ url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
84
+ attribution="Β© OpenStreetMap"
85
+ maxZoom={19}
86
+ />
87
+ ```
88
+
89
+ ### Marker
90
+
91
+ Add markers to your map.
92
+
93
+ ```tsx
94
+ <Marker
95
+ position={[51.505, -0.09]}
96
+ draggable={false}
97
+ eventHandlers={{
98
+ click: () => console.log('Marker clicked!')
99
+ }}
100
+ />
101
+ ```
102
+
103
+ ### Popup
104
+
105
+ Add popups to markers or the map.
106
+
107
+ ```tsx
108
+ <Marker position={[51.505, -0.09]}>
109
+ <Popup>
110
+ <h3>My Location</h3>
111
+ <p>This is where I am!</p>
112
+ </Popup>
113
+ </Marker>
114
+ ```
115
+
116
+ ### GeoJSON
117
+
118
+ Render GeoJSON data on your map.
119
+
120
+ ```tsx
121
+ <GeoJSON
122
+ data={geojsonData}
123
+ style={{ color: 'blue', weight: 2 }}
124
+ onEachFeature={(feature, layer) => {
125
+ layer.bindPopup(feature.properties.name)
126
+ }}
127
+ />
128
+ ```
129
+
130
+ ## πŸͺ Hooks
131
+
132
+ ### useMap
133
+
134
+ Access the map instance from any child component.
135
+
136
+ ```tsx
137
+ import { useMap } from '@geekles/react-map-components'
138
+
139
+ function MyComponent() {
140
+ const map = useMap()
141
+
142
+ const flyToLocation = () => {
143
+ map.flyTo([51.505, -0.09], 14)
144
+ }
145
+
146
+ return <button onClick={flyToLocation}>Go to London</button>
147
+ }
148
+ ```
149
+
150
+ ### useMapEvents
151
+
152
+ Subscribe to map events.
153
+
154
+ ```tsx
155
+ import { useMapEvents } from '@geekles/react-map-components'
156
+
157
+ function LocationLogger() {
158
+ useMapEvents({
159
+ click: (e) => {
160
+ console.log('Clicked at:', e.latlng)
161
+ },
162
+ zoomend: () => {
163
+ console.log('Zoom changed')
164
+ }
165
+ })
166
+
167
+ return null
168
+ }
169
+ ```
170
+
171
+ ## 🎨 Styling
172
+
173
+ Import the default styles:
174
+
175
+ ```tsx
176
+ import '@geekles/react-map-components/styles.css'
177
+ ```
178
+
179
+ Or customize with your own CSS:
180
+
181
+ ```css
182
+ .leaflet-container {
183
+ height: 100%;
184
+ width: 100%;
185
+ border-radius: 8px;
186
+ }
187
+
188
+ .leaflet-popup-content-wrapper {
189
+ border-radius: 12px;
190
+ }
191
+ ```
192
+
193
+ ## πŸ”§ TypeScript
194
+
195
+ All components are fully typed. Import types as needed:
196
+
197
+ ```tsx
198
+ import type {
199
+ MapContainerProps,
200
+ MarkerProps,
201
+ LatLngExpression
202
+ } from '@geekles/react-map-components'
203
+ ```
204
+
205
+ ## 🀝 Contributing
206
+
207
+ Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) for details.
208
+
209
+ ```bash
210
+ # Clone the repo
211
+ git clone https://github.com/geekles/react-map-components.git
212
+ cd react-map-components
213
+
214
+ # Install dependencies
215
+ pnpm install
216
+
217
+ # Start Storybook for development
218
+ pnpm dev
219
+
220
+ # Run tests
221
+ pnpm test
222
+
223
+ # Build the library
224
+ pnpm build
225
+ ```
226
+
227
+ ## πŸ“ License
228
+
229
+ MIT Β© [geekles](https://github.com/geekles)
230
+
231
+ ## πŸ™ Acknowledgments
232
+
233
+ - Built on top of [Leaflet](https://leafletjs.com/)
234
+ - Inspired by [react-leaflet](https://react-leaflet.js.org/)
package/dist/index.cjs ADDED
@@ -0,0 +1,3 @@
1
+ 'use strict';var react=require('react'),x=require('leaflet'),jsxRuntime=require('react/jsx-runtime'),reactDom=require('react-dom');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var x__default=/*#__PURE__*/_interopDefault(x);var g=react.createContext(null);function E({children:e}){let[t,o]=react.useState(null);return jsxRuntime.jsx(g.Provider,{value:{map:t,setMap:o},children:e})}function L(){let e=react.useContext(g);if(!e)throw new Error("useMapContext must be used within a MapProvider or MapContainer");return e}x__default.default.Icon&&x__default.default.Icon.Default&&x__default.default.Icon.Default.prototype&&delete x__default.default.Icon.Default.prototype._getIconUrl;x__default.default.Icon.Default.mergeOptions({iconRetinaUrl:"https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-icon-2x.png",iconUrl:"https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-icon.png",shadowUrl:"https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-shadow.png"});function F({center:e,zoom:t,minZoom:o,maxZoom:u,scrollWheelZoom:n=true,dragging:i=true,doubleClickZoom:s=true,zoomControl:f=true,style:r,className:a,children:p,whenReady:l,options:c,setMapReady:y}){let d=react.useRef(null),{setMap:M}=L(),P=react.useRef(null);return react.useEffect(()=>{if(!d.current||P.current)return;let C=x__default.default.map(d.current,{center:e,zoom:t,minZoom:o,maxZoom:u,scrollWheelZoom:n,dragging:i,doubleClickZoom:s,zoomControl:f,...c});return P.current=C,M(C),y(true),l&&l(C),()=>{C.remove(),P.current=null,M(null),y(false);}},[]),react.useEffect(()=>{P.current&&P.current.setView(e,t);},[e,t]),jsxRuntime.jsx("div",{ref:d,style:{height:"100%",width:"100%",...r},className:a,children:p})}function T(e){let[t,o]=react.useState(false);return jsxRuntime.jsx(E,{children:jsxRuntime.jsx(F,{...e,setMapReady:o,children:t?e.children:null})})}function m(){let{map:e}=L();if(!e)throw new Error("Map instance is not available. Make sure this hook is used within a MapContainer and the map has been initialized.");return e}function J({url:e,attribution:t,maxZoom:o,minZoom:u,opacity:n,zIndex:i,options:s}){let f=m(),r=react.useRef(null);return react.useEffect(()=>{if(!f)return;let a=x__default.default.tileLayer(e,{attribution:t,maxZoom:o,minZoom:u,opacity:n,zIndex:i,...s});return a.addTo(f),r.current=a,()=>{a.remove(),r.current=null;}},[f,e,t,o,u,n,i,s]),null}var N=react.createContext({marker:null});function v(){let{marker:e}=react.useContext(N);return e}function b({position:e,draggable:t=false,opacity:o,alt:u,eventHandlers:n,children:i,options:s}){let f=m(),[r,a]=react.useState(null);return react.useEffect(()=>{if(!f)return;let p=x__default.default.marker(e,{draggable:t,opacity:o,alt:u,...s});return p.addTo(f),a(p),()=>{p.remove(),a(null);}},[f]),react.useEffect(()=>{r&&r.setLatLng(e);},[e,r]),react.useEffect(()=>{r&&(t?r.dragging?.enable():r.dragging?.disable());},[t,r]),react.useEffect(()=>{r&&o!==void 0&&r.setOpacity(o);},[o,r]),react.useEffect(()=>{if(!r||!n)return;let p=Object.keys(n);return p.forEach(l=>{let c=n[l];c&&r.on(l,c);}),()=>{p.forEach(l=>{let c=n[l];c&&r.off(l,c);});}},[n,r]),jsxRuntime.jsx(N.Provider,{value:{marker:r},children:i})}function w({position:e,children:t,maxWidth:o=300,minWidth:u=50,autoClose:n=true,closeOnClick:i=true,className:s,options:f}){let r=m(),a=v(),p=react.useRef(null),[l,c]=react.useState(null);return react.useEffect(()=>{if(!r)return;let y=document.createElement("div");c(y);let d={maxWidth:o,minWidth:u,autoClose:n,closeOnClick:i,className:s,...f},M=!a&&e?x__default.default.popup(d).setLatLng(e):x__default.default.popup(d);return M.setContent(y),p.current=M,a&&a.bindPopup(M),()=>{a&&a.unbindPopup(),M.remove(),p.current=null,c(null);}},[r,a]),react.useEffect(()=>{p.current&&l&&r&&(a||e)&&p.current.openOn(r);},[l,r,a,e]),react.useEffect(()=>{p.current&&e&&!a&&r&&(p.current.setLatLng(e),p.current.isOpen()||p.current.openOn(r));},[e,a,r]),l?reactDom.createPortal(t,l):null}function D({data:e,style:t,onEachFeature:o,pointToLayer:u,filter:n,options:i}){let s=m(),f=react.useRef(null);return react.useEffect(()=>{if(!s||!e)return;let r=x__default.default.geoJSON(e,{style:t,onEachFeature:o,pointToLayer:u,filter:n,...i});return r.addTo(s),f.current=r,()=>{r.remove(),f.current=null;}},[s,e,t,o,u,n,i]),react.useEffect(()=>{f.current&&e&&(f.current.clearLayers(),f.current.addData(e));},[e]),null}function oe(e){let t=m();react.useEffect(()=>{if(!t||!e)return;let o=Object.keys(e);return o.forEach(u=>{let n=e[u];n&&t.on(u,n);}),()=>{o.forEach(u=>{let n=e[u];n&&t.off(u,n);});}},[t,e]);}
2
+ exports.GeoJSON=D;exports.MapContainer=T;exports.MapProvider=E;exports.Marker=b;exports.Popup=w;exports.TileLayer=J;exports.useMap=m;exports.useMapContext=L;exports.useMapEvents=oe;exports.useMarker=v;//# sourceMappingURL=index.cjs.map
3
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/context/MapContext.tsx","../src/components/MapContainer/MapContainer.tsx","../src/hooks/useMap.ts","../src/components/TileLayer/TileLayer.tsx","../src/components/Marker/Marker.tsx","../src/components/Popup/Popup.tsx","../src/components/GeoJSON/GeoJSON.tsx","../src/hooks/useMapEvents.ts"],"names":["MapContext","createContext","MapProvider","children","map","setMap","useState","jsx","useMapContext","context","useContext","L","MapContainerInner","center","zoom","minZoom","maxZoom","scrollWheelZoom","dragging","doubleClickZoom","zoomControl","style","className","whenReady","options","setMapReady","containerRef","useRef","mapRef","useEffect","MapContainer","props","mapReady","useMap","TileLayer","url","attribution","opacity","zIndex","tileLayerRef","tileLayer","MarkerContext","useMarker","marker","Marker","position","draggable","alt","eventHandlers","setMarker","markerInstance","eventNames","eventName","handler","Popup","maxWidth","minWidth","autoClose","closeOnClick","popupRef","container","setContainer","containerElement","popupOptions","popup","createPortal","GeoJSON","data","onEachFeature","pointToLayer","filter","geoJsonRef","geoJson","useMapEvents","handlers"],"mappings":"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","file":"index.cjs","sourcesContent":["import { createContext, useContext, useState, type ReactNode } from 'react'\nimport type { Map } from 'leaflet'\nimport type { MapContextValue } from '../types'\n\nconst MapContext = createContext<MapContextValue | null>(null)\n\nexport interface MapProviderProps {\n children: ReactNode\n}\n\n/**\n * Provider component for sharing map instance across components\n */\nexport function MapProvider({ children }: MapProviderProps) {\n const [map, setMap] = useState<Map | null>(null)\n\n return (\n <MapContext.Provider value={{ map, setMap }}>\n {children}\n </MapContext.Provider>\n )\n}\n\n/**\n * Hook to access the map context\n * @throws Error if used outside of MapProvider\n */\nexport function useMapContext(): MapContextValue {\n const context = useContext(MapContext)\n \n if (!context) {\n throw new Error('useMapContext must be used within a MapProvider or MapContainer')\n }\n \n return context\n}\n\nexport { MapContext }\n","import { useEffect, useRef, useState } from 'react'\nimport L from 'leaflet'\nimport type { Map } from 'leaflet'\nimport { MapProvider, useMapContext } from '../../context/MapContext'\nimport type { MapContainerProps } from '../../types'\n\n// Fix for default marker icons in Leaflet with bundlers\n// import 'leaflet/dist/leaflet.css' // Commented out for testing\n\n// Fix for default marker icons in Leaflet with bundlers\nif (L.Icon && L.Icon.Default && L.Icon.Default.prototype) {\n delete (L.Icon.Default.prototype as any)._getIconUrl\n}\nL.Icon.Default.mergeOptions({\n iconRetinaUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-icon-2x.png',\n iconUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-icon.png',\n shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-shadow.png',\n})\n\ninterface MapContainerInnerProps extends MapContainerProps {\n setMapReady: (ready: boolean) => void\n}\n\nfunction MapContainerInner({\n center,\n zoom,\n minZoom,\n maxZoom,\n scrollWheelZoom = true,\n dragging = true,\n doubleClickZoom = true,\n zoomControl = true,\n style,\n className,\n children,\n whenReady,\n options,\n setMapReady,\n}: MapContainerInnerProps) {\n const containerRef = useRef<HTMLDivElement>(null)\n const { setMap } = useMapContext()\n const mapRef = useRef<Map | null>(null)\n\n useEffect(() => {\n if (!containerRef.current || mapRef.current) return\n\n // Create the map\n const map = L.map(containerRef.current, {\n center,\n zoom,\n minZoom,\n maxZoom,\n scrollWheelZoom,\n dragging,\n doubleClickZoom,\n zoomControl,\n ...options,\n })\n\n mapRef.current = map\n setMap(map)\n setMapReady(true)\n\n // Call whenReady callback\n if (whenReady) {\n whenReady(map)\n }\n\n // Cleanup\n return () => {\n map.remove()\n mapRef.current = null\n setMap(null)\n setMapReady(false)\n }\n }, []) // eslint-disable-line react-hooks/exhaustive-deps\n\n // Update view when center or zoom changes\n useEffect(() => {\n if (mapRef.current) {\n mapRef.current.setView(center, zoom)\n }\n }, [center, zoom])\n\n return (\n <div\n ref={containerRef}\n style={{\n height: '100%',\n width: '100%',\n ...style,\n }}\n className={className}\n >\n {children}\n </div>\n )\n}\n\n/**\n * Main container component for creating a Leaflet map\n * \n * @example\n * ```tsx\n * <MapContainer\n * center={[51.505, -0.09]}\n * zoom={13}\n * style={{ height: '400px' }}\n * >\n * <TileLayer url=\"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png\" />\n * <Marker position={[51.505, -0.09]} />\n * </MapContainer>\n * ```\n */\nexport function MapContainer(props: MapContainerProps) {\n const [mapReady, setMapReady] = useState(false)\n\n return (\n <MapProvider>\n <MapContainerInner {...props} setMapReady={setMapReady}>\n {mapReady ? props.children : null}\n </MapContainerInner>\n </MapProvider>\n )\n}\n","import type { Map } from 'leaflet'\nimport { useMapContext } from '../context/MapContext'\n\n/**\n * Hook to access the Leaflet map instance\n * Must be used within a MapContainer or MapProvider\n * \n * @example\n * ```tsx\n * function MyComponent() {\n * const map = useMap()\n * \n * const flyToLocation = () => {\n * map.flyTo([51.505, -0.09], 14)\n * }\n * \n * return <button onClick={flyToLocation}>Go to London</button>\n * }\n * ```\n * \n * @returns The Leaflet map instance\n * @throws Error if map is not yet initialized or used outside MapContainer\n */\nexport function useMap(): Map {\n const { map } = useMapContext()\n \n if (!map) {\n throw new Error(\n 'Map instance is not available. Make sure this hook is used within a MapContainer ' +\n 'and the map has been initialized.'\n )\n }\n \n return map\n}\n","import { useEffect, useRef } from 'react'\nimport L from 'leaflet'\nimport type { TileLayer as LeafletTileLayer } from 'leaflet'\nimport { useMap } from '../../hooks/useMap'\nimport type { TileLayerProps } from '../../types'\n\n/**\n * Component for adding tile layers to the map\n * \n * @example\n * ```tsx\n * <TileLayer\n * url=\"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png\"\n * attribution='&copy; OpenStreetMap contributors'\n * maxZoom={19}\n * />\n * ```\n */\nexport function TileLayer({\n url,\n attribution,\n maxZoom,\n minZoom,\n opacity,\n zIndex,\n options,\n}: TileLayerProps) {\n const map = useMap()\n const tileLayerRef = useRef<LeafletTileLayer | null>(null)\n\n useEffect(() => {\n if (!map) return\n\n // Create tile layer\n const tileLayer = L.tileLayer(url, {\n attribution,\n maxZoom,\n minZoom,\n opacity,\n zIndex,\n ...options,\n })\n\n tileLayer.addTo(map)\n tileLayerRef.current = tileLayer\n\n // Cleanup\n return () => {\n tileLayer.remove()\n tileLayerRef.current = null\n }\n }, [map, url, attribution, maxZoom, minZoom, opacity, zIndex, options])\n\n return null\n}\n","import { useEffect, useState, createContext, useContext } from 'react'\nimport L from 'leaflet'\nimport type { Marker as LeafletMarker } from 'leaflet'\nimport { useMap } from '../../hooks/useMap'\nimport type { MarkerProps } from '../../types'\n\n// Context for sharing marker with Popup\ninterface MarkerContextValue {\n marker: LeafletMarker | null\n}\n\nconst MarkerContext = createContext<MarkerContextValue>({ marker: null })\n\nexport function useMarker(): LeafletMarker | null {\n const { marker } = useContext(MarkerContext)\n return marker\n}\n\n/**\n * Component for adding markers to the map\n * \n * @example\n * ```tsx\n * <Marker\n * position={[51.505, -0.09]}\n * draggable={false}\n * eventHandlers={{\n * click: () => console.log('Marker clicked!')\n * }}\n * >\n * <Popup>Hello!</Popup>\n * </Marker>\n * ```\n */\nexport function Marker({\n position,\n draggable = false,\n opacity,\n alt,\n eventHandlers,\n children,\n options,\n}: MarkerProps) {\n const map = useMap()\n const [marker, setMarker] = useState<LeafletMarker | null>(null)\n\n useEffect(() => {\n if (!map) return\n\n // Create marker\n const markerInstance = L.marker(position, {\n draggable,\n opacity,\n alt,\n ...options,\n })\n\n markerInstance.addTo(map)\n setMarker(markerInstance)\n\n // Cleanup\n return () => {\n markerInstance.remove()\n setMarker(null)\n }\n }, [map]) // eslint-disable-line react-hooks/exhaustive-deps\n\n // Update position\n useEffect(() => {\n if (marker) {\n marker.setLatLng(position)\n }\n }, [position, marker])\n\n // Update draggable option\n useEffect(() => {\n if (marker) {\n if (draggable) {\n marker.dragging?.enable()\n } else {\n marker.dragging?.disable()\n }\n }\n }, [draggable, marker])\n\n // Update opacity\n useEffect(() => {\n if (marker && opacity !== undefined) {\n marker.setOpacity(opacity)\n }\n }, [opacity, marker])\n\n // Attach event handlers\n useEffect(() => {\n if (!marker || !eventHandlers) return\n\n const eventNames = Object.keys(eventHandlers) as Array<keyof typeof eventHandlers>\n \n eventNames.forEach(eventName => {\n const handler = eventHandlers[eventName]\n if (handler) {\n // @ts-expect-error - Leaflet's type definitions require specific handler types per event, but we're dynamically iterating\n marker.on(eventName, handler)\n }\n })\n\n return () => {\n eventNames.forEach(eventName => {\n const handler = eventHandlers[eventName]\n if (handler) {\n // @ts-expect-error - Leaflet's type definitions require specific handler types per event, but we're dynamically iterating\n marker.off(eventName, handler)\n }\n })\n }\n }, [eventHandlers, marker])\n\n return (\n <MarkerContext.Provider value={{ marker }}>\n {children}\n </MarkerContext.Provider>\n )\n}\n","import { useEffect, useRef, useState } from 'react'\nimport { createPortal } from 'react-dom'\nimport L from 'leaflet'\nimport type { Popup as LeafletPopup } from 'leaflet'\nimport { useMap } from '../../hooks/useMap'\nimport { useMarker } from '../Marker/Marker'\nimport type { PopupProps } from '../../types'\n\n/**\n * Component for adding popups to markers or the map\n * \n * When used inside a Marker, it automatically binds to that marker.\n * When used standalone, you must provide a position.\n * \n * @example\n * ```tsx\n * // Inside a Marker\n * <Marker position={[51.505, -0.09]}>\n * <Popup>\n * <h3>My Location</h3>\n * <p>This is where I am!</p>\n * </Popup>\n * </Marker>\n * \n * // Standalone\n * <Popup position={[51.505, -0.09]}>\n * Hello from this location!\n * </Popup>\n * ```\n */\nexport function Popup({\n position,\n children,\n maxWidth = 300,\n minWidth = 50,\n autoClose = true,\n closeOnClick = true,\n className,\n options,\n}: PopupProps) {\n const map = useMap()\n const marker = useMarker()\n const popupRef = useRef<LeafletPopup | null>(null)\n const [container, setContainer] = useState<HTMLDivElement | null>(null)\n\n useEffect(() => {\n if (!map) return\n\n // Create container for React portal\n const containerElement = document.createElement('div')\n setContainer(containerElement)\n\n // Create popup with position if standalone\n const popupOptions = {\n maxWidth,\n minWidth,\n autoClose,\n closeOnClick,\n className,\n ...options,\n }\n\n const popup = !marker && position \n ? L.popup(popupOptions).setLatLng(position)\n : L.popup(popupOptions)\n\n popup.setContent(containerElement)\n popupRef.current = popup\n\n // Bind to marker (don't open yet)\n if (marker) {\n marker.bindPopup(popup)\n }\n\n // Cleanup\n return () => {\n if (marker) {\n marker.unbindPopup()\n }\n popup.remove()\n popupRef.current = null\n setContainer(null)\n }\n }, [map, marker]) // eslint-disable-line react-hooks/exhaustive-deps\n\n // Open popup after container is ready\n useEffect(() => {\n if (popupRef.current && container && map) {\n if (marker) {\n // For marker-bound popups, open them (in real usage, they'd open on click)\n popupRef.current.openOn(map)\n } else if (position) {\n // For standalone popups, open at position\n popupRef.current.openOn(map)\n }\n }\n }, [container, map, marker, position])\n\n // Update position for standalone popups\n useEffect(() => {\n if (popupRef.current && position && !marker && map) {\n popupRef.current.setLatLng(position)\n if (!popupRef.current.isOpen()) {\n popupRef.current.openOn(map)\n }\n }\n }, [position, marker, map])\n\n // Render children into popup container using portal\n if (!container) {\n return null\n }\n\n return createPortal(children, container)\n}\n","import { useEffect, useRef } from 'react'\nimport L from 'leaflet'\nimport type { GeoJSON as LeafletGeoJSON } from 'leaflet'\nimport { useMap } from '../../hooks/useMap'\nimport type { GeoJSONProps } from '../../types'\n\n/**\n * Component for rendering GeoJSON data on the map\n * \n * @example\n * ```tsx\n * const geojsonData = {\n * type: 'FeatureCollection',\n * features: [\n * {\n * type: 'Feature',\n * geometry: { type: 'Point', coordinates: [-0.09, 51.505] },\n * properties: { name: 'London' }\n * }\n * ]\n * }\n * \n * <GeoJSON\n * data={geojsonData}\n * style={{ color: 'blue', weight: 2 }}\n * onEachFeature={(feature, layer) => {\n * layer.bindPopup(feature.properties.name)\n * }}\n * />\n * ```\n */\nexport function GeoJSON({\n data,\n style,\n onEachFeature,\n pointToLayer,\n filter,\n options,\n}: GeoJSONProps) {\n const map = useMap()\n const geoJsonRef = useRef<LeafletGeoJSON | null>(null)\n\n useEffect(() => {\n if (!map || !data) return\n\n // Create GeoJSON layer\n const geoJson = L.geoJSON(data, {\n style,\n onEachFeature,\n pointToLayer,\n filter,\n ...options,\n })\n\n geoJson.addTo(map)\n geoJsonRef.current = geoJson\n\n // Cleanup\n return () => {\n geoJson.remove()\n geoJsonRef.current = null\n }\n }, [map, data, style, onEachFeature, pointToLayer, filter, options])\n\n // Update data when it changes\n useEffect(() => {\n if (geoJsonRef.current && data) {\n geoJsonRef.current.clearLayers()\n geoJsonRef.current.addData(data)\n }\n }, [data])\n\n return null\n}\n","import { useEffect } from 'react'\nimport type { LeafletEventHandlerFnMap } from 'leaflet'\nimport { useMap } from './useMap'\n\n/**\n * Hook to subscribe to Leaflet map events\n * Automatically cleans up event listeners on unmount\n * \n * @example\n * ```tsx\n * function LocationLogger() {\n * useMapEvents({\n * click: (e) => {\n * console.log('Clicked at:', e.latlng)\n * },\n * zoomend: () => {\n * console.log('Zoom changed')\n * },\n * moveend: () => {\n * console.log('Map moved')\n * }\n * })\n * \n * return null\n * }\n * ```\n * \n * @param handlers - Object mapping event names to handler functions\n */\nexport function useMapEvents(handlers: LeafletEventHandlerFnMap): void {\n const map = useMap()\n\n useEffect(() => {\n if (!map || !handlers) return\n\n // Register all event handlers\n const eventNames = Object.keys(handlers) as Array<keyof LeafletEventHandlerFnMap>\n \n eventNames.forEach(eventName => {\n const handler = handlers[eventName]\n if (handler) {\n // @ts-expect-error - Leaflet's type definitions require specific handler types per event, but we're dynamically iterating\n map.on(eventName, handler)\n }\n })\n\n // Cleanup: remove all event handlers\n return () => {\n eventNames.forEach(eventName => {\n const handler = handlers[eventName]\n if (handler) {\n // @ts-expect-error - Leaflet's type definitions require specific handler types per event, but we're dynamically iterating\n map.off(eventName, handler)\n }\n })\n }\n }, [map, handlers])\n}\n"]}
@@ -0,0 +1,291 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { LatLngExpression, Map, MapOptions, TileLayerOptions, LeafletEventHandlerFnMap, MarkerOptions, PopupOptions, GeoJSONOptions, Marker as Marker$1 } from 'leaflet';
3
+ export { LatLngExpression, Map as LeafletMap } from 'leaflet';
4
+ import * as react from 'react';
5
+ import { CSSProperties, ReactNode } from 'react';
6
+
7
+ /**
8
+ * Props for the MapContainer component
9
+ */
10
+ interface MapContainerProps {
11
+ /** Initial center position [lat, lng] */
12
+ center: LatLngExpression;
13
+ /** Initial zoom level */
14
+ zoom: number;
15
+ /** Minimum zoom level */
16
+ minZoom?: number;
17
+ /** Maximum zoom level */
18
+ maxZoom?: number;
19
+ /** Enable scroll wheel zoom */
20
+ scrollWheelZoom?: boolean;
21
+ /** Enable dragging */
22
+ dragging?: boolean;
23
+ /** Enable double click zoom */
24
+ doubleClickZoom?: boolean;
25
+ /** Enable zoom control */
26
+ zoomControl?: boolean;
27
+ /** Custom CSS styles */
28
+ style?: CSSProperties;
29
+ /** Custom CSS class */
30
+ className?: string;
31
+ /** Child components */
32
+ children?: ReactNode;
33
+ /** Callback when map is ready */
34
+ whenReady?: (map: Map) => void;
35
+ /** Additional Leaflet map options */
36
+ options?: Omit<MapOptions, 'center' | 'zoom'>;
37
+ }
38
+ /**
39
+ * Props for the TileLayer component
40
+ */
41
+ interface TileLayerProps {
42
+ /** Tile URL template */
43
+ url: string;
44
+ /** Attribution text */
45
+ attribution?: string;
46
+ /** Maximum zoom level */
47
+ maxZoom?: number;
48
+ /** Minimum zoom level */
49
+ minZoom?: number;
50
+ /** Tile opacity (0-1) */
51
+ opacity?: number;
52
+ /** Z-index */
53
+ zIndex?: number;
54
+ /** Additional Leaflet tile layer options */
55
+ options?: Omit<TileLayerOptions, 'attribution' | 'maxZoom' | 'minZoom'>;
56
+ }
57
+ /**
58
+ * Props for the Marker component
59
+ */
60
+ interface MarkerProps {
61
+ /** Marker position [lat, lng] */
62
+ position: LatLngExpression;
63
+ /** Enable dragging */
64
+ draggable?: boolean;
65
+ /** Marker opacity (0-1) */
66
+ opacity?: number;
67
+ /** Alt text for accessibility */
68
+ alt?: string;
69
+ /** Event handlers */
70
+ eventHandlers?: LeafletEventHandlerFnMap;
71
+ /** Child components (usually Popup) */
72
+ children?: ReactNode;
73
+ /** Additional Leaflet marker options */
74
+ options?: Omit<MarkerOptions, 'draggable' | 'opacity' | 'alt'>;
75
+ }
76
+ /**
77
+ * Props for the Popup component
78
+ */
79
+ interface PopupProps {
80
+ /** Popup position (optional if used inside Marker) */
81
+ position?: LatLngExpression;
82
+ /** Popup content */
83
+ children: ReactNode;
84
+ /** Maximum width */
85
+ maxWidth?: number;
86
+ /** Minimum width */
87
+ minWidth?: number;
88
+ /** Auto close on map click */
89
+ autoClose?: boolean;
90
+ /** Close on click */
91
+ closeOnClick?: boolean;
92
+ /** Custom CSS class */
93
+ className?: string;
94
+ /** Additional Leaflet popup options */
95
+ options?: Omit<PopupOptions, 'maxWidth' | 'minWidth' | 'autoClose' | 'closeOnClick' | 'className'>;
96
+ }
97
+ /**
98
+ * Props for the GeoJSON component
99
+ */
100
+ interface GeoJSONProps {
101
+ /** GeoJSON data */
102
+ data: GeoJSON.GeoJsonObject;
103
+ /** Style for features */
104
+ style?: GeoJSONOptions['style'];
105
+ /** Callback for each feature */
106
+ onEachFeature?: GeoJSONOptions['onEachFeature'];
107
+ /** Point to layer callback */
108
+ pointToLayer?: GeoJSONOptions['pointToLayer'];
109
+ /** Filter function */
110
+ filter?: GeoJSONOptions['filter'];
111
+ /** Additional Leaflet GeoJSON options */
112
+ options?: Omit<GeoJSONOptions, 'style' | 'onEachFeature' | 'pointToLayer' | 'filter'>;
113
+ }
114
+ /**
115
+ * Map context value
116
+ */
117
+ interface MapContextValue {
118
+ /** Leaflet map instance */
119
+ map: Map | null;
120
+ /** Set map instance */
121
+ setMap: (map: Map | null) => void;
122
+ }
123
+ /**
124
+ * Event handlers map type
125
+ */
126
+ type MapEventHandlers = LeafletEventHandlerFnMap;
127
+
128
+ /**
129
+ * Main container component for creating a Leaflet map
130
+ *
131
+ * @example
132
+ * ```tsx
133
+ * <MapContainer
134
+ * center={[51.505, -0.09]}
135
+ * zoom={13}
136
+ * style={{ height: '400px' }}
137
+ * >
138
+ * <TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" />
139
+ * <Marker position={[51.505, -0.09]} />
140
+ * </MapContainer>
141
+ * ```
142
+ */
143
+ declare function MapContainer(props: MapContainerProps): react_jsx_runtime.JSX.Element;
144
+
145
+ /**
146
+ * Component for adding tile layers to the map
147
+ *
148
+ * @example
149
+ * ```tsx
150
+ * <TileLayer
151
+ * url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
152
+ * attribution='&copy; OpenStreetMap contributors'
153
+ * maxZoom={19}
154
+ * />
155
+ * ```
156
+ */
157
+ declare function TileLayer({ url, attribution, maxZoom, minZoom, opacity, zIndex, options, }: TileLayerProps): null;
158
+
159
+ declare function useMarker(): Marker$1 | null;
160
+ /**
161
+ * Component for adding markers to the map
162
+ *
163
+ * @example
164
+ * ```tsx
165
+ * <Marker
166
+ * position={[51.505, -0.09]}
167
+ * draggable={false}
168
+ * eventHandlers={{
169
+ * click: () => console.log('Marker clicked!')
170
+ * }}
171
+ * >
172
+ * <Popup>Hello!</Popup>
173
+ * </Marker>
174
+ * ```
175
+ */
176
+ declare function Marker({ position, draggable, opacity, alt, eventHandlers, children, options, }: MarkerProps): react_jsx_runtime.JSX.Element;
177
+
178
+ /**
179
+ * Component for adding popups to markers or the map
180
+ *
181
+ * When used inside a Marker, it automatically binds to that marker.
182
+ * When used standalone, you must provide a position.
183
+ *
184
+ * @example
185
+ * ```tsx
186
+ * // Inside a Marker
187
+ * <Marker position={[51.505, -0.09]}>
188
+ * <Popup>
189
+ * <h3>My Location</h3>
190
+ * <p>This is where I am!</p>
191
+ * </Popup>
192
+ * </Marker>
193
+ *
194
+ * // Standalone
195
+ * <Popup position={[51.505, -0.09]}>
196
+ * Hello from this location!
197
+ * </Popup>
198
+ * ```
199
+ */
200
+ declare function Popup({ position, children, maxWidth, minWidth, autoClose, closeOnClick, className, options, }: PopupProps): react.ReactPortal | null;
201
+
202
+ /**
203
+ * Component for rendering GeoJSON data on the map
204
+ *
205
+ * @example
206
+ * ```tsx
207
+ * const geojsonData = {
208
+ * type: 'FeatureCollection',
209
+ * features: [
210
+ * {
211
+ * type: 'Feature',
212
+ * geometry: { type: 'Point', coordinates: [-0.09, 51.505] },
213
+ * properties: { name: 'London' }
214
+ * }
215
+ * ]
216
+ * }
217
+ *
218
+ * <GeoJSON
219
+ * data={geojsonData}
220
+ * style={{ color: 'blue', weight: 2 }}
221
+ * onEachFeature={(feature, layer) => {
222
+ * layer.bindPopup(feature.properties.name)
223
+ * }}
224
+ * />
225
+ * ```
226
+ */
227
+ declare function GeoJSON$1({ data, style, onEachFeature, pointToLayer, filter, options, }: GeoJSONProps): null;
228
+
229
+ /**
230
+ * Hook to access the Leaflet map instance
231
+ * Must be used within a MapContainer or MapProvider
232
+ *
233
+ * @example
234
+ * ```tsx
235
+ * function MyComponent() {
236
+ * const map = useMap()
237
+ *
238
+ * const flyToLocation = () => {
239
+ * map.flyTo([51.505, -0.09], 14)
240
+ * }
241
+ *
242
+ * return <button onClick={flyToLocation}>Go to London</button>
243
+ * }
244
+ * ```
245
+ *
246
+ * @returns The Leaflet map instance
247
+ * @throws Error if map is not yet initialized or used outside MapContainer
248
+ */
249
+ declare function useMap(): Map;
250
+
251
+ /**
252
+ * Hook to subscribe to Leaflet map events
253
+ * Automatically cleans up event listeners on unmount
254
+ *
255
+ * @example
256
+ * ```tsx
257
+ * function LocationLogger() {
258
+ * useMapEvents({
259
+ * click: (e) => {
260
+ * console.log('Clicked at:', e.latlng)
261
+ * },
262
+ * zoomend: () => {
263
+ * console.log('Zoom changed')
264
+ * },
265
+ * moveend: () => {
266
+ * console.log('Map moved')
267
+ * }
268
+ * })
269
+ *
270
+ * return null
271
+ * }
272
+ * ```
273
+ *
274
+ * @param handlers - Object mapping event names to handler functions
275
+ */
276
+ declare function useMapEvents(handlers: LeafletEventHandlerFnMap): void;
277
+
278
+ interface MapProviderProps {
279
+ children: ReactNode;
280
+ }
281
+ /**
282
+ * Provider component for sharing map instance across components
283
+ */
284
+ declare function MapProvider({ children }: MapProviderProps): react_jsx_runtime.JSX.Element;
285
+ /**
286
+ * Hook to access the map context
287
+ * @throws Error if used outside of MapProvider
288
+ */
289
+ declare function useMapContext(): MapContextValue;
290
+
291
+ export { GeoJSON$1 as GeoJSON, type GeoJSONProps, MapContainer, type MapContainerProps, type MapContextValue, type MapEventHandlers, MapProvider, Marker, type MarkerProps, Popup, type PopupProps, TileLayer, type TileLayerProps, useMap, useMapContext, useMapEvents, useMarker };
@@ -0,0 +1,291 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { LatLngExpression, Map, MapOptions, TileLayerOptions, LeafletEventHandlerFnMap, MarkerOptions, PopupOptions, GeoJSONOptions, Marker as Marker$1 } from 'leaflet';
3
+ export { LatLngExpression, Map as LeafletMap } from 'leaflet';
4
+ import * as react from 'react';
5
+ import { CSSProperties, ReactNode } from 'react';
6
+
7
+ /**
8
+ * Props for the MapContainer component
9
+ */
10
+ interface MapContainerProps {
11
+ /** Initial center position [lat, lng] */
12
+ center: LatLngExpression;
13
+ /** Initial zoom level */
14
+ zoom: number;
15
+ /** Minimum zoom level */
16
+ minZoom?: number;
17
+ /** Maximum zoom level */
18
+ maxZoom?: number;
19
+ /** Enable scroll wheel zoom */
20
+ scrollWheelZoom?: boolean;
21
+ /** Enable dragging */
22
+ dragging?: boolean;
23
+ /** Enable double click zoom */
24
+ doubleClickZoom?: boolean;
25
+ /** Enable zoom control */
26
+ zoomControl?: boolean;
27
+ /** Custom CSS styles */
28
+ style?: CSSProperties;
29
+ /** Custom CSS class */
30
+ className?: string;
31
+ /** Child components */
32
+ children?: ReactNode;
33
+ /** Callback when map is ready */
34
+ whenReady?: (map: Map) => void;
35
+ /** Additional Leaflet map options */
36
+ options?: Omit<MapOptions, 'center' | 'zoom'>;
37
+ }
38
+ /**
39
+ * Props for the TileLayer component
40
+ */
41
+ interface TileLayerProps {
42
+ /** Tile URL template */
43
+ url: string;
44
+ /** Attribution text */
45
+ attribution?: string;
46
+ /** Maximum zoom level */
47
+ maxZoom?: number;
48
+ /** Minimum zoom level */
49
+ minZoom?: number;
50
+ /** Tile opacity (0-1) */
51
+ opacity?: number;
52
+ /** Z-index */
53
+ zIndex?: number;
54
+ /** Additional Leaflet tile layer options */
55
+ options?: Omit<TileLayerOptions, 'attribution' | 'maxZoom' | 'minZoom'>;
56
+ }
57
+ /**
58
+ * Props for the Marker component
59
+ */
60
+ interface MarkerProps {
61
+ /** Marker position [lat, lng] */
62
+ position: LatLngExpression;
63
+ /** Enable dragging */
64
+ draggable?: boolean;
65
+ /** Marker opacity (0-1) */
66
+ opacity?: number;
67
+ /** Alt text for accessibility */
68
+ alt?: string;
69
+ /** Event handlers */
70
+ eventHandlers?: LeafletEventHandlerFnMap;
71
+ /** Child components (usually Popup) */
72
+ children?: ReactNode;
73
+ /** Additional Leaflet marker options */
74
+ options?: Omit<MarkerOptions, 'draggable' | 'opacity' | 'alt'>;
75
+ }
76
+ /**
77
+ * Props for the Popup component
78
+ */
79
+ interface PopupProps {
80
+ /** Popup position (optional if used inside Marker) */
81
+ position?: LatLngExpression;
82
+ /** Popup content */
83
+ children: ReactNode;
84
+ /** Maximum width */
85
+ maxWidth?: number;
86
+ /** Minimum width */
87
+ minWidth?: number;
88
+ /** Auto close on map click */
89
+ autoClose?: boolean;
90
+ /** Close on click */
91
+ closeOnClick?: boolean;
92
+ /** Custom CSS class */
93
+ className?: string;
94
+ /** Additional Leaflet popup options */
95
+ options?: Omit<PopupOptions, 'maxWidth' | 'minWidth' | 'autoClose' | 'closeOnClick' | 'className'>;
96
+ }
97
+ /**
98
+ * Props for the GeoJSON component
99
+ */
100
+ interface GeoJSONProps {
101
+ /** GeoJSON data */
102
+ data: GeoJSON.GeoJsonObject;
103
+ /** Style for features */
104
+ style?: GeoJSONOptions['style'];
105
+ /** Callback for each feature */
106
+ onEachFeature?: GeoJSONOptions['onEachFeature'];
107
+ /** Point to layer callback */
108
+ pointToLayer?: GeoJSONOptions['pointToLayer'];
109
+ /** Filter function */
110
+ filter?: GeoJSONOptions['filter'];
111
+ /** Additional Leaflet GeoJSON options */
112
+ options?: Omit<GeoJSONOptions, 'style' | 'onEachFeature' | 'pointToLayer' | 'filter'>;
113
+ }
114
+ /**
115
+ * Map context value
116
+ */
117
+ interface MapContextValue {
118
+ /** Leaflet map instance */
119
+ map: Map | null;
120
+ /** Set map instance */
121
+ setMap: (map: Map | null) => void;
122
+ }
123
+ /**
124
+ * Event handlers map type
125
+ */
126
+ type MapEventHandlers = LeafletEventHandlerFnMap;
127
+
128
+ /**
129
+ * Main container component for creating a Leaflet map
130
+ *
131
+ * @example
132
+ * ```tsx
133
+ * <MapContainer
134
+ * center={[51.505, -0.09]}
135
+ * zoom={13}
136
+ * style={{ height: '400px' }}
137
+ * >
138
+ * <TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" />
139
+ * <Marker position={[51.505, -0.09]} />
140
+ * </MapContainer>
141
+ * ```
142
+ */
143
+ declare function MapContainer(props: MapContainerProps): react_jsx_runtime.JSX.Element;
144
+
145
+ /**
146
+ * Component for adding tile layers to the map
147
+ *
148
+ * @example
149
+ * ```tsx
150
+ * <TileLayer
151
+ * url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
152
+ * attribution='&copy; OpenStreetMap contributors'
153
+ * maxZoom={19}
154
+ * />
155
+ * ```
156
+ */
157
+ declare function TileLayer({ url, attribution, maxZoom, minZoom, opacity, zIndex, options, }: TileLayerProps): null;
158
+
159
+ declare function useMarker(): Marker$1 | null;
160
+ /**
161
+ * Component for adding markers to the map
162
+ *
163
+ * @example
164
+ * ```tsx
165
+ * <Marker
166
+ * position={[51.505, -0.09]}
167
+ * draggable={false}
168
+ * eventHandlers={{
169
+ * click: () => console.log('Marker clicked!')
170
+ * }}
171
+ * >
172
+ * <Popup>Hello!</Popup>
173
+ * </Marker>
174
+ * ```
175
+ */
176
+ declare function Marker({ position, draggable, opacity, alt, eventHandlers, children, options, }: MarkerProps): react_jsx_runtime.JSX.Element;
177
+
178
+ /**
179
+ * Component for adding popups to markers or the map
180
+ *
181
+ * When used inside a Marker, it automatically binds to that marker.
182
+ * When used standalone, you must provide a position.
183
+ *
184
+ * @example
185
+ * ```tsx
186
+ * // Inside a Marker
187
+ * <Marker position={[51.505, -0.09]}>
188
+ * <Popup>
189
+ * <h3>My Location</h3>
190
+ * <p>This is where I am!</p>
191
+ * </Popup>
192
+ * </Marker>
193
+ *
194
+ * // Standalone
195
+ * <Popup position={[51.505, -0.09]}>
196
+ * Hello from this location!
197
+ * </Popup>
198
+ * ```
199
+ */
200
+ declare function Popup({ position, children, maxWidth, minWidth, autoClose, closeOnClick, className, options, }: PopupProps): react.ReactPortal | null;
201
+
202
+ /**
203
+ * Component for rendering GeoJSON data on the map
204
+ *
205
+ * @example
206
+ * ```tsx
207
+ * const geojsonData = {
208
+ * type: 'FeatureCollection',
209
+ * features: [
210
+ * {
211
+ * type: 'Feature',
212
+ * geometry: { type: 'Point', coordinates: [-0.09, 51.505] },
213
+ * properties: { name: 'London' }
214
+ * }
215
+ * ]
216
+ * }
217
+ *
218
+ * <GeoJSON
219
+ * data={geojsonData}
220
+ * style={{ color: 'blue', weight: 2 }}
221
+ * onEachFeature={(feature, layer) => {
222
+ * layer.bindPopup(feature.properties.name)
223
+ * }}
224
+ * />
225
+ * ```
226
+ */
227
+ declare function GeoJSON$1({ data, style, onEachFeature, pointToLayer, filter, options, }: GeoJSONProps): null;
228
+
229
+ /**
230
+ * Hook to access the Leaflet map instance
231
+ * Must be used within a MapContainer or MapProvider
232
+ *
233
+ * @example
234
+ * ```tsx
235
+ * function MyComponent() {
236
+ * const map = useMap()
237
+ *
238
+ * const flyToLocation = () => {
239
+ * map.flyTo([51.505, -0.09], 14)
240
+ * }
241
+ *
242
+ * return <button onClick={flyToLocation}>Go to London</button>
243
+ * }
244
+ * ```
245
+ *
246
+ * @returns The Leaflet map instance
247
+ * @throws Error if map is not yet initialized or used outside MapContainer
248
+ */
249
+ declare function useMap(): Map;
250
+
251
+ /**
252
+ * Hook to subscribe to Leaflet map events
253
+ * Automatically cleans up event listeners on unmount
254
+ *
255
+ * @example
256
+ * ```tsx
257
+ * function LocationLogger() {
258
+ * useMapEvents({
259
+ * click: (e) => {
260
+ * console.log('Clicked at:', e.latlng)
261
+ * },
262
+ * zoomend: () => {
263
+ * console.log('Zoom changed')
264
+ * },
265
+ * moveend: () => {
266
+ * console.log('Map moved')
267
+ * }
268
+ * })
269
+ *
270
+ * return null
271
+ * }
272
+ * ```
273
+ *
274
+ * @param handlers - Object mapping event names to handler functions
275
+ */
276
+ declare function useMapEvents(handlers: LeafletEventHandlerFnMap): void;
277
+
278
+ interface MapProviderProps {
279
+ children: ReactNode;
280
+ }
281
+ /**
282
+ * Provider component for sharing map instance across components
283
+ */
284
+ declare function MapProvider({ children }: MapProviderProps): react_jsx_runtime.JSX.Element;
285
+ /**
286
+ * Hook to access the map context
287
+ * @throws Error if used outside of MapProvider
288
+ */
289
+ declare function useMapContext(): MapContextValue;
290
+
291
+ export { GeoJSON$1 as GeoJSON, type GeoJSONProps, MapContainer, type MapContainerProps, type MapContextValue, type MapEventHandlers, MapProvider, Marker, type MarkerProps, Popup, type PopupProps, TileLayer, type TileLayerProps, useMap, useMapContext, useMapEvents, useMarker };
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ import {createContext,useState,useContext,useRef,useEffect}from'react';import x from'leaflet';import {jsx}from'react/jsx-runtime';import {createPortal}from'react-dom';var g=createContext(null);function E({children:e}){let[t,o]=useState(null);return jsx(g.Provider,{value:{map:t,setMap:o},children:e})}function L(){let e=useContext(g);if(!e)throw new Error("useMapContext must be used within a MapProvider or MapContainer");return e}x.Icon&&x.Icon.Default&&x.Icon.Default.prototype&&delete x.Icon.Default.prototype._getIconUrl;x.Icon.Default.mergeOptions({iconRetinaUrl:"https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-icon-2x.png",iconUrl:"https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-icon.png",shadowUrl:"https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-shadow.png"});function F({center:e,zoom:t,minZoom:o,maxZoom:u,scrollWheelZoom:n=true,dragging:i=true,doubleClickZoom:s=true,zoomControl:f=true,style:r,className:a,children:p,whenReady:l,options:c,setMapReady:y}){let d=useRef(null),{setMap:M}=L(),P=useRef(null);return useEffect(()=>{if(!d.current||P.current)return;let C=x.map(d.current,{center:e,zoom:t,minZoom:o,maxZoom:u,scrollWheelZoom:n,dragging:i,doubleClickZoom:s,zoomControl:f,...c});return P.current=C,M(C),y(true),l&&l(C),()=>{C.remove(),P.current=null,M(null),y(false);}},[]),useEffect(()=>{P.current&&P.current.setView(e,t);},[e,t]),jsx("div",{ref:d,style:{height:"100%",width:"100%",...r},className:a,children:p})}function T(e){let[t,o]=useState(false);return jsx(E,{children:jsx(F,{...e,setMapReady:o,children:t?e.children:null})})}function m(){let{map:e}=L();if(!e)throw new Error("Map instance is not available. Make sure this hook is used within a MapContainer and the map has been initialized.");return e}function J({url:e,attribution:t,maxZoom:o,minZoom:u,opacity:n,zIndex:i,options:s}){let f=m(),r=useRef(null);return useEffect(()=>{if(!f)return;let a=x.tileLayer(e,{attribution:t,maxZoom:o,minZoom:u,opacity:n,zIndex:i,...s});return a.addTo(f),r.current=a,()=>{a.remove(),r.current=null;}},[f,e,t,o,u,n,i,s]),null}var N=createContext({marker:null});function v(){let{marker:e}=useContext(N);return e}function b({position:e,draggable:t=false,opacity:o,alt:u,eventHandlers:n,children:i,options:s}){let f=m(),[r,a]=useState(null);return useEffect(()=>{if(!f)return;let p=x.marker(e,{draggable:t,opacity:o,alt:u,...s});return p.addTo(f),a(p),()=>{p.remove(),a(null);}},[f]),useEffect(()=>{r&&r.setLatLng(e);},[e,r]),useEffect(()=>{r&&(t?r.dragging?.enable():r.dragging?.disable());},[t,r]),useEffect(()=>{r&&o!==void 0&&r.setOpacity(o);},[o,r]),useEffect(()=>{if(!r||!n)return;let p=Object.keys(n);return p.forEach(l=>{let c=n[l];c&&r.on(l,c);}),()=>{p.forEach(l=>{let c=n[l];c&&r.off(l,c);});}},[n,r]),jsx(N.Provider,{value:{marker:r},children:i})}function w({position:e,children:t,maxWidth:o=300,minWidth:u=50,autoClose:n=true,closeOnClick:i=true,className:s,options:f}){let r=m(),a=v(),p=useRef(null),[l,c]=useState(null);return useEffect(()=>{if(!r)return;let y=document.createElement("div");c(y);let d={maxWidth:o,minWidth:u,autoClose:n,closeOnClick:i,className:s,...f},M=!a&&e?x.popup(d).setLatLng(e):x.popup(d);return M.setContent(y),p.current=M,a&&a.bindPopup(M),()=>{a&&a.unbindPopup(),M.remove(),p.current=null,c(null);}},[r,a]),useEffect(()=>{p.current&&l&&r&&(a||e)&&p.current.openOn(r);},[l,r,a,e]),useEffect(()=>{p.current&&e&&!a&&r&&(p.current.setLatLng(e),p.current.isOpen()||p.current.openOn(r));},[e,a,r]),l?createPortal(t,l):null}function D({data:e,style:t,onEachFeature:o,pointToLayer:u,filter:n,options:i}){let s=m(),f=useRef(null);return useEffect(()=>{if(!s||!e)return;let r=x.geoJSON(e,{style:t,onEachFeature:o,pointToLayer:u,filter:n,...i});return r.addTo(s),f.current=r,()=>{r.remove(),f.current=null;}},[s,e,t,o,u,n,i]),useEffect(()=>{f.current&&e&&(f.current.clearLayers(),f.current.addData(e));},[e]),null}function oe(e){let t=m();useEffect(()=>{if(!t||!e)return;let o=Object.keys(e);return o.forEach(u=>{let n=e[u];n&&t.on(u,n);}),()=>{o.forEach(u=>{let n=e[u];n&&t.off(u,n);});}},[t,e]);}
2
+ export{D as GeoJSON,T as MapContainer,E as MapProvider,b as Marker,w as Popup,J as TileLayer,m as useMap,L as useMapContext,oe as useMapEvents,v as useMarker};//# sourceMappingURL=index.js.map
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/context/MapContext.tsx","../src/components/MapContainer/MapContainer.tsx","../src/hooks/useMap.ts","../src/components/TileLayer/TileLayer.tsx","../src/components/Marker/Marker.tsx","../src/components/Popup/Popup.tsx","../src/components/GeoJSON/GeoJSON.tsx","../src/hooks/useMapEvents.ts"],"names":["MapContext","createContext","MapProvider","children","map","setMap","useState","jsx","useMapContext","context","useContext","L","MapContainerInner","center","zoom","minZoom","maxZoom","scrollWheelZoom","dragging","doubleClickZoom","zoomControl","style","className","whenReady","options","setMapReady","containerRef","useRef","mapRef","useEffect","MapContainer","props","mapReady","useMap","TileLayer","url","attribution","opacity","zIndex","tileLayerRef","tileLayer","MarkerContext","useMarker","marker","Marker","position","draggable","alt","eventHandlers","setMarker","markerInstance","eventNames","eventName","handler","Popup","maxWidth","minWidth","autoClose","closeOnClick","popupRef","container","setContainer","containerElement","popupOptions","popup","createPortal","GeoJSON","data","onEachFeature","pointToLayer","filter","geoJsonRef","geoJson","useMapEvents","handlers"],"mappings":"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","file":"index.js","sourcesContent":["import { createContext, useContext, useState, type ReactNode } from 'react'\nimport type { Map } from 'leaflet'\nimport type { MapContextValue } from '../types'\n\nconst MapContext = createContext<MapContextValue | null>(null)\n\nexport interface MapProviderProps {\n children: ReactNode\n}\n\n/**\n * Provider component for sharing map instance across components\n */\nexport function MapProvider({ children }: MapProviderProps) {\n const [map, setMap] = useState<Map | null>(null)\n\n return (\n <MapContext.Provider value={{ map, setMap }}>\n {children}\n </MapContext.Provider>\n )\n}\n\n/**\n * Hook to access the map context\n * @throws Error if used outside of MapProvider\n */\nexport function useMapContext(): MapContextValue {\n const context = useContext(MapContext)\n \n if (!context) {\n throw new Error('useMapContext must be used within a MapProvider or MapContainer')\n }\n \n return context\n}\n\nexport { MapContext }\n","import { useEffect, useRef, useState } from 'react'\nimport L from 'leaflet'\nimport type { Map } from 'leaflet'\nimport { MapProvider, useMapContext } from '../../context/MapContext'\nimport type { MapContainerProps } from '../../types'\n\n// Fix for default marker icons in Leaflet with bundlers\n// import 'leaflet/dist/leaflet.css' // Commented out for testing\n\n// Fix for default marker icons in Leaflet with bundlers\nif (L.Icon && L.Icon.Default && L.Icon.Default.prototype) {\n delete (L.Icon.Default.prototype as any)._getIconUrl\n}\nL.Icon.Default.mergeOptions({\n iconRetinaUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-icon-2x.png',\n iconUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-icon.png',\n shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-shadow.png',\n})\n\ninterface MapContainerInnerProps extends MapContainerProps {\n setMapReady: (ready: boolean) => void\n}\n\nfunction MapContainerInner({\n center,\n zoom,\n minZoom,\n maxZoom,\n scrollWheelZoom = true,\n dragging = true,\n doubleClickZoom = true,\n zoomControl = true,\n style,\n className,\n children,\n whenReady,\n options,\n setMapReady,\n}: MapContainerInnerProps) {\n const containerRef = useRef<HTMLDivElement>(null)\n const { setMap } = useMapContext()\n const mapRef = useRef<Map | null>(null)\n\n useEffect(() => {\n if (!containerRef.current || mapRef.current) return\n\n // Create the map\n const map = L.map(containerRef.current, {\n center,\n zoom,\n minZoom,\n maxZoom,\n scrollWheelZoom,\n dragging,\n doubleClickZoom,\n zoomControl,\n ...options,\n })\n\n mapRef.current = map\n setMap(map)\n setMapReady(true)\n\n // Call whenReady callback\n if (whenReady) {\n whenReady(map)\n }\n\n // Cleanup\n return () => {\n map.remove()\n mapRef.current = null\n setMap(null)\n setMapReady(false)\n }\n }, []) // eslint-disable-line react-hooks/exhaustive-deps\n\n // Update view when center or zoom changes\n useEffect(() => {\n if (mapRef.current) {\n mapRef.current.setView(center, zoom)\n }\n }, [center, zoom])\n\n return (\n <div\n ref={containerRef}\n style={{\n height: '100%',\n width: '100%',\n ...style,\n }}\n className={className}\n >\n {children}\n </div>\n )\n}\n\n/**\n * Main container component for creating a Leaflet map\n * \n * @example\n * ```tsx\n * <MapContainer\n * center={[51.505, -0.09]}\n * zoom={13}\n * style={{ height: '400px' }}\n * >\n * <TileLayer url=\"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png\" />\n * <Marker position={[51.505, -0.09]} />\n * </MapContainer>\n * ```\n */\nexport function MapContainer(props: MapContainerProps) {\n const [mapReady, setMapReady] = useState(false)\n\n return (\n <MapProvider>\n <MapContainerInner {...props} setMapReady={setMapReady}>\n {mapReady ? props.children : null}\n </MapContainerInner>\n </MapProvider>\n )\n}\n","import type { Map } from 'leaflet'\nimport { useMapContext } from '../context/MapContext'\n\n/**\n * Hook to access the Leaflet map instance\n * Must be used within a MapContainer or MapProvider\n * \n * @example\n * ```tsx\n * function MyComponent() {\n * const map = useMap()\n * \n * const flyToLocation = () => {\n * map.flyTo([51.505, -0.09], 14)\n * }\n * \n * return <button onClick={flyToLocation}>Go to London</button>\n * }\n * ```\n * \n * @returns The Leaflet map instance\n * @throws Error if map is not yet initialized or used outside MapContainer\n */\nexport function useMap(): Map {\n const { map } = useMapContext()\n \n if (!map) {\n throw new Error(\n 'Map instance is not available. Make sure this hook is used within a MapContainer ' +\n 'and the map has been initialized.'\n )\n }\n \n return map\n}\n","import { useEffect, useRef } from 'react'\nimport L from 'leaflet'\nimport type { TileLayer as LeafletTileLayer } from 'leaflet'\nimport { useMap } from '../../hooks/useMap'\nimport type { TileLayerProps } from '../../types'\n\n/**\n * Component for adding tile layers to the map\n * \n * @example\n * ```tsx\n * <TileLayer\n * url=\"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png\"\n * attribution='&copy; OpenStreetMap contributors'\n * maxZoom={19}\n * />\n * ```\n */\nexport function TileLayer({\n url,\n attribution,\n maxZoom,\n minZoom,\n opacity,\n zIndex,\n options,\n}: TileLayerProps) {\n const map = useMap()\n const tileLayerRef = useRef<LeafletTileLayer | null>(null)\n\n useEffect(() => {\n if (!map) return\n\n // Create tile layer\n const tileLayer = L.tileLayer(url, {\n attribution,\n maxZoom,\n minZoom,\n opacity,\n zIndex,\n ...options,\n })\n\n tileLayer.addTo(map)\n tileLayerRef.current = tileLayer\n\n // Cleanup\n return () => {\n tileLayer.remove()\n tileLayerRef.current = null\n }\n }, [map, url, attribution, maxZoom, minZoom, opacity, zIndex, options])\n\n return null\n}\n","import { useEffect, useState, createContext, useContext } from 'react'\nimport L from 'leaflet'\nimport type { Marker as LeafletMarker } from 'leaflet'\nimport { useMap } from '../../hooks/useMap'\nimport type { MarkerProps } from '../../types'\n\n// Context for sharing marker with Popup\ninterface MarkerContextValue {\n marker: LeafletMarker | null\n}\n\nconst MarkerContext = createContext<MarkerContextValue>({ marker: null })\n\nexport function useMarker(): LeafletMarker | null {\n const { marker } = useContext(MarkerContext)\n return marker\n}\n\n/**\n * Component for adding markers to the map\n * \n * @example\n * ```tsx\n * <Marker\n * position={[51.505, -0.09]}\n * draggable={false}\n * eventHandlers={{\n * click: () => console.log('Marker clicked!')\n * }}\n * >\n * <Popup>Hello!</Popup>\n * </Marker>\n * ```\n */\nexport function Marker({\n position,\n draggable = false,\n opacity,\n alt,\n eventHandlers,\n children,\n options,\n}: MarkerProps) {\n const map = useMap()\n const [marker, setMarker] = useState<LeafletMarker | null>(null)\n\n useEffect(() => {\n if (!map) return\n\n // Create marker\n const markerInstance = L.marker(position, {\n draggable,\n opacity,\n alt,\n ...options,\n })\n\n markerInstance.addTo(map)\n setMarker(markerInstance)\n\n // Cleanup\n return () => {\n markerInstance.remove()\n setMarker(null)\n }\n }, [map]) // eslint-disable-line react-hooks/exhaustive-deps\n\n // Update position\n useEffect(() => {\n if (marker) {\n marker.setLatLng(position)\n }\n }, [position, marker])\n\n // Update draggable option\n useEffect(() => {\n if (marker) {\n if (draggable) {\n marker.dragging?.enable()\n } else {\n marker.dragging?.disable()\n }\n }\n }, [draggable, marker])\n\n // Update opacity\n useEffect(() => {\n if (marker && opacity !== undefined) {\n marker.setOpacity(opacity)\n }\n }, [opacity, marker])\n\n // Attach event handlers\n useEffect(() => {\n if (!marker || !eventHandlers) return\n\n const eventNames = Object.keys(eventHandlers) as Array<keyof typeof eventHandlers>\n \n eventNames.forEach(eventName => {\n const handler = eventHandlers[eventName]\n if (handler) {\n // @ts-expect-error - Leaflet's type definitions require specific handler types per event, but we're dynamically iterating\n marker.on(eventName, handler)\n }\n })\n\n return () => {\n eventNames.forEach(eventName => {\n const handler = eventHandlers[eventName]\n if (handler) {\n // @ts-expect-error - Leaflet's type definitions require specific handler types per event, but we're dynamically iterating\n marker.off(eventName, handler)\n }\n })\n }\n }, [eventHandlers, marker])\n\n return (\n <MarkerContext.Provider value={{ marker }}>\n {children}\n </MarkerContext.Provider>\n )\n}\n","import { useEffect, useRef, useState } from 'react'\nimport { createPortal } from 'react-dom'\nimport L from 'leaflet'\nimport type { Popup as LeafletPopup } from 'leaflet'\nimport { useMap } from '../../hooks/useMap'\nimport { useMarker } from '../Marker/Marker'\nimport type { PopupProps } from '../../types'\n\n/**\n * Component for adding popups to markers or the map\n * \n * When used inside a Marker, it automatically binds to that marker.\n * When used standalone, you must provide a position.\n * \n * @example\n * ```tsx\n * // Inside a Marker\n * <Marker position={[51.505, -0.09]}>\n * <Popup>\n * <h3>My Location</h3>\n * <p>This is where I am!</p>\n * </Popup>\n * </Marker>\n * \n * // Standalone\n * <Popup position={[51.505, -0.09]}>\n * Hello from this location!\n * </Popup>\n * ```\n */\nexport function Popup({\n position,\n children,\n maxWidth = 300,\n minWidth = 50,\n autoClose = true,\n closeOnClick = true,\n className,\n options,\n}: PopupProps) {\n const map = useMap()\n const marker = useMarker()\n const popupRef = useRef<LeafletPopup | null>(null)\n const [container, setContainer] = useState<HTMLDivElement | null>(null)\n\n useEffect(() => {\n if (!map) return\n\n // Create container for React portal\n const containerElement = document.createElement('div')\n setContainer(containerElement)\n\n // Create popup with position if standalone\n const popupOptions = {\n maxWidth,\n minWidth,\n autoClose,\n closeOnClick,\n className,\n ...options,\n }\n\n const popup = !marker && position \n ? L.popup(popupOptions).setLatLng(position)\n : L.popup(popupOptions)\n\n popup.setContent(containerElement)\n popupRef.current = popup\n\n // Bind to marker (don't open yet)\n if (marker) {\n marker.bindPopup(popup)\n }\n\n // Cleanup\n return () => {\n if (marker) {\n marker.unbindPopup()\n }\n popup.remove()\n popupRef.current = null\n setContainer(null)\n }\n }, [map, marker]) // eslint-disable-line react-hooks/exhaustive-deps\n\n // Open popup after container is ready\n useEffect(() => {\n if (popupRef.current && container && map) {\n if (marker) {\n // For marker-bound popups, open them (in real usage, they'd open on click)\n popupRef.current.openOn(map)\n } else if (position) {\n // For standalone popups, open at position\n popupRef.current.openOn(map)\n }\n }\n }, [container, map, marker, position])\n\n // Update position for standalone popups\n useEffect(() => {\n if (popupRef.current && position && !marker && map) {\n popupRef.current.setLatLng(position)\n if (!popupRef.current.isOpen()) {\n popupRef.current.openOn(map)\n }\n }\n }, [position, marker, map])\n\n // Render children into popup container using portal\n if (!container) {\n return null\n }\n\n return createPortal(children, container)\n}\n","import { useEffect, useRef } from 'react'\nimport L from 'leaflet'\nimport type { GeoJSON as LeafletGeoJSON } from 'leaflet'\nimport { useMap } from '../../hooks/useMap'\nimport type { GeoJSONProps } from '../../types'\n\n/**\n * Component for rendering GeoJSON data on the map\n * \n * @example\n * ```tsx\n * const geojsonData = {\n * type: 'FeatureCollection',\n * features: [\n * {\n * type: 'Feature',\n * geometry: { type: 'Point', coordinates: [-0.09, 51.505] },\n * properties: { name: 'London' }\n * }\n * ]\n * }\n * \n * <GeoJSON\n * data={geojsonData}\n * style={{ color: 'blue', weight: 2 }}\n * onEachFeature={(feature, layer) => {\n * layer.bindPopup(feature.properties.name)\n * }}\n * />\n * ```\n */\nexport function GeoJSON({\n data,\n style,\n onEachFeature,\n pointToLayer,\n filter,\n options,\n}: GeoJSONProps) {\n const map = useMap()\n const geoJsonRef = useRef<LeafletGeoJSON | null>(null)\n\n useEffect(() => {\n if (!map || !data) return\n\n // Create GeoJSON layer\n const geoJson = L.geoJSON(data, {\n style,\n onEachFeature,\n pointToLayer,\n filter,\n ...options,\n })\n\n geoJson.addTo(map)\n geoJsonRef.current = geoJson\n\n // Cleanup\n return () => {\n geoJson.remove()\n geoJsonRef.current = null\n }\n }, [map, data, style, onEachFeature, pointToLayer, filter, options])\n\n // Update data when it changes\n useEffect(() => {\n if (geoJsonRef.current && data) {\n geoJsonRef.current.clearLayers()\n geoJsonRef.current.addData(data)\n }\n }, [data])\n\n return null\n}\n","import { useEffect } from 'react'\nimport type { LeafletEventHandlerFnMap } from 'leaflet'\nimport { useMap } from './useMap'\n\n/**\n * Hook to subscribe to Leaflet map events\n * Automatically cleans up event listeners on unmount\n * \n * @example\n * ```tsx\n * function LocationLogger() {\n * useMapEvents({\n * click: (e) => {\n * console.log('Clicked at:', e.latlng)\n * },\n * zoomend: () => {\n * console.log('Zoom changed')\n * },\n * moveend: () => {\n * console.log('Map moved')\n * }\n * })\n * \n * return null\n * }\n * ```\n * \n * @param handlers - Object mapping event names to handler functions\n */\nexport function useMapEvents(handlers: LeafletEventHandlerFnMap): void {\n const map = useMap()\n\n useEffect(() => {\n if (!map || !handlers) return\n\n // Register all event handlers\n const eventNames = Object.keys(handlers) as Array<keyof LeafletEventHandlerFnMap>\n \n eventNames.forEach(eventName => {\n const handler = handlers[eventName]\n if (handler) {\n // @ts-expect-error - Leaflet's type definitions require specific handler types per event, but we're dynamically iterating\n map.on(eventName, handler)\n }\n })\n\n // Cleanup: remove all event handlers\n return () => {\n eventNames.forEach(eventName => {\n const handler = handlers[eventName]\n if (handler) {\n // @ts-expect-error - Leaflet's type definitions require specific handler types per event, but we're dynamically iterating\n map.off(eventName, handler)\n }\n })\n }\n }, [map, handlers])\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,119 @@
1
+ {
2
+ "name": "@geekles007/motion-map-components",
3
+ "version": "0.2.0",
4
+ "description": "Modern React components for interactive maps with Leaflet",
5
+ "author": "Geekles",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/Geekles007/react-map-components.git"
10
+ },
11
+ "homepage": "https://github.com/Geekles007/react-map-components#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/Geekles007/react-map-components/issues"
14
+ },
15
+ "keywords": [
16
+ "react",
17
+ "map",
18
+ "leaflet",
19
+ "mapbox",
20
+ "gis",
21
+ "components",
22
+ "typescript",
23
+ "mapping",
24
+ "geojson",
25
+ "markers"
26
+ ],
27
+ "type": "module",
28
+ "main": "./dist/index.cjs",
29
+ "module": "./dist/index.js",
30
+ "types": "./dist/index.d.ts",
31
+ "exports": {
32
+ ".": {
33
+ "import": {
34
+ "types": "./dist/index.d.ts",
35
+ "default": "./dist/index.js"
36
+ },
37
+ "require": {
38
+ "types": "./dist/index.d.cts",
39
+ "default": "./dist/index.cjs"
40
+ }
41
+ },
42
+ "./styles.css": "./dist/styles.css"
43
+ },
44
+ "files": [
45
+ "dist",
46
+ "README.md",
47
+ "LICENSE"
48
+ ],
49
+ "sideEffects": [
50
+ "*.css"
51
+ ],
52
+ "scripts": {
53
+ "dev": "storybook dev -p 6006",
54
+ "build": "tsup",
55
+ "build:storybook": "storybook build",
56
+ "test": "vitest",
57
+ "test:ui": "vitest --ui",
58
+ "test:coverage": "vitest --coverage",
59
+ "lint": "eslint src --ext .ts,.tsx",
60
+ "lint:fix": "eslint src --ext .ts,.tsx --fix",
61
+ "format": "prettier --write \"src/**/*.{ts,tsx,css}\"",
62
+ "typecheck": "tsc --noEmit",
63
+ "prepublishOnly": "npm run build",
64
+ "release": "changeset publish",
65
+ "prepare": "husky install"
66
+ },
67
+ "peerDependencies": {
68
+ "react": "^18.0.0 || ^19.0.0",
69
+ "react-dom": "^18.0.0 || ^19.0.0"
70
+ },
71
+ "dependencies": {
72
+ "leaflet": "^1.9.4"
73
+ },
74
+ "devDependencies": {
75
+ "@changesets/cli": "^2.27.1",
76
+ "@storybook/addon-essentials": "^8.0.4",
77
+ "@storybook/addon-interactions": "^8.0.4",
78
+ "@storybook/addon-links": "^8.0.4",
79
+ "@storybook/blocks": "^8.0.4",
80
+ "@storybook/react": "^8.0.4",
81
+ "@storybook/react-vite": "^8.0.4",
82
+ "@storybook/test": "^8.0.4",
83
+ "@testing-library/jest-dom": "^6.4.2",
84
+ "@testing-library/react": "^14.2.2",
85
+ "@types/leaflet": "^1.9.8",
86
+ "@types/react": "^18.2.67",
87
+ "@types/react-dom": "^18.2.22",
88
+ "@typescript-eslint/eslint-plugin": "^7.3.1",
89
+ "@typescript-eslint/parser": "^7.3.1",
90
+ "@vitejs/plugin-react": "^4.2.1",
91
+ "@vitest/coverage-v8": "^1.4.0",
92
+ "@vitest/ui": "^1.4.0",
93
+ "eslint": "^8.57.0",
94
+ "eslint-config-prettier": "^9.1.0",
95
+ "eslint-plugin-react": "^7.34.1",
96
+ "eslint-plugin-react-hooks": "^4.6.0",
97
+ "eslint-plugin-storybook": "^0.8.0",
98
+ "husky": "^9.0.11",
99
+ "jsdom": "^24.0.0",
100
+ "lint-staged": "^15.2.2",
101
+ "prettier": "^3.2.5",
102
+ "react": "^18.2.0",
103
+ "react-dom": "^18.2.0",
104
+ "storybook": "^8.0.4",
105
+ "tsup": "^8.0.2",
106
+ "typescript": "^5.4.2",
107
+ "vite": "^5.2.6",
108
+ "vitest": "^1.4.0"
109
+ },
110
+ "lint-staged": {
111
+ "*.{ts,tsx}": [
112
+ "eslint --fix",
113
+ "prettier --write"
114
+ ]
115
+ },
116
+ "engines": {
117
+ "node": ">=18.0.0"
118
+ }
119
+ }