Skip to content

Commit

Permalink
feat: modal v2
Browse files Browse the repository at this point in the history
  • Loading branch information
magiziz committed Jan 22, 2024
1 parent 0f62e35 commit e1e02c1
Show file tree
Hide file tree
Showing 8 changed files with 129 additions and 115 deletions.
4 changes: 3 additions & 1 deletion packages/rainbowkit/src/components/ChainModal/Chain.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ interface ChainProps {
iconBackground: string | undefined;
src: string | AsyncImageSrc | undefined | null;
idx: number;
isConnected?: boolean;
}

const Chain = ({
Expand All @@ -30,6 +31,7 @@ const Chain = ({
src,
name,
iconBackground,
isConnected,
idx,
}: ChainProps) => {
const mobile = isMobile();
Expand Down Expand Up @@ -74,7 +76,7 @@ const Chain = ({
)}
<div>{name ?? name}</div>
</Box>
{isCurrentChain && (
{isCurrentChain && isConnected && (
<Box
alignItems="center"
display="flex"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ import { renderWithProviders } from '../../../test/';
import { ChainModal } from './ChainModal';

describe('<ChainModal />', () => {
it('Show current connected chain indicator', async () => {
it('Show current chain selected status', async () => {
const modal = renderWithProviders(<ChainModal onClose={() => {}} open />, {
mock: true,
});
const mainnetOption = await modal.findByTestId(
`rk-chain-option-${mainnet.id}`,
);

expect(mainnetOption).toHaveTextContent('Connected');
expect(mainnetOption).toHaveTextContent('Ethereum');
expect(mainnetOption).toBeDisabled();
});

Expand Down Expand Up @@ -55,13 +55,13 @@ describe('<ChainModal />', () => {
`rk-chain-option-${arbitrum.id}`,
);

expect(mainnetOption).toHaveTextContent('Connected');
expect(arbitrumOption).not.toHaveTextContent('Connected');
expect(mainnetOption).toHaveTextContent('Ethereum');
expect(mainnetOption).toBeDisabled();

await user.click(arbitrumOption);

expect(mainnetOption).not.toHaveTextContent('Connected');
expect(arbitrumOption).toHaveTextContent('Connected');
expect(arbitrumOption).toHaveTextContent('Arbitrum');
expect(arbitrumOption).toBeDisabled();

expect(onCloseGotCalled).toBe(true);
});
Expand Down
7 changes: 5 additions & 2 deletions packages/rainbowkit/src/components/ChainModal/ChainModal.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useContext, useState } from 'react';
import { useChainId, useDisconnect, useSwitchChain } from 'wagmi';
import { useAccount, useChainId, useDisconnect, useSwitchChain } from 'wagmi';
import { useConfig } from 'wagmi';
import { isMobile } from '../../utils/isMobile';
import { Box } from '../Box/Box';
Expand All @@ -23,7 +23,9 @@ export interface ChainModalProps {
}

export function ChainModal({ onClose, open }: ChainModalProps) {
const chainId = useChainId();
const { chainId: connectedChainId, isConnected } = useAccount();
const currentChainId = useChainId();
const chainId = isConnected ? connectedChainId : currentChainId;
const { chains } = useConfig();
const [pendingChainId, setPendingChainId] = useState<number | null>(null);
const { switchChain } = useSwitchChain({
Expand Down Expand Up @@ -101,6 +103,7 @@ export function ChainModal({ onClose, open }: ChainModalProps) {
key={id}
chainId={id}
currentChainId={chainId}
isConnected={isConnected}
switchChain={switchChain}
chainIconSize={chainIconSize}
isLoading={pendingChainId === id}
Expand Down
178 changes: 94 additions & 84 deletions packages/rainbowkit/src/components/ConnectButton/ConnectButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ import { Avatar } from '../Avatar/Avatar';
import { Box } from '../Box/Box';
import { DropdownIcon } from '../Icons/Dropdown';
import { I18nContext } from '../RainbowKitProvider/I18nContext';
import { useRainbowKitChains } from '../RainbowKitProvider/RainbowKitChainContext';
import {
useInitialChainId,
useRainbowKitChains,
} from '../RainbowKitProvider/RainbowKitChainContext';
import { useShowBalance } from '../RainbowKitProvider/ShowBalanceContext';
import { ConnectButtonRenderer } from './ConnectButtonRenderer';

Expand Down Expand Up @@ -42,7 +45,7 @@ export function ConnectButton({
const chains = useRainbowKitChains();
const connectionStatus = useConnectionStatus();
const { setShowBalance } = useShowBalance();

const initialChainId = useInitialChainId();
const { i18n } = useContext(I18nContext);

useEffect(() => {
Expand All @@ -59,8 +62,15 @@ export function ConnectButton({
openChainModal,
openConnectModal,
}) => {
// Hide the chain button if the user has specified a custom "initialChainId".
// This prevents users from switching to a different chain when they have a desired
// chain that they want to switch to. We also hide the chain button if user is using
// our authentication provider and is not yet signed in.
const shouldHideChainButton =
(initialChainId && connectionStatus !== 'connected') ||
connectionStatus === 'unauthenticated';
const ready = mounted && connectionStatus !== 'loading';
const unsupportedChain = chain?.unsupported ?? false;
const unsupportedChain = !!chain?.unsupported;

return (
<Box
Expand All @@ -75,98 +85,98 @@ export function ConnectButton({
},
})}
>
{ready && account && connectionStatus === 'connected' ? (
<>
{chain && (chains.length > 1 || unsupportedChain) && (
{ready && !shouldHideChainButton && chain && chains.length > 1 && (
<Box
alignItems="center"
aria-label="Chain Selector"
as="button"
background={
unsupportedChain
? 'connectButtonBackgroundError'
: 'connectButtonBackground'
}
borderRadius="connectButton"
boxShadow="connectButton"
className={touchableStyles({
active: 'shrink',
hover: 'grow',
})}
color={
unsupportedChain
? 'connectButtonTextError'
: 'connectButtonText'
}
display={mapResponsiveValue(chainStatus, (value) =>
value === 'none' ? 'none' : 'flex',
)}
fontFamily="body"
fontWeight="bold"
gap="6"
key={
// Force re-mount to prevent CSS transition
unsupportedChain ? 'unsupported' : 'supported'
}
onClick={openChainModal}
paddingX="10"
paddingY="8"
testId={
unsupportedChain ? 'wrong-network-button' : 'chain-button'
}
transition="default"
type="button"
>
{unsupportedChain ? (
<Box
alignItems="center"
aria-label="Chain Selector"
as="button"
background={
unsupportedChain
? 'connectButtonBackgroundError'
: 'connectButtonBackground'
}
borderRadius="connectButton"
boxShadow="connectButton"
className={touchableStyles({
active: 'shrink',
hover: 'grow',
})}
color={
unsupportedChain
? 'connectButtonTextError'
: 'connectButtonText'
}
display={mapResponsiveValue(chainStatus, (value) =>
value === 'none' ? 'none' : 'flex',
)}
fontFamily="body"
fontWeight="bold"
gap="6"
key={
// Force re-mount to prevent CSS transition
unsupportedChain ? 'unsupported' : 'supported'
}
onClick={openChainModal}
paddingX="10"
paddingY="8"
testId={
unsupportedChain ? 'wrong-network-button' : 'chain-button'
}
transition="default"
type="button"
display="flex"
height="24"
paddingX="4"
>
{unsupportedChain ? (
Wrong network
</Box>
) : (
<Box alignItems="center" display="flex" gap="6">
{chain.hasIcon ? (
<Box
alignItems="center"
display="flex"
display={mapResponsiveValue(chainStatus, (value) =>
value === 'full' || value === 'icon'
? 'block'
: 'none',
)}
height="24"
paddingX="4"
width="24"
>
Wrong network
<AsyncImage
alt={chain.name ?? 'Chain icon'}
background={chain.iconBackground}
borderRadius="full"
height="24"
src={chain.iconUrl}
width="24"
/>
</Box>
) : (
<Box alignItems="center" display="flex" gap="6">
{chain.hasIcon ? (
<Box
display={mapResponsiveValue(chainStatus, (value) =>
value === 'full' || value === 'icon'
? 'block'
: 'none',
)}
height="24"
width="24"
>
<AsyncImage
alt={chain.name ?? 'Chain icon'}
background={chain.iconBackground}
borderRadius="full"
height="24"
src={chain.iconUrl}
width="24"
/>
</Box>
) : null}
<Box
display={mapResponsiveValue(chainStatus, (value) => {
if (value === 'icon' && !chain.iconUrl) {
return 'block'; // Show the chain name if there is no iconUrl
}
) : null}
<Box
display={mapResponsiveValue(chainStatus, (value) => {
if (value === 'icon' && !chain.iconUrl) {
return 'block'; // Show the chain name if there is no iconUrl
}

return value === 'full' || value === 'name'
? 'block'
: 'none';
})}
>
{chain.name ?? chain.id}
</Box>
</Box>
)}
<DropdownIcon />
return value === 'full' || value === 'name'
? 'block'
: 'none';
})}
>
{chain.name ?? chain.id}
</Box>
</Box>
)}
<DropdownIcon />
</Box>
)}

{ready && account && connectionStatus === 'connected' ? (
<>
{!unsupportedChain && (
<Box
alignItems="center"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { ReactNode, useContext } from 'react';
import { useAccount, useBalance, useConfig } from 'wagmi';
import { useAccount, useBalance, useChainId, useConfig } from 'wagmi';
import { normalizeResponsiveValue } from '../../css/sprinkles.css';
import { useIsMounted } from '../../hooks/useIsMounted';
import { useMainnetEnsAvatar } from '../../hooks/useMainnetEnsAvatar';
Expand Down Expand Up @@ -65,9 +65,12 @@ export function ConnectButtonRenderer({
const { address } = useAccount();
const ensName = useMainnetEnsName(address);
const ensAvatar = useMainnetEnsAvatar(ensName);
const { isConnected } = useAccount();

const { chainId } = useAccount();
const currentChainId = useChainId();
const { chainId: connectedChainId } = useAccount();
const { chains: wagmiChains } = useConfig();
const chainId = isConnected ? connectedChainId : currentChainId;
const isCurrentChainSupported = wagmiChains.some(
(chain) => chain.id === chainId,
);
Expand Down Expand Up @@ -133,7 +136,7 @@ export function ConnectButtonRenderer({
iconUrl: resolvedChainIconUrl,
id: chainId,
name: chainName,
unsupported: !isCurrentChainSupported,
unsupported: isConnected && !isCurrentChainSupported,
}
: undefined,
chainModalOpen,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import React, {
useMemo,
useRef,
} from 'react';
import { useAccount, useAccountEffect } from 'wagmi';
import { Config, useAccount, useAccountEffect } from 'wagmi';

export type AuthenticationStatus =
| 'loading'
Expand Down Expand Up @@ -79,8 +79,10 @@ export function RainbowKitAuthenticationProvider<Message = unknown>({
}
}, [status, adapter, isDisconnected]);

const handleChangedAccount = () => {
adapter.signOut();
const handleChangedAccount = (
data: Parameters<Config['_internal']['events']['change']>[0],
) => {
if (data.accounts) adapter.signOut();
};

// Wait for user authentication before listening to "change" event.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,10 @@ export function ModalProvider({ children }: ModalProviderProps) {
? openAccountModal
: undefined,
openChainModal:
connectionStatus === 'connected' ? openChainModal : undefined,
connectionStatus === 'connected' ||
connectionStatus === 'disconnected'
? openChainModal
: undefined,
openConnectModal:
connectionStatus === 'disconnected' ||
connectionStatus === 'unauthenticated'
Expand Down
Loading

0 comments on commit e1e02c1

Please sign in to comment.