Browse Source
* init * chore: cssinjs base button * chore: more style * chore: mix style * chore: size * chore: more style * misc * chore: re-structrue * chore: icon onlt * chore: back of disabled * chore: loading status * chore: loading motion * chore: add active style * docs: site prepare dynamic theme * chore: bump antd cssinjs * chore: color type check * chore: bump cssinjs version * chore: clean up useless ts def * chore: ignore button style * chore: rename ci * chore: update cssinjs ver * chore: ssr default wrapper * chore: bump cssinjs version * chore: ssr support * chore: fix script * test: fix node snapshot * chore: move cssinjs pkg size from css to js * test: coveragepull/34247/head
二货机器人
3 years ago
committed by
GitHub
22 changed files with 770 additions and 21 deletions
@ -0,0 +1,33 @@ |
|||
import { TinyColor } from '@ctrl/tinycolor'; |
|||
import type { DesignToken } from '.'; |
|||
|
|||
const defaultDesignToken: DesignToken = { |
|||
primaryColor: '#1890ff', |
|||
errorColor: '#ff4d4f', |
|||
|
|||
// https://github.com/ant-design/ant-design/issues/20210
|
|||
lineHeight: 1.5715, |
|||
|
|||
borderWidth: 1, |
|||
borderStyle: 'solid', |
|||
borderRadius: 2, |
|||
borderColor: new TinyColor({ h: 0, s: 0, v: 85 }).toHexString(), |
|||
|
|||
easeInOut: `cubic-bezier(0.645, 0.045, 0.355, 1)`, |
|||
|
|||
fontSize: 14, |
|||
textColor: new TinyColor('#000').setAlpha(0.85).toRgbString(), |
|||
textColorDisabled: new TinyColor('#000').setAlpha(0.25).toRgbString(), |
|||
|
|||
height: 32, |
|||
|
|||
padding: 16, |
|||
margin: 16, |
|||
|
|||
componentBackground: '#fff', |
|||
componentBackgroundDisabled: new TinyColor({ h: 0, s: 0, v: 96 }).toHexString(), |
|||
|
|||
duration: '0.3s', |
|||
}; |
|||
|
|||
export default defaultDesignToken; |
@ -0,0 +1,112 @@ |
|||
import React from 'react'; |
|||
import { generate } from '@ant-design/colors'; |
|||
import { CSSObject, Theme, useCacheToken, useStyleRegister } from '@ant-design/cssinjs'; |
|||
import defaultDesignToken from './default'; |
|||
import version from '../../version'; |
|||
import { ConfigContext } from '../../config-provider'; |
|||
|
|||
export interface DesignToken { |
|||
primaryColor: string; |
|||
errorColor: string; |
|||
lineHeight: number; |
|||
borderWidth: number; |
|||
borderStyle: string; |
|||
borderRadius: number; |
|||
borderColor: string; |
|||
easeInOut: string; |
|||
|
|||
fontSize: number; |
|||
textColor: string; |
|||
textColorDisabled: string; |
|||
|
|||
height: number; |
|||
|
|||
padding: number; |
|||
margin: number; |
|||
|
|||
componentBackground: string; |
|||
componentBackgroundDisabled: string; |
|||
|
|||
duration: string; |
|||
} |
|||
|
|||
/** This is temporary token definition since final token definition is not ready yet. */ |
|||
export interface DerivativeToken extends DesignToken { |
|||
primaryHoverColor: string; |
|||
primaryActiveColor: string; |
|||
errorHoverColor: string; |
|||
errorActiveColor: string; |
|||
|
|||
linkColor: string; |
|||
fontSizeSM: number; |
|||
fontSizeLG: number; |
|||
heightSM: number; |
|||
heightLG: number; |
|||
paddingXS: number; |
|||
marginXS: number; |
|||
} |
|||
|
|||
export { useStyleRegister }; |
|||
|
|||
// =============================== Derivative ===============================
|
|||
function derivative(designToken: DesignToken): DerivativeToken { |
|||
const primaryColors = generate(designToken.primaryColor); |
|||
const errorColors = generate(designToken.errorColor); |
|||
|
|||
return { |
|||
...designToken, |
|||
|
|||
primaryHoverColor: primaryColors[4], |
|||
primaryActiveColor: primaryColors[6], |
|||
|
|||
errorHoverColor: errorColors[4], |
|||
errorActiveColor: errorColors[6], |
|||
|
|||
linkColor: designToken.primaryColor, |
|||
fontSizeSM: designToken.fontSize - 2, |
|||
fontSizeLG: designToken.fontSize + 2, |
|||
heightSM: designToken.height * 0.75, |
|||
heightLG: designToken.height * 1.25, |
|||
paddingXS: designToken.padding * 0.5, |
|||
marginXS: designToken.margin * 0.5, |
|||
}; |
|||
} |
|||
|
|||
// ================================ Context =================================
|
|||
export const ThemeContext = React.createContext( |
|||
new Theme<DesignToken, DerivativeToken>(derivative), |
|||
); |
|||
|
|||
export const DesignTokenContext = React.createContext<{ |
|||
token: Partial<DesignToken>; |
|||
hashed?: string | boolean; |
|||
}>({ |
|||
token: defaultDesignToken, |
|||
}); |
|||
|
|||
// ================================== Hook ==================================
|
|||
export function useToken() { |
|||
const { iconPrefixCls } = React.useContext(ConfigContext); |
|||
const { token: rootDesignToken, hashed } = React.useContext(DesignTokenContext); |
|||
const theme = React.useContext(ThemeContext); |
|||
|
|||
const salt = `${version}-${hashed || ''}`; |
|||
|
|||
const [token, hashId] = useCacheToken(theme, [defaultDesignToken, rootDesignToken], { |
|||
salt, |
|||
}); |
|||
return [theme, token, iconPrefixCls, hashed ? hashId : '']; |
|||
} |
|||
|
|||
// ================================== Util ==================================
|
|||
export function withPrefix( |
|||
style: CSSObject, |
|||
prefixCls: string, |
|||
additionalClsList: string[] = [], |
|||
): CSSObject { |
|||
const fullClsList = [prefixCls, ...additionalClsList].filter(cls => cls).map(cls => `.${cls}`); |
|||
|
|||
return { |
|||
[fullClsList.join('')]: style, |
|||
}; |
|||
} |
@ -0,0 +1,2 @@ |
|||
import '../../style/index.less'; |
|||
import './index.less'; |
@ -1,2 +1,391 @@ |
|||
import '../../style/index.less'; |
|||
import './index.less'; |
|||
// deps-lint-skip-all
|
|||
import { CSSInterpolation, CSSObject } from '@ant-design/cssinjs'; |
|||
import { TinyColor } from '@ctrl/tinycolor'; |
|||
import { DerivativeToken, useStyleRegister, useToken, withPrefix } from '../../_util/theme'; |
|||
|
|||
// ============================== Shared ==============================
|
|||
const genSharedButtonStyle = ( |
|||
prefixCls: string, |
|||
iconPrefixCls: string, |
|||
token: DerivativeToken, |
|||
): CSSObject => ({ |
|||
outline: 'none', |
|||
position: 'relative', |
|||
display: 'inline-block', |
|||
fontWeight: 400, |
|||
whiteSpace: 'nowrap', |
|||
textAlign: 'center', |
|||
backgroundImage: 'none', |
|||
backgroundColor: 'transparent', |
|||
border: `${token.borderWidth}px ${token.borderStyle} transparent`, |
|||
cursor: 'pointer', |
|||
transition: `all ${token.duration} ${token.easeInOut}`, |
|||
userSelect: 'none', |
|||
touchAction: 'manipulation', |
|||
lineHeight: token.lineHeight, |
|||
color: token.textColor, |
|||
|
|||
'> span': { |
|||
display: 'inline-block', |
|||
}, |
|||
|
|||
// Leave a space between icon and text.
|
|||
[`> .${iconPrefixCls} + span, > span + .${iconPrefixCls}`]: { |
|||
marginInlineStart: token.marginXS, |
|||
}, |
|||
|
|||
[`&.${prefixCls}-block`]: { |
|||
width: '100%', |
|||
}, |
|||
}); |
|||
|
|||
const genHoverActiveButtonStyle = (hoverStyle: CSSObject, activeStyle: CSSObject): CSSObject => ({ |
|||
'&:not(:disabled)': { |
|||
'&:hover, &:focus': hoverStyle, |
|||
'&:active': activeStyle, |
|||
}, |
|||
}); |
|||
|
|||
// ============================== Shape ===============================
|
|||
const genCircleButtonStyle = (token: DerivativeToken): CSSObject => ({ |
|||
minWidth: token.height, |
|||
paddingLeft: 0, |
|||
paddingRight: 0, |
|||
borderRadius: '50%', |
|||
}); |
|||
|
|||
const genRoundButtonStyle = (token: DerivativeToken): CSSObject => ({ |
|||
borderRadius: token.height, |
|||
paddingLeft: token.height / 2, |
|||
paddingRight: token.height / 2, |
|||
width: 'auto', |
|||
}); |
|||
|
|||
// =============================== Type ===============================
|
|||
const genGhostButtonStyle = ( |
|||
prefixCls: string, |
|||
textColor: string | false, |
|||
borderColor: string | false, |
|||
textColorDisabled: string | false, |
|||
borderColorDisabled: string | false, |
|||
): CSSObject => ({ |
|||
[`&.${prefixCls}-background-ghost`]: { |
|||
color: textColor || undefined, |
|||
backgroundColor: 'transparent', |
|||
borderColor: borderColor || undefined, |
|||
|
|||
'&:disabled': { |
|||
cursor: 'not-allowed', |
|||
color: textColorDisabled || undefined, |
|||
borderColor: borderColorDisabled || undefined, |
|||
}, |
|||
}, |
|||
}); |
|||
|
|||
const genSolidDisabledButtonStyle = (token: DerivativeToken): CSSObject => ({ |
|||
'&:disabled': { |
|||
cursor: 'not-allowed', |
|||
borderColor: token.borderColor, |
|||
color: token.textColorDisabled, |
|||
backgroundColor: token.componentBackgroundDisabled, |
|||
boxShadow: 'none', |
|||
}, |
|||
}); |
|||
|
|||
const genSolidButtonStyle = (token: DerivativeToken): CSSObject => ({ |
|||
borderRadius: token.borderRadius, |
|||
|
|||
...genSolidDisabledButtonStyle(token), |
|||
}); |
|||
|
|||
const genPureDisabledButtonStyle = (token: DerivativeToken): CSSObject => ({ |
|||
'&:disabled': { |
|||
cursor: 'not-allowed', |
|||
color: token.textColorDisabled, |
|||
}, |
|||
}); |
|||
|
|||
// Type: Default
|
|||
const genDefaultButtonStyle = (prefixCls: string, token: DerivativeToken): CSSObject => ({ |
|||
...genSolidButtonStyle(token), |
|||
|
|||
backgroundColor: token.componentBackground, |
|||
borderColor: token.borderColor, |
|||
|
|||
boxShadow: '0 2px 0 rgba(0, 0, 0, 0.015)', |
|||
|
|||
...genHoverActiveButtonStyle( |
|||
{ |
|||
color: token.primaryHoverColor, |
|||
borderColor: token.primaryHoverColor, |
|||
}, |
|||
{ |
|||
color: token.primaryActiveColor, |
|||
borderColor: token.primaryActiveColor, |
|||
}, |
|||
), |
|||
|
|||
...genGhostButtonStyle( |
|||
prefixCls, |
|||
token.componentBackground, |
|||
token.componentBackground, |
|||
token.textColorDisabled, |
|||
token.borderColor, |
|||
), |
|||
|
|||
[`&.${prefixCls}-dangerous`]: { |
|||
color: token.errorColor, |
|||
borderColor: token.errorColor, |
|||
|
|||
...genHoverActiveButtonStyle( |
|||
{ |
|||
color: token.errorHoverColor, |
|||
borderColor: token.errorHoverColor, |
|||
}, |
|||
{ |
|||
color: token.errorActiveColor, |
|||
borderColor: token.errorActiveColor, |
|||
}, |
|||
), |
|||
|
|||
...genGhostButtonStyle( |
|||
prefixCls, |
|||
token.errorColor, |
|||
token.errorColor, |
|||
token.textColorDisabled, |
|||
token.borderColor, |
|||
), |
|||
...genSolidDisabledButtonStyle(token), |
|||
}, |
|||
}); |
|||
|
|||
// Type: Primary
|
|||
const genPrimaryButtonStyle = (prefixCls: string, token: DerivativeToken): CSSObject => ({ |
|||
...genSolidButtonStyle(token), |
|||
|
|||
color: '#FFF', |
|||
backgroundColor: token.primaryColor, |
|||
|
|||
boxShadow: '0 2px 0 rgba(0, 0, 0, 0.045)', |
|||
|
|||
...genHoverActiveButtonStyle( |
|||
{ |
|||
backgroundColor: token.primaryHoverColor, |
|||
}, |
|||
{ |
|||
backgroundColor: token.primaryActiveColor, |
|||
}, |
|||
), |
|||
|
|||
...genGhostButtonStyle( |
|||
prefixCls, |
|||
token.primaryColor, |
|||
token.primaryColor, |
|||
token.textColorDisabled, |
|||
token.borderColor, |
|||
), |
|||
|
|||
[`&.${prefixCls}-dangerous`]: { |
|||
backgroundColor: token.errorColor, |
|||
|
|||
...genHoverActiveButtonStyle( |
|||
{ |
|||
backgroundColor: token.errorHoverColor, |
|||
}, |
|||
{ |
|||
backgroundColor: token.errorActiveColor, |
|||
}, |
|||
), |
|||
|
|||
...genGhostButtonStyle( |
|||
prefixCls, |
|||
token.errorColor, |
|||
token.errorColor, |
|||
token.textColorDisabled, |
|||
token.borderColor, |
|||
), |
|||
...genSolidDisabledButtonStyle(token), |
|||
}, |
|||
}); |
|||
|
|||
// Type: Dashed
|
|||
const genDashedButtonStyle = (prefixCls: string, token: DerivativeToken): CSSObject => ({ |
|||
...genDefaultButtonStyle(prefixCls, token), |
|||
|
|||
borderStyle: 'dashed', |
|||
}); |
|||
|
|||
// Type: Link
|
|||
const genLinkButtonStyle = (prefixCls: string, token: DerivativeToken): CSSObject => ({ |
|||
color: token.linkColor, |
|||
|
|||
...genHoverActiveButtonStyle( |
|||
{ |
|||
color: token.primaryHoverColor, |
|||
}, |
|||
{ |
|||
color: token.primaryActiveColor, |
|||
}, |
|||
), |
|||
|
|||
...genPureDisabledButtonStyle(token), |
|||
|
|||
[`&.${prefixCls}-dangerous`]: { |
|||
color: token.errorColor, |
|||
|
|||
...genHoverActiveButtonStyle( |
|||
{ |
|||
color: token.errorHoverColor, |
|||
}, |
|||
{ |
|||
color: token.errorActiveColor, |
|||
}, |
|||
), |
|||
|
|||
...genPureDisabledButtonStyle(token), |
|||
}, |
|||
}); |
|||
|
|||
// Type: Text
|
|||
const genTextButtonStyle = (prefixCls: string, token: DerivativeToken): CSSObject => { |
|||
const backgroundColor = new TinyColor({ r: 0, g: 0, b: 0, a: 0.018 }); |
|||
|
|||
return { |
|||
...genHoverActiveButtonStyle( |
|||
{ |
|||
backgroundColor: backgroundColor.toRgbString(), |
|||
}, |
|||
{ |
|||
backgroundColor: backgroundColor |
|||
.clone() |
|||
.setAlpha(backgroundColor.getAlpha() * 1.5) |
|||
.toRgbString(), |
|||
}, |
|||
), |
|||
|
|||
...genPureDisabledButtonStyle(token), |
|||
|
|||
[`&.${prefixCls}-dangerous`]: { |
|||
color: token.errorColor, |
|||
|
|||
...genPureDisabledButtonStyle(token), |
|||
}, |
|||
}; |
|||
}; |
|||
|
|||
const genTypeButtonStyle = (prefixCls: string, token: DerivativeToken): CSSInterpolation => [ |
|||
withPrefix(genDefaultButtonStyle(prefixCls, token), `${prefixCls}-default`, []), |
|||
withPrefix(genPrimaryButtonStyle(prefixCls, token), `${prefixCls}-primary`, []), |
|||
withPrefix(genDashedButtonStyle(prefixCls, token), `${prefixCls}-dashed`, []), |
|||
withPrefix(genLinkButtonStyle(prefixCls, token), `${prefixCls}-link`, []), |
|||
withPrefix(genTextButtonStyle(prefixCls, token), `${prefixCls}-text`, []), |
|||
]; |
|||
|
|||
// =============================== Size ===============================
|
|||
const genSizeButtonStyle = ( |
|||
prefixCls: string, |
|||
iconPrefixCls: string, |
|||
sizePrefixCls: string, |
|||
token: DerivativeToken, |
|||
): CSSInterpolation => { |
|||
const paddingVertical = Math.max( |
|||
0, |
|||
(token.height - token.fontSize * token.lineHeight) / 2 - token.borderWidth, |
|||
); |
|||
const paddingHorizontal = token.padding - token.borderWidth; |
|||
|
|||
const iconOnlyCls = `.${prefixCls}-icon-only`; |
|||
|
|||
return [ |
|||
// Size
|
|||
withPrefix( |
|||
{ |
|||
fontSize: token.fontSize, |
|||
height: token.height, |
|||
padding: `${paddingVertical}px ${paddingHorizontal}px`, |
|||
|
|||
[`&${iconOnlyCls}`]: { |
|||
width: token.height, |
|||
paddingLeft: 0, |
|||
paddingRight: 0, |
|||
|
|||
'> span': { |
|||
transform: 'scale(1.143)', // 14px -> 16px
|
|||
}, |
|||
}, |
|||
|
|||
// Loading
|
|||
[`&.${prefixCls}-loading`]: { |
|||
opacity: 0.65, |
|||
cursor: 'default', |
|||
}, |
|||
|
|||
[`.${prefixCls}-loading-icon`]: { |
|||
transition: `width ${token.duration} ${token.easeInOut}, opacity ${token.duration} ${token.easeInOut}`, |
|||
}, |
|||
|
|||
[`&:not(${iconOnlyCls}) .${prefixCls}-loading-icon > .${iconPrefixCls}`]: { |
|||
marginInlineEnd: token.marginXS, |
|||
}, |
|||
}, |
|||
prefixCls, |
|||
[sizePrefixCls], |
|||
), |
|||
|
|||
// Shape - patch prefixCls again to override solid border radius style
|
|||
withPrefix(genCircleButtonStyle(token), `${prefixCls}-circle`, [prefixCls, sizePrefixCls]), |
|||
withPrefix(genRoundButtonStyle(token), `${prefixCls}-round`, [prefixCls, sizePrefixCls]), |
|||
]; |
|||
}; |
|||
|
|||
const genSizeBaseButtonStyle = ( |
|||
prefixCls: string, |
|||
iconPrefixCls: string, |
|||
token: DerivativeToken, |
|||
): CSSInterpolation => genSizeButtonStyle(prefixCls, iconPrefixCls, '', token); |
|||
|
|||
const genSizeSmallButtonStyle = ( |
|||
prefixCls: string, |
|||
iconPrefixCls: string, |
|||
token: DerivativeToken, |
|||
): CSSInterpolation => { |
|||
const largeToken: DerivativeToken = { |
|||
...token, |
|||
height: token.heightSM, |
|||
padding: token.paddingXS, |
|||
}; |
|||
|
|||
return genSizeButtonStyle(prefixCls, iconPrefixCls, `${prefixCls}-sm`, largeToken); |
|||
}; |
|||
|
|||
const genSizeLargeButtonStyle = ( |
|||
prefixCls: string, |
|||
iconPrefixCls: string, |
|||
token: DerivativeToken, |
|||
): CSSInterpolation => { |
|||
const largeToken: DerivativeToken = { |
|||
...token, |
|||
height: token.heightLG, |
|||
fontSize: token.fontSizeLG, |
|||
}; |
|||
|
|||
return genSizeButtonStyle(prefixCls, iconPrefixCls, `${prefixCls}-lg`, largeToken); |
|||
}; |
|||
|
|||
// ============================== Export ==============================
|
|||
export default function useStyle(prefixCls: string) { |
|||
const [theme, token, iconPrefixCls, hashId] = useToken(); |
|||
|
|||
return useStyleRegister({ theme, token, hashId, path: [prefixCls] }, () => [ |
|||
// Shared
|
|||
withPrefix(genSharedButtonStyle(prefixCls, iconPrefixCls, token), prefixCls), |
|||
|
|||
// Size
|
|||
genSizeSmallButtonStyle(prefixCls, iconPrefixCls, token), |
|||
genSizeBaseButtonStyle(prefixCls, iconPrefixCls, token), |
|||
genSizeLargeButtonStyle(prefixCls, iconPrefixCls, token), |
|||
|
|||
// Group (type, ghost, danger, disabled, loading)
|
|||
genTypeButtonStyle(prefixCls, token), |
|||
]); |
|||
} |
|||
|
@ -0,0 +1,49 @@ |
|||
import * as React from 'react'; |
|||
import { mount } from 'enzyme'; |
|||
import ConfigProvider from '..'; |
|||
import Button from '../../button'; |
|||
|
|||
describe('ConfigProvider.DynamicTheme', () => { |
|||
beforeEach(() => { |
|||
Array.from(document.querySelectorAll('style')).forEach(style => { |
|||
style.parentNode?.removeChild(style); |
|||
}); |
|||
}); |
|||
|
|||
it('customize primary color', () => { |
|||
mount( |
|||
<ConfigProvider |
|||
theme={{ |
|||
token: { |
|||
primaryColor: '#f00', |
|||
}, |
|||
}} |
|||
> |
|||
<Button /> |
|||
</ConfigProvider>, |
|||
); |
|||
|
|||
const dynamicStyles = Array.from(document.querySelectorAll('style[data-css-hash]')); |
|||
|
|||
expect( |
|||
dynamicStyles.some(style => { |
|||
const { innerHTML } = style; |
|||
return ( |
|||
innerHTML.includes('.ant-btn-primary') && innerHTML.includes('background-color:#f00') |
|||
); |
|||
}), |
|||
).toBeTruthy(); |
|||
}); |
|||
|
|||
it('not crash on null token', () => { |
|||
expect(() => { |
|||
mount( |
|||
<ConfigProvider |
|||
theme={{ |
|||
token: null as any, |
|||
}} |
|||
/>, |
|||
); |
|||
}).not.toThrow(); |
|||
}); |
|||
}); |
@ -0,0 +1,102 @@ |
|||
import * as React from 'react'; |
|||
import { TinyColor } from '@ctrl/tinycolor'; |
|||
import { Drawer, Form, Input, Button, InputNumber } from 'antd'; |
|||
import { useIntl } from 'react-intl'; |
|||
import { BugOutlined } from '@ant-design/icons'; |
|||
import { DesignToken } from '../../../../components/_util/theme'; |
|||
import defaultTheme from '../../../../components/_util/theme/default'; |
|||
|
|||
export interface ThemeConfigProps { |
|||
defaultToken: DesignToken; |
|||
onChangeTheme: (theme: DesignToken) => void; |
|||
} |
|||
|
|||
export default ({ onChangeTheme, defaultToken }: ThemeConfigProps) => { |
|||
const { formatMessage } = useIntl(); |
|||
const [visible, setVisible] = React.useState(false); |
|||
const [form] = Form.useForm(); |
|||
|
|||
const keys = Object.keys(defaultTheme); |
|||
|
|||
const onFinish = (nextToken: DesignToken) => { |
|||
onChangeTheme(nextToken); |
|||
}; |
|||
|
|||
return ( |
|||
<> |
|||
<div |
|||
style={{ |
|||
position: 'fixed', |
|||
right: 0, |
|||
bottom: 32, |
|||
fontSize: 16, |
|||
borderRadius: '4px 0 0 4px', |
|||
background: '#FFF', |
|||
boxShadow: '0 0 4px rgba(0, 0, 0, 0.3)', |
|||
padding: '8px 16px 8px 12px', |
|||
cursor: 'pointer', |
|||
}} |
|||
onClick={() => setVisible(true)} |
|||
> |
|||
<BugOutlined /> Dynamic Theme |
|||
</div> |
|||
|
|||
<Drawer |
|||
zIndex={10001} |
|||
visible={visible} |
|||
onClose={() => { |
|||
setVisible(false); |
|||
}} |
|||
title={formatMessage({ id: 'app.theme.switch.dynamic' })} |
|||
extra={ |
|||
<Button onClick={form.submit} type="primary"> |
|||
Submit |
|||
</Button> |
|||
} |
|||
destroyOnClose |
|||
> |
|||
<Form |
|||
form={form} |
|||
initialValues={defaultToken} |
|||
layout="vertical" |
|||
onFinish={onFinish} |
|||
autoComplete="off" |
|||
> |
|||
{keys.map((key: keyof typeof defaultToken) => { |
|||
const originValue = defaultToken[key]; |
|||
const originValueType = typeof originValue; |
|||
|
|||
let node: React.ReactElement; |
|||
|
|||
switch (originValueType) { |
|||
case 'number': |
|||
node = <InputNumber />; |
|||
break; |
|||
|
|||
default: |
|||
node = <Input />; |
|||
} |
|||
|
|||
const rules: any[] = [{ required: true }]; |
|||
const originColor = new TinyColor(originValue); |
|||
if (originValueType === 'string' && originColor.isValid) { |
|||
rules.push({ |
|||
validator: async (_: any, value: string) => { |
|||
if (!new TinyColor(value).isValid) { |
|||
throw new Error('Invalidate color type'); |
|||
} |
|||
}, |
|||
}); |
|||
} |
|||
|
|||
return ( |
|||
<Form.Item key={key} label={key} name={key} rules={rules} validateFirst> |
|||
{node} |
|||
</Form.Item> |
|||
); |
|||
})} |
|||
</Form> |
|||
</Drawer> |
|||
</> |
|||
); |
|||
}; |
Loading…
Reference in new issue