@react-navigation/bottom-tabs 8.0.0-alpha.54 → 8.0.0-alpha.55

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.
package/src/types.tsx CHANGED
@@ -39,8 +39,23 @@ export type BottomTabNavigationEventMap = {
39
39
  *
40
40
  * Preventing default is only supported with `custom` implementation.
41
41
  * Use `tabBarSelectionEnabled: false` option with `native` implementation.
42
- */
43
- tabPress: { data: undefined; canPreventDefault: true };
42
+ *
43
+ * The `data` object contains the following properties:
44
+ * - `origin`: set to `native` when event originated from the native tab bar.
45
+ * - `behavior`: specifies how consumers of the event should handle the tab press:
46
+ * - `scrollToTop`: whether the content should scroll to top.
47
+ * - `popToTop`: whether the nested stack should pop to top.
48
+ */
49
+ tabPress: {
50
+ data: {
51
+ origin?: 'native';
52
+ behavior: {
53
+ scrollToTop: boolean;
54
+ popToTop: boolean;
55
+ };
56
+ };
57
+ canPreventDefault: true;
58
+ };
44
59
  /**
45
60
  * Event which fires on long press on the tab in the tab bar.
46
61
  *
@@ -95,18 +110,22 @@ export type BottomTabOptionsArgs<
95
110
 
96
111
  export type TimingKeyboardAnimationConfig = {
97
112
  animation: 'timing';
98
- config?: Omit<
99
- Partial<Animated.TimingAnimationConfig>,
100
- 'toValue' | 'useNativeDriver'
101
- >;
113
+ config?:
114
+ | Omit<
115
+ Partial<Animated.TimingAnimationConfig>,
116
+ 'toValue' | 'useNativeDriver'
117
+ >
118
+ | undefined;
102
119
  };
103
120
 
104
121
  export type SpringKeyboardAnimationConfig = {
105
122
  animation: 'spring';
106
- config?: Omit<
107
- Partial<Animated.SpringAnimationConfig>,
108
- 'toValue' | 'useNativeDriver'
109
- >;
123
+ config?:
124
+ | Omit<
125
+ Partial<Animated.SpringAnimationConfig>,
126
+ 'toValue' | 'useNativeDriver'
127
+ >
128
+ | undefined;
110
129
  };
111
130
 
112
131
  export type TabBarVisibilityAnimationConfig =
@@ -126,21 +145,21 @@ type BottomTabCustomOptions = {
126
145
  *
127
146
  * Only supported with `custom` implementation.
128
147
  */
129
- animation?: TabAnimationName;
148
+ animation?: TabAnimationName | undefined;
130
149
 
131
150
  /**
132
151
  * Function which specifies interpolated styles for bottom-tab scenes.
133
152
  *
134
153
  * Only supported with `custom` implementation.
135
154
  */
136
- sceneStyleInterpolator?: BottomTabSceneStyleInterpolator;
155
+ sceneStyleInterpolator?: BottomTabSceneStyleInterpolator | undefined;
137
156
 
138
157
  /**
139
158
  * Object which specifies the animation type (timing or spring) and their options (such as duration for timing).
140
159
  *
141
160
  * Only supported with `custom` implementation.
142
161
  */
143
- transitionSpec?: TransitionSpec;
162
+ transitionSpec?: TransitionSpec | undefined;
144
163
 
145
164
  /**
146
165
  * Whether the label is shown below the icon or beside the icon.
@@ -161,7 +180,7 @@ type BottomTabCustomOptions = {
161
180
  *
162
181
  * Only supported with `custom` implementation.
163
182
  */
164
- tabBarAllowFontScaling?: boolean;
183
+ tabBarAllowFontScaling?: boolean | undefined;
165
184
 
166
185
  /**
167
186
  * Style object for the tab item container.
@@ -184,24 +203,26 @@ type BottomTabCustomOptions = {
184
203
  *
185
204
  * Only supported with `custom` implementation.
186
205
  */
187
- tabBarHideOnKeyboard?: boolean;
206
+ tabBarHideOnKeyboard?: boolean | undefined;
188
207
 
189
208
  /**
190
209
  * Animation config for showing and hiding the tab bar when the keyboard is shown/hidden.
191
210
  *
192
211
  * Only supported with `custom` implementation.
193
212
  */
194
- tabBarVisibilityAnimationConfig?: {
195
- show?: TabBarVisibilityAnimationConfig;
196
- hide?: TabBarVisibilityAnimationConfig;
197
- };
213
+ tabBarVisibilityAnimationConfig?:
214
+ | {
215
+ show?: TabBarVisibilityAnimationConfig | undefined;
216
+ hide?: TabBarVisibilityAnimationConfig | undefined;
217
+ }
218
+ | undefined;
198
219
 
199
220
  /**
200
221
  * Variant of the tab bar. Defaults to `uikit`.
201
222
  *
202
223
  * Only supported with `custom` implementation.
203
224
  */
204
- tabBarVariant?: Variant;
225
+ tabBarVariant?: Variant | undefined;
205
226
 
206
227
  /**
207
228
  * Style object for the tab bar container.
@@ -219,28 +240,28 @@ type BottomTabCustomOptions = {
219
240
  *
220
241
  * Only supported with `custom` implementation.
221
242
  */
222
- tabBarBackground?: () => React.ReactNode;
243
+ tabBarBackground?: (() => React.ReactNode) | undefined;
223
244
 
224
245
  /**
225
246
  * Position of the tab bar on the screen. Defaults to `bottom`.
226
247
  *
227
248
  * Only supported with `custom` implementation or if custom tab bar is provided.
228
249
  */
229
- tabBarPosition?: 'bottom' | 'left' | 'right' | 'top';
250
+ tabBarPosition?: 'bottom' | 'left' | 'right' | 'top' | undefined;
230
251
 
231
252
  /**
232
253
  * Background color for the active tab.
233
254
  *
234
255
  * Only supported with `custom` implementation.
235
256
  */
236
- tabBarActiveBackgroundColor?: ColorValue;
257
+ tabBarActiveBackgroundColor?: ColorValue | undefined;
237
258
 
238
259
  /**
239
260
  * Background color for the inactive tabs.
240
261
  *
241
262
  * Only supported with `custom` implementation.
242
263
  */
243
- tabBarInactiveBackgroundColor?: ColorValue;
264
+ tabBarInactiveBackgroundColor?: ColorValue | undefined;
244
265
 
245
266
  /**
246
267
  * Function which returns a React element to render as the tab bar button.
@@ -248,7 +269,9 @@ type BottomTabCustomOptions = {
248
269
  *
249
270
  * Only supported with `custom` implementation.
250
271
  */
251
- tabBarButton?: (props: BottomTabBarButtonProps) => React.ReactNode;
272
+ tabBarButton?:
273
+ | ((props: BottomTabBarButtonProps) => React.ReactNode)
274
+ | undefined;
252
275
  };
253
276
 
254
277
  type BottomTabNativeOptions = {
@@ -262,7 +285,7 @@ type BottomTabNativeOptions = {
262
285
  *
263
286
  * @platform ios
264
287
  */
265
- tabBarSystemItem?: TabsScreenSystemItem;
288
+ tabBarSystemItem?: TabsScreenSystemItem | undefined;
266
289
 
267
290
  /**
268
291
  * Blur effect applied to the tab bar when tab screen is selected.
@@ -284,7 +307,7 @@ type BottomTabNativeOptions = {
284
307
  *
285
308
  * @platform ios
286
309
  */
287
- tabBarBlurEffect?: TabsScreenBlurEffect;
310
+ tabBarBlurEffect?: TabsScreenBlurEffect | undefined;
288
311
 
289
312
  /**
290
313
  * Minimize behavior for the tab bar.
@@ -307,7 +330,12 @@ type BottomTabNativeOptions = {
307
330
  *
308
331
  * @platform ios
309
332
  */
310
- tabBarMinimizeBehavior?: 'auto' | 'none' | 'onScrollDown' | 'onScrollUp';
333
+ tabBarMinimizeBehavior?:
334
+ | 'auto'
335
+ | 'none'
336
+ | 'onScrollDown'
337
+ | 'onScrollUp'
338
+ | undefined;
311
339
 
312
340
  /**
313
341
  * Background color of the active indicator.
@@ -316,7 +344,7 @@ type BottomTabNativeOptions = {
316
344
  *
317
345
  * @platform android
318
346
  */
319
- tabBarActiveIndicatorColor?: ColorValue;
347
+ tabBarActiveIndicatorColor?: ColorValue | undefined;
320
348
 
321
349
  /**
322
350
  * Specifies if the active indicator should be used. Defaults to `true`.
@@ -325,7 +353,7 @@ type BottomTabNativeOptions = {
325
353
  *
326
354
  * @platform android
327
355
  */
328
- tabBarActiveIndicatorEnabled?: boolean;
356
+ tabBarActiveIndicatorEnabled?: boolean | undefined;
329
357
 
330
358
  /**
331
359
  * Function which returns a React element to display as an accessory view.
@@ -343,9 +371,9 @@ type BottomTabNativeOptions = {
343
371
  *
344
372
  * @platform ios
345
373
  */
346
- bottomAccessory?: (options: {
347
- placement: 'regular' | 'inline';
348
- }) => React.ReactNode;
374
+ bottomAccessory?:
375
+ | ((options: { placement: 'regular' | 'inline' }) => React.ReactNode)
376
+ | undefined;
349
377
 
350
378
  /**
351
379
  * Specifies whether `contentInsetAdjustmentBehavior` of the `ScrollView`
@@ -366,14 +394,14 @@ type BottomTabNativeOptions = {
366
394
  *
367
395
  * @platform ios
368
396
  */
369
- overrideScrollViewContentInsetAdjustmentBehavior?: boolean;
397
+ overrideScrollViewContentInsetAdjustmentBehavior?: boolean | undefined;
370
398
  };
371
399
 
372
400
  export type BottomTabNavigationOptions = {
373
401
  /**
374
402
  * Title text for the screen.
375
403
  */
376
- title?: string;
404
+ title?: string | undefined;
377
405
 
378
406
  /**
379
407
  * Title string of the tab displayed in the tab bar
@@ -384,7 +412,7 @@ export type BottomTabNavigationOptions = {
384
412
  * - The system values are used if `tabBarSystemItem` is set on iOS.
385
413
  * - Otherwise, it falls back to the `title` or route name.
386
414
  */
387
- tabBarLabel?: string;
415
+ tabBarLabel?: string | undefined;
388
416
 
389
417
  /**
390
418
  * Label visibility mode for the tab bar items.
@@ -401,15 +429,17 @@ export type BottomTabNavigationOptions = {
401
429
  * Supported on all platforms with `custom` implementation.
402
430
  * Only supported on Android with `native` implementation.
403
431
  */
404
- tabBarLabelVisibilityMode?: TabBarItemLabelVisibilityMode;
432
+ tabBarLabelVisibilityMode?: TabBarItemLabelVisibilityMode | undefined;
405
433
 
406
434
  /**
407
435
  * Style object for the tab label.
408
436
  */
409
- tabBarLabelStyle?: Pick<
410
- TextStyle,
411
- 'fontFamily' | 'fontSize' | 'fontWeight' | 'fontStyle' | 'color'
412
- >;
437
+ tabBarLabelStyle?:
438
+ | Pick<
439
+ TextStyle,
440
+ 'fontFamily' | 'fontSize' | 'fontWeight' | 'fontStyle' | 'color'
441
+ >
442
+ | undefined;
413
443
 
414
444
  /**
415
445
  * Icon to display for the tab.
@@ -430,7 +460,8 @@ export type BottomTabNavigationOptions = {
430
460
  focused: boolean;
431
461
  color: ColorValue;
432
462
  size: number;
433
- }) => Icon | React.ReactNode);
463
+ }) => Icon | React.ReactNode)
464
+ | undefined;
434
465
 
435
466
  /**
436
467
  * Text to show in a badge on the tab icon.
@@ -445,10 +476,12 @@ export type BottomTabNavigationOptions = {
445
476
  * - on iOS, you can only set the background color.
446
477
  * - on Android, you can set both background and text colors.
447
478
  */
448
- tabBarBadgeStyle?: {
449
- backgroundColor?: ColorValue;
450
- color?: ColorValue;
451
- };
479
+ tabBarBadgeStyle?:
480
+ | {
481
+ backgroundColor?: ColorValue | undefined;
482
+ color?: ColorValue | undefined;
483
+ }
484
+ | undefined;
452
485
 
453
486
  /**
454
487
  * Color for the icon and label in the active tab.
@@ -458,14 +491,14 @@ export type BottomTabNavigationOptions = {
458
491
  /**
459
492
  * Color for the icon and label in the inactive tabs.
460
493
  */
461
- tabBarInactiveTintColor?: ColorValue;
494
+ tabBarInactiveTintColor?: ColorValue | undefined;
462
495
 
463
496
  /**
464
497
  * Color of tab bar item's ripple effect.
465
498
  *
466
499
  * @platform android
467
500
  */
468
- tabBarRippleColor?: ColorValue;
501
+ tabBarRippleColor?: ColorValue | undefined;
469
502
 
470
503
  /**
471
504
  * Display mode for the tab bar.
@@ -484,41 +517,43 @@ export type BottomTabNavigationOptions = {
484
517
  * Supported on iOS 18 and above with `native` implementation.
485
518
  * Not supported on tvOS.
486
519
  */
487
- tabBarControllerMode?: 'auto' | 'tabBar' | 'tabSidebar';
520
+ tabBarControllerMode?: 'auto' | 'tabBar' | 'tabSidebar' | undefined;
488
521
 
489
522
  /**
490
523
  * Accessibility label for the tab button. This is read by the screen reader when the user taps the tab.
491
524
  * It's recommended to set this if you don't have a label for the tab.
492
525
  */
493
- tabBarAccessibilityLabel?: string;
526
+ tabBarAccessibilityLabel?: string | undefined;
494
527
 
495
528
  /**
496
529
  * ID to locate this tab button in tests.
497
530
  */
498
- tabBarButtonTestID?: string;
531
+ tabBarButtonTestID?: string | undefined;
499
532
 
500
533
  /**
501
534
  * Style object for the tab bar container.
502
535
  */
503
- tabBarStyle?: {
504
- /**
505
- * Background color of the tab bar.
506
- *
507
- * Only supported on Android and iOS 18 and below.
508
- */
509
- backgroundColor?: ColorValue;
510
- /**
511
- * Shadow color of the tab bar.
512
- *
513
- * Only supported on iOS 18 and below.
514
- */
515
- shadowColor?: ColorValue;
516
- /**
517
- * Whether the tab bar is visible.
518
- * Setting this to `'none'` hides the tab bar.
519
- */
520
- display?: 'flex' | 'none';
521
- };
536
+ tabBarStyle?:
537
+ | {
538
+ /**
539
+ * Background color of the tab bar.
540
+ *
541
+ * Only supported on Android and iOS 18 and below.
542
+ */
543
+ backgroundColor?: ColorValue | undefined;
544
+ /**
545
+ * Shadow color of the tab bar.
546
+ *
547
+ * Only supported on iOS 18 and below.
548
+ */
549
+ shadowColor?: ColorValue | undefined;
550
+ /**
551
+ * Whether the tab bar is visible.
552
+ * Setting this to `'none'` hides the tab bar.
553
+ */
554
+ display?: 'flex' | 'none' | undefined;
555
+ }
556
+ | undefined;
522
557
 
523
558
  /**
524
559
  * Whether this tab can be selected.
@@ -527,7 +562,22 @@ export type BottomTabNavigationOptions = {
527
562
  *
528
563
  * Defaults to `true`.
529
564
  */
530
- tabBarSelectionEnabled?: boolean;
565
+ tabBarSelectionEnabled?: boolean | undefined;
566
+
567
+ /**
568
+ * Behavior when pressing the tab in the tab bar while it's already focused.
569
+ *
570
+ * - `scrollToTop`: scroll the first scroll view in the screen to top
571
+ * - `popToTop`: pop a nested stack to its first screen
572
+ *
573
+ * Both default to `true`. Ignored when `tabBarSelectionEnabled` is `false`.
574
+ */
575
+ tabBarRepeatedPressBehavior?:
576
+ | {
577
+ scrollToTop?: boolean | undefined;
578
+ popToTop?: boolean | undefined;
579
+ }
580
+ | undefined;
531
581
 
532
582
  /**
533
583
  * Whether this screen should render only when first accessed.
@@ -539,13 +589,13 @@ export type BottomTabNavigationOptions = {
539
589
  * Enabling in native implementation may result in flicker
540
590
  * as React renders after native transition is already finished.
541
591
  */
542
- lazy?: boolean;
592
+ lazy?: boolean | undefined;
543
593
 
544
594
  /**
545
595
  * Whether any nested stack should be popped to top when navigating away from the tab.
546
596
  * Defaults to `false`.
547
597
  */
548
- popToTopOnBlur?: boolean; // TODO: handle natively
598
+ popToTopOnBlur?: boolean | undefined; // TODO: handle natively
549
599
 
550
600
  /**
551
601
  * Style object for the component wrapping the screen content.
@@ -555,14 +605,14 @@ export type BottomTabNavigationOptions = {
555
605
  /**
556
606
  * Function that returns a React Element to display as a header.
557
607
  */
558
- header?: (props: BottomTabHeaderProps) => React.ReactNode;
608
+ header?: ((props: BottomTabHeaderProps) => React.ReactNode) | undefined;
559
609
 
560
610
  /**
561
611
  * Whether to show the header.
562
612
  *
563
613
  * Defaults to `false` unless a header is provided.
564
614
  */
565
- headerShown?: boolean;
615
+ headerShown?: boolean | undefined;
566
616
 
567
617
  /**
568
618
  * What should happen when screens become inactive.
@@ -575,7 +625,7 @@ export type BottomTabNavigationOptions = {
575
625
  * It won't be paused until after the first time it becomes focused.
576
626
  * This makes sure that effects are run to initialize the screen.
577
627
  */
578
- inactiveBehavior?: 'pause' | 'none';
628
+ inactiveBehavior?: 'pause' | 'none' | undefined;
579
629
  } & HeaderOptions &
580
630
  BottomTabNativeOptions &
581
631
  BottomTabCustomOptions;
@@ -660,12 +710,12 @@ export type BottomTabNavigationConfig = {
660
710
  *
661
711
  * On other platforms, it's always `custom` and this option has no effect.
662
712
  */
663
- implementation?: 'native' | 'custom';
713
+ implementation?: 'native' | 'custom' | undefined;
664
714
 
665
715
  /**
666
716
  * Function that returns a React element to display as the tab bar.
667
717
  */
668
- tabBar?: (props: BottomTabBarProps) => React.ReactNode;
718
+ tabBar?: ((props: BottomTabBarProps) => React.ReactNode) | undefined;
669
719
  };
670
720
 
671
721
  export type BottomTabHeaderProps = {
@@ -696,9 +746,13 @@ export type BottomTabBarButtonProps = Omit<
696
746
  href?: string | undefined;
697
747
  children: React.ReactNode;
698
748
  style?: StyleProp<ViewStyle>;
699
- onPress?: (
700
- e: React.MouseEvent<HTMLAnchorElement, MouseEvent> | GestureResponderEvent
701
- ) => void;
749
+ onPress?:
750
+ | ((
751
+ e:
752
+ | React.MouseEvent<HTMLAnchorElement, MouseEvent>
753
+ | GestureResponderEvent
754
+ ) => void)
755
+ | undefined;
702
756
  };
703
757
 
704
758
  export type BottomTabNavigatorProps = DefaultNavigatorOptions<
@@ -438,10 +438,23 @@ export function BottomTabBar({ state, navigation, descriptors, style }: Props) {
438
438
  const { options } = descriptor;
439
439
 
440
440
  const onPress = () => {
441
+ const isRepeatedPress =
442
+ focused && options.tabBarSelectionEnabled !== false;
443
+
441
444
  const event = navigation.emit({
442
445
  type: 'tabPress',
443
446
  target: route.key,
444
447
  canPreventDefault: true,
448
+ data: {
449
+ behavior: {
450
+ scrollToTop:
451
+ isRepeatedPress &&
452
+ options.tabBarRepeatedPressBehavior?.scrollToTop !== false,
453
+ popToTop:
454
+ isRepeatedPress &&
455
+ options.tabBarRepeatedPressBehavior?.popToTop !== false,
456
+ },
457
+ },
445
458
  });
446
459
 
447
460
  if (
@@ -7,7 +7,6 @@ import {
7
7
  import {
8
8
  CommonActions,
9
9
  MaterialSymbol,
10
- NavigationMetaContext,
11
10
  type ParamListBase,
12
11
  type Route,
13
12
  StackActions,
@@ -89,10 +88,6 @@ const ICON_SIZE = Platform.select({
89
88
  default: 24,
90
89
  });
91
90
 
92
- const meta = {
93
- type: 'native-tabs',
94
- };
95
-
96
91
  function reducer(state: NativeState, action: NativeAction): NativeState {
97
92
  switch (action.type) {
98
93
  case 'TRACK_TRANSITION':
@@ -214,7 +209,8 @@ export function BottomTabViewNative({
214
209
  // JS sends a requested tab with the native provenance it was based on.
215
210
  // Native replies with the selected tab and its new provenance.
216
211
  const onTabSelected = (event: NativeSyntheticEvent<TabSelectedEvent>) => {
217
- const { selectedScreenKey, provenance, actionOrigin } = event.nativeEvent;
212
+ const { selectedScreenKey, provenance, actionOrigin, isRepeated } =
213
+ event.nativeEvent;
218
214
 
219
215
  const confirmed = {
220
216
  routeKey: selectedScreenKey,
@@ -232,10 +228,22 @@ export function BottomTabViewNative({
232
228
  }
233
229
 
234
230
  if (actionOrigin === 'user') {
231
+ const { tabBarRepeatedPressBehavior } =
232
+ descriptors[route.key]?.options ?? {};
233
+
235
234
  const event = navigation.emit({
236
235
  type: 'tabPress',
237
236
  target: route.key,
238
237
  canPreventDefault: true,
238
+ data: {
239
+ origin: 'native',
240
+ behavior: {
241
+ scrollToTop:
242
+ isRepeated && tabBarRepeatedPressBehavior?.scrollToTop !== false,
243
+ popToTop:
244
+ isRepeated && tabBarRepeatedPressBehavior?.popToTop !== false,
245
+ },
246
+ },
239
247
  });
240
248
 
241
249
  if (event.defaultPrevented) {
@@ -311,6 +319,13 @@ export function BottomTabViewNative({
311
319
  type: 'tabPress',
312
320
  target: preventedScreenKey,
313
321
  canPreventDefault: true,
322
+ data: {
323
+ origin: 'native',
324
+ behavior: {
325
+ scrollToTop: false,
326
+ popToTop: false,
327
+ },
328
+ },
314
329
  });
315
330
  };
316
331
 
@@ -482,6 +497,7 @@ export function BottomTabViewNative({
482
497
  inactiveBehavior = 'pause',
483
498
  tabBarLabel,
484
499
  tabBarSelectionEnabled,
500
+ tabBarRepeatedPressBehavior,
485
501
  tabBarBadgeStyle,
486
502
  tabBarIcon,
487
503
  tabBarBadge,
@@ -594,8 +610,9 @@ export function BottomTabViewNative({
594
610
  nativeContainerStyle={{ backgroundColor: colors.background }}
595
611
  specialEffects={{
596
612
  repeatedTabSelection: {
597
- popToRoot: true,
598
- scrollToTop: true,
613
+ popToRoot: tabBarRepeatedPressBehavior?.popToTop !== false,
614
+ scrollToTop:
615
+ tabBarRepeatedPressBehavior?.scrollToTop !== false,
599
616
  },
600
617
  }}
601
618
  android={{
@@ -680,9 +697,7 @@ export function BottomTabViewNative({
680
697
  >
681
698
  <AnimatedScreenContent isFocused={isFocused}>
682
699
  <BottomTabBarHeightContext.Provider value={0}>
683
- <NavigationMetaContext.Provider value={meta}>
684
- {render()}
685
- </NavigationMetaContext.Provider>
700
+ {render()}
686
701
  </BottomTabBarHeightContext.Provider>
687
702
  </AnimatedScreenContent>
688
703
  </ScreenContent>