Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Address support format #139

Merged
merged 4 commits into from
Nov 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`Address > display address with default format 1`] = `
<div
class="ant-space css-dev-only-do-not-override-1ck3jst ant-space-horizontal ant-space-align-center ant-space-gap-row-small ant-space-gap-col-small ant-web3-address css-dev-only-do-not-override-1ck3jst"
>
<div
class="ant-space-item"
>
<span
class="ant-web3-address-text"
>
0x 21CD f097 4d53 a6e9 6eF0 5d7B 324a 9803 735f Fd3B
</span>
</div>
</div>
`;
98 changes: 98 additions & 0 deletions packages/web3/src/address/__tests__/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { Address } from '..';
import { fireEvent, render } from '@testing-library/react';
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { mockClipboard } from '../../utils/test-utils';
import { readCopyText } from '../../utils';

describe('Address', () => {
let resetMockClipboard: () => void;
beforeEach(() => {
resetMockClipboard = mockClipboard();
});
afterEach(() => {
resetMockClipboard();
});

it('mount correctly', () => {
expect(() => render(<Address />)).not.toThrow();
});

it('display address', () => {
const { baseElement } = render(
<Address address="0x21CDf0974d53a6e96eF05d7B324a9803735fFd3B" />,
);
expect(baseElement.querySelector('.ant-web3-address')?.textContent).toBe(
'0x21CDf0974d53a6e96eF05d7B324a9803735fFd3B',
);
});

it('display address with ellipsis', () => {
const { baseElement } = render(
<Address ellipsis address="0x21CDf0974d53a6e96eF05d7B324a9803735fFd3B" />,
);
expect(baseElement.querySelector('.ant-web3-address')?.textContent).toBe('0x21CD...Fd3B');
});

it('display address with ellipsis and custom clip', () => {
const { baseElement } = render(
<Address
ellipsis={{
headClip: 3,
tailClip: 3,
}}
address="0x21CDf0974d53a6e96eF05d7B324a9803735fFd3B"
/>,
);
expect(baseElement.querySelector('.ant-web3-address')?.textContent).toBe('0x2...d3B');
});

it('display address with tooltip', async () => {
const { baseElement } = render(
<Address address="0x21CDf0974d53a6e96eF05d7B324a9803735fFd3B" ellipsis />,
);

expect(baseElement.querySelector('.ant-web3-address')?.textContent).toBe('0x21CD...Fd3B');
fireEvent.mouseEnter(baseElement.querySelector('.ant-web3-address-text')!);
await vi.waitFor(() => {
expect(baseElement.querySelector('.ant-tooltip-inner')?.textContent).toBe(
'0x21CDf0974d53a6e96eF05d7B324a9803735fFd3B',
);
});
});

it('display address with default format', () => {
const { baseElement } = render(
<Address address="0x21CDf0974d53a6e96eF05d7B324a9803735fFd3B" format />,
);
expect(baseElement.querySelector('.ant-web3-address')?.textContent).toBe(
'0x 21CD f097 4d53 a6e9 6eF0 5d7B 324a 9803 735f Fd3B',
);
expect(baseElement.querySelector('.ant-web3-address')).toMatchSnapshot();
});

it('display address with custom format', () => {
const { baseElement } = render(
<Address
address="0x21CDf0974d53a6e96eF05d7B324a9803735fFd3B"
format={(input) => {
return input.slice(0, 10);
}}
/>,
);
expect(baseElement.querySelector('.ant-web3-address')?.textContent).toBe('0x21CDf097');
});
it('display address with copyable', async () => {
const { baseElement } = render(
<Address address="0x21CDf0974d53a6e96eF05d7B324a9803735fFd3B" ellipsis copyable />,
);
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(
'Address Copied!',
);
expect(readCopyText()).resolves.toBe('0x21CDf0974d53a6e96eF05d7B324a9803735fFd3B');
});
});
});
24 changes: 24 additions & 0 deletions packages/web3/src/address/demos/format.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Address } from '@ant-design/web3';
import { Space } from 'antd';
import { formatAddress } from '../../utils';

const App: React.FC = () => {
return (
<Space direction="vertical">
<div>
Default format: <Address address={'3ea2cfd153b8d8505097b81c87c11f5d05097c18'} format />
</div>
<div>
Custom format:{' '}
<Address
address={'3ea2cfd153b8d8505097b81c87c11f5d05097c18'}
format={(input) => {
return formatAddress(input, 5);
}}
/>
</div>
</Space>
);
};

export default App;
5 changes: 5 additions & 0 deletions packages/web3/src/address/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ group:

<code src="./demos/copyable.tsx"></code>

## Format

<code src="./demos/format.tsx"></code>

## API

| Property | Description | Type | Default | Version |
Expand All @@ -23,3 +27,4 @@ group:
| copyable | Address copyable | `boolean` | `false` | - |
| address | Address | `string` | - | - |
| tooltip | Show tooltip when hover address | `boolean \|`[Tooltip.title](https://ant.design/components/tooltip-cn#api) | Displays the current full address | - |
| format | Address format | `boolean \| (input: string) => ReactNode` | `false` | - |
27 changes: 21 additions & 6 deletions packages/web3/src/address/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { CopyOutlined } from '@ant-design/icons';
import type { TooltipProps } from 'antd';
import { Space, Tooltip, message, ConfigProvider } from 'antd';
import React, { useContext } from 'react';
import React, { ReactNode, useContext, useMemo } from 'react';
import { useStyle } from './style';
import classNames from 'classnames';
import { writeCopyText, fillWith0x } from '../utils';
import { writeCopyText, fillWith0x, formatAddress } from '../utils';

export interface AddressProps {
ellipsis?:
Expand All @@ -16,14 +16,25 @@ export interface AddressProps {
address?: string;
copyable?: boolean;
tooltip?: boolean | TooltipProps['title'];
format?: boolean | ((address: string) => ReactNode);
}

export const Address: React.FC<AddressProps> = (props) => {
const { ellipsis, address, copyable, tooltip } = props;
const { ellipsis, address, copyable, tooltip, format = false } = props;
const { getPrefixCls } = useContext(ConfigProvider.ConfigContext);
const prefixCls = getPrefixCls('web3-address');
const { wrapSSR, hashId } = useStyle(prefixCls);

const mergedFormat = useMemo(() => {
if (typeof format === 'function') {
return format;
}
if (format) {
return formatAddress;
}
return (input: string) => input;
}, [format]);

const isEllipsis = !!ellipsis;
const { headClip = 6, tailClip = 4 } =
typeof ellipsis !== 'object'
Expand All @@ -38,14 +49,18 @@ export const Address: React.FC<AddressProps> = (props) => {
}

const filledAddress = fillWith0x(address);

const formattedAddress = mergedFormat(filledAddress);
const displayTooltip = tooltip === undefined || tooltip === true ? filledAddress : tooltip;

return wrapSSR(
<Space className={classNames(prefixCls, hashId)}>
<Tooltip title={displayTooltip}>
{isEllipsis
? `${filledAddress.slice(0, headClip)}...${filledAddress.slice(-tailClip)}`
: filledAddress}
<span className={`${prefixCls}-text`}>
{isEllipsis
? `${filledAddress.slice(0, headClip)}...${filledAddress.slice(-tailClip)}`
: formattedAddress}
</span>
</Tooltip>
{copyable && (
<CopyOutlined
Expand Down
5 changes: 5 additions & 0 deletions packages/web3/src/address/index.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ group:

<code src="./demos/copyable.tsx"></code>

## 格式化

<code src="./demos/format.tsx"></code>

## API

| 属性 | 描述 | 类型 | 默认值 | 版本 |
Expand All @@ -23,3 +27,4 @@ group:
| copyable | 是否可复制 | `boolean` | `false` | - |
| address | 地址 | `string` | - | - |
| tooltip | 鼠标移入地址时展示提示 | `boolean \|` [Tooltip.title](https://ant.design/components/tooltip-cn#api) | 展示当前完整地址 | - |
| format | 地址格式化 | `boolean \| (input: string) => ReactNode` | `false` | - |
Loading