Environment
@rnmapbox/maps: 10.3.5 (also reproduced on 10.2.10)
- Mapbox Maps SDK (iOS): 11.23.1
- React Native: 0.81.5
- Platform: iOS only (not reproduced on Android)
- New Architecture (Fabric): enabled
Description
slot has no effect whatsoever on any layer on iOS with the New Architecture enabled — every combination of "top" / "middle" / "bottom" / unset produces a pixel-identical result, and the layer always ends up positioned as if unslotted.
Root cause: on Fabric, prop updates go through RNMBXSetCommonLayerPropsWithoutSourceID in ios/RNMBX/RNMBXFabricHelpers.h, which explicitly reads and applies id, sourceID, filter, aboveLayerID, belowLayerID, layerIndex, reactStyle, maxZoomLevel, minZoomLevel — but never reads slot, even though slot is declared in the codegen prop spec (e.g. src/specs/RNMBXRasterLayerNativeComponent.ts) and is correctly read/applied on the Swift side (RNMBXLayer.swift's setBaseOptions) once it reaches it. It just never reaches it on Fabric.
The old-architecture path doesn't go through this Fabric helper, so this only affects apps with newArchEnabled: true. PointAnnotationManager's own Fabric component view wires slot correctly (added in #4209/#4240) — it's specifically this shared layer helper that's missing it.
Reproduction
Any layer with slot set, e.g.:
<RasterLayer id="my-layer" sourceID="my-source" slot="bottom" style={{...}} />
on a style that imports Mapbox Standard, with New Architecture enabled — the layer renders as if slot were never set (typically ends up above line/road layers and below symbol/label layers, i.e. treated as unslotted).
Fix
Patch attached (also runnable via patch-package) — adds a compile-time check (slot isn't declared on every layer's Props struct — Sky, Background and FillExtrusion don't have it) and applies _view.slot when present:
diff --git a/node_modules/@rnmapbox/maps/ios/RNMBX/RNMBXFabricHelpers.h b/node_modules/@rnmapbox/maps/ios/RNMBX/RNMBXFabricHelpers.h
index 974ee24..17de6d1 100644
--- a/node_modules/@rnmapbox/maps/ios/RNMBX/RNMBXFabricHelpers.h
+++ b/node_modules/@rnmapbox/maps/ios/RNMBX/RNMBXFabricHelpers.h
@@ -1,9 +1,21 @@
#import <React/RCTConversions.h>
#import <folly/dynamic.h>
#import <react/renderer/components/rnmapbox_maps_specs/Props.h>
+#import <type_traits>
#import "rnmapbox_maps-Swift.pre.h"
+// Not every layer's codegen Props struct declares `slot` (Sky, Background and
+// FillExtrusion don't), but RNMBXSetCommonLayerPropsWithoutSourceID is one
+// template instantiated for all of them — an unconditional `newProps.slot`
+// fails to compile for those three. This detects the member at compile time
+// so the same function works for both.
+template <typename T, typename = void>
+struct RNMBXPropsHasSlot : std::false_type {};
+
+template <typename T>
+struct RNMBXPropsHasSlot<T, std::void_t<decltype(std::declval<T>().slot)>> : std::true_type {};
+
// copied from RCTFollyConvert
static id RNMBXConvertFollyDynamicToId(const folly::dynamic &dyn)
{
@@ -105,6 +117,17 @@ void RNMBXSetCommonLayerPropsWithoutSourceID(const T& newProps, RNMBXLayer *_vie
if (minZoomLevel != nil) {
_view.minZoomLevel = minZoomLevel;
}
+ // Upstream gap: `slot` is declared in the codegen spec and read on the old
+ // architecture, but this Fabric prop-application helper never reads it, so
+ // `slot` silently never reaches the layer on the New Architecture.
+ if constexpr (RNMBXPropsHasSlot<T>::value) {
+ id slot = RNMBXConvertFollyDynamicToId(newProps.slot);
+ if (slot != nil) {
+ _view.slot = slot;
+ }
+ }
}
template <typename T>
Confirmed working on-device (iOS, physical device) after applying this patch and rebuilding: slot="bottom" correctly positions a raster layer below Standard's line/symbol layers, which it did not before the patch regardless of the slot value passed.
Environment
@rnmapbox/maps: 10.3.5 (also reproduced on 10.2.10)Description
slothas no effect whatsoever on any layer on iOS with the New Architecture enabled — every combination of"top"/"middle"/"bottom"/ unset produces a pixel-identical result, and the layer always ends up positioned as if unslotted.Root cause: on Fabric, prop updates go through
RNMBXSetCommonLayerPropsWithoutSourceIDinios/RNMBX/RNMBXFabricHelpers.h, which explicitly reads and appliesid,sourceID,filter,aboveLayerID,belowLayerID,layerIndex,reactStyle,maxZoomLevel,minZoomLevel— but never readsslot, even thoughslotis declared in the codegen prop spec (e.g.src/specs/RNMBXRasterLayerNativeComponent.ts) and is correctly read/applied on the Swift side (RNMBXLayer.swift'ssetBaseOptions) once it reaches it. It just never reaches it on Fabric.The old-architecture path doesn't go through this Fabric helper, so this only affects apps with
newArchEnabled: true.PointAnnotationManager's own Fabric component view wiresslotcorrectly (added in #4209/#4240) — it's specifically this shared layer helper that's missing it.Reproduction
Any layer with
slotset, e.g.:on a style that imports Mapbox Standard, with New Architecture enabled — the layer renders as if
slotwere never set (typically ends up above line/road layers and below symbol/label layers, i.e. treated as unslotted).Fix
Patch attached (also runnable via
patch-package) — adds a compile-time check (slotisn't declared on every layer's Props struct —Sky,BackgroundandFillExtrusiondon't have it) and applies_view.slotwhen present:Confirmed working on-device (iOS, physical device) after applying this patch and rebuilding:
slot="bottom"correctly positions a raster layer below Standard's line/symbol layers, which it did not before the patch regardless of theslotvalue passed.