refactor: button

pull/6213/head
tangjinzhou 2023-01-26 21:42:27 +08:00
parent 287a8d0c4e
commit 75e4b72c21
11 changed files with 631 additions and 982 deletions

View File

@ -1,7 +1,7 @@
import { computed, defineComponent } from 'vue';
import { flattenChildren } from '../_util/props-util';
import useConfigInject from '../_util/hooks/useConfigInject';
import { useToken } from '../theme/internal';
import type { ExtractPropTypes, PropType, ComputedRef } from 'vue';
import type { SizeType } from '../config-provider';
import devWarning from '../vc-util/devWarning';
@ -24,13 +24,12 @@ export default defineComponent({
props: buttonGroupProps(),
setup(props, { slots }) {
const { prefixCls, direction } = useConfigInject('btn-group', props);
const [, , hashId] = useToken();
GroupSizeContext.useProvide({
size: computed(() => props.size),
});
const classes = computed(() => {
const { size } = props;
// large => lg
// small => sm
let sizeCls = '';
switch (size) {
case 'large':
@ -50,6 +49,7 @@ export default defineComponent({
[`${prefixCls.value}`]: true,
[`${prefixCls.value}-${sizeCls}`]: sizeCls,
[`${prefixCls.value}-rtl`]: direction.value === 'rtl',
[hashId.value]: true,
};
});
return () => {

View File

@ -15,7 +15,7 @@ import { flattenChildren, initDefaultProps } from '../_util/props-util';
import useConfigInject from '../_util/hooks/useConfigInject';
import devWarning from '../vc-util/devWarning';
import LoadingIcon from './LoadingIcon';
import useStyle from './style';
import type { ButtonType } from './buttonTypes';
import type { VNode, Ref } from 'vue';
import { GroupSizeContext } from './button-group';
@ -39,6 +39,7 @@ export default defineComponent({
// emits: ['click', 'mousedown'],
setup(props, { slots, attrs, emit }) {
const { prefixCls, autoInsertSpaceInButton, direction, size } = useConfigInject('btn', props);
const [wrapSSR, hashId] = useStyle(prefixCls);
const { size: groupSize } = GroupSizeContext.useInject();
const buttonNodeRef = ref<HTMLElement>(null);
const delayTimeoutRef = ref(undefined);
@ -82,6 +83,7 @@ export default defineComponent({
const sizeCls = sizeFullname ? sizeClassNameMap[sizeFullname] || '' : '';
return {
[hashId.value]: true,
[`${pre}`]: true,
[`${pre}-${type}`]: type,
[`${pre}-${shape}`]: shape !== 'default' && shape,
@ -119,6 +121,9 @@ export default defineComponent({
}
emit('click', event);
};
const handleMousedown = (event: Event) => {
emit('mousedown', event);
};
const insertSpace = (child: VNode, needInserted: boolean) => {
const SPACE = needInserted ? ' ' : '';
@ -153,7 +158,7 @@ export default defineComponent({
isNeedInserted = children.length === 1 && !icon && !isUnBorderedButtonType(props.type);
const { type, htmlType, disabled, href, title, target, onMousedown } = props;
const { type, htmlType, disabled, href, title, target } = props;
const iconType = innerLoading.value ? 'loading' : icon;
const buttonProps = {
@ -166,7 +171,7 @@ export default defineComponent({
{ [`${prefixCls.value}-icon-only`]: children.length === 0 && !!iconType },
],
onClick: handleClick,
onMousedown,
onMousedown: handleMousedown,
};
// https://github.com/vueComponent/ant-design-vue/issues/4930
if (!disabled) {
@ -189,29 +194,29 @@ export default defineComponent({
);
if (href !== undefined) {
return (
return wrapSSR(
<a {...buttonProps} href={href} target={target} ref={buttonNodeRef}>
{iconNode}
{kids}
</a>
</a>,
);
}
const buttonNode = (
let buttonNode = (
<button {...buttonProps} ref={buttonNodeRef} type={htmlType}>
{iconNode}
{kids}
</button>
);
if (isUnBorderedButtonType(type)) {
return buttonNode;
if (!isUnBorderedButtonType(type)) {
buttonNode = <Wave disabled={!!innerLoading.value}>{buttonNode}</Wave>;
}
return (
return wrapSSR(
<Wave ref="wave" disabled={!!innerLoading.value}>
{buttonNode}
</Wave>
</Wave>,
);
};
},

View File

@ -2,6 +2,8 @@ import PropTypes from '../_util/vue-types';
import type { ExtractPropTypes, PropType } from 'vue';
import type { SizeType } from '../config-provider';
import { eventType } from '../_util/type';
import type { MouseEventHandler } from '../_util/EventInterface';
export type ButtonType = 'link' | 'default' | 'primary' | 'ghost' | 'dashed' | 'text';
export type ButtonShape = 'default' | 'circle' | 'round';
@ -36,12 +38,8 @@ export const buttonProps = () => ({
href: String,
target: String,
title: String,
onClick: {
type: Function as PropType<(event: MouseEvent) => void>,
},
onMousedown: {
type: Function as PropType<(event: MouseEvent) => void>,
},
onClick: eventType<MouseEventHandler>(),
onMousedown: eventType<MouseEventHandler>(),
});
export type ButtonProps = Partial<ExtractPropTypes<ReturnType<typeof buttonProps>>>;

View File

@ -0,0 +1,80 @@
import type { ButtonToken } from '.';
import type { GenerateStyle } from '../../theme/internal';
const genButtonBorderStyle = (buttonTypeCls: string, borderColor: string) => ({
// Border
[`> span, > ${buttonTypeCls}`]: {
'&:not(:last-child)': {
[`&, & > ${buttonTypeCls}`]: {
'&:not(:disabled)': {
borderInlineEndColor: borderColor,
},
},
},
'&:not(:first-child)': {
[`&, & > ${buttonTypeCls}`]: {
'&:not(:disabled)': {
borderInlineStartColor: borderColor,
},
},
},
},
});
const genGroupStyle: GenerateStyle<ButtonToken> = token => {
const { componentCls, fontSize, lineWidth, colorPrimaryHover, colorErrorHover } = token;
return {
[`${componentCls}-group`]: [
{
position: 'relative',
display: 'inline-flex',
// Border
[`> span, > ${componentCls}`]: {
'&:not(:last-child)': {
[`&, & > ${componentCls}`]: {
borderStartEndRadius: 0,
borderEndEndRadius: 0,
},
},
'&:not(:first-child)': {
marginInlineStart: -lineWidth,
[`&, & > ${componentCls}`]: {
borderStartStartRadius: 0,
borderEndStartRadius: 0,
},
},
},
[componentCls]: {
position: 'relative',
zIndex: 1,
[`&:hover,
&:focus,
&:active`]: {
zIndex: 2,
},
'&[disabled]': {
zIndex: 0,
},
},
[`${componentCls}-icon-only`]: {
fontSize,
},
},
// Border Color
genButtonBorderStyle(`${componentCls}-primary`, colorPrimaryHover),
genButtonBorderStyle(`${componentCls}-danger`, colorErrorHover),
],
};
};
export default genGroupStyle;

View File

@ -1,290 +0,0 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
@import './mixin';
@btn-prefix-cls: ~'@{ant-prefix}-btn';
// for compatible
@btn-ghost-color: @text-color;
@btn-ghost-bg: transparent;
@btn-ghost-border: @border-color-base;
// Button styles
// -----------------------------
.@{btn-prefix-cls} {
// Fixing https://github.com/ant-design/ant-design/issues/12978
// Fixing https://github.com/ant-design/ant-design/issues/20058
// Fixing https://github.com/ant-design/ant-design/issues/19972
// Fixing https://github.com/ant-design/ant-design/issues/18107
// Fixing https://github.com/ant-design/ant-design/issues/13214
// It is a render problem of chrome, which is only happened in the codesandbox demo
// 0.001px solution works and I don't know why
line-height: @btn-line-height;
.btn();
.btn-default();
// Fix loading button animation
// https://github.com/ant-design/ant-design/issues/24323
> span {
display: inline-block;
}
&-primary {
.btn-primary();
.@{btn-prefix-cls}-group &:not(:first-child):not(:last-child) {
border-right-color: @btn-group-border;
border-left-color: @btn-group-border;
&:disabled {
border-color: @btn-default-border;
}
}
.@{btn-prefix-cls}-group &:first-child {
&:not(:last-child) {
border-right-color: @btn-group-border;
&[disabled] {
border-right-color: @btn-default-border;
}
}
}
.@{btn-prefix-cls}-group &:last-child:not(:first-child),
.@{btn-prefix-cls}-group & + & {
border-left-color: @btn-group-border;
&[disabled] {
border-left-color: @btn-default-border;
}
}
}
&-ghost {
.btn-ghost();
}
&-dashed {
.btn-dashed();
}
// type="danger" will deprecated
// use danger instead
&-danger {
.btn-danger();
}
&-link {
.btn-link();
}
&-text {
.btn-text();
}
&-dangerous {
.btn-danger-default();
}
&-dangerous&-primary {
.btn-danger();
}
&-dangerous&-link {
.btn-danger-link();
}
&-dangerous&-text {
.btn-danger-text();
}
&-icon-only {
.btn-square(@btn-prefix-cls);
vertical-align: -3px;
> .@{iconfont-css-prefix} {
display: flex;
justify-content: center;
}
}
// https://github.com/ant-design/ant-design/issues/32365
a&-icon-only {
vertical-align: -1px;
> .@{iconfont-css-prefix} {
display: inline;
}
}
&-round {
.btn-round(@btn-prefix-cls);
&.@{btn-prefix-cls}-icon-only {
width: auto;
}
}
&-circle {
.btn-circle(@btn-prefix-cls);
}
&::before {
position: absolute;
top: -@btn-border-width;
right: -@btn-border-width;
bottom: -@btn-border-width;
left: -@btn-border-width;
z-index: 1;
display: none;
background: @component-background;
border-radius: inherit;
opacity: 0.35;
transition: opacity 0.2s;
content: '';
pointer-events: none;
}
.@{iconfont-css-prefix} {
transition: margin-left 0.3s @ease-in-out;
// Follow icon blur under windows. Change the render.
// https://github.com/ant-design/ant-design/issues/13924
&.@{iconfont-css-prefix}-plus,
&.@{iconfont-css-prefix}-minus {
> svg {
shape-rendering: optimizespeed;
}
}
}
&&-loading {
position: relative;
cursor: default;
&::before {
display: block;
}
}
& > &-loading-icon {
transition: width 0.3s @ease-in-out, opacity 0.3s @ease-in-out;
.@{iconfont-css-prefix} {
padding-right: @padding-xs;
animation: none;
// for smooth button padding transition
svg {
animation: loadingCircle 1s infinite linear;
}
}
&:only-child {
.@{iconfont-css-prefix} {
padding-right: 0;
}
}
}
&-group {
.btn-group(@btn-prefix-cls);
}
// http://stackoverflow.com/a/21281554/3040605
&:focus > span,
&:active > span {
position: relative;
}
// To ensure that a space will be placed between character and `Icon`.
> .@{iconfont-css-prefix} + span,
> span + .@{iconfont-css-prefix} {
margin-left: @margin-xs;
}
&&-background-ghost {
color: @btn-default-ghost-color;
border-color: @btn-default-ghost-border;
&,
&:hover,
&:active,
&:focus {
background: @btn-default-ghost-bg;
}
&:hover,
&:focus {
color: @primary-color-hover;
border-color: @primary-color-hover;
}
&:active {
color: @primary-color-active;
border-color: @primary-color-active;
}
&[disabled] {
color: @disabled-color;
background: @btn-default-ghost-bg;
border-color: @btn-default-border;
}
}
&-background-ghost&-primary {
.button-variant-ghost(@btn-primary-bg, @btn-primary-bg, @primary-color-hover, @primary-color-active);
}
&-background-ghost&-danger {
.button-variant-ghost(@btn-danger-border, @btn-danger-border, @error-color-hover, @error-color-active);
}
&-background-ghost&-dangerous {
.button-variant-ghost(@btn-danger-border, @btn-danger-border, @error-color-hover, @error-color-active);
}
&-background-ghost&-dangerous&-link {
.button-variant-ghost(@btn-danger-border, transparent, @error-color-hover, @error-color-active);
}
&-two-chinese-chars::first-letter {
letter-spacing: 0.34em;
}
&-two-chinese-chars > *:not(.@{iconfont-css-prefix}) {
margin-right: -0.34em;
letter-spacing: 0.34em;
}
&&-block {
width: 100%;
}
// https://github.com/ant-design/ant-design/issues/12681
// same method as Select
&:empty {
display: inline-block;
width: 0;
visibility: hidden;
content: '\a0';
}
}
a.@{btn-prefix-cls} {
// Fixing https://github.com/ant-design/ant-design/issues/12978
// https://github.com/ant-design/ant-design/issues/29978
// It is a render problem of chrome, which is only happened in the codesandbox demo
// 0.1px for padding-top solution works and I don't why
padding-top: 0.01px !important;
line-height: @btn-height-base - 2px;
&-lg {
line-height: @btn-height-lg - 2px;
}
&-sm {
line-height: @btn-height-sm - 2px;
}
}
@import './rtl';

View File

@ -0,0 +1,526 @@
import type { CSSInterpolation, CSSObject } from '../../_util/cssinjs';
import type { FullToken, GenerateStyle } from '../../theme/internal';
import { genComponentStyleHook, mergeToken } from '../../theme/internal';
import genGroupStyle from './group';
import { genFocusStyle } from '../../_style';
import { genCompactItemStyle } from '../../_style/compact-item';
import { genCompactItemVerticalStyle } from '../../_style/compact-item-vertical';
/** Component only token. Which will handle additional calculation of alias token */
export interface ComponentToken {}
export interface ButtonToken extends FullToken<'Button'> {
// FIXME: should be removed
colorOutlineDefault: string;
buttonPaddingHorizontal: number;
}
// ============================== Shared ==============================
const genSharedButtonStyle: GenerateStyle<ButtonToken, CSSObject> = (token): CSSObject => {
const { componentCls, iconCls } = token;
return {
[componentCls]: {
outline: 'none',
position: 'relative',
display: 'inline-block',
fontWeight: 400,
whiteSpace: 'nowrap',
textAlign: 'center',
backgroundImage: 'none',
backgroundColor: 'transparent',
border: `${token.lineWidth}px ${token.lineType} transparent`,
cursor: 'pointer',
transition: `all ${token.motionDurationMid} ${token.motionEaseInOut}`,
userSelect: 'none',
touchAction: 'manipulation',
lineHeight: token.lineHeight,
color: token.colorText,
'> span': {
display: 'inline-block',
},
// Leave a space between icon and text.
[`> ${iconCls} + span, > span + ${iconCls}`]: {
marginInlineStart: token.marginXS,
},
'> a': {
color: 'currentColor',
},
'&:not(:disabled)': {
...genFocusStyle(token),
},
// make `btn-icon-only` not too narrow
[`&-icon-only${componentCls}-compact-item`]: {
flex: 'none',
},
// Special styles for Primary Button
[`&-compact-item${componentCls}-primary`]: {
[`&:not([disabled]) + ${componentCls}-compact-item${componentCls}-primary:not([disabled])`]:
{
position: 'relative',
'&:before': {
position: 'absolute',
top: -token.lineWidth,
insetInlineStart: -token.lineWidth,
display: 'inline-block',
width: token.lineWidth,
height: `calc(100% + ${token.lineWidth * 2}px)`,
backgroundColor: token.colorPrimaryHover,
content: '""',
},
},
},
// Special styles for Primary Button
'&-compact-vertical-item': {
[`&${componentCls}-primary`]: {
[`&:not([disabled]) + ${componentCls}-compact-vertical-item${componentCls}-primary:not([disabled])`]:
{
position: 'relative',
'&:before': {
position: 'absolute',
top: -token.lineWidth,
insetInlineStart: -token.lineWidth,
display: 'inline-block',
width: `calc(100% + ${token.lineWidth * 2}px)`,
height: token.lineWidth,
backgroundColor: token.colorPrimaryHover,
content: '""',
},
},
},
},
},
};
};
const genHoverActiveButtonStyle = (hoverStyle: CSSObject, activeStyle: CSSObject): CSSObject => ({
'&:not(:disabled)': {
'&:hover': hoverStyle,
'&:active': activeStyle,
},
});
// ============================== Shape ===============================
const genCircleButtonStyle: GenerateStyle<ButtonToken, CSSObject> = token => ({
minWidth: token.controlHeight,
paddingInlineStart: 0,
paddingInlineEnd: 0,
borderRadius: '50%',
});
const genRoundButtonStyle: GenerateStyle<ButtonToken, CSSObject> = token => ({
borderRadius: token.controlHeight,
paddingInlineStart: token.controlHeight / 2,
paddingInlineEnd: token.controlHeight / 2,
});
// =============================== Type ===============================
const genDisabledStyle: GenerateStyle<ButtonToken, CSSObject> = token => ({
cursor: 'not-allowed',
borderColor: token.colorBorder,
color: token.colorTextDisabled,
backgroundColor: token.colorBgContainerDisabled,
boxShadow: 'none',
});
const genGhostButtonStyle = (
btnCls: string,
textColor: string | false,
borderColor: string | false,
textColorDisabled: string | false,
borderColorDisabled: string | false,
hoverStyle?: CSSObject,
activeStyle?: CSSObject,
): CSSObject => ({
[`&${btnCls}-background-ghost`]: {
color: textColor || undefined,
backgroundColor: 'transparent',
borderColor: borderColor || undefined,
boxShadow: 'none',
...genHoverActiveButtonStyle(
{
backgroundColor: 'transparent',
...hoverStyle,
},
{
backgroundColor: 'transparent',
...activeStyle,
},
),
'&:disabled': {
cursor: 'not-allowed',
color: textColorDisabled || undefined,
borderColor: borderColorDisabled || undefined,
},
},
});
const genSolidDisabledButtonStyle: GenerateStyle<ButtonToken, CSSObject> = token => ({
'&:disabled': {
...genDisabledStyle(token),
},
});
const genSolidButtonStyle: GenerateStyle<ButtonToken, CSSObject> = token => ({
...genSolidDisabledButtonStyle(token),
});
const genPureDisabledButtonStyle: GenerateStyle<ButtonToken, CSSObject> = token => ({
'&:disabled': {
cursor: 'not-allowed',
color: token.colorTextDisabled,
},
});
// Type: Default
const genDefaultButtonStyle: GenerateStyle<ButtonToken, CSSObject> = token => ({
...genSolidButtonStyle(token),
backgroundColor: token.colorBgContainer,
borderColor: token.colorBorder,
boxShadow: `0 ${token.controlOutlineWidth}px 0 ${token.controlTmpOutline}`,
...genHoverActiveButtonStyle(
{
color: token.colorPrimaryHover,
borderColor: token.colorPrimaryHover,
},
{
color: token.colorPrimaryActive,
borderColor: token.colorPrimaryActive,
},
),
...genGhostButtonStyle(
token.componentCls,
token.colorBgContainer,
token.colorBgContainer,
token.colorTextDisabled,
token.colorBorder,
),
[`&${token.componentCls}-dangerous`]: {
color: token.colorError,
borderColor: token.colorError,
...genHoverActiveButtonStyle(
{
color: token.colorErrorHover,
borderColor: token.colorErrorBorderHover,
},
{
color: token.colorErrorActive,
borderColor: token.colorErrorActive,
},
),
...genGhostButtonStyle(
token.componentCls,
token.colorError,
token.colorError,
token.colorTextDisabled,
token.colorBorder,
),
...genSolidDisabledButtonStyle(token),
},
});
// Type: Primary
const genPrimaryButtonStyle: GenerateStyle<ButtonToken, CSSObject> = token => ({
...genSolidButtonStyle(token),
color: token.colorTextLightSolid,
backgroundColor: token.colorPrimary,
boxShadow: `0 ${token.controlOutlineWidth}px 0 ${token.controlOutline}`,
...genHoverActiveButtonStyle(
{
color: token.colorTextLightSolid,
backgroundColor: token.colorPrimaryHover,
},
{
color: token.colorTextLightSolid,
backgroundColor: token.colorPrimaryActive,
},
),
...genGhostButtonStyle(
token.componentCls,
token.colorPrimary,
token.colorPrimary,
token.colorTextDisabled,
token.colorBorder,
{
color: token.colorPrimaryHover,
borderColor: token.colorPrimaryHover,
},
{
color: token.colorPrimaryActive,
borderColor: token.colorPrimaryActive,
},
),
[`&${token.componentCls}-dangerous`]: {
backgroundColor: token.colorError,
boxShadow: `0 ${token.controlOutlineWidth}px 0 ${token.colorErrorOutline}`,
...genHoverActiveButtonStyle(
{
backgroundColor: token.colorErrorHover,
},
{
backgroundColor: token.colorErrorActive,
},
),
...genGhostButtonStyle(
token.componentCls,
token.colorError,
token.colorError,
token.colorTextDisabled,
token.colorBorder,
{
color: token.colorErrorHover,
borderColor: token.colorErrorHover,
},
{
color: token.colorErrorActive,
borderColor: token.colorErrorActive,
},
),
...genSolidDisabledButtonStyle(token),
},
});
// Type: Dashed
const genDashedButtonStyle: GenerateStyle<ButtonToken, CSSObject> = token => ({
...genDefaultButtonStyle(token),
borderStyle: 'dashed',
});
// Type: Link
const genLinkButtonStyle: GenerateStyle<ButtonToken, CSSObject> = token => ({
color: token.colorLink,
...genHoverActiveButtonStyle(
{
color: token.colorLinkHover,
},
{
color: token.colorLinkActive,
},
),
...genPureDisabledButtonStyle(token),
[`&${token.componentCls}-dangerous`]: {
color: token.colorError,
...genHoverActiveButtonStyle(
{
color: token.colorErrorHover,
},
{
color: token.colorErrorActive,
},
),
...genPureDisabledButtonStyle(token),
},
});
// Type: Text
const genTextButtonStyle: GenerateStyle<ButtonToken, CSSObject> = token => ({
...genHoverActiveButtonStyle(
{
color: token.colorText,
backgroundColor: token.colorBgTextHover,
},
{
color: token.colorText,
backgroundColor: token.colorBgTextActive,
},
),
...genPureDisabledButtonStyle(token),
[`&${token.componentCls}-dangerous`]: {
color: token.colorError,
...genPureDisabledButtonStyle(token),
...genHoverActiveButtonStyle(
{
color: token.colorErrorHover,
backgroundColor: token.colorErrorBg,
},
{
color: token.colorErrorHover,
backgroundColor: token.colorErrorBg,
},
),
},
});
// Href and Disabled
const genDisabledButtonStyle: GenerateStyle<ButtonToken, CSSObject> = token => ({
...genDisabledStyle(token),
[`&${token.componentCls}:hover`]: {
...genDisabledStyle(token),
},
});
const genTypeButtonStyle: GenerateStyle<ButtonToken> = token => {
const { componentCls } = token;
return {
[`${componentCls}-default`]: genDefaultButtonStyle(token),
[`${componentCls}-primary`]: genPrimaryButtonStyle(token),
[`${componentCls}-dashed`]: genDashedButtonStyle(token),
[`${componentCls}-link`]: genLinkButtonStyle(token),
[`${componentCls}-text`]: genTextButtonStyle(token),
[`${componentCls}-disabled`]: genDisabledButtonStyle(token),
};
};
// =============================== Size ===============================
const genSizeButtonStyle = (token: ButtonToken, sizePrefixCls: string = ''): CSSInterpolation => {
const {
componentCls,
iconCls,
controlHeight,
fontSize,
lineHeight,
lineWidth,
borderRadius,
buttonPaddingHorizontal,
} = token;
const paddingVertical = Math.max(0, (controlHeight - fontSize * lineHeight) / 2 - lineWidth);
const paddingHorizontal = buttonPaddingHorizontal - lineWidth;
const iconOnlyCls = `${componentCls}-icon-only`;
return [
// Size
{
[`${componentCls}${sizePrefixCls}`]: {
fontSize,
height: controlHeight,
padding: `${paddingVertical}px ${paddingHorizontal}px`,
borderRadius,
[`&${iconOnlyCls}`]: {
width: controlHeight,
paddingInlineStart: 0,
paddingInlineEnd: 0,
[`&${componentCls}-round`]: {
width: 'auto',
},
'> span': {
transform: 'scale(1.143)', // 14px -> 16px
},
},
// Loading
[`&${componentCls}-loading`]: {
opacity: token.opacityLoading,
cursor: 'default',
},
[`${componentCls}-loading-icon`]: {
transition: `width ${token.motionDurationSlow} ${token.motionEaseInOut}, opacity ${token.motionDurationSlow} ${token.motionEaseInOut}`,
},
[`&:not(${iconOnlyCls}) ${componentCls}-loading-icon > ${iconCls}`]: {
marginInlineEnd: token.marginXS,
},
},
},
// Shape - patch prefixCls again to override solid border radius style
{
[`${componentCls}${componentCls}-circle${sizePrefixCls}`]: genCircleButtonStyle(token),
},
{
[`${componentCls}${componentCls}-round${sizePrefixCls}`]: genRoundButtonStyle(token),
},
];
};
const genSizeBaseButtonStyle: GenerateStyle<ButtonToken> = token => genSizeButtonStyle(token);
const genSizeSmallButtonStyle: GenerateStyle<ButtonToken> = token => {
const smallToken = mergeToken<ButtonToken>(token, {
controlHeight: token.controlHeightSM,
padding: token.paddingXS,
buttonPaddingHorizontal: 8, // Fixed padding
borderRadius: token.borderRadiusSM,
});
return genSizeButtonStyle(smallToken, `${token.componentCls}-sm`);
};
const genSizeLargeButtonStyle: GenerateStyle<ButtonToken> = token => {
const largeToken = mergeToken<ButtonToken>(token, {
controlHeight: token.controlHeightLG,
fontSize: token.fontSizeLG,
borderRadius: token.borderRadiusLG,
});
return genSizeButtonStyle(largeToken, `${token.componentCls}-lg`);
};
const genBlockButtonStyle: GenerateStyle<ButtonToken> = token => {
const { componentCls } = token;
return {
[componentCls]: {
[`&${componentCls}-block`]: {
width: '100%',
},
},
};
};
// ============================== Export ==============================
export default genComponentStyleHook('Button', token => {
const { controlTmpOutline, paddingContentHorizontal } = token;
const buttonToken = mergeToken<ButtonToken>(token, {
colorOutlineDefault: controlTmpOutline,
buttonPaddingHorizontal: paddingContentHorizontal,
});
return [
// Shared
genSharedButtonStyle(buttonToken),
// Size
genSizeSmallButtonStyle(buttonToken),
genSizeBaseButtonStyle(buttonToken),
genSizeLargeButtonStyle(buttonToken),
// Block
genBlockButtonStyle(buttonToken),
// Group (type, ghost, danger, disabled, loading)
genTypeButtonStyle(buttonToken),
// Button Group
genGroupStyle(buttonToken),
// Space Compact
genCompactItemStyle(token, { focus: false }),
genCompactItemVerticalStyle(token),
];
});

View File

@ -1,2 +0,0 @@
import '../../style/index.less';
import './index.less';

View File

@ -1,571 +0,0 @@
// mixins for button
// ------------------------
.button-size(@height; @padding-horizontal; @font-size; @border-radius) {
@padding-vertical: max(
(round(((@height - @font-size * @line-height-base) / 2) * 10) / 10) - @border-width-base,
0
);
height: @height;
padding: @padding-vertical @padding-horizontal;
font-size: @font-size;
border-radius: @border-radius;
}
.button-color(@color; @background; @border) {
color: @color;
border-color: @border; // a inside Button which only work in Chrome
& when not(@background = null) {
background: @background;
}
// http://stackoverflow.com/a/17253457
> a:only-child {
color: currentcolor;
&::after {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background: transparent;
content: '';
}
}
}
.button-disabled(@color: @btn-disable-color; @background: @btn-disable-bg; @border: @btn-disable-border) {
&[disabled] {
&,
&:hover,
&:focus,
&:active {
.button-color(@color; @background; @border);
text-shadow: none;
box-shadow: none;
}
}
}
.button-variant-primary(@color; @background; @backgroundHover: yellow; @backgroundActive: yellow) {
.button-color(@color; @background; @background);
text-shadow: @btn-text-shadow;
box-shadow: @btn-primary-shadow;
&:hover,
&:focus {
& when (@theme = dark) {
.button-color(
@color; ~`colorPalette('@{background}', 7) `; ~`colorPalette('@{background}', 7) `
);
}
& when (not (@theme = dark) and not (@theme = variable)) {
.button-color(
@color; ~`colorPalette('@{background}', 5) `; ~`colorPalette('@{background}', 5) `
);
}
& when (@theme = variable) {
.button-color(@color; @backgroundHover; @backgroundHover);
}
}
&:active {
& when (@theme = dark) {
.button-color(
@color; ~`colorPalette('@{background}', 5) `; ~`colorPalette('@{background}', 5) `
);
}
& when (not (@theme = dark) and not (@theme = variable)) {
.button-color(
@color; ~`colorPalette('@{background}', 7) `; ~`colorPalette('@{background}', 7) `
);
}
& when (@theme = variable) {
.button-color(@color; @backgroundActive; @backgroundActive);
}
}
.button-disabled();
}
.button-variant-other(@color; @background; @border) {
.button-color(@color; @background; @border);
&:hover,
&:focus {
& when (@theme = dark) {
.button-color(@primary-5; @background; @primary-5);
}
& when (not (@theme = dark) and not (@theme = variable)) {
.button-color(
~`colorPalette('@{btn-primary-bg}', 5) `; @background;
~`colorPalette('@{btn-primary-bg}', 5) `
);
}
& when (@theme = variable) {
.button-color(@primary-color-hover; @background; @primary-color-hover);
}
}
&:active {
& when (@theme = dark) {
.button-color(@primary-7; @background; @primary-7);
}
& when (not (@theme = dark) and not (@theme = variable)) {
.button-color(
~`colorPalette('@{btn-primary-bg}', 7) `; @background;
~`colorPalette('@{btn-primary-bg}', 7) `
);
}
& when (@theme = variable) {
.button-color(@primary-color-active; @background; @primary-color-active);
}
}
.button-disabled();
}
.button-variant-ghost(@color; @border; @borderHover: yellow; @borderActive: yellow) {
.button-color(@color; null; @border);
text-shadow: none;
&:hover,
&:focus {
& when (@border = transparent) {
& when (@theme = dark) {
.button-color(~`colorPalette('@{color}', 7) `; null; transparent);
}
& when (not (@theme = dark) and not (@theme = variable)) {
.button-color(~`colorPalette('@{color}', 5) `; null; transparent);
}
& when (@theme = variable) {
.button-color(@borderActive; transparent; transparent);
}
}
& when not (@border = transparent) {
& when (@theme = dark) {
.button-color(
~`colorPalette('@{color}', 7) `; null; ~`colorPalette('@{color}', 7) `
);
}
& when (not (@theme = dark) and not (@theme = variable)) {
.button-color(
~`colorPalette('@{color}', 5) `; null; ~`colorPalette('@{color}', 5) `
);
}
& when (@theme = variable) {
.button-color(@borderHover; transparent; @borderHover);
}
}
}
&:active {
& when (@border = transparent) {
& when (@theme = dark) {
.button-color(~`colorPalette('@{color}', 5) `; null; transparent);
}
& when (not (@theme = dark) and not (@theme = variable)) {
.button-color(~`colorPalette('@{color}', 7) `; null; transparent);
}
& when (@theme = variable) {
.button-color(@borderActive; transparent; transparent);
}
}
& when not (@border = transparent) {
& when (@theme = dark) {
.button-color(
~`colorPalette('@{color}', 5) `; null; ~`colorPalette('@{color}', 5) `
);
}
& when (not (@theme = dark) and not (@theme = variable)) {
.button-color(
~`colorPalette('@{color}', 7) `; null; ~`colorPalette('@{color}', 7) `
);
}
& when (@theme = variable) {
.button-color(@borderActive; transparent; @borderActive);
}
}
}
.button-disabled();
}
.button-group-base(@btnClassName) {
position: relative;
display: inline-flex;
> .@{btnClassName},
> span > .@{btnClassName} {
position: relative;
&:hover,
&:focus,
&:active {
z-index: 2;
}
&[disabled] {
z-index: 0;
}
}
.@{btnClassName}-icon-only {
font-size: @font-size-base;
}
}
// Base styles of buttons
// --------------------------------------------------
.btn() {
position: relative;
display: inline-block;
font-weight: @btn-font-weight;
white-space: nowrap;
text-align: center;
background-image: none;
border: @btn-border-width @btn-border-style transparent;
box-shadow: @btn-shadow;
cursor: pointer;
transition: all 0.3s @ease-in-out;
user-select: none;
touch-action: manipulation;
.button-size(
@btn-height-base; @btn-padding-horizontal-base; @font-size-base; @btn-border-radius-base
);
> .@{iconfont-css-prefix} {
line-height: 1;
}
&,
&:active,
&:focus {
outline: 0;
}
&:not([disabled]):hover {
text-decoration: none;
}
&:not([disabled]):active {
outline: 0;
box-shadow: none;
}
&[disabled] {
cursor: not-allowed;
> * {
pointer-events: none;
}
}
&-lg {
.button-size(
@btn-height-lg; @btn-padding-horizontal-lg; @btn-font-size-lg; @btn-border-radius-base
);
}
&-sm {
.button-size(
@btn-height-sm; @btn-padding-horizontal-sm; @btn-font-size-sm; @btn-border-radius-sm
);
}
}
// primary button style
.btn-primary() {
.button-variant-primary(@btn-primary-color; @btn-primary-bg; @primary-color-hover; @primary-color-active);
}
// default button style
.btn-default() {
.button-variant-other(@btn-default-color; @btn-default-bg; @btn-default-border; );
&:hover,
&:focus,
&:active {
text-decoration: none;
background: @btn-default-bg;
}
}
// ghost button style
.btn-ghost() {
.button-variant-other(@btn-ghost-color, @btn-ghost-bg, @btn-ghost-border);
}
// dashed button style
.btn-dashed() {
.button-variant-other(@btn-default-color, @btn-default-bg, @btn-default-border);
border-style: dashed;
}
// danger button style
.btn-danger() {
.button-variant-primary(@btn-danger-color, @btn-danger-bg, @error-color-hover, @error-color-active);
}
// danger default button style
.btn-danger-default() {
.button-color(@error-color, @btn-default-bg, @error-color);
&:hover,
&:focus {
& when (@theme = dark) {
.button-color(
~`colorPalette('@{error-color}', 7) `; @btn-default-bg; ~`colorPalette('@{error-color}', 7)
`
);
}
& when (not (@theme = dark) and not (@theme = variable)) {
.button-color(
~`colorPalette('@{error-color}', 5) `; @btn-default-bg; ~`colorPalette('@{error-color}', 5)
`
);
}
& when (@theme = variable) {
.button-color(@error-color-hover, @btn-default-bg, @error-color-hover);
}
}
&:active {
& when (@theme = dark) {
.button-color(
~`colorPalette('@{error-color}', 5) `; @btn-default-bg; ~`colorPalette('@{error-color}', 5)
`
);
}
& when (not (@theme = dark) and not (@theme = variable)) {
.button-color(
~`colorPalette('@{error-color}', 7) `; @btn-default-bg; ~`colorPalette('@{error-color}', 7)
`
);
}
& when (@theme = variable) {
.button-color(@error-color-active, @btn-default-bg, @error-color-active);
}
}
.button-disabled();
}
// danger link button style
.btn-danger-link() {
.button-variant-other(@error-color, transparent, transparent);
box-shadow: none;
&:hover,
&:focus {
& when (@theme = dark) {
.button-color(~`colorPalette('@{error-color}', 7) `; transparent; transparent);
}
& when (not (@theme = dark) and not (@theme = variable)) {
.button-color(~`colorPalette('@{error-color}', 5) `; transparent; transparent);
}
& when (@theme = variable) {
.button-color(@error-color-hover; transparent; transparent);
}
}
&:active {
& when (@theme = dark) {
.button-color(~`colorPalette('@{error-color}', 5) `; transparent; transparent);
}
& when (not (@theme = dark) and not (@theme = variable)) {
.button-color(~`colorPalette('@{error-color}', 7) `; transparent; transparent);
}
& when (@theme = variable) {
.button-color(@error-color-active; transparent; transparent);
}
}
.button-disabled(@disabled-color; transparent; transparent);
}
// link button style
.btn-link() {
.button-variant-other(@link-color, transparent, transparent);
box-shadow: none;
&:hover {
background: @btn-link-hover-bg;
}
&:hover,
&:focus,
&:active {
border-color: transparent;
}
.button-disabled(@disabled-color; transparent; transparent);
}
// text button style
.btn-text() {
.button-variant-other(@text-color, transparent, transparent);
box-shadow: none;
&:hover,
&:focus {
color: @text-color;
background: @btn-text-hover-bg;
border-color: transparent;
}
&:active {
color: @text-color;
background: fadein(@btn-text-hover-bg, 1%);
border-color: transparent;
}
.button-disabled(@disabled-color; transparent; transparent);
}
.btn-danger-text() {
.button-variant-other(@error-color, transparent, transparent);
box-shadow: none;
&:hover,
&:focus {
& when (@theme = dark) {
.button-color(~`colorPalette('@{error-color}', 7) `; @btn-text-hover-bg; transparent);
}
& when (not (@theme = dark) and not (@theme = variable)) {
.button-color(~`colorPalette('@{error-color}', 5) `; @btn-text-hover-bg; transparent);
}
& when (@theme = variable) {
.button-color(@error-color-hover; @btn-text-hover-bg; transparent);
}
}
&:active {
& when (@theme = dark) {
.button-color(~`colorPalette('@{error-color}', 5) `; fadein(@btn-text-hover-bg, 1%); transparent);
}
& when (not (@theme = dark) and not (@theme = variable)) {
.button-color(~`colorPalette('@{error-color}', 7) `; fadein(@btn-text-hover-bg, 1%); transparent);
}
& when (@theme = variable) {
.button-color(@error-color-active; fadein(@btn-text-hover-bg, 1%); transparent);
}
}
.button-disabled(@disabled-color; transparent; transparent);
}
// round button
.btn-round(@btnClassName: btn) {
.button-size(@btn-circle-size; (@btn-circle-size / 2); @font-size-base; @btn-circle-size);
&.@{btnClassName}-lg {
.button-size(
@btn-circle-size-lg; (@btn-circle-size-lg / 2); @btn-font-size-lg; @btn-circle-size-lg
);
}
&.@{btnClassName}-sm {
.button-size(
@btn-circle-size-sm; (@btn-circle-size-sm / 2); @font-size-base; @btn-circle-size-sm
);
}
}
// square button: the content only contains icon
.btn-square(@btnClassName: btn) {
.square(@btn-square-size);
.button-size(@btn-square-size; 0; @btn-square-only-icon-size; @btn-border-radius-base);
& > * {
font-size: @btn-square-only-icon-size;
}
&.@{btnClassName}-lg {
.square(@btn-square-size-lg);
.button-size(@btn-square-size-lg; 0; @btn-square-only-icon-size-lg; @btn-border-radius-base);
& > * {
font-size: @btn-square-only-icon-size-lg;
}
}
&.@{btnClassName}-sm {
.square(@btn-square-size-sm);
.button-size(@btn-square-size-sm; 0; @btn-square-only-icon-size-sm; @btn-border-radius-base);
& > * {
font-size: @btn-square-only-icon-size-sm;
}
}
}
// circle button: the content only contains icon
.btn-circle(@btnClassName: btn) {
min-width: @btn-height-base;
padding-right: 0;
padding-left: 0;
text-align: center;
border-radius: 50%;
&.@{btnClassName}-lg {
min-width: @btn-height-lg;
border-radius: 50%;
}
&.@{btnClassName}-sm {
min-width: @btn-height-sm;
border-radius: 50%;
}
}
// Horizontal button groups style
// --------------------------------------------------
.btn-group(@btnClassName: btn) {
.button-group-base(@btnClassName);
.@{btnClassName} + .@{btnClassName},
.@{btnClassName} + &,
span + .@{btnClassName},
.@{btnClassName} + span,
> span + span,
& + .@{btnClassName},
& + & {
margin-left: -1px;
}
.@{btnClassName}-primary + .@{btnClassName}:not(.@{btnClassName}-primary):not([disabled]) {
border-left-color: transparent;
}
.@{btnClassName} {
border-radius: 0;
}
> .@{btnClassName}:first-child,
> span:first-child > .@{btnClassName} {
margin-left: 0;
}
> .@{btnClassName}:only-child {
border-radius: @btn-border-radius-base;
}
> span:only-child > .@{btnClassName} {
border-radius: @btn-border-radius-base;
}
> .@{btnClassName}:first-child:not(:last-child),
> span:first-child:not(:last-child) > .@{btnClassName} {
border-top-left-radius: @btn-border-radius-base;
border-bottom-left-radius: @btn-border-radius-base;
}
> .@{btnClassName}:last-child:not(:first-child),
> span:last-child:not(:first-child) > .@{btnClassName} {
border-top-right-radius: @btn-border-radius-base;
border-bottom-right-radius: @btn-border-radius-base;
}
&-sm {
> .@{btnClassName}:only-child {
border-radius: @btn-border-radius-sm;
}
> span:only-child > .@{btnClassName} {
border-radius: @btn-border-radius-sm;
}
> .@{btnClassName}:first-child:not(:last-child),
> span:first-child:not(:last-child) > .@{btnClassName} {
border-top-left-radius: @btn-border-radius-sm;
border-bottom-left-radius: @btn-border-radius-sm;
}
> .@{btnClassName}:last-child:not(:first-child),
> span:last-child:not(:first-child) > .@{btnClassName} {
border-top-right-radius: @btn-border-radius-sm;
border-bottom-right-radius: @btn-border-radius-sm;
}
}
& > & {
float: left;
}
& > &:not(:first-child):not(:last-child) > .@{btnClassName} {
border-radius: 0;
}
& > &:first-child:not(:last-child) {
> .@{btnClassName}:last-child {
padding-right: 8px;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
}
& > &:last-child:not(:first-child) > .@{btnClassName}:first-child {
padding-left: 8px;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
}

View File

@ -1,97 +0,0 @@
.@{btn-prefix-cls} {
&-rtl {
direction: rtl;
}
&-primary {
.@{btn-prefix-cls}-group &:last-child:not(:first-child),
.@{btn-prefix-cls}-group & + & {
.@{btn-prefix-cls}-group-rtl& {
border-right-color: @btn-group-border;
border-left-color: @btn-default-border;
}
&[disabled] {
.@{btn-prefix-cls}-group-rtl& {
border-right-color: @btn-default-border;
border-left-color: @btn-group-border;
}
}
}
}
& > &-loading-icon {
.@{iconfont-css-prefix} {
.@{btn-prefix-cls}-rtl& {
padding-right: 0;
padding-left: @margin-xs;
}
}
&:only-child {
.@{iconfont-css-prefix} {
padding-right: 0;
padding-left: 0;
}
}
}
> .@{iconfont-css-prefix} + span,
> span + .@{iconfont-css-prefix} {
.@{btn-prefix-cls}-rtl& {
margin-right: 8px;
margin-left: 0;
}
}
}
// mixin
.btn-group(@btnClassName: btn) {
.@{btnClassName} + .@{btnClassName},
.@{btnClassName} + &,
span + .@{btnClassName},
.@{btnClassName} + span,
> span + span,
& + .@{btnClassName},
& + & {
.@{btnClassName}-rtl&,
.@{btnClassName}-group-rtl& {
margin-right: -1px;
margin-left: auto;
}
}
&.@{btnClassName}-group-rtl {
direction: rtl;
}
> .@{btnClassName}:first-child:not(:last-child),
> span:first-child:not(:last-child) > .@{btnClassName} {
.@{btnClassName}-group-rtl& {
border-radius: 0 @btn-border-radius-base @btn-border-radius-base 0;
}
}
> .@{btnClassName}:last-child:not(:first-child),
> span:last-child:not(:first-child) > .@{btnClassName} {
.@{btnClassName}-group-rtl& {
border-radius: @btn-border-radius-base 0 0 @btn-border-radius-base;
}
}
&-sm {
> .@{btnClassName}:first-child:not(:last-child),
> span:first-child:not(:last-child) > .@{btnClassName} {
.@{btnClassName}-group-rtl& {
border-radius: 0 @btn-border-radius-sm @btn-border-radius-sm 0;
}
}
> .@{btnClassName}:last-child:not(:first-child),
> span:last-child:not(:first-child) > .@{btnClassName} {
.@{btnClassName}-group-rtl& {
border-radius: @btn-border-radius-sm 0 0 @btn-border-radius-sm;
}
}
}
}

View File

@ -1,4 +1,4 @@
import './button/style';
// import './button/style';
import './icon/style';
import './radio/style';
import './checkbox/style';

View File

@ -2,7 +2,7 @@ import type { ComponentToken as AlertComponentToken } from '../../alert/style';
import type { ComponentToken as AnchorComponentToken } from '../../anchor/style';
import type { ComponentToken as AvatarComponentToken } from '../../avatar/style';
import type { ComponentToken as BackTopComponentToken } from '../../back-top/style';
// import type { ComponentToken as ButtonComponentToken } from '../../button/style';
import type { ComponentToken as ButtonComponentToken } from '../../button/style';
// import type { ComponentToken as FloatButtonComponentToken } from '../../float-button/style';
// import type { ComponentToken as CalendarComponentToken } from '../../calendar/style';
// import type { ComponentToken as CardComponentToken } from '../../card/style';
@ -57,7 +57,7 @@ export interface ComponentTokenMap {
Avatar?: AvatarComponentToken;
BackTop?: BackTopComponentToken;
Badge?: {};
// Button?: ButtonComponentToken;
Button?: ButtonComponentToken;
Breadcrumb?: {};
// Card?: CardComponentToken;
// Carousel?: CarouselComponentToken;