Skip to content

Commit

Permalink
feat: add direction prop to TabView (#11322)
Browse files Browse the repository at this point in the history
**Motivation**

Goal of this PR is to add direction prop to unify usage of RTL layouts
across packages.

**Test plan**

Turn ON / OFF RTL in example app.
  • Loading branch information
okwasniewski committed Sep 4, 2023
1 parent 8309636 commit 46735a3
Show file tree
Hide file tree
Showing 12 changed files with 92 additions and 25 deletions.
4 changes: 4 additions & 0 deletions example/src/Screens/TabView/AutoWidthTabBar.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useLocale } from '@react-navigation/native';
import * as React from 'react';
import { StyleSheet } from 'react-native';
import {
Expand Down Expand Up @@ -28,6 +29,7 @@ const renderScene = SceneMap({
});

export const AutoWidthTabBar = () => {
const { direction } = useLocale();
const [index, onIndexChange] = React.useState(1);
const [routes] = React.useState([
{ key: 'article', title: 'Article' },
Expand All @@ -50,6 +52,7 @@ export const AutoWidthTabBar = () => {
labelStyle={styles.label}
tabStyle={styles.tabStyle}
gap={20}
direction={direction}
/>
);

Expand All @@ -59,6 +62,7 @@ export const AutoWidthTabBar = () => {
index,
routes,
}}
direction={direction}
renderScene={renderScene}
renderTabBar={renderTabBar}
onIndexChange={onIndexChange}
Expand Down
5 changes: 4 additions & 1 deletion example/src/Screens/TabView/Coverflow.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable import/no-commonjs */

import { useLocale } from '@react-navigation/native';
import * as React from 'react';
import {
Animated,
Expand Down Expand Up @@ -88,6 +88,8 @@ const Scene = ({ route, position, layout, index, length }: Props) => {
};

export function Coverflow() {
const { direction } = useLocale();

const [index, onIndexChange] = React.useState(2);
const [routes] = React.useState(Object.keys(ALBUMS).map((key) => ({ key })));

Expand All @@ -100,6 +102,7 @@ export function Coverflow() {
index,
routes,
}}
direction={direction}
onIndexChange={onIndexChange}
renderTabBar={() => null}
renderScene={(props: SceneRendererProps & { route: Route }) => (
Expand Down
7 changes: 5 additions & 2 deletions example/src/Screens/TabView/CustomIndicator.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Ionicons } from '@expo/vector-icons';
import { useLocale } from '@react-navigation/native';
import * as React from 'react';
import {
Animated,
I18nManager,
StyleProp,
StyleSheet,
Text,
Expand Down Expand Up @@ -36,6 +36,7 @@ const renderScene = SceneMap({
});

export const CustomIndicator = () => {
const { direction } = useLocale();
const insets = useSafeAreaInsets();
const [index, onIndexChange] = React.useState(0);
const [routes] = React.useState<Route[]>([
Expand Down Expand Up @@ -85,7 +86,7 @@ export const CustomIndicator = () => {
outputRange: inputRange.map((x) => {
const i = Math.round(x);
return (
(i * getTabWidth(i) + i * (gap ?? 0)) * (I18nManager.isRTL ? -1 : 1)
(i * getTabWidth(i) + i * (gap ?? 0)) * (direction === 'rtl' ? -1 : 1)
);
}),
});
Expand Down Expand Up @@ -129,6 +130,7 @@ export const CustomIndicator = () => {
<View style={[styles.tabbar, { paddingBottom: insets.bottom }]}>
<TabBar
{...props}
direction={direction}
renderIcon={renderIcon}
renderBadge={renderBadge}
renderIndicator={renderIndicator}
Expand All @@ -145,6 +147,7 @@ export const CustomIndicator = () => {
index,
routes,
}}
direction={direction}
renderScene={renderScene}
renderTabBar={renderTabBar}
tabBarPosition="bottom"
Expand Down
3 changes: 3 additions & 0 deletions example/src/Screens/TabView/CustomTabBar.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Ionicons } from '@expo/vector-icons';
import { useLocale } from '@react-navigation/native';
import * as React from 'react';
import {
Animated,
Expand Down Expand Up @@ -36,6 +37,7 @@ const renderScene = SceneMap({
});

export const CustomTabBar = () => {
const { direction } = useLocale();
const insets = useSafeAreaInsets();
const [index, onIndexChange] = React.useState(0);
const [routes] = React.useState<Route[]>([
Expand Down Expand Up @@ -121,6 +123,7 @@ export const CustomTabBar = () => {
index,
routes,
}}
direction={direction}
renderScene={renderScene}
renderTabBar={renderTabBar}
tabBarPosition="bottom"
Expand Down
4 changes: 4 additions & 0 deletions example/src/Screens/TabView/ScrollableTabBar.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useLocale } from '@react-navigation/native';
import * as React from 'react';
import { StyleSheet } from 'react-native';
import {
Expand Down Expand Up @@ -27,6 +28,7 @@ const renderScene = SceneMap({

export const ScrollableTabBar = () => {
const [index, onIndexChange] = React.useState(1);
const { direction } = useLocale();
const [routes] = React.useState([
{ key: 'article', title: 'Article' },
{ key: 'contacts', title: 'Contacts' },
Expand All @@ -46,6 +48,7 @@ export const ScrollableTabBar = () => {
tabStyle={styles.tab}
labelStyle={styles.label}
gap={20}
direction={direction}
/>
);

Expand All @@ -56,6 +59,7 @@ export const ScrollableTabBar = () => {
index,
routes,
}}
direction={direction}
renderScene={renderScene}
renderTabBar={renderTabBar}
onIndexChange={onIndexChange}
Expand Down
4 changes: 4 additions & 0 deletions example/src/Screens/TabView/TabBarIcon.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Ionicons } from '@expo/vector-icons';
import { useLocale } from '@react-navigation/native';
import * as React from 'react';
import { StyleSheet } from 'react-native';
import {
Expand Down Expand Up @@ -27,6 +28,7 @@ const renderScene = SceneMap({
});

export const TabBarIcon = () => {
const { direction } = useLocale();
const [index, onIndexChange] = React.useState(0);
const [routes] = React.useState<Route[]>([
{ key: 'chat', icon: 'md-chatbubbles' },
Expand All @@ -43,6 +45,7 @@ export const TabBarIcon = () => {
) => (
<TabBar
{...props}
direction={direction}
indicatorStyle={styles.indicator}
renderIcon={renderIcon}
style={styles.tabbar}
Expand All @@ -58,6 +61,7 @@ export const TabBarIcon = () => {
index,
routes,
}}
direction={direction}
renderScene={renderScene}
renderTabBar={renderTabBar}
onIndexChange={onIndexChange}
Expand Down
3 changes: 3 additions & 0 deletions packages/material-top-tabs/src/views/MaterialTopTabBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
ParamListBase,
Route,
TabNavigationState,
useLocale,
useTheme,
} from '@react-navigation/native';
import Color from 'color';
Expand All @@ -18,6 +19,7 @@ export function MaterialTopTabBar({
...rest
}: MaterialTopTabBarProps) {
const { colors, fonts } = useTheme();
const { direction } = useLocale();

const focusedOptions = descriptors[state.routes[state.index].key].options;

Expand All @@ -30,6 +32,7 @@ export function MaterialTopTabBar({
<TabBar
{...rest}
navigationState={state}
direction={direction}
scrollEnabled={focusedOptions.tabBarScrollEnabled}
bounces={focusedOptions.tabBarBounces}
activeColor={activeColor}
Expand Down
3 changes: 3 additions & 0 deletions packages/material-top-tabs/src/views/MaterialTopTabView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
ParamListBase,
Route,
TabNavigationState,
useLocale,
useTheme,
} from '@react-navigation/native';
import * as React from 'react';
Expand Down Expand Up @@ -31,6 +32,7 @@ export function MaterialTopTabView({
...rest
}: Props) {
const { colors } = useTheme();
const { direction } = useLocale();

const renderTabBar = (props: SceneRendererProps) => {
return tabBar({
Expand Down Expand Up @@ -70,6 +72,7 @@ export function MaterialTopTabView({
{ backgroundColor: colors.background },
sceneContainerStyle,
]}
direction={direction}
/>
);
}
12 changes: 7 additions & 5 deletions packages/react-native-tab-view/src/PanResponderAdapter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import * as React from 'react';
import {
Animated,
GestureResponderEvent,
I18nManager,
Keyboard,
PanResponder,
PanResponderGestureState,
Expand Down Expand Up @@ -60,6 +59,7 @@ export function PanResponderAdapter<T extends Route>({
children,
style,
animationEnabled = false,
layoutDirection = 'ltr',
}: Props<T>) {
const { routes, index } = navigationState;

Expand Down Expand Up @@ -147,7 +147,8 @@ export function PanResponderAdapter<T extends Route>({
return false;
}

const diffX = I18nManager.isRTL ? -gestureState.dx : gestureState.dx;
const diffX =
layoutDirection === 'rtl' ? -gestureState.dx : gestureState.dx;

return (
isMovingHorizontally(event, gestureState) &&
Expand All @@ -172,7 +173,8 @@ export function PanResponderAdapter<T extends Route>({
_: GestureResponderEvent,
gestureState: PanResponderGestureState
) => {
const diffX = I18nManager.isRTL ? -gestureState.dx : gestureState.dx;
const diffX =
layoutDirection === 'rtl' ? -gestureState.dx : gestureState.dx;

if (
// swiping left
Expand Down Expand Up @@ -222,7 +224,7 @@ export function PanResponderAdapter<T extends Route>({
Math.min(
Math.max(
0,
I18nManager.isRTL
layoutDirection === 'rtl'
? currentIndex + gestureState.dx / Math.abs(gestureState.dx)
: currentIndex - gestureState.dx / Math.abs(gestureState.dx)
),
Expand Down Expand Up @@ -281,7 +283,7 @@ export function PanResponderAdapter<T extends Route>({
outputRange: [-maxTranslate, 0],
extrapolate: 'clamp',
}),
I18nManager.isRTL ? -1 : 1
layoutDirection === 'rtl' ? -1 : 1
);

const position = React.useMemo(
Expand Down

0 comments on commit 46735a3

Please sign in to comment.