From dee18b2f952c302d004575da186684a78e212fcb Mon Sep 17 00:00:00 2001 From: Muhammad Saqlain Date: Fri, 17 Oct 2025 15:06:57 +0500 Subject: [PATCH] Added support for setStyleLayerProperty --- .../components/mapview/NativeMapViewModule.kt | 14 ++++ .../rnmbx/components/mapview/RNMBXMapView.kt | 35 ++++++++++ .../rnmbx/NativeMapViewModuleSpec.java | 4 ++ docs/MapView.md | 17 +++++ docs/docs.json | 36 ++++++++++ docs/examples.json | 14 +++- .../src/examples/Map/StyleLayerProperty.js | 65 +++++++++++++++++++ example/src/examples/Map/index.js | 1 + ios/RNMBX/RNMBXMapView.swift | 12 ++++ ios/RNMBX/RNMBXMapViewManager.swift | 12 ++++ ios/RNMBX/RNMBXMapViewModule.mm | 6 ++ setup-jest.js | 1 + src/components/MapView.tsx | 22 +++++++ src/specs/NativeMapViewModule.ts | 6 ++ 14 files changed, 244 insertions(+), 1 deletion(-) create mode 100755 example/src/examples/Map/StyleLayerProperty.js diff --git a/android/src/main/java/com/rnmapbox/rnmbx/components/mapview/NativeMapViewModule.kt b/android/src/main/java/com/rnmapbox/rnmbx/components/mapview/NativeMapViewModule.kt index 5ff073e3ff..7cdd784eaf 100644 --- a/android/src/main/java/com/rnmapbox/rnmbx/components/mapview/NativeMapViewModule.kt +++ b/android/src/main/java/com/rnmapbox/rnmbx/components/mapview/NativeMapViewModule.kt @@ -70,6 +70,20 @@ class NativeMapViewModule(context: ReactApplicationContext, val viewTagResolver: promise.resolve(null) } } + + override fun setStyleLayerProperty( + viewRef: ViewRefTag?, + layerId: String, + propertyName: String, + propertyValue: String, + promise: Promise + ) { + withMapViewOnUIThread(viewRef, promise) { + it.setStyleLayerProperty(layerId, propertyName, propertyValue) + + promise.resolve(null) + } + } override fun getCenter(viewRef: ViewRefTag?, promise: Promise) { withMapViewOnUIThread(viewRef, promise) { 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 308b27ebe9..fb98912221 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 @@ -1143,6 +1143,41 @@ open class RNMBXMapView(private val mContext: Context, var mManager: RNMBXMapVie } } } + + fun setStyleLayerProperty( + layerId: String, + propertyName: String, + propertyValue: String + ): Boolean { + if (mMap == null) { + Logger.e("MapView", "setStyleLayerProperty, map is null") + return false + } + + val style = mMap.getStyle() + if (style == null) { + Logger.e("MapView", "setStyleLayerProperty, style is null") + return false + } + + try { + val result = style.setStyleLayerProperty( + layerId, + propertyName, + Value.valueOf(propertyValue) + ) + + if (result.isError) { + Logger.e("MapView", "setStyleLayerProperty error: ${result.error}") + return false + } + + return true + } catch (e: Exception) { + Logger.e("MapView", "setStyleLayerProperty exception: ${e.message}") + return false + } + } // endregion companion object { diff --git a/android/src/main/old-arch/com/rnmapbox/rnmbx/NativeMapViewModuleSpec.java b/android/src/main/old-arch/com/rnmapbox/rnmbx/NativeMapViewModuleSpec.java index 7324cd218d..150b73c179 100644 --- a/android/src/main/old-arch/com/rnmapbox/rnmbx/NativeMapViewModuleSpec.java +++ b/android/src/main/old-arch/com/rnmapbox/rnmbx/NativeMapViewModuleSpec.java @@ -48,6 +48,10 @@ public NativeMapViewModuleSpec(ReactApplicationContext reactContext) { @DoNotStrip public abstract void setSourceVisibility(@Nullable Double viewRef, boolean visible, String sourceId, String sourceLayerId, Promise promise); + @ReactMethod + @DoNotStrip + public abstract void setStyleLayerProperty(@Nullable Double viewRef, String layerId, String propertyName, String propertyValue, Promise promise); + @ReactMethod @DoNotStrip public abstract void getCenter(@Nullable Double viewRef, Promise promise); diff --git a/docs/MapView.md b/docs/MapView.md index 03706c8d3e..35386fcb2c 100644 --- a/docs/MapView.md +++ b/docs/MapView.md @@ -729,6 +729,23 @@ Sets the visibility of all the layers referencing the specified `sourceLayerId` await this._map.setSourceVisibility(false, 'composite', 'building') ``` +### setStyleLayerProperty(layerId, propertyName, propertyValue) + +Sets the value of a property for a specific layer referencing the specified `layerId` + +#### arguments +| Name | Type | Required | Description | +| ---- | :--: | :------: | :----------: | +| `layerId` | `string` | `Yes` | layerId | +| `propertyName` | `string` | `Yes` | propertyName | +| `propertyValue` | `string` | `Yes` | propertyValue | + + + +```javascript +await this._map.setStyleLayerProperty('my-layer', 'visibility', 'none') +``` + ### setFeatureState(featureId, state, sourceId[, sourceLayerId]) diff --git a/docs/docs.json b/docs/docs.json index 9f1bdd957a..bbd100b5e6 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -3819,6 +3819,42 @@ "\nawait this._map.setSourceVisibility(false, 'composite', 'building')\n\n" ] }, + { + "name": "setStyleLayerProperty", + "docblock": "Sets the value of a property for a specific layer referencing the specified `layerId`\n\n@example\nawait this._map.setStyleLayerProperty('my-layer', 'visibility', 'none')\n\n@param {String} layerId - layerId\n@param {String} propertyName - propertyName\n@param {String} propertyValue - propertyValue", + "modifiers": [], + "params": [ + { + "name": "layerId", + "description": "layerId", + "type": { + "name": "string" + }, + "optional": false + }, + { + "name": "propertyName", + "description": "propertyName", + "type": { + "name": "string" + }, + "optional": false + }, + { + "name": "propertyValue", + "description": "propertyValue", + "type": { + "name": "string" + }, + "optional": false + } + ], + "returns": null, + "description": "Sets the value of a property for a specific layer referencing the specified `layerId`", + "examples": [ + "\nawait this._map.setStyleLayerProperty('my-layer', 'visibility', 'none')\n\n" + ] + }, { "name": "setFeatureState", "docblock": "Updates the state map of a feature within a style source.\n\nUpdates entries in the state map of a given feature within a style source.\nOnly entries listed in the `state` will be updated.\nAn entry in the feature state map that is not listed in `state` will retain its previous value.\n\n@param {string} featureId Identifier of the feature whose state should be updated.\n@param {[k: string]: NativeArg} state Map of entries to update with their respective new values.\n@param {string} sourceId Style source identifier.\n@param {string | null} sourceLayerId Style source layer identifier (for multi-layer sources such as vector sources).", diff --git a/docs/examples.json b/docs/examples.json index d3abf5fd24..40a1ca101d 100644 --- a/docs/examples.json +++ b/docs/examples.json @@ -432,7 +432,7 @@ "metadata": { "title": "Source Layer Visibility", "tags": [ - "MapView#setSoruceVisibility" + "MapView#setSourceVisibility" ], "docs": "\nChanges visibility of layers using a source in the map\n" }, @@ -440,6 +440,18 @@ "relPath": "Map/SourceLayerVisibility.js", "name": "SourceLayerVisibility" }, + { + "metadata": { + "title": "Style Layer Property", + "tags": [ + "MapView#setStyleLayerProperty" + ], + "docs": "\nChanges the property of a layer using the specified layerId\n" + }, + "fullPath": "example/src/examples/Map/StyleLayerProperty.js", + "relPath": "Map/StyleLayerProperty.js", + "name": "StyleLayerProperty" + }, { "metadata": { "title": "Style JSON", diff --git a/example/src/examples/Map/StyleLayerProperty.js b/example/src/examples/Map/StyleLayerProperty.js new file mode 100755 index 0000000000..5322e4e91d --- /dev/null +++ b/example/src/examples/Map/StyleLayerProperty.js @@ -0,0 +1,65 @@ +import React from 'react'; +import { Text } from 'react-native'; +import { MapView, Camera } from '@rnmapbox/maps'; + +import Bubble from '../common/Bubble'; + +const defaultCamera = { + centerCoordinate: [-74.005974, 40.712776], + zoomLevel: 13, +}; + +const styles = { + mapView: { flex: 1 }, +}; + +class StyleLayerProperty extends React.Component { + state = { + show: true, + }; + + onPress = () => { + this.setState( + { + show: !this.state.show, + }, + () => { + this._map.setStyleLayerProperty('building', 'visibility', this.state.show ? 'visible' : 'none'); + }, + ); + }; + + render() { + return ( + <> + { + this._map = c; + }} + onPress={this.onPress} + style={styles.mapView} + > + + + + {this.state.show ? 'Hide Buildings' : 'Show Buildings'} + + + ); + } +} + +export default StyleLayerProperty; + +/* end-example-doc */ + +/** + * @typedef {import('../common/ExampleMetadata').ExampleWithMetadata} ExampleWithMetadata + * @type {ExampleWithMetadata['metadata']} + */ +const metadata = { + title: 'Style Layer Property', + tags: ['MapView#setStyleLayerProperty'], + docs: `Changes the property of a layer using the specified layerId`, +}; +StyleLayerProperty.metadata = metadata; diff --git a/example/src/examples/Map/index.js b/example/src/examples/Map/index.js index 1f0b9734b0..7d4f80cc9e 100644 --- a/example/src/examples/Map/index.js +++ b/example/src/examples/Map/index.js @@ -9,6 +9,7 @@ export { default as MapFps } from './MapFps'; export { default as ShowMapLocalStyle } from './ShowMapLocalStyle'; export { default as ShowRegionDidChange } from './ShowRegionDidChange'; export { default as SourceLayerVisibility } from './SourceLayerVisibility'; +export { default as StyleLayerProperty } from './StyleLayerProperty'; export { default as StyleJson } from './StyleJson'; export { default as TwoByTwo } from './TwoByTwo'; export { default as MapAndRNNavigation } from './MapAndRNNavigation'; diff --git a/ios/RNMBX/RNMBXMapView.swift b/ios/RNMBX/RNMBXMapView.swift index bd59417ab3..3ad9adb22b 100644 --- a/ios/RNMBX/RNMBXMapView.swift +++ b/ios/RNMBX/RNMBXMapView.swift @@ -1514,6 +1514,18 @@ extension RNMBXMapView { } } +extension RNMBXMapView { + func setStyleLayerProperty(layerId: String, propertyName: String, propertyValue: Any) -> Void { + let style = self.mapboxMap.style + + do { + try style.setLayerProperty(for: layerId, property: propertyName, value: propertyValue) + } catch { + Logger.log(level: .error, message: "Cannot set property \(propertyName) on layer: \(layerId)") + } + } +} + class RNMBXPointAnnotationManager : AnnotationInteractionDelegate { weak var selected : RNMBXPointAnnotation? = nil private var draggedAnnotation: PointAnnotation? diff --git a/ios/RNMBX/RNMBXMapViewManager.swift b/ios/RNMBX/RNMBXMapViewManager.swift index 1b650bf375..1990e6fbeb 100644 --- a/ios/RNMBX/RNMBXMapViewManager.swift +++ b/ios/RNMBX/RNMBXMapViewManager.swift @@ -70,6 +70,18 @@ extension RNMBXMapViewManager { resolver(nil) } + @objc public static func setStyleLayerProperty( + _ view: RNMBXMapView, + layerId: String, + propertyName: String, + propertyValue: String, + resolver: @escaping RCTPromiseResolveBlock, + rejecter: @escaping RCTPromiseRejectBlock + ) { + view.setStyleLayerProperty(layerId: layerId, propertyName: propertyName, propertyValue: propertyValue) + resolver(nil) + } + @objc public static func getCenter( _ view: RNMBXMapView, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock diff --git a/ios/RNMBX/RNMBXMapViewModule.mm b/ios/RNMBX/RNMBXMapViewModule.mm index 878c4c32eb..ba72851af4 100644 --- a/ios/RNMBX/RNMBXMapViewModule.mm +++ b/ios/RNMBX/RNMBXMapViewModule.mm @@ -124,6 +124,12 @@ - (void)withMapView:(nonnull NSNumber*)viewRef block:(void (^)(RNMBXMapView *))b } reject:reject methodName:@"setSourceVisibility"]; } +RCT_EXPORT_METHOD(setStyleLayerProperty:(nonnull NSNumber*)viewRef layerId:(NSString *)layerId propertyName:(NSString *)propertyName propertyValue:(id)propertyValue resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { + [self withMapView:viewRef block:^(RNMBXMapView *view) { + [RNMBXMapViewManager setStyleLayerProperty:view layerId:layerId propertyName:propertyName propertyValue:propertyValue resolver:resolve rejecter:reject]; + } reject:reject methodName:@"setStyleLayerProperty"]; +} + RCT_EXPORT_METHOD(setFeatureState:(nonnull NSNumber*)viewRef featureId:(nonnull NSString *)featureId state:(nonnull NSDictionary *)state sourceId:(NSString *)sourceId sourceLayerId:(NSString *)sourceLayerId resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { [self withMapView:viewRef block:^(RNMBXMapView *view) { [RNMBXMapViewManager setFeatureState:view featureId:featureId state:state sourceId:sourceId sourceLayerId:sourceLayerId resolver:resolve rejecter:reject]; diff --git a/setup-jest.js b/setup-jest.js index 5a046367e6..ef68d4c56e 100644 --- a/setup-jest.js +++ b/setup-jest.js @@ -153,6 +153,7 @@ NativeModules.RNMBXMapViewModule = { takeSnap: jest.fn(), queryTerrainElevation: jest.fn(), setSourceVisibility: jest.fn(), + setStyleLayerProperty: jest.fn(), getCenter: jest.fn(), getCoordinateFromView: jest.fn(), getPointInView: jest.fn(), diff --git a/src/components/MapView.tsx b/src/components/MapView.tsx index fccb5b387a..ac1a948db8 100644 --- a/src/components/MapView.tsx +++ b/src/components/MapView.tsx @@ -933,6 +933,28 @@ class MapView extends NativeBridgeComponent( ]); } + /** + * Sets the value of a property for a specific layer referencing the specified `layerId` + * + * @example + * await this._map.setStyleLayerProperty('my-layer', 'visibility', 'none') + * + * @param {String} layerId - layerId + * @param {String} propertyName - propertyName + * @param {String} propertyValue - propertyValue + */ + setStyleLayerProperty( + layerId: string, + propertyName: string, + propertyValue: string, + ) { + this._runNative('setStyleLayerProperty', [ + layerId, + propertyName, + propertyValue, + ]); + } + /** * Updates the state map of a feature within a style source. * diff --git a/src/specs/NativeMapViewModule.ts b/src/specs/NativeMapViewModule.ts index c00887666c..eddbf6f75e 100644 --- a/src/specs/NativeMapViewModule.ts +++ b/src/specs/NativeMapViewModule.ts @@ -15,6 +15,12 @@ export interface Spec extends TurboModule { sourceId: string, sourceLayerId: string, ) => Promise; + setStyleLayerProperty: ( + viewRef: Int32 | null, + layerId: string, + propertyName: string, + propertyValue: string, + ) => Promise; getCenter: (viewRef: Int32 | null) => Promise; getCoordinateFromView: ( viewRef: Int32 | null,