Skip to content

slot has no effect on iOS with New Architecture (Fabric) enabled — RNMBXSetCommonLayerPropsWithoutSourceID never reads it #4300

Description

@tomsisbos

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions