From 9e50236330da322923ccc93d518172f6042175a0 Mon Sep 17 00:00:00 2001 From: edug Date: Mon, 23 Jan 2023 13:59:24 +0100 Subject: [PATCH] fix: activeColor and inactiveColor to match icon colors (#3592) --- .../BottomNavigation/BottomNavigation.tsx | 61 ++++++++-------- src/components/BottomNavigation/utils.ts | 71 +++++++++++++++++++ .../__tests__/BottomNavigation.test.js | 68 ++++++++++++++++++ .../BottomNavigation.test.js.snap | 18 ++--- 4 files changed, 180 insertions(+), 38 deletions(-) create mode 100644 src/components/BottomNavigation/utils.ts diff --git a/src/components/BottomNavigation/BottomNavigation.tsx b/src/components/BottomNavigation/BottomNavigation.tsx index 101c6520e3..aaa0602077 100644 --- a/src/components/BottomNavigation/BottomNavigation.tsx +++ b/src/components/BottomNavigation/BottomNavigation.tsx @@ -28,6 +28,11 @@ import Surface from '../Surface'; import TouchableRipple from '../TouchableRipple/TouchableRipple'; import Text from '../Typography/Text'; import BottomNavigationRouteScreen from './BottomNavigationRouteScreen'; +import { + getActiveTintColor, + getInactiveTintColor, + getLabelColor, +} from './utils'; type Route = { key: string; @@ -648,24 +653,18 @@ const BottomNavigation = ({ const textColor = isDark ? white : black; - const activeTintColor = - typeof activeColor !== 'undefined' - ? activeColor - : isV3 - ? theme.colors.onSecondaryContainer - : textColor; - - const inactiveTintColor = - typeof inactiveColor !== 'undefined' - ? inactiveColor - : isV3 - ? theme.colors.onSurfaceVariant - : color(textColor).alpha(0.5).rgb().string(); - - const touchColor = color(activeColor || activeTintColor) - .alpha(0.12) - .rgb() - .string(); + const activeTintColor = getActiveTintColor({ + activeColor, + defaultColor: textColor, + theme, + }); + + const inactiveTintColor = getInactiveTintColor({ + inactiveColor, + defaultColor: textColor, + theme, + }); + const touchColor = color(activeTintColor).alpha(0.12).rgb().string(); const maxTabWidth = routes.length > 3 ? MIN_TAB_WIDTH : MAX_TAB_WIDTH; const maxTabBarWidth = maxTabWidth * routes.length; @@ -746,7 +745,7 @@ const BottomNavigation = ({ style={[ styles.content, { - opacity: opacity, + opacity, transform: [{ translateX: left }, { translateY: top }], }, ]} @@ -891,17 +890,21 @@ const BottomNavigation = ({ const badge = getBadge({ route }); - const activeLabelColor = !isV3 - ? activeTintColor - : focused - ? theme.colors.onSurface - : theme.colors.onSurfaceVariant; + const activeLabelColor = getLabelColor({ + tintColor: activeTintColor, + hasColor: Boolean(activeColor), + focused, + defaultColor: textColor, + theme, + }); - const inactiveLabelColor = !isV3 - ? inactiveTintColor - : focused - ? theme.colors.onSurface - : theme.colors.onSurfaceVariant; + const inactiveLabelColor = getLabelColor({ + tintColor: inactiveTintColor, + hasColor: Boolean(inactiveColor), + focused, + defaultColor: textColor, + theme, + }); const badgeStyle = { top: !isV3 ? -2 : typeof badge === 'boolean' ? 4 : 2, diff --git a/src/components/BottomNavigation/utils.ts b/src/components/BottomNavigation/utils.ts new file mode 100644 index 0000000000..38f44fe6b8 --- /dev/null +++ b/src/components/BottomNavigation/utils.ts @@ -0,0 +1,71 @@ +import color from 'color'; +import type { InternalTheme } from 'src/types'; + +import type { black, white } from '../../styles/themes/v2/colors'; + +type BaseProps = { + defaultColor: typeof black | typeof white; + theme: InternalTheme; +}; + +export const getActiveTintColor = ({ + activeColor, + defaultColor, + theme, +}: BaseProps & { + activeColor: string | undefined; +}) => { + if (typeof activeColor === 'string') { + return activeColor; + } + + if (theme.isV3) { + return theme.colors.onSecondaryContainer; + } + + return defaultColor; +}; + +export const getInactiveTintColor = ({ + inactiveColor, + defaultColor, + theme, +}: BaseProps & { + inactiveColor: string | undefined; +}) => { + if (typeof inactiveColor === 'string') { + return inactiveColor; + } + + if (theme.isV3) { + return theme.colors.onSurfaceVariant; + } + + return color(defaultColor).alpha(0.5).rgb().string(); +}; + +export const getLabelColor = ({ + tintColor, + hasColor, + focused, + defaultColor, + theme, +}: BaseProps & { + tintColor: string; + hasColor: boolean; + focused: boolean; +}) => { + if (hasColor) { + return tintColor; + } + + if (focused) { + return theme.colors.onSurface; + } + + if (theme.isV3) { + return theme.colors.onSurfaceVariant; + } + + return defaultColor; +}; diff --git a/src/components/__tests__/BottomNavigation.test.js b/src/components/__tests__/BottomNavigation.test.js index d86187c09c..f1234c28da 100644 --- a/src/components/__tests__/BottomNavigation.test.js +++ b/src/components/__tests__/BottomNavigation.test.js @@ -2,11 +2,19 @@ import * as React from 'react'; import { StyleSheet, Easing, Animated, Platform } from 'react-native'; import { fireEvent, render } from '@testing-library/react-native'; +import color from 'color'; import renderer from 'react-test-renderer'; +import { getTheme } from '../../core/theming'; import { red300 } from '../../styles/themes/v2/colors'; +import { MD3Colors } from '../../styles/themes/v3/tokens'; import BottomNavigation from '../BottomNavigation/BottomNavigation.tsx'; import BottomNavigationRouteScreen from '../BottomNavigation/BottomNavigationRouteScreen.tsx'; +import { + getActiveTintColor, + getInactiveTintColor, + getLabelColor, +} from '../BottomNavigation/utils'; const styles = StyleSheet.create({ labelColor: { @@ -389,3 +397,63 @@ it('renders bottom navigation with getLazy', () => { expect(tree.queryByTestId('RouteScreen: 2')).toBeNull(); }); + +describe('getActiveTintColor', () => { + it.each` + activeColor | defaultColor | useV3 | expected + ${'#FBF7DB'} | ${'#fff'} | ${true} | ${'#FBF7DB'} + ${undefined} | ${'#fff'} | ${true} | ${MD3Colors.secondary10} + ${undefined} | ${'#fff'} | ${false} | ${'#fff'} + `( + 'returns $expected when activeColor: $activeColor and useV3: $useV3', + ({ activeColor, defaultColor, useV3, expected }) => { + const theme = getTheme(false, useV3); + const color = getActiveTintColor({ activeColor, defaultColor, theme }); + expect(color).toBe(expected); + } + ); +}); + +describe('getInactiveTintColor', () => { + it.each` + inactiveColor | defaultColor | useV3 | expected + ${'#853D4B'} | ${'#fff'} | ${true} | ${'#853D4B'} + ${undefined} | ${'#fff'} | ${true} | ${MD3Colors.neutralVariant30} + ${undefined} | ${'#fff'} | ${false} | ${color('#fff').alpha(0.5).rgb().string()} + `( + 'returns $expected when inactiveColor: $inactiveColor and useV3: $useV3', + ({ inactiveColor, defaultColor, useV3, expected }) => { + const theme = getTheme(false, useV3); + const color = getInactiveTintColor({ + inactiveColor, + defaultColor, + theme, + }); + expect(color).toBe(expected); + } + ); +}); + +describe('getLabelColor', () => { + it.each` + tintColor | focused | defaultColor | useV3 | expected + ${'#FBF7DB'} | ${true} | ${'#fff'} | ${true} | ${'#FBF7DB'} + ${'#853D4B'} | ${true} | ${'#fff'} | ${true} | ${'#853D4B'} + ${undefined} | ${true} | ${'#fff'} | ${true} | ${MD3Colors.neutral10} + ${undefined} | ${false} | ${'#fff'} | ${true} | ${MD3Colors.neutralVariant30} + ${undefined} | ${false} | ${'#fff'} | ${false} | ${'#fff'} + `( + 'returns $expected when tintColor: $tintColor, focused: $focused useV3: $useV3', + ({ tintColor, focused, defaultColor, useV3, expected }) => { + const theme = getTheme(false, useV3); + const color = getLabelColor({ + tintColor, + hasColor: Boolean(tintColor), + focused, + defaultColor, + theme, + }); + expect(color).toBe(expected); + } + ); +}); diff --git a/src/components/__tests__/__snapshots__/BottomNavigation.test.js.snap b/src/components/__tests__/__snapshots__/BottomNavigation.test.js.snap index 0cec7f265b..7a9bc44c6b 100644 --- a/src/components/__tests__/__snapshots__/BottomNavigation.test.js.snap +++ b/src/components/__tests__/__snapshots__/BottomNavigation.test.js.snap @@ -6889,7 +6889,7 @@ exports[`renders custom icon and label with custom colors in non-shifting bottom "textAlign": "center", }, Object { - "color": "rgba(28, 27, 31, 1)", + "color": "#FBF7DB", "fontFamily": "System", "fontSize": 12, "fontWeight": "500", @@ -6943,7 +6943,7 @@ exports[`renders custom icon and label with custom colors in non-shifting bottom "textAlign": "center", }, Object { - "color": "rgba(28, 27, 31, 1)", + "color": "#853D4B", "fontFamily": "System", "fontSize": 12, "fontWeight": "500", @@ -7197,7 +7197,7 @@ exports[`renders custom icon and label with custom colors in non-shifting bottom "textAlign": "center", }, Object { - "color": "rgba(73, 69, 79, 1)", + "color": "#FBF7DB", "fontFamily": "System", "fontSize": 12, "fontWeight": "500", @@ -7251,7 +7251,7 @@ exports[`renders custom icon and label with custom colors in non-shifting bottom "textAlign": "center", }, Object { - "color": "rgba(73, 69, 79, 1)", + "color": "#853D4B", "fontFamily": "System", "fontSize": 12, "fontWeight": "500", @@ -7505,7 +7505,7 @@ exports[`renders custom icon and label with custom colors in non-shifting bottom "textAlign": "center", }, Object { - "color": "rgba(73, 69, 79, 1)", + "color": "#FBF7DB", "fontFamily": "System", "fontSize": 12, "fontWeight": "500", @@ -7559,7 +7559,7 @@ exports[`renders custom icon and label with custom colors in non-shifting bottom "textAlign": "center", }, Object { - "color": "rgba(73, 69, 79, 1)", + "color": "#853D4B", "fontFamily": "System", "fontSize": 12, "fontWeight": "500", @@ -8008,7 +8008,7 @@ exports[`renders custom icon and label with custom colors in shifting bottom nav "textAlign": "center", }, Object { - "color": "rgba(28, 27, 31, 1)", + "color": "#FBF7DB", "fontFamily": "System", "fontSize": 12, "fontWeight": "500", @@ -8268,7 +8268,7 @@ exports[`renders custom icon and label with custom colors in shifting bottom nav "textAlign": "center", }, Object { - "color": "rgba(73, 69, 79, 1)", + "color": "#FBF7DB", "fontFamily": "System", "fontSize": 12, "fontWeight": "500", @@ -8528,7 +8528,7 @@ exports[`renders custom icon and label with custom colors in shifting bottom nav "textAlign": "center", }, Object { - "color": "rgba(73, 69, 79, 1)", + "color": "#FBF7DB", "fontFamily": "System", "fontSize": 12, "fontWeight": "500",