Skip to content

Commit 425aea5

Browse files
authored
feat: introduce scene style (#412)
1 parent 29353c9 commit 425aea5

File tree

7 files changed

+48
-2
lines changed

7 files changed

+48
-2
lines changed

.changeset/rotten-zebras-admire.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'react-native-bottom-tabs': patch
3+
'@bottom-tabs/react-navigation': patch
4+
---
5+
6+
feat: introduce scene style

docs/docs/docs/guides/standalone-usage.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ Each route in the `routes` array can have the following properties:
213213
- `lazy`: Whether to lazy load this tab's content
214214
- `freezeOnBlur`: Whether to freeze the tab's content when it's not visible
215215
- `role`: A value that defines the purpose of the tab
216+
- `style`: Style object for the component wrapping the screen content
216217

217218
### Helper Props
218219

@@ -267,3 +268,9 @@ Function to get the test ID for a tab item.
267268
Function to get the role for a tab item.
268269

269270
- Default: Uses `route.role`
271+
272+
#### `getSceneStyle`
273+
274+
Function to get the style for a tab scene.
275+
276+
- Default: Uses `route.style`

docs/docs/docs/guides/usage-with-react-navigation.mdx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,20 @@ Available options:
334334

335335
- `search` - The search role.
336336

337+
#### `sceneStyle`
338+
339+
Style object for the component wrapping the screen content.
340+
341+
```tsx
342+
<Tab.Screen
343+
name="Home"
344+
component={HomeScreen}
345+
options={{
346+
sceneStyle: { backgroundColor: 'red' },
347+
}}
348+
/>
349+
```
350+
337351
### Events
338352

339353
The navigator can emit events on certain actions. Supported events are:

packages/react-native-bottom-tabs/src/TabView.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ import {
1010
type DimensionValue,
1111
Image,
1212
Platform,
13+
type StyleProp,
1314
StyleSheet,
1415
View,
16+
type ViewStyle,
1517
processColor,
1618
} from 'react-native';
1719
import { BottomTabBarHeightContext } from './utils/BottomTabBarHeightContext';
@@ -139,6 +141,11 @@ interface Props<Route extends BaseRoute> {
139141
*/
140142
getFreezeOnBlur?: (props: { route: Route }) => boolean | undefined;
141143

144+
/**
145+
* Get style for the scene, uses `route.style` by default.
146+
*/
147+
getSceneStyle?: (props: { route: Route }) => StyleProp<ViewStyle>;
148+
142149
tabBarStyle?: {
143150
/**
144151
* Background color of the tab bar.
@@ -196,6 +203,7 @@ const TabView = <Route extends BaseRoute>({
196203
getActiveTintColor = ({ route }: { route: Route }) => route.activeTintColor,
197204
getTestID = ({ route }: { route: Route }) => route.testID,
198205
getRole = ({ route }: { route: Route }) => route.role,
206+
getSceneStyle = ({ route }: { route: Route }) => route.style,
199207
hapticFeedbackEnabled = false,
200208
// Android's native behavior is to show labels when there are less than 4 tabs. We leave it as undefined to use the platform default behavior.
201209
labeled = Platform.OS !== 'android' ? true : undefined,
@@ -374,12 +382,15 @@ const TabView = <Route extends BaseRoute>({
374382
const focused = route.key === focusedKey;
375383
const freeze = !focused ? getFreezeOnBlur({ route }) : false;
376384

385+
const customStyle = getSceneStyle({ route });
386+
377387
return (
378388
<View
379389
key={route.key}
380390
style={[
381391
styles.screen,
382392
renderCustomTabBar ? styles.fullWidth : measuredDimensions,
393+
customStyle,
383394
]}
384395
collapsable={false}
385396
pointerEvents={focused ? 'auto' : 'none'}

packages/react-native-bottom-tabs/src/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { ImageSourcePropType } from 'react-native';
1+
import type { ImageSourcePropType, StyleProp, ViewStyle } from 'react-native';
22
import type { SFSymbol } from 'sf-symbols-typescript';
33

44
export type IconSource = string | ImageSourcePropType;
@@ -19,6 +19,7 @@ export type BaseRoute = {
1919
testID?: string;
2020
role?: TabRole;
2121
freezeOnBlur?: boolean;
22+
style?: StyleProp<ViewStyle>;
2223
};
2324

2425
export type NavigationState<Route extends BaseRoute> = {

packages/react-navigation/src/types.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import type {
77
TabActionHelpers,
88
TabNavigationState,
99
} from '@react-navigation/native';
10-
import type { ImageSourcePropType } from 'react-native';
10+
import type { ImageSourcePropType, StyleProp, ViewStyle } from 'react-native';
1111
import type TabView from 'react-native-bottom-tabs';
1212
import type { AppleIcon, TabRole } from 'react-native-bottom-tabs';
1313

@@ -101,6 +101,11 @@ export type NativeBottomTabNavigationOptions = {
101101
* Whether inactive screens should be suspended from re-rendering. Defaults to `false`.
102102
*/
103103
freezeOnBlur?: boolean;
104+
105+
/**
106+
* Style object for the component wrapping the screen content.
107+
*/
108+
sceneStyle?: StyleProp<ViewStyle>;
104109
};
105110

106111
export type NativeBottomTabDescriptor = Descriptor<
@@ -139,6 +144,7 @@ export type NativeBottomTabNavigationConfig = Partial<
139144
| 'getRole'
140145
| 'tabBar'
141146
| 'getFreezeOnBlur'
147+
| 'getSceneStyle'
142148
>
143149
> & {
144150
tabBar?: (props: BottomTabBarProps) => React.ReactNode;

packages/react-navigation/src/views/NativeBottomTabView.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ export default function NativeBottomTabView({
6767
getFreezeOnBlur={({ route }) =>
6868
descriptors[route.key]?.options.freezeOnBlur
6969
}
70+
getSceneStyle={({ route }) => descriptors[route.key]?.options.sceneStyle}
7071
onTabLongPress={(index) => {
7172
const route = state.routes[index];
7273
if (!route) {

0 commit comments

Comments
 (0)