diff --git a/src/assets/translations/en/main.json b/src/assets/translations/en/main.json index c60be974583..2dfaf1da28c 100644 --- a/src/assets/translations/en/main.json +++ b/src/assets/translations/en/main.json @@ -188,7 +188,8 @@ "activeAccount": "Active Account", "update": "Update", "apy": "APY", - "tbd": "TBD" + "tbd": "TBD", + "installed": "Installed" }, "consentBanner": { "body": { @@ -1871,6 +1872,15 @@ "onboarding": { "skip": "Skip", "shapeshiftWallet": "ShapeShift Wallet", + "createNewWallet": "Create a new wallet", + "shapeshiftNative": "ShapeShift Native", + "addNewWallet": "Add new wallet", + "comingFromThorswap": "Coming from THORSwap?", + "importExisting": "Import existing", + "importFromKeystore": "Import from keystore", + "whatIsShapeshiftWallet": "What is ShapeShift Wallet?", + "yourDecentralizedGateway": "Your decentralization gateway. Trade and earn Bitcoin, Ethereum, Solana and more from a single, secure wallet.", + "crossChainFreedom": "Cross chain freedom. Access the best rates across multiple decentralized exchanges, no middleman required", "selfCustody": { "title": "Your ShapeShift Wallet is Self-Custody", "subTitle": "You hold the keys and you're the only one who can access it.", diff --git a/src/context/WalletProvider/NativeWallet/components/NativeImportKeystore.tsx b/src/context/WalletProvider/NativeWallet/components/NativeImportKeystore.tsx index ed4e2671c01..96f13c695b6 100644 --- a/src/context/WalletProvider/NativeWallet/components/NativeImportKeystore.tsx +++ b/src/context/WalletProvider/NativeWallet/components/NativeImportKeystore.tsx @@ -28,7 +28,6 @@ const hoverSx = { borderColor: 'blue.500' } // TODO(gomes): use https://www.chakra-ui.com/docs/components/file-upload if/when we migrate to chakra@3 const FileUpload = ({ onFileSelect }: { onFileSelect: (file: File) => void }) => { - const bgColor = useColorModeValue('gray.50', 'gray.800') const borderColor = useColorModeValue('gray.200', 'gray.600') const [isDragging, setIsDragging] = useState(false) const [filename, setFilename] = useState(null) @@ -98,7 +97,7 @@ const FileUpload = ({ onFileSelect }: { onFileSelect: (file: File) => void }) => flexDirection='column' alignItems='center' justifyContent='center' - bg={bgColor} + bg='background.surface.raised.base' cursor='pointer' transition='all 0.2s' _hover={hoverSx} diff --git a/src/context/WalletProvider/NativeWallet/components/NativePassword.tsx b/src/context/WalletProvider/NativeWallet/components/NativePassword.tsx index 61be77a68c0..f60b7f7cf34 100644 --- a/src/context/WalletProvider/NativeWallet/components/NativePassword.tsx +++ b/src/context/WalletProvider/NativeWallet/components/NativePassword.tsx @@ -44,6 +44,7 @@ export const NativePassword = ({ history, location }: NativeSetupProps) => { vault.seal() await vault.setPassword(values.password) vault.meta.set('name', values.name) + history.push(NativeWalletRoutes.Success, { vault }) } catch (e) { console.error(e) diff --git a/src/context/WalletProvider/NativeWallet/components/NativeSuccess.tsx b/src/context/WalletProvider/NativeWallet/components/NativeSuccess.tsx index 124e0df011c..9c1538bc8d2 100644 --- a/src/context/WalletProvider/NativeWallet/components/NativeSuccess.tsx +++ b/src/context/WalletProvider/NativeWallet/components/NativeSuccess.tsx @@ -1,12 +1,19 @@ import { Box, ModalBody, ModalHeader } from '@chakra-ui/react' +import { useQueryClient } from '@tanstack/react-query' +import { reactQueries } from 'react-queries' import { Text } from 'components/Text' import { useNativeSuccess } from '../hooks/useNativeSuccess' import type { NativeSetupProps } from '../types' export const NativeSuccess = ({ location }: NativeSetupProps) => { + const queryClient = useQueryClient() const { isSuccessful } = useNativeSuccess({ vault: location.state.vault }) + queryClient.invalidateQueries({ + queryKey: reactQueries.common.hdwalletNativeVaultsList().queryKey, + }) + return ( <> diff --git a/src/context/WalletProvider/NativeWallet/config.ts b/src/context/WalletProvider/NativeWallet/config.ts index 8d588ebb8ca..1b0d5fdef4c 100644 --- a/src/context/WalletProvider/NativeWallet/config.ts +++ b/src/context/WalletProvider/NativeWallet/config.ts @@ -1,5 +1,5 @@ import type { NativeAdapter } from '@shapeshiftoss/hdwallet-native' -import { FoxIcon } from 'components/Icons/FoxIcon' // Ensure the import path is correct +import { FoxIcon } from 'components/Icons/FoxIcon' import type { SupportedWalletInfo } from 'context/WalletProvider/config' type NativeConfigType = Omit, 'routes'> diff --git a/src/context/WalletProvider/NativeWallet/types.ts b/src/context/WalletProvider/NativeWallet/types.ts index f8adc9d889a..491d952c0c0 100644 --- a/src/context/WalletProvider/NativeWallet/types.ts +++ b/src/context/WalletProvider/NativeWallet/types.ts @@ -1,7 +1,5 @@ import type { Vault } from '@shapeshiftoss/hdwallet-native-vault' -import type React from 'react' import type { RouteComponentProps } from 'react-router-dom' -import type { ActionTypes } from 'context/WalletProvider/actions' export type NativeWalletValues = { name: string @@ -22,12 +20,4 @@ export interface LocationState { } } -export interface NativeSetupProps - extends RouteComponentProps< - {}, - any, // history - LocationState - > { - vault: Vault - dispatch: React.Dispatch -} +export type NativeSetupProps = RouteComponentProps<{}, any, LocationState> diff --git a/src/context/WalletProvider/NewWalletViews/NewWalletViewsSwitch.tsx b/src/context/WalletProvider/NewWalletViews/NewWalletViewsSwitch.tsx index 111d91307b5..3e9ef9096d7 100644 --- a/src/context/WalletProvider/NewWalletViews/NewWalletViewsSwitch.tsx +++ b/src/context/WalletProvider/NewWalletViews/NewWalletViewsSwitch.tsx @@ -1,6 +1,7 @@ import { ArrowBackIcon } from '@chakra-ui/icons' import { Box, + Divider, Flex, IconButton, Modal, @@ -10,9 +11,12 @@ import { useColorModeValue, useToast, } from '@chakra-ui/react' +import type { Location } from 'history' import { useCallback, useEffect, useMemo, useState } from 'react' import { isMobile } from 'react-device-detect' import { useTranslate } from 'react-polyglot' +import type { StaticContext } from 'react-router' +import type { RouteComponentProps } from 'react-router-dom' import { Route, Switch, useHistory } from 'react-router-dom' import { Text } from 'components/Text' import { WalletActions } from 'context/WalletProvider/actions' @@ -20,9 +24,21 @@ import { useWallet } from 'hooks/useWallet/useWallet' import { SnapInstall } from '../MetaMask/components/SnapInstall' import { SnapUpdate } from '../MetaMask/components/SnapUpdate' +import { EnterPassword } from '../NativeWallet/components/EnterPassword' +import { NativeCreate } from '../NativeWallet/components/NativeCreate' +import { NativeImportKeystore } from '../NativeWallet/components/NativeImportKeystore' +import { NativeImportSeed } from '../NativeWallet/components/NativeImportSeed' +import { NativeImportSelect } from '../NativeWallet/components/NativeImportSelect' +import { NativePassword } from '../NativeWallet/components/NativePassword' +import { NativeSuccess } from '../NativeWallet/components/NativeSuccess' +import { NativeTestPhrase } from '../NativeWallet/components/NativeTestPhrase' +import type { NativeSetupProps } from '../NativeWallet/types' import { NativeWalletRoutes } from '../types' import { InstalledWalletsSection } from './sections/InstalledWalletsSection' +import { SavedWalletsSection } from './sections/SavedWalletsSection' import { MipdBody } from './wallets/mipd/MipdBody' +import { NativeIntro } from './wallets/native/NativeIntro' +import { NativeStart } from './wallets/native/NativeStart' const sectionsWidth = { base: 'full', md: '300px' } const containerWidth = { @@ -38,18 +54,85 @@ type RightPanelContentProps = { setIsLoading: (loading: boolean) => void error: string | null setError: (error: string | null) => void + location: Location } +const nativeRoutes = ( + + } + /> + } + /> + } + /> + } + /> + + + + } + /> + + + + } + /> + } + /> + +) + const RightPanelContent = ({ isLoading, setIsLoading, error, setError, + location, }: RightPanelContentProps) => { const { state: { modalType, isMipdProvider }, } = useWallet() + if (location.pathname.startsWith('/native')) return nativeRoutes + + // No modal type, and no in-flight native routes - assume enpty state + if (!modalType || modalType === 'native' || location.pathname === '/') return + if (isMipdProvider && modalType) { return ( @@ -63,27 +146,10 @@ const RightPanelContent = ({ /> - - - - - + - - - - - - - - + ) @@ -95,6 +161,9 @@ const RightPanelContent = ({ export const NewWalletViewsSwitch = () => { const [isLoading, setIsLoading] = useState(false) const [error, setError] = useState(null) + // For visual tracking only. Do *not* use me in place of wallet state. This means exactly what you think the intent is: + // the option which is currently selected by the user (has been clicked), and is *not* related to the current wallet in the store. + const [selectedWalletId, setSelectedWalletId] = useState(null) const history = useHistory() const toast = useToast() @@ -103,8 +172,6 @@ export const NewWalletViewsSwitch = () => { state: { wallet, modal, - initialRoute, - modalType, disconnectOnCloseModal, deviceState: { disposition }, }, @@ -159,77 +226,101 @@ export const NewWalletViewsSwitch = () => { wallet, ]) + const handleWalletSelect = useCallback( + (walletId: string, _initialRoute: string) => { + setSelectedWalletId(walletId) + if (_initialRoute) history.push(_initialRoute) + }, + [history], + ) + // Reset history on modal open/unmount useEffect(() => { - if (initialRoute) history.push(initialRoute) - }, [history, initialRoute]) + history.replace('/') - // Reset initial route on connect to handle e.g switching from MM with snap install route to another mipd provider - const handleConnect = useCallback(() => { - if (initialRoute) history.push(initialRoute) - }, [history, initialRoute]) + return () => { + history.replace('/') + } + // Only run this on initial render, and unmount + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []) const sections = useMemo( () => ( - + + + {/* TODO(gomes): more sections */} ), - [handleConnect, isLoading, modalType], + [handleWalletSelect, isLoading, selectedWalletId], ) const bodyBgColor = useColorModeValue('gray.50', 'whiteAlpha.50') const buttonContainerBgColor = useColorModeValue('gray.100', 'whiteAlpha.100') - const body = useMemo(() => { - return ( - - - - ) - }, [bodyBgColor, error, isLoading]) - const maybeMobileBackButton = useMemo(() => { - if (!isMobile) return - return ( - - - - {/* Precisely what it says on the var name - adds a back button for mobile only, and for non-root paths only - * (i.e, can't go back when in root path) - */} - - - - - - ) - }, [buttonContainerBgColor, handleBack, translate]) + const body = useCallback( + (routeProps: RouteComponentProps<{}, StaticContext, unknown>) => { + // These routes do not have a previous step, so don't display back button + const isRootRoute = + routeProps.history.location.pathname === '/' || + routeProps.history.location.pathname === '/metamask/connect' + return ( + + {!isRootRoute || isMobile ? ( + + + + ) : null} + + + + + + + ) + }, + [bodyBgColor, buttonContainerBgColor, error, handleBack, isLoading, translate], + ) + + const bodyDesktopOnly = useCallback( + (routeProps: RouteComponentProps<{}, StaticContext, unknown>) => { + if (isMobile) return null + + return body(routeProps) + }, + [body], + ) return ( <> @@ -253,9 +344,7 @@ export const NewWalletViewsSwitch = () => { > - - {maybeMobileBackButton} - + {/* Always display sections for the root route, no matter the viewport */} @@ -266,11 +355,9 @@ export const NewWalletViewsSwitch = () => { {/* Only display side panel after a wallet has been selected on mobile */} - - {!isMobile ? body : null} - + {/* And for all non-root routes, no matter the viewport */} - {body} + diff --git a/src/context/WalletProvider/NewWalletViews/sections/InstalledWalletsSection.tsx b/src/context/WalletProvider/NewWalletViews/sections/InstalledWalletsSection.tsx index fac62e0d011..2b507a36796 100644 --- a/src/context/WalletProvider/NewWalletViews/sections/InstalledWalletsSection.tsx +++ b/src/context/WalletProvider/NewWalletViews/sections/InstalledWalletsSection.tsx @@ -1,4 +1,4 @@ -import { Box, Button, Flex, Image, Stack, Text as CText } from '@chakra-ui/react' +import { Box, Button, Flex, Image, Stack, Text as CText, useColorModeValue } from '@chakra-ui/react' import { uniqBy } from 'lodash' import type { EIP6963ProviderDetail } from 'mipd' import { useCallback, useMemo } from 'react' @@ -20,6 +20,7 @@ const MipdProviderSelectItem = ({ isSelected: boolean isDisabled: boolean }) => { + const backgroundColor = useColorModeValue('blackAlpha.100', 'whiteAlpha.100') const handleConnect = useCallback( () => connect(provider.info.rdns), [connect, provider.info.rdns], @@ -36,7 +37,7 @@ const MipdProviderSelectItem = ({ borderRadius='md' width='full' onClick={handleConnect} - bg={isSelected ? 'whiteAlpha.100' : undefined} + bg={isSelected ? backgroundColor : undefined} isDisabled={isDisabled} > @@ -48,13 +49,13 @@ const MipdProviderSelectItem = ({ } export const InstalledWalletsSection = ({ - modalType, isLoading, - onConnect, + selectedWalletId, + onWalletSelect, }: { - modalType: string | null isLoading: boolean - onConnect: () => void + selectedWalletId: string | null + onWalletSelect: (id: string, initialRoute: string) => void }) => { const { connect } = useWallet() const detectedMipdProviders = useMipdProviders() @@ -90,17 +91,17 @@ export const InstalledWalletsSection = ({ const handleConnectMipd = useCallback( (rdns: string) => { + onWalletSelect(rdns, '/metamask/connect') connect(rdns as KeyManager, true) - onConnect() }, - [connect, onConnect], + [connect, onWalletSelect], ) return ( - + {filteredProviders.map(provider => { - const isSelected = modalType === provider.info.rdns + const isSelected = selectedWalletId === provider.info.rdns return ( void + isSelected: boolean +} + +const WalletCard = ({ wallet, onClick, isSelected }: WalletCardProps) => { + const handleClick = useCallback(() => onClick(wallet), [onClick, wallet]) + const bgColor = useColorModeValue('blackAlpha.100', 'whiteAlpha.100') + + return ( + + + + + + + + {wallet.name} + + + + + ) +} + +export const SavedWalletsSection = ({ + selectedWalletId, + onWalletSelect, +}: { + selectedWalletId: string | null + onWalletSelect: (id: string, initialRoute: string) => void +}) => { + const buttonBgColor = useColorModeValue('blackAlpha.50', 'whiteAlpha.50') + + const history = useHistory() + const localWallet = useLocalWallet() + const { getAdapter, dispatch } = useWallet() + + const nativeVaultsQuery = useQuery({ + ...reactQueries.common.hdwalletNativeVaultsList(), + refetchOnMount: true, + }) + + const handleWalletSelect = useCallback( + async (wallet: VaultInfo) => { + // Ensure we're at the correct route when selecting a saved wallet + dispatch({ type: WalletActions.SET_INITIAL_ROUTE, payload: '/native/enter-password' }) + // Ensure the wallet is visually selected in the left wallets list + onWalletSelect(wallet.id, '/native/enter-password') + + const adapter = await getAdapter(KeyManager.Native) + const deviceId = wallet.id + if (adapter) { + const { name, icon } = NativeConfig + try { + dispatch({ + type: WalletActions.SET_NATIVE_PENDING_DEVICE_ID, + payload: deviceId, + }) + + const walletInstance = await adapter.pairDevice(deviceId) + if (!(await walletInstance?.isInitialized())) { + await walletInstance?.initialize() + } else { + dispatch({ + type: WalletActions.SET_WALLET, + payload: { + wallet: walletInstance, + name, + icon, + deviceId, + meta: { label: wallet.name }, + connectedType: KeyManager.Native, + }, + }) + dispatch({ + type: WalletActions.SET_IS_CONNECTED, + payload: true, + }) + dispatch({ type: WalletActions.RESET_NATIVE_PENDING_DEVICE_ID }) + dispatch({ type: WalletActions.SET_WALLET_MODAL, payload: false }) + } + + localWallet.setLocalWallet({ type: KeyManager.Native, deviceId }) + localWallet.setLocalNativeWalletName(wallet.name) + } catch (e) { + console.error(e) + } + } + }, + [dispatch, getAdapter, localWallet, onWalletSelect], + ) + + const handleAddNewWalletClick = useCallback(() => { + history.push(NativeWalletRoutes.Connect) + }, [history]) + + if (!nativeVaultsQuery.data?.length) return null + + return ( + <> + + + {nativeVaultsQuery.data.map(wallet => ( + + ))} + + + + + + + + + + + ) +} diff --git a/src/context/WalletProvider/NewWalletViews/wallets/mipd/MipdBody.tsx b/src/context/WalletProvider/NewWalletViews/wallets/mipd/MipdBody.tsx index 84f05efe634..5535a4430b2 100644 --- a/src/context/WalletProvider/NewWalletViews/wallets/mipd/MipdBody.tsx +++ b/src/context/WalletProvider/NewWalletViews/wallets/mipd/MipdBody.tsx @@ -211,7 +211,6 @@ export const MipdBody = ({ rdns, isLoading, error, setIsLoading, setError }: Mip loadingText={translate('common.pairing')} spinner={spinner} onClick={pairDevice} - data-test='wallet-pair-button' > {translate('walletProvider.mipd.connect.button')} diff --git a/src/context/WalletProvider/NewWalletViews/wallets/native/NativeIntro.tsx b/src/context/WalletProvider/NewWalletViews/wallets/native/NativeIntro.tsx new file mode 100644 index 00000000000..89a193831cd --- /dev/null +++ b/src/context/WalletProvider/NewWalletViews/wallets/native/NativeIntro.tsx @@ -0,0 +1,98 @@ +import { + Box, + Button, + Divider, + Flex, + Icon, + Stack, + Text as CText, + useColorModeValue, +} from '@chakra-ui/react' +import { useCallback } from 'react' +import { FaArrowRight } from 'react-icons/fa' +import { useTranslate } from 'react-polyglot' +import { useHistory } from 'react-router-dom' +import { FoxIcon } from 'components/Icons/FoxIcon' +import { Text } from 'components/Text' +import { NativeWalletRoutes } from 'context/WalletProvider/types' + +export const NativeIntro = () => { + const translate = useTranslate() + const history = useHistory() + + const headingColor = useColorModeValue('gray.800', 'whiteAlpha.800') + const bodyColor = useColorModeValue('gray.600', 'whiteAlpha.600') + const mainTextColor = useColorModeValue('gray.700', 'whiteAlpha.800') + + const handleCreateClick = useCallback(() => history.push(NativeWalletRoutes.Create), [history]) + const handleImportClick = useCallback( + () => history.push(NativeWalletRoutes.ImportSelect), + [history], + ) + const handleImportKeystoreClick = useCallback( + () => history.push(NativeWalletRoutes.ImportKeystore), + [history], + ) + + return ( + + + + + + + + + + + + + + + + + + + {translate('walletProvider.shapeShift.onboarding.comingFromThorswap')}{' '} + + + + + ) +} diff --git a/src/context/WalletProvider/NewWalletViews/wallets/native/NativeStart.tsx b/src/context/WalletProvider/NewWalletViews/wallets/native/NativeStart.tsx new file mode 100644 index 00000000000..b5765bd2b4d --- /dev/null +++ b/src/context/WalletProvider/NewWalletViews/wallets/native/NativeStart.tsx @@ -0,0 +1,52 @@ +import { ArrowForwardIcon } from '@chakra-ui/icons' +import { Button, Divider, ModalBody, ModalHeader, Stack } from '@chakra-ui/react' +import { useCallback } from 'react' +import type { RouteComponentProps } from 'react-router' +import { Text } from 'components/Text' +import { NativeWalletRoutes } from 'context/WalletProvider/types' + +const arrowForwardIcon = + +export const NativeStart = ({ history }: RouteComponentProps) => { + const handleCreate = useCallback(() => history.push(NativeWalletRoutes.Create), [history]) + const handleImportClick = useCallback( + () => history.push(NativeWalletRoutes.ImportSelect), + [history], + ) + + return ( + <> + + + + + + + + + + + + + ) +} diff --git a/src/context/WalletProvider/WalletProvider.test.tsx b/src/context/WalletProvider/WalletProvider.test.tsx index 6fe622ca385..69a1c74f4e5 100644 --- a/src/context/WalletProvider/WalletProvider.test.tsx +++ b/src/context/WalletProvider/WalletProvider.test.tsx @@ -34,6 +34,13 @@ vi.mock('@shapeshiftoss/hdwallet-metamask-multichain', () => ({ }, })) +vi.mock('@shapeshiftoss/hdwallet-native-vault', () => ({ + Vault: { + list: vi.fn().mockResolvedValue([]), + meta: vi.fn(), + }, +})) + vi.mock('./useEip1993EventHandler', () => ({ useEip1993EventHandler: vi.fn(), })) diff --git a/src/context/WalletProvider/WalletViewsRouter.tsx b/src/context/WalletProvider/WalletViewsRouter.tsx index c456a2677cd..1504f7cd711 100644 --- a/src/context/WalletProvider/WalletViewsRouter.tsx +++ b/src/context/WalletProvider/WalletViewsRouter.tsx @@ -1,5 +1,6 @@ import { MemoryRouter } from 'react-router-dom' import { useFeatureFlag } from 'hooks/useFeatureFlag/useFeatureFlag' +import { useWallet } from 'hooks/useWallet/useWallet' import { NewWalletViewsSwitch } from './NewWalletViews/NewWalletViewsSwitch' import { WalletViewsSwitch } from './WalletViewsSwitch' @@ -7,6 +8,13 @@ import { WalletViewsSwitch } from './WalletViewsSwitch' export const WalletViewsRouter = () => { const isNewWalletFlowEnabled = useFeatureFlag('NewWalletFlow') + const { + state: { modal }, + } = useWallet() + + // Do *not* render the modal if it's not opened. Else, effects that shouldn't *will* run and produce bugs. + if (!modal) return null + return ( {isNewWalletFlowEnabled ? : } diff --git a/src/react-queries/queries/common.ts b/src/react-queries/queries/common.ts index e3d7c0d888d..aba30e56f12 100644 --- a/src/react-queries/queries/common.ts +++ b/src/react-queries/queries/common.ts @@ -101,4 +101,22 @@ export const common = createQueryKeys('common', { }) => ({ queryKey: ['evmFees', to, chainId, data, value, from], }), + hdwalletNativeVaultsList: () => ({ + queryKey: ['hdwalletNativeVaultsList'], + queryFn: async () => { + const Vault = await import('@shapeshiftoss/hdwallet-native-vault').then(m => m.Vault) + + const storedWallets = await Vault.list().then(vaultIds => + Promise.all( + vaultIds.map(async id => { + const meta = await Vault.meta(id) + const name = String(meta?.get('name') ?? id) + return { id, name } + }), + ), + ) + + return storedWallets + }, + }), }) diff --git a/src/test/TestProviders.tsx b/src/test/TestProviders.tsx index 3e6822be8a1..cc2d31f6a99 100644 --- a/src/test/TestProviders.tsx +++ b/src/test/TestProviders.tsx @@ -1,3 +1,4 @@ +import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import type { PropsWithChildren } from 'react' import React from 'react' import { I18n } from 'react-polyglot' @@ -8,11 +9,14 @@ import { store } from 'state/store' const locale: string = navigator?.language?.split('-')[0] ?? 'en' const messages = translations['en'] +const queryClient = new QueryClient() + export const TestProviders: React.FC = ({ children }) => ( - - - {/* @ts-ignore remove warning */} - {children} - - + + + + {children} + + + ) diff --git a/src/theme/semanticTokens.ts b/src/theme/semanticTokens.ts index ec46d37ca95..f5b7f0915b5 100644 --- a/src/theme/semanticTokens.ts +++ b/src/theme/semanticTokens.ts @@ -61,15 +61,15 @@ export const semanticTokens = { }, input: { base: { - default: 'gray.50', + default: 'gray.100', _dark: 'darkNeutral.900', }, hover: { - default: 'gray.100', + default: 'gray.150', _dark: 'darkNeutral.800', }, pressed: { - default: 'gray.200', + default: 'gray.250', _dark: 'darkNeutral.900', }, },