From ee84685f922b867059e57308c7980ff02bb586bd Mon Sep 17 00:00:00 2001 From: Kevin Dice Date: Thu, 2 Apr 2026 17:01:45 -0600 Subject: [PATCH 1/2] feat: add minPitch prop to MapView component --- .../rnmbx/components/mapview/RNMBXMapView.kt | 26 +++++++++++++++++- .../components/mapview/RNMBXMapViewManager.kt | 6 +++++ docs/MapView.md | 7 +++++ docs/docs.json | 7 +++++ ios/RNMBX/RNMBXMapView.swift | 27 +++++++++++++++++++ src/components/MapView.tsx | 5 ++++ src/specs/RNMBXMapViewNativeComponent.ts | 1 + 7 files changed, 78 insertions(+), 1 deletion(-) diff --git a/android/src/main/java/com/rnmapbox/rnmbx/components/mapview/RNMBXMapView.kt b/android/src/main/java/com/rnmapbox/rnmbx/components/mapview/RNMBXMapView.kt index 63ca76733..ba8004cdc 100644 --- a/android/src/main/java/com/rnmapbox/rnmbx/components/mapview/RNMBXMapView.kt +++ b/android/src/main/java/com/rnmapbox/rnmbx/components/mapview/RNMBXMapView.kt @@ -158,6 +158,7 @@ open class RNMBXMapView(private val mContext: Context, var mManager: RNMBXMapVie private val mCameraChangeTracker = CameraChangeTracker() private var mPreferredFrameRate: Int? = null private var mMaxPitch: Double? = null + private var mMinPitch: Double? = null private lateinit var mMap: MapboxMap private lateinit var mMapView: MapView @@ -512,7 +513,8 @@ open class RNMBXMapView(private val mContext: Context, var mManager: RNMBXMapVie LOGO(RNMBXMapView::applyLogo), SCALEBAR(RNMBXMapView::applyScaleBar), COMPASS(RNMBXMapView::applyCompass), - MAX_PITCH(RNMBXMapView::applyMaxPitch),; + MAX_PITCH(RNMBXMapView::applyMaxPitch), + MIN_PITCH(RNMBXMapView::applyMinPitch),; override fun apply(mapView: RNMBXMapView) { _apply(mapView) @@ -603,6 +605,28 @@ open class RNMBXMapView(private val mContext: Context, var mManager: RNMBXMapVie mMap.setBounds(builder.build()) } + fun setReactMinPitch(minPitch: Double?) { + mMinPitch = minPitch + changes.add(Property.MIN_PITCH) + } + + private fun applyMinPitch() { + val minPitch = mMinPitch ?: return + if (!this::mMap.isInitialized) { + return + } + + val currentBounds = mMap.getBounds() + val builder = CameraBoundsOptions.Builder() + .bounds(currentBounds.bounds) + .maxZoom(currentBounds.maxZoom) + .minZoom(currentBounds.minZoom) + .minPitch(minPitch) + .maxPitch(currentBounds.maxPitch) + + mMap.setBounds(builder.build()) + } + fun setReactStyleURL(styleURL: String) { mStyleURL = styleURL changes.add(Property.STYLE_URL) diff --git a/android/src/main/java/com/rnmapbox/rnmbx/components/mapview/RNMBXMapViewManager.kt b/android/src/main/java/com/rnmapbox/rnmbx/components/mapview/RNMBXMapViewManager.kt index bdc25714d..90b05b9be 100644 --- a/android/src/main/java/com/rnmapbox/rnmbx/components/mapview/RNMBXMapViewManager.kt +++ b/android/src/main/java/com/rnmapbox/rnmbx/components/mapview/RNMBXMapViewManager.kt @@ -249,6 +249,12 @@ open class RNMBXMapViewManager(context: ReactApplicationContext, val viewTagReso map.setReactMaxPitch(if (maxPitch.type == ReadableType.Null) null else maxPitch.asDouble()) } + @ReactProp(name = "minPitch") + override fun setMinPitch(map: RNMBXMapView, minPitch: Dynamic) { + // Allow clearing the limit by passing null from JS + map.setReactMinPitch(if (minPitch.type == ReadableType.Null) null else minPitch.asDouble()) + } + @ReactProp(name = "rotateEnabled") override fun setRotateEnabled(map: RNMBXMapView, rotateEnabled: Dynamic) { map.withMapView { diff --git a/docs/MapView.md b/docs/MapView.md index dbc7f1b0c..a35c6b858 100644 --- a/docs/MapView.md +++ b/docs/MapView.md @@ -102,6 +102,13 @@ number Maximum allowed pitch in degrees. Mirrors the Mapbox map option `maxPitch`. +### minPitch + +```tsx +number +``` +Minimum allowed pitch in degrees. Mirrors the Mapbox map option `minPitch`. + ### rotateEnabled diff --git a/docs/docs.json b/docs/docs.json index f11c2b03d..7b86a7a9d 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -5237,6 +5237,13 @@ "default": "none", "description": "Maximum allowed pitch in degrees. Mirrors the Mapbox map option `maxPitch`." }, + { + "name": "minPitch", + "required": false, + "type": "number", + "default": "none", + "description": "Minimum allowed pitch in degrees. Mirrors the Mapbox map option `minPitch`." + }, { "name": "rotateEnabled", "required": false, diff --git a/ios/RNMBX/RNMBXMapView.swift b/ios/RNMBX/RNMBXMapView.swift index 62861b53c..ef4bf8b78 100644 --- a/ios/RNMBX/RNMBXMapView.swift +++ b/ios/RNMBX/RNMBXMapView.swift @@ -424,6 +424,7 @@ open class RNMBXMapView: UIView, RCTInvalidating { case rotateEnabled case pitchEnabled case maxPitch + case minPitch case onMapChange case styleURL case gestureSettings @@ -462,6 +463,8 @@ open class RNMBXMapView: UIView, RCTInvalidating { map.applyPitchEnabled() case .maxPitch: map.applyMaxPitch() + case .minPitch: + map.applyMinPitch() case .gestureSettings: map.applyGestureSettings() case .preferredFramesPerSecond: @@ -548,6 +551,30 @@ open class RNMBXMapView: UIView, RCTInvalidating { } } + var minPitch: Double? = nil + + @objc public func setReactMinPitch(_ value: NSNumber?) { + minPitch = value?.doubleValue + changed(.minPitch) + } + + func applyMinPitch() { + guard let minPitch = minPitch else { return } + + withMapboxMap { mapboxMap in + logged("RNMBXMapView.applyMinPitch") { + let current = mapboxMap.cameraBounds + var options = CameraBoundsOptions() + options.bounds = current.bounds + options.maxZoom = current.maxZoom + options.minZoom = current.minZoom + options.minPitch = minPitch + options.maxPitch = current.maxPitch + try mapboxMap.setCameraBounds(with: options) + } + } + } + var locale: (layerIds: [String]?, locale: Locale)? = nil @objc public func setReactLocalizeLabels(_ value: NSDictionary?) { diff --git a/src/components/MapView.tsx b/src/components/MapView.tsx index d551c8ef0..09402eef1 100644 --- a/src/components/MapView.tsx +++ b/src/components/MapView.tsx @@ -211,6 +211,11 @@ type Props = ViewProps & { */ maxPitch?: number; + /** + * Minimum allowed pitch in degrees. Mirrors the Mapbox map option `minPitch`. + */ + minPitch?: number; + /** * Enable/Disable rotation on map */ diff --git a/src/specs/RNMBXMapViewNativeComponent.ts b/src/specs/RNMBXMapViewNativeComponent.ts index 57d92e7c3..9b132c353 100644 --- a/src/specs/RNMBXMapViewNativeComponent.ts +++ b/src/specs/RNMBXMapViewNativeComponent.ts @@ -55,6 +55,7 @@ export interface NativeProps extends ViewProps { rotateEnabled?: OptionalProp; pitchEnabled?: OptionalProp; maxPitch?: OptionalProp; + minPitch?: OptionalProp; deselectAnnotationOnTap?: OptionalProp; From 17080044779208f62713224040fa461927b74a78 Mon Sep 17 00:00:00 2001 From: Kevin Dice Date: Thu, 2 Apr 2026 17:05:04 -0600 Subject: [PATCH 2/2] chore: update generated files --- docs/MapView.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/MapView.md b/docs/MapView.md index a35c6b858..af0d153f1 100644 --- a/docs/MapView.md +++ b/docs/MapView.md @@ -102,6 +102,7 @@ number Maximum allowed pitch in degrees. Mirrors the Mapbox map option `maxPitch`. + ### minPitch ```tsx @@ -109,6 +110,7 @@ number ``` Minimum allowed pitch in degrees. Mirrors the Mapbox map option `minPitch`. + ### rotateEnabled