diff --git a/src/components/Appbar/AppbarBackIcon.tsx b/src/components/Appbar/AppbarBackIcon.tsx index ff827b3f5f..41a85a4a81 100644 --- a/src/components/Appbar/AppbarBackIcon.tsx +++ b/src/components/Appbar/AppbarBackIcon.tsx @@ -1,7 +1,11 @@ +import * as React from 'react'; import { Image, Platform, StyleSheet, View } from 'react-native'; import type { ColorValue } from 'react-native'; import { useLocale } from '../../core/locale'; +import { SettingsContext } from '../../core/settings'; +import type { Settings } from '../../core/settings'; +import Icon from '../Icon'; import MaterialCommunityIcon from '../MaterialCommunityIcon'; const AppbarBackIcon = ({ @@ -12,10 +16,16 @@ const AppbarBackIcon = ({ color: ColorValue; }) => { const { direction } = useLocale(); + const { icon } = React.useContext(SettingsContext); const isRTL = direction === 'rtl'; const iosIconSize = size - 3; - return Platform.OS === 'ios' ? ( + // The bundled chevron is only kept while the default icon renderer is in + // place, so a renderer configured through `PaperProvider` wins on iOS too. + const shouldUseIOSAsset = + Platform.OS === 'ios' && (!icon || icon === MaterialCommunityIcon); + + return shouldUseIOSAsset ? ( ) : ( - ); }; diff --git a/src/components/__tests__/Appbar/Appbar.test.tsx b/src/components/__tests__/Appbar/Appbar.test.tsx index 27cd573f9d..43c285749e 100644 --- a/src/components/__tests__/Appbar/Appbar.test.tsx +++ b/src/components/__tests__/Appbar/Appbar.test.tsx @@ -1,9 +1,10 @@ -import { Animated } from 'react-native'; +import { Animated, Platform, Text as RNText } from 'react-native'; -import { describe, expect, it, jest } from '@jest/globals'; -import { act } from '@testing-library/react-native'; +import { afterEach, describe, expect, it, jest } from '@jest/globals'; +import { act, render as rtlRender } from '@testing-library/react-native'; import { SafeAreaProvider } from 'react-native-safe-area-context'; +import PaperProvider from '../../../core/PaperProvider'; import { getTheme } from '../../../core/theming'; import { render, screen } from '../../../test-utils'; import { tokens } from '../../../theme/tokens'; @@ -14,6 +15,7 @@ import { modeTextVariant, renderAppbarContent as utilRenderAppbarContent, } from '../../Appbar/utils'; +import type { IconProps } from '../../MaterialCommunityIcon'; import Menu from '../../Menu/Menu'; import Searchbar from '../../Searchbar'; import Text from '../../Typography/Text'; @@ -453,3 +455,70 @@ describe('animated value changes correctly', () => { }); }); }); + +describe('Appbar.BackAction icon', () => { + const originalPlatform = Platform.OS; + + afterEach(() => { + Platform.OS = originalPlatform; + }); + + const CustomIcon = ({ name, size, direction, testID }: IconProps) => ( + + {`custom-${name}`} + + ); + + const renderBackAction = (direction?: 'ltr' | 'rtl') => + rtlRender( + + {}} testID="back-action" /> + + ); + + it('renders the icon provided through PaperProvider settings', async () => { + Platform.OS = 'android'; + + await renderBackAction(); + + expect( + screen.getByText('custom-arrow-left', { includeHiddenElements: true }) + ).toBeOnTheScreen(); + }); + + it('renders the icon provided through PaperProvider settings on iOS', async () => { + Platform.OS = 'ios'; + + await renderBackAction(); + + expect( + screen.getByText('custom-arrow-left', { includeHiddenElements: true }) + ).toBeOnTheScreen(); + }); + + it('keeps the icon mirrored in RTL', async () => { + Platform.OS = 'android'; + + await renderBackAction('rtl'); + + expect( + screen.getByText('custom-arrow-left', { includeHiddenElements: true }) + ).toHaveStyle({ transform: [{ scaleX: -1 }] }); + }); + + it('keeps the icon unmirrored in LTR', async () => { + Platform.OS = 'android'; + + await renderBackAction('ltr'); + + expect( + screen.getByText('custom-arrow-left', { includeHiddenElements: true }) + ).toHaveStyle({ transform: [{ scaleX: 1 }] }); + }); +});