@lugg/maps 0.2.0-alpha.22 → 0.2.0-alpha.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/README.md +5 -0
  2. package/android/src/main/java/com/luggmaps/LuggMapView.kt +241 -0
  3. package/android/src/main/java/com/luggmaps/{LuggGoogleMapViewManager.kt → LuggMapViewManager.kt} +36 -31
  4. package/android/src/main/java/com/luggmaps/LuggPackage.kt +1 -4
  5. package/android/src/main/java/com/luggmaps/{LuggGoogleMapView.kt → core/GoogleMapProvider.kt} +172 -212
  6. package/android/src/main/java/com/luggmaps/core/MapProviderDelegate.kt +53 -0
  7. package/android/src/main/java/com/luggmaps/core/PolylineAnimator.kt +32 -26
  8. package/ios/LuggMapView.h +9 -0
  9. package/ios/LuggMapView.mm +285 -0
  10. package/ios/core/AppleMapProvider.h +15 -0
  11. package/ios/{LuggAppleMapView.mm → core/AppleMapProvider.mm} +310 -421
  12. package/ios/core/GMSPolylineAnimator.m +16 -4
  13. package/ios/core/GoogleMapProvider.h +13 -0
  14. package/ios/{LuggGoogleMapView.mm → core/GoogleMapProvider.mm} +178 -238
  15. package/ios/core/MapProviderDelegate.h +68 -0
  16. package/lib/module/MapView.js +5 -11
  17. package/lib/module/MapView.js.map +1 -1
  18. package/lib/module/fabric/{LuggGoogleMapViewNativeComponent.ts → LuggMapViewNativeComponent.ts} +2 -1
  19. package/lib/typescript/src/MapView.d.ts +0 -1
  20. package/lib/typescript/src/MapView.d.ts.map +1 -1
  21. package/lib/typescript/src/fabric/{LuggGoogleMapViewNativeComponent.d.ts → LuggMapViewNativeComponent.d.ts} +2 -1
  22. package/lib/typescript/src/fabric/LuggMapViewNativeComponent.d.ts.map +1 -0
  23. package/package.json +3 -4
  24. package/src/MapView.tsx +8 -21
  25. package/src/fabric/{LuggGoogleMapViewNativeComponent.ts → LuggMapViewNativeComponent.ts} +2 -1
  26. package/ios/LuggAppleMapView.h +0 -16
  27. package/ios/LuggGoogleMapView.h +0 -13
  28. package/lib/module/fabric/LuggAppleMapViewNativeComponent.ts +0 -85
  29. package/lib/typescript/src/fabric/LuggAppleMapViewNativeComponent.d.ts +0 -55
  30. package/lib/typescript/src/fabric/LuggAppleMapViewNativeComponent.d.ts.map +0 -1
  31. package/lib/typescript/src/fabric/LuggGoogleMapViewNativeComponent.d.ts.map +0 -1
  32. package/src/fabric/LuggAppleMapViewNativeComponent.ts +0 -85
package/README.md CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  Universal maps for your React Native apps 📍
4
4
 
5
+ <img alt="@lugg/maps" src="docs/preview.gif" width="720" />
6
+
7
+ > [!IMPORTANT]
8
+ > This library is currently under heavy development. APIs may change without notice.
9
+
5
10
  ## Installation
6
11
 
7
12
  ```sh
@@ -0,0 +1,241 @@
1
+ package com.luggmaps
2
+
3
+ import android.annotation.SuppressLint
4
+ import android.view.View
5
+ import android.view.View.VISIBLE
6
+ import com.facebook.react.uimanager.ThemedReactContext
7
+ import com.facebook.react.util.RNLog
8
+ import com.facebook.react.views.view.ReactViewGroup
9
+ import com.google.android.gms.maps.model.LatLng
10
+ import com.luggmaps.core.EdgeInsets
11
+ import com.luggmaps.core.GoogleMapProvider
12
+ import com.luggmaps.core.MapProvider
13
+ import com.luggmaps.core.MapProviderDelegate
14
+
15
+ interface LuggMapViewEventDelegate {
16
+ fun onCameraMove(
17
+ view: LuggMapView,
18
+ latitude: Double,
19
+ longitude: Double,
20
+ zoom: Float,
21
+ gesture: Boolean
22
+ )
23
+ fun onCameraIdle(
24
+ view: LuggMapView,
25
+ latitude: Double,
26
+ longitude: Double,
27
+ zoom: Float,
28
+ gesture: Boolean
29
+ )
30
+ fun onReady(view: LuggMapView)
31
+ }
32
+
33
+ @SuppressLint("ViewConstructor")
34
+ class LuggMapView(private val reactContext: ThemedReactContext) :
35
+ ReactViewGroup(reactContext),
36
+ MapProviderDelegate {
37
+
38
+ var eventDelegate: LuggMapViewEventDelegate? = null
39
+ private var provider: MapProvider? = null
40
+ private var mapWrapperView: LuggMapWrapperView? = null
41
+
42
+ // Cached props (applied during initializeProvider)
43
+ private var mapId: String = GoogleMapProvider.DEMO_MAP_ID
44
+ private var initialLatitude: Double = 37.78
45
+ private var initialLongitude: Double = -122.43
46
+ private var initialZoom: Float = 14f
47
+ private var theme: String = "system"
48
+ private var zoomEnabled: Boolean = true
49
+ private var scrollEnabled: Boolean = true
50
+ private var rotateEnabled: Boolean = true
51
+ private var pitchEnabled: Boolean = true
52
+ private var userLocationEnabled: Boolean = false
53
+ private var minZoom: Double? = null
54
+ private var maxZoom: Double? = null
55
+ private var padding: EdgeInsets = EdgeInsets()
56
+
57
+ // region View Lifecycle
58
+
59
+ override fun addView(child: View?, index: Int) {
60
+ super.addView(child, index)
61
+ when (child) {
62
+ is LuggMapWrapperView -> mapWrapperView = child
63
+ is LuggMarkerView -> provider?.addMarkerView(child)
64
+ is LuggPolylineView -> provider?.addPolylineView(child)
65
+ }
66
+ }
67
+
68
+ override fun removeViewAt(index: Int) {
69
+ val view = getChildAt(index)
70
+ when (view) {
71
+ is LuggMarkerView -> provider?.removeMarkerView(view)
72
+ is LuggPolylineView -> provider?.removePolylineView(view)
73
+ }
74
+ super.removeViewAt(index)
75
+ }
76
+
77
+ override fun onAttachedToWindow() {
78
+ super.onAttachedToWindow()
79
+ if (provider == null && mapWrapperView != null) {
80
+ initializeProvider()
81
+ }
82
+ }
83
+
84
+ override fun onWindowVisibilityChanged(visibility: Int) {
85
+ super.onWindowVisibilityChanged(visibility)
86
+ if (visibility == VISIBLE) {
87
+ provider?.resumeAnimations()
88
+ } else {
89
+ provider?.pauseAnimations()
90
+ }
91
+ }
92
+
93
+ fun onDropViewInstance() {
94
+ provider?.destroy()
95
+ provider = null
96
+ mapWrapperView = null
97
+ }
98
+
99
+ // endregion
100
+
101
+ // region Provider Initialization
102
+
103
+ private fun initializeProvider() {
104
+ if (provider != null || mapWrapperView == null) return
105
+
106
+ val google = GoogleMapProvider(context)
107
+ google.mapId = mapId
108
+ google.delegate = this
109
+ provider = google
110
+
111
+ applyProps()
112
+
113
+ google.initializeMap(mapWrapperView!!, initialLatitude, initialLongitude, initialZoom)
114
+
115
+ // Flush children mounted before provider was created
116
+ for (i in 0 until childCount) {
117
+ when (val child = getChildAt(i)) {
118
+ is LuggMarkerView -> google.addMarkerView(child)
119
+ is LuggPolylineView -> google.addPolylineView(child)
120
+ }
121
+ }
122
+ }
123
+
124
+ // endregion
125
+
126
+ // region MapProviderDelegate
127
+
128
+ override fun mapProviderDidReady() {
129
+ eventDelegate?.onReady(this)
130
+ }
131
+
132
+ override fun mapProviderDidMoveCamera(latitude: Double, longitude: Double, zoom: Float, gesture: Boolean) {
133
+ eventDelegate?.onCameraMove(this, latitude, longitude, zoom, gesture)
134
+ }
135
+
136
+ override fun mapProviderDidIdleCamera(latitude: Double, longitude: Double, zoom: Float, gesture: Boolean) {
137
+ eventDelegate?.onCameraIdle(this, latitude, longitude, zoom, gesture)
138
+ }
139
+
140
+ // endregion
141
+
142
+ // region Property Setters
143
+
144
+ private fun applyProps() {
145
+ provider?.setZoomEnabled(zoomEnabled)
146
+ provider?.setScrollEnabled(scrollEnabled)
147
+ provider?.setRotateEnabled(rotateEnabled)
148
+ provider?.setPitchEnabled(pitchEnabled)
149
+ provider?.setUserLocationEnabled(userLocationEnabled)
150
+ provider?.setTheme(theme)
151
+ minZoom?.let { provider?.setMinZoom(it) }
152
+ maxZoom?.let { provider?.setMaxZoom(it) }
153
+ provider?.setPadding(padding)
154
+ }
155
+
156
+ fun setProvider(value: String?) {
157
+ if (value != null && value != "google") {
158
+ RNLog.w(reactContext, "LuggMapView: Only Google Maps is supported on Android")
159
+ }
160
+ }
161
+
162
+ fun setMapId(value: String?) {
163
+ if (value.isNullOrEmpty()) return
164
+ mapId = value
165
+ }
166
+
167
+ fun setInitialCoordinate(latitude: Double, longitude: Double) {
168
+ initialLatitude = latitude
169
+ initialLongitude = longitude
170
+ }
171
+
172
+ fun setInitialZoom(zoom: Double) {
173
+ initialZoom = zoom.toFloat()
174
+ }
175
+
176
+ fun setZoomEnabled(enabled: Boolean) {
177
+ zoomEnabled = enabled
178
+ provider?.setZoomEnabled(enabled)
179
+ }
180
+
181
+ fun setScrollEnabled(enabled: Boolean) {
182
+ scrollEnabled = enabled
183
+ provider?.setScrollEnabled(enabled)
184
+ }
185
+
186
+ fun setRotateEnabled(enabled: Boolean) {
187
+ rotateEnabled = enabled
188
+ provider?.setRotateEnabled(enabled)
189
+ }
190
+
191
+ fun setPitchEnabled(enabled: Boolean) {
192
+ pitchEnabled = enabled
193
+ provider?.setPitchEnabled(enabled)
194
+ }
195
+
196
+ fun setUserLocationEnabled(enabled: Boolean) {
197
+ userLocationEnabled = enabled
198
+ provider?.setUserLocationEnabled(enabled)
199
+ }
200
+
201
+ fun setMinZoom(zoom: Double) {
202
+ minZoom = zoom
203
+ provider?.setMinZoom(zoom)
204
+ }
205
+
206
+ fun setMaxZoom(zoom: Double) {
207
+ maxZoom = zoom
208
+ provider?.setMaxZoom(zoom)
209
+ }
210
+
211
+ fun setTheme(value: String) {
212
+ theme = value
213
+ provider?.setTheme(value)
214
+ }
215
+
216
+ fun setPadding(top: Int, left: Int, bottom: Int, right: Int) {
217
+ padding = EdgeInsets(top, left, bottom, right)
218
+ provider?.setPadding(padding)
219
+ }
220
+
221
+ // endregion
222
+
223
+ // region Commands
224
+
225
+ fun moveCamera(latitude: Double, longitude: Double, zoom: Double, duration: Int) {
226
+ provider?.moveCamera(latitude, longitude, zoom, duration)
227
+ }
228
+
229
+ fun fitCoordinates(
230
+ coordinates: List<LatLng>,
231
+ paddingTop: Int,
232
+ paddingLeft: Int,
233
+ paddingBottom: Int,
234
+ paddingRight: Int,
235
+ duration: Int
236
+ ) {
237
+ provider?.fitCoordinates(coordinates, paddingTop, paddingLeft, paddingBottom, paddingRight, duration)
238
+ }
239
+
240
+ // endregion
241
+ }
@@ -8,27 +8,27 @@ import com.facebook.react.uimanager.ThemedReactContext
8
8
  import com.facebook.react.uimanager.ViewGroupManager
9
9
  import com.facebook.react.uimanager.ViewManagerDelegate
10
10
  import com.facebook.react.uimanager.annotations.ReactProp
11
- import com.facebook.react.viewmanagers.LuggGoogleMapViewManagerDelegate
12
- import com.facebook.react.viewmanagers.LuggGoogleMapViewManagerInterface
11
+ import com.facebook.react.viewmanagers.LuggMapViewManagerDelegate
12
+ import com.facebook.react.viewmanagers.LuggMapViewManagerInterface
13
13
  import com.google.android.gms.maps.model.LatLng
14
14
  import com.luggmaps.events.CameraIdleEvent
15
15
  import com.luggmaps.events.CameraMoveEvent
16
16
  import com.luggmaps.events.ReadyEvent
17
17
  import com.luggmaps.extensions.dispatchEvent
18
18
 
19
- @ReactModule(name = LuggGoogleMapViewManager.NAME)
20
- class LuggGoogleMapViewManager :
21
- ViewGroupManager<LuggGoogleMapView>(),
22
- LuggGoogleMapViewManagerInterface<LuggGoogleMapView>,
23
- LuggGoogleMapViewEventDelegate {
24
- private val delegate: ViewManagerDelegate<LuggGoogleMapView> = LuggGoogleMapViewManagerDelegate(this)
19
+ @ReactModule(name = LuggMapViewManager.NAME)
20
+ class LuggMapViewManager :
21
+ ViewGroupManager<LuggMapView>(),
22
+ LuggMapViewManagerInterface<LuggMapView>,
23
+ LuggMapViewEventDelegate {
24
+ private val delegate: ViewManagerDelegate<LuggMapView> = LuggMapViewManagerDelegate(this)
25
25
 
26
- override fun getDelegate(): ViewManagerDelegate<LuggGoogleMapView> = delegate
26
+ override fun getDelegate(): ViewManagerDelegate<LuggMapView> = delegate
27
27
 
28
28
  override fun getName(): String = NAME
29
29
 
30
- override fun createViewInstance(context: ThemedReactContext): LuggGoogleMapView {
31
- val view = LuggGoogleMapView(context)
30
+ override fun createViewInstance(context: ThemedReactContext): LuggMapView {
31
+ val view = LuggMapView(context)
32
32
  view.eventDelegate = this
33
33
  return view
34
34
  }
@@ -41,7 +41,7 @@ class LuggGoogleMapViewManager :
41
41
  )
42
42
 
43
43
  override fun onCameraMove(
44
- view: LuggGoogleMapView,
44
+ view: LuggMapView,
45
45
  latitude: Double,
46
46
  longitude: Double,
47
47
  zoom: Float,
@@ -51,7 +51,7 @@ class LuggGoogleMapViewManager :
51
51
  }
52
52
 
53
53
  override fun onCameraIdle(
54
- view: LuggGoogleMapView,
54
+ view: LuggMapView,
55
55
  latitude: Double,
56
56
  longitude: Double,
57
57
  zoom: Float,
@@ -60,17 +60,22 @@ class LuggGoogleMapViewManager :
60
60
  view.dispatchEvent(CameraIdleEvent(view, latitude, longitude, zoom, gesture))
61
61
  }
62
62
 
63
- override fun onReady(view: LuggGoogleMapView) {
63
+ override fun onReady(view: LuggMapView) {
64
64
  view.dispatchEvent(ReadyEvent(view))
65
65
  }
66
66
 
67
+ @ReactProp(name = "provider")
68
+ override fun setProvider(view: LuggMapView, value: String?) {
69
+ view.setProvider(value)
70
+ }
71
+
67
72
  @ReactProp(name = "mapId")
68
- override fun setMapId(view: LuggGoogleMapView, value: String?) {
73
+ override fun setMapId(view: LuggMapView, value: String?) {
69
74
  view.setMapId(value)
70
75
  }
71
76
 
72
77
  @ReactProp(name = "initialCoordinate")
73
- override fun setInitialCoordinate(view: LuggGoogleMapView, value: ReadableMap?) {
78
+ override fun setInitialCoordinate(view: LuggMapView, value: ReadableMap?) {
74
79
  value?.let {
75
80
  val latitude = if (it.hasKey("latitude")) it.getDouble("latitude") else 0.0
76
81
  val longitude = if (it.hasKey("longitude")) it.getDouble("longitude") else 0.0
@@ -79,68 +84,68 @@ class LuggGoogleMapViewManager :
79
84
  }
80
85
 
81
86
  @ReactProp(name = "initialZoom", defaultDouble = 10.0)
82
- override fun setInitialZoom(view: LuggGoogleMapView, value: Double) {
87
+ override fun setInitialZoom(view: LuggMapView, value: Double) {
83
88
  view.setInitialZoom(value)
84
89
  }
85
90
 
86
91
  @ReactProp(name = "zoomEnabled", defaultBoolean = true)
87
- override fun setZoomEnabled(view: LuggGoogleMapView, value: Boolean) {
92
+ override fun setZoomEnabled(view: LuggMapView, value: Boolean) {
88
93
  view.setZoomEnabled(value)
89
94
  }
90
95
 
91
96
  @ReactProp(name = "scrollEnabled", defaultBoolean = true)
92
- override fun setScrollEnabled(view: LuggGoogleMapView, value: Boolean) {
97
+ override fun setScrollEnabled(view: LuggMapView, value: Boolean) {
93
98
  view.setScrollEnabled(value)
94
99
  }
95
100
 
96
101
  @ReactProp(name = "rotateEnabled", defaultBoolean = true)
97
- override fun setRotateEnabled(view: LuggGoogleMapView, value: Boolean) {
102
+ override fun setRotateEnabled(view: LuggMapView, value: Boolean) {
98
103
  view.setRotateEnabled(value)
99
104
  }
100
105
 
101
106
  @ReactProp(name = "pitchEnabled", defaultBoolean = true)
102
- override fun setPitchEnabled(view: LuggGoogleMapView, value: Boolean) {
107
+ override fun setPitchEnabled(view: LuggMapView, value: Boolean) {
103
108
  view.setPitchEnabled(value)
104
109
  }
105
110
 
106
111
  @ReactProp(name = "userLocationEnabled", defaultBoolean = false)
107
- override fun setUserLocationEnabled(view: LuggGoogleMapView, value: Boolean) {
112
+ override fun setUserLocationEnabled(view: LuggMapView, value: Boolean) {
108
113
  view.setUserLocationEnabled(value)
109
114
  }
110
115
 
111
116
  @ReactProp(name = "minZoom")
112
- override fun setMinZoom(view: LuggGoogleMapView, value: Double) {
117
+ override fun setMinZoom(view: LuggMapView, value: Double) {
113
118
  view.setMinZoom(value)
114
119
  }
115
120
 
116
121
  @ReactProp(name = "maxZoom")
117
- override fun setMaxZoom(view: LuggGoogleMapView, value: Double) {
122
+ override fun setMaxZoom(view: LuggMapView, value: Double) {
118
123
  view.setMaxZoom(value)
119
124
  }
120
125
 
121
126
  @ReactProp(name = "theme")
122
- override fun setTheme(view: LuggGoogleMapView, value: String?) {
127
+ override fun setTheme(view: LuggMapView, value: String?) {
123
128
  view.setTheme(value ?: "system")
124
129
  }
125
130
 
126
131
  @ReactProp(name = "padding")
127
- override fun setPadding(view: LuggGoogleMapView, value: ReadableMap?) {
132
+ override fun setPadding(view: LuggMapView, value: ReadableMap?) {
128
133
  value?.let {
129
134
  val top = if (it.hasKey("top")) it.getDouble("top").toFloat().dpToPx().toInt() else 0
130
135
  val left = if (it.hasKey("left")) it.getDouble("left").toFloat().dpToPx().toInt() else 0
131
136
  val bottom = if (it.hasKey("bottom")) it.getDouble("bottom").toFloat().dpToPx().toInt() else 0
132
137
  val right = if (it.hasKey("right")) it.getDouble("right").toFloat().dpToPx().toInt() else 0
133
- view.setMapPadding(top, left, bottom, right)
138
+ view.setPadding(top, left, bottom, right)
134
139
  }
135
140
  }
136
141
 
137
- override fun onDropViewInstance(view: LuggGoogleMapView) {
142
+ override fun onDropViewInstance(view: LuggMapView) {
138
143
  super.onDropViewInstance(view)
139
144
  view.onDropViewInstance()
140
145
  }
141
146
 
142
147
  override fun moveCamera(
143
- view: LuggGoogleMapView,
148
+ view: LuggMapView,
144
149
  latitude: Double,
145
150
  longitude: Double,
146
151
  zoom: Double,
@@ -150,7 +155,7 @@ class LuggGoogleMapViewManager :
150
155
  }
151
156
 
152
157
  override fun fitCoordinates(
153
- view: LuggGoogleMapView,
158
+ view: LuggMapView,
154
159
  coordinates: ReadableArray?,
155
160
  paddingTop: Double,
156
161
  paddingLeft: Double,
@@ -171,6 +176,6 @@ class LuggGoogleMapViewManager :
171
176
  }
172
177
 
173
178
  companion object {
174
- const val NAME = "LuggGoogleMapView"
179
+ const val NAME = "LuggMapView"
175
180
  }
176
181
  }
@@ -1,13 +1,10 @@
1
1
  package com.luggmaps
2
2
 
3
3
  import com.facebook.react.ReactPackage
4
- import com.facebook.react.bridge.NativeModule
5
4
  import com.facebook.react.bridge.ReactApplicationContext
6
5
  import com.facebook.react.uimanager.ViewManager
7
6
 
8
7
  class LuggPackage : ReactPackage {
9
8
  override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> =
10
- listOf(LuggGoogleMapViewManager(), LuggMarkerViewManager(), LuggMapWrapperViewManager(), LuggPolylineViewManager())
11
-
12
- override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> = emptyList()
9
+ listOf(LuggMapViewManager(), LuggMarkerViewManager(), LuggMapWrapperViewManager(), LuggPolylineViewManager())
13
10
  }