react-native-navigation 8.7.5 → 8.7.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/android/ARCHITECTURE.md +458 -0
  2. package/android/src/main/java/com/reactnativenavigation/react/NavigationModule.java +2 -2
  3. package/android/src/main/java/com/reactnativenavigation/views/stack/topbar/titlebar/ButtonBar.kt +2 -0
  4. package/android/src/main/java/com/reactnativenavigation/views/stack/topbar/titlebar/IconBackgroundDrawable.kt +20 -17
  5. package/android/src/main/java/com/reactnativenavigation/views/stack/topbar/titlebar/TitleAndButtonsMeasurer.kt +2 -1
  6. package/android/src/main/java/com/reactnativenavigation/views/stack/topbar/titlebar/TitleBarReactView.kt +7 -10
  7. package/android/src/main/res/values/styles.xml +2 -0
  8. package/ios/ARCHITECTURE.md +416 -0
  9. package/ios/BottomTabsAfterInitialTabAttacher.mm +31 -0
  10. package/ios/BottomTabsAppearancePresenter.mm +69 -32
  11. package/ios/BottomTabsBasePresenter.mm +5 -4
  12. package/ios/RCTHelpers.mm +3 -1
  13. package/ios/RNNAppDelegate.mm +10 -0
  14. package/ios/RNNBottomTabsController.mm +19 -6
  15. package/ios/RNNBottomTabsOptions.mm +5 -1
  16. package/ios/RNNBridgeManager.mm +2 -0
  17. package/ios/RNNComponentViewController.mm +4 -2
  18. package/ios/RNNModalHostViewManagerHandler.h +5 -0
  19. package/ios/RNNModalHostViewManagerHandler.mm +2 -0
  20. package/ios/RNNOverlayWindow.mm +1 -2
  21. package/ios/RNNScrollEdgeAppearanceOptions.h +2 -0
  22. package/ios/RNNScrollEdgeAppearanceOptions.mm +2 -0
  23. package/ios/TopBarAppearancePresenter.mm +35 -0
  24. package/lib/module/ARCHITECTURE.md +301 -0
  25. package/lib/module/interfaces/Options.js.map +1 -1
  26. package/lib/typescript/interfaces/Options.d.ts +29 -0
  27. package/lib/typescript/interfaces/Options.d.ts.map +1 -1
  28. package/package.json +11 -11
  29. package/src/ARCHITECTURE.md +301 -0
  30. package/src/interfaces/Options.ts +30 -0
@@ -0,0 +1,416 @@
1
+ # iOS Native Architecture
2
+
3
+ The iOS implementation provides native navigation using UIKit view controllers, coordinated through a bridge module that receives commands from JavaScript.
4
+
5
+ ## App Integration
6
+
7
+ ### RNNAppDelegate
8
+ **Files**: `RNNAppDelegate.h/mm`
9
+
10
+ Base class that user's AppDelegate must extend. Handles React Native and navigation initialization:
11
+
12
+ ```objc
13
+ // AppDelegate.h - User extends RNNAppDelegate
14
+ #import "RNNAppDelegate.h"
15
+ @interface AppDelegate : RNNAppDelegate
16
+ @end
17
+
18
+ // AppDelegate.m - User implements sourceURLForBridge
19
+ @implementation AppDelegate
20
+ - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge {
21
+ return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
22
+ }
23
+ @end
24
+ ```
25
+
26
+ **What RNNAppDelegate does:**
27
+ - Sets up React Native feature flags (Fabric, TurboModules, Bridgeless)
28
+ - Creates `RCTRootViewFactory` and `ReactHost`
29
+ - Calls `[ReactNativeNavigation bootstrapWithHost:]` to initialize navigation
30
+ - Handles RN version differences (0.77, 0.78, 0.79+) via compile-time macros
31
+
32
+ ### ReactNativeNavigation Bootstrap
33
+ **File**: `ReactNativeNavigation.h/mm`
34
+
35
+ Public API for native initialization:
36
+
37
+ ```objc
38
+ // New architecture (0.77+)
39
+ [ReactNativeNavigation bootstrapWithHost:reactHost];
40
+
41
+ // Legacy bridge
42
+ [ReactNativeNavigation bootstrapWithBridge:bridge];
43
+
44
+ // Register native screens
45
+ [ReactNativeNavigation registerExternalComponent:@"NativeScreen"
46
+ callback:^(NSDictionary *props, RCTBridge *bridge) {
47
+ return [[MyNativeVC alloc] init];
48
+ }];
49
+ ```
50
+
51
+ ### Autolink Script (`npx rnn-link`)
52
+
53
+ The `autolink/postlink/postLinkIOS.js` script automates setup:
54
+
55
+ | Linker | What it does |
56
+ |--------|--------------|
57
+ | `AppDelegateLinker` | Changes AppDelegate to extend `RNNAppDelegate`, imports ReactNativeNavigation, removes RCTRootView setup |
58
+ | `PodfileLinker` | Adds required pods configuration |
59
+ | `PlistLinker` | Updates Info.plist if needed |
60
+
61
+ **AppDelegateLinker transformations:**
62
+ - Swift: `class AppDelegate: RCTAppDelegate` → `class AppDelegate: RNNAppDelegate`
63
+ - Obj-C header: `@interface AppDelegate : RCTAppDelegate` → `@interface AppDelegate : RNNAppDelegate`
64
+ - Imports `<ReactNativeNavigation/ReactNativeNavigation.h>`
65
+ - Removes manual RCTRootView/window setup (navigation manages the window)
66
+
67
+ ## Directory Structure
68
+
69
+ ```
70
+ ios/
71
+ ├── RNNBridgeModule.h/mm # Bridge entry point (legacy architecture)
72
+ ├── RNNBridgeManager.h/mm # Bridge initialization
73
+ ├── RNNCommandsHandler.h/mm # Command dispatcher
74
+ ├── RNNEventEmitter.h/mm # Event emission to JS
75
+ ├── RNNLayoutManager.h/mm # View controller tracking
76
+ ├── RNNLayoutNode.h/mm # Layout tree parsing
77
+ ├── RNNNavigationOptions.h/mm # Options model
78
+ ├── RNNComponentViewController.h/mm # React component screen
79
+ ├── RNNStackController.h/mm # Stack navigation
80
+ ├── RNNBottomTabsController.h/mm # Tab navigation
81
+ ├── RNNSideMenuViewController.h/mm # Side menu
82
+ ├── RNNTopTabsViewController.h/mm # Top tabs
83
+ ├── RNNSplitViewController.h/mm # Split view (iPad)
84
+ ├── RNNModalManager.h/mm # Modal presentation
85
+ ├── RNNOverlayManager.h/mm # Overlay management
86
+ ├── TurboModules/ # New architecture entry points
87
+ │ ├── RNNTurboModule.h/mm # TurboModule spec implementation
88
+ │ ├── RNNTurboManager.h/mm # Manager for host, window, external components
89
+ │ ├── RNNTurboCommandsHandler.h/mm # TurboModule command routing
90
+ │ └── RNNTurboEventEmitter.h/mm # Event emission for new arch
91
+ ├── Utils/ # Utility classes
92
+ ├── RNNSideMenu/ # MMDrawerController integration
93
+ └── ReactNativeNavigation.xcodeproj/
94
+ ```
95
+
96
+ ## Bridge Architecture
97
+
98
+ The library supports both the legacy bridge and new TurboModule architecture:
99
+ - **Legacy (Bridge)**: `RNNBridgeModule` receives commands via `RCT_EXPORT_METHOD`
100
+ - **New Architecture**: `RNNTurboModule` (in `TurboModules/`) receives commands directly
101
+
102
+ Both entry points delegate to `RNNCommandsHandler` for command execution.
103
+
104
+ ```
105
+ ┌────────────────────────────────────────────────────────────┐
106
+ │ JavaScript (TurboModule) │
107
+ └─────────────────────────┬──────────────────────────────────┘
108
+
109
+ ┌─────────────────────────▼──────────────────────────────────┐
110
+ │ RNNBridgeModule (bridge) / RNNTurboModule (new arch) │
111
+ │ - setRoot, push, pop, showModal, dismissModal, etc. │
112
+ └─────────────────────────┬──────────────────────────────────┘
113
+
114
+ ┌─────────────────────────▼──────────────────────────────────┐
115
+ │ RNNCommandsHandler │
116
+ │ - Validates commands, manages layout lifecycle │
117
+ │ - Coordinates with managers │
118
+ └──────┬──────────────┬──────────────┬──────────────┬────────┘
119
+ │ │ │ │
120
+ ┌──────▼─────┐ ┌──────▼─────┐ ┌──────▼─────┐ ┌─────▼──────┐
121
+ │RNNLayout │ │RNNModal │ │RNNOverlay │ │RNNViewController│
122
+ │Manager │ │Manager │ │Manager │ │Factory │
123
+ └────────────┘ └────────────┘ └────────────┘ └────────────┘
124
+ ```
125
+
126
+ ## View Controller Hierarchy
127
+
128
+ All navigation view controllers conform to `RNNLayoutProtocol`:
129
+
130
+ ```
131
+ UIViewController
132
+ ├── RNNComponentViewController # React component screen
133
+ ├── RNNExternalViewController # Native screen wrapper
134
+ └── RNNSplashScreenViewController # Launch screen
135
+
136
+ UINavigationController
137
+ └── RNNStackController # Stack navigation
138
+
139
+ UITabBarController
140
+ └── RNNBottomTabsController # Bottom tabs
141
+
142
+ UIViewController (custom)
143
+ ├── RNNTopTabsViewController # Horizontal top tabs
144
+ └── RNNSideMenuChildViewController # Drawer child
145
+
146
+ MMDrawerController
147
+ └── RNNSideMenuViewController # Side menu/drawer
148
+
149
+ UISplitViewController
150
+ └── RNNSplitViewController # Master-detail (iPad)
151
+ ```
152
+
153
+ ## Core Classes
154
+
155
+ ### RNNBridgeModule
156
+ Entry point for JavaScript commands (legacy architecture). Exports methods via `RCT_EXPORT_METHOD`:
157
+
158
+ ```objc
159
+ RCT_EXPORT_METHOD(setRoot:(NSString*)commandId layout:(NSDictionary*)layout
160
+ resolver:(RCTPromiseResolveBlock)resolve
161
+ rejecter:(RCTPromiseRejectBlock)reject);
162
+ ```
163
+
164
+ `RNNBridgeModule` returns the main queue as its `methodQueue`; `RNNTurboModule` uses `RCTExecuteOnMainQueue` for each command to ensure UI operations run on the main thread.
165
+
166
+ ### RNNBridgeManager
167
+ Initializes bridge infrastructure:
168
+ - Creates RNNLayoutManager, RNNModalManager, RNNOverlayManager
169
+ - Creates RNNViewControllerFactory, RNNCommandsHandler
170
+ - Provides extra modules to React bridge
171
+ - Handles JavaScript reload events
172
+
173
+ ### RNNCommandsHandler
174
+ Central command dispatcher implementing all navigation operations:
175
+ - `setRoot:` - Replace root view controller
176
+ - `push:componentId:layout:` - Push to stack
177
+ - `pop:componentId:` - Pop from stack
178
+ - `showModal:` - Present modal
179
+ - `dismissModal:` - Dismiss modal
180
+ - `showOverlay:` - Show overlay window
181
+ - `dismissOverlay:` - Hide overlay
182
+
183
+ ### RNNLayoutManager
184
+ Tracks active view controllers:
185
+ - `addPendingViewController:` - Register during creation
186
+ - `removePendingViewController:` - Cleanup after presentation
187
+ - `findComponentForId:` - Lookup by componentId
188
+
189
+ ### RNNLayoutNode
190
+ Parses JSON layout from JavaScript:
191
+ - Determines type via predicates: `isComponent`, `isStack`, `isTabs`, etc.
192
+ - Holds `type`, `nodeId`, `data` (options), `children`
193
+
194
+ ### RNNViewControllerFactory
195
+ Creates view controllers from RNNLayoutNode:
196
+ - `createStack:` → RNNStackController
197
+ - `createBottomTabs:` → RNNBottomTabsController
198
+ - `createComponent:` → RNNComponentViewController
199
+ - `createSideMenu:` → RNNSideMenuViewController
200
+
201
+ ## RNNLayoutProtocol
202
+
203
+ Protocol all navigation controllers implement:
204
+
205
+ ```objc
206
+ @protocol RNNLayoutProtocol
207
+ - (instancetype)initWithLayoutInfo:(RNNLayoutInfo*)layoutInfo
208
+ creator:(id<RNNComponentViewCreator>)creator
209
+ options:(RNNNavigationOptions*)options
210
+ defaultOptions:(RNNNavigationOptions*)defaultOptions
211
+ presenter:(RNNBasePresenter*)presenter
212
+ eventEmitter:(RNNEventEmitter*)eventEmitter
213
+ childViewControllers:(NSArray*)childViewControllers;
214
+
215
+ - (void)render;
216
+ - (UIViewController*)getCurrentChild;
217
+ - (void)mergeOptions:(RNNNavigationOptions*)options;
218
+ - (RNNNavigationOptions*)resolveOptions;
219
+ - (void)setDefaultOptions:(RNNNavigationOptions*)defaultOptions;
220
+ - (void)onChildWillAppear;
221
+ - (void)readyForPresentation;
222
+ - (CGFloat)getTopBarHeight;
223
+ - (CGFloat)getBottomTabsHeight;
224
+ @end
225
+ ```
226
+
227
+ Additional methods provided via `UIViewController+LayoutProtocol` category:
228
+ - `destroy`, `topMostViewController`, `stack`
229
+ - `componentWillAppear`, `componentDidAppear`, `componentDidDisappear`
230
+ - `screenPopped`, `prepareForTransition`
231
+ - `resolveOptionsWithDefault`, `mergeChildOptions:child:`
232
+
233
+ ## Presenter Pattern
234
+
235
+ Each view controller type has a corresponding presenter that applies options:
236
+
237
+ | Controller | Presenter |
238
+ |------------|-----------|
239
+ | RNNComponentViewController | RNNComponentPresenter |
240
+ | RNNStackController | RNNStackPresenter + TopBarPresenter |
241
+ | RNNBottomTabsController | RNNBottomTabsPresenter + BottomTabPresenter |
242
+ | RNNSideMenuViewController | RNNSideMenuPresenter |
243
+ | RNNSplitViewController | RNNSplitViewControllerPresenter |
244
+
245
+ ### RNNBasePresenter
246
+ Base class with lifecycle methods:
247
+ - `applyOptionsOnInit:` - Initial setup
248
+ - `applyOptions:` - Apply current options
249
+ - `mergeOptions:resolvedOptions:` - Runtime updates
250
+ - `componentWillAppear`, `componentDidAppear`, `componentDidDisappear`
251
+
252
+ ## React View Integration
253
+
254
+ ### RNNReactView
255
+ Wraps RCTRootView (legacy) or RCTSurfaceHostingView (new architecture):
256
+ - Implements `RNNComponentProtocol`
257
+ - Manages `componentId`, `componentType`, `moduleName`
258
+ - Lifecycle: `componentWillAppear`, `componentDidAppear`, `componentDidDisappear`
259
+
260
+ ### RNNReactRootViewCreator
261
+ Creates RNNReactView instances:
262
+ - Supports component types: Component, TopBarTitle, TopBarButton, TopBarBackground
263
+ - Handles size flexibility for flexible layouts
264
+
265
+ ### RNNReactComponentRegistry
266
+ Caches created React component instances:
267
+ - `createComponentIfNotExists:parentComponentId:componentType:reactViewReadyBlock:`
268
+ - `removeComponent:`, `clearComponentsForParentId:`
269
+
270
+ ## Options System
271
+
272
+ ### RNNNavigationOptions
273
+ Master options object containing all configuration:
274
+
275
+ ```objc
276
+ @interface RNNNavigationOptions : RNNOptions
277
+ @property RNNTopBarOptions* topBar;
278
+ @property RNNBottomTabsOptions* bottomTabs;
279
+ @property RNNBottomTabOptions* bottomTab;
280
+ @property RNNTopTabsOptions* topTabs;
281
+ @property RNNSideMenuOptions* sideMenu;
282
+ @property RNNOverlayOptions* overlay;
283
+ @property RNNAnimationsOptions* animations;
284
+ @property RNNStatusBarOptions* statusBar;
285
+ @property RNNLayoutOptions* layout;
286
+ @property RNNModalOptions* modal;
287
+ @property RNNPreviewOptions* preview;
288
+ @property RNNSplitViewOptions* splitView;
289
+ @end
290
+ ```
291
+
292
+ ### Options Resolution
293
+ Options merge in hierarchy:
294
+ 1. Component's own options
295
+ 2. Parent controller options (loop through chain)
296
+ 3. Default options (from `setDefaultOptions`)
297
+
298
+ ## Event Emission
299
+
300
+ ### RNNEventEmitter
301
+ Sends events to JavaScript via RCTEventEmitter:
302
+
303
+ | Event | Method |
304
+ |-------|--------|
305
+ | Component lifecycle | `sendComponentWillAppear:`, `sendComponentDidAppear:`, `sendComponentDidDisappear:` |
306
+ | Button press | `sendOnNavigationButtonPressed:buttonId:` |
307
+ | Command completion | `sendOnNavigationCommandCompletion:commandId:` |
308
+ | Tab events | `sendBottomTabSelected:unselected:`, `sendBottomTabLongPressed:`, `sendBottomTabPressed:` |
309
+ | Modal events | `sendModalsDismissedEvent:numberOfModalsDismissed:`, `sendModalAttemptedToDismissEvent:` |
310
+ | Screen events | `sendScreenPoppedEvent:` |
311
+ | Search | `sendOnSearchBarUpdated:text:isFocused:`, `sendOnSearchBarCancelPressed:` |
312
+ | Preview | `sendOnPreviewCompleted:previewComponentId:` |
313
+
314
+ ### RNNBridgeEventEmitter
315
+ Concrete implementation that sends `onAppLaunched` on initialization.
316
+
317
+ ## Modal & Overlay Management
318
+
319
+ ### RNNModalManager
320
+ - Tracks presented modals array
321
+ - Supports custom transition animations via ScreenAnimationController
322
+ - Handles presentationController delegate for adaptive presentation
323
+
324
+ ### RNNOverlayManager
325
+ - Manages UIWindow instances for overlays
326
+ - Each overlay gets its own RNNOverlayWindow
327
+ - Maintains previous window reference for restoration
328
+ - Controls window level and accessibility
329
+
330
+ ## Animation System
331
+
332
+ ### ScreenAnimationController
333
+ Implements `UIViewControllerAnimatedTransitioning`:
334
+ - Custom push/pop/modal transitions
335
+ - Content transitions (RNNEnterExitAnimation)
336
+ - Element transitions (ElementTransitionOptions)
337
+ - Shared element transitions (SharedElementTransitionOptions)
338
+
339
+ ### Element Animators
340
+ - `ElementAnimator` - Individual element animations
341
+ - `SharedElementAnimator` - Cross-screen shared elements
342
+ - Transition types: Alpha, Scale, Translation, Frame, Bounds, Color, CornerRadius
343
+
344
+ ### RNNSetRootAnimator
345
+ Animates window root replacement using CABasicAnimation.
346
+
347
+ ## Navigation Types
348
+
349
+ ### Stack Navigation (RNNStackController)
350
+ - Subclass of UINavigationController
351
+ - Push/pop with custom animations
352
+ - Back button customization
353
+ - Uses StackControllerDelegate for bar delegate handling
354
+
355
+ ```objc
356
+ // Extension methods
357
+ @interface UINavigationController (RNNCommands)
358
+ - (void)push:(UIViewController*)vc onTop:(UIViewController*)onTopVC
359
+ animated:(BOOL)animated completion:(void(^)(void))completion rejection:(RCTPromiseRejectBlock)rejection;
360
+ - (void)popAnimated:(BOOL)animated completion:(void(^)(NSString*))completion rejection:(RCTPromiseRejectBlock)rejection;
361
+ @end
362
+ ```
363
+
364
+ ### Bottom Tabs (RNNBottomTabsController)
365
+ - Subclass of UITabBarController
366
+ - Tab attachment modes: Together, OnSwitchToTab, AfterInitialTab
367
+ - Long-press gesture support
368
+ - Badge and dot indicator support
369
+
370
+ ### Side Menu (RNNSideMenuViewController)
371
+ - Uses MMDrawerController (third-party)
372
+ - Center, left, right child containers
373
+ - Configurable open modes and widths
374
+
375
+ ### Top Tabs (RNNTopTabsViewController)
376
+ - Custom horizontal tab implementation
377
+ - Not based on UITabBarController
378
+ - Manual content switching
379
+
380
+ ### Split View (RNNSplitViewController)
381
+ - UISplitViewController subclass
382
+ - Master-detail for iPad
383
+
384
+ ## External Components
385
+
386
+ ### RNNExternalComponentStore
387
+ Registry for native (non-React) view controllers.
388
+
389
+ ### RNNExternalViewController
390
+ Wraps native UIViewController for integration:
391
+
392
+ ```objc
393
+ [ReactNativeNavigation registerExternalComponent:@"NativeScreen"
394
+ callback:^(NSDictionary *props, RCTBridge *bridge) {
395
+ return [[MyNativeViewController alloc] init];
396
+ }];
397
+ ```
398
+
399
+ ## Key Files Reference
400
+
401
+ | File | Purpose |
402
+ |------|---------|
403
+ | `RNNBridgeModule.h/mm` | Bridge entry point (legacy) |
404
+ | `TurboModules/RNNTurboModule.mm` | TurboModule entry point (new arch) |
405
+ | `TurboModules/RNNTurboCommandsHandler.mm` | TurboModule command routing |
406
+ | `RNNCommandsHandler.h/mm` | Command execution |
407
+ | `RNNLayoutManager.h/mm` | Controller tracking |
408
+ | `RNNViewControllerFactory.h/mm` | Controller creation |
409
+ | `RNNComponentViewController.h/mm` | React screen |
410
+ | `RNNStackController.h/mm` | Stack navigation |
411
+ | `RNNBottomTabsController.h/mm` | Tab navigation |
412
+ | `RNNNavigationOptions.h/mm` | Options model |
413
+ | `RNNBasePresenter.h/mm` | Presenter base |
414
+ | `TopBarPresenter.h/mm` | Top bar styling |
415
+ | `RNNReactView.h/mm` | React view wrapper |
416
+ | `ScreenAnimationController.h/mm` | Custom transitions |
@@ -8,7 +8,38 @@
8
8
  [bottomTabsController readyForPresentation];
9
9
  for (UIViewController *viewController in bottomTabsController.deselectedViewControllers) {
10
10
  dispatch_async(dispatch_get_main_queue(), ^{
11
+ UIWindow *preloadWindow = [[UIWindow alloc] initWithFrame:CGRectZero];
12
+ preloadWindow.hidden = NO;
13
+
14
+ dispatch_group_t ready = dispatch_group_create();
15
+ dispatch_group_enter(ready);
16
+
17
+ viewController.waitForRender = YES;
18
+
19
+ [viewController setReactViewReadyCallback:^{
20
+ dispatch_group_leave(ready);
21
+ }];
22
+
11
23
  [viewController render];
24
+
25
+ UIView *containerView = nil;
26
+ UIView *reactView = nil;
27
+ if ([viewController isKindOfClass:[UINavigationController class]]) {
28
+ containerView = [(UINavigationController *)viewController topViewController].view;
29
+ reactView = containerView.subviews.firstObject;
30
+ }
31
+
32
+ if (reactView && !reactView.window) {
33
+ [preloadWindow addSubview:reactView];
34
+ }
35
+
36
+ dispatch_notify(ready, dispatch_get_main_queue(), ^{
37
+ if (reactView) {
38
+ reactView.frame = containerView.bounds;
39
+ [containerView addSubview:reactView];
40
+ }
41
+ preloadWindow.hidden = YES;
42
+ });
12
43
  });
13
44
  }
14
45
  }];
@@ -7,6 +7,11 @@
7
7
  #pragma mark - public
8
8
 
9
9
  - (void)applyBackgroundColor:(UIColor *)backgroundColor translucent:(BOOL)translucent {
10
+ if (@available(iOS 26.0, *)) {
11
+ [self setTabBarTransparentBackground];
12
+ self.tabBar.backgroundColor = UIColor.clearColor;
13
+ return;
14
+ }
10
15
  if (translucent)
11
16
  [self setTabBarTranslucent:YES];
12
17
  else if (backgroundColor.isTransparent)
@@ -19,26 +24,33 @@
19
24
 
20
25
  - (void)applyTabBarBorder:(RNNBottomTabsOptions *)options {
21
26
  if (options.borderColor.hasValue || options.borderWidth.hasValue) {
22
- for (UIViewController *childViewController in self.tabBarController.childViewControllers)
23
- childViewController.tabBarItem.standardAppearance.shadowImage = [UIImage
24
- imageWithSize:CGSizeMake(1.0, [[options.borderWidth withDefault:@(0.1)] floatValue])
25
- color:[options.borderColor withDefault:UIColor.blackColor]];
27
+ UIImage *borderImage = [UIImage
28
+ imageWithSize:CGSizeMake(1.0, [[options.borderWidth withDefault:@(0.1)] floatValue])
29
+ color:[options.borderColor withDefault:UIColor.blackColor]];
30
+
31
+ for (UIViewController *childViewController in self.tabBarController.childViewControllers) {
32
+ childViewController.tabBarItem.standardAppearance.shadowImage = borderImage;
33
+ #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 150000
34
+ if (@available(iOS 15.0, *)) {
35
+ childViewController.tabBarItem.scrollEdgeAppearance.shadowImage = borderImage;
36
+ }
37
+ #endif
38
+ }
26
39
  }
27
40
  }
28
41
 
29
42
  - (void)setTabBarBackgroundColor:(UIColor *)backgroundColor {
30
- [self setTabBarOpaqueBackground];
31
- for (UIViewController *childViewController in self.tabBarController.childViewControllers) {
32
- childViewController.tabBarItem.standardAppearance.backgroundColor = backgroundColor;
33
- #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 150000
34
- if (@available(iOS 15.0, *)) {
35
- childViewController.tabBarItem.scrollEdgeAppearance.backgroundColor = backgroundColor;
36
- }
37
- #endif
43
+ UITabBarAppearance *appearance = [self appearanceWithColor:backgroundColor];
44
+ [self applyTabBarAppearance:appearance];
45
+ self.tabBar.barTintColor = backgroundColor;
46
+ self.tabBar.translucent = NO;
47
+ if (@available(iOS 26.0, *)) {
48
+ self.tabBar.backgroundColor = backgroundColor;
38
49
  }
39
50
  }
40
51
 
41
52
  - (void)setTabBarTranslucent:(BOOL)translucent {
53
+ self.tabBar.translucent = translucent;
42
54
  if (translucent)
43
55
  [self setTabBarTranslucentBackground];
44
56
  else
@@ -48,38 +60,63 @@
48
60
  #pragma mark - private
49
61
 
50
62
  - (void)setTabBarDefaultBackground {
51
- [self setTabBarOpaqueBackground];
63
+ if (@available(iOS 26.0, *)) {
64
+ [self setTabBarTransparentBackground];
65
+ self.tabBar.backgroundColor = UIColor.clearColor;
66
+ } else {
67
+ [self setTabBarOpaqueBackground];
68
+ }
52
69
  }
53
70
 
54
71
  - (void)setTabBarTranslucentBackground {
55
- for (UIViewController *childViewController in self.tabBarController.childViewControllers) {
56
- [childViewController.tabBarItem.standardAppearance configureWithDefaultBackground];
57
- #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 150000
58
- if (@available(iOS 15.0, *)) {
59
- [childViewController.tabBarItem.scrollEdgeAppearance configureWithDefaultBackground];
60
- }
61
- #endif
62
- }
72
+ UITabBarAppearance *appearance = [UITabBarAppearance new];
73
+ [appearance configureWithDefaultBackground];
74
+ [self applyTabBarAppearance:appearance];
75
+ self.tabBar.barTintColor = nil;
63
76
  }
64
77
 
65
78
  - (void)setTabBarTransparentBackground {
66
- for (UIViewController *childViewController in self.tabBarController.childViewControllers) {
67
- [childViewController.tabBarItem.standardAppearance configureWithTransparentBackground];
68
- #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 150000
69
- if (@available(iOS 15.0, *)) {
70
- [childViewController.tabBarItem
71
- .scrollEdgeAppearance configureWithTransparentBackground];
72
- }
73
- #endif
74
- }
79
+ UITabBarAppearance *appearance = [UITabBarAppearance new];
80
+ [appearance configureWithTransparentBackground];
81
+ appearance.backgroundEffect = nil;
82
+ appearance.backgroundColor = UIColor.clearColor;
83
+ [self applyTabBarAppearance:appearance];
84
+ self.tabBar.barTintColor = UIColor.clearColor;
75
85
  }
76
86
 
77
87
  - (void)setTabBarOpaqueBackground {
88
+ UITabBarAppearance *appearance = [self appearanceWithColor:nil];
89
+ [self applyTabBarAppearance:appearance];
90
+ self.tabBar.barTintColor = UIColor.systemBackgroundColor;
91
+ self.tabBar.translucent = NO;
92
+ }
93
+
94
+ #pragma mark - helpers
95
+
96
+ - (UITabBarAppearance *)appearanceWithColor:(UIColor *)color {
97
+ UITabBarAppearance *appearance = [UITabBarAppearance new];
98
+ [appearance configureWithOpaqueBackground];
99
+ appearance.backgroundEffect = nil;
100
+ appearance.shadowColor = nil;
101
+ UIColor *resolvedColor = color ?: UIColor.systemBackgroundColor;
102
+ appearance.backgroundColor = resolvedColor;
103
+ appearance.backgroundImage = [UIImage imageWithSize:CGSizeMake(1, 1) color:resolvedColor];
104
+ return appearance;
105
+ }
106
+
107
+ - (void)applyTabBarAppearance:(UITabBarAppearance *)appearance {
108
+ self.tabBar.standardAppearance = appearance;
109
+ #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 150000
110
+ if (@available(iOS 15.0, *)) {
111
+ self.tabBar.scrollEdgeAppearance = [appearance copy];
112
+ }
113
+ #endif
114
+
78
115
  for (UIViewController *childViewController in self.tabBarController.childViewControllers) {
79
- [childViewController.tabBarItem.standardAppearance configureWithOpaqueBackground];
116
+ childViewController.tabBarItem.standardAppearance = [appearance copy];
80
117
  #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 150000
81
118
  if (@available(iOS 15.0, *)) {
82
- [childViewController.tabBarItem.scrollEdgeAppearance configureWithOpaqueBackground];
119
+ childViewController.tabBarItem.scrollEdgeAppearance = [appearance copy];
83
120
  }
84
121
  #endif
85
122
  }
@@ -27,11 +27,12 @@
27
27
  [bottomTabs setTabBarVisible:[withDefault.bottomTabs.visible withDefault:YES]];
28
28
 
29
29
  [bottomTabs.view setBackgroundColor:[withDefault.layout.backgroundColor withDefault:nil]];
30
+ [bottomTabs setTabBarHideShadow:[withDefault.bottomTabs.hideShadow withDefault:NO]];
31
+ if (options.bottomTabs.barStyle.hasValue) {
32
+ [bottomTabs setTabBarStyle:[RNNConvert UIBarStyle:options.bottomTabs.barStyle.get]];
33
+ }
30
34
  [self applyBackgroundColor:[withDefault.bottomTabs.backgroundColor withDefault:nil]
31
35
  translucent:[withDefault.bottomTabs.translucent withDefault:NO]];
32
- [bottomTabs setTabBarHideShadow:[withDefault.bottomTabs.hideShadow withDefault:NO]];
33
- [bottomTabs setTabBarStyle:[RNNConvert UIBarStyle:[withDefault.bottomTabs.barStyle
34
- withDefault:@"default"]]];
35
36
  [self applyTabBarBorder:withDefault.bottomTabs];
36
37
  [self applyTabBarShadow:withDefault.bottomTabs.shadow];
37
38
  }
@@ -65,7 +66,7 @@
65
66
  }
66
67
 
67
68
  if (mergeOptions.bottomTabs.translucent.hasValue) {
68
- [bottomTabs setTabBarTranslucent:mergeOptions.bottomTabs.translucent.get];
69
+ [self setTabBarTranslucent:mergeOptions.bottomTabs.translucent.get];
69
70
  }
70
71
 
71
72
  if (mergeOptions.bottomTabs.hideShadow.hasValue) {
package/ios/RCTHelpers.mm CHANGED
@@ -1,6 +1,8 @@
1
1
  #import "RCTHelpers.h"
2
2
  #import <React/RCTFont.h>
3
+ #if __has_include(<React/RCTScrollView.h>)
3
4
  #import <React/RCTScrollView.h>
5
+ #endif
4
6
  #import <React/RCTView.h>
5
7
 
6
8
  @implementation RCTHelpers
@@ -201,7 +203,7 @@
201
203
  UIView *yelloboxParentView = view;
202
204
  while (view.superview != nil) {
203
205
  yelloboxParentView = yelloboxParentView.superview;
204
- if ([yelloboxParentView isKindOfClass:[RCTScrollView class]]) {
206
+ if ([yelloboxParentView isKindOfClass:NSClassFromString(@"RCTScrollView")]) {
205
207
  yelloboxParentView = yelloboxParentView.superview;
206
208
  break;
207
209
  }
@@ -5,11 +5,17 @@
5
5
 
6
6
  #import "RCTAppSetupUtils.h"
7
7
  #import <React/CoreModulesPlugins.h>
8
+ #if __has_include(<React/RCTCxxBridgeDelegate.h>)
8
9
  #import <React/RCTCxxBridgeDelegate.h>
10
+ #endif
9
11
  #import <React/RCTLegacyViewManagerInteropComponentView.h>
10
12
  #import <React/RCTSurfacePresenter.h>
13
+ #if __has_include(<React/RCTSurfacePresenterStub.h>)
11
14
  #import <React/RCTSurfacePresenterStub.h>
15
+ #endif
16
+ #if __has_include(<React/RCTSurfacePresenterBridgeAdapter.h>)
12
17
  #import <React/RCTSurfacePresenterBridgeAdapter.h>
18
+ #endif
13
19
  #import <ReactCommon/RCTTurboModuleManager.h>
14
20
 
15
21
  #if __has_include(<react/config/ReactNativeConfig.h>)
@@ -19,9 +25,13 @@
19
25
  #import <react/renderer/runtimescheduler/RuntimeScheduler.h>
20
26
  #import <react/renderer/runtimescheduler/RuntimeSchedulerCallInvoker.h>
21
27
  #import <React/RCTSurfacePresenter.h>
28
+ #if __has_include(<React/RCTBridge+Private.h>)
22
29
  #import <React/RCTBridge+Private.h>
30
+ #endif
23
31
  #import <React/RCTImageLoader.h>
32
+ #if __has_include(<React/RCTBridgeProxy.h>)
24
33
  #import <React/RCTBridgeProxy.h>
34
+ #endif
25
35
  #import <React/RCTSurfacePresenter.h>
26
36
  #import <react/utils/ManagedObjectWrapper.h>
27
37