ant-design/components/badge/style/index.tsx

357 lines
12 KiB
TypeScript
Raw Normal View History

// deps-lint-skip-all
2022-05-09 22:20:07 +08:00
import type { CSSObject } from '@ant-design/cssinjs';
import { Keyframes } from '@ant-design/cssinjs';
import type { GenerateStyle, PresetColorType, FullToken } from '../../_util/theme';
import { resetComponent, PresetColors, genComponentStyleHook, mergeToken } from '../../_util/theme';
interface BadgeToken extends FullToken<'Badge'> {
2022-06-01 21:47:44 +08:00
badgeFontHeight: number;
badgeZIndex: number | string;
badgeHeight: number;
badgeHeightSm: number;
badgeTextColor: string;
badgeFontWeight: string;
badgeFontSize: number;
badgeColor: string;
badgeDotSize: number;
badgeFontSizeSm: number;
badgeStatusSize: number;
2022-06-01 21:47:44 +08:00
badgeShadowSize: number;
badgeProcessingDuration: string;
badgeRibbbonOffset: number;
badgeRibbbonCornerTransform: string;
badgeRibbbonCornerFilter: string;
}
const antStatusProcessing = new Keyframes('antStatusProcessing', {
'0%': { transform: 'scale(0.8)', opacity: 0.5 },
'100%': { transform: 'scale(2.4)', opacity: 0 },
});
const antZoomBadgeIn = new Keyframes('antZoomBadgeIn', {
'0%': { transform: 'scale(0) translate(50%, -50%)', opacity: 0 },
'100%': { transform: 'scale(1) translate(50%, -50%)' },
});
const antZoomBadgeOut = new Keyframes('antZoomBadgeOut', {
'0%': { transform: 'scale(1) translate(50%, -50%)' },
'100%': { transform: 'scale(0) translate(50%, -50%)', opacity: 0 },
});
const antNoWrapperZoomBadgeIn = new Keyframes('antNoWrapperZoomBadgeIn', {
'0%': { transform: 'scale(0)', opacity: 0 },
'100%': { transform: 'scale(1)' },
});
const antNoWrapperZoomBadgeOut = new Keyframes('antNoWrapperZoomBadgeOut', {
'0%': { transform: 'scale(1)' },
'100%': { transform: 'scale(0)', opacity: 0 },
});
const antBadgeLoadingCircle = new Keyframes('antBadgeLoadingCircle', {
'0%': { transformOrigin: '50%' },
'100%': {
transform: 'translate(50%, -50%) rotate(360deg)',
transformOrigin: '50%',
},
});
const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (token: BadgeToken): CSSObject => {
2022-06-01 21:47:44 +08:00
const {
componentCls,
iconCls,
antCls,
badgeFontHeight,
badgeShadowSize,
badgeHeightSm,
motionDurationSlow,
badgeStatusSize,
marginXS,
badgeRibbbonOffset,
} = token;
const numberPrefixCls = `${antCls}-scroll-number`;
const ribbonPrefixCls = `${antCls}-ribbon`;
const ribbonWrapperPrefixCls = `${antCls}-ribbon-wrapper`;
const statusPreset = PresetColors.reduce((prev: CSSObject, colorKey: keyof PresetColorType) => {
const darkColor = token[`${colorKey}-6`];
return {
...prev,
[`${componentCls}-status-${colorKey}`]: {
background: darkColor,
},
};
}, {} as CSSObject);
const statusRibbonPreset = PresetColors.reduce(
(prev: CSSObject, colorKey: keyof PresetColorType) => {
const darkColor = token[`${colorKey}-6`];
return {
...prev,
[`&${ribbonPrefixCls}-color-${colorKey}`]: {
background: darkColor,
color: darkColor,
},
};
},
{} as CSSObject,
);
return {
[componentCls]: {
...resetComponent(token),
position: 'relative',
display: 'inline-block',
lineHeight: 1,
[`${componentCls}-count`]: {
zIndex: token.badgeZIndex,
minWidth: token.badgeHeight,
height: token.badgeHeight,
color: token.badgeTextColor,
fontWeight: token.badgeFontWeight,
fontSize: token.badgeFontSize,
lineHeight: `${token.badgeHeight}px`,
whiteSpace: 'nowrap',
textAlign: 'center',
background: token.badgeColor,
borderRadius: token.badgeHeight / 2,
2022-06-01 21:47:44 +08:00
boxShadow: `0 0 0 ${badgeShadowSize}px ${token.colorBgComponent}`,
a: {
color: token.badgeTextColor,
},
'a:hover': {
color: token.badgeTextColor,
},
},
[`${componentCls}-count-sm`]: {
2022-06-01 21:47:44 +08:00
minWidth: badgeHeightSm,
height: badgeHeightSm,
fontSize: token.badgeFontSizeSm,
2022-06-01 21:47:44 +08:00
lineHeight: `${badgeHeightSm}px`,
borderRadius: badgeHeightSm / 2,
},
[`${componentCls}-multiple-words`]: {
padding: `0 ${token.paddingXS}px`,
},
[`${componentCls}-dot`]: {
zIndex: token.badgeZIndex,
width: token.badgeDotSize,
minWidth: token.badgeDotSize,
height: token.badgeDotSize,
background: token.badgeColor,
borderRadius: '100%',
2022-06-01 21:47:44 +08:00
boxShadow: `0 0 0 ${badgeShadowSize}px ${token.colorBgComponent}`,
},
[`${componentCls}-dot${numberPrefixCls}`]: {
2022-06-01 21:47:44 +08:00
transition: `background ${motionDurationSlow}`,
},
[`${componentCls}-count, ${componentCls}-dot, ${numberPrefixCls}-custom-component`]: {
position: 'absolute',
top: 0,
insetInlineEnd: 0,
transform: 'translate(50%, -50%)',
transformOrigin: '100% 0%',
[`${iconCls}-spin`]: {
animationName: antBadgeLoadingCircle,
animationDuration: token.motionDurationFast,
animationIterationCount: 'infinite',
animationTimingFunction: 'linear',
},
},
[`&${componentCls}-status`]: {
lineHeight: 'inherit',
verticalAlign: 'baseline',
[`${componentCls}-status-dot`]: {
position: 'relative',
2022-06-01 21:47:44 +08:00
top: -1, // Magic number, but seems better experience
display: 'inline-block',
2022-06-01 21:47:44 +08:00
width: badgeStatusSize,
height: badgeStatusSize,
verticalAlign: 'middle',
borderRadius: '50%',
},
[`${componentCls}-status-success`]: {
backgroundColor: token.colorSuccess,
},
[`${componentCls}-status-processing`]: {
position: 'relative',
backgroundColor: token.colorPrimary,
'&::after': {
position: 'absolute',
top: 0,
insetInlineStart: 0,
width: '100%',
height: '100%',
2022-06-01 21:47:44 +08:00
border: `${badgeShadowSize}px solid ${token.colorPrimary}`,
borderRadius: '50%',
animationName: antStatusProcessing,
2022-06-01 21:47:44 +08:00
animationDuration: token.badgeProcessingDuration,
animationIterationCount: 'infinite',
animationTimingFunction: 'ease-in-out',
content: '""',
},
},
[`${componentCls}-status-default`]: {
2022-06-01 21:47:44 +08:00
backgroundColor: token.colorPlaceholder,
},
[`${componentCls}-status-error`]: {
backgroundColor: token.colorError,
},
[`${componentCls}-status-warning`]: {
backgroundColor: token.colorWarning,
},
...statusPreset,
[`${componentCls}-status-text`]: {
2022-06-01 21:47:44 +08:00
marginInlineStart: marginXS,
color: token.colorText,
fontSize: token.fontSize,
},
},
[`${componentCls}-zoom-appear, ${componentCls}-zoom-enter`]: {
animationName: antZoomBadgeIn,
animationDuration: token.motionDurationSlow,
animationTimingFunction: token.motionEaseOutBack,
animationFillMode: 'both',
},
[`${componentCls}-zoom-leave`]: {
animationName: antZoomBadgeOut,
animationDuration: token.motionDurationSlow,
animationTimingFunction: token.motionEaseOutBack,
animationFillMode: 'both',
},
[`&${componentCls}-not-a-wrapper`]: {
[`${componentCls}-zoom-appear, ${componentCls}-zoom-enter`]: {
animationName: antNoWrapperZoomBadgeIn,
animationDuration: token.motionDurationSlow,
animationTimingFunction: token.motionEaseOutBack,
},
[`${componentCls}-zoom-leave`]: {
animationName: antNoWrapperZoomBadgeOut,
animationDuration: token.motionDurationSlow,
animationTimingFunction: token.motionEaseOutBack,
},
[`&:not(${componentCls}-status)`]: {
verticalAlign: 'middle',
},
[`${numberPrefixCls}-custom-component, ${componentCls}-count`]: {
transform: 'none',
},
[`${numberPrefixCls}-custom-component, ${numberPrefixCls}`]: {
position: 'relative',
top: 'auto',
display: 'block',
transformOrigin: '50% 50%',
},
},
[`${numberPrefixCls}`]: {
overflow: 'hidden',
direction: 'ltr',
[`${numberPrefixCls}-only`]: {
position: 'relative',
display: 'inline-block',
height: token.badgeHeight,
transition: `all ${token.motionDurationSlow} ${token.motionEaseOutBack}`,
WebkitTransformStyle: 'preserve-3d',
WebkitBackfaceVisibility: 'hidden',
[`> p${numberPrefixCls}-only-unit`]: {
height: token.badgeHeight,
margin: 0,
WebkitTransformStyle: 'preserve-3d',
WebkitBackfaceVisibility: 'hidden',
},
},
[`${numberPrefixCls}-symbol`]: { verticalAlign: 'top' },
},
},
[`${ribbonWrapperPrefixCls}`]: { position: 'relative' },
[`${ribbonPrefixCls}`]: {
...resetComponent(token),
position: 'absolute',
2022-06-01 21:47:44 +08:00
top: marginXS,
height: badgeFontHeight,
padding: `0 ${token.paddingXS}px`,
color: token.badgeTextColor,
2022-06-01 21:47:44 +08:00
lineHeight: `${badgeFontHeight}px`,
whiteSpace: 'nowrap',
backgroundColor: token.colorPrimary,
borderRadius: token.controlRadius,
2022-06-01 21:47:44 +08:00
[`${ribbonPrefixCls}-text`]: { color: token.colorTextLightSolid },
[`${ribbonPrefixCls}-corner`]: {
position: 'absolute',
top: '100%',
2022-06-01 21:47:44 +08:00
width: badgeRibbbonOffset,
height: badgeRibbbonOffset,
color: 'currentcolor',
2022-06-01 21:47:44 +08:00
border: `${badgeRibbbonOffset / 2}px solid`,
transform: token.badgeRibbbonCornerTransform,
transformOrigin: 'top',
2022-06-01 21:47:44 +08:00
filter: token.badgeRibbbonCornerFilter,
},
...statusRibbonPreset,
[`&${ribbonPrefixCls}-placement-end`]: {
2022-06-01 21:47:44 +08:00
insetInlineEnd: -badgeRibbbonOffset,
borderEndEndRadius: 0,
[`${ribbonPrefixCls}-corner`]: {
insetInlineEnd: 0,
borderColor: 'currentcolor transparent transparent currentcolor',
},
},
[`&${ribbonPrefixCls}-placement-start`]: {
2022-06-01 21:47:44 +08:00
insetInlineStart: -badgeRibbbonOffset,
borderEndStartRadius: 0,
[`${ribbonPrefixCls}-corner`]: {
insetInlineStart: 0,
borderColor: 'currentcolor currentcolor transparent transparent',
},
},
},
};
};
// ============================== Export ==============================
export default genComponentStyleHook('Badge', token => {
2022-06-01 21:47:44 +08:00
const { fontSize, lineHeight, fontSizeSM, controlLineWidth, marginXS } = token;
const badgeFontHeight = Math.round(fontSize * lineHeight);
const badgeShadowSize = controlLineWidth;
const badgeZIndex = 'auto';
2022-06-01 21:47:44 +08:00
const badgeHeight = badgeFontHeight - 2 * badgeShadowSize;
const badgeTextColor = token.colorBgComponent;
const badgeFontWeight = 'normal';
2022-06-01 21:47:44 +08:00
const badgeFontSize = fontSizeSM;
const badgeColor = token.colorError;
const badgeHeightSm = fontSize;
const badgeDotSize = fontSizeSM / 2;
const badgeFontSizeSm = fontSizeSM;
const badgeStatusSize = fontSizeSM / 2;
const badgeToken = mergeToken<BadgeToken>(token, {
2022-06-01 21:47:44 +08:00
badgeFontHeight,
badgeShadowSize,
badgeZIndex,
badgeHeight,
badgeTextColor,
badgeFontWeight,
badgeFontSize,
badgeColor,
badgeHeightSm,
badgeDotSize,
badgeFontSizeSm,
badgeStatusSize,
2022-06-01 21:47:44 +08:00
badgeProcessingDuration: '1.2s',
badgeRibbbonOffset: marginXS,
// Follow token just by Design. Not related with token
badgeRibbbonCornerTransform: 'scaleY(0.75)',
badgeRibbbonCornerFilter: `brightness(75%)`,
});
2022-06-01 21:47:44 +08:00
return [genSharedBadgeStyle(badgeToken)];
});