@rnmapbox/maps 10.3.2-rc.1 → 10.3.2

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 (35) hide show
  1. package/android/src/main/java/com/rnmapbox/rnmbx/RNMBXPackage.kt +2 -0
  2. package/android/src/main/java/com/rnmapbox/rnmbx/components/annotation/RNMBXMarkerView.kt +0 -2
  3. package/android/src/main/java/com/rnmapbox/rnmbx/components/annotation/RNMBXPointAnnotation.kt +6 -2
  4. package/android/src/main/java/com/rnmapbox/rnmbx/components/annotation/RNMBXPointAnnotationCoordinator.kt +10 -2
  5. package/android/src/main/java/com/rnmapbox/rnmbx/components/annotation/RNMBXPointAnnotationManagerView.kt +143 -0
  6. package/android/src/main/java/com/rnmapbox/rnmbx/components/annotation/RNMBXPointAnnotationManagerViewManager.kt +105 -0
  7. package/android/src/main/java/com/rnmapbox/rnmbx/components/mapview/RNMBXMapView.kt +33 -7
  8. package/ios/RNMBX/RNMBXMapView.swift +69 -7
  9. package/ios/RNMBX/RNMBXPointAnnotation.swift +11 -5
  10. package/ios/RNMBX/RNMBXPointAnnotationManagerComponentView.h +15 -0
  11. package/ios/RNMBX/RNMBXPointAnnotationManagerComponentView.mm +98 -0
  12. package/ios/RNMBX/RNMBXPointAnnotationManagerComponentView.swift +130 -0
  13. package/ios/RNMBX/rnmapbox_maps-Swift.pre.h +1 -1
  14. package/lib/module/Mapbox.native.js +1 -0
  15. package/lib/module/Mapbox.native.js.map +1 -1
  16. package/lib/module/components/PointAnnotationManager.js +37 -0
  17. package/lib/module/components/PointAnnotationManager.js.map +1 -0
  18. package/lib/module/components/StyleImport.js +9 -1
  19. package/lib/module/components/StyleImport.js.map +1 -1
  20. package/lib/module/specs/RNMBXPointAnnotationManagerNativeComponent.ts +28 -0
  21. package/lib/typescript/scripts/autogenHelpers/DocJSONBuilder.d.mts.map +1 -1
  22. package/lib/typescript/src/Mapbox.native.d.ts +2 -0
  23. package/lib/typescript/src/Mapbox.native.d.ts.map +1 -1
  24. package/lib/typescript/src/components/PointAnnotationManager.d.ts +59 -0
  25. package/lib/typescript/src/components/PointAnnotationManager.d.ts.map +1 -0
  26. package/lib/typescript/src/components/StyleImport.d.ts +63 -3
  27. package/lib/typescript/src/components/StyleImport.d.ts.map +1 -1
  28. package/lib/typescript/src/specs/RNMBXPointAnnotationManagerNativeComponent.d.ts +20 -0
  29. package/lib/typescript/src/specs/RNMBXPointAnnotationManagerNativeComponent.d.ts.map +1 -0
  30. package/package.json +6 -2
  31. package/rnmapbox-maps.podspec +12 -3
  32. package/src/Mapbox.native.ts +2 -0
  33. package/src/components/PointAnnotationManager.tsx +97 -0
  34. package/src/components/StyleImport.tsx +71 -4
  35. package/src/specs/RNMBXPointAnnotationManagerNativeComponent.ts +28 -0
@@ -11,6 +11,7 @@ import com.rnmapbox.rnmbx.components.annotation.RNMBXCalloutManager
11
11
  import com.rnmapbox.rnmbx.components.annotation.RNMBXMarkerViewContentManager
12
12
  import com.rnmapbox.rnmbx.components.annotation.RNMBXMarkerViewManager
13
13
  import com.rnmapbox.rnmbx.components.annotation.RNMBXPointAnnotationManager
14
+ import com.rnmapbox.rnmbx.components.annotation.RNMBXPointAnnotationManagerViewManager
14
15
  import com.rnmapbox.rnmbx.components.annotation.RNMBXPointAnnotationModule
15
16
  import com.rnmapbox.rnmbx.components.camera.RNMBXCameraManager
16
17
  import com.rnmapbox.rnmbx.components.camera.RNMBXCameraModule
@@ -135,6 +136,7 @@ class RNMBXPackage : TurboReactPackage() {
135
136
  managers.add(RNMBXMarkerViewManager(reactApplicationContext))
136
137
  managers.add(RNMBXMarkerViewContentManager(reactApplicationContext))
137
138
  managers.add(RNMBXPointAnnotationManager(reactApplicationContext, getViewTagResolver(reactApplicationContext, "RNMBXPointAnnotationManager")))
139
+ managers.add(RNMBXPointAnnotationManagerViewManager(reactApplicationContext))
138
140
  managers.add(RNMBXCalloutManager())
139
141
  managers.add(RNMBXNativeUserLocationManager())
140
142
  managers.add(RNMBXCustomLocationProviderManager())
@@ -129,8 +129,6 @@ class RNMBXMarkerView(context: Context?, private val mManager: RNMBXMarkerViewMa
129
129
  }
130
130
 
131
131
  if (view.width == 0 || view.height == 0) {
132
- // Fixes https://github.com/rnmapbox/maps/issues/4206
133
- // Wait for the next layout via onLayoutChange
134
132
  return
135
133
  }
136
134
 
@@ -27,6 +27,9 @@ import com.rnmapbox.rnmbx.v11compat.annotation.*;
27
27
  class RNMBXPointAnnotation(private val mContext: Context, private val mManager: RNMBXPointAnnotationManager) : AbstractMapFeature(mContext), View.OnLayoutChangeListener {
28
28
 
29
29
  var pointAnnotations: RNMBXPointAnnotationCoordinator? = null
30
+
31
+ var parentCoordinator: RNMBXPointAnnotationCoordinator? = null
32
+
30
33
  var annotation: PointAnnotation? = null
31
34
  private set
32
35
  private var mMap: MapboxMap? = null
@@ -97,7 +100,7 @@ class RNMBXPointAnnotation(private val mContext: Context, private val mManager:
97
100
  override fun addToMap(mapView: RNMBXMapView) {
98
101
  super.addToMap(mapView)
99
102
  mMap = mapView.getMapboxMap()
100
- pointAnnotations = mapView.pointAnnotations
103
+ pointAnnotations = parentCoordinator ?: mapView.pointAnnotations
101
104
  makeMarker()
102
105
  if (mChildView != null) {
103
106
  if (!mChildView!!.isAttachedToWindow) {
@@ -117,7 +120,8 @@ class RNMBXPointAnnotation(private val mContext: Context, private val mManager:
117
120
  override fun removeFromMap(mapView: RNMBXMapView, reason: RemovalReason): Boolean {
118
121
  val map = mMapView ?: mapView
119
122
 
120
- annotation?.let { map.pointAnnotations?.delete(it) }
123
+ val coordinator = pointAnnotations ?: map.pointAnnotations
124
+ annotation?.let { coordinator.delete(it) }
121
125
 
122
126
  mChildView?.let { map.offscreenAnnotationViewContainer?.removeView(it) }
123
127
  calloutView?.let { map.offscreenAnnotationViewContainer?.removeView(it)}
@@ -13,7 +13,7 @@ import com.mapbox.maps.plugin.annotation.generated.createPointAnnotationManager
13
13
  import com.rnmapbox.rnmbx.components.annotation.RNMBXPointAnnotation
14
14
  import com.rnmapbox.rnmbx.utils.Logger
15
15
 
16
- class RNMBXPointAnnotationCoordinator(val mapView: MapView) {
16
+ class RNMBXPointAnnotationCoordinator(val mapView: MapView, layerId: String? = "RNMBX-mapview-annotations") {
17
17
  val manager: PointAnnotationManager;
18
18
  var annotationClicked = false
19
19
  var annotationDragged = false
@@ -24,7 +24,11 @@ class RNMBXPointAnnotationCoordinator(val mapView: MapView) {
24
24
  val callouts: MutableMap<String, RNMBXPointAnnotation> = hashMapOf()
25
25
 
26
26
  init {
27
- manager = mapView.annotations.createPointAnnotationManager(AnnotationConfig(layerId = "RNMBX-mapview-annotations"))
27
+ manager = if (layerId != null) {
28
+ mapView.annotations.createPointAnnotationManager(AnnotationConfig(layerId = layerId))
29
+ } else {
30
+ mapView.annotations.createPointAnnotationManager()
31
+ }
28
32
  manager.addClickListener(OnPointAnnotationClickListener { pointAnnotation ->
29
33
  onAnnotationClick(pointAnnotation)
30
34
  false
@@ -161,6 +165,10 @@ class RNMBXPointAnnotationCoordinator(val mapView: MapView) {
161
165
  annotations[annotation.iD!!] = annotation
162
166
  }
163
167
 
168
+ fun destroy() {
169
+ mapView.annotations.removeAnnotationManager(manager)
170
+ }
171
+
164
172
  companion object {
165
173
  const val LOG_TAG = "RNMBXPointAnnotationCoordinator";
166
174
  }
@@ -0,0 +1,143 @@
1
+ package com.rnmapbox.rnmbx.components.annotation
2
+
3
+ import android.content.Context
4
+ import android.view.View
5
+ import com.rnmapbox.rnmbx.components.AbstractMapFeature
6
+ import com.rnmapbox.rnmbx.components.RemovalReason
7
+ import com.rnmapbox.rnmbx.components.mapview.RNMBXMapView
8
+ import com.rnmapbox.rnmbx.utils.Logger
9
+
10
+ class RNMBXPointAnnotationManagerView(context: Context) : AbstractMapFeature(context) {
11
+ var reactId: String? = null
12
+ var isDefault: Boolean = false
13
+
14
+ var slot: String? = null
15
+ set(value) { field = value; applyProps() }
16
+ var iconAllowOverlap: Boolean? = null
17
+ set(value) { field = value; applyProps() }
18
+ var iconIgnorePlacement: Boolean? = null
19
+ set(value) { field = value; applyProps() }
20
+ var iconOptional: Boolean? = null
21
+ set(value) { field = value; applyProps() }
22
+ var textAllowOverlap: Boolean? = null
23
+ set(value) { field = value; applyProps() }
24
+ var textIgnorePlacement: Boolean? = null
25
+ set(value) { field = value; applyProps() }
26
+ var textOptional: Boolean? = null
27
+ set(value) { field = value; applyProps() }
28
+
29
+ private val annotations = mutableListOf<RNMBXPointAnnotation>()
30
+ private var coordinator: RNMBXPointAnnotationCoordinator? = null
31
+
32
+ fun addAnnotation(childView: View, childPosition: Int) {
33
+ if (childView !is RNMBXPointAnnotation) {
34
+ Logger.w(LOG_TAG, "PointAnnotationManager: only PointAnnotation children are supported")
35
+ return
36
+ }
37
+ annotations.add(childPosition, childView)
38
+ val mapView = mMapView
39
+ if (mapView != null) {
40
+ ensureCoordinator(mapView)
41
+ attachAnnotation(childView, mapView)
42
+ }
43
+ }
44
+
45
+ fun removeAnnotationAt(childPosition: Int) {
46
+ val childView = annotations.removeAt(childPosition)
47
+ val mapView = mMapView
48
+ if (mapView != null) {
49
+ coordinator?.remove(childView)
50
+ childView.removeFromMap(mapView, RemovalReason.VIEW_REMOVAL)
51
+ }
52
+ childView.parentCoordinator = null
53
+ }
54
+
55
+ override fun getChildAt(childPosition: Int): View {
56
+ return annotations[childPosition]
57
+ }
58
+
59
+ override fun getChildCount(): Int {
60
+ return annotations.size
61
+ }
62
+
63
+ private fun attachAnnotation(annotation: RNMBXPointAnnotation, mapView: RNMBXMapView) {
64
+ val coordinator = coordinator ?: return
65
+ annotation.parentCoordinator = coordinator
66
+ coordinator.add(annotation)
67
+ annotation.addToMap(mapView)
68
+ }
69
+
70
+ private fun ensureCoordinator(mapView: RNMBXMapView) {
71
+ if (coordinator != null) return
72
+ coordinator = if (isDefault) {
73
+ val existing = mapView.defaultPointAnnotationManagerView
74
+ if (existing != null && existing !== this) {
75
+ Logger.w(LOG_TAG, "PointAnnotationManager: multiple default managers declared, ignoring extra default")
76
+ } else {
77
+ mapView.defaultPointAnnotationManagerView = this
78
+ }
79
+ mapView.pointAnnotations
80
+ } else {
81
+ val c = RNMBXPointAnnotationCoordinator(mapView.mapView, reactId)
82
+ mapView.registerPointAnnotationCoordinator(c)
83
+ c
84
+ }
85
+ applyProps()
86
+ }
87
+
88
+ override fun addToMap(mapView: RNMBXMapView) {
89
+ super.addToMap(mapView)
90
+ ensureCoordinator(mapView)
91
+ for (annotation in annotations) {
92
+ attachAnnotation(annotation, mapView)
93
+ }
94
+ }
95
+
96
+ override fun removeFromMap(mapView: RNMBXMapView, reason: RemovalReason): Boolean {
97
+ for (annotation in annotations) {
98
+ coordinator?.remove(annotation)
99
+ annotation.removeFromMap(mapView, reason)
100
+ annotation.parentCoordinator = null
101
+ }
102
+ coordinator?.let { c ->
103
+ if (isDefault) {
104
+ // The default coordinator is shared with bare annotations; leave it in
105
+ // place, just clear the configuration this view applied.
106
+ c.manager.slot = null
107
+ c.manager.iconAllowOverlap = null
108
+ c.manager.iconIgnorePlacement = null
109
+ c.manager.iconOptional = null
110
+ c.manager.textAllowOverlap = null
111
+ c.manager.textIgnorePlacement = null
112
+ c.manager.textOptional = null
113
+ } else {
114
+ mapView.unregisterPointAnnotationCoordinator(c)
115
+ c.destroy()
116
+ }
117
+ }
118
+ if (mapView.defaultPointAnnotationManagerView === this) {
119
+ mapView.defaultPointAnnotationManagerView = null
120
+ }
121
+ coordinator = null
122
+ return super.removeFromMap(mapView, reason)
123
+ }
124
+
125
+ private fun applyProps() {
126
+ val manager = coordinator?.manager ?: return
127
+ manager.slot = slot
128
+ // Only write when the prop is set. The annotation plugin defaults
129
+ // iconAllowOverlap/iconIgnorePlacement to true so annotations always show;
130
+ // writing null here would clobber that back to the style default (false) and
131
+ // cull colliding pins.
132
+ iconAllowOverlap?.let { manager.iconAllowOverlap = it }
133
+ iconIgnorePlacement?.let { manager.iconIgnorePlacement = it }
134
+ iconOptional?.let { manager.iconOptional = it }
135
+ textAllowOverlap?.let { manager.textAllowOverlap = it }
136
+ textIgnorePlacement?.let { manager.textIgnorePlacement = it }
137
+ textOptional?.let { manager.textOptional = it }
138
+ }
139
+
140
+ companion object {
141
+ const val LOG_TAG = "RNMBXPointAnnotationManagerView"
142
+ }
143
+ }
@@ -0,0 +1,105 @@
1
+ package com.rnmapbox.rnmbx.components.annotation
2
+
3
+ import android.view.View
4
+ import com.facebook.react.bridge.Dynamic
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.bridge.ReadableType
7
+ import com.facebook.react.common.MapBuilder
8
+ import com.facebook.react.uimanager.ThemedReactContext
9
+ import com.facebook.react.uimanager.ViewManagerDelegate
10
+ import com.facebook.react.uimanager.annotations.ReactProp
11
+ import com.facebook.react.viewmanagers.RNMBXPointAnnotationManagerManagerDelegate
12
+ import com.facebook.react.viewmanagers.RNMBXPointAnnotationManagerManagerInterface
13
+ import com.rnmapbox.rnmbx.components.AbstractEventEmitter
14
+
15
+ class RNMBXPointAnnotationManagerViewManager(context: ReactApplicationContext) :
16
+ AbstractEventEmitter<RNMBXPointAnnotationManagerView>(context),
17
+ RNMBXPointAnnotationManagerManagerInterface<RNMBXPointAnnotationManagerView> {
18
+ private val mDelegate: ViewManagerDelegate<RNMBXPointAnnotationManagerView> =
19
+ RNMBXPointAnnotationManagerManagerDelegate(this)
20
+
21
+ override fun getDelegate(): ViewManagerDelegate<RNMBXPointAnnotationManagerView> {
22
+ return mDelegate
23
+ }
24
+
25
+ override fun customEvents(): Map<String, String>? {
26
+ return MapBuilder.builder<String, String>().build()
27
+ }
28
+
29
+ override fun getName(): String {
30
+ return REACT_CLASS
31
+ }
32
+
33
+ override fun createViewInstance(context: ThemedReactContext): RNMBXPointAnnotationManagerView {
34
+ return RNMBXPointAnnotationManagerView(context)
35
+ }
36
+
37
+ override fun addView(parent: RNMBXPointAnnotationManagerView, childView: View, childPosition: Int) {
38
+ parent.addAnnotation(childView, childPosition)
39
+ }
40
+
41
+ override fun removeViewAt(parent: RNMBXPointAnnotationManagerView, childPosition: Int) {
42
+ parent.removeAnnotationAt(childPosition)
43
+ }
44
+
45
+ override fun getChildAt(parent: RNMBXPointAnnotationManagerView, childPosition: Int): View {
46
+ return parent.getChildAt(childPosition)
47
+ }
48
+
49
+ override fun getChildCount(parent: RNMBXPointAnnotationManagerView): Int {
50
+ return parent.getChildCount()
51
+ }
52
+
53
+ private fun optBoolean(value: Dynamic): Boolean? {
54
+ return if (value.isNull || value.type != ReadableType.Boolean) null else value.asBoolean()
55
+ }
56
+
57
+ companion object {
58
+ const val REACT_CLASS = "RNMBXPointAnnotationManager"
59
+ }
60
+
61
+ @ReactProp(name = "id")
62
+ override fun setId(view: RNMBXPointAnnotationManagerView, value: Dynamic) {
63
+ view.reactId = if (value.isNull) null else value.asString()
64
+ }
65
+
66
+ @ReactProp(name = "isDefault")
67
+ override fun setIsDefault(view: RNMBXPointAnnotationManagerView, value: Dynamic) {
68
+ view.isDefault = !value.isNull && value.asBoolean()
69
+ }
70
+
71
+ @ReactProp(name = "slot")
72
+ override fun setSlot(view: RNMBXPointAnnotationManagerView, value: Dynamic) {
73
+ view.slot = if (value.isNull) null else value.asString()
74
+ }
75
+
76
+ @ReactProp(name = "iconAllowOverlap")
77
+ override fun setIconAllowOverlap(view: RNMBXPointAnnotationManagerView, value: Dynamic) {
78
+ view.iconAllowOverlap = optBoolean(value)
79
+ }
80
+
81
+ @ReactProp(name = "iconIgnorePlacement")
82
+ override fun setIconIgnorePlacement(view: RNMBXPointAnnotationManagerView, value: Dynamic) {
83
+ view.iconIgnorePlacement = optBoolean(value)
84
+ }
85
+
86
+ @ReactProp(name = "iconOptional")
87
+ override fun setIconOptional(view: RNMBXPointAnnotationManagerView, value: Dynamic) {
88
+ view.iconOptional = optBoolean(value)
89
+ }
90
+
91
+ @ReactProp(name = "textAllowOverlap")
92
+ override fun setTextAllowOverlap(view: RNMBXPointAnnotationManagerView, value: Dynamic) {
93
+ view.textAllowOverlap = optBoolean(value)
94
+ }
95
+
96
+ @ReactProp(name = "textIgnorePlacement")
97
+ override fun setTextIgnorePlacement(view: RNMBXPointAnnotationManagerView, value: Dynamic) {
98
+ view.textIgnorePlacement = optBoolean(value)
99
+ }
100
+
101
+ @ReactProp(name = "textOptional")
102
+ override fun setTextOptional(view: RNMBXPointAnnotationManagerView, value: Dynamic) {
103
+ view.textOptional = optBoolean(value)
104
+ }
105
+ }
@@ -61,6 +61,7 @@ import com.rnmapbox.rnmbx.utils.extensions.toReadableArray
61
61
  import java.util.*
62
62
 
63
63
  import com.rnmapbox.rnmbx.components.annotation.RNMBXPointAnnotationCoordinator
64
+ import com.rnmapbox.rnmbx.components.annotation.RNMBXPointAnnotationManagerView
64
65
  import com.rnmapbox.rnmbx.components.images.ImageManager
65
66
  import com.rnmapbox.rnmbx.utils.extensions.toStringKeyPairs
66
67
 
@@ -135,16 +136,35 @@ open class RNMBXMapView(private val mContext: Context, var mManager: RNMBXMapVie
135
136
 
136
137
  private val mSources: MutableMap<String, RNMBXSource<*>>
137
138
  private val mImages: MutableList<RNMBXImages>
138
- public val pointAnnotations: RNMBXPointAnnotationCoordinator by lazy {
139
+ val pointAnnotationCoordinators = mutableListOf<RNMBXPointAnnotationCoordinator>()
140
+ private var pointAnnotationGesturesInited = false
141
+
142
+ var defaultPointAnnotationManagerView: RNMBXPointAnnotationManagerView? = null
143
+
144
+ private fun ensurePointAnnotationGestures() {
145
+ if (pointAnnotationGesturesInited) return
139
146
  val gesturesPlugin: GesturesPlugin = mapView.gestures
140
147
  gesturesPlugin.removeOnMapClickListener(this)
141
148
  gesturesPlugin.removeOnMapLongClickListener(this)
142
-
143
- val result = RNMBXPointAnnotationCoordinator(mapView)
144
-
145
149
  gesturesPlugin.addOnMapClickListener(this)
146
150
  gesturesPlugin.addOnMapLongClickListener(this)
151
+ pointAnnotationGesturesInited = true
152
+ }
153
+
154
+ fun registerPointAnnotationCoordinator(coordinator: RNMBXPointAnnotationCoordinator) {
155
+ ensurePointAnnotationGestures()
156
+ if (!pointAnnotationCoordinators.contains(coordinator)) {
157
+ pointAnnotationCoordinators.add(coordinator)
158
+ }
159
+ }
160
+
161
+ fun unregisterPointAnnotationCoordinator(coordinator: RNMBXPointAnnotationCoordinator) {
162
+ pointAnnotationCoordinators.remove(coordinator)
163
+ }
147
164
 
165
+ public val pointAnnotations: RNMBXPointAnnotationCoordinator by lazy {
166
+ val result = RNMBXPointAnnotationCoordinator(mapView)
167
+ registerPointAnnotationCoordinator(result)
148
168
  result
149
169
  }
150
170
  private var mProjection: ProjectionName = ProjectionName.MERCATOR
@@ -690,11 +710,17 @@ open class RNMBXMapView(private val mContext: Context, var mManager: RNMBXMapVie
690
710
 
691
711
  override fun onMapClick(point: Point): Boolean {
692
712
  val _this = this
693
- if (pointAnnotations.getAndClearAnnotationClicked()) {
713
+ if (pointAnnotationCoordinators.any { it.getAndClearAnnotationClicked() }) {
694
714
  return true
695
715
  }
696
716
  if (deselectAnnotationOnTap) {
697
- if (pointAnnotations.deselectSelectedAnnotation()) {
717
+ var deselected = false
718
+ for (coordinator in pointAnnotationCoordinators) {
719
+ if (coordinator.deselectSelectedAnnotation()) {
720
+ deselected = true
721
+ }
722
+ }
723
+ if (deselected) {
698
724
  return true
699
725
  }
700
726
  }
@@ -728,7 +754,7 @@ open class RNMBXMapView(private val mContext: Context, var mManager: RNMBXMapVie
728
754
 
729
755
  override fun onMapLongClick(point: Point): Boolean {
730
756
  val _this = this
731
- if (pointAnnotations.getAndClearAnnotationDragged()) {
757
+ if (pointAnnotationCoordinators.any { it.getAndClearAnnotationDragged() }) {
732
758
  return true
733
759
  }
734
760
  val screenPointPx = mMap?.pixelForCoordinate(point)
@@ -229,12 +229,31 @@ open class RNMBXMapView: UIView, RCTInvalidating {
229
229
 
230
230
  var cancelables = Set<AnyCancelable>()
231
231
 
232
+ var pointAnnotationManagers: [RNMBXPointAnnotationManager] = []
233
+
234
+ weak var defaultPointAnnotationManagerView: RNMBXPointAnnotationManagerView? = nil
235
+
232
236
  lazy var pointAnnotationManager : RNMBXPointAnnotationManager = {
233
- let result = RNMBXPointAnnotationManager(annotations: mapView.annotations, mapView: mapView)
237
+ let result = RNMBXPointAnnotationManager(annotations: mapView.annotations, mapView: mapView, id: "RNMBX-mapview-point-annotations")
234
238
  self._removeMapboxLongPressGestureRecognizer()
239
+ self.registerPointAnnotationManager(result)
235
240
  return result
236
241
  }()
237
242
 
243
+ func registerPointAnnotationManager(_ manager: RNMBXPointAnnotationManager) {
244
+ if !pointAnnotationManagers.contains(where: { $0 === manager }) {
245
+ pointAnnotationManagers.append(manager)
246
+ }
247
+ // We handle taps ourselves; detach Mapbox's built-in tap target for this manager.
248
+ if let mapView = _mapView {
249
+ mapView.gestures.singleTapGestureRecognizer.removeTarget(manager.manager, action: nil)
250
+ }
251
+ }
252
+
253
+ func unregisterPointAnnotationManager(_ manager: RNMBXPointAnnotationManager) {
254
+ pointAnnotationManagers.removeAll { $0 === manager }
255
+ }
256
+
238
257
  lazy var calloutAnnotationManager : MapboxMaps.PointAnnotationManager = {
239
258
  let manager = mapView.annotations.makePointAnnotationManager(id: "RNMBX-mapview-callouts")
240
259
  manager.iconAllowOverlap = true
@@ -1284,7 +1303,10 @@ extension RNMBXMapView {
1284
1303
  func applyOnPress() {
1285
1304
  let singleTapGestureRecognizer = self.mapView.gestures.singleTapGestureRecognizer
1286
1305
 
1287
- singleTapGestureRecognizer.removeTarget(pointAnnotationManager.manager, action: nil)
1306
+ // Detach Mapbox's built-in tap target for every manager; we handle taps ourselves.
1307
+ for manager in pointAnnotationManagers {
1308
+ singleTapGestureRecognizer.removeTarget(manager.manager, action: nil)
1309
+ }
1288
1310
  singleTapGestureRecognizer.addTarget(self, action: #selector(doHandleTap(_:)))
1289
1311
 
1290
1312
  self.tapDelegate = IgnoreRNMBXMakerViewGestureDelegate(originalDelegate: singleTapGestureRecognizer.delegate)
@@ -1386,13 +1408,34 @@ extension RNMBXMapView: GestureManagerDelegate {
1386
1408
  return event
1387
1409
  }
1388
1410
 
1411
+ private func handleTapAcrossPointAnnotationManagers(_ sender: UITapGestureRecognizer, index: Int, noneFound: @escaping () -> Void) {
1412
+ if index >= pointAnnotationManagers.count {
1413
+ noneFound()
1414
+ return
1415
+ }
1416
+ pointAnnotationManagers[index].handleTap(sender) { _ in
1417
+ self.handleTapAcrossPointAnnotationManagers(sender, index: index + 1, noneFound: noneFound)
1418
+ }
1419
+ }
1420
+
1421
+ @discardableResult
1422
+ func deselectCurrentlySelectedPointAnnotation(deselectAnnotationOnTap: Bool) -> Bool {
1423
+ var any = false
1424
+ for manager in pointAnnotationManagers {
1425
+ if manager.deselectCurrentlySelected(deselectAnnotationOnTap: deselectAnnotationOnTap) {
1426
+ any = true
1427
+ }
1428
+ }
1429
+ return any
1430
+ }
1431
+
1389
1432
  @objc
1390
1433
  func doHandleTap(_ sender: UITapGestureRecognizer) {
1391
1434
  let tapPoint = sender.location(in: self)
1392
- pointAnnotationManager.handleTap(sender) { (_: UITapGestureRecognizer) in
1435
+ handleTapAcrossPointAnnotationManagers(sender, index: 0) {
1393
1436
  DispatchQueue.main.async {
1394
1437
  if (self.deselectAnnotationOnTap) {
1395
- if (self.pointAnnotationManager.deselectCurrentlySelected(deselectAnnotationOnTap: true)) {
1438
+ if (self.deselectCurrentlySelectedPointAnnotation(deselectAnnotationOnTap: true)) {
1396
1439
  return
1397
1440
  }
1398
1441
  }
@@ -1435,10 +1478,23 @@ extension RNMBXMapView: GestureManagerDelegate {
1435
1478
  }
1436
1479
  }
1437
1480
 
1481
+ private func handleLongPressAcrossPointAnnotationManagers(_ sender: UILongPressGestureRecognizer, index: Int, noneFound: @escaping () -> Void) {
1482
+ if index >= pointAnnotationManagers.count {
1483
+ noneFound()
1484
+ return
1485
+ }
1486
+ pointAnnotationManagers[index].handleLongPress(sender) { _ in
1487
+ self.handleLongPressAcrossPointAnnotationManagers(sender, index: index + 1, noneFound: noneFound)
1488
+ }
1489
+ }
1490
+
1438
1491
  @objc
1439
1492
  func doHandleLongPress(_ sender: UILongPressGestureRecognizer) {
1440
1493
  let position = sender.location(in: self)
1441
- pointAnnotationManager.handleLongPress(sender) { (_: UILongPressGestureRecognizer) in
1494
+ handleLongPressAcrossPointAnnotationManagers(sender, index: 0) {
1495
+ // Source-based drag handling only starts on `.began`; annotation drag
1496
+ // continuation (.changed/.ended) is consumed by the owning manager above.
1497
+ guard sender.state == .began else { return }
1442
1498
  DispatchQueue.main.async {
1443
1499
  let draggableSources = self.draggableSources()
1444
1500
  self.doHandleTapInSources(sources: draggableSources, tapPoint: position, hits: [:], touchedSources: []) { (hits, draggedSources) in
@@ -2026,8 +2082,12 @@ class RNMBXPointAnnotationManager : AnnotationInteractionDelegate {
2026
2082
  var manager : MapboxMaps.PointAnnotationManager
2027
2083
  weak var mapView : MapView? = nil
2028
2084
 
2029
- init(annotations: AnnotationOrchestrator, mapView: MapView) {
2030
- manager = annotations.makePointAnnotationManager(id: "RNMBX-mapview-point-annotations")
2085
+ init(annotations: AnnotationOrchestrator, mapView: MapView, id: String? = nil) {
2086
+ if let id = id {
2087
+ manager = annotations.makePointAnnotationManager(id: id)
2088
+ } else {
2089
+ manager = annotations.makePointAnnotationManager()
2090
+ }
2031
2091
  manager.delegate = self
2032
2092
  self.mapView = mapView
2033
2093
  }
@@ -2119,6 +2179,7 @@ class RNMBXPointAnnotationManager : AnnotationInteractionDelegate {
2119
2179
 
2120
2180
  case .changed:
2121
2181
  guard var annotation = self.draggedAnnotation else {
2182
+ noAnnotationFound(sender)
2122
2183
  return
2123
2184
  }
2124
2185
 
@@ -2130,6 +2191,7 @@ class RNMBXPointAnnotationManager : AnnotationInteractionDelegate {
2130
2191
  }
2131
2192
  case .cancelled, .ended:
2132
2193
  guard let annotation = self.draggedAnnotation else {
2194
+ noAnnotationFound(sender)
2133
2195
  return
2134
2196
  }
2135
2197
  // Optionally notify some other delegate to tell them the drag finished.
@@ -12,6 +12,12 @@ final class WeakRef<T: AnyObject> {
12
12
  public class RNMBXPointAnnotation : RNMBXInteractiveElement {
13
13
  weak var manager: RNMBXPointAnnotationManager? = nil
14
14
 
15
+ weak var ownerManager: RNMBXPointAnnotationManager? = nil
16
+
17
+ var resolvedManager: RNMBXPointAnnotationManager? {
18
+ return ownerManager ?? map?.pointAnnotationManager
19
+ }
20
+
15
21
  static let key = "RNMBXPointAnnotation"
16
22
  static var gid = 0;
17
23
 
@@ -293,28 +299,28 @@ public class RNMBXPointAnnotation : RNMBXInteractiveElement {
293
299
 
294
300
  extension RNMBXPointAnnotation {
295
301
  func removeIfAdded() {
296
- if added, let pointAnnotationManager = map?.pointAnnotationManager {
302
+ if added, let pointAnnotationManager = resolvedManager {
297
303
  pointAnnotationManager.remove(annotation)
298
304
  added = false
299
305
  }
300
306
  }
301
-
307
+
302
308
  @discardableResult
303
309
  func addIfPossible() -> Bool {
304
310
  if !added
305
311
  && annotation.point.coordinates.isValid()
306
312
  && (logged("PointAnnotation: missing id attribute") { return id }) != nil,
307
- let pointAnnotationManager = map?.pointAnnotationManager {
313
+ let pointAnnotationManager = resolvedManager {
308
314
  pointAnnotationManager.add(annotation, self)
309
315
  added = true
310
316
  return true
311
317
  }
312
318
  return false
313
319
  }
314
-
320
+
315
321
  func update(callback: (_ annotation: inout PointAnnotation) -> Void) {
316
322
  callback(&annotation)
317
- if let pointAnnotationManager = map?.pointAnnotationManager {
323
+ if let pointAnnotationManager = resolvedManager {
318
324
  if added {
319
325
  pointAnnotationManager.update(annotation)
320
326
  } else if !added {
@@ -0,0 +1,15 @@
1
+ #ifdef __cplusplus
2
+
3
+ #import <UIKit/UIKit.h>
4
+
5
+ #import <React/RCTUIManager.h>
6
+ #import <React/RCTViewComponentView.h>
7
+
8
+ NS_ASSUME_NONNULL_BEGIN
9
+
10
+ @interface RNMBXPointAnnotationManagerComponentView : RCTViewComponentView
11
+
12
+ @end
13
+
14
+ NS_ASSUME_NONNULL_END
15
+ #endif // __cplusplus