Skip to content

Commit eaed2ee

Browse files
author
pac-guerreiro
committed
fix: rtl not being detected correctly on web
1 parent d88ff20 commit eaed2ee

23 files changed

Lines changed: 182 additions & 104 deletions

example/src/index.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,10 @@ export default function PaperExample() {
215215
};
216216

217217
return (
218-
<PaperProvider theme={customFontLoaded ? configuredFontTheme : theme}>
218+
<PaperProvider
219+
theme={customFontLoaded ? configuredFontTheme : theme}
220+
direction={rtl ? 'rtl' : 'ltr'}
221+
>
219222
<PreferencesContext.Provider value={preferences}>
220223
<React.Fragment>
221224
<NavigationContainer

src/components/Appbar/AppbarBackIcon.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import * as React from 'react';
2-
import { Platform, I18nManager, View, Image, StyleSheet } from 'react-native';
2+
import { Platform, View, Image, StyleSheet } from 'react-native';
33

4+
import { useLocaleDirection } from '../../core/Localization';
45
import MaterialCommunityIcon from '../MaterialCommunityIcon';
56

67
const AppbarBackIcon = ({ size, color }: { size: number; color: string }) => {
8+
const direction = useLocaleDirection();
79
const iosIconSize = size - 3;
810

911
return Platform.OS === 'ios' ? (
@@ -13,7 +15,7 @@ const AppbarBackIcon = ({ size, color }: { size: number; color: string }) => {
1315
{
1416
width: size,
1517
height: size,
16-
transform: [{ scaleX: I18nManager.getConstants().isRTL ? -1 : 1 }],
18+
transform: [{ scaleX: direction === 'rtl' ? -1 : 1 }],
1719
},
1820
]}
1921
>
@@ -31,7 +33,7 @@ const AppbarBackIcon = ({ size, color }: { size: number; color: string }) => {
3133
name="arrow-left"
3234
color={color}
3335
size={size}
34-
direction={I18nManager.getConstants().isRTL ? 'rtl' : 'ltr'}
36+
direction={direction}
3537
/>
3638
);
3739
};

src/components/DataTable/DataTablePagination.tsx

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
11
import * as React from 'react';
2-
import {
3-
I18nManager,
4-
StyleProp,
5-
StyleSheet,
6-
View,
7-
ViewStyle,
8-
} from 'react-native';
2+
import { StyleProp, StyleSheet, View, ViewStyle } from 'react-native';
93

104
import color from 'color';
115
import type { ThemeProp } from 'src/types';
126

7+
import { useLocaleDirection } from '../../core/Localization';
138
import { useInternalTheme } from '../../core/theming';
149
import Button from '../Button/Button';
1510
import IconButton from '../IconButton/IconButton';
@@ -93,6 +88,7 @@ const PaginationControls = ({
9388
theme: themeOverrides,
9489
}: PaginationControlsProps) => {
9590
const theme = useInternalTheme(themeOverrides);
91+
const direction = useLocaleDirection();
9692

9793
const textColor = theme.isV3 ? theme.colors.onSurface : theme.colors.text;
9894

@@ -105,7 +101,7 @@ const PaginationControls = ({
105101
name="page-first"
106102
color={color}
107103
size={size}
108-
direction={I18nManager.getConstants().isRTL ? 'rtl' : 'ltr'}
104+
direction={direction}
109105
/>
110106
)}
111107
iconColor={textColor}
@@ -121,7 +117,7 @@ const PaginationControls = ({
121117
name="chevron-left"
122118
color={color}
123119
size={size}
124-
direction={I18nManager.getConstants().isRTL ? 'rtl' : 'ltr'}
120+
direction={direction}
125121
/>
126122
)}
127123
iconColor={textColor}
@@ -136,7 +132,7 @@ const PaginationControls = ({
136132
name="chevron-right"
137133
color={color}
138134
size={size}
139-
direction={I18nManager.getConstants().isRTL ? 'rtl' : 'ltr'}
135+
direction={direction}
140136
/>
141137
)}
142138
iconColor={textColor}
@@ -152,7 +148,7 @@ const PaginationControls = ({
152148
name="page-last"
153149
color={color}
154150
size={size}
155-
direction={I18nManager.getConstants().isRTL ? 'rtl' : 'ltr'}
151+
direction={direction}
156152
/>
157153
)}
158154
iconColor={textColor}

src/components/DataTable/DataTableTitle.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import * as React from 'react';
22
import {
33
Animated,
44
GestureResponderEvent,
5-
I18nManager,
65
StyleProp,
76
StyleSheet,
87
TextStyle,
@@ -13,6 +12,7 @@ import {
1312

1413
import color from 'color';
1514

15+
import { useLocaleDirection } from '../../core/Localization';
1616
import { useInternalTheme } from '../../core/theming';
1717
import type { ThemeProp } from '../../types';
1818
import MaterialCommunityIcon from '../MaterialCommunityIcon';
@@ -97,6 +97,7 @@ const DataTableTitle = ({
9797
...rest
9898
}: Props) => {
9999
const theme = useInternalTheme(themeOverrides);
100+
const direction = useLocaleDirection();
100101
const { current: spinAnim } = React.useRef<Animated.Value>(
101102
new Animated.Value(sortDirection === 'ascending' ? 0 : 1)
102103
);
@@ -124,7 +125,7 @@ const DataTableTitle = ({
124125
name="arrow-up"
125126
size={16}
126127
color={textColor}
127-
direction={I18nManager.getConstants().isRTL ? 'rtl' : 'ltr'}
128+
direction={direction}
128129
/>
129130
</Animated.View>
130131
) : null;
@@ -142,7 +143,7 @@ const DataTableTitle = ({
142143
// if numberOfLines causes wrap, center is lost. Align directly, sensitive to numeric and RTL
143144
numberOfLines > 1
144145
? numeric
145-
? I18nManager.getConstants().isRTL
146+
? direction === 'rtl'
146147
? styles.leftText
147148
: styles.rightText
148149
: styles.centerText

src/components/FAB/AnimatedFAB.tsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import {
88
Animated,
99
Easing,
1010
GestureResponderEvent,
11-
I18nManager,
1211
Platform,
1312
ScrollView,
1413
StyleProp,
@@ -20,6 +19,7 @@ import {
2019

2120
import color from 'color';
2221

22+
import { useLocaleDirection } from '../../core/Localization';
2323
import { useInternalTheme } from '../../core/theming';
2424
import type { $RemoveChildren, ThemeProp } from '../../types';
2525
import type { IconSource } from '../Icon';
@@ -126,7 +126,6 @@ const SCALE = 0.9;
126126
* ScrollView,
127127
* Text,
128128
* SafeAreaView,
129-
* I18nManager,
130129
* } from 'react-native';
131130
* import { AnimatedFAB } from 'react-native-paper';
132131
*
@@ -209,11 +208,11 @@ const AnimatedFAB = ({
209208
...rest
210209
}: Props) => {
211210
const theme = useInternalTheme(themeOverrides);
211+
const direction = useLocaleDirection();
212212
const uppercase: boolean = uppercaseProp ?? !theme.isV3;
213213
const isIOS = Platform.OS === 'ios';
214214
const isAnimatedFromRight = animateFrom === 'right';
215215
const isIconStatic = iconMode === 'static';
216-
const { isRTL } = I18nManager;
217216
const { current: visibility } = React.useRef<Animated.Value>(
218217
new Animated.Value(visible ? 1 : 0)
219218
);
@@ -302,6 +301,7 @@ const AnimatedFAB = ({
302301
isIconStatic,
303302
distance,
304303
animFAB,
304+
direction,
305305
});
306306

307307
const font = isV3 ? theme.fonts.labelLarge : theme.fonts.medium;
@@ -452,9 +452,10 @@ const AnimatedFAB = ({
452452
ellipsizeMode={'tail'}
453453
style={[
454454
{
455-
[isAnimatedFromRight || isRTL ? 'right' : 'left']: isIconStatic
456-
? textWidth - SIZE + borderRadius / (isV3 ? 1 : 2)
457-
: borderRadius,
455+
[isAnimatedFromRight || direction === 'rtl' ? 'right' : 'left']:
456+
isIconStatic
457+
? textWidth - SIZE + borderRadius / (isV3 ? 1 : 2)
458+
: borderRadius,
458459
},
459460
{
460461
minWidth: textWidth,

src/components/FAB/utils.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import { Animated, ColorValue, I18nManager, ViewStyle } from 'react-native';
1+
import type { Animated, ColorValue, ViewStyle } from 'react-native';
22

33
import color from 'color';
44

5+
import type { Direction } from '../../core/Localization';
56
import { black, white } from '../../styles/themes/v2/colors';
67
import type { InternalTheme } from '../../types';
78
import getContrastingColor from '../../utils/getContrastingColor';
@@ -11,6 +12,7 @@ type GetCombinedStylesProps = {
1112
isIconStatic: boolean;
1213
distance: number;
1314
animFAB: Animated.Value;
15+
direction: Direction;
1416
};
1517

1618
type CombinedStyles = {
@@ -32,9 +34,9 @@ export const getCombinedStyles = ({
3234
isIconStatic,
3335
distance,
3436
animFAB,
37+
direction,
3538
}: GetCombinedStylesProps): CombinedStyles => {
36-
const { isRTL } = I18nManager;
37-
39+
const isRTL = direction === 'rtl';
3840
const defaultPositionStyles = { left: -distance, right: undefined };
3941

4042
const combinedStyles: CombinedStyles = {

src/components/Icon.tsx

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
import * as React from 'react';
2-
import {
3-
I18nManager,
4-
Image,
5-
ImageSourcePropType,
6-
Platform,
7-
} from 'react-native';
2+
import { Image, ImageSourcePropType, Platform } from 'react-native';
83

4+
import { useLocaleDirection } from '../core/Localization';
95
import { Consumer as SettingsConsumer } from '../core/settings';
106
import { useInternalTheme } from '../core/theming';
117
import type { ThemeProp } from '../types';
@@ -75,10 +71,11 @@ const Icon = ({
7571
...rest
7672
}: Props) => {
7773
const theme = useInternalTheme(themeOverrides);
74+
const localeDirection = useLocaleDirection();
7875
const direction =
7976
typeof source === 'object' && source.direction && source.source
8077
? source.direction === 'auto'
81-
? I18nManager.getConstants().isRTL
78+
? localeDirection
8279
? 'rtl'
8380
: 'ltr'
8481
: source.direction

src/components/List/ListAccordion.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import * as React from 'react';
22
import {
33
GestureResponderEvent,
4-
I18nManager,
54
StyleProp,
65
StyleSheet,
76
TextStyle,
@@ -10,6 +9,7 @@ import {
109
ViewStyle,
1110
} from 'react-native';
1211

12+
import { useLocaleDirection } from '../../core/Localization';
1313
import { useInternalTheme } from '../../core/theming';
1414
import type { ThemeProp } from '../../types';
1515
import MaterialCommunityIcon from '../MaterialCommunityIcon';
@@ -166,6 +166,7 @@ const ListAccordion = ({
166166
pointerEvents = 'none',
167167
}: Props) => {
168168
const theme = useInternalTheme(themeOverrides);
169+
const direction = useLocaleDirection();
169170
const [expanded, setExpanded] = React.useState<boolean>(
170171
expandedProp || false
171172
);
@@ -266,7 +267,7 @@ const ListAccordion = ({
266267
name={isExpanded ? 'chevron-up' : 'chevron-down'}
267268
color={theme.isV3 ? descriptionColor : titleColor}
268269
size={24}
269-
direction={I18nManager.getConstants().isRTL ? 'rtl' : 'ltr'}
270+
direction={direction}
270271
/>
271272
)}
272273
</View>

src/components/Menu/Menu.tsx

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import {
66
Easing,
77
EmitterSubscription,
88
findNodeHandle,
9-
I18nManager,
109
Keyboard,
1110
KeyboardEvent as RNKeyboardEvent,
1211
LayoutRectangle,
@@ -22,6 +21,7 @@ import {
2221
} from 'react-native';
2322

2423
import { APPROX_STATUSBAR_HEIGHT } from '../../constants';
24+
import { Direction, withLocaleDirection } from '../../core/Localization';
2525
import { withInternalTheme } from '../../core/theming';
2626
import type { $Omit, InternalTheme } from '../../types';
2727
import { addEventListener } from '../../utils/addEventListener';
@@ -79,6 +79,10 @@ export type Props = {
7979
* testID to be used on tests.
8080
*/
8181
testID?: string;
82+
/**
83+
* Indicates the text direction
84+
*/
85+
direction: Direction;
8286
};
8387

8488
type Layout = $Omit<$Omit<LayoutRectangle, 'x'>, 'y'>;
@@ -155,9 +159,6 @@ const WINDOW_LAYOUT = Dimensions.get('window');
155159
* wrapping is not necessary if you use Paper's `Modal` instead.
156160
*/
157161
class Menu extends React.Component<Props, State> {
158-
// @component ./MenuItem.tsx
159-
static Item = MenuItem;
160-
161162
static defaultProps = {
162163
statusBarHeight: APPROX_STATUSBAR_HEIGHT,
163164
overlayAccessibilityLabel: 'Close menu',
@@ -418,6 +419,7 @@ class Menu extends React.Component<Props, State> {
418419
overlayAccessibilityLabel,
419420
keyboardShouldPersistTaps,
420421
testID,
422+
direction,
421423
} = this.props;
422424

423425
const {
@@ -457,7 +459,14 @@ class Menu extends React.Component<Props, State> {
457459
];
458460

459461
// We need to translate menu while animating scale to imitate transform origin for scale animation
460-
const positionTransforms = [];
462+
const positionTransforms: (
463+
| {
464+
translateX: Animated.AnimatedInterpolation<string | number>;
465+
}
466+
| {
467+
translateY: Animated.AnimatedInterpolation<string | number>;
468+
}
469+
)[] = [];
461470

462471
// Check if menu fits horizontally and if not align it to right.
463472
if (left <= windowLayout.width - menuLayout.width - SCREEN_INDENT) {
@@ -598,10 +607,10 @@ class Menu extends React.Component<Props, State> {
598607
...(scrollableMenuHeight ? { height: scrollableMenuHeight } : {}),
599608
};
600609

601-
const positionStyle = {
610+
const positionStyle = (isRTL: boolean) => ({
602611
top: this.isCoordinate(anchor) ? top : top + additionalVerticalValue,
603-
...(I18nManager.getConstants().isRTL ? { right: left } : { left }),
604-
};
612+
...(isRTL ? { right: left } : { left }),
613+
});
605614

606615
return (
607616
<View
@@ -626,7 +635,11 @@ class Menu extends React.Component<Props, State> {
626635
}}
627636
collapsable={false}
628637
accessibilityViewIsModal={visible}
629-
style={[styles.wrapper, positionStyle, style]}
638+
style={[
639+
styles.wrapper,
640+
positionStyle(direction === 'rtl'),
641+
style,
642+
]}
630643
pointerEvents={visible ? 'box-none' : 'none'}
631644
onAccessibilityEscape={onDismiss}
632645
>
@@ -671,4 +684,7 @@ const styles = StyleSheet.create({
671684
},
672685
});
673686

674-
export default withInternalTheme(Menu);
687+
export default Object.assign(withInternalTheme(withLocaleDirection(Menu)), {
688+
// @component ./MenuItem.tsx
689+
Item: MenuItem,
690+
});

0 commit comments

Comments
 (0)