diff --git a/package.json b/package.json index 6dc9f22355..00938bd0f2 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "watch:uiw": "lerna exec --scope uiw -- tsbb watch", "watch:react-menu": "lerna exec --scope @uiw/react-menu -- tsbb watch", "watch:css:react-menu": "lerna exec --scope @uiw/react-menu -- compile-less -d src -o esm --watch", - "watch": "lerna exec --scope @uiw/react-date-picker -- tsbb watch", + "watch": "lerna exec --scope @uiw/react-button -- tsbb watch", "//-----------": "//-----------", "build": "npm run b:uiw && npm run b:css && npm run b:css:dist", "start": "lerna exec --scope website -- npm run start", diff --git a/packages/react-button/README.md b/packages/react-button/README.md index ab7ebeed63..0f0f6b79c7 100644 --- a/packages/react-button/README.md +++ b/packages/react-button/README.md @@ -25,7 +25,7 @@ import { Button, Divider, Icon } from 'uiw'; const Demo = ()=>(
- + @@ -209,7 +209,7 @@ const Demo = ()=>( - + 添加图标 @@ -224,7 +224,7 @@ const Demo = ()=>( - + diff --git a/packages/react-button/src/index.tsx b/packages/react-button/src/index.tsx index 09af328477..a12171867d 100644 --- a/packages/react-button/src/index.tsx +++ b/packages/react-button/src/index.tsx @@ -10,6 +10,7 @@ export interface ButtonProps extends IProps, Omit { loading?: boolean; block?: boolean; icon?: React.ReactNode; + focus?: boolean; /** * 按钮类型 * @mytag {@link link } @@ -59,7 +60,24 @@ const Button = React.forwardRef((props, ref) => .trim(); return ( - + {icon} {children && React.Children.map(children, (child: React.ReactNode) => { diff --git a/packages/react-button/src/style/Variant.ts b/packages/react-button/src/style/Variant.ts index 5475c1d096..6afcadcd46 100644 --- a/packages/react-button/src/style/Variant.ts +++ b/packages/react-button/src/style/Variant.ts @@ -1,14 +1,30 @@ import { getThemeVariantValue } from '@uiw/utils'; -import { css } from 'styled-components'; - +import { css, ThemedCssFunction } from 'styled-components'; +import { ButtonBaseProps } from '.'; type Options = { type: string; - defaultTheme?: Record; - theme?: Record; +} & ButtonBaseProps; + +/** + * @description: 生成公共css + * @param {string} style 样式 + * @param {string} attrName 属性名 + * @param {boolean} fig 直接生成 + * @param {string} lastName 生成对象 + */ +export const getCommonCss = (style: string, attrName: string, fig?: boolean, lastName?: string) => { + const com = css` + ${attrName && `${attrName}{${style}}`} + ${fig && lastName && `${lastName}{${style}}`} + ${fig && !lastName && style} + `; + return com; }; export const buttonVariant = (options: Options) => { - const { type } = options; + const { type, param } = options; + const { basic, focus, active, disabled } = param || {}; + const color = getThemeVariantValue(options, `color${type}`); const backgroundColor = getThemeVariantValue(options, `backgroundColor${type}`); const backgroundColorHover = getThemeVariantValue(options, `backgroundColor${type}Hover`); @@ -24,49 +40,173 @@ export const buttonVariant = (options: Options) => { color: ${color}; background-color: ${backgroundColor}; z-index: 1; - &:focus, - &.focus { - outline: 0; - box-shadow: 0 0 0 2px ${boxShadowColorFocus}; - } &:hover { - color: ${color}; background-color: ${backgroundColorHover}; z-index: 2; } - &:active, - &.active { + ${getCommonCss( + ` + outline: 0; + box-shadow: 0 0 0 2px ${boxShadowColorFocus}; + `, + '&:focus', + focus, + )} + ${getCommonCss( + ` color: ${color}; background-color: ${backgroundColorActive}; background-image: none; - } + `, + ' &:active', + active, + )} &.disabled, &[disabled] { background-color: ${backgroundColorDisabled}; z-index: 0; } - &.w-btn-basic { - background-color: transparent !important; - box-shadow: inset 0 0 0 ${boxShadowColorBasic}; - color: ${backgroundColor}; - &:hover { - background-color: ${backgroundColorBasicHover} !important; - } - &:active, - &.active { - color: ${backgroundColor}; - background-color: ${backgroundColorBasicActive} !important; - background-image: none; - } - &.disabled, - &[disabled] { + ${getCommonCss( + ` + background-color: ${backgroundColorDisabled}; + z-index: 0; + `, + ' &[disabled]', + disabled, + )} + ${basic && + css` + & { background-color: transparent !important; - color: ${colorBasicDisabled}; + box-shadow: inset 0 0 0 ${boxShadowColorBasic}; + color: ${backgroundColor}; + &:hover { + background-color: ${backgroundColorBasicHover} !important; + } + ${getCommonCss( + ` + color: ${backgroundColor}; + background-color: ${backgroundColorBasicActive} !important; + background-image: none; + `, + ' &:active', + active, + )} + ${getCommonCss( + ` + background-color: transparent !important; + color: ${colorBasicDisabled}; + `, + '&[disabled]', + disabled, + )} } - } + `} `; }; +export const buttonTypes = (props: ButtonBaseProps) => { + const { type, focus, basic, active, disabled } = props.param || {}; + + switch (type) { + case 'primary': + return buttonVariant({ ...props, type: 'Primary' }); + case 'success': + return buttonVariant({ ...props, type: 'Success' }); + case 'danger': + return buttonVariant({ ...props, type: 'Error' }); + case 'dark': + return buttonVariant({ ...props, type: 'Dark' }); + case 'light': + return css` + box-shadow: inset 0 1px 0 0 ${getThemeVariantValue(props, 'boxShadowColorLightDefault')}, + inset 1px -1px 0 0 ${getThemeVariantValue(props, 'boxShadowColorLightDefault')}, + inset -1px 0px 0 0 ${getThemeVariantValue(props, 'boxShadowColorLightDefault')}; + ${buttonVariant({ ...props, type: 'Light' })} + ${getCommonCss( + ` + outline: 0; + box-shadow: inset 0 1px 0 0 ${getThemeVariantValue(props, 'boxShadowColorLightDefault')}, + inset 1px -1px 0 0 ${getThemeVariantValue(props, 'boxShadowColorLightDefault')}, + inset -1px 0px 0 0 ${getThemeVariantValue(props, 'boxShadowColorLightDefault')}, + 0 0 0 2px ${getThemeVariantValue(props, 'boxShadowColorLight4')}; + `, + '&:focus', + focus, + )} + ${basic && + css` + color: ${getThemeVariantValue(props, 'colorLightBasic')} !important; + &:focus { + box-shadow: inset 0 0 0 0 ${getThemeVariantValue(props, 'boxShadowColorLightDefault')}; + } + ${focus && + css` + box-shadow: inset 0 0 0 0 ${getThemeVariantValue(props, 'boxShadowColorLightDefault')}; + `} + &:hover { + background-color: ${getThemeVariantValue(props, 'backgroundColorLightBasicHover')} !important; + } + ${getCommonCss( + ` + color: ${getThemeVariantValue(props, 'colorLightBasic')}; + background-color: ${getThemeVariantValue(props, 'backgroundColorLightBasicActive')} !important; + background-image: none; + `, + '&:active', + active, + )} + ${getCommonCss( + ` + background-color: transparent !important; + color: ${getThemeVariantValue(props, 'colorLightBasicDisabled')}; + `, + '&[disabled]', + disabled, + )} + `} + ${getCommonCss( + ` + color: ${getThemeVariantValue(props, 'colorLightBasicDisabled')}; + z-index: 0; + `, + '&[disabled]', + disabled, + )} + `; + case 'link': + return css` + ${buttonVariant({ ...props, type: 'Link' })}; + color: ${getThemeVariantValue(props, 'colorLink')} !important; + &:hover:not([disabled]) { + color: ${getThemeVariantValue(props, 'colorLinkNotDisabled')}; + text-decoration: underline; + } + ${getCommonCss( + ` + color: ${getThemeVariantValue(props, 'colorLinkNotDisabledActive')}; + box-shadow: none; + text-decoration: underline; + `, + '&:not([disabled]):active', + disabled, + '&:not([disabled]) ', + )} + &[disabled] { + z-index: 0; + } + ${disabled && + css` + z-index: 0; + `} + `; + case 'warning': + return buttonVariant({ ...props, type: 'Warning' }); + default: + return css``; + } +}; + export const buttonSize = (fontSize: string, iconSize: string, lineHeight: string | number, minHeight: string) => { return css` font-size: ${fontSize}; @@ -77,3 +217,24 @@ export const buttonSize = (fontSize: string, iconSize: string, lineHeight: strin } `; }; +const getSize = (props: ButtonBaseProps, type: string) => { + const fontSize = getThemeVariantValue(props, `fontSize${type}`); + const minHeight = getThemeVariantValue(props, `minHeightButton${type}`); + const fontSizeIcon = getThemeVariantValue(props, `fontSizeButtonIcon${type}`); + return buttonSize(`${fontSize}`, `${fontSizeIcon}`, fontSize, `${minHeight}`); +}; +export const buttonSizeCss = (props: ButtonBaseProps) => { + const { size } = props.param || {}; + switch (size) { + case 'large': + return getSize(props, 'Large'); + case 'small': + return css` + padding: 0 6px; + min-width: ${getThemeVariantValue(props, 'minHeightButtonSmall')}; + ${getSize(props, 'Small')} + `; + default: + return css``; + } +}; diff --git a/packages/react-button/src/style/index.ts b/packages/react-button/src/style/index.ts index 9caef7cc7c..a6ce66096c 100644 --- a/packages/react-button/src/style/index.ts +++ b/packages/react-button/src/style/index.ts @@ -1,20 +1,23 @@ -import styled from 'styled-components'; +import styled, { css } from 'styled-components'; import { getThemeVariantValue } from '@uiw/utils'; -import { buttonVariant, buttonSize } from './Variant'; - -interface ButtonProps { +import { buttonTypes, buttonSizeCss } from './Variant'; +import { ButtonType, ButtonSize } from '../'; +export interface ButtonBaseProps { defaultTheme?: Record; theme?: Record; + param?: { + size: ButtonSize; + type: ButtonType; + basic: boolean; + loading: boolean; + disabled: boolean; + active: boolean; + block: boolean; + focus: boolean; + }; } -const getSize = (props: ButtonProps, type: string) => { - const fontSize = getThemeVariantValue(props, `fontSize${type}`); - const minHeight = getThemeVariantValue(props, `minHeightButton${type}`); - const fontSizeIcon = getThemeVariantValue(props, `fontSizeButtonIcon${type}`); - return buttonSize(`${fontSize}`, `${fontSizeIcon}`, fontSize, `${minHeight}`); -}; - -const Button = styled.button` +const ButtonBase = styled.button` user-select: none; display: inline-flex; flex-direction: row; @@ -49,121 +52,49 @@ const Button = styled.button` &[disabled] { cursor: not-allowed; } - &.w-btn-primary { - ${(props) => buttonVariant({ ...props, type: 'Primary' })} - } - &.w-btn-success { - ${(props) => buttonVariant({ ...props, type: 'Success' })} - } - &.w-btn-warning { - ${(props) => buttonVariant({ ...props, type: 'Warning' })} - } - &.w-btn-danger { - ${(props) => buttonVariant({ ...props, type: 'Error' })} - } - &.w-btn-light { - box-shadow: inset 0 1px 0 0 ${(props) => getThemeVariantValue(props, 'boxShadowColorLightDefault')}, - inset 1px -1px 0 0 ${(props) => getThemeVariantValue(props, 'boxShadowColorLightDefault')}, - inset -1px 0px 0 0 ${(props) => getThemeVariantValue(props, 'boxShadowColorLightDefault')}; - ${(props) => buttonVariant({ ...props, type: 'Light' })} - &:focus, - &.focus { - outline: 0; - box-shadow: inset 0 1px 0 0 ${(props) => getThemeVariantValue(props, 'boxShadowColorLightDefault')}, - inset 1px -1px 0 0 ${(props) => getThemeVariantValue(props, 'boxShadowColorLightDefault')}, - inset -1px 0px 0 0 ${(props) => getThemeVariantValue(props, 'boxShadowColorLightDefault')}, - 0 0 0 2px ${(props) => getThemeVariantValue(props, 'boxShadowColorLight4')}; - } - &.w-btn-basic { - color: ${(props) => getThemeVariantValue(props, 'colorLightBasic')}; - &:focus, - &.focus { - box-shadow: inset 0 0 0 0 ${(props) => getThemeVariantValue(props, 'boxShadowColorLightDefault')}; - } - &:hover { - background-color: ${(props) => getThemeVariantValue(props, 'backgroundColorLightBasicHover')} !important; - } - &:active, - &.active { - color: ${(props) => getThemeVariantValue(props, 'colorLightBasic')}; - background-color: ${(props) => getThemeVariantValue(props, 'backgroundColorLightBasicActive')} !important; - background-image: none; - } - &.disabled, - &[disabled] { - background-color: transparent !important; - color: ${(props) => getThemeVariantValue(props, 'colorLightBasicDisabled')}; - } - } - &.disabled, - &[disabled] { - color: ${(props) => getThemeVariantValue(props, 'colorLightBasicDisabled')}; - z-index: 0; - } - } - &.w-btn-dark { - ${(props) => buttonVariant({ ...props, type: 'Dark' })} - } - &.w-btn-link { - ${(props) => buttonVariant({ ...props, type: 'Link' })} - color:${(props) => getThemeVariantValue(props, 'colorLink')} !important; - &:hover:not([disabled]) { - color: ${(props) => getThemeVariantValue(props, 'colorLinkNotDisabled')}; - text-decoration: underline; - } - &:not([disabled]):active, - &:not([disabled]).active { - color: ${(props) => getThemeVariantValue(props, 'colorLinkNotDisabledActive')}; - box-shadow: none; - text-decoration: underline; - } - &.disabled, - &[disabled] { - z-index: 0; - } - } + ${buttonTypes} .w-icon { font-size: ${(props) => getThemeVariantValue(props, 'fontSizeButtonIcontDefault')}; } - &.w-btn-size-large { - ${(props) => getSize(props, 'Large')} - } - &.w-btn-size-small { - padding: 0 6px; - min-width: ${(props) => getThemeVariantValue(props, 'minHeightButtonSmall')}; - ${(props) => getSize(props, 'Small')} - } - & .w-icon:not(:last-child) { + ${buttonSizeCss} + .w-icon:not(:last-child) { margin-right: 5px; } - &.w-btn-loading.w-btn-light::before { - border: 1.2px solid ${(props) => getThemeVariantValue(props, 'borderColorLinghtLoadingBefore')}; - } - &.w-btn-loading { - &::before { - content: ''; - display: inline-block; - width: 1em; - height: 1em; - border-radius: 50%; - border: 1.2px solid ${(props) => getThemeVariantValue(props, 'colorButtonLoadingBefore')}; - color: ${(props) => getThemeVariantValue(props, 'colorButtonLoadingBefore')}; - margin: 0 3px 0 0; - clip-path: polygon(0% 0%, 100% 0, 100% 30%, 0% 30%); - animation: rotate 0.5s linear infinite; - @keyframes rotate { - from { - transform: rotateZ(0deg); - } - to { - transform: rotateZ(360deg); + ${(props) => + props.param?.loading && + props.param.type === 'light' && + css` + &::before { + border: 1.2px solid ${(props) => getThemeVariantValue(props, 'borderColorLinghtLoadingBefore')}; + } + `} + ${(props) => + props.param?.loading && + css` + &::before { + content: ''; + display: inline-block; + width: 1em; + height: 1em; + border-radius: 50%; + border: 1.2px solid ${(props) => getThemeVariantValue(props, 'colorButtonLoadingBefore')}; + color: ${(props) => getThemeVariantValue(props, 'colorButtonLoadingBefore')}; + margin: 0 3px 0 0; + clip-path: polygon(0% 0%, 100% 0, 100% 30%, 0% 30%); + animation: rotate 0.5s linear infinite; + @keyframes rotate { + from { + transform: rotateZ(0deg); + } + to { + transform: rotateZ(360deg); + } } } - } - } + `} `; -Button.defaultProps = { +ButtonBase.defaultProps = { defaultTheme: { colorButtonBase: '#fff', // 大小设置 @@ -275,4 +206,4 @@ Button.defaultProps = { colorLinkNotDisabledActive: '#002d4d', }, }; -export default Button; +export default ButtonBase;