feat: collapse css var (#8331)

Co-authored-by: nishu <nishu@qianxin.com>
feat-4.3
Shuhari 2025-08-26 00:09:22 +08:00 committed by GitHub
parent 10382c4526
commit e3eff68312
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 160 additions and 65 deletions

View File

@ -19,6 +19,7 @@ import collapseMotion from '../_util/collapseMotion';
import type { CustomSlotsType } from '../_util/type'; import type { CustomSlotsType } from '../_util/type';
// CSSINJS // CSSINJS
import useCSSVarCls from '../config-provider/hooks/useCssVarCls';
import useStyle from './style'; import useStyle from './style';
type Key = number | string; type Key = number | string;
@ -63,7 +64,8 @@ export default defineComponent({
const { prefixCls, direction, rootPrefixCls } = useConfigInject('collapse', props); const { prefixCls, direction, rootPrefixCls } = useConfigInject('collapse', props);
// style // style
const [wrapSSR, hashId] = useStyle(prefixCls); const rootCls = useCSSVarCls(prefixCls);
const [wrapSSR, hashId, cssVarCls] = useStyle(prefixCls, rootCls);
const iconPosition = computed(() => { const iconPosition = computed(() => {
const { expandIconPosition } = props; const { expandIconPosition } = props;
@ -186,6 +188,8 @@ export default defineComponent({
[`${prefixCls.value}-ghost`]: !!ghost, [`${prefixCls.value}-ghost`]: !!ghost,
[attrs.class as string]: !!attrs.class, [attrs.class as string]: !!attrs.class,
}, },
cssVarCls.value,
rootCls.value,
hashId.value, hashId.value,
); );
return wrapSSR( return wrapSSR(

View File

@ -1,26 +1,63 @@
import { genCollapseMotion } from '../../style/motion'; import type { CSSProperties } from 'vue';
import type { FullToken, GenerateStyle } from '../../theme/internal'; import { unit } from '../../_util/cssinjs';
import { genComponentStyleHook, mergeToken } from '../../theme/internal';
import { resetComponent, resetIcon } from '../../style';
export interface ComponentToken {} import { genFocusStyle, resetComponent, resetIcon } from '../../style';
import { genCollapseMotion } from '../../style/motion';
import type { FullToken, GenerateStyle, GetDefaultToken } from '../../theme/internal';
import { genStyleHooks, mergeToken } from '../../theme/internal';
/** Component only token. Which will handle additional calculation of alias token */
export interface ComponentToken {
// Component token here
/**
* @desc 折叠面板头部内边距
* @descEN Padding of header
*/
headerPadding: CSSProperties['padding'];
/**
* @desc 折叠面板头部背景
* @descEN Background of header
*/
headerBg: string;
/**
* @desc 折叠面板内容内边距
* @descEN Padding of content
*/
contentPadding: CSSProperties['padding'];
/**
* @desc 折叠面板内容背景
* @descEN Background of content
*/
contentBg: string;
}
type CollapseToken = FullToken<'Collapse'> & { type CollapseToken = FullToken<'Collapse'> & {
collapseContentBg: string; /**
collapseHeaderBg: string; * @desc 小号折叠面板头部内边距
collapseHeaderPadding: string; * @descEN Padding of small header
*/
collapseHeaderPaddingSM: string;
/**
* @desc 大号折叠面板头部内边距
* @descEN Padding of large header
*/
collapseHeaderPaddingLG: string;
/**
* @desc 折叠面板边框圆角
* @descEN Border radius of collapse panel
*/
collapsePanelBorderRadius: number; collapsePanelBorderRadius: number;
collapseContentPaddingHorizontal: number;
}; };
export const genBaseStyle: GenerateStyle<CollapseToken> = token => { export const genBaseStyle: GenerateStyle<CollapseToken> = token => {
const { const {
componentCls, componentCls,
collapseContentBg, contentBg,
padding, padding,
collapseContentPaddingHorizontal, headerBg,
collapseHeaderBg, headerPadding,
collapseHeaderPadding, collapseHeaderPaddingSM,
collapseHeaderPaddingLG,
collapsePanelBorderRadius, collapsePanelBorderRadius,
lineWidth, lineWidth,
@ -29,35 +66,52 @@ export const genBaseStyle: GenerateStyle<CollapseToken> = token => {
colorText, colorText,
colorTextHeading, colorTextHeading,
colorTextDisabled, colorTextDisabled,
fontSize, fontSizeLG,
lineHeight, lineHeight,
lineHeightLG,
marginSM, marginSM,
paddingSM, paddingSM,
paddingLG,
paddingXS,
motionDurationSlow, motionDurationSlow,
fontSizeIcon, fontSizeIcon,
contentPadding,
fontHeight,
fontHeightLG,
} = token; } = token;
const borderBase = `${lineWidth}px ${lineType} ${colorBorder}`; const borderBase = `${unit(lineWidth)} ${lineType} ${colorBorder}`;
return { return {
[componentCls]: { [componentCls]: {
...resetComponent(token), ...resetComponent(token),
backgroundColor: collapseHeaderBg, backgroundColor: headerBg,
border: borderBase, border: borderBase,
borderBottom: 0, borderRadius: collapsePanelBorderRadius,
borderRadius: `${collapsePanelBorderRadius}px`,
[`&-rtl`]: { '&-rtl': {
direction: 'rtl', direction: 'rtl',
}, },
[`& > ${componentCls}-item`]: { [`& > ${componentCls}-item`]: {
borderBottom: borderBase, borderBottom: borderBase,
[`&:last-child`]: { '&:first-child': {
[` [`
&, &,
& > ${componentCls}-header`]: { & > ${componentCls}-header`]: {
borderRadius: `0 0 ${collapsePanelBorderRadius}px ${collapsePanelBorderRadius}px`, borderRadius: `${unit(collapsePanelBorderRadius)} ${unit(
collapsePanelBorderRadius,
)} 0 0`,
},
},
'&:last-child': {
[`
&,
& > ${componentCls}-header`]: {
borderRadius: `0 0 ${unit(collapsePanelBorderRadius)} ${unit(
collapsePanelBorderRadius,
)}`,
}, },
}, },
@ -66,23 +120,20 @@ export const genBaseStyle: GenerateStyle<CollapseToken> = token => {
display: 'flex', display: 'flex',
flexWrap: 'nowrap', flexWrap: 'nowrap',
alignItems: 'flex-start', alignItems: 'flex-start',
padding: collapseHeaderPadding, padding: headerPadding,
color: colorTextHeading, color: colorTextHeading,
lineHeight, lineHeight,
cursor: 'pointer', cursor: 'pointer',
transition: `all ${motionDurationSlow}, visibility 0s`, transition: `all ${motionDurationSlow}, visibility 0s`,
...genFocusStyle(token),
[`> ${componentCls}-header-text`]: { [`> ${componentCls}-header-text`]: {
flex: 'auto', flex: 'auto',
}, },
'&:focus': {
outline: 'none',
},
// >>>>> Arrow // >>>>> Arrow
[`${componentCls}-expand-icon`]: { [`${componentCls}-expand-icon`]: {
height: fontSize * lineHeight, height: fontHeight,
display: 'flex', display: 'flex',
alignItems: 'center', alignItems: 'center',
paddingInlineEnd: marginSM, paddingInlineEnd: marginSM,
@ -91,7 +142,9 @@ export const genBaseStyle: GenerateStyle<CollapseToken> = token => {
[`${componentCls}-arrow`]: { [`${componentCls}-arrow`]: {
...resetIcon(), ...resetIcon(),
fontSize: fontSizeIcon, fontSize: fontSizeIcon,
// when `transform: rotate()` is applied to icon's root element
transition: `transform ${motionDurationSlow}`,
// when `transform: rotate()` is applied to icon's child element
svg: { svg: {
transition: `transform ${motionDurationSlow}`, transition: `transform ${motionDurationSlow}`,
}, },
@ -103,50 +156,79 @@ export const genBaseStyle: GenerateStyle<CollapseToken> = token => {
}, },
}, },
[`${componentCls}-header-collapsible-only`]: { [`${componentCls}-collapsible-header`]: {
cursor: 'default', cursor: 'default',
[`${componentCls}-header-text`]: { [`${componentCls}-header-text`]: {
flex: 'none', flex: 'none',
cursor: 'pointer', cursor: 'pointer',
}, },
[`${componentCls}-expand-icon`]: {
cursor: 'pointer',
},
}, },
[`${componentCls}-icon-collapsible-only`]: { [`${componentCls}-collapsible-icon`]: {
cursor: 'default', cursor: 'unset',
[`${componentCls}-expand-icon`]: { [`${componentCls}-expand-icon`]: {
cursor: 'pointer', cursor: 'pointer',
}, },
}, },
[`&${componentCls}-no-arrow`]: {
[`> ${componentCls}-header`]: {
paddingInlineStart: paddingSM,
},
},
}, },
[`${componentCls}-content`]: { [`${componentCls}-content`]: {
color: colorText, color: colorText,
backgroundColor: collapseContentBg, backgroundColor: contentBg,
borderTop: borderBase, borderTop: borderBase,
[`& > ${componentCls}-content-box`]: { [`& > ${componentCls}-content-box`]: {
padding: `${padding}px ${collapseContentPaddingHorizontal}px`, padding: contentPadding,
}, },
[`&-hidden`]: { '&-hidden': {
display: 'none', display: 'none',
}, },
}, },
'&-small': {
[`> ${componentCls}-item`]: {
[`> ${componentCls}-header`]: {
padding: collapseHeaderPaddingSM,
paddingInlineStart: paddingXS,
[`> ${componentCls}-expand-icon`]: {
// Arrow offset
marginInlineStart: token.calc(paddingSM).sub(paddingXS).equal(),
},
},
[`> ${componentCls}-content > ${componentCls}-content-box`]: {
padding: paddingSM,
},
},
},
'&-large': {
[`> ${componentCls}-item`]: {
fontSize: fontSizeLG,
lineHeight: lineHeightLG,
[`> ${componentCls}-header`]: {
padding: collapseHeaderPaddingLG,
paddingInlineStart: padding,
[`> ${componentCls}-expand-icon`]: {
height: fontHeightLG,
// Arrow offset
marginInlineStart: token.calc(paddingLG).sub(padding).equal(),
},
},
[`> ${componentCls}-content > ${componentCls}-content-box`]: {
padding: paddingLG,
},
},
},
[`${componentCls}-item:last-child`]: { [`${componentCls}-item:last-child`]: {
borderBottom: 0,
[`> ${componentCls}-content`]: { [`> ${componentCls}-content`]: {
borderRadius: `0 0 ${collapsePanelBorderRadius}px ${collapsePanelBorderRadius}px`, borderRadius: `0 0 ${unit(collapsePanelBorderRadius)} ${unit(collapsePanelBorderRadius)}`,
}, },
}, },
@ -179,7 +261,7 @@ export const genBaseStyle: GenerateStyle<CollapseToken> = token => {
const genArrowStyle: GenerateStyle<CollapseToken> = token => { const genArrowStyle: GenerateStyle<CollapseToken> = token => {
const { componentCls } = token; const { componentCls } = token;
const fixedSelector = `> ${componentCls}-item > ${componentCls}-header ${componentCls}-arrow svg`; const fixedSelector = `> ${componentCls}-item > ${componentCls}-header ${componentCls}-arrow`;
return { return {
[`${componentCls}-rtl`]: { [`${componentCls}-rtl`]: {
@ -193,7 +275,7 @@ const genArrowStyle: GenerateStyle<CollapseToken> = token => {
const genBorderlessStyle: GenerateStyle<CollapseToken> = token => { const genBorderlessStyle: GenerateStyle<CollapseToken> = token => {
const { const {
componentCls, componentCls,
collapseHeaderBg, headerBg,
paddingXXS, paddingXXS,
colorBorder, colorBorder,
@ -201,7 +283,7 @@ const genBorderlessStyle: GenerateStyle<CollapseToken> = token => {
return { return {
[`${componentCls}-borderless`]: { [`${componentCls}-borderless`]: {
backgroundColor: collapseHeaderBg, backgroundColor: headerBg,
border: 0, border: 0,
[`> ${componentCls}-item`]: { [`> ${componentCls}-item`]: {
@ -252,20 +334,29 @@ const genGhostStyle: GenerateStyle<CollapseToken> = token => {
}; };
}; };
export default genComponentStyleHook('Collapse', token => { export const prepareComponentToken: GetDefaultToken<'Collapse'> = token => ({
const collapseToken = mergeToken<CollapseToken>(token, { headerPadding: `${token.paddingSM}px ${token.padding}px`,
collapseContentBg: token.colorBgContainer, headerBg: token.colorFillAlter,
collapseHeaderBg: token.colorFillAlter, contentPadding: `${token.padding}px 16px`, // Fixed Value
collapseHeaderPadding: `${token.paddingSM}px ${token.padding}px`, contentBg: token.colorBgContainer,
collapsePanelBorderRadius: token.borderRadiusLG,
collapseContentPaddingHorizontal: 16, // Fixed value
});
return [
genBaseStyle(collapseToken),
genBorderlessStyle(collapseToken),
genGhostStyle(collapseToken),
genArrowStyle(collapseToken),
genCollapseMotion(collapseToken),
];
}); });
export default genStyleHooks(
'Collapse',
token => {
const collapseToken = mergeToken<CollapseToken>(token, {
collapseHeaderPaddingSM: `${unit(token.paddingXS)} ${unit(token.paddingSM)}`,
collapseHeaderPaddingLG: `${unit(token.padding)} ${unit(token.paddingLG)}`,
collapsePanelBorderRadius: token.borderRadiusLG,
});
return [
genBaseStyle(collapseToken),
genBorderlessStyle(collapseToken),
genGhostStyle(collapseToken),
genArrowStyle(collapseToken),
genCollapseMotion(collapseToken),
];
},
prepareComponentToken,
);