diff --git a/babel.config.js b/babel.config.js index f842b77fcf..eec5f170e5 100644 --- a/babel.config.js +++ b/babel.config.js @@ -1,3 +1,4 @@ module.exports = { presets: ['module:metro-react-native-babel-preset'], + plugins: ['lodash'], }; diff --git a/example/src/Examples/AppbarExample.tsx b/example/src/Examples/AppbarExample.tsx index f2d26701c2..475a1d5a69 100644 --- a/example/src/Examples/AppbarExample.tsx +++ b/example/src/Examples/AppbarExample.tsx @@ -3,7 +3,7 @@ import { View, Platform, StyleSheet } from 'react-native'; import type { StackNavigationProp } from '@react-navigation/stack'; import { Appbar, FAB, Switch, Paragraph } from 'react-native-paper'; import ScreenWrapper from '../ScreenWrapper'; -import { yellowA200 } from '../../../src/styles/colors'; +import { yellowA200 } from '../../../src/styles/themes/v2/colors'; type Props = { navigation: StackNavigationProp<{}>; diff --git a/example/src/Examples/TextInputExample.tsx b/example/src/Examples/TextInputExample.tsx index b2d56eb6f0..6008097113 100644 --- a/example/src/Examples/TextInputExample.tsx +++ b/example/src/Examples/TextInputExample.tsx @@ -15,7 +15,7 @@ import { pink400, red500, transparent, -} from '../../../src/styles/colors'; +} from '../../../src/styles/themes/v2/colors'; const MAX_LENGTH = 20; diff --git a/package.json b/package.json index ef5ddd28e0..005dff3009 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "dependencies": { "@callstack/react-theme-provider": "^3.0.7", "color": "^3.1.2", + "lodash": "^4.17.21", "react-native-iphone-x-helper": "^1.3.1" }, "devDependencies": { @@ -58,6 +59,7 @@ "@release-it/conventional-changelog": "^1.1.0", "@types/color": "^3.0.0", "@types/jest": "^24.0.13", + "@types/lodash": "^4.14.178", "@types/node": "^13.1.0", "@types/react-dom": "^16.8.4", "@types/react-native": "^0.66.1", @@ -68,6 +70,7 @@ "babel-cli": "^6.26.0", "babel-core": "^7.0.0-bridge.0", "babel-jest": "^26.1.0", + "babel-plugin-lodash": "^3.3.4", "babel-test": "^0.1.1", "chalk": "^4.0.0", "commitlint": "^8.3.4", diff --git a/src/babel/__fixtures__/rewrite-imports/output.js b/src/babel/__fixtures__/rewrite-imports/output.js index 0c9893c090..68550cea59 100644 --- a/src/babel/__fixtures__/rewrite-imports/output.js +++ b/src/babel/__fixtures__/rewrite-imports/output.js @@ -5,7 +5,7 @@ import BottomNavigation from "react-native-paper/lib/module/components/BottomNav import Button from "react-native-paper/lib/module/components/Button"; import FAB from "react-native-paper/lib/module/components/FAB"; import Appbar from "react-native-paper/lib/module/components/Appbar"; -import * as Colors from "react-native-paper/lib/module/styles/colors"; +import * as Colors from "react-native-paper/lib/module/styles/themes/v2/colors"; import { NonExistent, NonExistentSecond as Stuff, Theme } from "react-native-paper/lib/module/index.js"; import { ThemeProvider } from "react-native-paper/lib/module/core/theming"; import { withTheme } from "react-native-paper/lib/module/core/theming"; diff --git a/src/components/Appbar/Appbar.tsx b/src/components/Appbar/Appbar.tsx index 0f28be5bc1..d43666504f 100644 --- a/src/components/Appbar/Appbar.tsx +++ b/src/components/Appbar/Appbar.tsx @@ -7,7 +7,7 @@ import AppbarAction from './AppbarAction'; import AppbarBackAction from './AppbarBackAction'; import Surface from '../Surface'; import { withTheme } from '../../core/theming'; -import { black, white } from '../../styles/colors'; +import { black, white } from '../../styles/themes/v2/colors'; import overlay from '../../styles/overlay'; type Props = Partial> & { diff --git a/src/components/Appbar/AppbarAction.tsx b/src/components/Appbar/AppbarAction.tsx index 1ef4de58dd..cffab3cd94 100644 --- a/src/components/Appbar/AppbarAction.tsx +++ b/src/components/Appbar/AppbarAction.tsx @@ -5,7 +5,7 @@ import type { ViewStyle, TouchableWithoutFeedback, } from 'react-native'; -import { black } from '../../styles/colors'; +import { black } from '../../styles/themes/v2/colors'; import IconButton from '../IconButton'; import type { IconSource } from '../Icon'; diff --git a/src/components/Appbar/AppbarContent.tsx b/src/components/Appbar/AppbarContent.tsx index e19a88b489..41011b7ff1 100644 --- a/src/components/Appbar/AppbarContent.tsx +++ b/src/components/Appbar/AppbarContent.tsx @@ -13,7 +13,7 @@ import color from 'color'; import Text from '../Typography/Text'; import { withTheme } from '../../core/theming'; -import { white } from '../../styles/colors'; +import { white } from '../../styles/themes/v2/colors'; import type { $RemoveChildren } from '../../types'; diff --git a/src/components/Avatar/AvatarIcon.tsx b/src/components/Avatar/AvatarIcon.tsx index 633a24b45d..4d5c7ef4e3 100644 --- a/src/components/Avatar/AvatarIcon.tsx +++ b/src/components/Avatar/AvatarIcon.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import { View, ViewStyle, StyleSheet, StyleProp } from 'react-native'; import Icon, { IconSource } from '../Icon'; import { withTheme } from '../../core/theming'; -import { white } from '../../styles/colors'; +import { white } from '../../styles/themes/v2/colors'; import getContrastingColor from '../../utils/getContrastingColor'; const defaultSize = 64; diff --git a/src/components/Avatar/AvatarText.tsx b/src/components/Avatar/AvatarText.tsx index 4d8c045e08..a81488b7d6 100644 --- a/src/components/Avatar/AvatarText.tsx +++ b/src/components/Avatar/AvatarText.tsx @@ -8,7 +8,7 @@ import { } from 'react-native'; import Text from '../Typography/Text'; import { withTheme } from '../../core/theming'; -import { white } from '../../styles/colors'; +import { white } from '../../styles/themes/v2/colors'; import getContrastingColor from '../../utils/getContrastingColor'; const defaultSize = 64; diff --git a/src/components/Badge.tsx b/src/components/Badge.tsx index 0284184bf2..3d7730d5a9 100644 --- a/src/components/Badge.tsx +++ b/src/components/Badge.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { Animated, StyleSheet, StyleProp, TextStyle } from 'react-native'; -import { white, black } from '../styles/colors'; +import { white, black } from '../styles/themes/v2/colors'; import { withTheme } from '../core/theming'; import getContrastingColor from '../utils/getContrastingColor'; diff --git a/src/components/BottomNavigation/BottomNavigation.tsx b/src/components/BottomNavigation/BottomNavigation.tsx index d079b081a1..56d850340c 100644 --- a/src/components/BottomNavigation/BottomNavigation.tsx +++ b/src/components/BottomNavigation/BottomNavigation.tsx @@ -17,7 +17,7 @@ import Surface from '../Surface'; import Badge from '../Badge'; import TouchableRipple from '../TouchableRipple/TouchableRipple'; import Text from '../Typography/Text'; -import { black, white } from '../../styles/colors'; +import { black, white } from '../../styles/themes/v2/colors'; import { withTheme } from '../../core/theming'; import useAnimatedValue from '../../utils/useAnimatedValue'; import useAnimatedValueArray from '../../utils/useAnimatedValueArray'; diff --git a/src/components/Button.tsx b/src/components/Button.tsx index 69d60a32fe..f3c83813e1 100644 --- a/src/components/Button.tsx +++ b/src/components/Button.tsx @@ -14,7 +14,7 @@ import Icon, { IconSource } from './Icon'; import Surface from './Surface'; import Text from './Typography/Text'; import TouchableRipple from './TouchableRipple/TouchableRipple'; -import { black, white } from '../styles/colors'; +import { black, white } from '../styles/themes/v2/colors'; import { withTheme } from '../core/theming'; type Props = React.ComponentProps & { diff --git a/src/components/Card/Card.tsx b/src/components/Card/Card.tsx index d504524116..631daea813 100644 --- a/src/components/Card/Card.tsx +++ b/src/components/Card/Card.tsx @@ -8,7 +8,7 @@ import { ViewStyle, } from 'react-native'; import color from 'color'; -import { white, black } from '../../styles/colors'; +import { white, black } from '../../styles/themes/v2/colors'; import CardContent from './CardContent'; import CardActions from './CardActions'; // eslint-disable-next-line @typescript-eslint/no-unused-vars diff --git a/src/components/Card/CardCover.tsx b/src/components/Card/CardCover.tsx index 49832ac860..87384ee68b 100644 --- a/src/components/Card/CardCover.tsx +++ b/src/components/Card/CardCover.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { StyleSheet, View, ViewStyle, Image, StyleProp } from 'react-native'; import { withTheme } from '../../core/theming'; -import { grey200 } from '../../styles/colors'; +import { grey200 } from '../../styles/themes/v2/colors'; type Props = React.ComponentPropsWithRef & { /** diff --git a/src/components/Chip.tsx b/src/components/Chip.tsx index e6bde3bb52..d8902d1c31 100644 --- a/src/components/Chip.tsx +++ b/src/components/Chip.tsx @@ -18,7 +18,7 @@ import Surface from './Surface'; import Text from './Typography/Text'; import TouchableRipple from './TouchableRipple/TouchableRipple'; import { withTheme } from '../core/theming'; -import { black, white } from '../styles/colors'; +import { black, white } from '../styles/themes/v2/colors'; import type { EllipsizeProp } from '../types'; type Props = React.ComponentProps & { diff --git a/src/components/DataTable/DataTableHeader.tsx b/src/components/DataTable/DataTableHeader.tsx index a6d0463eda..658a7bbb1d 100644 --- a/src/components/DataTable/DataTableHeader.tsx +++ b/src/components/DataTable/DataTableHeader.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import color from 'color'; import { StyleSheet, StyleProp, View, ViewStyle } from 'react-native'; -import { black, white } from '../../styles/colors'; +import { black, white } from '../../styles/themes/v2/colors'; import { withTheme } from '../../core/theming'; type Props = React.ComponentPropsWithRef & { diff --git a/src/components/DataTable/DataTableRow.tsx b/src/components/DataTable/DataTableRow.tsx index 385b6dcf67..244eb6cdd6 100644 --- a/src/components/DataTable/DataTableRow.tsx +++ b/src/components/DataTable/DataTableRow.tsx @@ -8,7 +8,7 @@ import { ViewProps, } from 'react-native'; import TouchableRipple from '../TouchableRipple/TouchableRipple'; -import { black, white } from '../../styles/colors'; +import { black, white } from '../../styles/themes/v2/colors'; import { withTheme } from '../../core/theming'; import type { $RemoveChildren } from '../../types'; diff --git a/src/components/Divider.tsx b/src/components/Divider.tsx index 942da2eca0..8a15598957 100644 --- a/src/components/Divider.tsx +++ b/src/components/Divider.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import color from 'color'; import { StyleSheet, View, ViewStyle, StyleProp } from 'react-native'; import { withTheme } from '../core/theming'; -import { black, white } from '../styles/colors'; +import { black, white } from '../styles/themes/v2/colors'; import type { $RemoveChildren } from '../types'; type Props = $RemoveChildren & { diff --git a/src/components/FAB/AnimatedFAB/AnimatedFAB.tsx b/src/components/FAB/AnimatedFAB/AnimatedFAB.tsx index e12f4d9338..bc98ed86d6 100644 --- a/src/components/FAB/AnimatedFAB/AnimatedFAB.tsx +++ b/src/components/FAB/AnimatedFAB/AnimatedFAB.tsx @@ -23,7 +23,7 @@ import type { NativeSyntheticEvent, TextLayoutEventData, } from 'react-native'; -import { white, black } from '../../../styles/colors'; +import { white, black } from '../../../styles/themes/v2/colors'; import AnimatedText from '../../Typography/AnimatedText'; import { getCombinedStyles } from './utils'; diff --git a/src/components/FAB/FAB.tsx b/src/components/FAB/FAB.tsx index 15e24ce4a3..f748b17f4a 100644 --- a/src/components/FAB/FAB.tsx +++ b/src/components/FAB/FAB.tsx @@ -14,7 +14,7 @@ import CrossFadeIcon from '../CrossFadeIcon'; import Icon, { IconSource } from '../Icon'; import Text from '../Typography/Text'; import TouchableRipple from '../TouchableRipple/TouchableRipple'; -import { black, white } from '../../styles/colors'; +import { black, white } from '../../styles/themes/v2/colors'; import { withTheme } from '../../core/theming'; import getContrastingColor from '../../utils/getContrastingColor'; import type { $RemoveChildren } from '../../types'; diff --git a/src/components/Menu/MenuItem.tsx b/src/components/Menu/MenuItem.tsx index 0330689a83..cd3bc391d1 100644 --- a/src/components/Menu/MenuItem.tsx +++ b/src/components/Menu/MenuItem.tsx @@ -10,7 +10,7 @@ import { import Icon, { IconSource } from '../Icon'; import TouchableRipple from '../TouchableRipple/TouchableRipple'; import Text from '../Typography/Text'; -import { black, white } from '../../styles/colors'; +import { black, white } from '../../styles/themes/v2/colors'; import { withTheme } from '../../core/theming'; type Props = { diff --git a/src/components/Switch.tsx b/src/components/Switch.tsx index f89115800b..5e4b94187a 100644 --- a/src/components/Switch.tsx +++ b/src/components/Switch.tsx @@ -1,5 +1,11 @@ import * as React from 'react'; -import { grey400, grey800, grey50, white, black } from '../styles/colors'; +import { + grey400, + grey800, + grey50, + white, + black, +} from '../styles/themes/v2/colors'; import { NativeModules, Platform, diff --git a/src/components/ToggleButton/ToggleButton.tsx b/src/components/ToggleButton/ToggleButton.tsx index 5eb3ddf12a..7ca63b26df 100644 --- a/src/components/ToggleButton/ToggleButton.tsx +++ b/src/components/ToggleButton/ToggleButton.tsx @@ -9,7 +9,7 @@ import { withTheme } from '../../core/theming'; import color from 'color'; import IconButton from '../IconButton'; import { ToggleButtonGroupContext } from './ToggleButtonGroup'; -import { black, white } from '../../styles/colors'; +import { black, white } from '../../styles/themes/v2/colors'; import type { IconSource } from '../Icon'; type Props = { diff --git a/src/components/__tests__/Avatar.test.js b/src/components/__tests__/Avatar.test.js index 774bacd632..b455423db1 100644 --- a/src/components/__tests__/Avatar.test.js +++ b/src/components/__tests__/Avatar.test.js @@ -3,7 +3,7 @@ import { StyleSheet } from 'react-native'; import renderer from 'react-test-renderer'; import { fireEvent, render } from 'react-native-testing-library'; import * as Avatar from '../Avatar/Avatar.tsx'; -import { red500 } from '../../styles/colors'; +import { red500 } from '../../styles/themes/v2/colors'; const styles = StyleSheet.create({ bgColor: { diff --git a/src/components/__tests__/Badge.test.js b/src/components/__tests__/Badge.test.js index 7c2ec7af3d..39866bc9eb 100644 --- a/src/components/__tests__/Badge.test.js +++ b/src/components/__tests__/Badge.test.js @@ -1,7 +1,7 @@ import * as React from 'react'; import renderer from 'react-test-renderer'; import Badge from '../Badge.tsx'; -import { red500 } from '../../styles/colors.tsx'; +import { red500 } from '../../styles/themes/v2/colors'; it('renders badge', () => { const tree = renderer.create().toJSON(); diff --git a/src/components/__tests__/BottomNavigation.test.js b/src/components/__tests__/BottomNavigation.test.js index 9653c30eb2..b010e1e312 100644 --- a/src/components/__tests__/BottomNavigation.test.js +++ b/src/components/__tests__/BottomNavigation.test.js @@ -4,7 +4,7 @@ import { render } from 'react-native-testing-library'; import renderer from 'react-test-renderer'; import BottomNavigation from '../BottomNavigation/BottomNavigation.tsx'; import BottomNavigationRouteScreen from '../BottomNavigation/BottomNavigationRouteScreen.tsx'; -import { red300 } from '../../styles/colors'; +import { red300 } from '../../styles/themes/v2/colors'; const styles = StyleSheet.create({ bgColor: { diff --git a/src/components/__tests__/Button.test.js b/src/components/__tests__/Button.test.js index dc7e4ccd43..5f5420c917 100644 --- a/src/components/__tests__/Button.test.js +++ b/src/components/__tests__/Button.test.js @@ -2,7 +2,7 @@ import * as React from 'react'; import { StyleSheet } from 'react-native'; import renderer from 'react-test-renderer'; import Button from '../Button.tsx'; -import { pink500 } from '../../styles/colors.tsx'; +import { pink500 } from '../../styles/themes/v2/colors'; const styles = StyleSheet.create({ flexing: { diff --git a/src/components/__tests__/IconButton.test.js b/src/components/__tests__/IconButton.test.js index b1ae82301a..c65c80224e 100644 --- a/src/components/__tests__/IconButton.test.js +++ b/src/components/__tests__/IconButton.test.js @@ -1,7 +1,7 @@ import * as React from 'react'; import renderer from 'react-test-renderer'; import IconButton from '../IconButton.tsx'; -import { pink500 } from '../../styles/colors.tsx'; +import { pink500 } from '../../styles/themes/v2/colors'; it('renders icon button by default', () => { const tree = renderer.create().toJSON(); diff --git a/src/components/__tests__/ListAccordion.test.js b/src/components/__tests__/ListAccordion.test.js index c72e396c6f..c3ccb0e108 100644 --- a/src/components/__tests__/ListAccordion.test.js +++ b/src/components/__tests__/ListAccordion.test.js @@ -4,7 +4,7 @@ import renderer from 'react-test-renderer'; import ListAccordion from '../List/ListAccordion.tsx'; import ListItem from '../List/ListItem.tsx'; import ListIcon from '../List/ListIcon.tsx'; -import { red500 } from '../../styles/colors'; +import { red500 } from '../../styles/themes/v2/colors'; const styles = StyleSheet.create({ coloring: { diff --git a/src/components/__tests__/ListItem.test.js b/src/components/__tests__/ListItem.test.js index e924336b05..caf8995e0a 100644 --- a/src/components/__tests__/ListItem.test.js +++ b/src/components/__tests__/ListItem.test.js @@ -5,7 +5,7 @@ import { Text, View } from 'react-native'; import ListItem from '../List/ListItem.tsx'; import ListIcon from '../List/ListIcon.tsx'; import Chip from '../Chip'; -import { red500 } from '../../styles/colors'; +import { red500 } from '../../styles/themes/v2/colors'; const styles = StyleSheet.create({ title: { diff --git a/src/components/__tests__/ListSection.test.js b/src/components/__tests__/ListSection.test.js index e2cc833704..ce0bf8e412 100644 --- a/src/components/__tests__/ListSection.test.js +++ b/src/components/__tests__/ListSection.test.js @@ -5,7 +5,7 @@ import ListSection from '../List/ListSection.tsx'; import ListItem from '../List/ListItem.tsx'; import ListIcon from '../List/ListIcon.tsx'; import ListSubheader from '../List/ListSubheader.tsx'; -import { red500 } from '../../styles/colors'; +import { red500 } from '../../styles/themes/v2/colors'; const styles = StyleSheet.create({ itemColor: { diff --git a/src/components/__tests__/Switch.test.js b/src/components/__tests__/Switch.test.js index 92910cd041..9cee3ae803 100644 --- a/src/components/__tests__/Switch.test.js +++ b/src/components/__tests__/Switch.test.js @@ -1,7 +1,7 @@ import * as React from 'react'; import renderer from 'react-test-renderer'; import Switch from '../Switch.tsx'; -import { pink500 } from '../../styles/colors.tsx'; +import { pink500 } from '../../styles/themes/v2/colors'; it('renders on switch', () => { const tree = renderer.create().toJSON(); diff --git a/src/components/__tests__/TextInput.test.js b/src/components/__tests__/TextInput.test.js index a478adc053..c94bb07169 100644 --- a/src/components/__tests__/TextInput.test.js +++ b/src/components/__tests__/TextInput.test.js @@ -2,7 +2,7 @@ import * as React from 'react'; import { StyleSheet, Text, Platform } from 'react-native'; import { fireEvent, render } from 'react-native-testing-library'; import TextInput from '../TextInput/TextInput'; -import { red500 } from '../../styles/colors'; +import { red500 } from '../../styles/themes/v2/colors'; const style = StyleSheet.create({ inputStyle: { diff --git a/src/components/__tests__/Typography/Caption.test.js b/src/components/__tests__/Typography/Caption.test.js index 2dbe99c0c8..ed1c24132f 100644 --- a/src/components/__tests__/Typography/Caption.test.js +++ b/src/components/__tests__/Typography/Caption.test.js @@ -2,7 +2,7 @@ import * as React from 'react'; import { StyleSheet } from 'react-native'; import renderer from 'react-test-renderer'; import Caption from '../../Typography/Caption.tsx'; -import { red500 } from '../../../styles/colors'; +import { red500 } from '../../../styles/themes/v2/colors'; const style = StyleSheet.create({ caption: { diff --git a/src/components/__tests__/__snapshots__/ListSection.test.js.snap b/src/components/__tests__/__snapshots__/ListSection.test.js.snap index f4c6c68a17..7557391503 100644 --- a/src/components/__tests__/__snapshots__/ListSection.test.js.snap +++ b/src/components/__tests__/__snapshots__/ListSection.test.js.snap @@ -47,7 +47,9 @@ exports[`renders list section with custom title style 1`] = ` "fontWeight": "100", }, }, + "isV3": false, "roundness": 4, + "version": 2, } } > @@ -356,7 +358,9 @@ exports[`renders list section with subheader 1`] = ` "fontWeight": "100", }, }, + "isV3": false, "roundness": 4, + "version": 2, } } > @@ -663,7 +667,9 @@ exports[`renders list section without subheader 1`] = ` "fontWeight": "100", }, }, + "isV3": false, "roundness": 4, + "version": 2, } } > diff --git a/src/core/Provider.tsx b/src/core/Provider.tsx index bb6b49af64..aa9f0f50a9 100644 --- a/src/core/Provider.tsx +++ b/src/core/Provider.tsx @@ -9,13 +9,15 @@ import { ThemeProvider } from './theming'; import { Provider as SettingsProvider, Settings } from './settings'; import MaterialCommunityIcon from '../components/MaterialCommunityIcon'; import PortalHost from '../components/Portal/PortalHost'; -import DefaultTheme from '../styles/DefaultTheme'; -import DarkTheme from '../styles/DarkTheme'; +import LightTheme from '../styles/themes/v2/LightTheme'; +import DarkTheme from '../styles/themes/v2/DarkTheme'; import { addEventListener } from '../utils/addEventListener'; +import { get } from 'lodash'; +import type { MD3Token, Theme } from '../types'; type Props = { children: React.ReactNode; - theme?: ReactNativePaper.Theme; + theme?: Theme; settings?: Settings; }; @@ -73,24 +75,36 @@ const Provider = ({ ...props }: Props) => { const getTheme = () => { const { theme: providedTheme } = props; - if (providedTheme) { - return providedTheme; - } else { - const theme = ( - colorScheme === 'dark' ? DarkTheme : DefaultTheme - ) as ReactNativePaper.Theme; + const theme = providedTheme + ? providedTheme + : ((colorScheme === 'dark' ? DarkTheme : LightTheme) as Theme); - return { - ...theme, - animation: { - ...theme.animation, - scale: reduceMotionEnabled ? 0 : 1, - }, - }; - } + const isV3 = theme?.version === 3; + + /** + * Function that allows to access theme values using Material 3 tokens + * @param {string} tokenKey - Material 3 token + * + * ## Usage + * md('md.sys.color.secondary') + */ + const md = (tokenKey: MD3Token) => get(theme.tokens, tokenKey); + + return { + ...theme, + isV3, + animation: { + ...theme.animation, + scale: reduceMotionEnabled ? 0 : 1, + }, + ...(isV3 && { + md, + }), + }; }; const { children, settings } = props; + return ( diff --git a/src/core/__tests__/Provider.test.js b/src/core/__tests__/Provider.test.js index 03f21378be..03ecf4a783 100644 --- a/src/core/__tests__/Provider.test.js +++ b/src/core/__tests__/Provider.test.js @@ -3,8 +3,8 @@ import { Appearance, AccessibilityInfo, View } from 'react-native'; import { render, act } from 'react-native-testing-library'; import Provider from '../Provider'; import { useTheme } from '../theming'; -import DarkTheme from '../../styles/DarkTheme'; -import DefaultTheme from '../../styles/DefaultTheme'; +import DarkTheme from '../../styles/themes/v2/DarkTheme'; +import LightTheme from '../../styles/themes/v2/LightTheme'; const mockAppearance = () => { jest.mock('react-native/Libraries/Utilities/Appearance', () => { @@ -73,7 +73,7 @@ describe('Provider', () => { mockAppearance(); const { getByTestId } = render(createProvider(null)); expect(getByTestId('provider-child-view').props.theme).toStrictEqual( - DefaultTheme + LightTheme ); act(() => Appearance.__internalListeners[0]({ colorScheme: 'dark' })); expect(getByTestId('provider-child-view').props.theme).toStrictEqual( @@ -98,7 +98,7 @@ describe('Provider', () => { getByTestId('provider-child-view').props.theme.animation.scale ).toStrictEqual(0); - rerender(createProvider(DefaultTheme)); + rerender(createProvider(LightTheme)); expect(AccessibilityInfo.removeEventListener).toHaveBeenCalled(); }); @@ -126,12 +126,12 @@ describe('Provider', () => { it('should not set Appearance listeners, if the theme is passed', async () => { mockAppearance(); - const { getByTestId } = render(createProvider(DefaultTheme)); + const { getByTestId } = render(createProvider(LightTheme)); expect(Appearance.addChangeListener).not.toHaveBeenCalled(); expect(Appearance.removeChangeListener).not.toHaveBeenCalled(); expect(getByTestId('provider-child-view').props.theme).toStrictEqual( - DefaultTheme + LightTheme ); }); @@ -142,14 +142,14 @@ describe('Provider', () => { const { getByTestId } = render(createProvider(null)); expect(Appearance).toEqual(null); expect(getByTestId('provider-child-view').props.theme).toStrictEqual( - DefaultTheme + LightTheme ); }); it.each` - label | theme | colorScheme - ${'default theme'} | ${DefaultTheme} | ${'light'} - ${'dark theme'} | ${DarkTheme} | ${'dark'} + label | theme | colorScheme + ${'default theme'} | ${LightTheme} | ${'light'} + ${'dark theme'} | ${DarkTheme} | ${'dark'} `( 'provides $label for $colorScheme color scheme', async ({ theme, colorScheme }) => { @@ -165,9 +165,9 @@ describe('Provider', () => { it('uses provided custom theme', async () => { mockAppearance(); const customTheme = { - ...DefaultTheme, + ...LightTheme, colors: { - ...DefaultTheme.colors, + ...LightTheme.colors, primary: 'tomato', accent: 'yellow', }, diff --git a/src/core/theming.tsx b/src/core/theming.tsx index 9e35a024ca..4829801384 100644 --- a/src/core/theming.tsx +++ b/src/core/theming.tsx @@ -1,5 +1,5 @@ import { createTheming } from '@callstack/react-theme-provider'; -import DefaultTheme from '../styles/DefaultTheme'; +import LightTheme from '../styles/themes/v2/LightTheme'; export const { ThemeProvider, withTheme, useTheme } = - createTheming(DefaultTheme as ReactNativePaper.Theme); + createTheming(LightTheme as ReactNativePaper.Theme); diff --git a/src/index.tsx b/src/index.tsx index e082feb725..5e2666c3b1 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,12 +1,12 @@ -import * as Colors from './styles/colors'; +import * as Colors from './styles/themes/v2/colors'; export { Colors }; export { useTheme, withTheme, ThemeProvider } from './core/theming'; export { default as Provider } from './core/Provider'; -export { default as DefaultTheme } from './styles/DefaultTheme'; -export { default as DarkTheme } from './styles/DarkTheme'; +export { default as DefaultTheme } from './styles/themes/v2/LightTheme'; +export { default as DarkTheme } from './styles/themes/v2/DarkTheme'; export { default as shadow } from './styles/shadow'; export { default as overlay } from './styles/overlay'; export { default as configureFonts } from './styles/fonts'; diff --git a/src/styles/overlay.tsx b/src/styles/overlay.tsx index 767a6f5efc..21ebc2945a 100644 --- a/src/styles/overlay.tsx +++ b/src/styles/overlay.tsx @@ -1,6 +1,6 @@ import color from 'color'; import { Animated } from 'react-native'; -import DarkTheme from './DarkTheme'; +import DarkTheme from './themes/v2/DarkTheme'; const isAnimatedValue = ( it: number | Animated.AnimatedInterpolation diff --git a/src/styles/shadow.tsx b/src/styles/shadow.tsx index fb13085dc3..91766f809f 100644 --- a/src/styles/shadow.tsx +++ b/src/styles/shadow.tsx @@ -1,4 +1,4 @@ -import * as Colors from './colors'; +import * as Colors from './themes/v2/colors'; import { Animated } from 'react-native'; const SHADOW_COLOR = Colors.black; diff --git a/src/styles/DarkTheme.tsx b/src/styles/themes/v2/DarkTheme.tsx similarity index 76% rename from src/styles/DarkTheme.tsx rename to src/styles/themes/v2/DarkTheme.tsx index 4de0a1da55..35a6019347 100644 --- a/src/styles/DarkTheme.tsx +++ b/src/styles/themes/v2/DarkTheme.tsx @@ -1,14 +1,14 @@ import color from 'color'; -import DefaultTheme from './DefaultTheme'; +import LightTheme from './LightTheme'; import { black, white, pinkA100 } from './colors'; -import type { Theme } from '../types'; +import type { MD2Theme } from '../../../types'; -const DarkTheme: Theme = { - ...DefaultTheme, +const DarkTheme: MD2Theme = { + ...LightTheme, dark: true, mode: 'adaptive', colors: { - ...DefaultTheme.colors, + ...LightTheme.colors, primary: '#BB86FC', accent: '#03dac6', background: '#121212', diff --git a/src/styles/DefaultTheme.tsx b/src/styles/themes/v2/LightTheme.tsx similarity index 75% rename from src/styles/DefaultTheme.tsx rename to src/styles/themes/v2/LightTheme.tsx index aa4967e507..cf901f33ed 100644 --- a/src/styles/DefaultTheme.tsx +++ b/src/styles/themes/v2/LightTheme.tsx @@ -1,11 +1,13 @@ import color from 'color'; import { black, white, pinkA400 } from './colors'; -import configureFonts from './fonts'; -import type { Theme } from '../types'; +import configureFonts from '../../fonts'; +import type { MD2Theme } from '../../../types'; -const DefaultTheme: Theme = { +const LightTheme: MD2Theme = { dark: false, roundness: 4, + version: 2, + isV3: false, colors: { primary: '#6200ee', accent: '#03dac4', @@ -25,4 +27,4 @@ const DefaultTheme: Theme = { }, }; -export default DefaultTheme; +export default LightTheme; diff --git a/src/styles/colors.tsx b/src/styles/themes/v2/colors.tsx similarity index 100% rename from src/styles/colors.tsx rename to src/styles/themes/v2/colors.tsx diff --git a/src/styles/themes/v3/DarkTheme.tsx b/src/styles/themes/v3/DarkTheme.tsx new file mode 100644 index 0000000000..c76fec5009 --- /dev/null +++ b/src/styles/themes/v3/DarkTheme.tsx @@ -0,0 +1,60 @@ +import LightTheme from './LightTheme'; +import type { MD3Theme } from '../../../types'; +import { tokens } from './tokens'; + +const { palette } = tokens.md.ref; + +const DarkTheme: MD3Theme = { + ...LightTheme, + dark: true, + mode: 'adaptive', + version: 3, + tokens: { + ...tokens, + md: { + ...tokens.md, + sys: { + ...tokens.md.sys, + color: { + primary: palette.primary80, + 'primary-container': palette.primary30, + secondary: palette.secondary80, + 'secondary-container': palette.secondary30, + tertiary: palette.tertiary80, + 'tertiary-container': palette.tertiary30, + surface: palette.neutral10, + 'surface-variant': palette['neutral-variant30'], + background: palette.neutral10, + error: palette.error80, + 'error-container': palette.error30, + 'on-primary': palette.primary20, + 'on-primary-container': palette.primary90, + 'on-secondary': palette.secondary20, + 'on-secondary-container': palette.secondary90, + 'on-tertiary': palette.tertiary20, + 'on-tertiary-container': palette.tertiary90, + 'on-surface': palette.neutral90, + 'on-surface-variant': palette['neutral-variant80'], + 'on-error': palette.error20, + 'on-error-container': palette.error80, + 'on-background': palette.neutral90, + outline: palette['neutral-variant60'], + shadow: palette.neutral0, + 'inverse-on-surface': palette.neutral90, + 'inverse-surface': palette.neutral20, + 'inverse-primary': palette.primary40, + }, + + elevation: [ + '0px 1px 2px rgba(0, 0, 0, 0.3), 0px 1px 3px rgba(0, 0, 0, 0.15)', + '0px 1px 2px rgba(0, 0, 0, 0.3), 0px 2px 6px rgba(0, 0, 0, 0.15)', + '0px 1px 3px rgba(0, 0, 0, 0.3), 0px 4px 8px rgba(0, 0, 0, 0.15)', + '0px 2px 3px rgba(0, 0, 0, 0.3), 0px 6px 10px rgba(0, 0, 0, 0.15)', + '0px 4px 4px rgba(0, 0, 0, 0.3), 0px 8px 12px rgba(0, 0, 0, 0.15)', + ], + }, + }, + }, +}; + +export default DarkTheme; diff --git a/src/styles/themes/v3/LightTheme.tsx b/src/styles/themes/v3/LightTheme.tsx new file mode 100644 index 0000000000..f11dadc4d3 --- /dev/null +++ b/src/styles/themes/v3/LightTheme.tsx @@ -0,0 +1,62 @@ +import configureFonts from '../../fonts'; +import type { MD3Theme } from '../../../types'; +import { tokens } from './tokens'; + +const { palette } = tokens.md.ref; + +const LightTheme: MD3Theme = { + dark: false, + roundness: 4, + version: 3, + tokens: { + ...tokens, + md: { + ...tokens.md, + sys: { + ...tokens.md.sys, + color: { + primary: palette.primary40, + 'primary-container': palette.primary90, + secondary: palette.secondary40, + 'secondary-container': palette.secondary90, + tertiary: palette.tertiary40, + 'tertiary-container': palette.tertiary90, + surface: palette.neutral99, + 'surface-variant': palette['neutral-variant90'], + background: palette.neutral99, + error: palette.error40, + 'error-container': palette.error90, + 'on-primary': palette.primary100, + 'on-primary-container': palette.primary10, + 'on-secondary': palette.secondary100, + 'on-secondary-container': palette.secondary10, + 'on-tertiary': palette.tertiary100, + 'on-tertiary-container': palette.tertiary10, + 'on-surface': palette.neutral10, + 'on-surface-variant': palette['neutral-variant30'], + 'on-error': palette.error100, + 'on-error-container': palette.error10, + 'on-background': palette.neutral10, + outline: palette['neutral-variant50'], + shadow: palette.neutral0, + 'inverse-on-surface': palette.neutral20, + 'inverse-surface': palette.neutral95, + 'inverse-primary': palette.primary80, + }, + elevation: [ + '0px 1px 3px rgba(0, 0, 0, 0.15), 0px 1px 2px rgba(0, 0, 0, 0.3)', + '0px 2px 6px rgba(0, 0, 0, 0.15), 0px 1px 2px rgba(0, 0, 0, 0.3)', + '0px 1px 3px rgba(0, 0, 0, 0.3), 0px 4px 8px rgba(0, 0, 0, 0.15)', + '0px 2px 3px rgba(0, 0, 0, 0.3), 0px 6px 10px rgba(0, 0, 0, 0.15)', + '0px 4px 4px rgba(0, 0, 0, 0.3), 0px 8px 12px rgba(0, 0, 0, 0.15)', + ], + }, + }, + }, + fonts: configureFonts(), + animation: { + scale: 1.0, + }, +}; + +export default LightTheme; diff --git a/src/styles/themes/v3/tokens.tsx b/src/styles/themes/v3/tokens.tsx new file mode 100644 index 0000000000..e23e85a7cd --- /dev/null +++ b/src/styles/themes/v3/tokens.tsx @@ -0,0 +1,203 @@ +import type { Font } from '../../../types'; + +const ref = { + palette: { + primary100: 'rgba(255, 255, 255, 1)', + primary99: 'rgba(255, 251, 254, 1)', + primary95: 'rgba(246, 237, 255, 1)', + primary90: 'rgba(234, 221, 255, 1)', + primary80: 'rgba(208, 188, 255, 1)', + primary70: 'rgba(182, 157, 248, 1)', + primary60: 'rgba(154, 130, 219, 1)', + primary50: 'rgba(127, 103, 190, 1)', + primary40: 'rgba(103, 80, 164, 1)', + primary30: 'rgba(79, 55, 139, 1)', + primary20: 'rgba(56, 30, 114, 1)', + primary10: 'rgba(33, 0, 93, 1)', + primary0: 'rgba(0, 0, 0, 1)', + secondary100: 'rgba(255, 255, 255, 1)', + secondary99: 'rgba(255, 251, 254, 1)', + secondary95: 'rgba(246, 237, 255, 1)', + secondary90: 'rgba(232, 222, 248, 1)', + secondary80: 'rgba(204, 194, 220, 1)', + secondary70: 'rgba(176, 167, 192, 1)', + secondary60: 'rgba(149, 141, 165, 1)', + secondary50: 'rgba(122, 114, 137, 1)', + secondary40: 'rgba(98, 91, 113, 1)', + secondary30: 'rgba(74, 68, 88, 1)', + secondary20: 'rgba(51, 45, 65, 1)', + secondary10: 'rgba(29, 25, 43, 1)', + secondary0: 'rgba(0, 0, 0, 1)', + tertiary100: 'rgba(255, 255, 255, 1)', + tertiary99: 'rgba(255, 251, 250, 1)', + tertiary95: 'rgba(255, 236, 241, 1)', + tertiary90: 'rgba(255, 216, 228, 1)', + tertiary80: 'rgba(239, 184, 200, 1)', + tertiary70: 'rgba(210, 157, 172, 1)', + tertiary60: 'rgba(181, 131, 146, 1)', + tertiary50: 'rgba(152, 105, 119, 1)', + tertiary40: 'rgba(125, 82, 96, 1)', + tertiary30: 'rgba(99, 59, 72, 1)', + tertiary20: 'rgba(73, 37, 50, 1)', + tertiary10: 'rgba(49, 17, 29, 1)', + tertiary0: 'rgba(0, 0, 0, 1)', + neutral100: 'rgba(255, 255, 255, 1)', + neutral99: 'rgba(255, 251, 254, 1)', + neutral95: 'rgba(244, 239, 244, 1)', + neutral90: 'rgba(230, 225, 229, 1)', + neutral80: 'rgba(201, 197, 202, 1)', + neutral70: 'rgba(174, 170, 174, 1)', + neutral60: 'rgba(147, 144, 148, 1)', + neutral50: 'rgba(120, 117, 121, 1)', + neutral40: 'rgba(96, 93, 98, 1)', + neutral30: 'rgba(72, 70, 73, 1)', + neutral20: 'rgba(49, 48, 51, 1)', + neutral10: 'rgba(28, 27, 31, 1)', + neutral0: 'rgba(0, 0, 0, 1)', + 'neutral-variant100': 'rgba(255, 255, 255, 1)', + 'neutral-variant99': 'rgba(255, 251, 254, 1)', + 'neutral-variant95': 'rgba(245, 238, 250, 1)', + 'neutral-variant90': 'rgba(231, 224, 236, 1)', + 'neutral-variant80': 'rgba(202, 196, 208, 1)', + 'neutral-variant70': 'rgba(174, 169, 180, 1)', + 'neutral-variant60': 'rgba(147, 143, 153, 1)', + 'neutral-variant50': 'rgba(121, 116, 126, 1)', + 'neutral-variant40': 'rgba(96, 93, 102, 1)', + 'neutral-variant30': 'rgba(73, 69, 79, 1)', + 'neutral-variant20': 'rgba(50, 47, 55, 1)', + 'neutral-variant10': 'rgba(29, 26, 34, 1)', + 'neutral-variant0': 'rgba(0, 0, 0, 1)', + error100: 'rgba(255, 255, 255, 1)', + error99: 'rgba(255, 251, 249, 1)', + error95: 'rgba(252, 238, 238, 1)', + error90: 'rgba(249, 222, 220, 1)', + error80: 'rgba(242, 184, 181, 1)', + error70: 'rgba(236, 146, 142, 1)', + error60: 'rgba(228, 105, 98, 1)', + error50: 'rgba(220, 54, 46, 1)', + error40: 'rgba(179, 38, 30, 1)', + error30: 'rgba(140, 29, 24, 1)', + error20: 'rgba(96, 20, 16, 1)', + error10: 'rgba(65, 14, 11, 1)', + error0: 'rgba(0, 0, 0, 1)', + }, + + typeface: { + 'brand-regular': 'Roboto Regular', + 'weight-regular': '400' as Font['fontWeight'], + + 'plain-medium': 'Roboto Medium', + 'weight-medium': '500' as Font['fontWeight'], + }, + + opacity: [0.08, 0.12, 0.16], +}; + +const regularType = { + font: ref.typeface['brand-regular'], + tracking: 0, + weight: ref.typeface['weight-regular'], +}; + +const mediumType = { + font: ref.typeface['plain-medium'], + tracking: 0.15, + weight: ref.typeface['weight-medium'], +}; + +const typescale = { + 'display-large': { + ...regularType, + 'line-height': 57, + size: 64, + }, + 'display-medium': { + ...regularType, + 'line-height': 52, + size: 45, + }, + 'display-small': { + ...regularType, + 'line-height': 44, + size: 36, + }, + + 'headline-large': { + ...regularType, + 'line-height': 40, + size: 32, + }, + 'headline-medium': { + ...regularType, + 'line-height': 36, + size: 28, + }, + 'headline-small': { + ...regularType, + 'line-height': 32, + size: 24, + }, + + 'title-large': { + ...regularType, + 'line-height': 28, + size: 22, + }, + 'title-medium': { + ...mediumType, + 'line-height': 24, + size: 16, + }, + 'title-small': { + ...mediumType, + 'line-height': 20, + size: 14, + }, + + 'label-large': { + ...regularType, + tracking: 0.1, + 'line-height': 20, + size: 14, + }, + 'label-medium': { + ...mediumType, + tracking: 0.5, + 'line-height': 16, + size: 12, + }, + 'label-small': { + ...mediumType, + tracking: 0.5, + 'line-height': 6, + size: 11, + }, + + 'body-large': { + ...mediumType, + tracking: 0.15, + 'line-height': 24, + size: 16, + }, + 'body-medium': { + ...mediumType, + tracking: 0.25, + 'line-height': 20, + size: 14, + }, + 'body-small': { + ...mediumType, + tracking: 0.4, + 'line-height': 16, + size: 12, + }, +}; + +export const tokens = { + md: { + ref, + sys: { + typescale, + }, + }, +}; diff --git a/src/types.tsx b/src/types.tsx index 6b1a90064a..1cf28ab01c 100644 --- a/src/types.tsx +++ b/src/types.tsx @@ -25,29 +25,117 @@ export type Fonts = { type Mode = 'adaptive' | 'exact'; -export type Theme = { +export type Material2Colors = { + primary: string; + background: string; + surface: string; + accent: string; + error: string; + text: string; + onSurface: string; + disabled: string; + placeholder: string; + backdrop: string; + notification: string; +}; + +export type MD3Color = { + primary: string; + 'primary-container': string; + secondary: string; + 'secondary-container': string; + tertiary: string; + 'tertiary-container': string; + surface: string; + 'surface-variant': string; + background: string; + error: string; + 'error-container': string; + 'on-primary': string; + 'on-primary-container': string; + 'on-secondary': string; + 'on-secondary-container': string; + 'on-tertiary': string; + 'on-tertiary-container': string; + 'on-surface': string; + 'on-surface-variant': string; + 'on-error': string; + 'on-error-container': string; + 'on-background': string; + outline: string; + shadow: string; + 'inverse-surface': string; + 'inverse-on-surface': string; + 'inverse-primary': string; +}; + +export type MD3Palette = {}; + +type SharedTheme = { dark: boolean; mode?: Mode; roundness: number; - colors: { - primary: string; - background: string; - surface: string; - accent: string; - error: string; - text: string; - onSurface: string; - disabled: string; - placeholder: string; - backdrop: string; - notification: string; - }; + version?: 2 | 3; + isV3?: boolean; fonts: Fonts; + userDefinedThemeProperty: string; animation: { scale: number; }; }; +export type Theme = AllXOR<[MD2Theme, MD3Theme]>; + +export type MD2Theme = SharedTheme & { + colors: Material2Colors; +}; + +export type MD3Theme = SharedTheme & { + tokens: { + md: { + sys: { + color: MD3Color; + elevation: string[]; + }; + ref: { + palette: MD3Palette; + typeface: { + 'brand-regular': Font['fontFamily']; + 'weight-regular': Font['fontWeight']; + 'plain-medium': Font['fontFamily']; + 'weight-medium': Font['fontWeight']; + }; + opacity: number[]; + }; + }; + }; + md?(tokenKey: MD3Token): string | number | object; +}; + +type Without = { [P in Exclude]?: never }; + +export type XOR = T | U extends object + ? (Without & U) | (Without & T) + : T | U; + +export type AllXOR = T extends [infer Only] + ? Only + : T extends [infer A, infer B, ...infer Rest] + ? AllXOR<[XOR, ...Rest]> + : never; + +type PathImpl = K extends string + ? T[K] extends Record + ? T[K] extends ArrayLike + ? K | `${K}.${PathImpl>>}` + : K | `${K}.${PathImpl}` + : K + : never; + +type Path = PathImpl | keyof T; + +export type MD3Token = Path; + export type $Omit = Pick>; export type $RemoveChildren> = $Omit< React.ComponentPropsWithoutRef, @@ -96,14 +184,5 @@ declare global { interface ThemeAnimation { scale: number; } - - interface Theme { - dark: boolean; - mode?: Mode; - roundness: number; - colors: ThemeColors; - fonts: ThemeFonts; - animation: ThemeAnimation; - } } } diff --git a/yarn.lock b/yarn.lock index b8a0fd3c26..4726b4fd2d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -440,6 +440,13 @@ dependencies: "@babel/types" "^7.16.7" +"@babel/helper-module-imports@^7.0.0-beta.49", "@babel/helper-module-imports@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz#25612a8091a999704461c8a222d0efec5d091437" + integrity sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg== + dependencies: + "@babel/types" "^7.16.7" + "@babel/helper-module-imports@^7.10.1", "@babel/helper-module-imports@^7.10.3": version "7.10.3" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.10.3.tgz#766fa1d57608e53e5676f23ae498ec7a95e1b11a" @@ -454,13 +461,6 @@ dependencies: "@babel/types" "^7.12.5" -"@babel/helper-module-imports@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz#25612a8091a999704461c8a222d0efec5d091437" - integrity sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg== - dependencies: - "@babel/types" "^7.16.7" - "@babel/helper-module-transforms@^7.10.1": version "7.10.1" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.10.1.tgz#24e2f08ee6832c60b157bb0936c86bef7210c622" @@ -2074,6 +2074,14 @@ lodash "^4.17.13" to-fast-properties "^2.0.0" +"@babel/types@^7.0.0-beta.49", "@babel/types@^7.16.0", "@babel/types@^7.16.8": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.16.8.tgz#0ba5da91dd71e0a4e7781a30f22770831062e3c1" + integrity sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + to-fast-properties "^2.0.0" + "@babel/types@^7.10.4", "@babel/types@^7.10.5", "@babel/types@^7.11.0", "@babel/types@^7.12.1", "@babel/types@^7.12.10", "@babel/types@^7.12.5", "@babel/types@^7.12.7", "@babel/types@^7.9.0": version "7.12.10" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.12.10.tgz#7965e4a7260b26f09c56bcfcb0498af1f6d9b260" @@ -2092,14 +2100,6 @@ lodash "^4.17.19" to-fast-properties "^2.0.0" -"@babel/types@^7.16.0", "@babel/types@^7.16.8": - version "7.16.8" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.16.8.tgz#0ba5da91dd71e0a4e7781a30f22770831062e3c1" - integrity sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg== - dependencies: - "@babel/helper-validator-identifier" "^7.16.7" - to-fast-properties "^2.0.0" - "@babel/types@^7.16.7", "@babel/types@^7.7.0": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.16.7.tgz#4ed19d51f840ed4bd5645be6ce40775fecf03159" @@ -3012,6 +3012,11 @@ dependencies: "@types/node" "*" +"@types/lodash@^4.14.178": + version "4.14.178" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.178.tgz#341f6d2247db528d4a13ddbb374bcdc80406f4f8" + integrity sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw== + "@types/minimist@^1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.0.tgz#69a23a3ad29caf0097f06eda59b361ee2f0639f6" @@ -3813,6 +3818,17 @@ babel-plugin-jest-hoist@^26.1.0: "@types/babel__core" "^7.0.0" "@types/babel__traverse" "^7.0.6" +babel-plugin-lodash@^3.3.4: + version "3.3.4" + resolved "https://registry.yarnpkg.com/babel-plugin-lodash/-/babel-plugin-lodash-3.3.4.tgz#4f6844358a1340baed182adbeffa8df9967bc196" + integrity sha512-yDZLjK7TCkWl1gpBeBGmuaDIFhZKmkoL+Cu2MUUjv5VxUZx/z7tBGBCBcQs5RI1Bkz5LLmNdjx7paOyQtMovyg== + dependencies: + "@babel/helper-module-imports" "^7.0.0-beta.49" + "@babel/types" "^7.0.0-beta.49" + glob "^7.1.1" + lodash "^4.17.10" + require-package-name "^2.0.1" + babel-plugin-syntax-trailing-function-commas@^7.0.0-beta.0: version "7.0.0-beta.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-7.0.0-beta.0.tgz#aa213c1435e2bffeb6fca842287ef534ad05d5cf" @@ -8566,6 +8582,11 @@ lodash@^4.17.19: resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== +lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + log-symbols@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" @@ -10787,6 +10808,11 @@ require-main-filename@^2.0.0: resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== +require-package-name@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/require-package-name/-/require-package-name-2.0.1.tgz#c11e97276b65b8e2923f75dabf5fb2ef0c3841b9" + integrity sha1-wR6XJ2tluOKSP3Xav1+y7ww4Qbk= + resolve-alpn@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.0.0.tgz#745ad60b3d6aff4b4a48e01b8c0bdc70959e0e8c"