Skip to content

feat[cssvar]: Avatar & Badge support cssvar #8327

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: feat-4.3
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions components/avatar/Avatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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,
};

Expand Down Expand Up @@ -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,
Expand Down
6 changes: 5 additions & 1 deletion components/avatar/Group.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -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);
Expand All @@ -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,
};

Expand Down
100 changes: 48 additions & 52 deletions components/avatar/style/index.ts
Original file line number Diff line number Diff line change
@@ -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;
/**
Expand Down Expand Up @@ -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 => {
Expand All @@ -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}`]: {
Expand All @@ -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',
},

Expand All @@ -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),
},

Expand All @@ -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,
},
},
Expand All @@ -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;
Expand All @@ -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,
);
6 changes: 5 additions & 1 deletion components/badge/Badge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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(() => {
Expand Down Expand Up @@ -189,6 +191,8 @@ export default defineComponent({
[`${pre}-rtl`]: direction.value === 'rtl',
},
attrs.class,
cssVarCls.value,
rootCls.value,
hashId.value,
);

Expand Down
11 changes: 8 additions & 3 deletions components/badge/Ribbon.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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,
Expand All @@ -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]}
Expand Down
Loading