From 4eb105ad27debac99099ae9aa3a28f7bc13aa671 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikl=C3=B3s=20Fazekas?= Date: Sat, 28 Feb 2026 20:04:31 +0100 Subject: [PATCH] feat: add line border properties to LineLayer Co-Authored-By: Fl0h0 <25343805+Fl0h0@users.noreply.github.com> --- .../components/styles/RNMBXStyleFactory.kt | 60 ++++++++++++++ docs/LineLayer.md | 83 +++++++++++++++++++ docs/docs.json | 49 +++++++++++ ios/RNMBX/RNMBXStyle.swift | 36 ++++++++ .../autogenHelpers/generateCodeWithEjs.mjs | 8 +- src/utils/MapboxStyles.ts | 18 ++++ src/utils/styleMap.ts | 4 + 7 files changed, 257 insertions(+), 1 deletion(-) diff --git a/android/src/main/java/com/rnmapbox/rnmbx/components/styles/RNMBXStyleFactory.kt b/android/src/main/java/com/rnmapbox/rnmbx/components/styles/RNMBXStyleFactory.kt index 84694cb53..0fd2d91a2 100644 --- a/android/src/main/java/com/rnmapbox/rnmbx/components/styles/RNMBXStyleFactory.kt +++ b/android/src/main/java/com/rnmapbox/rnmbx/components/styles/RNMBXStyleFactory.kt @@ -175,6 +175,14 @@ object RNMBXStyleFactory { setLineGradient(layer, styleValue) "lineTrimOffset" -> setLineTrimOffset(layer, styleValue) + "lineBorderWidth" -> + setLineBorderWidth(layer, styleValue) + "lineBorderWidthTransition" -> + setLineBorderWidthTransition(layer, styleValue) + "lineBorderColor" -> + setLineBorderColor(layer, styleValue) + "lineBorderColorTransition" -> + setLineBorderColorTransition(layer, styleValue) "lineZOffset" -> setLineZOffset(layer, styleValue) "lineElevationReference" -> @@ -1623,6 +1631,58 @@ object RNMBXStyleFactory { } } + fun setLineBorderWidth(layer: LineLayer, styleValue: RNMBXStyleValue ) { + if (styleValue.isExpression()) { + val expression = styleValue.getExpression() + if (expression != null) { + layer.lineBorderWidth(expression) + } else { + Logger.e("RNMBXLine", "Expression for lineBorderWidth is null") + } + } else { + val value = styleValue.getDouble(VALUE_KEY) + if (value != null) { + layer.lineBorderWidth(value) + } else { + Logger.e("RNMBXLine", "value for lineBorderWidth is null") + } + } + } + + + fun setLineBorderWidthTransition(layer: LineLayer, styleValue: RNMBXStyleValue) { + val transition = styleValue.transition + if (transition != null) { + layer.lineBorderWidthTransition(transition); + } + } + + fun setLineBorderColor(layer: LineLayer, styleValue: RNMBXStyleValue ) { + if (styleValue.isExpression()) { + val expression = styleValue.getExpression() + if (expression != null) { + layer.lineBorderColor(expression) + } else { + Logger.e("RNMBXLine", "Expression for lineBorderColor is null") + } + } else { + val value = styleValue.getInt(VALUE_KEY) + if (value != null) { + layer.lineBorderColor(value) + } else { + Logger.e("RNMBXLine", "value for lineBorderColor is null") + } + } + } + + + fun setLineBorderColorTransition(layer: LineLayer, styleValue: RNMBXStyleValue) { + val transition = styleValue.transition + if (transition != null) { + layer.lineBorderColorTransition(transition); + } + } + fun setLineZOffset(layer: LineLayer, styleValue: RNMBXStyleValue ) { if (styleValue.isExpression()) { val expression = styleValue.getExpression() diff --git a/docs/LineLayer.md b/docs/LineLayer.md index 0d2258ddb..1728e745c 100644 --- a/docs/LineLayer.md +++ b/docs/LineLayer.md @@ -161,6 +161,8 @@ Customizable style attributes * lineTrimFadeRange
* lineTrimColor
* lineEmissiveStrength
+* lineBorderWidth
+* lineBorderColor
* lineOcclusionOpacity
___ @@ -942,6 +944,87 @@ The transition affecting any changes to this layer’s lineEmissiveStrength prop `{duration: 300, delay: 0}` +___ + +### lineBorderWidth +Name: `lineBorderWidth` + +Mapbox spec: [line-border-width](https://docs.mapbox.com/style-spec/reference/layers/#paint-line-line-border-width) + +#### Description +The width of the line border. A value of zero means no border. + +#### Type +`number` +#### Default Value +`0` + +#### Minimum +`0` + + +#### Expression + +Parameters: `zoom, feature, feature-state` +___ + +### lineBorderWidthTransition +Name: `lineBorderWidthTransition` + +#### Description + +The transition affecting any changes to this layer’s lineBorderWidth property. + +#### Type + +`{ duration, delay }` + +#### Units +`milliseconds` + +#### Default Value +`{duration: 300, delay: 0}` + + +___ + +### lineBorderColor +Name: `lineBorderColor` + +Mapbox spec: [line-border-color](https://docs.mapbox.com/style-spec/reference/layers/#paint-line-line-border-color) + +#### Description +The color of the line border. If lineBorderWidth is greater than zero and the alpha value of this color is 0 (default), the color for the border will be selected automatically based on the line color. + +#### Type +`color` +#### Default Value +`rgba(0, 0, 0, 0)` + + +#### Expression + +Parameters: `zoom, feature, feature-state` +___ + +### lineBorderColorTransition +Name: `lineBorderColorTransition` + +#### Description + +The transition affecting any changes to this layer’s lineBorderColor property. + +#### Type + +`{ duration, delay }` + +#### Units +`milliseconds` + +#### Default Value +`{duration: 300, delay: 0}` + + ___ ### lineOcclusionOpacity diff --git a/docs/docs.json b/docs/docs.json index d10948f88..7f9b2bd2d 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -4379,6 +4379,55 @@ "namespace": "paint" } }, + { + "name": "lineBorderWidth", + "type": "number", + "values": [], + "minimum": 0, + "default": 0, + "description": "The width of the line border. A value of zero means no border.", + "requires": [], + "disabledBy": [], + "allowedFunctionTypes": [], + "expression": { + "interpolated": true, + "parameters": [ + "zoom", + "feature", + "feature-state" + ] + }, + "transition": true, + "mbx": { + "fullName": "paint-line-line-border-width", + "name": "line-border-width", + "namespace": "paint" + } + }, + { + "name": "lineBorderColor", + "type": "color", + "values": [], + "default": "rgba(0, 0, 0, 0)", + "description": "The color of the line border. If lineBorderWidth is greater than zero and the alpha value of this color is 0 (default), the color for the border will be selected automatically based on the line color.", + "requires": [], + "disabledBy": [], + "allowedFunctionTypes": [], + "expression": { + "interpolated": true, + "parameters": [ + "zoom", + "feature", + "feature-state" + ] + }, + "transition": true, + "mbx": { + "fullName": "paint-line-line-border-color", + "name": "line-border-color", + "namespace": "paint" + } + }, { "name": "lineOcclusionOpacity", "type": "number", diff --git a/ios/RNMBX/RNMBXStyle.swift b/ios/RNMBX/RNMBXStyle.swift index 140f5584a..20e362048 100644 --- a/ios/RNMBX/RNMBXStyle.swift +++ b/ios/RNMBX/RNMBXStyle.swift @@ -154,6 +154,14 @@ func lineLayer(layer: inout LineLayer, reactStyle:Dictionary, oldRe self.setLineGradient(&layer, styleValue:styleValue); } else if (prop == "lineTrimOffset") { self.setLineTrimOffset(&layer, styleValue:styleValue); + } else if (prop == "lineBorderWidth") { + self.setLineBorderWidth(&layer, styleValue:styleValue); + } else if (prop == "lineBorderWidthTransition") { + self.setLineBorderWidthTransition(&layer, styleValue:styleValue); + } else if (prop == "lineBorderColor") { + self.setLineBorderColor(&layer, styleValue:styleValue); + } else if (prop == "lineBorderColorTransition") { + self.setLineBorderColorTransition(&layer, styleValue:styleValue); } else if (prop == "lineZOffset") { self.setLineZOffset(&layer, styleValue:styleValue); } else if (prop == "lineElevationReference") { @@ -1375,6 +1383,34 @@ func setLineTrimOffset(_ layer: inout LineLayer, styleValue: RNMBXStyleValue) } +func setLineBorderWidth(_ layer: inout LineLayer, styleValue: RNMBXStyleValue) +{ + + + layer.lineBorderWidth = styleValue.mglStyleValueNumber(); + + +} + +func setLineBorderWidthTransition(_ layer: inout LineLayer, styleValue: RNMBXStyleValue) +{ + layer.lineBorderWidthTransition = styleValue.getTransition(); +} + +func setLineBorderColor(_ layer: inout LineLayer, styleValue: RNMBXStyleValue) +{ + + + layer.lineBorderColor = styleValue.mglStyleValueColor(); + + +} + +func setLineBorderColorTransition(_ layer: inout LineLayer, styleValue: RNMBXStyleValue) +{ + layer.lineBorderColorTransition = styleValue.getTransition(); +} + func setLineZOffset(_ layer: inout LineLayer, styleValue: RNMBXStyleValue) { diff --git a/scripts/autogenHelpers/generateCodeWithEjs.mjs b/scripts/autogenHelpers/generateCodeWithEjs.mjs index 2238b88b0..60aa9773f 100644 --- a/scripts/autogenHelpers/generateCodeWithEjs.mjs +++ b/scripts/autogenHelpers/generateCodeWithEjs.mjs @@ -331,6 +331,12 @@ const UnsupportedProperties = [ 'raster-particle-elevation', // should be supported in v11 11.7.0 but it's not yet implemented in SDK ]; +// Properties marked as private in the style-spec but supported by native SDKs +const AllowedPrivateProperties = [ + 'line-border-width', + 'line-border-color', +]; + /** * * @param {string[]|undefined} only @@ -340,7 +346,7 @@ function isAttrSupported(name, attr, only) { return false; } const support = getAttributeSupport(attr['sdk-support']); - if (attr.private === true) { + if (attr.private === true && !AllowedPrivateProperties.includes(name)) { return false; } if (only != null) { diff --git a/src/utils/MapboxStyles.ts b/src/utils/MapboxStyles.ts index d13e5ea26..b747b3f7f 100644 --- a/src/utils/MapboxStyles.ts +++ b/src/utils/MapboxStyles.ts @@ -729,6 +729,24 @@ export interface LineLayerStyleProps { * The line part between [trimStart, trimEnd] will be painted using `lineTrimColor,` which is transparent by default to produce a route vanishing effect. The line trimOff offset is based on the whole line range [0.0, 1.0]. */ lineTrimOffset?: number[]; + /** + * The width of the line border. A value of zero means no border. + */ + lineBorderWidth?: Value; + + /** + * The transition affecting any changes to this layer’s lineBorderWidth property. + */ + lineBorderWidthTransition?: Transition; + /** + * The color of the line border. If lineBorderWidth is greater than zero and the alpha value of this color is 0 (default), the color for the border will be selected automatically based on the line color. + */ + lineBorderColor?: Value; + + /** + * The transition affecting any changes to this layer’s lineBorderColor property. + */ + lineBorderColorTransition?: Transition; /** * Vertical offset from ground, in meters. Not supported for globe projection at the moment. * diff --git a/src/utils/styleMap.ts b/src/utils/styleMap.ts index 34f292d50..9f2e5b7f4 100644 --- a/src/utils/styleMap.ts +++ b/src/utils/styleMap.ts @@ -66,6 +66,10 @@ const styleMap = { linePattern: StyleTypes.Image, lineGradient: StyleTypes.Color, lineTrimOffset: StyleTypes.Constant, + lineBorderWidth: StyleTypes.Constant, + lineBorderWidthTransition: StyleTypes.Transition, + lineBorderColor: StyleTypes.Color, + lineBorderColorTransition: StyleTypes.Transition, lineZOffset: StyleTypes.Constant, lineElevationReference: StyleTypes.Enum, lineCrossSlope: StyleTypes.Constant,