mirror of
https://github.com/ant-design/ant-design.git
synced 2024-11-28 05:05:48 +08:00
5d3bdf4c34
* refactor: refactor badge component with css in js * refactor: refactor ribbon component with css in js * update: update ribbon css * fix review * fix review * fix review
370 lines
12 KiB
TypeScript
370 lines
12 KiB
TypeScript
// deps-lint-skip-all
|
|
import { CSSObject, Keyframes } from '@ant-design/cssinjs';
|
|
import {
|
|
useStyleRegister,
|
|
useToken,
|
|
resetComponent,
|
|
UseComponentStyleResult,
|
|
GenerateStyle,
|
|
PresetColorKeys,
|
|
PresetColorType,
|
|
} from '../../_util/theme';
|
|
import type { DerivativeToken } from '../../_util/theme';
|
|
|
|
interface BadgeToken extends DerivativeToken {
|
|
badgeZIndex: number | string;
|
|
badgeHeight: number;
|
|
badgeHeightSm: number;
|
|
badgeTextColor: string;
|
|
badgeFontWeight: string;
|
|
badgeFontSize: number;
|
|
badgeColor: string;
|
|
badgeDotSize: number;
|
|
badgeFontSizeSm: number;
|
|
badgeStatusSize: number;
|
|
badgePrefixCls: string;
|
|
antPrefix: string;
|
|
iconPrefixCls: 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,
|
|
hashId: string,
|
|
): CSSObject => {
|
|
const { badgePrefixCls, iconPrefixCls, antPrefix } = token;
|
|
const numberPrefixCls = `${antPrefix}-scroll-number`;
|
|
const ribbonPrefixCls = `${antPrefix}-ribbon`;
|
|
const ribbonWrapperPrefixCls = `${antPrefix}-ribbon-wrapper`;
|
|
|
|
// FIXME preset color 后面可能要统一重构
|
|
const statusPreset = PresetColorKeys.reduce(
|
|
(prev: CSSObject, colorKey: keyof PresetColorType) => {
|
|
const darkColor = token[`${colorKey}-6`];
|
|
return {
|
|
...prev,
|
|
[`.${badgePrefixCls}-status-${colorKey}`]: {
|
|
background: darkColor,
|
|
},
|
|
};
|
|
},
|
|
{} as CSSObject,
|
|
);
|
|
const statusRibbonPreset = PresetColorKeys.reduce(
|
|
(prev: CSSObject, colorKey: keyof PresetColorType) => {
|
|
const darkColor = token[`${colorKey}-6`];
|
|
return {
|
|
...prev,
|
|
[`&.${ribbonPrefixCls}-color-${colorKey}`]: {
|
|
background: darkColor,
|
|
color: darkColor,
|
|
},
|
|
};
|
|
},
|
|
{} as CSSObject,
|
|
);
|
|
|
|
return {
|
|
[`.${badgePrefixCls}`]: {
|
|
...resetComponent(token),
|
|
position: 'relative',
|
|
display: 'inline-block',
|
|
lineHeight: 1,
|
|
|
|
[`.${badgePrefixCls}-count`]: {
|
|
zIndex: token.badgeZIndex,
|
|
minWidth: token.badgeHeight,
|
|
height: token.badgeHeight,
|
|
padding: '0 6px', // FIXME: hard code, copied from old less file
|
|
color: token.badgeTextColor,
|
|
fontWeight: token.badgeFontWeight,
|
|
fontSize: token.badgeFontSize,
|
|
lineHeight: `${token.badgeHeight}px`,
|
|
whiteSpace: 'nowrap',
|
|
textAlign: 'center',
|
|
background: token.badgeColor,
|
|
borderRadius: token.badgeHeight / 2,
|
|
boxShadow: `0 0 0 1px ${token.componentBackground}`,
|
|
a: {
|
|
color: token.badgeTextColor,
|
|
},
|
|
'a:hover': {
|
|
color: token.badgeTextColor,
|
|
},
|
|
},
|
|
[`.${badgePrefixCls}-count-sm`]: {
|
|
minWidth: token.badgeHeightSm,
|
|
height: token.badgeHeightSm,
|
|
padding: 0,
|
|
fontSize: token.badgeFontSizeSm,
|
|
lineHeight: `${token.badgeHeightSm}px`,
|
|
borderRadius: token.badgeHeightSm / 2,
|
|
},
|
|
|
|
[`.${badgePrefixCls}-multiple-words`]: {
|
|
padding: `0 ${token.paddingXS}px`,
|
|
},
|
|
|
|
[`.${badgePrefixCls}-dot`]: {
|
|
zIndex: token.badgeZIndex,
|
|
width: token.badgeDotSize,
|
|
minWidth: token.badgeDotSize,
|
|
height: token.badgeDotSize,
|
|
background: token.badgeColor,
|
|
borderRadius: '100%',
|
|
boxShadow: `0 0 0 1px ${token.componentBackground}`,
|
|
},
|
|
[`.${badgePrefixCls}-dot.${numberPrefixCls}`]: {
|
|
transition: 'background 1.5s', // FIXME: hard code, copied from old less file
|
|
},
|
|
[`.${badgePrefixCls}-count, .${badgePrefixCls}-dot, .${numberPrefixCls}-custom-component`]: {
|
|
position: 'absolute',
|
|
top: 0,
|
|
insetInlineEnd: 0,
|
|
transform: 'translate(50%, -50%)',
|
|
transformOrigin: '100% 0%',
|
|
[`.${iconPrefixCls}-spin`]: {
|
|
animation: `${antBadgeLoadingCircle.getName(hashId)} ${
|
|
token.durationFast
|
|
} infinite linear`,
|
|
},
|
|
},
|
|
[`&.${badgePrefixCls}-status`]: {
|
|
lineHeight: 'inherit',
|
|
verticalAlign: 'baseline',
|
|
|
|
[`.${badgePrefixCls}-status-dot`]: {
|
|
position: 'relative',
|
|
top: -1, // FIXME: hard code, copied from old less file
|
|
display: 'inline-block',
|
|
width: token.badgeStatusSize,
|
|
height: token.badgeStatusSize,
|
|
verticalAlign: 'middle',
|
|
borderRadius: '50%',
|
|
},
|
|
|
|
[`.${badgePrefixCls}-status-success`]: {
|
|
backgroundColor: token.successColor,
|
|
},
|
|
[`.${badgePrefixCls}-status-processing`]: {
|
|
position: 'relative',
|
|
backgroundColor: token.primaryColor,
|
|
|
|
'&::after': {
|
|
position: 'absolute',
|
|
top: 0,
|
|
insetInlineStart: 0,
|
|
width: '100%',
|
|
height: '100%',
|
|
border: `1px solid ${token.primaryColor}`,
|
|
borderRadius: '50%',
|
|
animation: `${antStatusProcessing.getName(hashId)} 1.2s infinite ease-in-out`, // FIXME: hard code, copied from old less file
|
|
content: '""',
|
|
},
|
|
},
|
|
[`.${badgePrefixCls}-status-default`]: {
|
|
backgroundColor: '#d9d9d9', // FIXME: @normal-color;
|
|
},
|
|
|
|
[`.${badgePrefixCls}-status-error`]: {
|
|
backgroundColor: token.errorColor,
|
|
},
|
|
|
|
[`.${badgePrefixCls}-status-warning`]: {
|
|
backgroundColor: token.warningColor,
|
|
},
|
|
...statusPreset,
|
|
[`.${badgePrefixCls}-status-text`]: {
|
|
marginInlineStart: token.marginXS,
|
|
color: token.textColor,
|
|
fontSize: token.fontSize,
|
|
},
|
|
},
|
|
[`.${badgePrefixCls}-zoom-appear, .${badgePrefixCls}-zoom-enter`]: {
|
|
animation: `${antZoomBadgeIn.getName(hashId)} ${token.duration} ${token.easeOutBack}`,
|
|
animationFillMode: 'both',
|
|
},
|
|
[`.${badgePrefixCls}-zoom-leave`]: {
|
|
animation: `${antZoomBadgeOut.getName(hashId)} ${token.duration} ${token.easeOutBack}`,
|
|
animationFillMode: 'both',
|
|
},
|
|
[`&.${badgePrefixCls}-not-a-wrapper`]: {
|
|
[`.${badgePrefixCls}-zoom-appear, .${badgePrefixCls}-zoom-enter`]: {
|
|
animation: `${antNoWrapperZoomBadgeIn.getName(hashId)} ${token.duration} ${
|
|
token.easeOutBack
|
|
}`,
|
|
},
|
|
|
|
[`.${badgePrefixCls}-zoom-leave`]: {
|
|
animation: `${antNoWrapperZoomBadgeOut.getName(hashId)} ${token.duration} ${
|
|
token.easeOutBack
|
|
}`,
|
|
},
|
|
[`&:not(.${badgePrefixCls}-status)`]: {
|
|
verticalAlign: 'middle',
|
|
},
|
|
[`.${numberPrefixCls}-custom-component, .${badgePrefixCls}-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.duration} ${token.easeOutBack}`,
|
|
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',
|
|
top: 8, // FIXME: hard code, copied from old less file
|
|
height: 22, // FIXME: hard code, copied from old less file
|
|
padding: `0 ${token.paddingXS}px`,
|
|
color: token.badgeTextColor,
|
|
lineHeight: '22px', // FIXME: hard code, copied from old less file
|
|
whiteSpace: 'nowrap',
|
|
backgroundColor: token.primaryColor,
|
|
borderRadius: token.borderRadius,
|
|
[`.${ribbonPrefixCls}-text`]: { color: '#fff' },
|
|
[`.${ribbonPrefixCls}-corner`]: {
|
|
position: 'absolute',
|
|
top: '100%',
|
|
width: 8,
|
|
height: 8,
|
|
color: 'currentcolor',
|
|
border: '4px solid', // FIXME: hard code, copied from old less file
|
|
transform: 'scaleY(0.75)', // FIXME: hard code, copied from old less file
|
|
transformOrigin: 'top',
|
|
'&::after': {
|
|
position: 'absolute',
|
|
top: `${-0.5 * token.paddingXS}px`,
|
|
insetInlineStart: `${-0.5 * token.paddingXS}px`,
|
|
width: 'inherit',
|
|
height: 'inherit',
|
|
color: 'rgba(0, 0, 0, 0.25)',
|
|
border: 'inherit',
|
|
content: "''",
|
|
},
|
|
},
|
|
...statusRibbonPreset,
|
|
[`&.${ribbonPrefixCls}-placement-end`]: {
|
|
insetInlineEnd: -1 * token.marginXS,
|
|
borderBottomRightRadius: 0,
|
|
[`.${ribbonPrefixCls}-corner`]: {
|
|
insetInlineEnd: 0,
|
|
borderColor: 'currentcolor transparent transparent currentcolor',
|
|
},
|
|
},
|
|
[`&.${ribbonPrefixCls}-placement-start`]: {
|
|
insetInlineStart: -1 * token.marginXS,
|
|
borderBottomLeftRadius: 0,
|
|
[`.${ribbonPrefixCls}-corner`]: {
|
|
insetInlineStart: 0,
|
|
borderColor: 'currentcolor currentcolor transparent transparent',
|
|
},
|
|
},
|
|
antStatusProcessing,
|
|
antZoomBadgeIn,
|
|
antZoomBadgeOut,
|
|
antNoWrapperZoomBadgeIn,
|
|
antNoWrapperZoomBadgeOut,
|
|
antBadgeLoadingCircle,
|
|
},
|
|
};
|
|
};
|
|
|
|
// ============================== Export ==============================
|
|
export default function useStyle(
|
|
antPrefix: string,
|
|
badgePrefixCls: string,
|
|
iconPrefixCls: string,
|
|
): UseComponentStyleResult {
|
|
const [theme, token, hashId] = useToken();
|
|
|
|
const badgeZIndex = 'auto';
|
|
const badgeHeight = 20; // FIXME: hard code
|
|
const badgeTextColor = token.componentBackground;
|
|
const badgeFontWeight = 'normal';
|
|
const badgeFontSize = token.fontSizeSM;
|
|
const badgeColor = token.highlightColor;
|
|
const badgeHeightSm = 14; // FIXME: hard code
|
|
const badgeDotSize = 6; // FIXME: hard code
|
|
const badgeFontSizeSm = token.fontSizeSM;
|
|
const badgeStatusSize = 6; // FIXME: hard code
|
|
|
|
const badgeToken: BadgeToken = {
|
|
...token,
|
|
badgeZIndex,
|
|
badgeHeight,
|
|
badgeTextColor,
|
|
badgeFontWeight,
|
|
badgeFontSize,
|
|
badgeColor,
|
|
badgeHeightSm,
|
|
badgeDotSize,
|
|
badgeFontSizeSm,
|
|
badgeStatusSize,
|
|
badgePrefixCls,
|
|
antPrefix,
|
|
iconPrefixCls,
|
|
};
|
|
|
|
return [
|
|
useStyleRegister({ theme, token, hashId, path: [badgePrefixCls] }, () => [
|
|
genSharedBadgeStyle(badgeToken, hashId),
|
|
{ display: 'none' },
|
|
]),
|
|
hashId,
|
|
];
|
|
}
|