refactor: cssinjs alert (#34285)

* refactor: cssinjs alert

* fix: color

* fix: default

* fix: cs

* fix: ssr

* fix: ssr

* fix: ssr

* fix: ssr
This commit is contained in:
xrkffgg 2022-03-04 19:09:55 +08:00 committed by GitHub
parent fa90168c4c
commit 8b1e5a2ab5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 481 additions and 132 deletions

View File

@ -3,7 +3,10 @@ import type { DesignToken } from '.';
const defaultDesignToken: DesignToken = { const defaultDesignToken: DesignToken = {
primaryColor: '#1890ff', primaryColor: '#1890ff',
successColor: '#52c41a',
warningColor: '#faad14',
errorColor: '#ff4d4f', errorColor: '#ff4d4f',
infoColor: '#1890ff',
// https://github.com/ant-design/ant-design/issues/20210 // https://github.com/ant-design/ant-design/issues/20210
lineHeight: 1.5715, lineHeight: 1.5715,
@ -14,13 +17,19 @@ const defaultDesignToken: DesignToken = {
borderColor: new TinyColor({ h: 0, s: 0, v: 85 }).toHexString(), borderColor: new TinyColor({ h: 0, s: 0, v: 85 }).toHexString(),
easeInOut: `cubic-bezier(0.645, 0.045, 0.355, 1)`, easeInOut: `cubic-bezier(0.645, 0.045, 0.355, 1)`,
easeInOutCirc: `cubic-bezier(0.78, 0.14, 0.15, 0.86)`,
easeOutBack: `cubic-bezier(0.12, 0.4, 0.29, 1.46)`, easeOutBack: `cubic-bezier(0.12, 0.4, 0.29, 1.46)`,
fontSize: 14, fontSize: 14,
textColor: new TinyColor('#000').setAlpha(0.85).toRgbString(), textColor: new TinyColor('#000').setAlpha(0.85).toRgbString(),
textColorSecondary: new TinyColor('#000').setAlpha(0.45).toRgbString(),
textColorDisabled: new TinyColor('#000').setAlpha(0.25).toRgbString(), textColorDisabled: new TinyColor('#000').setAlpha(0.25).toRgbString(),
textColorInverse: '#fff', textColorInverse: '#fff',
headingColor: new TinyColor('#000').setAlpha(0.85).toRgbString(),
iconColorHover: new TinyColor('#000').setAlpha(0.75).toRgbString(),
itemHoverBackground: '#f5f5f5', itemHoverBackground: '#f5f5f5',
height: 32, height: 32,

View File

@ -9,20 +9,31 @@ export { resetComponent };
export interface DesignToken { export interface DesignToken {
primaryColor: string; primaryColor: string;
successColor: string;
warningColor: string;
errorColor: string; errorColor: string;
infoColor: string;
lineHeight: number; lineHeight: number;
borderWidth: number; borderWidth: number;
borderStyle: string; borderStyle: string;
borderRadius: number; borderRadius: number;
borderColor: string; borderColor: string;
easeInOut: string; easeInOut: string;
easeInOutCirc: string;
easeOutBack: string; easeOutBack: string;
fontSize: number; fontSize: number;
textColor: string; textColor: string;
textColorSecondary: string;
textColorDisabled: string; textColorDisabled: string;
textColorInverse: string; textColorInverse: string;
headingColor: string;
iconColorHover: string;
itemHoverBackground: string; itemHoverBackground: string;
height: number; height: number;

View File

@ -16,6 +16,9 @@ import getDataOrAriaProps from '../_util/getDataOrAriaProps';
import ErrorBoundary from './ErrorBoundary'; import ErrorBoundary from './ErrorBoundary';
import { replaceElement } from '../_util/reactNode'; import { replaceElement } from '../_util/reactNode';
// CSSINJS
import useStyle from './style';
export interface AlertProps { export interface AlertProps {
/** Type of Alert styles, options:`success`, `info`, `warning`, `error` */ /** Type of Alert styles, options:`success`, `info`, `warning`, `error` */
type?: 'success' | 'info' | 'warning' | 'error'; type?: 'success' | 'info' | 'warning' | 'error';
@ -87,8 +90,9 @@ const Alert: AlertInterface = ({
const [closed, setClosed] = React.useState(false); const [closed, setClosed] = React.useState(false);
const ref = React.useRef<HTMLElement>(); const ref = React.useRef<HTMLElement>();
const { getPrefixCls, direction } = React.useContext(ConfigContext); const { getPrefixCls, direction, iconPrefixCls } = React.useContext(ConfigContext);
const prefixCls = getPrefixCls('alert', customizePrefixCls); const prefixCls = getPrefixCls('alert', customizePrefixCls);
const [wrapSSR, hashId] = useStyle(prefixCls, iconPrefixCls);
const handleClose = (e: React.MouseEvent<HTMLButtonElement>) => { const handleClose = (e: React.MouseEvent<HTMLButtonElement>) => {
setClosed(true); setClosed(true);
@ -147,11 +151,12 @@ const Alert: AlertInterface = ({
[`${prefixCls}-rtl`]: direction === 'rtl', [`${prefixCls}-rtl`]: direction === 'rtl',
}, },
className, className,
hashId,
); );
const dataOrAriaProps = getDataOrAriaProps(props); const dataOrAriaProps = getDataOrAriaProps(props);
return ( return wrapSSR(
<CSSMotion <CSSMotion
visible={!closed} visible={!closed}
motionName={`${prefixCls}-motion`} motionName={`${prefixCls}-motion`}
@ -183,7 +188,7 @@ const Alert: AlertInterface = ({
{renderCloseIcon()} {renderCloseIcon()}
</div> </div>
)} )}
</CSSMotion> </CSSMotion>,
); );
}; };

View File

@ -1,155 +1,155 @@
@import '../../style/themes/index'; // @import '../../style/themes/index';
@import '../../style/mixins/index'; // @import '../../style/mixins/index';
@alert-prefix-cls: ~'@{ant-prefix}-alert'; // @alert-prefix-cls: ~'@{ant-prefix}-alert';
.@{alert-prefix-cls} { // .@{alert-prefix-cls} {
.reset-component(); // .reset-component();
position: relative; // position: relative;
display: flex; // display: flex;
align-items: center; // align-items: center;
padding: 8px 15px; // padding: 8px 15px;
word-wrap: break-word; // word-wrap: break-word;
border-radius: @border-radius-base; // border-radius: @border-radius-base;
&-content { // &-content {
flex: 1; // flex: 1;
min-width: 0; // min-width: 0;
} // }
&-icon { // &-icon {
margin-right: @margin-xs; // margin-right: @margin-xs;
} // }
&-description { // &-description {
display: none; // display: none;
font-size: @font-size-base; // font-size: @font-size-base;
line-height: @font-size-base + 8px; // line-height: @font-size-base + 8px;
} // }
&-success { // &-success {
background-color: @alert-success-bg-color; // background-color: @alert-success-bg-color;
border: @border-width-base @border-style-base @alert-success-border-color; // border: @border-width-base @border-style-base @alert-success-border-color;
.@{alert-prefix-cls}-icon { // .@{alert-prefix-cls}-icon {
color: @alert-success-icon-color; // color: @alert-success-icon-color;
} // }
} // }
&-info { // &-info {
background-color: @alert-info-bg-color; // background-color: @alert-info-bg-color;
border: @border-width-base @border-style-base @alert-info-border-color; // border: @border-width-base @border-style-base @alert-info-border-color;
.@{alert-prefix-cls}-icon { // .@{alert-prefix-cls}-icon {
color: @alert-info-icon-color; // color: @alert-info-icon-color;
} // }
} // }
&-warning { // &-warning {
background-color: @alert-warning-bg-color; // background-color: @alert-warning-bg-color;
border: @border-width-base @border-style-base @alert-warning-border-color; // border: @border-width-base @border-style-base @alert-warning-border-color;
.@{alert-prefix-cls}-icon { // .@{alert-prefix-cls}-icon {
color: @alert-warning-icon-color; // color: @alert-warning-icon-color;
} // }
} // }
&-error { // &-error {
background-color: @alert-error-bg-color; // background-color: @alert-error-bg-color;
border: @border-width-base @border-style-base @alert-error-border-color; // border: @border-width-base @border-style-base @alert-error-border-color;
.@{alert-prefix-cls}-icon { // .@{alert-prefix-cls}-icon {
color: @alert-error-icon-color; // color: @alert-error-icon-color;
} // }
.@{alert-prefix-cls}-description > pre { // .@{alert-prefix-cls}-description > pre {
margin: 0; // margin: 0;
padding: 0; // padding: 0;
} // }
} // }
&-action { // &-action {
margin-left: @margin-xs; // margin-left: @margin-xs;
} // }
&-close-icon { // &-close-icon {
margin-left: @margin-xs; // margin-left: @margin-xs;
padding: 0; // padding: 0;
overflow: hidden; // overflow: hidden;
font-size: @font-size-sm; // font-size: @font-size-sm;
line-height: @font-size-sm; // line-height: @font-size-sm;
background-color: transparent; // background-color: transparent;
border: none; // border: none;
outline: none; // outline: none;
cursor: pointer; // cursor: pointer;
.@{iconfont-css-prefix}-close { // .@{iconfont-css-prefix}-close {
color: @alert-close-color; // color: @alert-close-color;
transition: color 0.3s; // transition: color 0.3s;
&:hover { // &:hover {
color: @alert-close-hover-color; // color: @alert-close-hover-color;
} // }
} // }
} // }
&-close-text { // &-close-text {
color: @alert-close-color; // color: @alert-close-color;
transition: color 0.3s; // transition: color 0.3s;
&:hover { // &:hover {
color: @alert-close-hover-color; // color: @alert-close-hover-color;
} // }
} // }
&-with-description { // &-with-description {
align-items: flex-start; // align-items: flex-start;
padding: @alert-with-description-padding; // padding: @alert-with-description-padding;
} // }
&-with-description&-no-icon { // &-with-description&-no-icon {
padding: @alert-with-description-no-icon-padding-vertical 15px; // padding: @alert-with-description-no-icon-padding-vertical 15px;
} // }
&-with-description &-icon { // &-with-description &-icon {
margin-right: @alert-with-description-padding-vertical; // margin-right: @alert-with-description-padding-vertical;
font-size: @alert-with-description-icon-size; // font-size: @alert-with-description-icon-size;
} // }
&-with-description &-message { // &-with-description &-message {
display: block; // display: block;
margin-bottom: 4px; // margin-bottom: 4px;
color: @alert-message-color; // color: @alert-message-color;
font-size: @font-size-lg; // font-size: @font-size-lg;
} // }
&-message { // &-message {
color: @alert-message-color; // color: @alert-message-color;
} // }
&-with-description &-description { // &-with-description &-description {
display: block; // display: block;
} // }
&&-motion-leave { // &&-motion-leave {
overflow: hidden; // overflow: hidden;
opacity: 1; // opacity: 1;
transition: max-height 0.3s @ease-in-out-circ, opacity 0.3s @ease-in-out-circ, // transition: max-height 0.3s @ease-in-out-circ, opacity 0.3s @ease-in-out-circ,
padding-top 0.3s @ease-in-out-circ, padding-bottom 0.3s @ease-in-out-circ, // padding-top 0.3s @ease-in-out-circ, padding-bottom 0.3s @ease-in-out-circ,
margin-bottom 0.3s @ease-in-out-circ; // margin-bottom 0.3s @ease-in-out-circ;
} // }
&&-motion-leave-active { // &&-motion-leave-active {
max-height: 0; // max-height: 0;
margin-bottom: 0 !important; // margin-bottom: 0 !important;
padding-top: 0; // padding-top: 0;
padding-bottom: 0; // padding-bottom: 0;
opacity: 0; // opacity: 0;
} // }
&-banner { // &-banner {
margin-bottom: 0; // margin-bottom: 0;
border: 0; // border: 0;
border-radius: 0; // border-radius: 0;
} // }
} // }
@import './rtl'; // @import './rtl';

View File

@ -1,2 +1,326 @@
import '../../style/index.less'; // import '../../style/index.less';
import './index.less'; // import './index.less';
// deps-lint-skip-all
import { generate } from '@ant-design/colors';
import { CSSInterpolation, CSSObject } from '@ant-design/cssinjs';
import {
DerivativeToken,
useStyleRegister,
useToken,
resetComponent,
UseComponentStyleResult,
} from '../../_util/theme';
// FIXME: missing token
type AlertToken = DerivativeToken & {
alertMessageColor: string,
alertCloseColor: string,
alertCloseHoverColor: string,
alertInfoBgColor: string,
alertInfoIconColor: string,
alertInfoBorderColor: string,
alertSuccessBgColor: string,
alertSuccessIconColor: string,
alertSuccessBorderColor: string,
alertWarningBgColor: string,
alertWarningIconColor: string,
alertWarningBorderColor: string,
alertErrorBgColor: string,
alertErrorIconColor: string,
alertErrorBorderColor: string,
alertWithDescriptionIconSize: number,
alertWithDescriptionPadding: string,
alertWithDescriptionPaddingVertical: number,
alertWithDescriptionNoIconPaddingVertical: number,
}
const genAlertTypeStyle = (bgColor: string, borderColor: string, iconColor: string, token: AlertToken, alertCls: string): CSSObject => ({
backgroundColor: bgColor,
border: `${token.borderWidth}px ${token.borderStyle} ${borderColor}`,
[`${alertCls}-icon`]: {
color: iconColor,
},
});
export const genBaseStyle = (alertCls: string, token: AlertToken): CSSObject => {
const {
duration,
marginXS,
fontSize,
fontSizeLG,
borderRadius,
easeInOutCirc,
alertMessageColor,
alertWithDescriptionIconSize,
alertWithDescriptionPaddingVertical,
alertWithDescriptionNoIconPaddingVertical,
alertWithDescriptionPadding,
} = token;
return {
[alertCls]: {
...resetComponent(token),
position: 'relative',
display: 'flex',
alignItems: 'center',
padding: '8px 15px',
wordWrap: 'break-word',
borderRadius,
[`${alertCls}-content`]: {
flex: 1,
minWidth: 0,
},
[`${alertCls}-icon`]: {
marginInlineEnd: marginXS,
},
[`&-description`]: {
display: 'none',
fontSize,
lineHeight: `${fontSize + 8}px`,
},
'&-message': {
color: alertMessageColor,
},
'&&-motion-leave': {
overflow: 'hidden',
opacity: 1,
transition: `max-height ${duration} ${easeInOutCirc}, opacity ${duration} ${easeInOutCirc},
padding-top ${duration} ${easeInOutCirc}, padding-bottom ${duration} ${easeInOutCirc},
margin-bottom ${duration} ${easeInOutCirc}`,
},
'&&-motion-leave-active': {
maxHeight: 0,
marginBottom: '0 !important',
paddingTop: 0,
paddingBottom: 0,
opacity: 0,
},
},
[`${alertCls}-with-description`]: {
alignItems: 'flex-start',
padding: alertWithDescriptionPadding,
[`&${alertCls}-no-icon`]: {
padding: `${alertWithDescriptionNoIconPaddingVertical}px 15px`,
},
[`${alertCls}-icon`]: {
marginInlineEnd: alertWithDescriptionPaddingVertical,
fontSize: alertWithDescriptionIconSize,
},
[`${alertCls}-message`]: {
display: 'block',
marginBottom: '4px',
color: alertMessageColor,
fontSize: fontSizeLG,
},
[`${alertCls}-description`]: {
display: 'block',
},
},
[`${alertCls}-banner`]: {
marginBottom: 0,
border: '0 !important',
borderRadius: 0,
},
};
};
export const genTypeStyle = (alertCls: string, token: AlertToken): CSSObject => {
const {
alertInfoBgColor,
alertInfoIconColor,
alertInfoBorderColor,
alertSuccessBgColor,
alertSuccessIconColor,
alertSuccessBorderColor,
alertWarningBgColor,
alertWarningIconColor,
alertWarningBorderColor,
alertErrorBgColor,
alertErrorIconColor,
alertErrorBorderColor,
} = token;
return {
[alertCls]: {
'&-success': genAlertTypeStyle(alertSuccessBgColor, alertSuccessBorderColor, alertSuccessIconColor, token, alertCls),
'&-info': genAlertTypeStyle(alertInfoBgColor, alertInfoBorderColor, alertInfoIconColor, token, alertCls),
'&-warning': genAlertTypeStyle(alertWarningBgColor, alertWarningBorderColor, alertWarningIconColor, token, alertCls),
'&-error': {
...genAlertTypeStyle(alertErrorBgColor, alertErrorBorderColor, alertErrorIconColor, token, alertCls),
[`${alertCls}-description > pre`]: {
margin: 0,
padding: 0,
},
},
},
};
};
export const genActionStyle = (alertCls: string, iconPrefixCls: string, token: AlertToken): CSSObject => {
const {
duration,
marginXS,
fontSizeSM,
alertCloseColor,
alertCloseHoverColor,
} = token;
return {
[alertCls]: {
[`&-action`]: {
marginInlineStart: marginXS,
},
[`${alertCls}-close-icon`]: {
marginInlineStart: marginXS,
padding: 0,
overflow: 'hidden',
fontSize: fontSizeSM,
lineHeight: `${fontSizeSM}px`,
backgroundColor: 'transparent',
border: 'none',
outline: 'none',
cursor: 'pointer',
[`.${iconPrefixCls}-close`]: {
color: alertCloseColor,
transition: `color ${duration}`,
'&:hover': {
color: alertCloseHoverColor,
},
},
},
'&-close-text': {
color: alertCloseColor,
transition: `color ${duration}`,
'&:hover': {
color: alertCloseHoverColor,
},
},
},
};
};
export const genRTLStyle = (alertCls: string, token: AlertToken): CSSObject => {
const {
alertWithDescriptionIconSize,
alertWithDescriptionPaddingVertical,
} = token;
return {
[alertCls]: {
'&&-rtl': {
direction: 'rtl',
},
'&-with-description': {
[`${alertCls}-rtl&`]: {
paddingRight: alertWithDescriptionIconSize,
paddingLeft: alertWithDescriptionPaddingVertical,
},
},
},
};
};
export const genAlertStyle = (
prefixCls: string,
iconPrefixCls: string,
token: DerivativeToken,
): CSSInterpolation => {
const alertCls = `.${prefixCls}`;
const alertMessageColor = token.headingColor;
const alertCloseColor = token.textColorSecondary;
const alertCloseHoverColor = token.iconColorHover;
// FIXME
const alertWithDescriptionIconSize = 24;
const alertWithDescriptionPaddingVertical = token.padding - 1;
const alertWithDescriptionNoIconPaddingVertical = token.padding - 1;
const alertWithDescriptionPadding = `${alertWithDescriptionPaddingVertical}px 15px ${alertWithDescriptionNoIconPaddingVertical}px ${alertWithDescriptionIconSize}px`;
// FIXME
const infoColors = generate(token.infoColor);
const alertInfoBgColor = infoColors[0];
const alertInfoIconColor = token.infoColor;
const alertInfoBorderColor = infoColors[2];
const successColors = generate(token.successColor);
const alertSuccessBgColor = successColors[0];
const alertSuccessIconColor = token.successColor;
const alertSuccessBorderColor = successColors[2];
const warningColors = generate(token.warningColor);
const alertWarningBgColor = warningColors[0];
const alertWarningIconColor = token.warningColor;
const alertWarningBorderColor = warningColors[2];
const errorColors = generate(token.errorColor);
const alertErrorBgColor = errorColors[0];
const alertErrorIconColor = token.errorColor;
const alertErrorBorderColor = errorColors[2];
const alertToken = {
...token,
alertInfoBgColor,
alertInfoIconColor,
alertInfoBorderColor,
alertSuccessBgColor,
alertSuccessIconColor,
alertSuccessBorderColor,
alertWarningBgColor,
alertWarningIconColor,
alertWarningBorderColor,
alertErrorBgColor,
alertErrorIconColor,
alertErrorBorderColor,
alertMessageColor,
alertCloseColor,
alertCloseHoverColor,
alertWithDescriptionIconSize,
alertWithDescriptionPaddingVertical,
alertWithDescriptionNoIconPaddingVertical,
alertWithDescriptionPadding,
};
return [
genBaseStyle(alertCls, alertToken),
genTypeStyle(alertCls, alertToken),
genActionStyle(alertCls, iconPrefixCls, alertToken),
genRTLStyle(alertCls, alertToken),
];
};
export default function useStyle(prefixCls: string, iconPrefixCls: string): UseComponentStyleResult {
const [theme, token, hashId] = useToken();
return [
useStyleRegister({ theme, token, hashId, path: [prefixCls] }, () => [
genAlertStyle(prefixCls, iconPrefixCls, token),
]),
hashId,
];
}