feat[cssvar]: Avatar & Badge support cssvar (#8327)
parent
2d3f40aa3f
commit
437fdda197
|
@ -12,6 +12,7 @@ import ResizeObserver from '../vc-resize-observer';
|
|||
import eagerComputed from '../_util/eagerComputed';
|
||||
import useStyle from './style';
|
||||
import { useAvatarInjectContext } from './AvatarContext';
|
||||
import useCSSVarCls from '../config-provider/hooks/useCssVarCls';
|
||||
|
||||
export type AvatarSize = 'large' | 'small' | 'default' | number | ScreenSizeMap;
|
||||
|
||||
|
@ -55,7 +56,8 @@ const Avatar = defineComponent({
|
|||
const avatarNodeRef = shallowRef<HTMLElement>(null);
|
||||
|
||||
const { prefixCls } = useConfigInject('avatar', props);
|
||||
const [wrapSSR, hashId] = useStyle(prefixCls);
|
||||
const rootCls = useCSSVarCls(prefixCls);
|
||||
const [wrapSSR, hashId, cssVarCls] = useStyle(prefixCls, rootCls);
|
||||
const avatarCtx = useAvatarInjectContext();
|
||||
const size = computed(() => {
|
||||
return props.size === 'default' ? avatarCtx.size : props.size;
|
||||
|
@ -146,6 +148,8 @@ const Avatar = defineComponent({
|
|||
[`${pre}-${mergeShape}`]: true,
|
||||
[`${pre}-image`]: src && isImgExist.value,
|
||||
[`${pre}-icon`]: icon,
|
||||
[cssVarCls.value]: true,
|
||||
[rootCls.value]: true,
|
||||
[hashId.value]: true,
|
||||
};
|
||||
|
||||
|
@ -175,7 +179,7 @@ const Avatar = defineComponent({
|
|||
} else if (icon) {
|
||||
childrenToRender = icon;
|
||||
} else if (isMounted.value || scale.value !== 1) {
|
||||
const transformString = `scale(${scale.value}) translateX(-50%)`;
|
||||
const transformString = `scale(${scale.value})`;
|
||||
const childrenStyle: CSSProperties = {
|
||||
msTransform: transformString,
|
||||
WebkitTransform: transformString,
|
||||
|
|
|
@ -6,6 +6,7 @@ import type { PropType, ExtractPropTypes, CSSProperties } from 'vue';
|
|||
import { computed, defineComponent, watchEffect } from 'vue';
|
||||
import { flattenChildren, getPropsSlot } from '../_util/props-util';
|
||||
import useConfigInject from '../config-provider/hooks/useConfigInject';
|
||||
import useCSSVarCls from '../config-provider/hooks/useCssVarCls';
|
||||
import useStyle from './style';
|
||||
import { useAvatarProviderContext } from './AvatarContext';
|
||||
|
||||
|
@ -36,7 +37,8 @@ const Group = defineComponent({
|
|||
setup(props, { slots, attrs }) {
|
||||
const { prefixCls, direction } = useConfigInject('avatar', props);
|
||||
const groupPrefixCls = computed(() => `${prefixCls.value}-group`);
|
||||
const [wrapSSR, hashId] = useStyle(prefixCls);
|
||||
const rootCls = useCSSVarCls(prefixCls);
|
||||
const [wrapSSR, hashId, cssVarCls] = useStyle(prefixCls, rootCls);
|
||||
watchEffect(() => {
|
||||
const context = { size: props.size, shape: props.shape };
|
||||
useAvatarProviderContext(context);
|
||||
|
@ -54,6 +56,8 @@ const Group = defineComponent({
|
|||
[groupPrefixCls.value]: true,
|
||||
[`${groupPrefixCls.value}-rtl`]: direction.value === 'rtl',
|
||||
[`${attrs.class}`]: !!attrs.class,
|
||||
[cssVarCls.value]: true,
|
||||
[rootCls.value]: true,
|
||||
[hashId.value]: true,
|
||||
};
|
||||
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
import { unit } from '../../_util/cssinjs';
|
||||
import type { CSSObject } from '../../_util/cssinjs';
|
||||
import type { FullToken, GenerateStyle } from '../../theme/internal';
|
||||
import { genComponentStyleHook, mergeToken } from '../../theme/internal';
|
||||
|
||||
import { resetComponent } from '../../style';
|
||||
import type { FullToken, GenerateStyle, GetDefaultToken } from '../../theme/internal';
|
||||
import { genStyleHooks, mergeToken } from '../../theme/internal';
|
||||
|
||||
export interface ComponentToken {
|
||||
/**
|
||||
* @desc 头像背景色
|
||||
* @descEN Background color of Avatar
|
||||
* @desc 头像尺寸
|
||||
* @descEN Size of Avatar
|
||||
*/
|
||||
containerSize: number;
|
||||
/**
|
||||
|
@ -51,10 +53,14 @@ export interface ComponentToken {
|
|||
groupBorderColor: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @desc Avatar 组件的 Token
|
||||
* @descEN Token for Avatar component
|
||||
*/
|
||||
type AvatarToken = FullToken<'Avatar'> & {
|
||||
avatarBgColor: string;
|
||||
avatarBg: string;
|
||||
avatarColor: string;
|
||||
avatarBgColor: string;
|
||||
};
|
||||
|
||||
const genBaseStyle: GenerateStyle<AvatarToken> = token => {
|
||||
|
@ -81,22 +87,12 @@ const genBaseStyle: GenerateStyle<AvatarToken> = token => {
|
|||
const avatarSizeStyle = (size: number, fontSize: number, radius: number): CSSObject => ({
|
||||
width: size,
|
||||
height: size,
|
||||
lineHeight: `${size - lineWidth * 2}px`,
|
||||
borderRadius: '50%',
|
||||
|
||||
[`&${componentCls}-square`]: {
|
||||
borderRadius: radius,
|
||||
},
|
||||
|
||||
[`${componentCls}-string`]: {
|
||||
position: 'absolute',
|
||||
left: {
|
||||
_skip_check_: true,
|
||||
value: '50%',
|
||||
},
|
||||
transformOrigin: '0 center',
|
||||
},
|
||||
|
||||
[`&${componentCls}-icon`]: {
|
||||
fontSize,
|
||||
[`> ${iconCls}`]: {
|
||||
|
@ -109,16 +105,18 @@ const genBaseStyle: GenerateStyle<AvatarToken> = token => {
|
|||
[componentCls]: {
|
||||
...resetComponent(token),
|
||||
position: 'relative',
|
||||
display: 'inline-block',
|
||||
display: 'inline-flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
overflow: 'hidden',
|
||||
color: avatarColor,
|
||||
whiteSpace: 'nowrap',
|
||||
textAlign: 'center',
|
||||
verticalAlign: 'middle',
|
||||
background: avatarBg,
|
||||
border: `${lineWidth}px ${lineType} transparent`,
|
||||
border: `${unit(lineWidth)} ${lineType} transparent`,
|
||||
|
||||
[`&-image`]: {
|
||||
'&-image': {
|
||||
background: 'transparent',
|
||||
},
|
||||
|
||||
|
@ -128,11 +126,11 @@ const genBaseStyle: GenerateStyle<AvatarToken> = token => {
|
|||
|
||||
...avatarSizeStyle(containerSize, textFontSize, borderRadius),
|
||||
|
||||
[`&-lg`]: {
|
||||
'&-lg': {
|
||||
...avatarSizeStyle(containerSizeLG, textFontSizeLG, borderRadiusLG),
|
||||
},
|
||||
|
||||
[`&-sm`]: {
|
||||
'&-sm': {
|
||||
...avatarSizeStyle(containerSizeSM, textFontSizeSM, borderRadiusSM),
|
||||
},
|
||||
|
||||
|
@ -153,11 +151,11 @@ const genGroupStyle: GenerateStyle<AvatarToken> = token => {
|
|||
[`${componentCls}-group`]: {
|
||||
display: 'inline-flex',
|
||||
|
||||
[`${componentCls}`]: {
|
||||
[componentCls]: {
|
||||
borderColor: groupBorderColor,
|
||||
},
|
||||
|
||||
[`> *:not(:first-child)`]: {
|
||||
'> *:not(:first-child)': {
|
||||
marginInlineStart: groupOverlapping,
|
||||
},
|
||||
},
|
||||
|
@ -169,7 +167,33 @@ const genGroupStyle: GenerateStyle<AvatarToken> = token => {
|
|||
};
|
||||
};
|
||||
|
||||
export default genComponentStyleHook(
|
||||
export const prepareComponentToken: GetDefaultToken<'Avatar'> = token => {
|
||||
const {
|
||||
controlHeight,
|
||||
controlHeightLG,
|
||||
controlHeightSM,
|
||||
fontSize,
|
||||
fontSizeLG,
|
||||
fontSizeXL,
|
||||
fontSizeHeading3,
|
||||
marginXS,
|
||||
marginXXS,
|
||||
colorBorderBg,
|
||||
} = token;
|
||||
return {
|
||||
containerSize: controlHeight,
|
||||
containerSizeLG: controlHeightLG,
|
||||
containerSizeSM: controlHeightSM,
|
||||
textFontSize: Math.round((fontSizeLG + fontSizeXL) / 2),
|
||||
textFontSizeLG: fontSizeHeading3,
|
||||
textFontSizeSM: fontSize,
|
||||
groupSpace: marginXXS,
|
||||
groupOverlapping: -marginXS,
|
||||
groupBorderColor: colorBorderBg,
|
||||
};
|
||||
};
|
||||
|
||||
export default genStyleHooks(
|
||||
'Avatar',
|
||||
token => {
|
||||
const { colorTextLightSolid, colorTextPlaceholder } = token;
|
||||
|
@ -179,33 +203,5 @@ export default genComponentStyleHook(
|
|||
});
|
||||
return [genBaseStyle(avatarToken), genGroupStyle(avatarToken)];
|
||||
},
|
||||
token => {
|
||||
const {
|
||||
controlHeight,
|
||||
controlHeightLG,
|
||||
controlHeightSM,
|
||||
|
||||
fontSize,
|
||||
fontSizeLG,
|
||||
fontSizeXL,
|
||||
fontSizeHeading3,
|
||||
|
||||
marginXS,
|
||||
marginXXS,
|
||||
colorBorderBg,
|
||||
} = token;
|
||||
return {
|
||||
containerSize: controlHeight,
|
||||
containerSizeLG: controlHeightLG,
|
||||
containerSizeSM: controlHeightSM,
|
||||
|
||||
textFontSize: Math.round((fontSizeLG + fontSizeXL) / 2),
|
||||
textFontSizeLG: fontSizeHeading3,
|
||||
textFontSizeSM: fontSize,
|
||||
|
||||
groupSpace: marginXXS,
|
||||
groupOverlapping: -marginXS,
|
||||
groupBorderColor: colorBorderBg,
|
||||
};
|
||||
},
|
||||
prepareComponentToken,
|
||||
);
|
||||
|
|
|
@ -9,6 +9,7 @@ import { defineComponent, computed, ref, watch, Transition } from 'vue';
|
|||
import Ribbon from './Ribbon';
|
||||
import useConfigInject from '../config-provider/hooks/useConfigInject';
|
||||
import isNumeric from '../_util/isNumeric';
|
||||
import useCSSVarCls from '../config-provider/hooks/useCssVarCls';
|
||||
import useStyle from './style';
|
||||
import type { PresetColorKey } from '../theme/interface';
|
||||
import type { LiteralUnion, CustomSlotsType } from '../_util/type';
|
||||
|
@ -49,7 +50,8 @@ export default defineComponent({
|
|||
}>,
|
||||
setup(props, { slots, attrs }) {
|
||||
const { prefixCls, direction } = useConfigInject('badge', props);
|
||||
const [wrapSSR, hashId] = useStyle(prefixCls);
|
||||
const rootCls = useCSSVarCls(prefixCls);
|
||||
const [wrapSSR, hashId, cssVarCls] = useStyle(prefixCls, rootCls);
|
||||
|
||||
// ================================ Misc ================================
|
||||
const numberedDisplayCount = computed(() => {
|
||||
|
@ -189,6 +191,8 @@ export default defineComponent({
|
|||
[`${pre}-rtl`]: direction.value === 'rtl',
|
||||
},
|
||||
attrs.class,
|
||||
cssVarCls.value,
|
||||
rootCls.value,
|
||||
hashId.value,
|
||||
);
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import type { CustomSlotsType, LiteralUnion } from '../_util/type';
|
||||
import type { PresetColorType } from '../_util/colors';
|
||||
import useStyle from './style';
|
||||
import useCSSVarCls from '../config-provider/hooks/useCssVarCls';
|
||||
import useStyle from './style/ribbon';
|
||||
import { isPresetColor } from '../_util/colors';
|
||||
import type { CSSProperties, PropType, ExtractPropTypes } from 'vue';
|
||||
import { defineComponent, computed } from 'vue';
|
||||
|
@ -27,7 +28,8 @@ export default defineComponent({
|
|||
}>,
|
||||
setup(props, { attrs, slots }) {
|
||||
const { prefixCls, direction } = useConfigInject('ribbon', props);
|
||||
const [wrapSSR, hashId] = useStyle(prefixCls);
|
||||
const rootCls = useCSSVarCls(prefixCls);
|
||||
const [wrapSSR, hashId, cssVarCls] = useStyle(prefixCls, rootCls);
|
||||
const colorInPreset = computed(() => isPresetColor(props.color, false));
|
||||
const ribbonCls = computed(() => [
|
||||
prefixCls.value,
|
||||
|
@ -46,7 +48,10 @@ export default defineComponent({
|
|||
cornerColorStyle.color = props.color;
|
||||
}
|
||||
return wrapSSR(
|
||||
<div class={`${prefixCls.value}-wrapper ${hashId.value}`} {...restAttrs}>
|
||||
<div
|
||||
class={`${prefixCls.value}-wrapper ${cssVarCls.value} ${rootCls.value} ${hashId.value}`}
|
||||
{...restAttrs}
|
||||
>
|
||||
{slots.default?.()}
|
||||
<div
|
||||
class={[ribbonCls.value, className, hashId.value]}
|
||||
|
|
|
@ -1,29 +1,108 @@
|
|||
import type { CSSObject } from '../../_util/cssinjs';
|
||||
import { Keyframes } from '../../_util/cssinjs';
|
||||
import type { FullToken, GenerateStyle } from '../../theme/internal';
|
||||
import { genComponentStyleHook, mergeToken } from '../../theme/internal';
|
||||
import { genPresetColor, resetComponent } from '../../style';
|
||||
import { Keyframes, unit } from '../../_util/cssinjs';
|
||||
|
||||
export interface ComponentToken {}
|
||||
import { resetComponent } from '../../style';
|
||||
import type { FullToken, GenerateStyle, GenStyleFn, GetDefaultToken } from '../../theme/internal';
|
||||
import { genPresetColor, genStyleHooks, mergeToken } from '../../theme/internal';
|
||||
|
||||
interface BadgeToken extends FullToken<'Badge'> {
|
||||
/** Component only token. Which will handle additional calculation of alias token */
|
||||
export interface ComponentToken {
|
||||
// Component token here
|
||||
/**
|
||||
* @desc 徽标 z-index
|
||||
* @descEN z-index of badge
|
||||
*/
|
||||
indicatorZIndex: number | string;
|
||||
/**
|
||||
* @desc 徽标高度
|
||||
* @descEN Height of badge
|
||||
*/
|
||||
indicatorHeight: number | string;
|
||||
/**
|
||||
* @desc 小号徽标高度
|
||||
* @descEN Height of small badge
|
||||
*/
|
||||
indicatorHeightSM: number | string;
|
||||
/**
|
||||
* @desc 点状徽标尺寸
|
||||
* @descEN Size of dot badge
|
||||
*/
|
||||
dotSize: number;
|
||||
/**
|
||||
* @desc 徽标文本尺寸
|
||||
* @descEN Font size of badge text
|
||||
*/
|
||||
textFontSize: number;
|
||||
/**
|
||||
* @desc 小号徽标文本尺寸
|
||||
* @descEN Font size of small badge text
|
||||
*/
|
||||
textFontSizeSM: number;
|
||||
/**
|
||||
* @desc 徽标文本粗细
|
||||
* @descEN Font weight of badge text
|
||||
*/
|
||||
textFontWeight: number | string;
|
||||
/**
|
||||
* @desc 状态徽标尺寸
|
||||
* @descEN Size of status badge
|
||||
*/
|
||||
statusSize: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* @desc Badge 组件的 Token
|
||||
* @descEN Token for Badge component
|
||||
*/
|
||||
export interface BadgeToken extends FullToken<'Badge'> {
|
||||
/**
|
||||
* @desc 徽标字体高度
|
||||
* @descEN Font height of badge
|
||||
*/
|
||||
badgeFontHeight: number;
|
||||
badgeZIndex: number | string;
|
||||
badgeHeight: number;
|
||||
badgeHeightSm: number;
|
||||
/**
|
||||
* @desc 徽标文本颜色
|
||||
* @descEN Text color of badge
|
||||
*/
|
||||
badgeTextColor: string;
|
||||
badgeFontWeight: string;
|
||||
badgeFontSize: number;
|
||||
/**
|
||||
* @desc 徽标颜色
|
||||
* @descEN Color of badge
|
||||
*/
|
||||
badgeColor: string;
|
||||
/**
|
||||
* @desc 徽标悬停颜色
|
||||
* @descEN Hover color of badge
|
||||
*/
|
||||
badgeColorHover: string;
|
||||
badgeDotSize: number;
|
||||
badgeFontSizeSm: number;
|
||||
badgeStatusSize: number;
|
||||
/**
|
||||
* @desc 徽标阴影尺寸
|
||||
* @descEN Shadow size of badge
|
||||
*/
|
||||
badgeShadowSize: number;
|
||||
/**
|
||||
* @desc 徽标阴影颜色
|
||||
* @descEN Shadow color of badge
|
||||
*/
|
||||
badgeShadowColor: string;
|
||||
/**
|
||||
* @desc 徽标处理持续时间
|
||||
* @descEN Processing duration of badge
|
||||
*/
|
||||
badgeProcessingDuration: string;
|
||||
/**
|
||||
* @desc 徽标丝带偏移量
|
||||
* @descEN Ribbon offset of badge
|
||||
*/
|
||||
badgeRibbonOffset: number;
|
||||
/**
|
||||
* @desc 徽标丝带角变换
|
||||
* @descEN Ribbon corner transform of badge
|
||||
*/
|
||||
badgeRibbonCornerTransform: string;
|
||||
/**
|
||||
* @desc 徽标丝带角滤镜
|
||||
* @descEN Ribbon corner filter of badge
|
||||
*/
|
||||
badgeRibbonCornerFilter: string;
|
||||
}
|
||||
|
||||
|
@ -46,10 +125,12 @@ 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%': {
|
||||
|
@ -58,22 +139,23 @@ const antBadgeLoadingCircle = new Keyframes('antBadgeLoadingCircle', {
|
|||
},
|
||||
});
|
||||
|
||||
const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (token: BadgeToken): CSSObject => {
|
||||
const genSharedBadgeStyle: GenerateStyle<BadgeToken> = token => {
|
||||
const {
|
||||
componentCls,
|
||||
iconCls,
|
||||
antCls,
|
||||
badgeFontHeight,
|
||||
badgeShadowSize,
|
||||
badgeHeightSm,
|
||||
motionDurationSlow,
|
||||
badgeStatusSize,
|
||||
textFontSize,
|
||||
textFontSizeSM,
|
||||
statusSize,
|
||||
dotSize,
|
||||
textFontWeight,
|
||||
indicatorHeight,
|
||||
indicatorHeightSM,
|
||||
marginXS,
|
||||
badgeRibbonOffset,
|
||||
calc,
|
||||
} = token;
|
||||
const numberPrefixCls = `${antCls}-scroll-number`;
|
||||
const ribbonPrefixCls = `${antCls}-ribbon`;
|
||||
const ribbonWrapperPrefixCls = `${antCls}-ribbon-wrapper`;
|
||||
|
||||
const colorPreset = genPresetColor(token, (colorKey, { darkColor }) => ({
|
||||
[`&${componentCls} ${componentCls}-color-${colorKey}`]: {
|
||||
|
@ -81,13 +163,9 @@ const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (token: BadgeToken): CSSO
|
|||
[`&:not(${componentCls}-count)`]: {
|
||||
color: darkColor,
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
const statusRibbonPreset = genPresetColor(token, (colorKey, { darkColor }) => ({
|
||||
[`&${ribbonPrefixCls}-color-${colorKey}`]: {
|
||||
background: darkColor,
|
||||
color: darkColor,
|
||||
'a:hover &': {
|
||||
background: darkColor,
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
|
@ -100,18 +178,20 @@ const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (token: BadgeToken): CSSO
|
|||
lineHeight: 1,
|
||||
|
||||
[`${componentCls}-count`]: {
|
||||
zIndex: token.badgeZIndex,
|
||||
minWidth: token.badgeHeight,
|
||||
height: token.badgeHeight,
|
||||
display: 'inline-flex',
|
||||
justifyContent: 'center',
|
||||
zIndex: token.indicatorZIndex,
|
||||
minWidth: indicatorHeight,
|
||||
height: indicatorHeight,
|
||||
color: token.badgeTextColor,
|
||||
fontWeight: token.badgeFontWeight,
|
||||
fontSize: token.badgeFontSize,
|
||||
lineHeight: `${token.badgeHeight}px`,
|
||||
fontWeight: textFontWeight,
|
||||
fontSize: textFontSize,
|
||||
lineHeight: unit(indicatorHeight),
|
||||
whiteSpace: 'nowrap',
|
||||
textAlign: 'center',
|
||||
background: token.badgeColor,
|
||||
borderRadius: token.badgeHeight / 2,
|
||||
boxShadow: `0 0 0 ${badgeShadowSize}px ${token.badgeShadowColor}`,
|
||||
borderRadius: calc(indicatorHeight).div(2).equal(),
|
||||
boxShadow: `0 0 0 ${unit(badgeShadowSize)} ${token.badgeShadowColor}`,
|
||||
transition: `background ${token.motionDurationMid}`,
|
||||
|
||||
a: {
|
||||
|
@ -126,28 +206,29 @@ const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (token: BadgeToken): CSSO
|
|||
},
|
||||
},
|
||||
[`${componentCls}-count-sm`]: {
|
||||
minWidth: badgeHeightSm,
|
||||
height: badgeHeightSm,
|
||||
fontSize: token.badgeFontSizeSm,
|
||||
lineHeight: `${badgeHeightSm}px`,
|
||||
borderRadius: badgeHeightSm / 2,
|
||||
minWidth: indicatorHeightSM,
|
||||
height: indicatorHeightSM,
|
||||
fontSize: textFontSizeSM,
|
||||
lineHeight: unit(indicatorHeightSM),
|
||||
borderRadius: calc(indicatorHeightSM).div(2).equal(),
|
||||
},
|
||||
|
||||
[`${componentCls}-multiple-words`]: {
|
||||
padding: `0 ${token.paddingXS}px`,
|
||||
padding: `0 ${unit(token.paddingXS)}`,
|
||||
|
||||
bdi: {
|
||||
unicodeBidi: 'plaintext',
|
||||
},
|
||||
},
|
||||
|
||||
[`${componentCls}-dot`]: {
|
||||
zIndex: token.badgeZIndex,
|
||||
width: token.badgeDotSize,
|
||||
minWidth: token.badgeDotSize,
|
||||
height: token.badgeDotSize,
|
||||
zIndex: token.indicatorZIndex,
|
||||
width: dotSize,
|
||||
minWidth: dotSize,
|
||||
height: dotSize,
|
||||
background: token.badgeColor,
|
||||
borderRadius: '100%',
|
||||
boxShadow: `0 0 0 ${badgeShadowSize}px ${token.badgeShadowColor}`,
|
||||
},
|
||||
[`${componentCls}-dot${numberPrefixCls}`]: {
|
||||
transition: `background ${motionDurationSlow}`,
|
||||
boxShadow: `0 0 0 ${unit(badgeShadowSize)} ${token.badgeShadowColor}`,
|
||||
},
|
||||
[`${componentCls}-count, ${componentCls}-dot, ${numberPrefixCls}-custom-component`]: {
|
||||
position: 'absolute',
|
||||
|
@ -170,8 +251,8 @@ const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (token: BadgeToken): CSSO
|
|||
position: 'relative',
|
||||
top: -1, // Magic number, but seems better experience
|
||||
display: 'inline-block',
|
||||
width: badgeStatusSize,
|
||||
height: badgeStatusSize,
|
||||
width: statusSize,
|
||||
height: statusSize,
|
||||
verticalAlign: 'middle',
|
||||
borderRadius: '50%',
|
||||
},
|
||||
|
@ -181,8 +262,9 @@ const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (token: BadgeToken): CSSO
|
|||
},
|
||||
[`${componentCls}-status-processing`]: {
|
||||
overflow: 'visible',
|
||||
color: token.colorPrimary,
|
||||
backgroundColor: token.colorPrimary,
|
||||
color: token.colorInfo,
|
||||
backgroundColor: token.colorInfo,
|
||||
borderColor: 'currentcolor',
|
||||
|
||||
'&::after': {
|
||||
position: 'absolute',
|
||||
|
@ -256,118 +338,56 @@ const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (token: BadgeToken): CSSO
|
|||
transformOrigin: '50% 50%',
|
||||
},
|
||||
},
|
||||
[`${numberPrefixCls}`]: {
|
||||
[numberPrefixCls]: {
|
||||
overflow: 'hidden',
|
||||
transition: `all ${token.motionDurationMid} ${token.motionEaseOutBack}`,
|
||||
[`${numberPrefixCls}-only`]: {
|
||||
position: 'relative',
|
||||
display: 'inline-block',
|
||||
height: token.badgeHeight,
|
||||
height: indicatorHeight,
|
||||
transition: `all ${token.motionDurationSlow} ${token.motionEaseOutBack}`,
|
||||
WebkitTransformStyle: 'preserve-3d',
|
||||
WebkitBackfaceVisibility: 'hidden',
|
||||
[`> p${numberPrefixCls}-only-unit`]: {
|
||||
height: token.badgeHeight,
|
||||
height: indicatorHeight,
|
||||
margin: 0,
|
||||
WebkitTransformStyle: 'preserve-3d',
|
||||
WebkitBackfaceVisibility: 'hidden',
|
||||
},
|
||||
},
|
||||
[`${numberPrefixCls}-symbol`]: { verticalAlign: 'top' },
|
||||
[`${numberPrefixCls}-symbol`]: {
|
||||
verticalAlign: 'top',
|
||||
},
|
||||
},
|
||||
|
||||
// ====================== RTL =======================
|
||||
'&-rtl': {
|
||||
direction: 'rtl',
|
||||
|
||||
[`${componentCls}-count, ${componentCls}-dot, ${numberPrefixCls}-custom-component`]: {
|
||||
transform: 'translate(-50%, -50%)',
|
||||
},
|
||||
},
|
||||
},
|
||||
[`${ribbonWrapperPrefixCls}`]: { position: 'relative' },
|
||||
[`${ribbonPrefixCls}`]: {
|
||||
...resetComponent(token),
|
||||
position: 'absolute',
|
||||
top: marginXS,
|
||||
padding: `0 ${token.paddingXS}px`,
|
||||
color: token.colorPrimary,
|
||||
lineHeight: `${badgeFontHeight}px`,
|
||||
whiteSpace: 'nowrap',
|
||||
backgroundColor: token.colorPrimary,
|
||||
borderRadius: token.borderRadiusSM,
|
||||
[`${ribbonPrefixCls}-text`]: { color: token.colorTextLightSolid },
|
||||
[`${ribbonPrefixCls}-corner`]: {
|
||||
position: 'absolute',
|
||||
top: '100%',
|
||||
width: badgeRibbonOffset,
|
||||
height: badgeRibbonOffset,
|
||||
color: 'currentcolor',
|
||||
border: `${badgeRibbonOffset / 2}px solid`,
|
||||
transform: token.badgeRibbonCornerTransform,
|
||||
transformOrigin: 'top',
|
||||
filter: token.badgeRibbonCornerFilter,
|
||||
},
|
||||
...statusRibbonPreset,
|
||||
[`&${ribbonPrefixCls}-placement-end`]: {
|
||||
insetInlineEnd: -badgeRibbonOffset,
|
||||
borderEndEndRadius: 0,
|
||||
[`${ribbonPrefixCls}-corner`]: {
|
||||
insetInlineEnd: 0,
|
||||
borderInlineEndColor: 'transparent',
|
||||
borderBlockEndColor: 'transparent',
|
||||
},
|
||||
},
|
||||
[`&${ribbonPrefixCls}-placement-start`]: {
|
||||
insetInlineStart: -badgeRibbonOffset,
|
||||
borderEndStartRadius: 0,
|
||||
[`${ribbonPrefixCls}-corner`]: {
|
||||
insetInlineStart: 0,
|
||||
borderBlockEndColor: 'transparent',
|
||||
borderInlineStartColor: 'transparent',
|
||||
},
|
||||
},
|
||||
|
||||
// ====================== RTL =======================
|
||||
'&-rtl': {
|
||||
direction: 'rtl',
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
// ============================== Export ==============================
|
||||
export default genComponentStyleHook('Badge', token => {
|
||||
const { fontSize, lineHeight, fontSizeSM, lineWidth, marginXS, colorBorderBg } = token;
|
||||
export const prepareToken: (token: Parameters<GenStyleFn<'Badge'>>[0]) => BadgeToken = token => {
|
||||
const { fontHeight, lineWidth, marginXS, colorBorderBg } = token;
|
||||
|
||||
const badgeFontHeight = Math.round(fontSize * lineHeight);
|
||||
const badgeFontHeight = fontHeight;
|
||||
const badgeShadowSize = lineWidth;
|
||||
const badgeZIndex = 'auto';
|
||||
const badgeHeight = badgeFontHeight - 2 * badgeShadowSize;
|
||||
const badgeTextColor = token.colorBgContainer;
|
||||
const badgeFontWeight = 'normal';
|
||||
const badgeFontSize = fontSizeSM;
|
||||
const badgeTextColor = token.colorTextLightSolid;
|
||||
const badgeColor = token.colorError;
|
||||
const badgeColorHover = token.colorErrorHover;
|
||||
const badgeHeightSm = fontSize;
|
||||
const badgeDotSize = fontSizeSM / 2;
|
||||
const badgeFontSizeSm = fontSizeSM;
|
||||
const badgeStatusSize = fontSizeSM / 2;
|
||||
|
||||
const badgeToken = mergeToken<BadgeToken>(token, {
|
||||
badgeFontHeight,
|
||||
badgeShadowSize,
|
||||
badgeZIndex,
|
||||
badgeHeight,
|
||||
badgeTextColor,
|
||||
badgeFontWeight,
|
||||
badgeFontSize,
|
||||
badgeColor,
|
||||
badgeColorHover,
|
||||
badgeShadowColor: colorBorderBg,
|
||||
badgeHeightSm,
|
||||
badgeDotSize,
|
||||
badgeFontSizeSm,
|
||||
badgeStatusSize,
|
||||
badgeProcessingDuration: '1.2s',
|
||||
badgeRibbonOffset: marginXS,
|
||||
|
||||
|
@ -376,5 +396,28 @@ export default genComponentStyleHook('Badge', token => {
|
|||
badgeRibbonCornerFilter: `brightness(75%)`,
|
||||
});
|
||||
|
||||
return [genSharedBadgeStyle(badgeToken)];
|
||||
});
|
||||
return badgeToken;
|
||||
};
|
||||
|
||||
export const prepareComponentToken: GetDefaultToken<'Badge'> = token => {
|
||||
const { fontSize, lineHeight, fontSizeSM, lineWidth } = token;
|
||||
return {
|
||||
indicatorZIndex: 'auto',
|
||||
indicatorHeight: Math.round(fontSize * lineHeight) - 2 * lineWidth,
|
||||
indicatorHeightSM: fontSize,
|
||||
dotSize: fontSizeSM / 2,
|
||||
textFontSize: fontSizeSM,
|
||||
textFontSizeSM: fontSizeSM,
|
||||
textFontWeight: 'normal',
|
||||
statusSize: fontSizeSM / 2,
|
||||
};
|
||||
};
|
||||
|
||||
export default genStyleHooks(
|
||||
'Badge',
|
||||
token => {
|
||||
const badgeToken = prepareToken(token);
|
||||
return genSharedBadgeStyle(badgeToken);
|
||||
},
|
||||
prepareComponentToken,
|
||||
);
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
import { unit } from '../../_util/cssinjs';
|
||||
|
||||
import { prepareComponentToken, prepareToken } from '.';
|
||||
import type { BadgeToken } from '.';
|
||||
import { resetComponent } from '../../style';
|
||||
import type { GenerateStyle } from '../../theme/internal';
|
||||
import { genPresetColor, genStyleHooks } from '../../theme/internal';
|
||||
|
||||
// ============================== Ribbon ==============================
|
||||
const genRibbonStyle: GenerateStyle<BadgeToken> = token => {
|
||||
const { antCls, badgeFontHeight, marginXS, badgeRibbonOffset, calc } = token;
|
||||
const ribbonPrefixCls = `${antCls}-ribbon`;
|
||||
const ribbonWrapperPrefixCls = `${antCls}-ribbon-wrapper`;
|
||||
|
||||
const statusRibbonPreset = genPresetColor(token, (colorKey, { darkColor }) => ({
|
||||
[`&${ribbonPrefixCls}-color-${colorKey}`]: {
|
||||
background: darkColor,
|
||||
color: darkColor,
|
||||
},
|
||||
}));
|
||||
|
||||
return {
|
||||
[ribbonWrapperPrefixCls]: {
|
||||
position: 'relative',
|
||||
},
|
||||
[ribbonPrefixCls]: {
|
||||
...resetComponent(token),
|
||||
position: 'absolute',
|
||||
top: marginXS,
|
||||
padding: `0 ${unit(token.paddingXS)}`,
|
||||
color: token.colorPrimary,
|
||||
lineHeight: unit(badgeFontHeight),
|
||||
whiteSpace: 'nowrap',
|
||||
backgroundColor: token.colorPrimary,
|
||||
borderRadius: token.borderRadiusSM,
|
||||
[`${ribbonPrefixCls}-text`]: {
|
||||
color: token.badgeTextColor,
|
||||
},
|
||||
[`${ribbonPrefixCls}-corner`]: {
|
||||
position: 'absolute',
|
||||
top: '100%',
|
||||
width: badgeRibbonOffset,
|
||||
height: badgeRibbonOffset,
|
||||
color: 'currentcolor',
|
||||
border: `${unit(calc(badgeRibbonOffset).div(2).equal())} solid`,
|
||||
transform: token.badgeRibbonCornerTransform,
|
||||
transformOrigin: 'top',
|
||||
filter: token.badgeRibbonCornerFilter,
|
||||
},
|
||||
...statusRibbonPreset,
|
||||
[`&${ribbonPrefixCls}-placement-end`]: {
|
||||
insetInlineEnd: calc(badgeRibbonOffset).mul(-1).equal(),
|
||||
borderEndEndRadius: 0,
|
||||
[`${ribbonPrefixCls}-corner`]: {
|
||||
insetInlineEnd: 0,
|
||||
borderInlineEndColor: 'transparent',
|
||||
borderBlockEndColor: 'transparent',
|
||||
},
|
||||
},
|
||||
[`&${ribbonPrefixCls}-placement-start`]: {
|
||||
insetInlineStart: calc(badgeRibbonOffset).mul(-1).equal(),
|
||||
borderEndStartRadius: 0,
|
||||
[`${ribbonPrefixCls}-corner`]: {
|
||||
insetInlineStart: 0,
|
||||
borderBlockEndColor: 'transparent',
|
||||
borderInlineStartColor: 'transparent',
|
||||
},
|
||||
},
|
||||
|
||||
// ====================== RTL =======================
|
||||
'&-rtl': {
|
||||
direction: 'rtl',
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
// ============================== Export ==============================
|
||||
export default genStyleHooks(
|
||||
['Badge', 'Ribbon'],
|
||||
token => {
|
||||
const badgeToken = prepareToken(token);
|
||||
return genRibbonStyle(badgeToken);
|
||||
},
|
||||
prepareComponentToken,
|
||||
);
|
|
@ -0,0 +1,36 @@
|
|||
import type {
|
||||
GlobalToken as GlobalTokenTypeUtil,
|
||||
OverrideTokenMap as OverrideTokenTypeUtil,
|
||||
FullToken as FullTokenTypeUtil,
|
||||
GetDefaultToken as GetDefaultTokenTypeUtil,
|
||||
GenStyleFn as GenStyleFnTypeUtil,
|
||||
TokenMapKey,
|
||||
} from './interface';
|
||||
|
||||
import type { AliasToken } from '../alias';
|
||||
import type { ComponentTokenMap } from '../components';
|
||||
|
||||
/** Final token which contains the components level override */
|
||||
export type GlobalToken = GlobalTokenTypeUtil<ComponentTokenMap, AliasToken>;
|
||||
|
||||
export type OverrideToken = OverrideTokenTypeUtil<ComponentTokenMap, AliasToken>;
|
||||
|
||||
export type OverrideComponent = TokenMapKey<ComponentTokenMap>;
|
||||
|
||||
export type FullToken<C extends TokenMapKey<ComponentTokenMap>> = FullTokenTypeUtil<
|
||||
ComponentTokenMap,
|
||||
AliasToken,
|
||||
C
|
||||
>;
|
||||
|
||||
export type GetDefaultToken<C extends TokenMapKey<ComponentTokenMap>> = GetDefaultTokenTypeUtil<
|
||||
ComponentTokenMap,
|
||||
AliasToken,
|
||||
C
|
||||
>;
|
||||
|
||||
export type GenStyleFn<C extends TokenMapKey<ComponentTokenMap>> = GenStyleFnTypeUtil<
|
||||
ComponentTokenMap,
|
||||
AliasToken,
|
||||
C
|
||||
>;
|
|
@ -0,0 +1,56 @@
|
|||
import type { CSSInterpolation, TokenType } from '../../../_util/cssinjs';
|
||||
import type { StyleInfo, TokenWithCommonCls } from '../../util/genComponentStyleHook';
|
||||
|
||||
/** Override the some definition of the @ant-design/cssinjs-utils https://github.com/ant-design/cssinjs-utils */
|
||||
export type TokenMap = Record<PropertyKey, any>;
|
||||
|
||||
export type TokenMapKey<CompTokenMap extends TokenMap> = Extract<keyof CompTokenMap, string>;
|
||||
|
||||
export type GlobalToken<CompTokenMap extends TokenMap, AliasToken extends TokenType> = AliasToken &
|
||||
CompTokenMap;
|
||||
|
||||
export type OverrideTokenMap<CompTokenMap extends TokenMap, AliasToken extends TokenType> = {
|
||||
[key in keyof CompTokenMap]: Partial<CompTokenMap[key]> & Partial<AliasToken>;
|
||||
};
|
||||
|
||||
export type GlobalTokenWithComponent<
|
||||
CompTokenMap extends TokenMap,
|
||||
AliasToken extends TokenType,
|
||||
C extends TokenMapKey<CompTokenMap>,
|
||||
> = GlobalToken<CompTokenMap, AliasToken> & CompTokenMap[C];
|
||||
|
||||
export type ComponentToken<
|
||||
CompTokenMap extends TokenMap,
|
||||
AliasToken extends TokenType,
|
||||
C extends TokenMapKey<CompTokenMap>,
|
||||
> = Exclude<OverrideTokenMap<CompTokenMap, AliasToken>[C], undefined>;
|
||||
|
||||
export type ComponentTokenKey<
|
||||
CompTokenMap extends TokenMap,
|
||||
AliasToken extends TokenType,
|
||||
C extends TokenMapKey<CompTokenMap>,
|
||||
> = keyof ComponentToken<CompTokenMap, AliasToken, C>;
|
||||
|
||||
export type FullToken<
|
||||
CompTokenMap extends TokenMap,
|
||||
AliasToken extends TokenType,
|
||||
C extends TokenMapKey<CompTokenMap>,
|
||||
> = TokenWithCommonCls<GlobalTokenWithComponent<CompTokenMap, AliasToken, C>>;
|
||||
|
||||
export type GenStyleFn<
|
||||
CompTokenMap extends TokenMap,
|
||||
AliasToken extends TokenType,
|
||||
C extends TokenMapKey<CompTokenMap>,
|
||||
> = (token: FullToken<CompTokenMap, AliasToken, C>, info: StyleInfo) => CSSInterpolation;
|
||||
|
||||
export type GetDefaultTokenFn<
|
||||
CompTokenMap extends TokenMap,
|
||||
AliasToken extends TokenType,
|
||||
C extends TokenMapKey<CompTokenMap>,
|
||||
> = (token: AliasToken & Partial<CompTokenMap[C]>) => CompTokenMap[C];
|
||||
|
||||
export type GetDefaultToken<
|
||||
CompTokenMap extends TokenMap,
|
||||
AliasToken extends TokenType,
|
||||
C extends TokenMapKey<CompTokenMap>,
|
||||
> = null | CompTokenMap[C] | GetDefaultTokenFn<CompTokenMap, AliasToken, C>;
|
|
@ -6,6 +6,8 @@ import type { SeedToken } from './seeds';
|
|||
import type { VueNode } from '../..//_util/type';
|
||||
import type { Ref } from 'vue';
|
||||
|
||||
export type { FullToken, OverrideComponent, GetDefaultToken, GenStyleFn } from './cssinjs-utils';
|
||||
|
||||
export type MappingAlgorithm = DerivativeFunc<SeedToken, MapToken>;
|
||||
|
||||
export type OverrideToken = {
|
||||
|
|
|
@ -7,6 +7,7 @@ import type {
|
|||
PresetColorType,
|
||||
SeedToken,
|
||||
UseComponentStyleResult,
|
||||
GenStyleFn,
|
||||
} from './interface';
|
||||
import { PresetColors } from './interface';
|
||||
import useToken from './useToken';
|
||||
|
@ -48,4 +49,5 @@ export type {
|
|||
SeedToken,
|
||||
UseComponentStyleResult,
|
||||
GetDefaultToken,
|
||||
GenStyleFn,
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue