diff --git a/.changeset/little-cougars-smile.md b/.changeset/little-cougars-smile.md new file mode 100644 index 000000000..27e701a7e --- /dev/null +++ b/.changeset/little-cougars-smile.md @@ -0,0 +1,6 @@ +--- +'@ant-design/web3-common': minor +'@ant-design/web3': minor +--- + +feat: optimize connect-modal component diff --git a/packages/common/src/locale/en_US.ts b/packages/common/src/locale/en_US.ts index 938f0222f..643ca9c30 100644 --- a/packages/common/src/locale/en_US.ts +++ b/packages/common/src/locale/en_US.ts @@ -35,6 +35,7 @@ const localeValues: RequiredLocale = { walletCardAppTitle: '{selectedWalletName} for Mobile', walletCardAppDesc: 'Use the mobile wallet to explore the world of Ethereum.', walletCardExtensionTitle: '{selectedWalletName} for {selectedExtensionBrowserName}', + walletPanelPlugin: 'PLUGIN', }, NFTCard: { actionText: 'Buy Now', diff --git a/packages/common/src/locale/zh_CN.ts b/packages/common/src/locale/zh_CN.ts index e5d8d341e..1cef64d7e 100644 --- a/packages/common/src/locale/zh_CN.ts +++ b/packages/common/src/locale/zh_CN.ts @@ -33,6 +33,7 @@ const localeValues: RequiredLocale = { walletCardAppTitle: '在手机使用 {selectedWalletName}', walletCardAppDesc: '使用移动钱包探索以太坊世界。', walletCardExtensionTitle: '在 {selectedExtensionBrowserName} 浏览器中使用 {selectedWalletName}', + walletPanelPlugin: '插件', }, NFTCard: { actionText: '立即购买', diff --git a/packages/common/src/types.ts b/packages/common/src/types.ts index 1820cf87e..e044a84a1 100644 --- a/packages/common/src/types.ts +++ b/packages/common/src/types.ts @@ -211,6 +211,7 @@ export interface RequiredLocale { walletCardAppTitle: string; walletCardAppDesc: string; walletCardExtensionTitle: string; + walletPanelPlugin: string; }; NFTCard: { actionText: string; diff --git a/packages/web3/src/connect-modal/__tests__/__snapshots__/basic.test.tsx.snap b/packages/web3/src/connect-modal/__tests__/__snapshots__/basic.test.tsx.snap index 67f55b87f..9d47665a1 100644 --- a/packages/web3/src/connect-modal/__tests__/__snapshots__/basic.test.tsx.snap +++ b/packages/web3/src/connect-modal/__tests__/__snapshots__/basic.test.tsx.snap @@ -18,7 +18,7 @@ exports[`ConnectModal with guide > panel route change 1`] = ` aria-modal="true" class="ant-modal css-dev-only-do-not-override-1qhpsh8 ant-web3-connect-modal css-dev-only-do-not-override-1qhpsh8 ant-zoom-appear ant-zoom-appear-prepare ant-zoom" role="dialog" - style="width: 737px;" + style="width: 797px;" > +
+
+
+
+
+
  • panel route change 1`] = ` Test Wallet3
  • +
    +
    +
    +
    +
    +
    @@ -187,6 +215,20 @@ exports[`ConnectModal with guide > panel route change 1`] = ` Test Wallet2
    +
    +
    +
    +
    +
    +
  • panel route change 1`] = ` Test Wallet4
  • +
    +
    +
    +
    +
    +
  • panel route change 1`] = ` Test Wallet5
  • +
    +
    +
    +
    +
    +
  • panel route change 1`] = ` Test Wallet6
  • +
    +
    +
    +
    +
    +
  • panel route change 1`] = ` Test Wallet6
  • +
    +
    +
    +
    +
    +
    @@ -418,7 +516,7 @@ exports[`ConnectModal with guide > panel route change 2`] = ` aria-modal="true" class="ant-modal css-dev-only-do-not-override-1qhpsh8 ant-web3-connect-modal css-dev-only-do-not-override-1qhpsh8 ant-zoom-appear ant-zoom-appear-prepare ant-zoom" role="dialog" - style="width: 737px;" + style="width: 797px;" >
    +
    +
    +
    +
    +
    +
  • panel route change 2`] = ` Test Wallet3
  • +
    +
    +
    +
    +
    +
    @@ -587,6 +713,20 @@ exports[`ConnectModal with guide > panel route change 2`] = ` Test Wallet2
    +
    +
    +
    +
    +
    +
  • panel route change 2`] = ` Test Wallet4
  • +
    +
    +
    +
    +
    +
  • panel route change 2`] = ` Test Wallet5
  • +
    +
    +
    +
    +
    +
  • panel route change 2`] = ` Test Wallet6
  • +
    +
    +
    +
    +
    +
  • panel route change 2`] = ` Test Wallet6
  • +
    +
    +
    +
    +
    +
    @@ -818,7 +1014,7 @@ exports[`ConnectModal with guide > should display default guide 1`] = ` aria-modal="true" class="ant-modal css-dev-only-do-not-override-1qhpsh8 ant-web3-connect-modal css-dev-only-do-not-override-1qhpsh8 ant-zoom-appear ant-zoom-appear-prepare ant-zoom" role="dialog" - style="width: 737px; transform-origin: 0px 0px;" + style="width: 797px; transform-origin: 0px 0px;" >
    +
    +
    +
    +
    +
    +
  • should display default guide 1`] = ` Test Wallet3
  • +
    +
    +
    +
    +
    +
    @@ -987,6 +1211,20 @@ exports[`ConnectModal with guide > should display default guide 1`] = ` Test Wallet2
    +
    +
    +
    +
    +
    +
  • should display default guide 1`] = ` Test Wallet4
  • +
    +
    +
    +
    +
    +
  • should display default guide 1`] = ` Test Wallet5
  • +
    +
    +
    +
    +
    +
  • should display default guide 1`] = ` Test Wallet6
  • +
    +
    +
    +
    +
    +
  • should display default guide 1`] = ` Test Wallet6
  • +
    +
    +
    +
    +
    +
    @@ -1213,7 +1507,7 @@ exports[`ConnectModal with guide > should render in dark mode 1`] = ` aria-modal="true" class="ant-modal css-dev-only-do-not-override-1hnpuv1 ant-web3-connect-modal css-dev-only-do-not-override-1hnpuv1 ant-zoom-appear ant-zoom-appear-prepare ant-zoom" role="dialog" - style="width: 737px;" + style="width: 797px;" >
    +
    +
    +
    +
    +
    +
  • should render in dark mode 1`] = ` Test Wallet3
  • +
    +
    +
    +
    +
    +
    @@ -1382,6 +1704,20 @@ exports[`ConnectModal with guide > should render in dark mode 1`] = ` Test Wallet2
    +
    +
    +
    +
    +
    +
  • should render in dark mode 1`] = ` Test Wallet4
  • +
    +
    +
    +
    +
    +
  • should render in dark mode 1`] = ` Test Wallet5
  • +
    +
    +
    +
    +
    +
  • should render in dark mode 1`] = ` Test Wallet6
  • +
    +
    +
    +
    +
    +
  • should render in dark mode 1`] = ` Test Wallet6
  • +
    +
    +
    +
    +
    +
    @@ -1633,7 +2025,7 @@ exports[`ConnectModal with guide > should render in light mode 1`] = ` aria-modal="true" class="ant-modal css-dev-only-do-not-override-1qhpsh8 ant-web3-connect-modal css-dev-only-do-not-override-1qhpsh8 ant-zoom-appear ant-zoom-appear-prepare ant-zoom" role="dialog" - style="width: 737px;" + style="width: 797px;" >
    +
    +
    +
    +
    +
    +
  • should render in light mode 1`] = ` Test Wallet3
  • +
    +
    +
    +
    +
    +
    @@ -1802,6 +2222,20 @@ exports[`ConnectModal with guide > should render in light mode 1`] = ` Test Wallet2
    +
    +
    +
    +
    +
    +
  • should render in light mode 1`] = ` Test Wallet4
  • +
    +
    +
    +
    +
    +
  • should render in light mode 1`] = ` Test Wallet5
  • +
    +
    +
    +
    +
    +
  • should render in light mode 1`] = ` Test Wallet6
  • +
    +
    +
    +
    +
    +
  • should render in light mode 1`] = ` Test Wallet6
  • +
    +
    +
    +
    +
    +
    diff --git a/packages/web3/src/connect-modal/__tests__/__snapshots__/simple.test.tsx.snap b/packages/web3/src/connect-modal/__tests__/__snapshots__/simple.test.tsx.snap index 293d8f924..236f97b0f 100644 --- a/packages/web3/src/connect-modal/__tests__/__snapshots__/simple.test.tsx.snap +++ b/packages/web3/src/connect-modal/__tests__/__snapshots__/simple.test.tsx.snap @@ -122,6 +122,20 @@ exports[`ConnectModal without guide > should render in dark mode 1`] = ` Test Wallet
    +
    +
    +
    +
    +
    +
  • should render in dark mode 1`] = ` Test Wallet3
  • +
    +
    +
    +
    +
    +
    @@ -187,6 +215,20 @@ exports[`ConnectModal without guide > should render in dark mode 1`] = ` Test Wallet2
    +
    +
    +
    +
    +
    +
  • should render in dark mode 1`] = ` Test Wallet4
  • +
    +
    +
    +
    +
    +
  • should render in dark mode 1`] = ` Test Wallet5
  • +
    +
    +
    +
    +
    +
  • should render in dark mode 1`] = ` Test Wallet6
  • +
    +
    +
    +
    +
    +
  • should render in dark mode 1`] = ` Test Wallet6
  • +
    +
    +
    +
    +
    +
    @@ -407,6 +505,20 @@ exports[`ConnectModal without guide > should render in light mode 1`] = ` Test Wallet
    +
    +
    +
    +
    +
    +
  • should render in light mode 1`] = ` Test Wallet3
  • +
    +
    +
    +
    +
    +
    @@ -472,6 +598,20 @@ exports[`ConnectModal without guide > should render in light mode 1`] = ` Test Wallet2
    +
    +
    +
    +
    +
    +
  • should render in light mode 1`] = ` Test Wallet4
  • +
    +
    +
    +
    +
    +
  • should render in light mode 1`] = ` Test Wallet5
  • +
    +
    +
    +
    +
    +
  • should render in light mode 1`] = ` Test Wallet6
  • +
    +
    +
    +
    +
    +
  • should render in light mode 1`] = ` Test Wallet6
  • +
    +
    +
    +
    +
    +
    diff --git a/packages/web3/src/connect-modal/__tests__/pluginTag.test.tsx b/packages/web3/src/connect-modal/__tests__/pluginTag.test.tsx new file mode 100644 index 000000000..aaf82384b --- /dev/null +++ b/packages/web3/src/connect-modal/__tests__/pluginTag.test.tsx @@ -0,0 +1,138 @@ +import { ConnectModal } from '@ant-design/web3'; +import { metadata_MetaMask } from '@ant-design/web3-assets'; +import { Wallet } from '@ant-design/web3-common'; +import { fireEvent, render, screen, waitFor } from '@testing-library/react'; +import { describe, expect, it } from 'vitest'; + +describe('ConnectModal with qrCode & plugin tag', () => { + it('show qrCode', async () => { + const wallet: Wallet = { + ...metadata_MetaMask, + getQrCode: async () => { + return { + uri: '', + }; + }, + }; + + const App = () => ( + + ); + const { baseElement } = render(); + expect(baseElement.querySelector('.anticon-qrcode')).toBeTruthy(); + }); + + it('do not show qrCode', async () => { + const wallet: Wallet = { + ...metadata_MetaMask, + }; + + const App = () => ( + + ); + const { baseElement } = render(); + expect(baseElement.querySelector('.anticon-qrcode')).not.toBeTruthy(); + }); + + it('not show plugin tag', async () => { + const wallet: Wallet = { + ...metadata_MetaMask, + }; + + const App = () => ( + + ); + render(); + const span = screen.queryByText('PLUGIN'); + expect(!!span?.parentElement === false).toBeTruthy(); + }); + + it('show plugin tag when installed', async () => { + const wallet: Wallet = { + ...metadata_MetaMask, + hasExtensionInstalled: async () => { + return true; + }, + }; + + const App = () => ( + + ); + render(); + const span = screen.queryByText('PLUGIN'); + expect(!!span?.parentElement?.getAttribute('disabled') === false).toBeTruthy(); + }); + + it('show plugin tag when not installed', async () => { + const wallet: Wallet = { + ...metadata_MetaMask, + hasExtensionInstalled: async () => { + return false; + }, + }; + + const App = () => ( + + ); + render(); + const span = screen.queryByText('PLUGIN'); + expect(span?.parentElement?.getAttribute('disabled') === '').toBeTruthy(); + }); + + it('click event trigger', async () => { + const wallet: Wallet = { + ...metadata_MetaMask, + getQrCode: async () => { + return { + uri: '', + }; + }, + }; + + const App = () => ( + + ); + const { baseElement } = render(); + const icon = baseElement.querySelector('.anticon-qrcode'); + fireEvent.click(icon!); + await waitFor(() => { + expect(baseElement.querySelector('.anticon-qrcode')).toBeTruthy(); + }); + }); +}); diff --git a/packages/web3/src/connect-modal/components/PluginTag.tsx b/packages/web3/src/connect-modal/components/PluginTag.tsx new file mode 100644 index 000000000..efed9ca2e --- /dev/null +++ b/packages/web3/src/connect-modal/components/PluginTag.tsx @@ -0,0 +1,32 @@ +import React from 'react'; +import { Badge, Button } from 'antd'; + +import { connectModalContext } from '../context'; +import type { Wallet } from '../interface'; + +const PluginTag: React.FC<{ wallet: Wallet }> = ({ wallet }) => { + const [extensionInstalled, setExtensionInstalled] = React.useState(false); + const { getMessage, localeMessage } = React.useContext(connectModalContext); + + const judgeExtensionInstalled = async () => { + const hasWalletReady = await wallet.hasWalletReady?.(); + if (hasWalletReady) { + const hasInstalled = await wallet.hasExtensionInstalled?.(); + setExtensionInstalled(!!hasInstalled); + } + }; + + React.useEffect(() => { + judgeExtensionInstalled(); + }, [wallet]); + + return wallet.hasExtensionInstalled ? ( + + + + ) : null; +}; + +export default PluginTag; diff --git a/packages/web3/src/connect-modal/components/WalletList.tsx b/packages/web3/src/connect-modal/components/WalletList.tsx index c41e07f11..0be0a2fdd 100644 --- a/packages/web3/src/connect-modal/components/WalletList.tsx +++ b/packages/web3/src/connect-modal/components/WalletList.tsx @@ -1,10 +1,12 @@ import React, { useContext, useMemo } from 'react'; -import { List } from 'antd'; +import { QrcodeOutlined } from '@ant-design/icons'; +import { Button, List, Space } from 'antd'; import classNames from 'classnames'; import { connectModalContext } from '../context'; import type { ConnectModalProps, Wallet } from '../interface'; import { defaultGroupOrder } from '../utils'; +import PluginTag from './PluginTag'; export type WalletListProps = Pick; @@ -75,6 +77,22 @@ const WalletList: React.FC = (props) => { )}
    {item.name}
    + + + {item.getQrCode ? ( + + ) : ( +
    + )} + )} /> diff --git a/packages/web3/src/connect-modal/demos/panel.tsx b/packages/web3/src/connect-modal/demos/panel.tsx index 427aea8f2..7ae43a4a2 100644 --- a/packages/web3/src/connect-modal/demos/panel.tsx +++ b/packages/web3/src/connect-modal/demos/panel.tsx @@ -55,7 +55,7 @@ const App: React.FC = () => { return ( & { return wrapSSR( { [`${componentCls}-list-panel`]: { paddingInline: 18, paddingBlock: 24, - width: 268, + width: 328, flexShrink: 0, borderRight: `1px solid ${token.splitColor}`, display: 'flex', @@ -99,6 +99,12 @@ const getThemeStyle = (token: ConnectModalToken): CSSInterpolation => { marginBlock: token.marginSM, overflow: 'auto', [`${componentCls}-wallet-list`]: { + maxHeight: 390, + overflow: 'scroll', + '&::-webkit-scrollbar': { + display: 'none', + }, + scrollbarWidth: 'none', [`${componentCls}-group`]: { marginBlockEnd: token.marginSM, [`${componentCls}-group-title`]: { @@ -115,10 +121,6 @@ const getThemeStyle = (token: ConnectModalToken): CSSInterpolation => { transition: 'background .3s, color .3s', marginBlockEnd: 5, border: 'none', - [`${componentCls}-extra`]: { - fontSize: token.fontSizeSM, - color: token.colorTextDescription, - }, [`${componentCls}-content`]: { display: 'flex', alignItems: 'center', @@ -141,8 +143,12 @@ const getThemeStyle = (token: ConnectModalToken): CSSInterpolation => { justifySelf: 'flex-start', marginInlineStart: token.marginSM, color: token.colorText, + wordBreak: 'break-word', }, }, + [`${componentCls}-qr-icon-empty`]: { + width: 30, + }, '&:last-child': { marginBlockEnd: 0, }, @@ -151,9 +157,6 @@ const getThemeStyle = (token: ConnectModalToken): CSSInterpolation => { }, '&.selected': { background: token.selectedBg, - [`${componentCls}-name`]: { - color: token.selectedColor, - }, }, }, }, @@ -427,14 +430,16 @@ const genModalStyle: GenerateStyle = (token) => { export function useStyle(prefixCls: string): UseStyleResult { return useAntdStyle('ConnectModal', (token) => { const isDark = isDarkTheme(token); + const hoverBg = new TinyColor(isDark ? token.colorWhite : '#000') + .setAlpha(0.08) + .onBackground(token.colorBgContainer) + .toRgbString(); + const connectModalToken: ConnectModalToken = { ...token, - selectedBg: isDark ? token.colorWhite : token.colorPrimary, selectedColor: token.colorBgContainer, - hoverBg: new TinyColor(isDark ? token.colorWhite : token.colorPrimary) - .setAlpha(0.1) - .onBackground(token.colorBgContainer) - .toRgbString(), + hoverBg, + selectedBg: hoverBg, splitColor: new TinyColor(token.colorText).setAlpha(0.06).toRgbString(), modalTitleStartColor: isDark ? token.colorWhite : token.colorPrimary, modalTitleEndColor: new TinyColor('#000')