refactor: Cascader cssinjs (#34374)

This commit is contained in:
二货机器人 2022-03-09 00:29:00 +08:00 committed by GitHub
parent 4f2a8bed37
commit de24558a6c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 271 additions and 93 deletions

View File

@ -98,6 +98,8 @@ export interface DerivativeToken extends Omit<DesignToken, 'duration'> {
warningOutlineColor: string; warningOutlineColor: string;
itemActiveBackground: string; itemActiveBackground: string;
highlightColor: string;
linkColor: string; linkColor: string;
fontSizeSM: number; fontSizeSM: number;
fontSizeLG: number; fontSizeLG: number;
@ -154,6 +156,8 @@ function derivative(designToken: DesignToken): DerivativeToken {
warningHoverColor: warningColors[4], warningHoverColor: warningColors[4],
warningOutlineColor: new TinyColor(warningColor).setAlpha(0.2).toRgbString(), warningOutlineColor: new TinyColor(warningColor).setAlpha(0.2).toRgbString(),
highlightColor: errorColors[4], // FIXME: Should not align with error color
itemActiveBackground: primaryColors[0], itemActiveBackground: primaryColors[0],
linkColor: primaryColor, linkColor: primaryColor,

View File

@ -22,6 +22,8 @@ import getIcons from '../select/utils/iconUtil';
import { getTransitionName, getTransitionDirection, SelectCommonPlacement } from '../_util/motion'; import { getTransitionName, getTransitionDirection, SelectCommonPlacement } from '../_util/motion';
import { FormItemStatusContext } from '../form/context'; import { FormItemStatusContext } from '../form/context';
import { getMergedStatus, getStatusClassNames, InputStatus } from '../_util/statusUtils'; import { getMergedStatus, getStatusClassNames, InputStatus } from '../_util/statusUtils';
import useStyle from './style';
import useSelectStyle from '../select/style';
// Align the design since we use `rc-select` in root. This help: // Align the design since we use `rc-select` in root. This help:
// - List search content will show all content // - List search content will show all content
@ -140,6 +142,7 @@ const Cascader = React.forwardRef((props: CascaderProps<any>, ref: React.Ref<Cas
direction: rootDirection, direction: rootDirection,
// virtual, // virtual,
// dropdownMatchSelectWidth, // dropdownMatchSelectWidth,
iconPrefixCls,
} = useContext(ConfigContext); } = useContext(ConfigContext);
const mergedDirection = direction || rootDirection; const mergedDirection = direction || rootDirection;
@ -172,6 +175,9 @@ const Cascader = React.forwardRef((props: CascaderProps<any>, ref: React.Ref<Cas
const prefixCls = getPrefixCls('select', customizePrefixCls); const prefixCls = getPrefixCls('select', customizePrefixCls);
const cascaderPrefixCls = getPrefixCls('cascader', customizePrefixCls); const cascaderPrefixCls = getPrefixCls('cascader', customizePrefixCls);
const [wrapSelectSSR, hashId] = useSelectStyle(rootPrefixCls, prefixCls, iconPrefixCls);
const [wrapCascaderSSR] = useStyle(cascaderPrefixCls);
// =================== Dropdown ==================== // =================== Dropdown ====================
const mergedDropdownClassName = classNames( const mergedDropdownClassName = classNames(
dropdownClassName || popupClassName, dropdownClassName || popupClassName,
@ -179,6 +185,7 @@ const Cascader = React.forwardRef((props: CascaderProps<any>, ref: React.Ref<Cas
{ {
[`${cascaderPrefixCls}-dropdown-rtl`]: mergedDirection === 'rtl', [`${cascaderPrefixCls}-dropdown-rtl`]: mergedDirection === 'rtl',
}, },
hashId,
); );
// ==================== Search ===================== // ==================== Search =====================
@ -245,7 +252,7 @@ const Cascader = React.forwardRef((props: CascaderProps<any>, ref: React.Ref<Cas
}; };
// ==================== Render ===================== // ==================== Render =====================
return ( const renderNode = (
<RcCascader <RcCascader
prefixCls={prefixCls} prefixCls={prefixCls}
className={classNames( className={classNames(
@ -258,6 +265,7 @@ const Cascader = React.forwardRef((props: CascaderProps<any>, ref: React.Ref<Cas
}, },
getStatusClassNames(prefixCls, mergedStatus, hasFeedback), getStatusClassNames(prefixCls, mergedStatus, hasFeedback),
className, className,
hashId,
)} )}
{...(restProps as any)} {...(restProps as any)}
direction={mergedDirection} direction={mergedDirection}
@ -284,6 +292,8 @@ const Cascader = React.forwardRef((props: CascaderProps<any>, ref: React.Ref<Cas
showArrow={hasFeedback || showArrow} showArrow={hasFeedback || showArrow}
/> />
); );
return wrapCascaderSSR(wrapSelectSSR(renderNode));
}) as (<OptionType extends BaseOptionType | DefaultOptionType = DefaultOptionType>( }) as (<OptionType extends BaseOptionType | DefaultOptionType = DefaultOptionType>(
props: React.PropsWithChildren<CascaderProps<OptionType>> & { ref?: React.Ref<CascaderRef> }, props: React.PropsWithChildren<CascaderProps<OptionType>> & { ref?: React.Ref<CascaderRef> },
) => React.ReactElement) & { ) => React.ReactElement) & {

View File

@ -1,104 +1,104 @@
@import '../../style/themes/index'; // @import '../../style/themes/index';
@import '../../style/mixins/index'; // @import '../../style/mixins/index';
@import '../../input/style/mixin'; // @import '../../input/style/mixin';
@import '../../checkbox/style/mixin'; // @import '../../checkbox/style/mixin';
@cascader-prefix-cls: ~'@{ant-prefix}-cascader'; // @cascader-prefix-cls: ~'@{ant-prefix}-cascader';
.antCheckboxFn(@checkbox-prefix-cls: ~'@{cascader-prefix-cls}-checkbox'); // .antCheckboxFn(@checkbox-prefix-cls: ~'@{cascader-prefix-cls}-checkbox');
.@{cascader-prefix-cls} { // .@{cascader-prefix-cls} {
width: 184px; // width: 184px;
&-checkbox { // &-checkbox {
top: 0; // top: 0;
margin-right: @padding-xs; // margin-right: @padding-xs;
} // }
&-menus { // &-menus {
display: flex; // display: flex;
flex-wrap: nowrap; // flex-wrap: nowrap;
align-items: flex-start; // align-items: flex-start;
&.@{cascader-prefix-cls}-menu-empty { // &.@{cascader-prefix-cls}-menu-empty {
.@{cascader-prefix-cls}-menu { // .@{cascader-prefix-cls}-menu {
width: 100%; // width: 100%;
height: auto; // height: auto;
} // }
} // }
} // }
&-menu { // &-menu {
min-width: 111px; // min-width: 111px;
height: 180px; // height: 180px;
margin: 0; // margin: 0;
margin: -@dropdown-edge-child-vertical-padding 0; // margin: -@dropdown-edge-child-vertical-padding 0;
padding: @cascader-dropdown-edge-child-vertical-padding 0; // padding: @cascader-dropdown-edge-child-vertical-padding 0;
overflow: auto; // overflow: auto;
vertical-align: top; // vertical-align: top;
list-style: none; // list-style: none;
border-right: @border-width-base @border-style-base @cascader-menu-border-color-split; // border-right: @border-width-base @border-style-base @cascader-menu-border-color-split;
-ms-overflow-style: -ms-autohiding-scrollbar; // https://github.com/ant-design/ant-design/issues/11857 // -ms-overflow-style: -ms-autohiding-scrollbar; // https://github.com/ant-design/ant-design/issues/11857
&-item { // &-item {
display: flex; // display: flex;
flex-wrap: nowrap; // flex-wrap: nowrap;
align-items: center; // align-items: center;
padding: @cascader-dropdown-vertical-padding @control-padding-horizontal; // padding: @cascader-dropdown-vertical-padding @control-padding-horizontal;
overflow: hidden; // overflow: hidden;
line-height: @cascader-dropdown-line-height; // line-height: @cascader-dropdown-line-height;
white-space: nowrap; // white-space: nowrap;
text-overflow: ellipsis; // text-overflow: ellipsis;
cursor: pointer; // cursor: pointer;
transition: all 0.3s; // transition: all 0.3s;
&:hover { // &:hover {
background: @item-hover-bg; // background: @item-hover-bg;
} // }
&-disabled { // &-disabled {
color: @disabled-color; // color: @disabled-color;
cursor: not-allowed; // cursor: not-allowed;
&:hover { // &:hover {
background: transparent; // background: transparent;
} // }
} // }
.@{cascader-prefix-cls}-menu-empty & { // .@{cascader-prefix-cls}-menu-empty & {
color: @disabled-color; // color: @disabled-color;
cursor: default; // cursor: default;
pointer-events: none; // pointer-events: none;
} // }
&-active:not(&-disabled) { // &-active:not(&-disabled) {
&, // &,
&:hover { // &:hover {
font-weight: @select-item-selected-font-weight; // font-weight: @select-item-selected-font-weight;
background-color: @cascader-item-selected-bg; // background-color: @cascader-item-selected-bg;
} // }
} // }
&-content { // &-content {
flex: auto; // flex: auto;
} // }
&-expand &-expand-icon, // &-expand &-expand-icon,
&-loading-icon { // &-loading-icon {
margin-left: @padding-xss; // margin-left: @padding-xss;
color: @text-color-secondary; // color: @text-color-secondary;
font-size: 10px; // font-size: 10px;
.@{cascader-prefix-cls}-menu-item-disabled& { // .@{cascader-prefix-cls}-menu-item-disabled& {
color: @disabled-color; // color: @disabled-color;
} // }
} // }
&-keyword { // &-keyword {
color: @highlight-color; // color: @highlight-color;
} // }
} // }
} // }
} // }
@import './rtl'; // @import './rtl';

View File

@ -1,8 +1,172 @@
import '../../style/index.less'; // import '../../style/index.less';
import './index.less'; // import './index.less';
// style dependencies // // style dependencies
import '../../empty/style'; // import '../../empty/style';
import '../../select/style'; // import '../../select/style';
// deps-lint-skip: form // // deps-lint-skip: form
// deps-lint-skip-all
import { CSSInterpolation } from '@ant-design/cssinjs';
import {
DerivativeToken,
useStyleRegister,
useToken,
UseComponentStyleResult,
} from '../../_util/theme';
import { getStyle as getCheckboxStyle } from '../../checkbox/style';
interface CascaderToken extends DerivativeToken {
cascaderCls: string;
}
// =============================== Base ===============================
const genBaseStyle = (token: CascaderToken): CSSInterpolation => {
const { cascaderCls } = token;
const cascaderMenuItemCls = `${cascaderCls}-menu-item`;
const iconCls = `
${cascaderMenuItemCls}-expand ${cascaderMenuItemCls}-expand-icon,
${cascaderMenuItemCls}-loading-icon
`;
const itemPaddingVertical = Math.round(
(token.controlHeight - token.fontSize * token.lineHeight) / 2,
);
return [
// =====================================================
// == Control ==
// =====================================================
{
[cascaderCls]: {
width: 184, // FIXME: hardcode in v4
},
},
// =====================================================
// == Popup ==
// =====================================================
{
[`${cascaderCls}-dropdown`]: {
[cascaderCls]: {
// ================== Checkbox ==================
'&-checkbox': {
top: 0,
marginInlineEnd: token.paddingXS,
},
// ==================== Menu ====================
// >>> Menus
'&-menus': {
display: 'flex',
flexWrap: 'nowrap',
alignItems: 'flex-start',
[`&${cascaderCls}-menu-empty`]: {
[`${cascaderCls}-menu`]: {
width: '100%',
height: 'auto',
[cascaderMenuItemCls]: {
color: token.textColorDisabled,
cursor: 'default',
pointerEvents: 'none',
},
},
},
},
// >>> Menu
'&-menu': {
minWidth: 111, // FIXME: hardcode in v4
height: 180, // FIXME: hardcode in v4
margin: `-${token.paddingXS}px 0`,
padding: `${token.paddingXS}px 0`,
overflow: 'auto',
verticalAlign: 'top',
listStyle: 'none',
borderInlineEnd: `${token.borderWidth}px ${token.borderStyle} ${token.borderColorSplit}`,
'-ms-overflow-style': '-ms-autohiding-scrollbar', // https://github.com/ant-design/ant-design/issues/11857
'&-item': {
display: 'flex',
flexWrap: 'nowrap',
alignItems: 'center',
padding: `${itemPaddingVertical}px ${token.paddingSM}px`,
overflow: 'hidden',
lineHeight: token.lineHeight,
whiteSpace: 'nowrap',
textOverflow: 'ellipsis',
cursor: 'pointer',
transition: `all ${token.duration}`,
'&:hover': {
background: token.itemHoverBackground,
},
' &-disabled': {
color: token.textColorDisabled,
cursor: 'not-allowed',
'&:hover': {
background: 'transparent',
},
[iconCls]: {
color: token.textColorDisabled,
},
},
[`&-active:not(${cascaderMenuItemCls}-disabled)`]: {
[`&, &:hover`]: {
fontWeight: 600, // FIXME: hardcode
backgroundColor: token.itemActiveBackground,
},
},
'&-content': {
flex: 'auto',
},
[iconCls]: {
marginInlineStart: token.paddingXXS,
color: token.textColorSecondary,
fontSize: 10, // FIXME: hardcode in v4
},
'&-keyword': {
color: token.highlightColor,
},
},
},
},
},
},
// =====================================================
// == RTL ==
// =====================================================
{
[`${cascaderCls}-dropdown-rtl`]: {
direction: 'rtl',
},
},
];
};
// ============================== Export ==============================
export default function useStyle(prefixCls: string): UseComponentStyleResult {
const [theme, token, hashId] = useToken();
const cascaderToken: CascaderToken = {
...token,
cascaderCls: `.${prefixCls}`,
};
return [
useStyleRegister({ theme, token, hashId, path: [prefixCls] }, () => [
getCheckboxStyle(`${prefixCls}-checkbox`, token, hashId),
genBaseStyle(cascaderToken),
]),
hashId,
];
}