From 397fa6172da43d54ea283ccffb7da078ee729d84 Mon Sep 17 00:00:00 2001 From: PCCCCCCC Date: Tue, 17 May 2022 20:15:34 +0800 Subject: [PATCH] Refactor:Component Notification Less to cssinjs (#35559) * refactor: complete the basic less refactor * refactor: complete the Notification part of placement * refactor: complete the Notification part of RTL * refactor: add necessary FIXME for Notification * chore: remove useless code for Notification * style: remove useless code * refactor: fix the float style issue --- components/notification/style/index.tsx | 291 +++++++++++++++++++- components/notification/style/placement.ts | 85 ++++++ components/notification/useNotification.tsx | 6 +- 3 files changed, 365 insertions(+), 17 deletions(-) create mode 100644 components/notification/style/placement.ts diff --git a/components/notification/style/index.tsx b/components/notification/style/index.tsx index 2e5ac073de..3b3501371b 100644 --- a/components/notification/style/index.tsx +++ b/components/notification/style/index.tsx @@ -1,28 +1,289 @@ // deps-lint-skip-all -import { genComponentStyleHook } from '../../_util/theme'; +// import '../../style/index.less'; +// import './index.less'; + +import type { CSSObject } from '@ant-design/cssinjs'; +import { Keyframes } from '@ant-design/cssinjs'; +import { TinyColor } from '@ctrl/tinycolor'; import type { FullToken, GenerateStyle } from '../../_util/theme'; +import { genComponentStyleHook, mergeToken, resetComponent } from '../../_util/theme'; +import genNotificationPlacementStyle from './placement'; /** Component only token. Which will handle additional calculation of alias token */ export interface ComponentToken {} -export interface NotificationToken extends FullToken<'Notification'> {} +export interface NotificationToken extends FullToken<'Notification'> { + // default.less variables + zIndexNotification: number; + notificationBg: string; + notificationPaddingVertical: number; + notificationPaddingHorizontal: number; + // index.less variables + popoverBackground: string; + notificationWidth: number; + notificationPadding: string; + notificationMarginBottom: number; + notificationMarginEdge: number; +} + +const genNotificationStyle: GenerateStyle = token => { + const { + iconCls, + componentCls, // .ant-notification + colorTextSecondary, + notificationWidth, + boxShadow, + fontSizeLG, + notificationMarginBottom, + radiusBase, + notificationPaddingHorizontal, + colorSuccess, + colorInfo, + colorWarning, + colorError, + colorTextHeading, + notificationBg, + notificationPadding, + notificationMarginEdge, + zIndexNotification, + motionDurationMid, + motionEaseInOut, + fontSizeBase, + lineHeight, + } = token; + + const notificationFadeIn = new Keyframes('antNotificationFadeIn', { + '0%': { + left: { + _skip_check_: true, + value: notificationWidth, + }, + opacity: 0, // FIXME: hardcode in v4 + }, + + '100%': { + left: { + _skip_check_: true, + value: 0, // FIXME: hardcode in v4 + }, + opacity: 1, // FIXME: hardcode in v4 + }, + }); + + const notificationFadeOut = new Keyframes('antNotificationFadeOut', { + '0%': { + maxHeight: 150, // FIXME: hardcode in v4 + marginBottom: notificationMarginBottom, + opacity: 1, // FIXME: hardcode in v4 + }, -// =============================== Base =============================== -const genBaseStyle: GenerateStyle = token => { - const { componentCls } = token; + '100%': { + maxHeight: 0, // FIXME: hardcode in v4 + marginBottom: 0, // FIXME: hardcode in v4 + paddingTop: 0, // FIXME: hardcode in v4 + paddingBottom: 0, // FIXME: hardcode in v4 + opacity: 0, // FIXME: hardcode in v4 + }, + }); return { - [componentCls]: {}, + [componentCls]: { + ...resetComponent(token), + + position: 'fixed', + zIndex: zIndexNotification, + // marginRight: notificationMarginEdge, + marginInlineEnd: notificationMarginEdge, + + [`${componentCls}-close-icon`]: { + fontSize: fontSizeBase, + cursor: 'pointer', + }, + + [`${componentCls}-hook-holder`]: { + position: 'relative', + }, + + [`${componentCls}-notice`]: { + position: 'relative', + width: notificationWidth, + maxWidth: `calc(100vw - ${notificationMarginEdge * 2}px)`, // FIXME: hardcode in v4 + marginBottom: notificationMarginBottom, + // marginLeft: 'auto', + marginInlineStart: 'auto', + padding: notificationPadding, + overflow: 'hidden', + lineHeight, + wordWrap: 'break-word', + background: notificationBg, + borderRadius: radiusBase, + boxShadow, + + [`&-message`]: { + marginBottom: 8, // FIXME: hardcode in v4 + color: colorTextHeading, + fontSize: fontSizeLG, + lineHeight: '24px', // FIXME: hardcode in v4 + + // https://github.com/ant-design/ant-design/issues/5846#issuecomment-296244140 + [`&-single-line-auto-margin`]: { + display: 'block', + width: `calc(${notificationWidth} ${ + notificationPaddingHorizontal * 2 + } 24px 48px 100%)`, // FIXME: hardcode in v4 + maxWidth: 4, // FIXME: hardcode in v4 + backgroundColor: 'transparent', + pointerEvents: 'none', + + '&::before': { + display: 'block', + content: '""', + }, + }, + }, + + '&-description': { + fontSize: fontSizeBase, + }, + + [`&-closable ${componentCls}-notice-message`]: { + paddingInlineEnd: 24, // FIXME: hardcode in v4 + }, + + [`&-with-icon ${componentCls}-notice-message`]: { + marginBottom: 4, // FIXME: hardcode in v4 + marginInlineStart: 48, // FIXME: hardcode in v4 + fontSize: fontSizeLG, + }, + + [`&-with-icon ${componentCls}-notice-description`]: { + marginInlineStart: 48, // FIXME: hardcode in v4 + fontSize: fontSizeBase, + }, + + // Icon & color style in different selector level + // https://github.com/ant-design/ant-design/issues/16503 + // https://github.com/ant-design/ant-design/issues/15512 + '&-icon': { + position: 'absolute', + marginInlineStart: 4, // FIXME: hardcode in v4 + fontSize: 24, // FIXME: hardcode in v4 + lineHeight: '24px', // FIXME: hardcode in v4 + + // icon-font + [`&-success${iconCls}`]: { + color: colorSuccess, + }, + [`&-info${iconCls}`]: { + color: colorInfo, + }, + [`&-warning${iconCls}`]: { + color: colorWarning, + }, + [`&-error${iconCls}`]: { + color: colorError, + }, + }, + + '&-close': { + position: 'absolute', + top: 16, // FIXME: hardcode in v4 + insetInlineEnd: 22, // FIXME: hardcode in v4 + color: colorTextSecondary, + outline: 'none', + + '&:hover': { + // FIXME: hard code in v4, shade(@text-color-secondary, 40%) + color: new TinyColor(colorTextSecondary).setAlpha(0.4).toRgbString(), + }, + }, + + '&-btn': { + float: 'right', + marginTop: 16, // FIXME: hardcode in v4 + }, + }, + + [`&${componentCls}-top, &${componentCls}-bottom`]: { + [`${componentCls}-notice`]: { + // marginRight: 'auto', + // marginLeft: 'auto', + marginInline: 'auto auto', + }, + }, + + [`&${componentCls}-topLeft, &${componentCls}-bottomLeft`]: { + [`${componentCls}-notice`]: { + // marginRight: 'auto', + marginInlineEnd: 'auto', + // marginLeft: 0, + marginInlineStart: 0, // FIXME: hardcode in v4 + }, + }, + + // animation + [`${componentCls}-fade-enter, ${componentCls}-fade-appear`]: { + animationDuration: '0.24s', // FIXME: hardcode in v4 + animationTimingFunction: motionEaseInOut, + animationFillMode: 'both', + + opacity: 0, // FIXME: hardcode in v4 + animationPlayState: 'paused', + }, + + [`${componentCls}-fade-leave`]: { + animationTimingFunction: motionEaseInOut, + animationFillMode: 'both', + + animationDuration: motionDurationMid, + animationPlayState: 'paused', + }, + + [`${componentCls}-fade-enter${componentCls}-fade-enter-active, ${componentCls}-fade-appear${componentCls}-fade-appear-active`]: + { + animationName: notificationFadeIn, + animationPlayState: 'running', + }, + + [`${componentCls}-fade-leave${componentCls}-fade-leave-active`]: { + animationName: notificationFadeOut, + animationPlayState: 'running', + }, + + // placement + ...genNotificationPlacementStyle(token), + + // RTL + '&-rtl': { + direction: 'rtl', + + [`${componentCls}-notice-btn`]: { + float: 'left', + }, + }, + }, }; }; // ============================== Export ============================== -export default genComponentStyleHook( - 'Notification', - token => [genBaseStyle(token)], - token => { - // Not error in lint tmp - console.log('>>', !!token); - return {}; - }, -); +export default genComponentStyleHook('Notification', token => { + const { colorBgComponent, zIndexPopupBase } = token; + const notificationPaddingVertical = 16; // FIXME: hardcode in v4 + const notificationPaddingHorizontal = 24; // FIXME: hardcode in v4 + + const notificationToken = mergeToken(token, { + // default.less variables + zIndexNotification: zIndexPopupBase + 50, // FIXME: hardcode in v4 + notificationBg: colorBgComponent, + notificationPaddingVertical, + notificationPaddingHorizontal, + // index.less variables + popoverBackground: colorBgComponent, + notificationWidth: 384, // FIXME: hardcode in v4 + notificationPadding: `${notificationPaddingVertical}px ${notificationPaddingHorizontal}px`, + notificationMarginBottom: 16, // FIXME: hardcode in v4 + notificationMarginEdge: 24, // FIXME: hardcode in v4 + }); + + return [genNotificationStyle(notificationToken)]; +}); diff --git a/components/notification/style/placement.ts b/components/notification/style/placement.ts new file mode 100644 index 0000000000..974deb786a --- /dev/null +++ b/components/notification/style/placement.ts @@ -0,0 +1,85 @@ +import type { CSSObject } from '@ant-design/cssinjs'; +import { Keyframes } from '@ant-design/cssinjs'; +import type { GenerateStyle } from '../../_util/theme'; +import type { NotificationToken } from '.'; + +const genNotificationPlacementStyle: GenerateStyle = token => { + const { componentCls, notificationWidth, notificationMarginEdge } = token; + + const notificationTopFadeIn = new Keyframes('antNotificationTopFadeIn', { + '0%': { + marginTop: '-100%', // FIXME: hardcode in v4 + opacity: 0, // FIXME: hardcode in v4 + }, + + '100%': { + marginTop: 0, // FIXME: hardcode in v4 + opacity: 1, // FIXME: hardcode in v4 + }, + }); + + const notificationBottomFadeIn = new Keyframes('antNotificationBottomFadeIn', { + '0%': { + marginBottom: '-100%', // FIXME: hardcode in v4 + opacity: 0, // FIXME: hardcode in v4 + }, + + '100%': { + marginBottom: 0, // FIXME: hardcode in v4 + opacity: 1, // FIXME: hardcode in v4 + }, + }); + + const notificationLeftFadeIn = new Keyframes('antNotificationLeftFadeIn', { + '0%': { + right: { + _skip_check_: true, + value: notificationWidth, + }, + opacity: 0, // FIXME: hardcode in v4 + }, + + '100%': { + right: { + _skip_check_: true, + value: 0, // FIXME: hardcode in v4 + }, + opacity: 1, // FIXME: hardcode in v4 + }, + }); + + return { + [`&${componentCls}-top, &${componentCls}-bottom`]: { + // marginRight: 0, + // marginLeft: 0, + marginInline: '0 0', // FIXME: hardcode in v4 + }, + + [`&${componentCls}-top`]: { + [`${componentCls}-fade-enter${componentCls}-fade-enter-active, ${componentCls}-fade-appear${componentCls}-fade-appear-active`]: + { + animationName: notificationTopFadeIn, + }, + }, + + [`&${componentCls}-bottom`]: { + [`${componentCls}-fade-enter${componentCls}-fade-enter-active, ${componentCls}-fade-appear${componentCls}-fade-appear-active`]: + { + animationName: notificationBottomFadeIn, + }, + }, + + [`&${componentCls}-topLeft, &${componentCls}-bottomLeft`]: { + // marginRight: 0, + marginInlineEnd: 0, // FIXME: hardcode in v4 + // marginLeft: notificationMarginEdge, + marginInlineStart: notificationMarginEdge, + + [`${componentCls}-fade-enter${componentCls}-fade-enter-active, ${componentCls}-fade-appear${componentCls}-fade-appear-active`]: + { + animationName: notificationLeftFadeIn, + }, + }, + }; +}; +export default genNotificationPlacementStyle; diff --git a/components/notification/useNotification.tsx b/components/notification/useNotification.tsx index b58e317cf4..bb23677b1c 100644 --- a/components/notification/useNotification.tsx +++ b/components/notification/useNotification.tsx @@ -52,13 +52,15 @@ const Holder = React.forwardRef((props, ref) => { const { getPrefixCls, getPopupContainer } = React.useContext(ConfigContext); const prefixCls = staticPrefixCls || getPrefixCls('notification'); - const [, hashId] = useStyle(prefixCls); // =============================== Style =============================== const getStyle = (placement: NotificationPlacement) => getPlacementStyle(placement, top ?? DEFAULT_OFFSET, bottom ?? DEFAULT_OFFSET); - const getClassName = () => classNames(hashId, rtl ? `${prefixCls}-rtl` : ''); + // Style + const [, hashId] = useStyle(prefixCls); + + const getClassName = () => classNames(hashId, { [`${prefixCls}-rtl`]: rtl }); // ============================== Motion =============================== const getNotificationMotion = () => getMotion(prefixCls);