diff --git a/src/components/Appbar/AppbarBackIcon.tsx b/src/components/Appbar/AppbarBackIcon.tsx index 7579a3f1a6..6b047e4623 100644 --- a/src/components/Appbar/AppbarBackIcon.tsx +++ b/src/components/Appbar/AppbarBackIcon.tsx @@ -1,9 +1,11 @@ import * as React from 'react'; -import { I18nManager, Image, Platform, StyleSheet, View } from 'react-native'; +import { Image, Platform, StyleSheet, View } from 'react-native'; +import { useTheme } from '../../core/theming'; import MaterialCommunityIcon from '../MaterialCommunityIcon'; const AppbarBackIcon = ({ size, color }: { size: number; color: string }) => { + const theme = useTheme(); const iosIconSize = size - 3; return Platform.OS === 'ios' ? ( @@ -13,7 +15,7 @@ const AppbarBackIcon = ({ size, color }: { size: number; color: string }) => { { width: size, height: size, - transform: [{ scaleX: I18nManager.getConstants().isRTL ? -1 : 1 }], + transform: [{ scaleX: theme.direction === 'rtl' ? -1 : 1 }], }, ]} > @@ -31,7 +33,7 @@ const AppbarBackIcon = ({ size, color }: { size: number; color: string }) => { name="arrow-left" color={color} size={size} - direction={I18nManager.getConstants().isRTL ? 'rtl' : 'ltr'} + direction={theme.direction} /> ); }; diff --git a/src/components/DataTable/DataTablePagination.tsx b/src/components/DataTable/DataTablePagination.tsx index dd72dbe54f..6b14da37a4 100644 --- a/src/components/DataTable/DataTablePagination.tsx +++ b/src/components/DataTable/DataTablePagination.tsx @@ -1,7 +1,6 @@ import * as React from 'react'; import { ColorValue, - I18nManager, StyleProp, StyleSheet, View, @@ -119,7 +118,7 @@ const PaginationControls = ({ name="page-first" color={color} size={size} - direction={I18nManager.getConstants().isRTL ? 'rtl' : 'ltr'} + direction={theme.direction} /> )} iconColor={textColor} @@ -136,7 +135,7 @@ const PaginationControls = ({ name="chevron-left" color={color} size={size} - direction={I18nManager.getConstants().isRTL ? 'rtl' : 'ltr'} + direction={theme.direction} /> )} iconColor={textColor} @@ -152,7 +151,7 @@ const PaginationControls = ({ name="chevron-right" color={color} size={size} - direction={I18nManager.getConstants().isRTL ? 'rtl' : 'ltr'} + direction={theme.direction} /> )} iconColor={textColor} @@ -169,7 +168,7 @@ const PaginationControls = ({ name="page-last" color={color} size={size} - direction={I18nManager.getConstants().isRTL ? 'rtl' : 'ltr'} + direction={theme.direction} /> )} iconColor={textColor} diff --git a/src/components/DataTable/DataTableTitle.tsx b/src/components/DataTable/DataTableTitle.tsx index 6402e67506..95e9743cc7 100644 --- a/src/components/DataTable/DataTableTitle.tsx +++ b/src/components/DataTable/DataTableTitle.tsx @@ -2,7 +2,6 @@ import * as React from 'react'; import { Animated, GestureResponderEvent, - I18nManager, PixelRatio, Pressable, StyleProp, @@ -120,7 +119,7 @@ const DataTableTitle = ({ name="arrow-up" size={16} color={textColor} - direction={I18nManager.getConstants().isRTL ? 'rtl' : 'ltr'} + direction={theme.direction} /> ) : null; @@ -142,7 +141,7 @@ const DataTableTitle = ({ // if numberOfLines causes wrap, center is lost. Align directly, sensitive to numeric and RTL numberOfLines > 1 ? numeric - ? I18nManager.getConstants().isRTL + ? theme.direction === 'rtl' ? styles.leftText : styles.rightText : styles.centerText diff --git a/src/components/FAB/AnimatedFAB.tsx b/src/components/FAB/AnimatedFAB.tsx index 94468e5687..fa2fe19991 100644 --- a/src/components/FAB/AnimatedFAB.tsx +++ b/src/components/FAB/AnimatedFAB.tsx @@ -10,7 +10,6 @@ import { Animated, Easing, GestureResponderEvent, - I18nManager, Platform, ScrollView, StyleProp, @@ -146,7 +145,6 @@ const SCALE = 0.9; * ScrollView, * Text, * SafeAreaView, - * I18nManager, * } from 'react-native'; * import { AnimatedFAB } from 'react-native-paper'; * @@ -238,7 +236,7 @@ const AnimatedFAB = ({ const isWeb = Platform.OS === 'web'; const isAnimatedFromRight = animateFrom === 'right'; const isIconStatic = iconMode === 'static'; - const { isRTL } = I18nManager; + const isRTL = theme.direction === 'rtl'; const labelRef = React.useRef(null); const { current: visibility } = React.useRef( new Animated.Value(visible ? 1 : 0) @@ -362,6 +360,7 @@ const AnimatedFAB = ({ isIconStatic, distance, animFAB, + isRTL: theme.direction === 'rtl', }); const font = isV3 ? theme.fonts.labelLarge : theme.fonts.medium; diff --git a/src/components/FAB/utils.ts b/src/components/FAB/utils.ts index e87d24019f..50be9f65b4 100644 --- a/src/components/FAB/utils.ts +++ b/src/components/FAB/utils.ts @@ -1,11 +1,5 @@ import { MutableRefObject } from 'react'; -import { - Animated, - ColorValue, - I18nManager, - Platform, - ViewStyle, -} from 'react-native'; +import { Animated, ColorValue, Platform, ViewStyle } from 'react-native'; import color from 'color'; @@ -18,6 +12,7 @@ type GetCombinedStylesProps = { isIconStatic: boolean; distance: number; animFAB: Animated.Value; + isRTL: boolean; }; type CombinedStyles = { @@ -39,9 +34,8 @@ export const getCombinedStyles = ({ isIconStatic, distance, animFAB, + isRTL, }: GetCombinedStylesProps): CombinedStyles => { - const { isRTL } = I18nManager; - const defaultPositionStyles = { left: -distance, right: undefined }; const combinedStyles: CombinedStyles = { diff --git a/src/components/Icon.tsx b/src/components/Icon.tsx index b3d26c699d..7014a19634 100644 --- a/src/components/Icon.tsx +++ b/src/components/Icon.tsx @@ -1,10 +1,5 @@ import * as React from 'react'; -import { - I18nManager, - Image, - ImageSourcePropType, - Platform, -} from 'react-native'; +import { Image, ImageSourcePropType, Platform } from 'react-native'; import { accessibilityProps } from './MaterialCommunityIcon'; import { Consumer as SettingsConsumer } from '../core/settings'; @@ -112,9 +107,7 @@ const Icon = ({ const direction = typeof source === 'object' && source.direction && source.source ? source.direction === 'auto' - ? I18nManager.getConstants().isRTL - ? 'rtl' - : 'ltr' + ? theme.direction : source.direction : null; diff --git a/src/components/List/ListAccordion.tsx b/src/components/List/ListAccordion.tsx index 75505c7367..58cb222f42 100644 --- a/src/components/List/ListAccordion.tsx +++ b/src/components/List/ListAccordion.tsx @@ -2,7 +2,6 @@ import * as React from 'react'; import { ColorValue, GestureResponderEvent, - I18nManager, NativeSyntheticEvent, StyleProp, StyleSheet, @@ -331,7 +330,7 @@ const ListAccordion = ({ name={isExpanded ? 'chevron-up' : 'chevron-down'} color={theme.isV3 ? descriptionColor : titleColor} size={24} - direction={I18nManager.getConstants().isRTL ? 'rtl' : 'ltr'} + direction={theme.direction} /> )} diff --git a/src/components/Menu/Menu.tsx b/src/components/Menu/Menu.tsx index 0e241a2c01..80b4f9224d 100644 --- a/src/components/Menu/Menu.tsx +++ b/src/components/Menu/Menu.tsx @@ -4,7 +4,6 @@ import { Dimensions, Easing, EmitterSubscription, - I18nManager, Keyboard, KeyboardEvent as RNKeyboardEvent, LayoutRectangle, @@ -620,7 +619,7 @@ const Menu = ({ top: isCoordinate(anchor) ? topTransformation : topTransformation + additionalVerticalValue, - ...(I18nManager.getConstants().isRTL + ...(theme.direction === 'rtl' ? { right: leftTransformation } : { left: leftTransformation }), }; diff --git a/src/components/ProgressBar.tsx b/src/components/ProgressBar.tsx index 790204f4f8..0adacecd66 100644 --- a/src/components/ProgressBar.tsx +++ b/src/components/ProgressBar.tsx @@ -1,7 +1,6 @@ import * as React from 'react'; import { Animated, - I18nManager, LayoutChangeEvent, Platform, StyleProp, @@ -55,7 +54,6 @@ export type Props = React.ComponentPropsWithRef & { const INDETERMINATE_DURATION = 2000; const INDETERMINATE_MAX_WIDTH = 0.6; -const { isRTL } = I18nManager; /** * Progress bar is an indicator used to present progress of some activity in the app. @@ -99,6 +97,7 @@ const ProgressBar = ({ React.useRef(null); const { scale } = theme.animation; + const isRTL = theme.direction === 'rtl'; React.useEffect(() => { passedAnimatedValue.current = animatedValue; diff --git a/src/components/Searchbar.tsx b/src/components/Searchbar.tsx index 11c79d2e9a..325ba8e3e3 100644 --- a/src/components/Searchbar.tsx +++ b/src/components/Searchbar.tsx @@ -3,7 +3,6 @@ import { Animated, ColorValue, GestureResponderEvent, - I18nManager, Platform, StyleProp, StyleSheet, @@ -290,7 +289,7 @@ const Searchbar = forwardRef( name="magnify" color={color} size={size} - direction={I18nManager.getConstants().isRTL ? 'rtl' : 'ltr'} + direction={theme.direction} /> )) } @@ -302,6 +301,7 @@ const Searchbar = forwardRef( style={[ styles.input, { + textAlign: theme.direction === 'rtl' ? 'right' : 'left', color: textColor, ...font, ...Platform.select({ web: { outline: 'none' } }), @@ -352,7 +352,7 @@ const Searchbar = forwardRef( name={isV3 ? 'close' : 'close-circle-outline'} color={color} size={size} - direction={I18nManager.getConstants().isRTL ? 'rtl' : 'ltr'} + direction={theme.direction} /> )) } @@ -403,7 +403,6 @@ const styles = StyleSheet.create({ fontSize: 18, paddingLeft: 8, alignSelf: 'stretch', - textAlign: I18nManager.getConstants().isRTL ? 'right' : 'left', minWidth: 0, }, barModeInput: { diff --git a/src/components/Snackbar.tsx b/src/components/Snackbar.tsx index 137a69ae82..cd34588f49 100644 --- a/src/components/Snackbar.tsx +++ b/src/components/Snackbar.tsx @@ -3,7 +3,6 @@ import { Animated, ColorValue, Easing, - I18nManager, StyleProp, StyleSheet, View, @@ -360,9 +359,7 @@ const Snackbar = ({ name="close" color={color} size={size} - direction={ - I18nManager.getConstants().isRTL ? 'rtl' : 'ltr' - } + direction={theme.direction} /> ); }) diff --git a/src/components/TextInput/TextInputFlat.tsx b/src/components/TextInput/TextInputFlat.tsx index 378366e176..f4253831b5 100644 --- a/src/components/TextInput/TextInputFlat.tsx +++ b/src/components/TextInput/TextInputFlat.tsx @@ -1,6 +1,5 @@ import * as React from 'react'; import { - I18nManager, Platform, StyleSheet, TextInput as NativeTextInput, @@ -170,11 +169,9 @@ const TextInputFlat = ({ const labelHalfHeight = labelHeight / 2; const baseLabelTranslateX = - (I18nManager.getConstants().isRTL ? 1 : -1) * + (theme.direction === 'rtl' ? 1 : -1) * (labelHalfWidth - (labelScale * labelWidth) / 2) + - (1 - labelScale) * - (I18nManager.getConstants().isRTL ? -1 : 1) * - paddingLeft; + (1 - labelScale) * (theme.direction === 'rtl' ? -1 : 1) * paddingLeft; const minInputHeight = dense ? (label ? MIN_DENSE_HEIGHT_WL : MIN_DENSE_HEIGHT) - LABEL_PADDING_TOP_DENSE @@ -279,12 +276,12 @@ const TextInputFlat = ({ wiggleOffsetX: LABEL_WIGGLE_X_OFFSET, topPosition, paddingLeft: isAndroid - ? I18nManager.isRTL + ? theme.direction === 'rtl' ? paddingRight : paddingLeft : paddingLeft, paddingRight: isAndroid - ? I18nManager.isRTL + ? theme.direction === 'rtl' ? paddingLeft : paddingRight : paddingRight, @@ -420,7 +417,7 @@ const TextInputFlat = ({ textAlignVertical: multiline ? 'top' : 'center', textAlign: textAlign ? textAlign - : I18nManager.getConstants().isRTL + : theme.direction === 'rtl' ? 'right' : 'left', minWidth: Math.min( diff --git a/src/components/TextInput/TextInputOutlined.tsx b/src/components/TextInput/TextInputOutlined.tsx index 70b590fabb..10a7aa59aa 100644 --- a/src/components/TextInput/TextInputOutlined.tsx +++ b/src/components/TextInput/TextInputOutlined.tsx @@ -4,7 +4,6 @@ import { View, TextInput as NativeTextInput, StyleSheet, - I18nManager, Platform, TextStyle, ColorValue, @@ -131,7 +130,7 @@ const TextInputOutlined = ({ const labelHalfHeight = labelHeight / 2; const baseLabelTranslateX = - (I18nManager.getConstants().isRTL ? 1 : -1) * + (theme.direction === 'rtl' ? 1 : -1) * (labelHalfWidth - (labelScale * labelWidth) / 2 - (fontSize - MINIMIZED_LABEL_FONT_SIZE) * labelScale); @@ -148,7 +147,7 @@ const TextInputOutlined = ({ if (isAdornmentLeftIcon) { labelTranslationXOffset = - (I18nManager.getConstants().isRTL ? -1 : 1) * + (theme.direction === 'rtl' ? -1 : 1) * (ADORNMENT_SIZE + ADORNMENT_OFFSET - (isV3 ? 0 : 8)); } @@ -406,7 +405,7 @@ const TextInputOutlined = ({ textAlignVertical: multiline ? 'top' : 'center', textAlign: textAlign ? textAlign - : I18nManager.getConstants().isRTL + : theme.direction === 'rtl' ? 'right' : 'left', paddingHorizontal: INPUT_PADDING_HORIZONTAL, diff --git a/src/components/Typography/AnimatedText.tsx b/src/components/Typography/AnimatedText.tsx index bab41a617c..b68cbfc440 100644 --- a/src/components/Typography/AnimatedText.tsx +++ b/src/components/Typography/AnimatedText.tsx @@ -1,12 +1,5 @@ import * as React from 'react'; -import { - Animated, - I18nManager, - StyleProp, - StyleSheet, - TextStyle, - Text, -} from 'react-native'; +import { Animated, StyleProp, StyleSheet, TextStyle, Text } from 'react-native'; import type { VariantProp } from './types'; import { useInternalTheme } from '../../core/theming'; @@ -47,7 +40,6 @@ const AnimatedText = forwardRef>( ref ) { const theme = useInternalTheme(themeOverrides); - const writingDirection = I18nManager.getConstants().isRTL ? 'rtl' : 'ltr'; if (theme.isV3 && variant) { const font = theme.fonts[variant]; @@ -66,7 +58,10 @@ const AnimatedText = forwardRef>( style={[ font, styles.text, - { writingDirection, color: theme.colors.onSurface }, + { + writingDirection: theme.direction, + color: theme.colors.onSurface, + }, style, ]} /> @@ -85,7 +80,7 @@ const AnimatedText = forwardRef>( styles.text, textStyle, { - writingDirection, + writingDirection: theme.direction, }, style, ]} diff --git a/src/components/Typography/Text.tsx b/src/components/Typography/Text.tsx index e34c4b5054..b9e21ee549 100644 --- a/src/components/Typography/Text.tsx +++ b/src/components/Typography/Text.tsx @@ -1,6 +1,5 @@ import * as React from 'react'; import { - I18nManager, StyleProp, StyleSheet, Text as NativeText, @@ -87,7 +86,6 @@ const Text = ( const root = React.useRef(null); // FIXME: destructure it in TS 4.6+ const theme = useInternalTheme(initialTheme); - const writingDirection = I18nManager.getConstants().isRTL ? 'rtl' : 'ltr'; React.useImperativeHandle(ref, () => ({ setNativeProps: (args: Object) => root.current?.setNativeProps(args), @@ -147,7 +145,7 @@ const Text = ( ref={root} style={[ styles.text, - { writingDirection, color: theme.colors.onSurface }, + { writingDirection: theme.direction, color: theme.colors.onSurface }, textStyle, ]} {...rest} @@ -163,7 +161,12 @@ const Text = ( ); } diff --git a/src/components/Typography/v2/StyledText.tsx b/src/components/Typography/v2/StyledText.tsx index 5d976ff267..faa30f5ca6 100644 --- a/src/components/Typography/v2/StyledText.tsx +++ b/src/components/Typography/v2/StyledText.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { I18nManager, StyleProp, StyleSheet, TextStyle } from 'react-native'; +import { StyleProp, StyleSheet, TextStyle } from 'react-native'; import color from 'color'; import type { ThemeProp } from 'src/types'; @@ -29,7 +29,6 @@ const StyledText = ({ .alpha(alpha) .rgb() .string(); - const writingDirection = I18nManager.getConstants().isRTL ? 'rtl' : 'ltr'; return ( right={ } + theme={{ + direction: I18nManager.isRTL ? 'rtl' : 'ltr', + }} /> ); diff --git a/src/components/__tests__/__snapshots__/ListSection.test.tsx.snap b/src/components/__tests__/__snapshots__/ListSection.test.tsx.snap index b5bc07c4b8..2c6a7441fa 100644 --- a/src/components/__tests__/__snapshots__/ListSection.test.tsx.snap +++ b/src/components/__tests__/__snapshots__/ListSection.test.tsx.snap @@ -58,6 +58,7 @@ exports[`renders list section with custom title style 1`] = ` "tertiaryContainer": "rgba(255, 216, 228, 1)", }, "dark": false, + "direction": "ltr", "fonts": { "bodyLarge": { "fontFamily": "System", @@ -585,6 +586,7 @@ exports[`renders list section with subheader 1`] = ` "tertiaryContainer": "rgba(255, 216, 228, 1)", }, "dark": false, + "direction": "ltr", "fonts": { "bodyLarge": { "fontFamily": "System", @@ -1110,6 +1112,7 @@ exports[`renders list section without subheader 1`] = ` "tertiaryContainer": "rgba(255, 216, 228, 1)", }, "dark": false, + "direction": "ltr", "fonts": { "bodyLarge": { "fontFamily": "System", diff --git a/src/components/__tests__/__snapshots__/Searchbar.test.tsx.snap b/src/components/__tests__/__snapshots__/Searchbar.test.tsx.snap index 16831396de..ae9b3b42d6 100644 --- a/src/components/__tests__/__snapshots__/Searchbar.test.tsx.snap +++ b/src/components/__tests__/__snapshots__/Searchbar.test.tsx.snap @@ -187,7 +187,6 @@ exports[`activity indicator snapshot test 1`] = ` "fontSize": 18, "minWidth": 0, "paddingLeft": 8, - "textAlign": "left", }, { "color": "rgba(73, 69, 79, 1)", @@ -196,6 +195,7 @@ exports[`activity indicator snapshot test 1`] = ` "fontWeight": "400", "letterSpacing": 0.15, "lineHeight": 0, + "textAlign": "left", }, { "minHeight": 56, @@ -608,7 +608,6 @@ exports[`renders with placeholder 1`] = ` "fontSize": 18, "minWidth": 0, "paddingLeft": 8, - "textAlign": "left", }, { "color": "rgba(73, 69, 79, 1)", @@ -617,6 +616,7 @@ exports[`renders with placeholder 1`] = ` "fontWeight": "400", "letterSpacing": 0.15, "lineHeight": 0, + "textAlign": "left", }, { "minHeight": 56, @@ -969,7 +969,6 @@ exports[`renders with text 1`] = ` "fontSize": 18, "minWidth": 0, "paddingLeft": 8, - "textAlign": "left", }, { "color": "rgba(73, 69, 79, 1)", @@ -978,6 +977,7 @@ exports[`renders with text 1`] = ` "fontWeight": "400", "letterSpacing": 0.15, "lineHeight": 0, + "textAlign": "left", }, { "minHeight": 56, diff --git a/src/styles/themes/v2/LightTheme.tsx b/src/styles/themes/v2/LightTheme.tsx index 8566bdcc40..06e5d80f05 100644 --- a/src/styles/themes/v2/LightTheme.tsx +++ b/src/styles/themes/v2/LightTheme.tsx @@ -1,3 +1,5 @@ +import { I18nManager } from 'react-native'; + import color from 'color'; import { black, pinkA400, white } from './colors'; @@ -6,6 +8,7 @@ import configureFonts from '../../fonts'; export const MD2LightTheme: MD2Theme = { dark: false, + direction: I18nManager.getConstants().isRTL ? 'rtl' : 'ltr', roundness: 4, version: 2, isV3: false, diff --git a/src/styles/themes/v3/LightTheme.tsx b/src/styles/themes/v3/LightTheme.tsx index 99e0d11ab4..596b683138 100644 --- a/src/styles/themes/v3/LightTheme.tsx +++ b/src/styles/themes/v3/LightTheme.tsx @@ -1,3 +1,5 @@ +import { I18nManager } from 'react-native'; + import color from 'color'; import { MD3Colors, tokens } from './tokens'; @@ -8,6 +10,7 @@ const { palette, opacity } = tokens.md.ref; export const MD3LightTheme: MD3Theme = { dark: false, + direction: I18nManager.getConstants().isRTL ? 'rtl' : 'ltr', roundness: 4, version: 3, isV3: true, diff --git a/src/types.tsx b/src/types.tsx index 175131cab3..07e1498347 100644 --- a/src/types.tsx +++ b/src/types.tsx @@ -117,6 +117,7 @@ export type ThemeProp = $DeepPartial; export type ThemeBase = { dark: boolean; + direction: 'rtl' | 'ltr'; mode?: Mode; roundness: number; animation: {