Skip to content

Commit 0683933

Browse files
authored
refactor(tabs): split native nav state into state and update request (#3950)
## Description > [!NOTE] > This PR stacks on top of #3949 — please review/land that one first. The base branch here is `@kkafar/rename-is-native-action`, not `main`. The native tabs JS-driven nav state update path was using a single type — `RNSTabsNavigationState` on iOS and `TabsNavState` on Android — to represent two distinct concepts: 1. **Authoritative state** held by the native container: `(selectedScreenKey, provenance)`. 2. **A JS request to change that state** delivered via the `navStateRequest` prop: `(selectedScreenKey, baseProvenance)`. This conflation was tolerable while we only had one origin (`ProgrammaticJs` / `PROGRAMMATIC_JS`), but with the new public `actionOrigin` enum and the need to support more origins in the future (notably native-programmatic), the request needs to carry its own origin alongside its base provenance. The state type is the wrong place for that field — it describes a result, not a request. This PR introduces a sibling `…UpdateRequest` type on both platforms and threads it through the JS-driven update path. The architectural consequence is that the native container becomes **origin-agnostic** on its success path: instead of hardcoding `actionOrigin = ProgrammaticJs` when the update succeeds, it forwards whatever the incoming request carried. The view manager / component view (which knows the origin is `ProgrammaticJs` for prop-driven updates) is now the place that decides. The runtime value of `actionOrigin` on the public event is unchanged today — JS-driven updates still surface `'programmatic-js'`. This is purely an internal architectural shift. ## Changes ### iOS - New `RNSTabsNavigationStateUpdateRequest` type in `RNSTabsNavigationState.h/.mm` with `selectedScreenKey`, `baseProvenance`, `actionOrigin`. Mirrors `RNSTabsNavigationState`'s utility surface (designated init, `cloneRequest`, static factory). - `RNSTabsHostComponentView`: - `navStateRequest` property retyped to `RNSTabsNavigationStateUpdateRequest *`. - `updateProps:oldProps:` constructs the request directly from C++ props with `actionOrigin = RNSTabsActionOriginProgrammaticJs` and forwards a `cloneRequest` to the controller. - The `rejectedStateUpdateTo:` delegate impl reads `request.selectedScreenKey` / `request.baseProvenance` for the rejection event payload. - `RNSTabBarController`: - `setPendingNavigationStateUpdate:` retyped to take the request. - Ivar renamed `_pendingOperation` → `_pendingStateUpdate` and retyped. - Success-path `RNSTabsNavigationStateUpdateContext` now uses `_pendingStateUpdate.actionOrigin` instead of hardcoded `ProgrammaticJs`. - `isNavigationStateUpdateStale:` retyped; reads `.baseProvenance`. - Delegate `rejectedStateUpdateTo:` parameter retyped to the request. - `OnTabSelectionRejectedPayload.rejectedNavState` (in `RNSTabsHostEventEmitter.h`) renamed/retyped to `rejectedRequest: RNSTabsNavigationStateUpdateRequest *`. The JSI emit reads `selectedScreenKey` / `baseProvenance` from the request. ### Android - New `TabsNavStateUpdateRequest` data class in `TabsNavState.kt` with `selectedScreenKey`, `baseProvenance`, `actionOrigin`. - `TabsHostViewManager.setNavStateRequest` constructs the request with `actionOrigin = TabsActionOrigin.PROGRAMMATIC_JS` baked in (instead of just a `TabsNavState`). - `TabsHost.jsNavStateRequest` retyped to `TabsNavStateUpdateRequest?`. `updateJSNavStateRequest` retyped. - `TabSelectOp` retyped to wrap a `TabsNavStateUpdateRequest` (field `navState` → `request`). - `TabsContainer`: - `onMenuItemSelected` no longer hardcodes `PROGRAMMATIC_JS` in the external-context branch — it reads `(pendingOperation as TabSelectOp).request.actionOrigin`. The `isInExternalOperationContext` flag stays (it still suppresses the prevent-native-selection check and the `lastUINavState` capture). - `isNavStateStale` retyped; reads `request.baseProvenance`. - All `performOperation` reads updated to `tabSelectOp.request.…`. - `TabsContainerDelegate.onNavStateUpdateRejected` parameter `rejectedNavState: TabsNavState` retyped to `rejectedRequest: TabsNavStateUpdateRequest`. `TabsHostEventEmitter` and `TabsHostTabSelectionRejectedEvent` follow. - Bundles a `TabsNavState.selectedKey` → `selectedScreenKey` rename for cross-platform consistency with the JS contract and the new request type. JS-facing `WritableMap` keys (`selectedScreenKey`, `rejectedScreenKey`) were already named correctly — only the Kotlin-internal field name moves. No JS, codegen-spec, or conversion-helper changes — public contract untouched. ## Test plan No new automated tests; this is an internal architectural refactor with no behavioral change on the user/JS-driven paths. Manual verification via `FabricExample`: ### iOS - Tab bar tap → `actionOrigin === 'user'` (unchanged path). - JS-driven `navStateRequest` update → `actionOrigin === 'programmatic-js'` (now sourced from the request, not hardcoded in the controller). - iPad horizontal size-class transition forcing UIKit reshuffle → `actionOrigin === 'implicit'` (unchanged path). - Stale JS update (`rejectStaleNavStateUpdates: true`, mid-flight tap) → `onTabSelectionRejected` fires with `rejectedScreenKey` and `rejectedProvenance` matching the request's `selectedScreenKey` and `baseProvenance`. ### Android - Tab bar tap → `actionOrigin === 'user'` (unchanged path). - JS-driven `navStateRequest` update → `actionOrigin === 'programmatic-js'` (now sourced from the request, not hardcoded in the container). - Stale JS update (`rejectStaleNavStateUpdates: true`, mid-flight tap) → `onTabSelectionRejected` fires with `rejectedScreenKey` and `rejectedProvenance` matching the request's `selectedScreenKey` and `baseProvenance`. Reproduction lives in the `FabricExample` Tabs test screens; log `e.nativeEvent.actionOrigin` from `onTabSelected` and `e.nativeEvent.rejectedScreenKey` / `rejectedProvenance` from `onTabSelectionRejected`. ## Checklist - [ ] Included code example that can be used to test this change. - [ ] For visual changes, included screenshots / GIFs / recordings documenting the change. - [ ] For API changes, updated relevant public types. - [ ] Ensured that CI passes
1 parent 6f65cc3 commit 0683933

18 files changed

Lines changed: 217 additions & 118 deletions

android/src/main/java/com/swmansion/rnscreens/gamma/tabs/container/TabsContainer.kt

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ internal class TabsContainer(
7777

7878
internal val selectedTab: TabsScreenFragment
7979
get() =
80-
checkNotNull(getFragmentForScreenKey(navState.selectedKey)) { "[RNScreens] No selected tab present" }
80+
checkNotNull(getFragmentForScreenKey(navState.selectedScreenKey)) { "[RNScreens] No selected tab present" }
8181

8282
internal val invalidationFlags = TabsContainerInvalidationFlags()
8383

@@ -259,14 +259,14 @@ internal class TabsContainer(
259259
val tabSelectOp = pendingOperation as TabSelectOp
260260

261261
val nextSelectedMenuItemId =
262-
checkNotNull(getMenuItemIdForFragment(requireFragmentForScreenKey(tabSelectOp.navState.selectedKey))) {
263-
"[RNScreens] Failed to find Menu Item for screenKey: ${tabSelectOp.navState.selectedKey}"
262+
checkNotNull(getMenuItemIdForFragment(requireFragmentForScreenKey(tabSelectOp.request.selectedScreenKey))) {
263+
"[RNScreens] Failed to find Menu Item for screenKey: ${tabSelectOp.request.selectedScreenKey}"
264264
}
265265

266-
if (rejectOpsWithStaleNavState && isNavStateStale(tabSelectOp.navState)) {
266+
if (rejectOpsWithStaleNavState && isNavStateStale(tabSelectOp.request)) {
267267
delegate.onNavStateUpdateRejected(
268268
navState,
269-
tabSelectOp.navState,
269+
tabSelectOp.request,
270270
TabsNavStateUpdateRejectionReason.STALE,
271271
)
272272
pendingOperation = null
@@ -281,7 +281,7 @@ internal class TabsContainer(
281281
} else {
282282
delegate.onNavStateUpdateRejected(
283283
navState,
284-
tabSelectOp.navState,
284+
tabSelectOp.request,
285285
TabsNavStateUpdateRejectionReason.REPEATED,
286286
)
287287
}
@@ -328,7 +328,7 @@ internal class TabsContainer(
328328
val currentSelectedFragment = selectedTab
329329

330330
if (nextSelectedFragment === currentSelectedFragment) {
331-
progressNavigationState(navState.selectedKey)
331+
progressNavigationState(navState.selectedScreenKey)
332332
return true
333333
}
334334

@@ -343,8 +343,8 @@ internal class TabsContainer(
343343
return true
344344
}
345345

346-
private fun progressNavigationState(selectedKey: String) {
347-
navState = TabsNavState(selectedKey, navState.provenance + 1)
346+
private fun progressNavigationState(selectedScreenKey: String) {
347+
navState = TabsNavState(selectedScreenKey, navState.provenance + 1)
348348
if (!isInExternalOperationContext) {
349349
lastUINavState = navState
350350
}
@@ -377,7 +377,15 @@ internal class TabsContainer(
377377
navState,
378378
isRepeated = isRepeated,
379379
hasTriggeredSpecialEffect = hasTriggeredSpecialEffect,
380-
actionOrigin = if (isInExternalOperationContext) TabsActionOrigin.PROGRAMMATIC_JS else TabsActionOrigin.USER,
380+
actionOrigin =
381+
if (isInExternalOperationContext) {
382+
check(pendingOperation != null && pendingOperation is TabSelectOp) {
383+
"[RNScreens] Unexpected pending operation $pendingOperation while in external operation context"
384+
}
385+
(pendingOperation as TabSelectOp).request.actionOrigin
386+
} else {
387+
TabsActionOrigin.USER
388+
},
381389
)
382390
}
383391

@@ -413,7 +421,7 @@ internal class TabsContainer(
413421

414422
private fun getSelectedTabsScreenFragmentId(): Int? =
415423
tabsModel
416-
.indexOfFirst { it.requireScreenKey == navState.selectedKey }
424+
.indexOfFirst { it.requireScreenKey == navState.selectedScreenKey }
417425
.takeIf { it != -1 }
418426

419427
private fun getMenuItemForTabsScreen(tabsScreen: TabsScreen): MenuItem? =
@@ -544,9 +552,9 @@ internal class TabsContainer(
544552
fragmentManager = null
545553
}
546554

547-
private fun isNavStateStale(state: TabsNavState): Boolean {
555+
private fun isNavStateStale(request: TabsNavStateUpdateRequest): Boolean {
548556
if (navState.isEmpty() || lastUINavState.isEmpty()) return false
549-
return state.provenance < lastUINavState.provenance
557+
return request.baseProvenance < lastUINavState.provenance
550558
}
551559

552560
companion object {

android/src/main/java/com/swmansion/rnscreens/gamma/tabs/container/TabsContainerDelegate.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,12 @@ internal interface TabsContainerDelegate {
2424
* Called when the container rejects a navigation state update.
2525
*
2626
* @param currentNavState The currently active navigation state that was kept.
27-
* @param rejectedNavState The navigation state update that was rejected.
27+
* @param rejectedRequest The navigation state update request that was rejected.
2828
* @param reason Why the update was rejected.
2929
*/
3030
fun onNavStateUpdateRejected(
3131
currentNavState: TabsNavState,
32-
rejectedNavState: TabsNavState,
32+
rejectedRequest: TabsNavStateUpdateRequest,
3333
reason: TabsNavStateUpdateRejectionReason,
3434
)
3535

android/src/main/java/com/swmansion/rnscreens/gamma/tabs/container/TabsContainerOps.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@ package com.swmansion.rnscreens.gamma.tabs.container
33
internal sealed class TabsContainerOp
44

55
internal data class TabSelectOp(
6-
val navState: TabsNavState,
6+
val request: TabsNavStateUpdateRequest,
77
) : TabsContainerOp()

android/src/main/java/com/swmansion/rnscreens/gamma/tabs/container/TabsNavState.kt

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ import com.swmansion.rnscreens.gamma.tabs.container.TabsNavStateUpdateRejectionR
66
/**
77
* Describes navigation state of a tabs container.
88
*
9-
* @property selectedKey Screen key of the currently selected tab.
9+
* @property selectedScreenKey Screen key of the currently selected tab.
1010
* @property provenance Monotonically increasing number describing the history (generation) of the state.
1111
* State with provenance `N + 1` is derived from state with provenance `N`.
1212
* This allows detecting stale updates.
1313
*/
1414
data class TabsNavState(
15-
val selectedKey: String,
15+
val selectedScreenKey: String,
1616
val provenance: Int,
1717
) {
1818
internal fun isEmpty(): Boolean = this === EMPTY
@@ -24,6 +24,23 @@ data class TabsNavState(
2424
}
2525
}
2626

27+
/**
28+
* A request to change navigation state.
29+
*
30+
* Carries the target [selectedScreenKey], the [baseProvenance] of the state the request was derived from,
31+
* and the [actionOrigin] (actor) that initiated it. Mirrors the public `TabsHostNavStateRequest` TS type
32+
* plus an [actionOrigin] carried internally.
33+
*
34+
* @property selectedScreenKey Screen key of the requested tab.
35+
* @property baseProvenance Provenance of the state this request was derived from. Used for staleness detection.
36+
* @property actionOrigin Origin (actor) that initiated this request.
37+
*/
38+
data class TabsNavStateUpdateRequest(
39+
val selectedScreenKey: String,
40+
val baseProvenance: Int,
41+
val actionOrigin: TabsActionOrigin,
42+
)
43+
2744
/**
2845
* Reason why a navigation state update was rejected by the container.
2946
*

android/src/main/java/com/swmansion/rnscreens/gamma/tabs/host/TabsHost.kt

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import com.swmansion.rnscreens.gamma.tabs.container.TabsContainer
1818
import com.swmansion.rnscreens.gamma.tabs.container.TabsContainerDelegate
1919
import com.swmansion.rnscreens.gamma.tabs.container.TabsNavState
2020
import com.swmansion.rnscreens.gamma.tabs.container.TabsNavStateUpdateRejectionReason
21+
import com.swmansion.rnscreens.gamma.tabs.container.TabsNavStateUpdateRequest
2122
import com.swmansion.rnscreens.gamma.tabs.screen.TabsScreen
2223
import com.swmansion.rnscreens.utils.RNSLog
2324
import kotlin.properties.Delegates
@@ -30,7 +31,7 @@ class TabsHost(
3031
TabsContainerDelegate,
3132
UIManagerListener {
3233
private val renderedScreens: ArrayList<TabsScreen> = arrayListOf()
33-
private var jsNavStateRequest: TabsNavState = TabsNavState.EMPTY
34+
private var jsNavStateRequest: TabsNavStateUpdateRequest? = null
3435

3536
private val container: TabsContainer =
3637
TabsContainer(reactContext, this).apply {
@@ -110,9 +111,9 @@ class TabsHost(
110111
container.removeAllTabsScreens()
111112
}
112113

113-
internal fun updateJSNavStateRequest(navStateRequest: TabsNavState) {
114+
internal fun updateJSNavStateRequest(navStateRequest: TabsNavStateUpdateRequest) {
114115
jsNavStateRequest = navStateRequest
115-
container.setContainerOperation(TabSelectOp(jsNavStateRequest.copy()))
116+
container.setContainerOperation(TabSelectOp(navStateRequest.copy()))
116117
}
117118

118119
private val layoutCallback =
@@ -163,7 +164,7 @@ class TabsHost(
163164
actionOrigin: TabsActionOrigin,
164165
) {
165166
eventEmitter.emitOnTabSelectedEvent(
166-
navState.selectedKey,
167+
navState.selectedScreenKey,
167168
navState.provenance,
168169
isRepeated,
169170
hasTriggeredSpecialEffect,
@@ -173,12 +174,12 @@ class TabsHost(
173174

174175
override fun onNavStateUpdateRejected(
175176
currentNavState: TabsNavState,
176-
rejectedNavState: TabsNavState,
177+
rejectedRequest: TabsNavStateUpdateRequest,
177178
reason: TabsNavStateUpdateRejectionReason,
178179
) {
179180
eventEmitter.emitOnTabSelectionRejectedEvent(
180181
currentNavState,
181-
rejectedNavState,
182+
rejectedRequest,
182183
reason,
183184
)
184185
}

android/src/main/java/com/swmansion/rnscreens/gamma/tabs/host/TabsHostEventEmitter.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import com.swmansion.rnscreens.gamma.common.event.BaseEventEmitter
55
import com.swmansion.rnscreens.gamma.tabs.container.TabsActionOrigin
66
import com.swmansion.rnscreens.gamma.tabs.container.TabsNavState
77
import com.swmansion.rnscreens.gamma.tabs.container.TabsNavStateUpdateRejectionReason
8+
import com.swmansion.rnscreens.gamma.tabs.container.TabsNavStateUpdateRequest
89
import com.swmansion.rnscreens.gamma.tabs.host.event.TabsHostTabSelectedEvent
910
import com.swmansion.rnscreens.gamma.tabs.host.event.TabsHostTabSelectionPreventedEvent
1011
import com.swmansion.rnscreens.gamma.tabs.host.event.TabsHostTabSelectionRejectedEvent
@@ -42,15 +43,15 @@ internal class TabsHostEventEmitter(
4243
*/
4344
fun emitOnTabSelectionRejectedEvent(
4445
currentNavState: TabsNavState,
45-
rejectedNavState: TabsNavState,
46+
rejectedRequest: TabsNavStateUpdateRequest,
4647
rejectionReason: TabsNavStateUpdateRejectionReason,
4748
) {
4849
reactEventDispatcher.dispatchEvent(
4950
TabsHostTabSelectionRejectedEvent(
5051
surfaceId,
5152
viewTag,
5253
currentNavState,
53-
rejectedNavState,
54+
rejectedRequest,
5455
rejectionReason,
5556
),
5657
)

android/src/main/java/com/swmansion/rnscreens/gamma/tabs/host/TabsHostViewManager.kt

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ import com.facebook.react.viewmanagers.RNSTabsHostAndroidManagerDelegate
1111
import com.facebook.react.viewmanagers.RNSTabsHostAndroidManagerInterface
1212
import com.swmansion.rnscreens.gamma.common.colorscheme.ColorScheme
1313
import com.swmansion.rnscreens.gamma.helpers.makeEventRegistrationInfo
14-
import com.swmansion.rnscreens.gamma.tabs.container.TabsNavState
14+
import com.swmansion.rnscreens.gamma.tabs.container.TabsActionOrigin
15+
import com.swmansion.rnscreens.gamma.tabs.container.TabsNavStateUpdateRequest
1516
import com.swmansion.rnscreens.gamma.tabs.host.event.TabsHostTabSelectedEvent
1617
import com.swmansion.rnscreens.gamma.tabs.host.event.TabsHostTabSelectionPreventedEvent
1718
import com.swmansion.rnscreens.gamma.tabs.host.event.TabsHostTabSelectionRejectedEvent
@@ -79,7 +80,13 @@ class TabsHostViewManager :
7980
val navStateRequestMap = requireNotNull(value) { "[RNScreens] navStateRequest must not be nullish" }
8081
val selectedScreenKey = requireNotNull(navStateRequestMap.getString("selectedScreenKey"))
8182
val baseProvenance = requireNotNull(navStateRequestMap.getInt("baseProvenance"))
82-
view.updateJSNavStateRequest(TabsNavState(selectedScreenKey, baseProvenance))
83+
view.updateJSNavStateRequest(
84+
TabsNavStateUpdateRequest(
85+
selectedScreenKey = selectedScreenKey,
86+
baseProvenance = baseProvenance,
87+
actionOrigin = TabsActionOrigin.PROGRAMMATIC_JS,
88+
),
89+
)
8390
}
8491

8592
override fun setRejectStaleNavStateUpdates(

android/src/main/java/com/swmansion/rnscreens/gamma/tabs/host/event/TabsHostTabSelectionPreventedEvent.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class TabsHostTabSelectionPreventedEvent(
2727

2828
override fun getEventData(): WritableMap? =
2929
Arguments.createMap().apply {
30-
putString(EK_SELECTED_KEY, currentNavState.selectedKey)
30+
putString(EK_SELECTED_KEY, currentNavState.selectedScreenKey)
3131
putInt(EK_PROVENANCE, currentNavState.provenance)
3232
putString(EK_PREVENTED_KEY, preventedScreenKey)
3333
}

android/src/main/java/com/swmansion/rnscreens/gamma/tabs/host/event/TabsHostTabSelectionRejectedEvent.kt

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,20 @@ import com.facebook.react.uimanager.events.Event
66
import com.swmansion.rnscreens.gamma.common.event.NamingAwareEventType
77
import com.swmansion.rnscreens.gamma.tabs.container.TabsNavState
88
import com.swmansion.rnscreens.gamma.tabs.container.TabsNavStateUpdateRejectionReason
9+
import com.swmansion.rnscreens.gamma.tabs.container.TabsNavStateUpdateRequest
910

1011
/**
1112
* React Native event dispatched to JS when a tab selection request is rejected by the container.
1213
*
13-
* Carries the currently active navigation state ([currentNavState]), the rejected update
14-
* ([rejectedNavState]), and the [rejectionReason]. This event is never coalesced — every
14+
* Carries the currently active navigation state ([currentNavState]), the rejected request
15+
* ([rejectedRequest]), and the [rejectionReason]. This event is never coalesced — every
1516
* rejection is delivered individually so the JS side has a complete picture of state transitions.
1617
*/
1718
class TabsHostTabSelectionRejectedEvent(
1819
surfaceId: Int,
1920
viewId: Int,
2021
val currentNavState: TabsNavState,
21-
val rejectedNavState: TabsNavState,
22+
val rejectedRequest: TabsNavStateUpdateRequest,
2223
val rejectionReason: TabsNavStateUpdateRejectionReason,
2324
) : Event<TabsHostTabSelectionRejectedEvent>(surfaceId, viewId),
2425
NamingAwareEventType {
@@ -31,10 +32,10 @@ class TabsHostTabSelectionRejectedEvent(
3132

3233
override fun getEventData(): WritableMap? =
3334
Arguments.createMap().apply {
34-
putString(EK_SELECTED_KEY, currentNavState.selectedKey)
35+
putString(EK_SELECTED_KEY, currentNavState.selectedScreenKey)
3536
putInt(EK_PROVENANCE, currentNavState.provenance)
36-
putString(EK_REJECTED_KEY, rejectedNavState.selectedKey)
37-
putInt(EK_REJECTED_PROVENANCE, rejectedNavState.provenance)
37+
putString(EK_REJECTED_KEY, rejectedRequest.selectedScreenKey)
38+
putInt(EK_REJECTED_PROVENANCE, rejectedRequest.baseProvenance)
3839
putString(EK_REJECTION_REASON, rejectionReason.toString())
3940
}
4041

ios/RNSScreenStackHeaderConfig.mm

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -282,10 +282,11 @@ - (UIImage *)loadBackButtonImageInViewController:(UIViewController *)vc
282282
// in the image attribute not being updated. We manually set frame to the size of an image
283283
// in order to trigger proper reload that'd update the image attribute.
284284
RCTImageSource *imageSource = [RNSScreenStackHeaderConfig imageSourceFromImageView:imageView];
285-
[imageView reactSetFrame:CGRectMake(imageView.frame.origin.x,
286-
imageView.frame.origin.y,
287-
imageSource.size.width,
288-
imageSource.size.height)];
285+
[imageView reactSetFrame:CGRectMake(
286+
imageView.frame.origin.x,
287+
imageView.frame.origin.y,
288+
imageSource.size.width,
289+
imageSource.size.height)];
289290
}
290291

291292
UIImage *image = imageView.image;
@@ -847,12 +848,13 @@ - (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)childCompone
847848
return;
848849
}
849850

850-
RCTAssert(childComponentView.superview == nil,
851-
@"Attempt to mount already mounted component view. (parent: %@, child: %@, index: %@, existing parent: %@)",
852-
self,
853-
childComponentView,
854-
@(index),
855-
@([childComponentView.superview tag]));
851+
RCTAssert(
852+
childComponentView.superview == nil,
853+
@"Attempt to mount already mounted component view. (parent: %@, child: %@, index: %@, existing parent: %@)",
854+
self,
855+
childComponentView,
856+
@(index),
857+
@([childComponentView.superview tag]));
856858

857859
// [_reactSubviews insertObject:(RNSScreenStackHeaderSubview *)childComponentView atIndex:index];
858860
[self insertReactSubview:(RNSScreenStackHeaderSubview *)childComponentView atIndex:index];
@@ -1129,21 +1131,23 @@ @implementation RNSScreenStackHeaderConfigManager
11291131

11301132
@implementation RCTConvert (RNSScreenStackHeader)
11311133

1132-
RCT_ENUM_CONVERTER(UISemanticContentAttribute,
1133-
(@{
1134-
@"ltr" : @(UISemanticContentAttributeForceLeftToRight),
1135-
@"rtl" : @(UISemanticContentAttributeForceRightToLeft),
1136-
}),
1137-
UISemanticContentAttributeUnspecified,
1138-
integerValue)
1139-
1140-
RCT_ENUM_CONVERTER(UINavigationItemBackButtonDisplayMode,
1141-
(@{
1142-
@"default" : @(UINavigationItemBackButtonDisplayModeDefault),
1143-
@"generic" : @(UINavigationItemBackButtonDisplayModeGeneric),
1144-
@"minimal" : @(UINavigationItemBackButtonDisplayModeMinimal),
1145-
}),
1146-
UINavigationItemBackButtonDisplayModeDefault,
1147-
integerValue)
1134+
RCT_ENUM_CONVERTER(
1135+
UISemanticContentAttribute,
1136+
(@{
1137+
@"ltr" : @(UISemanticContentAttributeForceLeftToRight),
1138+
@"rtl" : @(UISemanticContentAttributeForceRightToLeft),
1139+
}),
1140+
UISemanticContentAttributeUnspecified,
1141+
integerValue)
1142+
1143+
RCT_ENUM_CONVERTER(
1144+
UINavigationItemBackButtonDisplayMode,
1145+
(@{
1146+
@"default" : @(UINavigationItemBackButtonDisplayModeDefault),
1147+
@"generic" : @(UINavigationItemBackButtonDisplayModeGeneric),
1148+
@"minimal" : @(UINavigationItemBackButtonDisplayModeMinimal),
1149+
}),
1150+
UINavigationItemBackButtonDisplayModeDefault,
1151+
integerValue)
11481152

11491153
@end

0 commit comments

Comments
 (0)