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: init ConnectButton style and add useStyle for cssinjs #102

Merged
merged 2 commits into from
Nov 22, 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
35 changes: 27 additions & 8 deletions packages/web3/src/connect-button/chain-select.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,52 @@
import React from 'react';
import { Button, Dropdown, Space } from 'antd';
import React, { useContext } from 'react';
import { Dropdown, Space, ConfigProvider, Divider } from 'antd';
import type { Chain } from '@ant-design/web3-common';
import classNames from 'classnames';
import { DownOutlined } from '@ant-design/icons';

export interface ChainSelectProps {
className?: string;
hashId: string;
chains: Chain[];
onSwitchChain?: (chain: Chain) => void;
currentChain?: Chain;
style?: React.CSSProperties;
}

export const ChainSelect: React.FC<ChainSelectProps> = (props) => {
export const ChainSelect: React.FC<ChainSelectProps> = ({
className,
onSwitchChain,
style,
chains,
hashId,
currentChain,
}) => {
const { getPrefixCls } = useContext(ConfigProvider.ConfigContext);
const prefixCls = getPrefixCls('web3-connect-button-chain-select');

return (
<Dropdown
className={classNames(className, hashId, prefixCls)}
menu={{
items: props.chains.map((chain) => ({
items: chains.map((chain) => ({
key: chain.id,
label: chain.name,
icon: chain.icon,
onClick: () => {
onSwitchChain?.(chain);
},
})),
onClick: console.log,
}}
trigger={['click']}
>
<Button onClick={(e) => e.preventDefault()} style={props.style} className={props.className}>
<div style={style}>
<Space>
Hover me
{currentChain?.icon}
{currentChain?.name}
<DownOutlined />
<Divider type="vertical" />
</Space>
</Button>
</div>
</Dropdown>
);
};
Expand Down
94 changes: 51 additions & 43 deletions packages/web3/src/connect-button/connect-button.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import React from 'react';
import { Button, Dropdown } from 'antd';
import React, { useContext } from 'react';
import { Button, ConfigProvider } from 'antd';
import classNames from 'classnames';
import { Address } from '../address';
import type { ConnectButtonProps, ConnectButtonTooltipProps } from './interface';
import { ConnectButtonTooltip } from './tooltip';
import { ChainSelect } from './chain-select';
import { useStyle } from './style';

export const ConnectButton: React.FC<ConnectButtonProps> = (props) => {
const {
Expand All @@ -11,56 +14,59 @@ export const ConnectButton: React.FC<ConnectButtonProps> = (props) => {
onConnectClick,
onDisconnectClick,
chains,
currentChain,
onSwitchChain,
tooltip,
currentChain,
name,
...restProps
} = props;

const { getPrefixCls } = useContext(ConfigProvider.ConfigContext);
const prefixCls = getPrefixCls('web3-connect-button');
const { wrapSSR, hashId } = useStyle(prefixCls);
let buttonText: React.ReactNode = 'Connect Wallet';
if (connected) {
buttonText = name ?? <Address ellipsis address={address} />;
}
const buttonProps = {
style: props.style,
className: props.className,
className: classNames(props.className, hashId, prefixCls),
size: props.size,
type: props.type,
ghost: props.ghost,
onClick: () => {
if (connected) {
onDisconnectClick?.();
} else {
onConnectClick?.();
}
},
children: buttonText,
...restProps,
};

let content = <Button {...buttonProps} />;
const renderChainSelect = () => {
if (chains && chains.length > 1) {
return (
<ChainSelect
hashId={hashId}
onSwitchChain={onSwitchChain}
currentChain={currentChain}
chains={chains}
/>
);
}
return null;
};

if (chains && chains.length > 1) {
content = (
<Dropdown.Button
icon={currentChain?.icon}
menu={{
items: chains.map((item) => {
return {
onClick: () => {
onSwitchChain?.(item);
},
icon: item.icon,
label: item.name,
key: item.id,
};
}),
const content = (
<Button {...buttonProps}>
{renderChainSelect()}
<div
className={classNames(`${prefixCls}-text`, hashId)}
onClick={() => {
if (connected) {
onDisconnectClick?.();
} else {
onConnectClick?.();
}
}}
{...buttonProps}
/>
);
}
>
{buttonText}
</div>
</Button>
);

const mergedTooltipCopyable: ConnectButtonTooltipProps['copyable'] =
typeof tooltip === 'object' ? tooltip.copyable !== false : !!tooltip;
Expand All @@ -81,16 +87,18 @@ export const ConnectButton: React.FC<ConnectButtonProps> = (props) => {
/>
);

return tooltip || (!customTooltipTitle && !!address) ? (
<ConnectButtonTooltip
copyable={customTooltipTitle && mergedTooltipCopyable}
title={tooltipTitle}
{...(typeof tooltip === 'object' ? tooltip : {})}
>
{content}
</ConnectButtonTooltip>
) : (
content
return wrapSSR(
tooltip || (!customTooltipTitle && !!address) ? (
<ConnectButtonTooltip
copyable={customTooltipTitle && mergedTooltipCopyable}
title={tooltipTitle}
{...(typeof tooltip === 'object' ? tooltip : {})}
>
{content}
</ConnectButtonTooltip>
) : (
content
),
);
};

Expand Down
1 change: 1 addition & 0 deletions packages/web3/src/connect-button/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export type ConnectButtonTooltipProps = TooltipProps & {

export type ConnectButtonProps = ButtonProps &
ConnectorTriggerProps & {
prefixCls?: string;
avatar?: AvatarProps;
menuItems?: MenuItemProps[];
onMenuClick?: (e: MenuItemProps) => void;
Expand Down
34 changes: 34 additions & 0 deletions packages/web3/src/connect-button/style/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import type React from 'react';
import {
useStyle as useAntdStyle,
type GenerateStyle,
type Web3AliasToken,
} from '../../theme/useStyle';

export interface ConnectButtonToken extends Web3AliasToken {
componentCls: string;
}

const genConnectButtonStyle: GenerateStyle<ConnectButtonToken> = (token) => {
return {
[token.componentCls]: {
[`${token.componentCls}-text`]: {
display: 'inline-block',
},
[`${token.componentCls}-chain-select`]: {
display: 'inline-block',
marginRight: 8,
},
},
};
};

export function useStyle(prefixCls: string) {
return useAntdStyle('ConnectButton', (token) => {
const proListToken: ConnectButtonToken = {
...token,
componentCls: `.${prefixCls}`,
};
return [genConnectButtonStyle(proListToken)];
});
}
98 changes: 98 additions & 0 deletions packages/web3/src/theme/useStyle/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import type { CSSInterpolation, CSSObject } from '@ant-design/cssinjs';
import { useStyleRegister } from '@ant-design/cssinjs';
import { TinyColor } from '@ctrl/tinycolor';

import { ConfigProvider as AntdConfigProvider } from 'antd';
import useToken from 'antd/lib/theme/useToken';
import type { GlobalToken } from 'antd/lib/theme/interface';
import type React from 'react';
import { useContext } from 'react';

/**
* Set alpha for a color
* @example (#fff, 0.5) => rgba(255, 255, 255, 0.5)
* @param baseColor {string}
* @param alpha {0-1}
* @returns rgba {string}
*/
export const setAlpha = (baseColor: string, alpha: number) =>
new TinyColor(baseColor).setAlpha(alpha).toRgbString();

/**
* Lighten a color
* @example (#000, 50) => #808080
* @param baseColor {string}
* @param brightness {0-100}
* @returns hexColor {string}
*/
export const lighten = (baseColor: string, brightness: number) => {
const instance = new TinyColor(baseColor);
return instance.lighten(brightness).toHexString();
};

export type GenerateStyle<
ComponentToken extends object = GlobalToken,
ReturnType = CSSInterpolation,
> = (token: ComponentToken, ...rest: any[]) => ReturnType;

export type UseStyleResult = {
wrapSSR: (node: React.ReactElement) => React.ReactElement;
hashId: string;
};

export type Web3AliasToken = GlobalToken & {
/**
* classname for web3 compoennts
* @type {string}
* @example .ant-pro
*/
web3ComponentsCls: string;
/**
* antd 的 className
* @type {string}
* @example .ant
*/
antCls: string;
};

export const resetComponent = (token: Web3AliasToken): CSSObject => ({
boxSizing: 'border-box',
margin: 0,
padding: 0,
color: token.colorText,
fontSize: token.fontSize,
lineHeight: token.lineHeight,
listStyle: 'none',
});

/**
* useStyle for css in js
* @param componentName {string} 组件的名字
* @param styleFn {GenerateStyle} 生成样式的函数
* @returns UseStyleResult
*/
export function useStyle(
componentName: string,
styleFn: (token: Web3AliasToken) => CSSInterpolation,
) {
const [theme, token, hashId] = useToken();
const { getPrefixCls } = useContext(AntdConfigProvider.ConfigContext);
const web3Token = {
...token,
web3ComponentsCls: `.${getPrefixCls('web3')}`,
antCls: `.${getPrefixCls()}`,
};

return {
wrapSSR: useStyleRegister(
{
theme: theme,
token: web3Token,
hashId,
path: [componentName],
},
() => styleFn(web3Token as Web3AliasToken),
),
hashId,
};
}
Loading