Skip to content
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion docs/docusaurus.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ const config = {
Banner: 'Banner',
BottomNavigation: {
BottomNavigation: 'BottomNavigation/BottomNavigation',
BottomNavigationBar: 'BottomNavigation/BottomNavigationBar',
},
Button: {
Button: 'Button/Button',
Expand Down Expand Up @@ -148,6 +147,9 @@ const config = {
MenuItem: 'Menu/MenuItem',
},
Modal: 'Modal',
NavigationBar: {
NavigationBar: 'NavigationBar/NavigationBar',
},
Comment on lines 86 to +152

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the BottomNavigation component still needed? it'd be inconsistent to have a mix of old and new APIs

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kept intentionally. BottomNavigation is the router-integrated scene component (owns tab screens + transitions); NavigationBar is the standalone bar for use with React Navigation's own navigator — same layering split as React Navigation itself, so it isn't an old-vs-new API mix. Every deprecation/alias is gone (13d34e9), so there's no MD2 surface remaining.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kept intentionally. BottomNavigation is the router-integrated scene component (owns tab screens + transitions); NavigationBar is the standalone bar for use with

then the naming is inconsistent. both should use the same naming scheme.

Portal: {
Portal: 'Portal/Portal',
PortalHost: 'Portal/PortalHost',
Expand Down
2 changes: 2 additions & 0 deletions example/src/ExampleList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import ListAccordionExampleGroup from './Examples/ListAccordionGroupExample';
import ListItemExample from './Examples/ListItemExample';
import ListSectionExample from './Examples/ListSectionExample';
import MenuExample from './Examples/MenuExample';
import NavigationBarExample from './Examples/NavigationBarExample';
import ProgressBarExample from './Examples/ProgressBarExample';
import RadioButtonExample from './Examples/RadioButtonExample';
import RadioButtonGroupExample from './Examples/RadioButtonGroupExample';
Expand Down Expand Up @@ -72,6 +73,7 @@ export const mainExamples = {
ListSection: ListSectionExample,
ListItem: ListItemExample,
Menu: MenuExample,
NavigationBar: NavigationBarExample,
Progressbar: ProgressBarExample,
Radio: RadioButtonExample,
RadioGroup: RadioButtonGroupExample,
Expand Down
108 changes: 108 additions & 0 deletions example/src/Examples/NavigationBarExample.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import * as React from 'react';
import { StyleSheet, View, useWindowDimensions } from 'react-native';

import {
NavigationBar,
SegmentedButtons,
Switch,
Text,
} from 'react-native-paper';

type VariantMode = 'auto' | 'stacked' | 'horizontal';

// The flexible navigation bar switches to a horizontal item arrangement in
// medium-width windows. M3 recommends ~600dp as the breakpoint, but the
// component leaves the decision to the consumer — here it is driven by
// `useWindowDimensions`.
const MEDIUM_WINDOW_WIDTH = 600;

const routes = [
{ key: 'album', title: 'Album', focusedIcon: 'image-album', badge: 3 },
{ key: 'library', title: 'Library', focusedIcon: 'bookshelf' },
{
key: 'favorites',
title: 'Favorites',
focusedIcon: 'heart',
unfocusedIcon: 'heart-outline',
},
{
key: 'settings',
title: 'Settings',
focusedIcon: 'cog',
unfocusedIcon: 'cog-outline',
},
];

const NavigationBarExample = () => {
const [index, setIndex] = React.useState(0);
const [labeled, setLabeled] = React.useState(true);
const [variantMode, setVariantMode] = React.useState<VariantMode>('auto');

const { width } = useWindowDimensions();
const autoVariant = width >= MEDIUM_WINDOW_WIDTH ? 'horizontal' : 'stacked';
const variant = variantMode === 'auto' ? autoVariant : variantMode;

return (
<View style={styles.container}>
<View style={styles.content}>
<Text variant="headlineSmall">{routes[index].title}</Text>

<View style={styles.controls}>
<View style={styles.row}>
<Text variant="labelLarge">Show labels</Text>
<Switch value={labeled} onValueChange={setLabeled} />
</View>

<SegmentedButtons
value={variantMode}
onValueChange={(value) => setVariantMode(value as VariantMode)}
buttons={[
{ value: 'auto', label: `Auto (${autoVariant})` },
{ value: 'stacked', label: 'Stacked' },
{ value: 'horizontal', label: 'Horizontal' },
]}
/>
</View>
</View>

<NavigationBar
navigationState={{ index, routes }}
labeled={labeled}
variant={variant}
onTabPress={({ route }) => {
const nextIndex = routes.findIndex((r) => r.key === route.key);
if (nextIndex !== -1) {
setIndex(nextIndex);
}
}}
/>
</View>
);
};

NavigationBarExample.title = 'Navigation Bar (flexible)';

export default NavigationBarExample;

const styles = StyleSheet.create({
container: {
flex: 1,
},
content: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 16,
},
controls: {
marginTop: 32,
width: '100%',
maxWidth: 480,
gap: 24,
},
row: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
},
});
26 changes: 10 additions & 16 deletions src/components/BottomNavigation/BottomNavigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,10 @@ type TouchableProps<Route extends BaseRoute> = TouchableRippleProps & {

export type Props<Route extends BaseRoute> = {
/**
* Whether the shifting style is used, the active tab icon shifts up to show the label and the inactive tabs won't have a label.
*
* By default, this is `false` with theme version 3 and `true` when you have more than 3 tabs.
* Pass `shifting={false}` to explicitly disable this animation, or `shifting={true}` to always use this animation.
* Note that you need at least 2 tabs be able to run this animation.
* @deprecated The `shifting` style is a Material Design 2 pattern that is not
* part of Material Design 3 and no longer has any effect. It will be removed
* in a future version. To animate scene transitions, use `sceneAnimationType`
* and `sceneAnimationEnabled` instead.
*/
shifting?: boolean;
/**
Expand Down Expand Up @@ -261,7 +260,7 @@ const SceneComponent = React.memo(({ component, ...rest }: any) =>

/**
* BottomNavigation provides quick navigation between top-level views of an app with a bottom navigation bar.
* It is primarily designed for use on mobile. If you want to use the navigation bar only see [`BottomNavigation.Bar`](BottomNavigationBar).
* It is primarily designed for use on mobile. If you want to use the navigation bar only see [`NavigationBar`](../NavigationBar).
*
* By default BottomNavigation uses primary color as a background, in dark theme with `adaptive` mode it will use surface colour instead.
* See [Dark Theme](https://callstack.github.io/react-native-paper/docs/guides/theming#dark-theme) for more information.
Expand Down Expand Up @@ -330,7 +329,6 @@ const BottomNavigation = <Route extends BaseRoute>({
onTabPress,
onTabLongPress,
onIndexChange,
shifting: shiftingProp,
safeAreaInsets,
labelMaxFontSizeMultiplier = 1,
compact: compactProp,
Expand All @@ -341,14 +339,6 @@ const BottomNavigation = <Route extends BaseRoute>({
const theme = useInternalTheme(themeOverrides);
const { scale } = theme.animation;
const compact = compactProp ?? false;
let shifting = shiftingProp ?? false;

if (shifting && navigationState.routes.length < 2) {
shifting = false;
console.warn(
'BottomNavigation needs at least 2 tabs to run shifting animation'
);
}

const focusedKey = navigationState.routes[navigationState.index].key;

Expand Down Expand Up @@ -574,7 +564,6 @@ const BottomNavigation = <Route extends BaseRoute>({
animationEasing={sceneAnimationEasing}
onTabPress={handleTabPress}
onTabLongPress={onTabLongPress}
shifting={shifting}
safeAreaInsets={safeAreaInsets}
labelMaxFontSizeMultiplier={labelMaxFontSizeMultiplier}
compact={compact}
Expand Down Expand Up @@ -612,6 +601,11 @@ BottomNavigation.SceneMap = <Route extends BaseRoute>(scenes: {
);
};

/**
* @deprecated Use the top-level `NavigationBar` export instead.
* `BottomNavigation.Bar` is the M3 "original" navigation bar, superseded by the
* flexible `NavigationBar`. Kept as an alias for backwards compatibility.
*/

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved in 13d34e9 — the deprecation block is removed; BottomNavigation renders NavigationBar directly.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There shouldn't be any deprecations. Remove any old code entirely

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 13d34e9 — removed the BottomNavigation.Bar alias, the BottomNavigationBar module, and the dead no-op shifting prop. No deprecated surface left.

// @component ./BottomNavigationBar.tsx
BottomNavigation.Bar = BottomNavigationBar;

Expand Down
Loading
Loading