Bluesky app fork with some witchin' additions 💫

Update react native screens, remove patch (#9210)

* update react native screens

* bump rns

* see if nightly works

* update nightly

* yay it's out

* update react-nav

* update drawer layout and remove patch

* Update createNativeStackNavigatorWithAuth.tsx

* render drawer as "layout" component

* rm react-nav/drawer (unused)

* restore drawer layout patch

authored by samuel.fm and committed by GitHub caa02db8 f390167f

+5 -6
package.json
··· 98 "@miblanchard/react-native-slider": "^2.6.0", 99 "@mozzius/expo-dynamic-app-icon": "^1.8.0", 100 "@react-native-async-storage/async-storage": "2.2.0", 101 - "@react-navigation/bottom-tabs": "^7.3.13", 102 - "@react-navigation/drawer": "^7.3.12", 103 - "@react-navigation/native": "^7.1.9", 104 - "@react-navigation/native-stack": "^7.3.13", 105 "@sentry/react-native": "~6.20.0", 106 "@tanstack/query-async-storage-persister": "^5.25.0", 107 "@tanstack/react-query": "5.25.0", ··· 194 "react-native-compressor": "^1.13.0", 195 "react-native-date-picker": "^5.0.13", 196 "react-native-device-attest": "^0.1.6", 197 - "react-native-drawer-layout": "^4.1.8", 198 "react-native-edge-to-edge": "^1.6.0", 199 "react-native-gesture-handler": "~2.28.0", 200 "react-native-get-random-values": "~1.11.0", ··· 204 "react-native-qrcode-styled": "^0.3.3", 205 "react-native-reanimated": "^3.19.1", 206 "react-native-safe-area-context": "~5.6.0", 207 - "react-native-screens": "~4.16.0", 208 "react-native-svg": "15.12.1", 209 "react-native-uitextview": "^1.4.0", 210 "react-native-url-polyfill": "^1.3.0",
··· 98 "@miblanchard/react-native-slider": "^2.6.0", 99 "@mozzius/expo-dynamic-app-icon": "^1.8.0", 100 "@react-native-async-storage/async-storage": "2.2.0", 101 + "@react-navigation/bottom-tabs": "^7.9.0", 102 + "@react-navigation/native": "^7.1.26", 103 + "@react-navigation/native-stack": "^7.9.0", 104 "@sentry/react-native": "~6.20.0", 105 "@tanstack/query-async-storage-persister": "^5.25.0", 106 "@tanstack/react-query": "5.25.0", ··· 193 "react-native-compressor": "^1.13.0", 194 "react-native-date-picker": "^5.0.13", 195 "react-native-device-attest": "^0.1.6", 196 + "react-native-drawer-layout": "^4.2.1", 197 "react-native-edge-to-edge": "^1.6.0", 198 "react-native-gesture-handler": "~2.28.0", 199 "react-native-get-random-values": "~1.11.0", ··· 203 "react-native-qrcode-styled": "^0.3.3", 204 "react-native-reanimated": "^3.19.1", 205 "react-native-safe-area-context": "~5.6.0", 206 + "react-native-screens": "^4.19.0", 207 "react-native-svg": "15.12.1", 208 "react-native-uitextview": "^1.4.0", 209 "react-native-url-polyfill": "^1.3.0",
+2 -2
patches/react-native-drawer-layout+4.1.10.patch patches/react-native-drawer-layout+4.2.1.patch
··· 1 diff --git a/node_modules/react-native-drawer-layout/lib/module/views/Drawer.native.js b/node_modules/react-native-drawer-layout/lib/module/views/Drawer.native.js 2 - index efa71f9..a23c624 100644 3 --- a/node_modules/react-native-drawer-layout/lib/module/views/Drawer.native.js 4 +++ b/node_modules/react-native-drawer-layout/lib/module/views/Drawer.native.js 5 @@ -124,15 +124,21 @@ export function Drawer({ ··· 31 - }, finished => runOnJS(onAnimationEnd)(open, finished)); 32 + }, finished => { 33 + animatingTo.value = null; 34 - + runOnJS(onAnimationEnd)(open, finished) 35 + }); 36 if (open) { 37 runOnJS(onOpen)();
··· 1 diff --git a/node_modules/react-native-drawer-layout/lib/module/views/Drawer.native.js b/node_modules/react-native-drawer-layout/lib/module/views/Drawer.native.js 2 + index 40fdcdb..770fd67 100644 3 --- a/node_modules/react-native-drawer-layout/lib/module/views/Drawer.native.js 4 +++ b/node_modules/react-native-drawer-layout/lib/module/views/Drawer.native.js 5 @@ -124,15 +124,21 @@ export function Drawer({ ··· 31 - }, finished => runOnJS(onAnimationEnd)(open, finished)); 32 + }, finished => { 33 + animatingTo.value = null; 34 + + runOnJS(onAnimationEnd)(open, finished); 35 + }); 36 if (open) { 37 runOnJS(onOpen)();
-326
patches/react-native-screens+4.16.0.patch
··· 1 - diff --git a/node_modules/react-native-screens/ios/RNSScreen.mm b/node_modules/react-native-screens/ios/RNSScreen.mm 2 - index b62a2e2..cb469db 100644 3 - --- a/node_modules/react-native-screens/ios/RNSScreen.mm 4 - +++ b/node_modules/react-native-screens/ios/RNSScreen.mm 5 - @@ -729,9 +729,26 @@ - (void)notifyTransitionProgress:(double)progress closing:(BOOL)closing goingFor 6 - #endif 7 - } 8 - 9 - -#if !RCT_NEW_ARCH_ENABLED 10 - +- (void)willMoveToWindow:(UIWindow *)newWindow 11 - +{ 12 - + if (@available(iOS 26, *)) { 13 - + // In iOS 26, as soon as another screen appears in transition, it is interactable 14 - + // To avoid glitches resulting from clicking buttons mid transition, we temporarily disable all interactions 15 - + // Disabling interactions for parent navigation controller won't be enough in case of nested stack 16 - + // Furthermore, a stack put inside a modal will exist in an entirely different hierarchy 17 - + // To be sure, we block interactions on the whole window. 18 - + // Note that newWindows is nil when moving from instead of moving to, and Obj-C handles nil correctly 19 - + newWindow.userInteractionEnabled = false; 20 - + } 21 - +} 22 - + 23 - - (void)presentationControllerWillDismiss:(UIPresentationController *)presentationController 24 - { 25 - + if (@available(iOS 26, *)) { 26 - + // Disable interactions to disallow multiple modals dismissed at once; see willMoveToWindow 27 - + presentationController.containerView.window.userInteractionEnabled = false; 28 - + } 29 - +#if !RCT_NEW_ARCH_ENABLED 30 - // On Paper, we need to call both "cancel" and "reset" here because RN's gesture 31 - // recognizer does not handle the scenario when it gets cancelled by other top 32 - // level gesture recognizer. In this case by the modal dismiss gesture. 33 - @@ -744,8 +761,8 @@ - (void)presentationControllerWillDismiss:(UIPresentationController *)presentati 34 - // down. 35 - [_touchHandler cancel]; 36 - [_touchHandler reset]; 37 - -} 38 - #endif // !RCT_NEW_ARCH_ENABLED 39 - +} 40 - 41 - - (BOOL)presentationControllerShouldDismiss:(UIPresentationController *)presentationController 42 - { 43 - @@ -757,6 +774,10 @@ - (BOOL)presentationControllerShouldDismiss:(UIPresentationController *)presenta 44 - 45 - - (void)presentationControllerDidAttemptToDismiss:(UIPresentationController *)presentationController 46 - { 47 - + if (@available(iOS 26, *)) { 48 - + // Reenable interactions; see presentationControllerWillDismiss 49 - + presentationController.containerView.window.userInteractionEnabled = true; 50 - + } 51 - // NOTE(kkafar): We should consider depracating the use of gesture cancel here & align 52 - // with usePreventRemove API of react-navigation v7. 53 - [self notifyGestureCancel]; 54 - @@ -767,6 +788,11 @@ - (void)presentationControllerDidAttemptToDismiss:(UIPresentationController *)pr 55 - 56 - - (void)presentationControllerDidDismiss:(UIPresentationController *)presentationController 57 - { 58 - + if (@available(iOS 26, *)) { 59 - + // Reenable interactions; see presentationControllerWillDismiss 60 - + // Dismissed screen doesn't hold a reference to window, but presentingViewController.view does 61 - + presentationController.presentingViewController.view.window.userInteractionEnabled = true; 62 - + } 63 - if ([_reactSuperview respondsToSelector:@selector(presentationControllerDidDismiss:)]) { 64 - [_reactSuperview performSelector:@selector(presentationControllerDidDismiss:) withObject:presentationController]; 65 - } 66 - @@ -1518,6 +1544,10 @@ - (void)viewWillDisappear:(BOOL)animated 67 - 68 - - (void)viewDidAppear:(BOOL)animated 69 - { 70 - + if (@available(iOS 26, *)) { 71 - + // Reenable interactions, see willMoveToWindow 72 - + self.view.window.userInteractionEnabled = true; 73 - + } 74 - [super viewDidAppear:animated]; 75 - if (!_isSwiping || _shouldNotify) { 76 - // we are going forward or dismissing without swipe 77 - diff --git a/node_modules/react-native-screens/ios/RNSScreenStack.mm b/node_modules/react-native-screens/ios/RNSScreenStack.mm 78 - index 229dc58..10b365b 100644 79 - --- a/node_modules/react-native-screens/ios/RNSScreenStack.mm 80 - +++ b/node_modules/react-native-screens/ios/RNSScreenStack.mm 81 - @@ -62,26 +62,6 @@ @interface RNSScreenStackView () < 82 - 83 - @implementation RNSNavigationController 84 - 85 - -#if RNS_IPHONE_OS_VERSION_AVAILABLE(26_0) 86 - -- (void)viewDidLoad 87 - -{ 88 - - // iOS 26 introduces new gesture recognizer which replaces our RNSPanGestureRecognizer. 89 - - // The problem is that we are not able to handle it here for various reasons: 90 - - // - the new recognizer comes with its own delegate and our current approach is to wire 91 - - // all recognizers to RNSScreenStackView; to be 100% sure we don't break the logic, 92 - - // we would have to decorate its delegate and call it after our code, which would 93 - - // break other recognizers that the stack view is the delegate for 94 - - // - when RNSScreenStackView.setupGestureHandler method is called, the recognizer hasn't been 95 - - // loaded yet and there is no other place to configure in a not "hacky" way 96 - - // - the official docs warn us to not use it for anything other than "setting up failure requirements with it" 97 - - // - we expose fullScreenGestureEnabled prop to enable/disable the feature, 98 - - // so we need control over the delegate 99 - - if (@available(iOS 26.0, *)) { 100 - - self.interactiveContentPopGestureRecognizer.enabled = NO; 101 - - } 102 - -} 103 - -#endif // iOS 26 104 - - 105 - #if !TARGET_OS_TV 106 - - (UIViewController *)childViewControllerForStatusBarStyle 107 - { 108 - @@ -219,50 +199,6 @@ - (bool)onRepeatedTabSelectionOfTabScreenController:(RNSTabsScreenViewController 109 - return false; 110 - } 111 - 112 - -#pragma mark - UINavigationBarDelegate 113 - - 114 - -#if RNS_IPHONE_OS_VERSION_AVAILABLE(26_0) 115 - -- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item 116 - -{ 117 - - if (@available(iOS 26, *)) { 118 - - // To prevent popping multiple screens when back button is pressed repeatedly, 119 - - // We allow for pop operation to proceed only if no transition is in progress, 120 - - // which we check indirectly by checking if transitionCoordinator is set. 121 - - // If it's not, we are safe to proceed. 122 - - if (self.transitionCoordinator == nil) { 123 - - // We still need to disable interactions for back button so click effects are not applied, 124 - - // and there is unfortunately no better place for it currently 125 - - UIView *button = [navigationBar rnscreens_findBackButtonWrapperView]; 126 - - if (button != nil) { 127 - - button.userInteractionEnabled = false; 128 - - } 129 - - 130 - - return true; 131 - - } 132 - - 133 - - return false; 134 - - } 135 - - 136 - - return true; 137 - -} 138 - - 139 - -- (void)navigationBar:(UINavigationBar *)navigationBar didPopItem:(UINavigationItem *)item 140 - -{ 141 - - if (@available(iOS 26, *)) { 142 - - // Reset interactions on back button -> see navigationBar:shouldPopItem 143 - - // IMPORTANT: This reset won't execute when preventNativeDismiss is on. 144 - - // However, on iOS 26, unlike in previous versions, the back button instance changes 145 - - // when handling preventNativeDismiss and userIteractionEnabled is reset. 146 - - // The instance also changes when regular screen pop happens, but in that case 147 - - // the value of userInteractionEnabled is carried on, and we reset it here. 148 - - UIView *button = [navigationBar rnscreens_findBackButtonWrapperView]; 149 - - if (button != nil) { 150 - - button.userInteractionEnabled = true; 151 - - } 152 - - } 153 - -} 154 - -#endif // Check for iOS >= 26 155 - - 156 - #pragma mark - RNSFrameCorrectionProvider 157 - 158 - #ifdef RNS_GAMMA_ENABLED 159 - @@ -327,7 +263,7 @@ @implementation RNSScreenStackView { 160 - UINavigationController *_controller; 161 - NSMutableArray<RNSScreenView *> *_reactSubviews; 162 - BOOL _invalidated; 163 - - BOOL _isFullWidthSwiping; 164 - + BOOL _isFullWidthSwipingWithPanGesture; // used only for content swipe with RNSPanGestureRecognizer 165 - RNSPercentDrivenInteractiveTransition *_interactionController; 166 - __weak RNSScreenStackManager *_manager; 167 - BOOL _updateScheduled; 168 - @@ -522,6 +458,11 @@ - (void)reactAddControllerToClosestParent:(UIViewController *)controller 169 - [self addSubview:controller.view]; 170 - #if !TARGET_OS_TV 171 - _controller.interactivePopGestureRecognizer.delegate = self; 172 - + #if RNS_IPHONE_OS_VERSION_AVAILABLE(26_0) 173 - + if (@available(iOS 26, *)) { 174 - + _controller.interactiveContentPopGestureRecognizer.delegate = self; 175 - + } 176 - +#endif // Check for iOS >= 26.0 177 - #endif 178 - [controller didMoveToParentViewController:parentView.reactViewController]; 179 - // On iOS pre 12 we observed that `willShowViewController` delegate method does not always 180 - @@ -943,7 +884,7 @@ - (void)dismissOnReload 181 - // when preventing the native dismiss with back button, we have to return the animator. 182 - // Also, we need to return the animator when full width swiping even if the animation is not custom, 183 - // otherwise the screen will be just popped immediately due to no animation 184 - - ((operation == UINavigationControllerOperationPop && shouldCancelDismiss) || _isFullWidthSwiping || 185 - + ((operation == UINavigationControllerOperationPop && shouldCancelDismiss) || _isFullWidthSwipingWithPanGesture || 186 - [RNSScreenStackAnimator isCustomAnimation:screen.stackAnimation] || _customAnimation)) { 187 - return [[RNSScreenStackAnimator alloc] initWithOperation:operation]; 188 - } 189 - @@ -967,23 +908,39 @@ - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer 190 - } 191 - RNSScreenView *topScreen = _reactSubviews.lastObject; 192 - 193 - + BOOL customAnimationOnSwipePropSetAndSelectedAnimationIsCustom = 194 - + topScreen.customAnimationOnSwipe && [RNSScreenStackAnimator isCustomAnimation:topScreen.stackAnimation]; 195 - + 196 - #if TARGET_OS_TV || TARGET_OS_VISION 197 - [self cancelTouchesInParent]; 198 - return YES; 199 - #else 200 - - // RNSPanGestureRecognizer will receive events iff topScreen.fullScreenSwipeEnabled == YES; 201 - - // Events are filtered in gestureRecognizer:shouldReceivePressOrTouchEvent: method 202 - if ([gestureRecognizer isKindOfClass:[RNSPanGestureRecognizer class]]) { 203 - - if ([self isInGestureResponseDistance:gestureRecognizer topScreen:topScreen]) { 204 - - _isFullWidthSwiping = YES; 205 - - [self cancelTouchesInParent]; 206 - - return YES; 207 - + // On iOS < 26, we have a custom full screen swipe recognizer that functions similarily 208 - + // to interactiveContentPopGestureRecognizer introduced in iOS 26. 209 - + // On iOS >= 26, we want to use the native one, but we are unable to handle custom animations 210 - + // with native interactiveContentPopGestureRecognizer, so we have to fallback to the old implementation. 211 - + // In this case, the old one should behave as close as the new native one, having only the difference 212 - + // in animation, and without any customization that is exclusive for it (e.g. gestureResponseDistance). 213 - + if (@available(iOS 26, *)) { 214 - + if (customAnimationOnSwipePropSetAndSelectedAnimationIsCustom) { 215 - + _isFullWidthSwipingWithPanGesture = YES; 216 - + [self cancelTouchesInParent]; 217 - + return YES; 218 - + } 219 - + return NO; 220 - + } else { 221 - + if ([self isInGestureResponseDistance:gestureRecognizer topScreen:topScreen]) { 222 - + _isFullWidthSwipingWithPanGesture = YES; 223 - + [self cancelTouchesInParent]; 224 - + return YES; 225 - + } 226 - + return NO; 227 - } 228 - - return NO; 229 - } 230 - 231 - // Now we're dealing with RNSScreenEdgeGestureRecognizer (or _UIParallaxTransitionPanGestureRecognizer) 232 - - if (topScreen.customAnimationOnSwipe && [RNSScreenStackAnimator isCustomAnimation:topScreen.stackAnimation]) { 233 - + if (customAnimationOnSwipePropSetAndSelectedAnimationIsCustom) { 234 - if ([gestureRecognizer isKindOfClass:[RNSScreenEdgeGestureRecognizer class]]) { 235 - UIRectEdge edges = ((RNSScreenEdgeGestureRecognizer *)gestureRecognizer).edges; 236 - BOOL isRTL = _controller.view.semanticContentAttribute == UISemanticContentAttributeForceRightToLeft; 237 - @@ -1028,7 +985,9 @@ - (void)setupGestureHandlers 238 - rightEdgeSwipeGestureRecognizer.delegate = self; 239 - [self addGestureRecognizer:rightEdgeSwipeGestureRecognizer]; 240 - 241 - - // gesture recognizer for full width swipe gesture 242 - + // Starting from iOS 26, RNSPanGestureRecognizer has been mostly replaced by native 243 - + // interactiveContentPopGestureRecognizer. It still needs to handle custom dismiss animations, 244 - + // which we are not able to handle with the latter. 245 - RNSPanGestureRecognizer *panRecognizer = [[RNSPanGestureRecognizer alloc] initWithTarget:self 246 - action:@selector(handleSwipe:)]; 247 - panRecognizer.delegate = self; 248 - @@ -1091,7 +1050,7 @@ - (void)handleSwipe:(UIPanGestureRecognizer *)gestureRecognizer 249 - [_interactionController cancelInteractiveTransition]; 250 - } 251 - _interactionController = nil; 252 - - _isFullWidthSwiping = NO; 253 - + _isFullWidthSwipingWithPanGesture = NO; 254 - } 255 - default: { 256 - break; 257 - @@ -1225,14 +1184,6 @@ - (BOOL)isScrollViewPanGestureRecognizer:(UIGestureRecognizer *)gestureRecognize 258 - // Be careful when adding another type of gesture recognizer. 259 - - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceivePressOrTouchEvent:(NSObject *)event 260 - { 261 - - if (@available(iOS 26, *)) { 262 - - // in iOS 26, you can swipe to pop screen before the previous one finished transitioning; 263 - - // this prevents from registering the second gesture 264 - - if ([self isTransitionInProgress]) { 265 - - return NO; 266 - - } 267 - - } 268 - - 269 - RNSScreenView *topScreen = _reactSubviews.lastObject; 270 - 271 - for (RNSScreenView *s in _reactSubviews.reverseObjectEnumerator) { 272 - @@ -1249,10 +1200,30 @@ - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceive 273 - return NO; 274 - } 275 - 276 - + BOOL customAnimationOnSwipePropSetAndSelectedAnimationIsCustom = 277 - + topScreen.customAnimationOnSwipe && [RNSScreenStackAnimator isCustomAnimation:topScreen.stackAnimation]; 278 - +#if RNS_IPHONE_OS_VERSION_AVAILABLE(26_0) 279 - + if (@available(iOS 26, *)) { 280 - + // On iOS 26, fullScreenSwipeEnabled takes no effect, and depending on whether custom animations are on, 281 - + // we select either interactiveContentPopGestureRecognizer or RNSPanGestureRecognizer 282 - + if (([gestureRecognizer isKindOfClass:[RNSPanGestureRecognizer class]] && 283 - + !customAnimationOnSwipePropSetAndSelectedAnimationIsCustom) || 284 - + (gestureRecognizer == _controller.interactiveContentPopGestureRecognizer && 285 - + customAnimationOnSwipePropSetAndSelectedAnimationIsCustom)) { 286 - + return NO; 287 - + } 288 - + } else { 289 - + // We want to pass events to RNSPanGestureRecognizer iff full screen swipe is enabled. 290 - + if ([gestureRecognizer isKindOfClass:[RNSPanGestureRecognizer class]]) { 291 - + return topScreen.fullScreenSwipeEnabled; 292 - + } 293 - + } 294 - +#else // check for iOS >= 26 295 - // We want to pass events to RNSPanGestureRecognizer iff full screen swipe is enabled. 296 - if ([gestureRecognizer isKindOfClass:[RNSPanGestureRecognizer class]]) { 297 - return topScreen.fullScreenSwipeEnabled; 298 - } 299 - +#endif // check for iOS >= 26 300 - 301 - // RNSScreenEdgeGestureRecognizer || _UIParallaxTransitionPanGestureRecognizer 302 - return YES; 303 - @@ -1268,15 +1239,6 @@ - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceive 304 - return [self gestureRecognizer:gestureRecognizer shouldReceivePressOrTouchEvent:touch]; 305 - } 306 - 307 - -- (BOOL)isTransitionInProgress 308 - -{ 309 - - if (_controller.transitionCoordinator != nil) { 310 - - return YES; 311 - - } 312 - - 313 - - return NO; 314 - -} 315 - - 316 - - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer 317 - shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer 318 - { 319 - @@ -1289,7 +1251,6 @@ - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer 320 - if (gestureRecognizer.state == UIGestureRecognizerStateBegan || isBackGesture) { 321 - return NO; 322 - } 323 - - 324 - return YES; 325 - } 326 - return NO;
···
+4 -2
src/Navigation.tsx
··· 5 import {msg} from '@lingui/macro' 6 import { 7 type BottomTabBarProps, 8 createBottomTabNavigator, 9 } from '@react-navigation/bottom-tabs' 10 import { ··· 636 * The TabsNavigator is used by native mobile to represent the routes 637 * in 3 distinct tab-stacks with a different root screen on each. 638 */ 639 - function TabsNavigator() { 640 const tabBar = useCallback( 641 (props: JSX.IntrinsicAttributes & BottomTabBarProps) => ( 642 <BottomBar {...props} /> ··· 649 initialRouteName="HomeTab" 650 backBehavior="initialRoute" 651 screenOptions={{headerShown: false, lazy: true}} 652 - tabBar={tabBar}> 653 <Tab.Screen name="HomeTab" getComponent={() => HomeTabNavigator} /> 654 <Tab.Screen name="SearchTab" getComponent={() => SearchTabNavigator} /> 655 <Tab.Screen
··· 5 import {msg} from '@lingui/macro' 6 import { 7 type BottomTabBarProps, 8 + type BottomTabNavigatorProps, 9 createBottomTabNavigator, 10 } from '@react-navigation/bottom-tabs' 11 import { ··· 637 * The TabsNavigator is used by native mobile to represent the routes 638 * in 3 distinct tab-stacks with a different root screen on each. 639 */ 640 + function TabsNavigator({layout}: {layout: BottomTabNavigatorProps['layout']}) { 641 const tabBar = useCallback( 642 (props: JSX.IntrinsicAttributes & BottomTabBarProps) => ( 643 <BottomBar {...props} /> ··· 650 initialRouteName="HomeTab" 651 backBehavior="initialRoute" 652 screenOptions={{headerShown: false, lazy: true}} 653 + tabBar={tabBar} 654 + layout={layout}> 655 <Tab.Screen name="HomeTab" getComponent={() => HomeTabNavigator} /> 656 <Tab.Screen name="SearchTab" getComponent={() => SearchTabNavigator} /> 657 <Tab.Screen
+5 -1
src/view/shell/createNativeStackNavigatorWithAuth.tsx
··· 50 function NativeStackNavigator({ 51 id, 52 initialRouteName, 53 children, 54 layout, 55 screenListeners, 56 screenOptions, 57 screenLayout, 58 ...rest 59 }: NativeStackNavigatorProps) { 60 // --- this is copy and pasted from the original native stack navigator --- ··· 68 >(StackRouter, { 69 id, 70 initialRouteName, 71 children, 72 layout, 73 screenListeners, 74 screenOptions, 75 screenLayout, 76 }) 77 78 React.useEffect( ··· 169 170 export function createNativeStackNavigatorWithAuth< 171 const ParamList extends ParamListBase, 172 - const NavigatorID extends string | undefined = undefined, 173 const TypeBag extends NavigatorTypeBagBase = { 174 ParamList: ParamList 175 NavigatorID: NavigatorID
··· 50 function NativeStackNavigator({ 51 id, 52 initialRouteName, 53 + UNSTABLE_routeNamesChangeBehavior, 54 children, 55 layout, 56 screenListeners, 57 screenOptions, 58 screenLayout, 59 + UNSTABLE_router, 60 ...rest 61 }: NativeStackNavigatorProps) { 62 // --- this is copy and pasted from the original native stack navigator --- ··· 70 >(StackRouter, { 71 id, 72 initialRouteName, 73 + UNSTABLE_routeNamesChangeBehavior, 74 children, 75 layout, 76 screenListeners, 77 screenOptions, 78 screenLayout, 79 + UNSTABLE_router, 80 }) 81 82 React.useEffect( ··· 173 174 export function createNativeStackNavigatorWithAuth< 175 const ParamList extends ParamListBase, 176 + const NavigatorID extends string | undefined = string | undefined, 177 const TypeBag extends NavigatorTypeBagBase = { 178 ParamList: ParamList 179 NavigatorID: NavigatorID
+8 -3
src/view/shell/index.tsx
··· 91 } 92 }, [dedupe, navigation]) 93 94 return ( 95 <> 96 <View style={[a.h_full]}> 97 <ErrorBoundary 98 style={{paddingTop: insets.top, paddingBottom: insets.bottom}}> 99 - <DrawerLayout> 100 - <TabsNavigator /> 101 - </DrawerLayout> 102 </ErrorBoundary> 103 </View> 104
··· 91 } 92 }, [dedupe, navigation]) 93 94 + const drawerLayout = useCallback( 95 + ({children}: {children: React.ReactNode}) => ( 96 + <DrawerLayout>{children}</DrawerLayout> 97 + ), 98 + [], 99 + ) 100 + 101 return ( 102 <> 103 <View style={[a.h_full]}> 104 <ErrorBoundary 105 style={{paddingTop: insets.top, paddingBottom: insets.bottom}}> 106 + <TabsNavigator layout={drawerLayout} /> 107 </ErrorBoundary> 108 </View> 109
+54 -53
yarn.lock
··· 6549 invariant "^2.2.4" 6550 nullthrows "^1.1.1" 6551 6552 - "@react-navigation/bottom-tabs@^7.3.13": 6553 - version "7.3.14" 6554 - resolved "https://registry.yarnpkg.com/@react-navigation/bottom-tabs/-/bottom-tabs-7.3.14.tgz#9ee02baea86ab24abe267726665bc69c6df0bf4c" 6555 - integrity sha512-s2qinJggS2HYZdCOey9A+fN+bNpWeEKwiL/FjAVOTcv+uofxPWN6CtEZUZGPEjfRjis/srURBmCmpNZSI6sQ9Q== 6556 dependencies: 6557 - "@react-navigation/elements" "^2.4.3" 6558 color "^4.2.3" 6559 6560 - "@react-navigation/core@^7.10.0": 6561 - version "7.10.0" 6562 - resolved "https://registry.yarnpkg.com/@react-navigation/core/-/core-7.10.0.tgz#8205ea6b84ce34b2fc2c196701b4cd9b434211b9" 6563 - integrity sha512-qZBA5gGm+9liT4+EHk+kl9apwvqh7HqhLF1XeX6SQRmC/n2QI0u1B8OevKc+EPUDEM9Od15IuwT/GRbSs7/Umw== 6564 dependencies: 6565 - "@react-navigation/routers" "^7.4.0" 6566 escape-string-regexp "^4.0.0" 6567 nanoid "^3.3.11" 6568 query-string "^7.1.3" 6569 react-is "^19.1.0" 6570 - use-latest-callback "^0.2.3" 6571 use-sync-external-store "^1.5.0" 6572 6573 - "@react-navigation/drawer@^7.3.12": 6574 - version "7.4.1" 6575 - resolved "https://registry.yarnpkg.com/@react-navigation/drawer/-/drawer-7.4.1.tgz#50517d8c57f09cdbfc20a485c47016066b918e76" 6576 - integrity sha512-kj5wL31smDLw/6l+0KPR5cjaOZg6oHJCl3RPQonFPuYolUPZBVnuS++uvlifWcD/mqdGmhl3rgLTircRH4vQ7Q== 6577 dependencies: 6578 - "@react-navigation/elements" "^2.4.3" 6579 color "^4.2.3" 6580 - react-native-drawer-layout "^4.1.10" 6581 - use-latest-callback "^0.2.3" 6582 6583 - "@react-navigation/elements@^2.4.3": 6584 - version "2.4.3" 6585 - resolved "https://registry.yarnpkg.com/@react-navigation/elements/-/elements-2.4.3.tgz#cc1dde4c98739d35a0c9c23872316063962cfaee" 6586 - integrity sha512-psoNmnZ0DQIt9nxxPITVLtYW04PGCAfnmd/Pcd3yhiBs93aj+HYKH+SDZDpUnXMf3BN7Wvo4+jPI+/Xjqb+m9w== 6587 dependencies: 6588 color "^4.2.3" 6589 - 6590 - "@react-navigation/native-stack@^7.3.13": 6591 - version "7.3.14" 6592 - resolved "https://registry.yarnpkg.com/@react-navigation/native-stack/-/native-stack-7.3.14.tgz#d1c90f2e50cd13bbced923991cf2faee8083f725" 6593 - integrity sha512-45Sf7ReqSCIySXS5nrKtLGmNlFXm5x+u32YQMwKDONCqVGOBCfo4ryKqeQq1EMJ7Py6IDyOwHMhA+jhNOxnfPw== 6594 - dependencies: 6595 - "@react-navigation/elements" "^2.4.3" 6596 warn-once "^0.1.1" 6597 6598 - "@react-navigation/native@^7.1.9": 6599 - version "7.1.10" 6600 - resolved "https://registry.yarnpkg.com/@react-navigation/native/-/native-7.1.10.tgz#768f674f7c09b6a57215762052aa62a7dc107402" 6601 - integrity sha512-Ug4IML0DkAxZTMF/E7lyyLXSclkGAYElY2cxZWITwfBjtlVeda0NjsdnTWY5EGjnd7bwvhTIUC+CO6qSlrDn5A== 6602 dependencies: 6603 - "@react-navigation/core" "^7.10.0" 6604 escape-string-regexp "^4.0.0" 6605 fast-deep-equal "^3.1.3" 6606 nanoid "^3.3.11" 6607 - use-latest-callback "^0.2.3" 6608 6609 - "@react-navigation/routers@^7.4.0": 6610 - version "7.4.0" 6611 - resolved "https://registry.yarnpkg.com/@react-navigation/routers/-/routers-7.4.0.tgz#5bace799713ac163310c18711b98dfbe418c6b36" 6612 - integrity sha512-th5THnuWKJlmr7GGHiicy979di11ycDWub9iIXbEDvQwmwmsRzppmVbfs2nD8bC/MgyMgqWu/gxfys+HqN+kcw== 6613 dependencies: 6614 nanoid "^3.3.11" 6615 ··· 17055 dependencies: 17056 dotenv "^16.4.5" 17057 17058 - react-native-drawer-layout@^4.1.10, react-native-drawer-layout@^4.1.8: 17059 - version "4.1.10" 17060 - resolved "https://registry.yarnpkg.com/react-native-drawer-layout/-/react-native-drawer-layout-4.1.10.tgz#9007cb747767ca8e1c9c3337671ad35ed95ad4d9" 17061 - integrity sha512-wejQo0F+EffCkOkRh+DP6ENWMB+aWEHkXV8Pd564PmtoySZLUsV/ksYrh/mrufh7T7EuvGT8+fNHz7mMRYftWg== 17062 dependencies: 17063 - use-latest-callback "^0.2.3" 17064 17065 react-native-edge-to-edge@^1.6.0: 17066 version "1.6.0" ··· 17149 resolved "https://registry.yarnpkg.com/react-native-safe-area-context/-/react-native-safe-area-context-5.6.1.tgz#cb4d249ef1a6f7e8fd0cfdfa9764838dffda26b6" 17150 integrity sha512-/wJE58HLEAkATzhhX1xSr+fostLsK8Q97EfpfMDKo8jlOc1QKESSX/FQrhk7HhQH/2uSaox4Y86sNaI02kteiA== 17151 17152 - react-native-screens@~4.16.0: 17153 - version "4.16.0" 17154 - resolved "https://registry.yarnpkg.com/react-native-screens/-/react-native-screens-4.16.0.tgz#efa42e77a092aa0b5277c9ae41391ea0240e0870" 17155 - integrity sha512-yIAyh7F/9uWkOzCi1/2FqvNvK6Wb9Y1+Kzn16SuGfN9YFJDTbwlzGRvePCNTOX0recpLQF3kc2FmvMUhyTCH1Q== 17156 dependencies: 17157 react-freeze "^1.0.0" 17158 - react-native-is-edge-to-edge "^1.2.1" 17159 warn-once "^0.1.0" 17160 17161 react-native-svg@15.12.1: ··· 18128 version "1.2.0" 18129 resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" 18130 integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== 18131 18132 shallow-equal@^3.1.0: 18133 version "3.1.0" ··· 19630 resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz#497cefb13d863d687b08477d9e5a164ad8c1a6fb" 19631 integrity sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA== 19632 19633 - use-latest-callback@^0.2.3: 19634 - version "0.2.3" 19635 - resolved "https://registry.yarnpkg.com/use-latest-callback/-/use-latest-callback-0.2.3.tgz#2d644d3063040b9bc2d4c55bb525a13ae3de9e16" 19636 - integrity sha512-7vI3fBuyRcP91pazVboc4qu+6ZqM8izPWX9k7cRnT8hbD5svslcknsh3S9BUhaK11OmgTV4oWZZVSeQAiV53SQ== 19637 19638 use-latest@^1.2.1: 19639 version "1.2.1"
··· 6549 invariant "^2.2.4" 6550 nullthrows "^1.1.1" 6551 6552 + "@react-navigation/bottom-tabs@^7.9.0": 6553 + version "7.9.0" 6554 + resolved "https://registry.yarnpkg.com/@react-navigation/bottom-tabs/-/bottom-tabs-7.9.0.tgz#b546adb0cedd72a1f0179e00b74039b3c8abb6bd" 6555 + integrity sha512-024FWdHp3ZsE5rP8tmGI4vh+1z3wg8u8E9Frep8eeGoYo1h9rQhvgofQDGxknmrKsb7t8o8Dim+IZSvl57cPFQ== 6556 dependencies: 6557 + "@react-navigation/elements" "^2.9.3" 6558 color "^4.2.3" 6559 + sf-symbols-typescript "^2.1.0" 6560 6561 + "@react-navigation/core@^7.13.7": 6562 + version "7.13.7" 6563 + resolved "https://registry.yarnpkg.com/@react-navigation/core/-/core-7.13.7.tgz#1263903a703b5f183a08c22dfc5c3735ac4ef91c" 6564 + integrity sha512-k2ABo3250vq1ovOh/iVwXS6Hwr5PVRGXoPh/ewVFOOuEKTvOx9i//OBzt8EF+HokBxS2HBRlR2b+aCOmscRqBw== 6565 dependencies: 6566 + "@react-navigation/routers" "^7.5.3" 6567 escape-string-regexp "^4.0.0" 6568 + fast-deep-equal "^3.1.3" 6569 nanoid "^3.3.11" 6570 query-string "^7.1.3" 6571 react-is "^19.1.0" 6572 + use-latest-callback "^0.2.4" 6573 use-sync-external-store "^1.5.0" 6574 6575 + "@react-navigation/elements@^2.9.3": 6576 + version "2.9.3" 6577 + resolved "https://registry.yarnpkg.com/@react-navigation/elements/-/elements-2.9.3.tgz#505ae38af347a0bc5326155318a3d9a54e2071e3" 6578 + integrity sha512-3+eyvWiVPIEf6tN9UdduhOEHcTuNe3R5WovgiVkfH9+jApHMTZDc2loePTpY/i2HDJhObhhChpJzO6BVjrpdYQ== 6579 dependencies: 6580 color "^4.2.3" 6581 + use-latest-callback "^0.2.4" 6582 + use-sync-external-store "^1.5.0" 6583 6584 + "@react-navigation/native-stack@^7.9.0": 6585 + version "7.9.0" 6586 + resolved "https://registry.yarnpkg.com/@react-navigation/native-stack/-/native-stack-7.9.0.tgz#4fcd08a403ff86c465a908f3b49f86ab3f66d06a" 6587 + integrity sha512-C/mNPhI0Pnerl7C2cB+6fAkdgSmfKECMERrbyfjx3P6JmEuTC54o+GV1c62FUmlRaRUassVHbtw4EeaY2uLh0g== 6588 dependencies: 6589 + "@react-navigation/elements" "^2.9.3" 6590 color "^4.2.3" 6591 + sf-symbols-typescript "^2.1.0" 6592 warn-once "^0.1.1" 6593 6594 + "@react-navigation/native@^7.1.26": 6595 + version "7.1.26" 6596 + resolved "https://registry.yarnpkg.com/@react-navigation/native/-/native-7.1.26.tgz#220672e115f39014b95ca3ce8f2c37076a0e74f4" 6597 + integrity sha512-RhKmeD0E2ejzKS6z8elAfdfwShpcdkYY8zJzvHYLq+wv183BBcElTeyMLcIX6wIn7QutXeI92Yi21t7aUWfqNQ== 6598 dependencies: 6599 + "@react-navigation/core" "^7.13.7" 6600 escape-string-regexp "^4.0.0" 6601 fast-deep-equal "^3.1.3" 6602 nanoid "^3.3.11" 6603 + use-latest-callback "^0.2.4" 6604 6605 + "@react-navigation/routers@^7.5.3": 6606 + version "7.5.3" 6607 + resolved "https://registry.yarnpkg.com/@react-navigation/routers/-/routers-7.5.3.tgz#8002930ef5f62351be2475d0dffde3ffaee174d7" 6608 + integrity sha512-1tJHg4KKRJuQ1/EvJxatrMef3NZXEPzwUIUZ3n1yJ2t7Q97siwRtbynRpQG9/69ebbtiZ8W3ScOZF/OmhvM4Rg== 6609 dependencies: 6610 nanoid "^3.3.11" 6611 ··· 17051 dependencies: 17052 dotenv "^16.4.5" 17053 17054 + react-native-drawer-layout@^4.2.1: 17055 + version "4.2.1" 17056 + resolved "https://registry.yarnpkg.com/react-native-drawer-layout/-/react-native-drawer-layout-4.2.1.tgz#5c89425662c9b5216a227dbc87bc7f38c4ec8719" 17057 + integrity sha512-liwRJ7ynRU/ogRlUdiK1Yoi1VzUSq2Vu/RU+UgqlMB3XduslZ1DZg/mTX0f1uCEV2dJ4ec+1fRa3OlIierfyZg== 17058 dependencies: 17059 + color "^4.2.3" 17060 + use-latest-callback "^0.2.4" 17061 17062 react-native-edge-to-edge@^1.6.0: 17063 version "1.6.0" ··· 17146 resolved "https://registry.yarnpkg.com/react-native-safe-area-context/-/react-native-safe-area-context-5.6.1.tgz#cb4d249ef1a6f7e8fd0cfdfa9764838dffda26b6" 17147 integrity sha512-/wJE58HLEAkATzhhX1xSr+fostLsK8Q97EfpfMDKo8jlOc1QKESSX/FQrhk7HhQH/2uSaox4Y86sNaI02kteiA== 17148 17149 + react-native-screens@^4.19.0: 17150 + version "4.19.0" 17151 + resolved "https://registry.yarnpkg.com/react-native-screens/-/react-native-screens-4.19.0.tgz#d00f2ec070d7426204eaf34ef6c64396a6871e1d" 17152 + integrity sha512-qSDAO3AL5bti0Ri7KZRSVmWlhDr8MV86N5GruiKVQfEL7Zx2nUi3Dl62lqHUAD/LnDvOPuDDsMHCfIpYSv3hPQ== 17153 dependencies: 17154 react-freeze "^1.0.0" 17155 warn-once "^0.1.0" 17156 17157 react-native-svg@15.12.1: ··· 18124 version "1.2.0" 18125 resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" 18126 integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== 18127 + 18128 + sf-symbols-typescript@^2.1.0: 18129 + version "2.2.0" 18130 + resolved "https://registry.yarnpkg.com/sf-symbols-typescript/-/sf-symbols-typescript-2.2.0.tgz#926d6e0715e3d8784cadf7658431e36581254208" 18131 + integrity sha512-TPbeg0b7ylrswdGCji8FRGFAKuqbpQlLbL8SOle3j1iHSs5Ob5mhvMAxWN2UItOjgALAB5Zp3fmMfj8mbWvXKw== 18132 18133 shallow-equal@^3.1.0: 18134 version "3.1.0" ··· 19631 resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz#497cefb13d863d687b08477d9e5a164ad8c1a6fb" 19632 integrity sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA== 19633 19634 + use-latest-callback@^0.2.4: 19635 + version "0.2.6" 19636 + resolved "https://registry.yarnpkg.com/use-latest-callback/-/use-latest-callback-0.2.6.tgz#e5ea752808c86219acc179ace0ae3c1203255e77" 19637 + integrity sha512-FvRG9i1HSo0wagmX63Vrm8SnlUU3LMM3WyZkQ76RnslpBrX694AdG4A0zQBx2B3ZifFA0yv/BaEHGBnEax5rZg== 19638 19639 use-latest@^1.2.1: 19640 version "1.2.1"