Skip to content

Commit

Permalink
Copy address to try a more internationalized interaction (#448)
Browse files Browse the repository at this point in the history
* feat: Copy address to try a more internationalized interaction.

* docs: changelog

* test: Supplement adress test cases.

---------

Co-authored-by: cong_wang <[email protected]>
  • Loading branch information
cong1223 and 0xbe37e authored Jan 3, 2024
1 parent 6a6f670 commit 7778597
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 42 deletions.
5 changes: 5 additions & 0 deletions .changeset/nice-items-search.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@ant-design/web3': minor
---

feat: Copy address to try a more internationalized interaction.
20 changes: 17 additions & 3 deletions packages/web3/src/address/__tests__/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@ describe('Address', () => {
let resetMockClipboard: () => void;
beforeEach(() => {
resetMockClipboard = mockClipboard();
vi.useFakeTimers({ shouldAdvanceTime: true });
});
afterEach(() => {
resetMockClipboard();
vi.runOnlyPendingTimers();
vi.useRealTimers();
});

it('mount correctly', () => {
Expand Down Expand Up @@ -88,9 +91,10 @@ describe('Address', () => {
);
expect(baseElement.querySelector('.ant-web3-address')?.textContent).toBe('0x21CD...Fd3B');
fireEvent.click(baseElement.querySelector('.anticon-copy')!);
await vi.waitFor(() => {
expect(baseElement.querySelector('.ant-message')).not.toBeNull();
expect(baseElement.querySelector('.ant-message-notice-content')?.textContent?.trim()).toBe(
await vi.waitFor(async () => {
expect(baseElement.querySelector('.anticon-check')).not.toBeNull();
expect(baseElement.querySelector('.anticon-copy')).toBeNull();
expect(baseElement.querySelector('.anticon-check')?.getAttribute('title')).toBe(
'Address Copied!',
);
expect(readCopyText()).resolves.toBe('0x21CDf0974d53a6e96eF05d7B324a9803735fFd3B');
Expand Down Expand Up @@ -121,4 +125,14 @@ describe('Address', () => {
'0x21CDf0974d53a6e96eF05d7B324a9803735fFd3B',
);
});

it('should show copy icon after 2s', async () => {
const { baseElement } = render(
<Address address="0x21CDf0974d53a6e96eF05d7B324a9803735fFd3B" copyable />,
);
fireEvent.click(baseElement.querySelector('.anticon-copy')!);
vi.advanceTimersByTime(2000);
expect(baseElement.querySelector('.anticon-check')).toBeNull();
expect(baseElement.querySelector('.anticon-copy')).not.toBeNull();
});
});
69 changes: 42 additions & 27 deletions packages/web3/src/address/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { ReactNode } from 'react';
import React, { useContext, useMemo } from 'react';
import { CopyOutlined } from '@ant-design/icons';
import React, { useContext, useEffect, useMemo, useRef, useState } from 'react';
import { CheckOutlined, CopyOutlined } from '@ant-design/icons';
import type { TooltipProps } from 'antd';
import { ConfigProvider, message, Space, Tooltip } from 'antd';
import { ConfigProvider, Space, Tooltip } from 'antd';
import classNames from 'classnames';

import { fillWith0x, formatAddress, writeCopyText } from '../utils';
Expand All @@ -23,10 +23,11 @@ export interface AddressProps {

export const Address: React.FC<React.PropsWithChildren<AddressProps>> = (props) => {
const { ellipsis, address, copyable, tooltip, format = false, children } = props;
const [messageApi, contextHolder] = message.useMessage();
const { getPrefixCls } = useContext(ConfigProvider.ConfigContext);
const prefixCls = getPrefixCls('web3-address');
const { wrapSSR, hashId } = useStyle(prefixCls);
const [copied, setCopied] = useState(false);
const timerRef = useRef<ReturnType<typeof setTimeout>>();

const mergedFormat = useMemo(() => {
if (typeof format === 'function') {
Expand All @@ -47,6 +48,14 @@ export const Address: React.FC<React.PropsWithChildren<AddressProps>> = (props)
}
: ellipsis;

useEffect(() => {
return () => {
if (timerRef.current) {
clearTimeout(timerRef.current);
}
};
}, []);

if (!address) {
return null;
}
Expand All @@ -57,28 +66,34 @@ export const Address: React.FC<React.PropsWithChildren<AddressProps>> = (props)
const displayTooltip = tooltip === undefined || tooltip === true ? filledAddress : tooltip;

return wrapSSR(
<>
{contextHolder}
<Space className={classNames(prefixCls, hashId)}>
<Tooltip title={displayTooltip}>
<span className={`${prefixCls}-text`}>
{children ??
(isEllipsis
? `${filledAddress.slice(0, headClip)}...${filledAddress.slice(-tailClip)}`
: formattedAddress)}
</span>
</Tooltip>
{copyable && (
<CopyOutlined
title="Copy Address"
onClick={() => {
writeCopyText(filledAddress).then(() => {
messageApi.success('Address Copied!');
});
}}
/>
)}
</Space>
</>,
<Space className={classNames(prefixCls, hashId)}>
<Tooltip title={displayTooltip}>
<span className={`${prefixCls}-text`}>
{children ??
(isEllipsis
? `${filledAddress.slice(0, headClip)}...${filledAddress.slice(-tailClip)}`
: formattedAddress)}
</span>
</Tooltip>
{copyable && (
<>
{copied ? (
<CheckOutlined title="Address Copied!" />
) : (
<CopyOutlined
title="Copy Address"
onClick={() => {
writeCopyText(filledAddress).then(() => {
setCopied(true);
timerRef.current = setTimeout(() => {
setCopied(false);
}, 2000);
});
}}
/>
)}
</>
)}
</Space>,
);
};
27 changes: 15 additions & 12 deletions packages/web3/src/hooks/demos/useConnection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,21 @@ const Demo: React.FC = () => {
const { account } = useAccount();
const { connect, disconnect } = useConnection();
return (
<Button
onClick={() => {
if (account) {
disconnect?.();
} else {
console.log('connect');
connect?.();
}
}}
>
{account ? 'Disconnect' : 'Connect'}
</Button>
<>
<Button
onClick={() => {
if (account) {
disconnect?.();
} else {
console.log('connect');
connect?.();
}
}}
>
{account ? 'Disconnect' : 'Connect'}
</Button>
{account ? <p>Account: {account?.address}</p> : <p>Not Connected</p>}
</>
);
};

Expand Down

0 comments on commit 7778597

Please sign in to comment.