From be18ea659b4771738acd4176c862c92fc3e2c6c2 Mon Sep 17 00:00:00 2001 From: Zack Chang <73225408+jrr997@users.noreply.github.com> Date: Thu, 24 Mar 2022 22:12:41 +0800 Subject: [PATCH 01/11] chore: update test cases of Spin (#34695) --- .../__snapshots__/index.test.js.snap | 31 ++++++------------- components/spin/__tests__/index.test.js | 4 +-- 2 files changed, 11 insertions(+), 24 deletions(-) diff --git a/components/spin/__tests__/__snapshots__/index.test.js.snap b/components/spin/__tests__/__snapshots__/index.test.js.snap index 27a4496000..06af70fc48 100644 --- a/components/spin/__tests__/__snapshots__/index.test.js.snap +++ b/components/spin/__tests__/__snapshots__/index.test.js.snap @@ -1,16 +1,9 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Spin if indicator set null should not be render default indicator 1`] = ` - -
- +
`; exports[`Spin rtl render component should be rendered correctly in RTL direction 1`] = ` @@ -47,17 +40,11 @@ exports[`Spin should render custom indicator when it's set 1`] = ` `; exports[`Spin should support static method Spin.setDefaultIndicator 1`] = ` - -
- -
-
+ +
`; diff --git a/components/spin/__tests__/index.test.js b/components/spin/__tests__/index.test.js index 641adc7eb5..3cb6b8b99b 100644 --- a/components/spin/__tests__/index.test.js +++ b/components/spin/__tests__/index.test.js @@ -33,13 +33,13 @@ describe('Spin', () => { it('if indicator set null should not be render default indicator', () => { const wrapper = mount(); - expect(wrapper).toMatchSnapshot(); + expect(wrapper.render()).toMatchSnapshot(); }); it('should support static method Spin.setDefaultIndicator', () => { Spin.setDefaultIndicator(); const wrapper = mount(); - expect(wrapper).toMatchSnapshot(); + expect(wrapper.render()).toMatchSnapshot(); Spin.setDefaultIndicator(null); }); From 6451b2ea04d172e407121ba6d0850f3b7aaf3152 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=91=E9=9B=A8?= Date: Thu, 24 Mar 2022 23:33:51 +0800 Subject: [PATCH 02/11] feat: cssinjs for drawer (#34656) --- components/drawer/index.tsx | 15 +- components/drawer/style/index.less | 12 +- components/drawer/style/index.tsx | 341 ++++++++++++++++++++++++++++- 3 files changed, 356 insertions(+), 12 deletions(-) diff --git a/components/drawer/index.tsx b/components/drawer/index.tsx index d5d8755a25..5aae5fde37 100644 --- a/components/drawer/index.tsx +++ b/components/drawer/index.tsx @@ -4,6 +4,9 @@ import CloseOutlined from '@ant-design/icons/CloseOutlined'; import classNames from 'classnames'; import { ConfigContext } from '../config-provider'; import { tuple } from '../_util/type'; +// CSSINJS +import useStyle from './style'; + import useForceUpdate from '../_util/hooks/useForceUpdate'; type DrawerRef = { @@ -109,8 +112,13 @@ const Drawer = React.forwardRef( const parentDrawer = React.useContext(DrawerContext); const destroyClose = React.useRef(false); - const { getPopupContainer, getPrefixCls, direction } = React.useContext(ConfigContext); + const { getPopupContainer, getPrefixCls, direction, iconPrefixCls } = + React.useContext(ConfigContext); const prefixCls = getPrefixCls('drawer', customizePrefixCls); + + // Style + const [wrapSSR, hashId] = useStyle(prefixCls, iconPrefixCls); + const getContainer = // 有可能为 false,所以不能直接判断 customizeGetContainer === undefined && getPopupContainer @@ -297,10 +305,11 @@ const Drawer = React.forwardRef( [`${prefixCls}-rtl`]: direction === 'rtl', }, className, + hashId, ); const offsetStyle = mask ? getOffsetStyle() : {}; - return ( + return wrapSSR( ( > {renderBody()} - + , ); }, ); diff --git a/components/drawer/style/index.less b/components/drawer/style/index.less index 77efacf49d..3acac2551b 100644 --- a/components/drawer/style/index.less +++ b/components/drawer/style/index.less @@ -1,6 +1,6 @@ -@import '../../style/themes/index'; -@import '../../style/mixins/index'; -@import './drawer'; -@import './rtl'; - -.popover-customize-bg(@drawer-prefix-cls, @popover-background); +//@import '../../style/themes/index'; +//@import '../../style/mixins/index'; +//@import './drawer'; +//@import './rtl'; +// +//.popover-customize-bg(@drawer-prefix-cls, @popover-background); diff --git a/components/drawer/style/index.tsx b/components/drawer/style/index.tsx index 1f18f88462..0d71d25a46 100644 --- a/components/drawer/style/index.tsx +++ b/components/drawer/style/index.tsx @@ -1,3 +1,338 @@ -// deps-lint-skip: empty -import '../../style/index.less'; -import './index.less'; +// deps-lint-skip-all +import { CSSObject, Keyframes } from '@ant-design/cssinjs'; +import { TinyColor } from '@ctrl/tinycolor'; +import { + DerivativeToken, + GenerateStyle, + UseComponentStyleResult, + useStyleRegister, + useToken, +} from '../../_util/theme'; + +export interface DrawerToken extends DerivativeToken { + prefixCls: string; + iconPrefixCls: string; + drawerHeaderCloseSize: number; + shadow1Right: string; + shadow1Left: string; + shadow1Up: string; + shadow1Down: string; + drawerTitleLineHeight: number; + closeRight: number; + white: string; + black: string; + paddingMd: number; + modalFooterPaddingVertical: number; + modalFooterPaddingHorizontal: number; + hoverColor: string; + borderColorSplit: string; + borderStyle: string; + textColorSecondary: string; + motionEaseOut: string; + drawerPrefixCls: string; +} + +const antdDrawerFadeIn = new Keyframes('antNoWrapperZoomBadgeIn', { + '0%': { opacity: 0 }, + '100%': { opacity: 1 }, +}); + +// =============================== Base =============================== +const genBaseStyle: GenerateStyle = ( + token: DrawerToken, + hashId: string, +): CSSObject => { + const { + drawerPrefixCls, + motionEaseOut, + motionDurationSlow, + fontSizeLG, + drawerTitleLineHeight, + white, + closeRight, + paddingLG, + paddingMd, + lineWidth, + borderStyle, + radiusBase, + fontSize, + lineHeight, + modalFooterPaddingVertical, + modalFooterPaddingHorizontal, + borderColorSplit, + zIndexPopup, + colorText, + textColorSecondary, + hoverColor, + } = token; + + return { + [`${drawerPrefixCls}`]: { + // FIXME: Seems useless? + // @drawer-header-close-padding: ceil(((drawerHeaderCloseSize - @font-size-lg) / 2)); + position: 'fixed', + zIndex: zIndexPopup, + width: 0, + height: '100%', + transition: `width 0s ease ${motionDurationSlow}, height 0s ease ${motionDurationSlow}`, + [`${drawerPrefixCls}-content-wrapper`]: { + position: 'absolute', + width: '100%', + height: '100%', + transition: `transform ${motionDurationSlow} ${motionEaseOut},box-shadow ${motionDurationSlow} ${motionEaseOut}`, + [`${drawerPrefixCls}-content`]: { + width: '100%', + height: '100%', + position: 'relative', + zIndex: 1, + overflow: 'auto', + backgroundColor: white, + backgroundClip: `padding-box`, + border: 0, + [`${drawerPrefixCls}-wrapper-body`]: { + display: 'flex', + flexFlow: 'column nowrap', + width: '100%', + height: '100%', + [`${drawerPrefixCls}-header`]: { + position: 'relative', + display: 'flex', + alignItems: 'center', + justifyContent: 'space-between', + padding: `${paddingMd}px ${paddingLG}px`, // FIXME px + color: colorText, + background: white, + borderBottom: `${lineWidth}px ${borderStyle} ${borderColorSplit}`, // FIXME px + borderRadius: `${radiusBase}px ${radiusBase}px 0 0`, // FIXME px + + [`${drawerPrefixCls}-header-title`]: { + display: 'flex', + flex: 1, + alignItems: 'center', + justifyContent: 'space-between', + [`${drawerPrefixCls}-title`]: { + flex: 1, + margin: 0, + color: colorText, + fontWeight: 500, + fontSize: fontSizeLG, + lineHeight: drawerTitleLineHeight, + }, + [`${drawerPrefixCls}-close`]: { + display: 'inline-block', + marginRight: closeRight, + color: textColorSecondary, + fontWeight: 700, + fontSize: fontSizeLG, + fontStyle: 'normal', + lineHeight: 1, + textAlign: 'center', + textTransform: 'none', + textDecoration: 'none', + background: 'transparent', + border: 0, + outline: 0, + cursor: 'pointer', + transition: `color ${motionDurationSlow}`, + textRendering: 'auto', + + [`${drawerPrefixCls}:focus,${drawerPrefixCls}:hover`]: { + color: hoverColor, + textDecoration: 'none', + }, + }, + }, + [`${drawerPrefixCls}-header-close-only`]: { + paddingBottom: 0, + border: 'none', + }, + }, + [`${drawerPrefixCls}-body`]: { + flexGrow: 1, + padding: paddingLG, + overflow: 'auto', + fontSize, + lineHeight, + wordWrap: 'break-word', + }, + [`${drawerPrefixCls}-footer`]: { + flexShrink: 0, + padding: `${modalFooterPaddingVertical}px ${modalFooterPaddingHorizontal}px`, // FIXME px + borderTop: `${lineWidth}px ${borderStyle} ${borderColorSplit}`, // FIXME px + }, + }, + }, + }, + [`${drawerPrefixCls}-mask`]: { + position: 'absolute', + insetBlockStart: 0, + insetInlineStart: 0, + width: '100%', + height: 0, + backgroundColor: textColorSecondary, + opacity: 0, + transition: `opacity ${motionDurationSlow} linear, height 0s ease ${motionDurationSlow}`, + pointerEvents: 'none', + }, + }, + [`${drawerPrefixCls}${drawerPrefixCls}-open ${drawerPrefixCls}-mask`]: { + height: '100%', + opacity: 1, + transition: 'none', + animation: `${antdDrawerFadeIn.getName(hashId)} ${motionDurationSlow} ${motionEaseOut}`, + pointerEvents: 'auto', + }, + }; +}; + +const genDrawerStyle: GenerateStyle = (token: DrawerToken) => { + const { + drawerPrefixCls, + motionDurationSlow, + shadow1Right, + shadow1Left, + shadow1Down, + shadow1Up, + lineWidth, + motionEaseOut, + } = token; + + return { + // =================== left,right =================== + [`${drawerPrefixCls}-left`]: { + insetInlineStart: 0, + insetBlockStart: 0, + width: 0, + height: '100%', + [`${drawerPrefixCls}-content-wrapper`]: { + height: '100%', + insetInlineStart: 0, + }, + }, + [`${drawerPrefixCls}-left${drawerPrefixCls}-open`]: { + width: '100%', + transition: `transform ${motionDurationSlow} ${motionEaseOut}`, + [`${drawerPrefixCls}-content-wrapper`]: { + boxShadow: shadow1Right, + }, + }, + [`${drawerPrefixCls}-right`]: { + insetInlineEnd: 0, + insetBlockStart: 0, + width: 0, + height: '100%', + [`${drawerPrefixCls}-content-wrapper`]: { + height: '100%', + insetInlineEnd: 0, + }, + }, + [`${drawerPrefixCls}-right${drawerPrefixCls}-open`]: { + width: '100%', + transition: `transform ${motionDurationSlow} ${motionEaseOut}`, + [`${drawerPrefixCls}-content-wrapper`]: { + boxShadow: shadow1Left, + }, + }, + // https://github.com/ant-design/ant-design/issues/18607, Avoid edge alignment bug. + [`${drawerPrefixCls}-right${drawerPrefixCls}-open.no-mask`]: { + insetInlineEnd: lineWidth, + transform: `translateX(${lineWidth})`, + }, + + // =================== top,bottom =================== + [`${drawerPrefixCls}-top,${drawerPrefixCls}-bottom`]: { + insetInlineStart: 0, + width: '100%', + height: 0, + [`${drawerPrefixCls}-content-wrapper`]: { + width: '100%', + }, + }, + + [`${drawerPrefixCls}-top${drawerPrefixCls}-open,${drawerPrefixCls}-bottom${drawerPrefixCls}-open`]: + { + height: '100%', + transition: `transform ${motionDurationSlow} ${motionEaseOut}`, + }, + + [`${drawerPrefixCls}-top`]: { + insetBlockStart: 0, + }, + + [`${drawerPrefixCls}-top${drawerPrefixCls}-open`]: { + [`${drawerPrefixCls}-content-wrapper`]: { + boxShadow: shadow1Down, + }, + }, + + [`${drawerPrefixCls}-bottom`]: { + bottom: 0, + [`${drawerPrefixCls}-content-wrapper`]: { + bottom: 0, + }, + }, + + [`${drawerPrefixCls}-bottom${drawerPrefixCls}-bottom-open`]: { + [`${drawerPrefixCls}-content-wrapper`]: { + boxShadow: shadow1Up, + }, + }, + + [`${drawerPrefixCls}-bottom${drawerPrefixCls}-bottom-open.no-mask`]: { + insetBlockEnd: lineWidth, + transform: `translateY(${lineWidth})`, + }, + + // ==================== Hook Components =================== + // FIXME: Seems useless? + // .@{picker-prefix-cls} { + // &-clear { + // background: @popover-background, + // } + // } + }; +}; + +// ============================== Export ============================== +export default function useStyle( + prefixCls: string, + iconPrefixCls: string, +): UseComponentStyleResult { + const [theme, token, hashId] = useToken(); + const drawerToken: DrawerToken = { + ...token, + prefixCls, + iconPrefixCls, + drawerPrefixCls: `.${prefixCls}`, + + black: '#000', // FIXME: hard code + white: '#fff', // FIXME: hard code + drawerHeaderCloseSize: 56, // FIXME: hard code + shadow1Right: + '6px 0 16px -8px rgba(0, 0, 0, 0.08), 9px 0 28px 0 rgba(0, 0, 0, 0.05),12px 0 48px 16px rgba(0, 0, 0, 0.03)', // FIXME: hard code in v4 + shadow1Left: + '-6px 0 16px -8px rgba(0, 0, 0, 0.08), -9px 0 28px 0 rgba(0, 0, 0, 0.05), -12px 0 48px 16px rgba(0, 0, 0, 0.03)', // FIXME: hard code in v4 + shadow1Up: + '0 -6px 16px -8px rgba(0, 0, 0, 0.32), 0 -9px 28px 0 rgba(0, 0, 0, 0.2),0 -12px 48px 16px rgba(0, 0, 0, 0.12)', // FIXME: hard code in v4 + shadow1Down: + '0 6px 16px -8px rgba(0, 0, 0, 0.32), 0 9px 28px 0 rgba(0, 0, 0, 0.2), 0 12px 48px 16px rgba(0, 0, 0, 0.12)', // FIXME: hard code in v4 + drawerTitleLineHeight: 1.375, // FIXME: hard code + closeRight: 22, // FIXME: hard code + paddingMd: 16, // FIXME: hard code + modalFooterPaddingVertical: 10, // FIXME: hard code + modalFooterPaddingHorizontal: 16, // FIXME: hard code + borderColorSplit: new TinyColor({ h: 0, s: 0, v: 94 }).toHexString(), // FIXME: hard code + hoverColor: new TinyColor('#000').setAlpha(0.75).toRgbString(), // FIXME: hard code + textColorSecondary: new TinyColor('#000').setAlpha(0.45).toRgbString(), // FIXME: hard code + borderStyle: 'solid', // FIXME: hard code + motionEaseOut: 'cubic-bezier(0.215, 0.61, 0.355, 1)', // FIXME: hard code + }; + + return [ + useStyleRegister({ theme, token, hashId, path: [prefixCls] }, () => [ + genBaseStyle(drawerToken, hashId), + genDrawerStyle(drawerToken), + ]), + hashId, + ]; +} From 5588dae2121c89bc46636c70e3d02b91bfdcf4aa Mon Sep 17 00:00:00 2001 From: zhao-huo-long Date: Fri, 25 Mar 2022 09:38:55 +0800 Subject: [PATCH 03/11] fix: Descriptions number 0 can't render span (#34696) * fix: number 0 can't render span * Update Cell.tsx * chore: add test case --- components/descriptions/Cell.tsx | 4 +- .../__snapshots__/index.test.js.snap | 40 +++++++++++++++++++ .../descriptions/__tests__/index.test.js | 11 +++++ 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/components/descriptions/Cell.tsx b/components/descriptions/Cell.tsx index 928f43aeaa..0fbdb66caa 100644 --- a/components/descriptions/Cell.tsx +++ b/components/descriptions/Cell.tsx @@ -60,7 +60,7 @@ const Cell: React.FC = ({ colSpan={span} >
- {label && ( + {(label || label === 0) && ( = ({ {label} )} - {content && ( + {(content || content === 0) && ( {content} diff --git a/components/descriptions/__tests__/__snapshots__/index.test.js.snap b/components/descriptions/__tests__/__snapshots__/index.test.js.snap index 52c052dbcd..5142da10b0 100644 --- a/components/descriptions/__tests__/__snapshots__/index.test.js.snap +++ b/components/descriptions/__tests__/__snapshots__/index.test.js.snap @@ -209,6 +209,46 @@ exports[`Descriptions column is number 1`] = `
`; +exports[`Descriptions number 0 should render correct 1`] = ` +
+
+ + + + + + +
+
+ + 0 + + + 0 + +
+
+
+
+`; + exports[`Descriptions should work with React Fragment 1`] = `
{ wrapper.setProps({ extra: undefined }); expect(wrapper.find('.ant-descriptions-extra').exists()).toBe(false); }); + + it('number 0 should render correct', () => { + const wrapper = mount( + + + {0} + + , + ); + expect(wrapper.render()).toMatchSnapshot(); + }); }); From 5b1fa4ccaceb788045a340ca53f43c2643267a5e Mon Sep 17 00:00:00 2001 From: xrkffgg Date: Fri, 25 Mar 2022 10:17:46 +0800 Subject: [PATCH 04/11] ci: update pr merge branch --- .github/workflows/pr-check-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-check-ci.yml b/.github/workflows/pr-check-ci.yml index d9599590a5..e3e608b4b5 100644 --- a/.github/workflows/pr-check-ci.yml +++ b/.github/workflows/pr-check-ci.yml @@ -13,7 +13,7 @@ jobs: with: filter-label: 'BranchAutoMerge' filter-creator-authority: 'write' - filter-head-ref: 'master, feature, next, master-merge-feature, feature-merge-master, next-merge-master' + filter-head-ref: 'master, feature, next, master-merge-feature, feature-merge-master, next-merge-master, next-merge-feature' filter-support-fork: false skip-run-names: 'deploy preview, pr-check-ci, build preview failed, suggest-related-links' conflict-review-body: '😅 This branch has conflicts that must be resolved!' From 8fe200286012a705c0a5896a40b68decc4cad8e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=83=E5=87=9B?= Date: Fri, 25 Mar 2022 12:07:48 +0800 Subject: [PATCH 05/11] test: update spin snap --- components/spin/__tests__/__snapshots__/index.test.js.snap | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/spin/__tests__/__snapshots__/index.test.js.snap b/components/spin/__tests__/__snapshots__/index.test.js.snap index c40f0abfd3..18de381464 100644 --- a/components/spin/__tests__/__snapshots__/index.test.js.snap +++ b/components/spin/__tests__/__snapshots__/index.test.js.snap @@ -2,6 +2,8 @@ exports[`Spin if indicator set null should not be render default indicator 1`] = `
`; @@ -45,6 +47,8 @@ exports[`Spin should render custom indicator when it's set 1`] = ` exports[`Spin should support static method Spin.setDefaultIndicator 1`] = `
Date: Fri, 25 Mar 2022 13:20:42 +0800 Subject: [PATCH 06/11] refactor: popover cssinjs (#34607) * refactor: popover cssinjs * fix cls * fix cls * fix overlay * fix: token * fix: util * fix: block -> line * fix: interface --- components/_util/theme/index.tsx | 3 +- components/_util/theme/interface.ts | 2 + components/_util/theme/themes/default.ts | 1 + components/_util/theme/util/alias.ts | 2 +- components/_util/theme/util/index.tsx | 2 + components/_util/theme/util/roundedArrow.tsx | 41 ++ components/popover/index.tsx | 19 +- components/popover/style/index.less | 430 +++++++++---------- components/popover/style/index.tsx | 397 ++++++++++++++++- 9 files changed, 674 insertions(+), 223 deletions(-) create mode 100644 components/_util/theme/util/roundedArrow.tsx diff --git a/components/_util/theme/index.tsx b/components/_util/theme/index.tsx index 77869031da..f4758bdb7b 100644 --- a/components/_util/theme/index.tsx +++ b/components/_util/theme/index.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { CSSInterpolation, Theme, useCacheToken, useStyleRegister } from '@ant-design/cssinjs'; import defaultSeedToken, { derivative as defaultDerivative } from './themes/default'; import version from '../../version'; -import { resetComponent, resetIcon, clearFix } from './util'; +import { resetComponent, resetIcon, clearFix, roundedArrow } from './util'; import formatToken from './util/alias'; import { initSlideMotion, @@ -29,6 +29,7 @@ export { resetComponent, resetIcon, clearFix, + roundedArrow, initSlideMotion, slideUpIn, slideUpOut, diff --git a/components/_util/theme/interface.ts b/components/_util/theme/interface.ts index c0ed72ba8a..633175a11b 100644 --- a/components/_util/theme/interface.ts +++ b/components/_util/theme/interface.ts @@ -87,6 +87,7 @@ export interface SeedToken extends PresetColorType { // zIndex /** Base zIndex of component like BackTop, Affix which can be cover by large popup */ zIndexBase: number; + zIndexPopover: number; /** Base popup component zIndex */ zIndexPopup: number; } @@ -253,6 +254,7 @@ export interface AliasToken extends Omit { paddingXXS: number; paddingLG: number; marginXS: number; + marginSM: number; marginLG: number; marginXXS: number; } diff --git a/components/_util/theme/themes/default.ts b/components/_util/theme/themes/default.ts index 9d0249b6da..320eee5a0f 100644 --- a/components/_util/theme/themes/default.ts +++ b/components/_util/theme/themes/default.ts @@ -194,6 +194,7 @@ const seedToken: SeedToken = { // zIndex zIndexBase: 0, + zIndexPopover: 1030, zIndexPopup: 1000, }; diff --git a/components/_util/theme/util/alias.ts b/components/_util/theme/util/alias.ts index f3aa9edc56..3f072aafdc 100644 --- a/components/_util/theme/util/alias.ts +++ b/components/_util/theme/util/alias.ts @@ -110,7 +110,7 @@ export default function formatToken(derivativeToken: RawMergedToken): AliasToken marginXXS: 2, marginXS: 4, - // marginSM: 8, + marginSM: 8, marginLG: 32, boxShadow: ` diff --git a/components/_util/theme/util/index.tsx b/components/_util/theme/util/index.tsx index c69f4a99b7..a08467980b 100644 --- a/components/_util/theme/util/index.tsx +++ b/components/_util/theme/util/index.tsx @@ -2,6 +2,8 @@ import { CSSObject } from '@ant-design/cssinjs'; import type { DerivativeToken } from '..'; +export { roundedArrow } from './roundedArrow'; + export const resetComponent = (token: DerivativeToken): CSSObject => ({ boxSizing: 'border-box', margin: 0, diff --git a/components/_util/theme/util/roundedArrow.tsx b/components/_util/theme/util/roundedArrow.tsx new file mode 100644 index 0000000000..bfb98656aa --- /dev/null +++ b/components/_util/theme/util/roundedArrow.tsx @@ -0,0 +1,41 @@ +/* eslint-disable import/prefer-default-export */ +import { CSSObject } from '@ant-design/cssinjs'; +import seedToken from '../themes/default'; + +export const roundedArrow = ( + width: number, + outerRadius: number, + bgColor: string, +): CSSObject => { + const cornerHeight = outerRadius * (1 - 1 / Math.sqrt(2)); + const { radiusBase } = seedToken; + + const ax = width - cornerHeight; + const ay = 2 * width + cornerHeight; + const bx = ax + outerRadius * (1 / Math.sqrt(2)); + const by = 2 * width; + const cx = 2 * width - radiusBase; + const cy = 2 * width; + const dx = 2 * width; + const dy = 2 * width - radiusBase; + const fx = 2 * width + cornerHeight; + const fy = width - cornerHeight; + const ex = 2 * width; + const ey = fy + outerRadius * (1 / Math.sqrt(2)); + + return { + borderRadius: `0 0 ${radiusBase}px 0`, + pointerEvents: 'none', + + '&::before': { + position: 'absolute', + top: -width, + insetInlineStart: -width, + width: width * 3, + height: width * 3, + background: `linear-gradient(to left, ${bgColor} 50%, ${bgColor} 50%) no-repeat ${Math.ceil(-width + 1)}px ${Math.ceil(-width + 1)}px`, + content: '""', + clipPath: `path('M ${ax} ${ay} A ${outerRadius} ${outerRadius} 0 0 1 ${bx} ${by} L ${cx} ${cy} A ${radiusBase} ${radiusBase} 0 0 0 ${dx} ${dy} L ${ex} ${ey} A ${outerRadius} ${outerRadius} 0 0 1 ${fx} ${fy} Z')`, + }, + }; +} diff --git a/components/popover/index.tsx b/components/popover/index.tsx index a02a1b635a..1db57e6348 100644 --- a/components/popover/index.tsx +++ b/components/popover/index.tsx @@ -1,17 +1,21 @@ import * as React from 'react'; +import classNames from 'classnames'; import Tooltip, { AbstractTooltipProps, TooltipPlacement } from '../tooltip'; import { ConfigContext } from '../config-provider'; import { getRenderPropValue, RenderFunction } from '../_util/getRenderPropValue'; import { getTransitionName } from '../_util/motion'; +// CSSINJS +import useStyle from './style'; + export interface PopoverProps extends AbstractTooltipProps { title?: React.ReactNode | RenderFunction; content?: React.ReactNode | RenderFunction; } const Popover = React.forwardRef( - ({ prefixCls: customizePrefixCls, title, content, ...otherProps }, ref) => { - const { getPrefixCls } = React.useContext(ConfigContext); + ({ prefixCls: customizePrefixCls, title, content, overlayClassName, ...otherProps }, ref) => { + const { getPrefixCls, iconPrefixCls } = React.useContext(ConfigContext); const getOverlay = (prefixCls: string) => { if (!title && !content) return undefined; @@ -24,16 +28,23 @@ const Popover = React.forwardRef( }; const prefixCls = getPrefixCls('popover', customizePrefixCls); + const [wrapSSR, hashId] = useStyle(prefixCls, iconPrefixCls); const rootPrefixCls = getPrefixCls(); - return ( + const overlayCls = classNames( + overlayClassName, + hashId, + ); + + return wrapSSR( + />, ); }, ); diff --git a/components/popover/style/index.less b/components/popover/style/index.less index 6cc7c294be..d0da7cc28a 100644 --- a/components/popover/style/index.less +++ b/components/popover/style/index.less @@ -1,258 +1,258 @@ -@import '../../style/themes/index'; -@import '../../style/mixins/index'; +// @import '../../style/themes/index'; +// @import '../../style/mixins/index'; -@popover-prefix-cls: ~'@{ant-prefix}-popover'; +// @popover-prefix-cls: ~'@{ant-prefix}-popover'; -@popover-arrow-rotate-width: sqrt(@popover-arrow-width * @popover-arrow-width * 2); +// @popover-arrow-rotate-width: sqrt(@popover-arrow-width * @popover-arrow-width * 2); -@popover-arrow-offset-vertical: 12px; -@popover-arrow-offset-horizontal: 16px; +// @popover-arrow-offset-vertical: 12px; +// @popover-arrow-offset-horizontal: 16px; -.@{popover-prefix-cls} { - .reset-component(); +// .@{popover-prefix-cls} { +// .reset-component(); - position: absolute; - top: 0; - left: 0; - z-index: @zindex-popover; - font-weight: normal; - white-space: normal; - text-align: left; - cursor: auto; - user-select: text; +// position: absolute; +// top: 0; +// left: 0; +// z-index: @zindex-popover; +// font-weight: normal; +// white-space: normal; +// text-align: left; +// cursor: auto; +// user-select: text; - &::after { - position: absolute; - background: fade(@white, 1%); - content: ''; - } +// &::after { +// position: absolute; +// background: fade(@white, 1%); +// content: ''; +// } - &-hidden { - display: none; - } +// &-hidden { +// display: none; +// } - // Offset the popover to account for the popover arrow - &-placement-top, - &-placement-topLeft, - &-placement-topRight { - padding-bottom: @popover-distance; - } +// // Offset the popover to account for the popover arrow +// &-placement-top, +// &-placement-topLeft, +// &-placement-topRight { +// padding-bottom: @popover-distance; +// } - &-placement-right, - &-placement-rightTop, - &-placement-rightBottom { - padding-left: @popover-distance; - } +// &-placement-right, +// &-placement-rightTop, +// &-placement-rightBottom { +// padding-left: @popover-distance; +// } - &-placement-bottom, - &-placement-bottomLeft, - &-placement-bottomRight { - padding-top: @popover-distance; - } +// &-placement-bottom, +// &-placement-bottomLeft, +// &-placement-bottomRight { +// padding-top: @popover-distance; +// } - &-placement-left, - &-placement-leftTop, - &-placement-leftBottom { - padding-right: @popover-distance; - } +// &-placement-left, +// &-placement-leftTop, +// &-placement-leftBottom { +// padding-right: @popover-distance; +// } - &-inner { - background-color: @popover-bg; - background-clip: padding-box; - border-radius: @border-radius-base; - box-shadow: @box-shadow-base; - box-shadow: ~'0 0 8px @{shadow-color} \9'; - } +// &-inner { +// background-color: @popover-bg; +// background-clip: padding-box; +// border-radius: @border-radius-base; +// box-shadow: @box-shadow-base; +// box-shadow: ~'0 0 8px @{shadow-color} \9'; +// } - @media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { - /* IE10+ */ - &-inner { - box-shadow: @box-shadow-base; - } - } +// @media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { +// /* IE10+ */ +// &-inner { +// box-shadow: @box-shadow-base; +// } +// } - &-title { - min-width: @popover-min-width; - min-height: @popover-min-height; - margin: 0; // reset heading margin - padding: 5px @popover-padding-horizontal 4px; - color: @heading-color; - font-weight: 500; - border-bottom: 1px solid @border-color-split; - } +// &-title { +// min-width: @popover-min-width; +// min-height: @popover-min-height; +// margin: 0; // reset heading margin +// padding: 5px @popover-padding-horizontal 4px; +// color: @heading-color; +// font-weight: 500; +// border-bottom: 1px solid @border-color-split; +// } - &-inner-content { - padding: @padding-sm @popover-padding-horizontal; - color: @popover-color; - } +// &-inner-content { +// padding: @padding-sm @popover-padding-horizontal; +// color: @popover-color; +// } - &-message { - position: relative; - padding: 4px 0 12px; - color: @popover-color; - font-size: @font-size-base; - > .@{iconfont-css-prefix} { - position: absolute; - top: ( - 4px + ((@line-height-base * @font-size-base - @font-size-base) / 2) - ); // 4px for padding-top, 4px for vertical middle - color: @warning-color; - font-size: @font-size-base; - } +// &-message { +// position: relative; +// padding: 4px 0 12px; +// color: @popover-color; +// font-size: @font-size-base; +// > .@{iconfont-css-prefix} { +// position: absolute; +// top: ( +// 4px + ((@line-height-base * @font-size-base - @font-size-base) / 2) +// ); // 4px for padding-top, 4px for vertical middle +// color: @warning-color; +// font-size: @font-size-base; +// } - &-title { - padding-left: @font-size-base + 8px; - } - } +// &-title { +// padding-left: @font-size-base + 8px; +// } +// } - &-buttons { - margin-bottom: 4px; - text-align: right; +// &-buttons { +// margin-bottom: 4px; +// text-align: right; - button { - margin-left: 8px; - } - } +// button { +// margin-left: 8px; +// } +// } - // Arrows - &-arrow { - position: absolute; - display: block; - width: @popover-arrow-rotate-width; - height: @popover-arrow-rotate-width; - overflow: hidden; - background: transparent; - pointer-events: none; +// // Arrows +// &-arrow { +// position: absolute; +// display: block; +// width: @popover-arrow-rotate-width; +// height: @popover-arrow-rotate-width; +// overflow: hidden; +// background: transparent; +// pointer-events: none; - &-content { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - display: block; - width: @popover-arrow-width; - height: @popover-arrow-width; - margin: auto; - background-color: @popover-bg; - content: ''; - pointer-events: auto; - .roundedArrow(@popover-arrow-width, 5px, @popover-bg); - } - } +// &-content { +// position: absolute; +// top: 0; +// right: 0; +// bottom: 0; +// left: 0; +// display: block; +// width: @popover-arrow-width; +// height: @popover-arrow-width; +// margin: auto; +// background-color: @popover-bg; +// content: ''; +// pointer-events: auto; +// .roundedArrow(@popover-arrow-width, 5px, @popover-bg); +// } +// } - &-placement-top &-arrow, - &-placement-topLeft &-arrow, - &-placement-topRight &-arrow { - bottom: @popover-distance - @popover-arrow-rotate-width; +// &-placement-top &-arrow, +// &-placement-topLeft &-arrow, +// &-placement-topRight &-arrow { +// bottom: @popover-distance - @popover-arrow-rotate-width; - &-content { - box-shadow: 3px 3px 7px fade(@black, 7%); - transform: translateY((-@popover-arrow-rotate-width / 2)) rotate(45deg); - } - } +// &-content { +// box-shadow: 3px 3px 7px fade(@black, 7%); +// transform: translateY((-@popover-arrow-rotate-width / 2)) rotate(45deg); +// } +// } - &-placement-top &-arrow { - left: 50%; - transform: translateX(-50%); - } +// &-placement-top &-arrow { +// left: 50%; +// transform: translateX(-50%); +// } - &-placement-topLeft &-arrow { - left: @popover-arrow-offset-horizontal; - } +// &-placement-topLeft &-arrow { +// left: @popover-arrow-offset-horizontal; +// } - &-placement-topRight &-arrow { - right: @popover-arrow-offset-horizontal; - } +// &-placement-topRight &-arrow { +// right: @popover-arrow-offset-horizontal; +// } - &-placement-right &-arrow, - &-placement-rightTop &-arrow, - &-placement-rightBottom &-arrow { - left: @popover-distance - @popover-arrow-rotate-width; +// &-placement-right &-arrow, +// &-placement-rightTop &-arrow, +// &-placement-rightBottom &-arrow { +// left: @popover-distance - @popover-arrow-rotate-width; - &-content { - box-shadow: 3px 3px 7px fade(@black, 7%); - transform: translateX((@popover-arrow-rotate-width / 2)) rotate(135deg); - } - } +// &-content { +// box-shadow: 3px 3px 7px fade(@black, 7%); +// transform: translateX((@popover-arrow-rotate-width / 2)) rotate(135deg); +// } +// } - &-placement-right &-arrow { - top: 50%; - transform: translateY(-50%); - } +// &-placement-right &-arrow { +// top: 50%; +// transform: translateY(-50%); +// } - &-placement-rightTop &-arrow { - top: @popover-arrow-offset-vertical; - } +// &-placement-rightTop &-arrow { +// top: @popover-arrow-offset-vertical; +// } - &-placement-rightBottom &-arrow { - bottom: @popover-arrow-offset-vertical; - } +// &-placement-rightBottom &-arrow { +// bottom: @popover-arrow-offset-vertical; +// } - &-placement-bottom &-arrow, - &-placement-bottomLeft &-arrow, - &-placement-bottomRight &-arrow { - top: @popover-distance - @popover-arrow-rotate-width; +// &-placement-bottom &-arrow, +// &-placement-bottomLeft &-arrow, +// &-placement-bottomRight &-arrow { +// top: @popover-distance - @popover-arrow-rotate-width; - &-content { - box-shadow: 2px 2px 5px fade(@black, 6%); - transform: translateY((@popover-arrow-rotate-width / 2)) rotate(-135deg); - } - } +// &-content { +// box-shadow: 2px 2px 5px fade(@black, 6%); +// transform: translateY((@popover-arrow-rotate-width / 2)) rotate(-135deg); +// } +// } - &-placement-bottom &-arrow { - left: 50%; - transform: translateX(-50%); - } +// &-placement-bottom &-arrow { +// left: 50%; +// transform: translateX(-50%); +// } - &-placement-bottomLeft &-arrow { - left: @popover-arrow-offset-horizontal; - } +// &-placement-bottomLeft &-arrow { +// left: @popover-arrow-offset-horizontal; +// } - &-placement-bottomRight &-arrow { - right: @popover-arrow-offset-horizontal; - } +// &-placement-bottomRight &-arrow { +// right: @popover-arrow-offset-horizontal; +// } - &-placement-left &-arrow, - &-placement-leftTop &-arrow, - &-placement-leftBottom &-arrow { - right: @popover-distance - @popover-arrow-rotate-width; +// &-placement-left &-arrow, +// &-placement-leftTop &-arrow, +// &-placement-leftBottom &-arrow { +// right: @popover-distance - @popover-arrow-rotate-width; - &-content { - box-shadow: 3px 3px 7px fade(@black, 7%); - transform: translateX((-@popover-arrow-rotate-width / 2)) rotate(-45deg); - } - } +// &-content { +// box-shadow: 3px 3px 7px fade(@black, 7%); +// transform: translateX((-@popover-arrow-rotate-width / 2)) rotate(-45deg); +// } +// } - &-placement-left &-arrow { - top: 50%; - transform: translateY(-50%); - } +// &-placement-left &-arrow { +// top: 50%; +// transform: translateY(-50%); +// } - &-placement-leftTop &-arrow { - top: @popover-arrow-offset-vertical; - } +// &-placement-leftTop &-arrow { +// top: @popover-arrow-offset-vertical; +// } - &-placement-leftBottom &-arrow { - bottom: @popover-arrow-offset-vertical; - } -} +// &-placement-leftBottom &-arrow { +// bottom: @popover-arrow-offset-vertical; +// } +// } -.generator-popover-preset-color(@i: length(@preset-colors)) when (@i > 0) { - .generator-popover-preset-color(@i - 1); - @color: extract(@preset-colors, @i); - @lightColor: '@{color}-6'; - .@{popover-prefix-cls}-@{color} { - .@{popover-prefix-cls}-inner { - background-color: @@lightColor; - } - .@{popover-prefix-cls}-arrow { - &-content { - background-color: @@lightColor; - } - } - } -} -.generator-popover-preset-color(); +// .generator-popover-preset-color(@i: length(@preset-colors)) when (@i > 0) { +// .generator-popover-preset-color(@i - 1); +// @color: extract(@preset-colors, @i); +// @lightColor: '@{color}-6'; +// .@{popover-prefix-cls}-@{color} { +// .@{popover-prefix-cls}-inner { +// background-color: @@lightColor; +// } +// .@{popover-prefix-cls}-arrow { +// &-content { +// background-color: @@lightColor; +// } +// } +// } +// } +// .generator-popover-preset-color(); -@import './rtl'; +// @import './rtl'; diff --git a/components/popover/style/index.tsx b/components/popover/style/index.tsx index 9f2a34a79c..fa176410f5 100644 --- a/components/popover/style/index.tsx +++ b/components/popover/style/index.tsx @@ -1,5 +1,398 @@ -import '../../style/index.less'; -import './index.less'; +// import '../../style/index.less'; +// import './index.less'; // style dependencies // deps-lint-skip: tooltip + +// deps-lint-skip-all +import { TinyColor } from '@ctrl/tinycolor'; +import { CSSInterpolation, CSSObject } from '@ant-design/cssinjs'; +import { + PresetColors, + PresetColorType, + DerivativeToken, + useStyleRegister, + useToken, + UseComponentStyleResult, + GenerateStyle, + resetComponent, + roundedArrow, +} from '../../_util/theme'; + +// FIXME +type PopoverToken = DerivativeToken & { + popoverCls: string; + iconPrefixCls: string, + popoverBg: string; + popoverColor: string; + popoverMinWidth: number; + popoverMinHeight: number; + popoverArrowWidth: number; + popoverArrowColor: string; + popoverArrowOuterColor: string; + popoverDistance: number; + popoverPaddingHorizonta: number; + popoverArrowRotateWidth: number; + popoverArrowOffsetVertical: number; + popoverArrowOffsetHorizontal: number; +}; + + +const genBaseStyle: GenerateStyle = token => { + const { + popoverCls, + iconPrefixCls, + popoverBg, + popoverColor, + popoverMinWidth, + popoverMinHeight, + popoverArrowWidth, + popoverPaddingHorizonta, + popoverArrowRotateWidth, + + boxShadow, + colorSplit, + colorTextHeading, + colorWarning, + fontSize, + marginSM, + marginXS, + lineHeight, + radiusBase: borderRadius, + paddingSM, + zIndexPopover, + } = token; + + return { + [popoverCls]: { + ...resetComponent(token), + position: 'absolute', + top: 0, + insetInlineStart: 0, + zIndex: zIndexPopover, + fontWeight: 'normal', + whiteSpace: 'normal', + textAlign: 'start', + cursor: 'auto', + userSelect: 'text', + + '&::after': { + position: 'absolute', + // FIXME + background: new TinyColor('#fff').setAlpha(0.01).toRgbString(), + content: '""', + }, + + '&-rtl': { + direction: 'rtl', + }, + + '&-hidden': { + display: 'none', + }, + + [`${popoverCls}-inner`]: { + backgroundColor: popoverBg, + backgroundClip: 'padding-box', + borderRadius, + boxShadow, + }, + + [`${popoverCls}-title`]: { + minWidth: popoverMinWidth, + minHeight: popoverMinHeight, + margin: 0, + // FIXME + padding: `5px ${popoverPaddingHorizonta}px 4px`, + color: colorTextHeading, + fontWeight: 500, + // FIXME + borderBottom: `1px solid ${colorSplit}`, + }, + + [`${popoverCls}-inner-content`]: { + padding: `${paddingSM}px ${popoverPaddingHorizonta}px`, + color: popoverColor, + }, + + // FIXME 没找到使用地方,先保留 + '&-message': { + position: 'relative', + // FIXME + padding: '4px 0 12px', + color: popoverColor, + fontSize, + + [`> .${iconPrefixCls}`]: { + position: 'absolute', + // FIXME + top: 4 + ((lineHeight * fontSize - fontSize) / 2), + color: colorWarning, + fontSize, + }, + + '&-title': { + // FIXME + paddingInlineStart: fontSize + 8, + }, + }, + + // FIXME 没找到使用地方,先保留 + '&-buttons': { + marginBottom: marginXS, + textAlign: 'end', + + 'button': { + marginInlineStart: marginSM, + }, + }, + + [`${popoverCls}-arrow`]: { + position: 'absolute', + display: 'block', + width: popoverArrowRotateWidth, + height: popoverArrowRotateWidth, + overflow: 'hidden', + background: 'transparent', + pointerEvents: 'none', + + '&-content': { + position: 'absolute', + top: 0, + insetInlineEnd: 0, + bottom: 0, + insetInlineStart: 0, + display: 'block', + width: popoverArrowWidth, + height: popoverArrowWidth, + margin: 'auto', + backgroundColor: popoverBg, + content: '""', + pointerEvents: 'auto', + ...roundedArrow(popoverArrowWidth, 5, popoverBg), + }, + }, + + }, + } +}; + +const genPlacementStyle: GenerateStyle = token => { + const { + popoverCls, + popoverDistance, + popoverArrowRotateWidth, + popoverArrowOffsetHorizontal, + popoverArrowOffsetVertical, + } = token; + + return { + [popoverCls]: { + [` + &-placement-top, + &-placement-topLeft, + &-placement-topRight + `]: { + paddingBottom: popoverDistance, + }, + + [` + &-placement-right, + &-placement-rightTop, + &-placement-rightBottom + `]: { + paddingLeft: popoverDistance, + }, + + [` + &-placement-bottom, + &-placement-bottomLeft, + &-placement-bottomRight + `]: { + paddingTop: popoverDistance, + }, + + [` + &-placement-left, + &-placement-leftTop, + &-placement-leftBottom + `]: { + paddingRight: popoverDistance, + }, + + [` + &-placement-top ${popoverCls}-arrow, + &-placement-topLeft ${popoverCls}-arrow, + &-placement-topRight ${popoverCls}-arrow + `]: { + bottom: popoverDistance - popoverArrowRotateWidth, + + '&-content': { + // FIXME + boxShadow: `3px 3px 7px ${new TinyColor('#000').setAlpha(0.07).toRgbString()}`, + transform: `translateY(-${popoverArrowRotateWidth / 2}px) rotate(45deg)`, + }, + }, + + [`&-placement-top ${popoverCls}-arrow`]: { + insetInlineStart : '50%', + transform: 'translateX(-50%)', + }, + + [`&-placement-topLeft ${popoverCls}-arrow`]: { + insetInlineStart: popoverArrowOffsetHorizontal, + }, + + [`&-placement-topRight ${popoverCls}-arrow`]: { + insetInlineEnd: popoverArrowOffsetHorizontal, + }, + + [` + &-placement-right ${popoverCls}-arrow, + &-placement-rightTop ${popoverCls}-arrow, + &-placement-rightBottom ${popoverCls}-arrow + `]: { + insetInlineStart: popoverDistance - popoverArrowRotateWidth, + + '&-content': { + // FIXME + boxShadow: `3px 3px 7px ${new TinyColor('#000').setAlpha(0.07).toRgbString()}`, + transform: `translateX(${popoverArrowRotateWidth / 2}px) rotate(135deg)`, + }, + }, + + [`&-placement-right ${popoverCls}-arrow`]: { + top: '50%', + transform: 'translateY(-50%)', + }, + + [`&-placement-rightTop ${popoverCls}-arrow`]: { + top: popoverArrowOffsetVertical, + }, + + [`&-placement-rightBottom ${popoverCls}-arrow`]: { + bottom: popoverArrowOffsetVertical, + }, + + [` + &-placement-bottom ${popoverCls}-arrow, + &-placement-bottomLeft ${popoverCls}-arrow, + &-placement-bottomRight ${popoverCls}-arrow + `]: { + top: popoverDistance - popoverArrowRotateWidth, + + '&-content': { + // FIXME + boxShadow: `2px 2px 5px ${new TinyColor('#000').setAlpha(0.06).toRgbString()}`, + transform: `translateY(${popoverArrowRotateWidth / 2}px) rotate(-135deg)`, + }, + }, + + [`&-placement-bottom ${popoverCls}-arrow`]: { + insetInlineStart: '50%', + transform: 'translateX(-50%)', + }, + + [`&-placement-bottomLeft ${popoverCls}-arrow`]: { + insetInlineStart: popoverArrowOffsetHorizontal, + }, + + [`&-placement-bottomRight ${popoverCls}-arrow`]: { + insetInlineEnd: popoverArrowOffsetHorizontal, + }, + + [` + &-placement-left ${popoverCls}-arrow, + &-placement-leftTop ${popoverCls}-arrow, + &-placement-leftBottom ${popoverCls}-arrow + `]: { + insetInlineEnd: popoverDistance - popoverArrowRotateWidth, + + '&-content': { + // FIXME + boxShadow: `3px 3px 7px ${new TinyColor('#000').setAlpha(0.07).toRgbString()}`, + transform: `translateX(-${popoverArrowRotateWidth / 2}px) rotate(-45deg)`, + }, + }, + + [`&-placement-left ${popoverCls}-arrow`]: { + top: '50%', + transform: 'translateY(-50%)', + }, + + [`&-placement-leftTop ${popoverCls}-arrow`]: { + top: popoverArrowOffsetVertical, + }, + + [`&-placement-leftBottom ${popoverCls}-arrow`]: { + bottom: popoverArrowOffsetVertical, + }, + }, + } +}; + +// FIXME: special preset colors +const genColorStyle: GenerateStyle = token => { + const { popoverCls } = token; + + return PresetColors.reduce((prev: CSSObject, colorKey: keyof PresetColorType) => { + const lightColor = token[`${colorKey}-6`]; + return { + ...prev, + [`${popoverCls}-${colorKey}`]: { + [`${popoverCls}-inner`]: { + backgroundColor: lightColor, + }, + [`${popoverCls}-arrow`]: { + '&-content': { + backgroundColor: lightColor, + }, + }, + }, + }; + }, {} as CSSObject); +}; + +export const genPopoverStyle: GenerateStyle = (token: PopoverToken): CSSInterpolation => [ + genBaseStyle(token), + genPlacementStyle(token), + genColorStyle(token), +]; + +export default function useStyle( + prefixCls: string, + iconPrefixCls: string, +): UseComponentStyleResult { + const [theme, token, hashId] = useToken(); + + const popoverBg = token.colorBg; + // FIXME + const popoverArrowWidth = 8 * Math.sqrt(2); + + const popoverToken = { + ...token, + popoverCls: `.${prefixCls}`, + iconPrefixCls, + popoverBg, + popoverColor: token.colorText, + // FIXME + popoverMinWidth: 177, + popoverMinHeight: 32, + popoverArrowWidth, + popoverArrowColor: popoverBg, + popoverArrowOuterColor: popoverBg, + popoverDistance: popoverArrowWidth + 4, + popoverPaddingHorizonta: token.padding, + popoverArrowRotateWidth: Math.sqrt(popoverArrowWidth * popoverArrowWidth * 2), + // FIXME + popoverArrowOffsetVertical: 12, + popoverArrowOffsetHorizontal: 16, + }; + + return [ + useStyleRegister({ theme, token, hashId, path: [prefixCls] }, () => [ + genPopoverStyle(popoverToken), + ]), + hashId, + ]; +} From c8b2b28c95f98885556cc3fb54fc90f1d498fc2d Mon Sep 17 00:00:00 2001 From: Zack Chang <73225408+jrr997@users.noreply.github.com> Date: Fri, 25 Mar 2022 14:26:09 +0800 Subject: [PATCH 07/11] Refactor/spin cssinjs (#34653) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * TODO: fix test case * TODO: 样式、test文件的import * TODO: 伪类不生效 * temp changed * fix: disable eslint * chore: update snapshots * chore: 解决伪类不生效 * chore: update token prop name * TODO: mark FIXME * fix: recover snapshot * fix: recover snapshot again * chore: update snapshot Co-authored-by: Zack Chang --- .../__tests__/components.test.js | 1 + components/list/index.tsx | 1 + components/mentions/index.tsx | 1 + components/spin/__tests__/delay.test.js | 7 +- components/spin/__tests__/index.test.js | 7 +- components/spin/index.tsx | 64 +++-- .../spin/style/{index.less => _index.less} | 0 components/spin/style/index.tsx | 246 +++++++++++++++++- components/table/Table.tsx | 1 + 9 files changed, 305 insertions(+), 23 deletions(-) rename components/spin/style/{index.less => _index.less} (100%) diff --git a/components/config-provider/__tests__/components.test.js b/components/config-provider/__tests__/components.test.js index 0a8ef2fa77..ec6718d9be 100644 --- a/components/config-provider/__tests__/components.test.js +++ b/components/config-provider/__tests__/components.test.js @@ -40,6 +40,7 @@ import Rate from '../../rate'; import Select from '../../select'; import Skeleton from '../../skeleton'; import Slider from '../../slider'; +// eslint-disable-next-line import/no-named-as-default import Spin from '../../spin'; import Statistic from '../../statistic'; import Steps from '../../steps'; diff --git a/components/list/index.tsx b/components/list/index.tsx index 0f4ba9718d..ad59d67300 100644 --- a/components/list/index.tsx +++ b/components/list/index.tsx @@ -1,5 +1,6 @@ import * as React from 'react'; import classNames from 'classnames'; +// eslint-disable-next-line import/no-named-as-default import Spin, { SpinProps } from '../spin'; import useBreakpoint from '../grid/hooks/useBreakpoint'; import { Breakpoint, responsiveArray } from '../_util/responsiveObserve'; diff --git a/components/mentions/index.tsx b/components/mentions/index.tsx index f100555179..5ee5ae3828 100644 --- a/components/mentions/index.tsx +++ b/components/mentions/index.tsx @@ -3,6 +3,7 @@ import classNames from 'classnames'; import RcMentions from 'rc-mentions'; import { MentionsProps as RcMentionsProps } from 'rc-mentions/lib/Mentions'; import { composeRef } from 'rc-util/lib/ref'; +// eslint-disable-next-line import/no-named-as-default import Spin from '../spin'; import { ConfigContext } from '../config-provider'; import { FormItemInputContext } from '../form/context'; diff --git a/components/spin/__tests__/delay.test.js b/components/spin/__tests__/delay.test.js index fbee446e7c..61f345746d 100644 --- a/components/spin/__tests__/delay.test.js +++ b/components/spin/__tests__/delay.test.js @@ -1,6 +1,7 @@ import React from 'react'; import { mount } from 'enzyme'; -import Spin from '..'; +// eslint-disable-next-line import/no-named-as-default +import Spin, { Spin as SpinClass } from '..'; import { sleep } from '../../../tests/utils'; describe('delay spinning', () => { @@ -24,8 +25,8 @@ describe('delay spinning', () => { it('should cancel debounce function when unmount', async () => { const wrapper = mount(); - const spy = jest.spyOn(wrapper.instance().updateSpinning, 'cancel'); - expect(wrapper.instance().updateSpinning.cancel).toEqual(expect.any(Function)); + const spy = jest.spyOn(wrapper.find(SpinClass).instance().updateSpinning, 'cancel'); + expect(wrapper.find(SpinClass).instance().updateSpinning.cancel).toEqual(expect.any(Function)); expect(spy).not.toHaveBeenCalled(); wrapper.unmount(); expect(spy).toHaveBeenCalled(); diff --git a/components/spin/__tests__/index.test.js b/components/spin/__tests__/index.test.js index 3cb6b8b99b..8460c5b94c 100644 --- a/components/spin/__tests__/index.test.js +++ b/components/spin/__tests__/index.test.js @@ -1,6 +1,7 @@ import React from 'react'; import { render, mount } from 'enzyme'; -import Spin from '..'; +// eslint-disable-next-line import/no-named-as-default +import Spin, { Spin as SpinClass } from '..'; import mountTest from '../../../tests/shared/mountTest'; import rtlTest from '../../../tests/shared/rtlTest'; @@ -26,9 +27,9 @@ describe('Spin', () => { it('should be controlled by spinning', () => { const wrapper = mount(); - expect(wrapper.instance().state.spinning).toBe(false); + expect(wrapper.find(SpinClass).instance().state.spinning).toBe(false); wrapper.setProps({ spinning: true }); - expect(wrapper.instance().state.spinning).toBe(true); + expect(wrapper.find(SpinClass).instance().state.spinning).toBe(true); }); it('if indicator set null should not be render default indicator', () => { diff --git a/components/spin/index.tsx b/components/spin/index.tsx index 4c1b1163e0..1b45d51d54 100644 --- a/components/spin/index.tsx +++ b/components/spin/index.tsx @@ -2,9 +2,10 @@ import * as React from 'react'; import classNames from 'classnames'; import omit from 'rc-util/lib/omit'; import debounce from 'lodash/debounce'; -import { ConfigConsumer, ConfigConsumerProps } from '../config-provider'; +import { ConfigConsumer, ConfigConsumerProps, ConfigContext } from '../config-provider'; import { tuple } from '../_util/type'; import { isValidElement, cloneElement } from '../_util/reactNode'; +import useStyle from './style/index'; const SpinSizes = tuple('small', 'default', 'large'); export type SpinSize = typeof SpinSizes[number]; @@ -22,6 +23,15 @@ export interface SpinProps { indicator?: SpinIndicator; } +export interface SpinClassProps extends SpinProps { + hashId: string; + spinPrefixCls: string; +} + +export type SpinFCType = React.FC & { + setDefaultIndicator: (indicator: React.ReactNode) => void; +}; + export interface SpinState { spinning?: boolean; notCssAnimationSupported?: boolean; @@ -30,7 +40,7 @@ export interface SpinState { // Render indicator let defaultIndicator: React.ReactNode = null; -function renderIndicator(prefixCls: string, props: SpinProps): React.ReactNode { +function renderIndicator(prefixCls: string, props: SpinClassProps): React.ReactNode { const { indicator } = props; const dotClassName = `${prefixCls}-dot`; @@ -65,20 +75,16 @@ function shouldDelay(spinning?: boolean, delay?: number): boolean { return !!spinning && !!delay && !isNaN(Number(delay)); } -class Spin extends React.Component { +export class Spin extends React.Component { static defaultProps = { spinning: true, size: 'default' as SpinSize, wrapperClassName: '', }; - static setDefaultIndicator(indicator: React.ReactNode) { - defaultIndicator = indicator; - } - originalUpdateSpinning: () => void; - constructor(props: SpinProps) { + constructor(props: SpinClassProps) { super(props); const { spinning, delay } = props; @@ -103,7 +109,7 @@ class Spin extends React.Component { this.cancelExistingSpin(); } - debouncifyUpdateSpinning = (props?: SpinProps) => { + debouncifyUpdateSpinning = (props?: SpinClassProps) => { const { delay } = props || this.props; if (delay) { this.cancelExistingSpin(); @@ -130,9 +136,10 @@ class Spin extends React.Component { return !!(this.props && typeof this.props.children !== 'undefined'); } - renderSpin = ({ getPrefixCls, direction }: ConfigConsumerProps) => { + renderSpin = ({ direction }: ConfigConsumerProps) => { const { - prefixCls: customizePrefixCls, + spinPrefixCls: prefixCls, + hashId, className, size, tip, @@ -142,7 +149,6 @@ class Spin extends React.Component { } = this.props; const { spinning } = this.state; - const prefixCls = getPrefixCls('spin', customizePrefixCls); const spinClassName = classNames( prefixCls, { @@ -153,10 +159,11 @@ class Spin extends React.Component { [`${prefixCls}-rtl`]: direction === 'rtl', }, className, + hashId, ); // fix https://fb.me/react-unknown-prop - const divProps = omit(restProps, ['spinning', 'delay', 'indicator']); + const divProps = omit(restProps, ['spinning', 'delay', 'indicator', 'prefixCls']); const spinElement = (
{ [`${prefixCls}-blur`]: spinning, }); return ( -
+
{spinning &&
{spinElement}
}
{this.props.children} @@ -191,4 +201,28 @@ class Spin extends React.Component { } } -export default Spin; +const SpinFC: SpinFCType = (props: SpinProps) => { + const { prefixCls: customizePrefixCls } = props; + const { getPrefixCls } = React.useContext(ConfigContext); + + const spinPrefixCls = getPrefixCls('spin', customizePrefixCls); + + const [wrapSSR, hashId] = useStyle(spinPrefixCls); + + const spinClassProps: SpinClassProps = { + ...props, + spinPrefixCls, + hashId, + }; + return wrapSSR(); +}; + +SpinFC.setDefaultIndicator = (indicator: React.ReactNode) => { + defaultIndicator = indicator; +}; + +if (process.env.NODE_ENV !== 'production') { + SpinFC.displayName = 'Spin'; +} + +export default SpinFC; diff --git a/components/spin/style/index.less b/components/spin/style/_index.less similarity index 100% rename from components/spin/style/index.less rename to components/spin/style/_index.less diff --git a/components/spin/style/index.tsx b/components/spin/style/index.tsx index 3a3ab0de59..330d5246a6 100644 --- a/components/spin/style/index.tsx +++ b/components/spin/style/index.tsx @@ -1,2 +1,244 @@ -import '../../style/index.less'; -import './index.less'; +// deps-lint-skip-all +import { CSSObject, Keyframes } from '@ant-design/cssinjs'; +import { + useStyleRegister, + useToken, + resetComponent, + GenerateStyle, + UseComponentStyleResult, +} from '../../_util/theme'; +import type { DerivativeToken } from '../../_util/theme'; + +interface SpinToken extends DerivativeToken { + spinCls: string; + spinDotDefault: string; + spinDotSize: number; + spinDotSizeSM: number; + spinDotSizeLG: number; +} + +const antSpinMove = new Keyframes('antSpinMove', { + to: { opacity: 1 }, +}); + +const antRotate = new Keyframes('antRotate', { + to: { transform: 'rotate(405deg)' }, +}); + +const genSpinStyle: GenerateStyle = (token: SpinToken, hashId: string): CSSObject => ({ + [`${token.spinCls}`]: { + ...resetComponent(token), + position: 'absolute', + display: 'none', + color: token.colorPrimary, + textAlign: 'center', + verticalAlign: 'middle', + opacity: 0, + transition: `transform ${token.motionDurationSlow} ${token.motionEaseInOutCirc}`, + + '&-spinning': { + position: 'static', + display: 'inline-block', + opacity: 1, + }, + + '&-nested-loading': { + position: 'relative', + [`> div > ${token.spinCls}`]: { + position: 'absolute', + top: 0, + insetInlineStart: 0, + zIndex: 4, + display: 'block', + width: '100%', + height: '100%', + maxHeight: 400, // FIXME: hard code in v4 + + [`${token.spinCls}-dot`]: { + position: 'absolute', + top: '50%', + insetInlineStart: '50%', + margin: -token.spinDotSize / 2, + }, + + [`${token.spinCls}-text`]: { + position: 'absolute', + top: '50%', + width: '100%', + paddingTop: (token.spinDotSize - token.fontSize) / 2 + 2, + textShadow: `0 1px 2px ${token.colorBgComponent}`, + }, + + [`&${token.spinCls}-show-text ${token.spinCls}-dot`]: { + marginTop: -(token.spinDotSize / 2) - 10, + }, + + [`> div > ${token.spinCls}-sm`]: { + [`${token.spinCls}-dot`]: { + margin: -token.spinDotSizeSM / 2, + }, + [`${token.spinCls}-text`]: { + paddingTop: (token.spinDotSizeSM - token.fontSize) / 2 + 2, + }, + [`&${token.spinCls}-show-text ${token.spinCls}-dot`]: { + marginTop: -(token.spinDotSizeSM / 2) - 10, + }, + }, + + [`> div > ${token.spinCls}-lg`]: { + [`${token.spinCls}-dot`]: { + margin: -(token.spinDotSizeLG / 2), + }, + [`${token.spinCls}-text`]: { + paddingTop: (token.spinDotSizeLG - token.fontSize) / 2 + 2, + }, + [`&${token.spinCls}-show-text ${token.spinCls}-dot`]: { + marginTop: -(token.spinDotSizeLG / 2) - 10, + }, + }, + }, + + [`${token.spinCls}-container`]: { + position: 'relative', + transition: `opacity ${token.motionDurationSlow}`, + + '&::after': { + position: 'absolute', + top: 0, + insetInlineEnd: 0, + bottom: 0, + insetInlineStart: 0, + zIndex: 10, + width: '100%', + height: '100%', + background: token.colorBgComponent, + opacity: 0, + transition: `all ${token.motionDurationSlow}`, + content: '""', + pointerEvents: 'none', + }, + }, + + [`${token.spinCls}-blur`]: { + clear: 'both', + opacity: 0.5, + userSelect: 'none', + pointerEvents: 'none', + + [`&::after`]: { + opacity: 0.4, + pointerEvents: 'auto', + }, + }, + }, + + // tip + // ------------------------------ + [`&-tip`]: { + color: token.spinDotDefault, + }, + + // dots + // ------------------------------ + [`${token.spinCls}-dot`]: { + position: 'relative', + display: 'inline-block', + fontSize: token.spinDotSize, + width: '1em', + height: '1em', + + '&-item': { + position: 'absolute', + display: 'block', + width: 9, // FIXME: hard code in v4 + height: 9, // FIXME: hard code in v4 + backgroundColor: token.colorPrimary, + borderRadius: '100%', + transform: 'scale(0.75)', + transformOrigin: '50% 50%', + opacity: 0.3, + animation: `${antSpinMove.getName(hashId)} 1s infinite linear alternate`, + + '&:nth-child(1)': { + top: 0, + insetInlineStart: 0, + }, + + '&:nth-child(2)': { + top: 0, + insetInlineEnd: 0, + animationDelay: '0.4s', + }, + + '&:nth-child(3)': { + insetInlineEnd: 0, + bottom: 0, + animationDelay: '0.8s', + }, + + '&:nth-child(4)': { + bottom: 0, + insetInlineStart: 0, + animationDelay: '1.2s', + }, + }, + + '&-spin': { + transform: 'rotate(45deg)', + animation: `${antRotate.getName(hashId)} 1.2s infinite linear`, + }, + }, + + // Sizes + // ------------------------------ + + // small + [`&-sm ${token.spinCls}-dot`]: { + fontSize: token.spinDotSizeSM, + + i: { + width: 6, // FIXME: hard code in v4 + height: 6, // FIXME: hard code in v4 + }, + }, + + // large + [`&-lg ${token.spinCls}-dot`]: { + fontSize: token.spinDotSizeLG, + + i: { + width: 14, // FIXME: hard code in v4 + height: 14, // FIXME: hard code in v4 + }, + }, + + [`&${token.spinCls}-show-text ${token.spinCls}-text`]: { + display: 'block', + }, + + // animation + antSpinMove, + antRotate, + }, +}); + +// ============================== Export ============================== +export default function useStyle(prefixCls: string): UseComponentStyleResult { + const [theme, token, hashId] = useToken(); + + const spinToken: SpinToken = { + ...token, + spinCls: `.${prefixCls}`, + spinDotDefault: token.colorTextSecondary, + spinDotSize: 20, // FIXME: hard code in v4 + spinDotSizeSM: 14, // FIXME: hard code in v4 + spinDotSizeLG: 32, // FIXME: hard code in v4 + }; + + return [ + useStyleRegister({ theme, token, hashId, path: [prefixCls] }, () => [ + genSpinStyle(spinToken, hashId), + ]), + hashId, + ]; +} diff --git a/components/table/Table.tsx b/components/table/Table.tsx index aed6bb309e..cec6668e27 100644 --- a/components/table/Table.tsx +++ b/components/table/Table.tsx @@ -4,6 +4,7 @@ import omit from 'rc-util/lib/omit'; import RcTable, { Summary } from 'rc-table'; import { TableProps as RcTableProps, INTERNAL_HOOKS } from 'rc-table/lib/Table'; import { convertChildrenToColumns } from 'rc-table/lib/hooks/useColumns'; +// eslint-disable-next-line import/no-named-as-default import Spin, { SpinProps } from '../spin'; import Pagination from '../pagination'; import { TooltipProps } from '../tooltip'; From c7553c2ba5d4ad00fbc96c1d19e86f99944117f1 Mon Sep 17 00:00:00 2001 From: Yunwoo Ji Date: Fri, 25 Mar 2022 15:27:30 +0900 Subject: [PATCH 08/11] docs: fix type of style in tabs component (#34706) --- components/tabs/index.en-US.md | 2 +- components/tabs/index.zh-CN.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/tabs/index.en-US.md b/components/tabs/index.en-US.md index c9b2559063..385d6c7dec 100644 --- a/components/tabs/index.en-US.md +++ b/components/tabs/index.en-US.md @@ -33,7 +33,7 @@ Ant Design has 3 types of Tabs for different situations. | size | Preset tab bar size | `large` \| `default` \| `small` | `default` | | | tabBarExtraContent | Extra content in tab bar | ReactNode \| {left?: ReactNode, right?: ReactNode} | - | object: 4.6.0 | | tabBarGutter | The gap between tabs | number | - | | -| tabBarStyle | Tab bar style object | object | - | | +| tabBarStyle | Tab bar style object | CSSProperties | - | | | tabPosition | Position of tabs | `top` \| `right` \| `bottom` \| `left` | `top` | | | destroyInactiveTabPane | Whether destroy inactive TabPane when change tab | boolean | false | | | type | Basic style of tabs | `line` \| `card` \| `editable-card` | `line` | | diff --git a/components/tabs/index.zh-CN.md b/components/tabs/index.zh-CN.md index 0e54eb999d..bd7deb80b7 100644 --- a/components/tabs/index.zh-CN.md +++ b/components/tabs/index.zh-CN.md @@ -36,7 +36,7 @@ Ant Design 依次提供了三级选项卡,分别用于不同的场景。 | size | 大小,提供 `large` `default` 和 `small` 三种大小 | string | `default` | | | tabBarExtraContent | tab bar 上额外的元素 | ReactNode \| {left?: ReactNode, right?: ReactNode} | - | object: 4.6.0 | | tabBarGutter | tabs 之间的间隙 | number | - | | -| tabBarStyle | tab bar 的样式对象 | object | - | | +| tabBarStyle | tab bar 的样式对象 | CSSProperties | - | | | tabPosition | 页签位置,可选值有 `top` `right` `bottom` `left` | string | `top` | | | destroyInactiveTabPane | 被隐藏时是否销毁 DOM 结构 | boolean | false | | | type | 页签的基本样式,可选 `line`、`card` `editable-card` 类型 | string | `line` | | From 2aa33578c276322455c8abce327fbb4b4674dacb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Fri, 25 Mar 2022 17:54:57 +0800 Subject: [PATCH 09/11] refactor: Align with token (#34713) * chore: Divider full token * chore: typography with tokn * chore: select with token * chore: tree with token * chore: select style * chore: select style * chore: clean up --- components/_util/theme/interface.ts | 7 ++ components/_util/theme/util/alias.ts | 23 ++--- components/_util/theme/util/index.tsx | 3 +- components/_util/theme/util/roundedArrow.tsx | 12 +-- components/cascader/style/index.tsx | 2 +- components/checkbox/style/index.tsx | 2 +- components/divider/style/index.tsx | 86 +++++++++-------- components/input/style/index.tsx | 6 +- components/popover/index.tsx | 5 +- components/popover/style/index.tsx | 22 ++--- components/select/style/dropdown.tsx | 2 +- components/select/style/index.tsx | 13 +-- components/select/style/multiple.tsx | 1 - components/tree/style/index.tsx | 2 +- components/typography/style/index.tsx | 57 +++++++----- components/typography/style/mixins.tsx | 97 ++++++++++---------- 16 files changed, 170 insertions(+), 170 deletions(-) diff --git a/components/_util/theme/interface.ts b/components/_util/theme/interface.ts index 633175a11b..e17233285e 100644 --- a/components/_util/theme/interface.ts +++ b/components/_util/theme/interface.ts @@ -1,5 +1,7 @@ import * as React from 'react'; import type { ComponentToken as ButtonComponentToken } from '../../button/style'; +import type { ComponentToken as DividerComponentToken } from '../../divider/style'; +import type { ComponentToken as TypographyComponentToken } from '../../typography/style'; export const PresetColors = [ 'blue', @@ -32,6 +34,8 @@ export interface OverrideToken { // Customize component button?: ButtonComponentToken; + divider?: DividerComponentToken; + typography?: TypographyComponentToken; } /** Final token which contains the components level override */ @@ -196,6 +200,9 @@ export interface AliasToken extends Omit { fontSizeHeading4: number; fontSizeHeading5: number; + /** For heading like h1, h2, h3 or option selected item */ + fontWeightStrong: number; + // LineHeight lineHeight: number; lineHeightLG: number; diff --git a/components/_util/theme/util/alias.ts b/components/_util/theme/util/alias.ts index 3f072aafdc..6ef0c37559 100644 --- a/components/_util/theme/util/alias.ts +++ b/components/_util/theme/util/alias.ts @@ -79,8 +79,9 @@ export default function formatToken(derivativeToken: RawMergedToken): AliasToken controlLineType: 'solid', controlRadius: mergedToken.radiusBase, colorBorder: new TinyColor({ h: 0, s: 0, v: 85 }).toHexString(), - colorSplit: new TinyColor({ h: 0, s: 0, v: 94 }).toHexString(), + colorSplit: 'rgba(0, 0, 0, 0.06)', controlItemBgActive: primaryColors[0], + fontWeightStrong: 600, // 🔥🔥🔥🔥🔥🔥🔥🔥🔥 All TMP Token leaves here 🔥🔥🔥🔥🔥🔥🔥🔥🔥 // FIXME: Handle this when derivative is ready @@ -97,21 +98,21 @@ export default function formatToken(derivativeToken: RawMergedToken): AliasToken linkHoverDecoration: 'none', linkFocusDecoration: 'none', - controlPaddingHorizontal: 16, - controlPaddingHorizontalSM: 12, + controlPaddingHorizontal: 12, + controlPaddingHorizontalSM: 8, padding: 16, margin: 16, - paddingXXS: 2, - paddingXS: 4, - paddingSM: 8, - paddingLG: 32, + paddingXXS: 4, + paddingXS: 8, + paddingSM: 12, + paddingLG: 24, - marginXXS: 2, - marginXS: 4, - marginSM: 8, - marginLG: 32, + marginXXS: 4, + marginXS: 8, + marginSM: 12, + marginLG: 24, boxShadow: ` 0 3px 6px -4px rgba(0, 0, 0, 0.12), diff --git a/components/_util/theme/util/index.tsx b/components/_util/theme/util/index.tsx index a08467980b..374d3421c4 100644 --- a/components/_util/theme/util/index.tsx +++ b/components/_util/theme/util/index.tsx @@ -17,7 +17,8 @@ export const resetComponent = (token: DerivativeToken): CSSObject => ({ }); export const resetIcon = (): CSSObject => ({ - display: 'inline-block', + display: 'inline-flex', + alignItems: 'center', color: 'inherit', fontStyle: 'normal', lineHeight: 0, diff --git a/components/_util/theme/util/roundedArrow.tsx b/components/_util/theme/util/roundedArrow.tsx index bfb98656aa..4777876665 100644 --- a/components/_util/theme/util/roundedArrow.tsx +++ b/components/_util/theme/util/roundedArrow.tsx @@ -2,11 +2,7 @@ import { CSSObject } from '@ant-design/cssinjs'; import seedToken from '../themes/default'; -export const roundedArrow = ( - width: number, - outerRadius: number, - bgColor: string, -): CSSObject => { +export const roundedArrow = (width: number, outerRadius: number, bgColor: string): CSSObject => { const cornerHeight = outerRadius * (1 - 1 / Math.sqrt(2)); const { radiusBase } = seedToken; @@ -33,9 +29,11 @@ export const roundedArrow = ( insetInlineStart: -width, width: width * 3, height: width * 3, - background: `linear-gradient(to left, ${bgColor} 50%, ${bgColor} 50%) no-repeat ${Math.ceil(-width + 1)}px ${Math.ceil(-width + 1)}px`, + background: `linear-gradient(to left, ${bgColor} 50%, ${bgColor} 50%) no-repeat ${Math.ceil( + -width + 1, + )}px ${Math.ceil(-width + 1)}px`, content: '""', clipPath: `path('M ${ax} ${ay} A ${outerRadius} ${outerRadius} 0 0 1 ${bx} ${by} L ${cx} ${cy} A ${radiusBase} ${radiusBase} 0 0 0 ${dx} ${dy} L ${ex} ${ey} A ${outerRadius} ${outerRadius} 0 0 1 ${fx} ${fy} Z')`, }, }; -} +}; diff --git a/components/cascader/style/index.tsx b/components/cascader/style/index.tsx index 40ad4a3e3c..fabb095743 100644 --- a/components/cascader/style/index.tsx +++ b/components/cascader/style/index.tsx @@ -123,7 +123,7 @@ const genBaseStyle: GenerateStyle = (token, hashId) => { [`&-active:not(${cascaderMenuItemCls}-disabled)`]: { [`&, &:hover`]: { - fontWeight: 600, // FIXME: hardcode + fontWeight: token.fontWeightStrong, backgroundColor: token.controlItemBgActive, }, }, diff --git a/components/checkbox/style/index.tsx b/components/checkbox/style/index.tsx index de843d1be3..b39d451e45 100644 --- a/components/checkbox/style/index.tsx +++ b/components/checkbox/style/index.tsx @@ -184,7 +184,7 @@ export const genCheckboxStyle: GenerateStyle = (token, hashId) => '&:after': { opacity: 1, transform: 'rotate(45deg) scale(1) translate(-50%,-50%)', - transition: `all ${token.motionDurationSlow} ${token.motionEaseOutBack} 0.1s`, + transition: `all ${token.motionDurationSlow} ${token.motionEaseOutBack} ${token.motionDurationFast}`, }, }, diff --git a/components/divider/style/index.tsx b/components/divider/style/index.tsx index a289a17288..e7a1f61759 100644 --- a/components/divider/style/index.tsx +++ b/components/divider/style/index.tsx @@ -9,14 +9,14 @@ import { GenerateStyle, } from '../../_util/theme'; -interface DividerToken extends DerivativeToken { +/** Component only token. Which will handle additional calculation of alias token */ +export interface ComponentToken { + sizePaddingEdgeHorizontal: number; +} + +interface DividerToken extends DerivativeToken, ComponentToken { dividerCls: string; - dividerBorderColor: string; - - dividerBorderWidth: number; - - dividerNotDefaultTextPadding: number; dividerVerticalGutterMargin: number; dividerHorizontalWithTextGutterMargin: number; dividerHorizontalGutterMargin: number; @@ -24,12 +24,12 @@ interface DividerToken extends DerivativeToken { // ============================== Shared ============================== const genSharedDividerStyle: GenerateStyle = (token): CSSObject => { - const { dividerCls } = token; + const { dividerCls, sizePaddingEdgeHorizontal, colorSplit, controlLineWidth } = token; return { [dividerCls]: { ...resetComponent(token), - borderBlockStart: `${token.dividerBorderWidth}px solid ${token.dividerBorderColor}`, + borderBlockStart: `${controlLineWidth}px solid ${colorSplit}`, // vertical '&-vertical': { @@ -40,7 +40,7 @@ const genSharedDividerStyle: GenerateStyle = (token): CSSObject => margin: `0 ${token.dividerVerticalGutterMargin}px`, verticalAlign: 'middle', borderTop: 0, - borderInlineStart: `${token.dividerBorderWidth}px solid ${token.dividerBorderColor}`, + borderInlineStart: `${controlLineWidth}px solid ${colorSplit}`, }, '&-horizontal': { @@ -59,13 +59,13 @@ const genSharedDividerStyle: GenerateStyle = (token): CSSObject => fontSize: token.fontSizeLG, whiteSpace: 'nowrap', textAlign: 'center', - borderBlockStart: `0 ${token.dividerBorderColor}`, + borderBlockStart: `0 ${colorSplit}`, '&::before, &::after': { position: 'relative', top: '50%', width: '50%', - borderBlockStart: `${token.dividerBorderWidth}px solid transparent`, + borderBlockStart: `${controlLineWidth}px solid transparent`, // Chrome not accept `inherit` in `border-top` borderBlockStartColor: 'inherit', borderBlockEnd: 0, @@ -105,10 +105,10 @@ const genSharedDividerStyle: GenerateStyle = (token): CSSObject => '&-dashed': { background: 'none', - borderColor: token.dividerBorderColor, + borderColor: colorSplit, borderStyle: 'dashed', borderWidth: 0, - borderBlockStart: `${token.dividerBorderWidth}px`, + borderBlockStart: `${controlLineWidth}px`, }, '&-horizontal&-with-text&-dashed': { @@ -118,7 +118,7 @@ const genSharedDividerStyle: GenerateStyle = (token): CSSObject => }, '&-vertical&-dashed': { - borderWidth: `0 0 0 ${token.dividerBorderWidth}px`, + borderWidth: `0 0 0 ${controlLineWidth}px`, }, '&-plain&-with-text': { @@ -136,8 +136,8 @@ const genSharedDividerStyle: GenerateStyle = (token): CSSObject => width: '100%', }, - '.ant-divider-inner-text': { - paddingInlineStart: `${token.dividerNotDefaultTextPadding}px`, + [`${dividerCls}-inner-text`]: { + paddingInlineStart: sizePaddingEdgeHorizontal, }, }, @@ -150,8 +150,8 @@ const genSharedDividerStyle: GenerateStyle = (token): CSSObject => width: 0, }, - '.ant-divider-inner-text': { - paddingInlineEnd: `${token.dividerNotDefaultTextPadding}px`, + [`${dividerCls}-inner-text`]: { + paddingInlineEnd: sizePaddingEdgeHorizontal, }, }, }, @@ -161,35 +161,31 @@ const genSharedDividerStyle: GenerateStyle = (token): CSSObject => // ============================== Export ============================== export default function useStyle(prefixCls: string): UseComponentStyleResult { const [theme, token, hashId] = useToken(); - // FIXME - const dividerBorderColor = 'rgba(0, 0, 0, 6%)'; - - const dividerBorderWidth = token.controlLineWidth; - - const dividerNotDefaultTextPadding = 0; - const dividerVerticalGutterMargin = token.marginXS; - const dividerHorizontalWithTextGutterMargin = token.margin; - const dividerHorizontalGutterMargin = token.marginLG; - - const dividerToken: DividerToken = { - ...token, - - dividerCls: `.${prefixCls}`, - - dividerBorderColor, - - dividerBorderWidth, - - dividerNotDefaultTextPadding, - dividerVerticalGutterMargin, - dividerHorizontalWithTextGutterMargin, - dividerHorizontalGutterMargin, - }; return [ - useStyleRegister({ theme, token, hashId, path: [prefixCls] }, () => [ - genSharedDividerStyle(dividerToken), - ]), + useStyleRegister({ theme, token, hashId, path: [prefixCls] }, () => { + const { divider } = token; + + const dividerVerticalGutterMargin = token.marginSM; + const dividerHorizontalWithTextGutterMargin = token.margin; + const dividerHorizontalGutterMargin = token.marginLG; + + const dividerToken: DividerToken = { + ...token, + + dividerCls: `.${prefixCls}`, + + sizePaddingEdgeHorizontal: 0, + + dividerVerticalGutterMargin, + dividerHorizontalWithTextGutterMargin, + dividerHorizontalGutterMargin, + + ...divider, + }; + + return [genSharedDividerStyle(dividerToken)]; + }), hashId, ]; } diff --git a/components/input/style/index.tsx b/components/input/style/index.tsx index d502e655ca..c1780baa07 100644 --- a/components/input/style/index.tsx +++ b/components/input/style/index.tsx @@ -75,7 +75,7 @@ const genInputLargeStyle = (token: InputToken): CSSObject => { }; const genInputSmallStyle = (token: InputToken): CSSObject => ({ - padding: `${token.inputPaddingVerticalSM}px ${token.paddingXS - 1}px`, + padding: `${token.inputPaddingVerticalSM}px ${token.controlPaddingHorizontalSM - 1}px`, }); export const genStatusStyle = (token: InputToken): CSSObject => { @@ -809,7 +809,7 @@ export const initInputToken = ( ...token, prefixCls, iconPrefixCls, - inputAffixMargin: token.marginXXS, + inputAffixMargin: token.marginXS, inputPaddingVertical: Math.max( Math.round(((token.controlHeight - token.fontSize * token.lineHeight) / 2) * 10) / 10 - token.controlLineWidth, @@ -823,7 +823,7 @@ export const initInputToken = ( token.controlLineWidth, 0, ), - inputPaddingHorizontal: token.paddingSM - token.controlLineWidth, + inputPaddingHorizontal: token.controlPaddingHorizontal - token.controlLineWidth, inputBorderHoverColor: token.colorPrimaryHover, inputBorderActiveColor: token.colorPrimaryHover, }); diff --git a/components/popover/index.tsx b/components/popover/index.tsx index 1db57e6348..be7839ba18 100644 --- a/components/popover/index.tsx +++ b/components/popover/index.tsx @@ -31,10 +31,7 @@ const Popover = React.forwardRef( const [wrapSSR, hashId] = useStyle(prefixCls, iconPrefixCls); const rootPrefixCls = getPrefixCls(); - const overlayCls = classNames( - overlayClassName, - hashId, - ); + const overlayCls = classNames(overlayClassName, hashId); return wrapSSR( = token => { const { popoverCls, @@ -126,7 +125,7 @@ const genBaseStyle: GenerateStyle = token => { [`> .${iconPrefixCls}`]: { position: 'absolute', // FIXME - top: 4 + ((lineHeight * fontSize - fontSize) / 2), + top: 4 + (lineHeight * fontSize - fontSize) / 2, color: colorWarning, fontSize, }, @@ -142,7 +141,7 @@ const genBaseStyle: GenerateStyle = token => { marginBottom: marginXS, textAlign: 'end', - 'button': { + button: { marginInlineStart: marginSM, }, }, @@ -172,9 +171,8 @@ const genBaseStyle: GenerateStyle = token => { ...roundedArrow(popoverArrowWidth, 5, popoverBg), }, }, - }, - } + }; }; const genPlacementStyle: GenerateStyle = token => { @@ -235,7 +233,7 @@ const genPlacementStyle: GenerateStyle = token => { }, [`&-placement-top ${popoverCls}-arrow`]: { - insetInlineStart : '50%', + insetInlineStart: '50%', transform: 'translateX(-50%)', }, @@ -328,7 +326,7 @@ const genPlacementStyle: GenerateStyle = token => { bottom: popoverArrowOffsetVertical, }, }, - } + }; }; // FIXME: special preset colors @@ -353,11 +351,9 @@ const genColorStyle: GenerateStyle = token => { }, {} as CSSObject); }; -export const genPopoverStyle: GenerateStyle = (token: PopoverToken): CSSInterpolation => [ - genBaseStyle(token), - genPlacementStyle(token), - genColorStyle(token), -]; +export const genPopoverStyle: GenerateStyle = ( + token: PopoverToken, +): CSSInterpolation => [genBaseStyle(token), genPlacementStyle(token), genColorStyle(token)]; export default function useStyle( prefixCls: string, diff --git a/components/select/style/dropdown.tsx b/components/select/style/dropdown.tsx index 302ccf6f97..f3a950b132 100644 --- a/components/select/style/dropdown.tsx +++ b/components/select/style/dropdown.tsx @@ -123,7 +123,7 @@ const genSingleStyle: GenerateStyle = (token, hashId) => { [`&-selected:not(${selectItemCls}-option-disabled)`]: { color: token.colorText, - fontWeight: 600, // FIXME: Need design token? + fontWeight: token.fontWeightStrong, backgroundColor: token.controlItemBgActive, [`${selectItemCls}-option-state`]: { diff --git a/components/select/style/index.tsx b/components/select/style/index.tsx index 31b788bdc9..8fa3c6fbf9 100644 --- a/components/select/style/index.tsx +++ b/components/select/style/index.tsx @@ -96,7 +96,6 @@ const genStatusStyle = ( [`${selectCls}-focused& ${selectCls}-selector`]: { borderColor: borderHoverColor, - // FIXME: missing variable of `@input-outline-offset` boxShadow: `0 0 0 ${token.controlOutlineWidth}px ${outlineColor}`, borderInlineEndWidth: `${token.controlLineWidth}px !important`, outline: 0, @@ -179,7 +178,6 @@ const genBaseStyle: GenerateStyle = token => { top: '50%', insetInlineStart: 'auto', insetInlineEnd: inputPaddingHorizontalBase, - width: token.fontSizeSM, height: token.fontSizeSM, marginTop: -token.fontSizeSM / 2, color: token.colorTextDisabled, @@ -236,8 +234,10 @@ const genBaseStyle: GenerateStyle = token => { '&:hover': { color: token.colorTextSecondary, }, + }, - [`${selectCls}:hover &`]: { + '&:hover': { + [`${selectCls}-clear`]: { opacity: 1, }, }, @@ -246,12 +246,7 @@ const genBaseStyle: GenerateStyle = token => { // ========================= Feedback ========================== [`${selectCls}-has-feedback`]: { [`${selectCls}-clear`]: { - insetInlineEnd: token.padding * 2, - }, - - // FIXME: what's this? @MadCcc - [`${selectCls}-selection-selected-value`]: { - paddingInlineEnd: 42, + insetInlineEnd: inputPaddingHorizontalBase + token.fontSize + token.paddingXXS, }, [`${selectCls}-feedback-icon`]: { diff --git a/components/select/style/multiple.tsx b/components/select/style/multiple.tsx index 071412f976..d4a5ff8795 100644 --- a/components/select/style/multiple.tsx +++ b/components/select/style/multiple.tsx @@ -148,7 +148,6 @@ function genSizeStyle(token: SelectToken, suffix?: string): CSSObject { display: 'inline-flex', position: 'relative', maxWidth: '100%', - // FIXME: no sure this style marginInlineStart: token.inputPaddingHorizontalBase - selectItemDist, [` diff --git a/components/tree/style/index.tsx b/components/tree/style/index.tsx index b2a1c96926..7a236c39a1 100644 --- a/components/tree/style/index.tsx +++ b/components/tree/style/index.tsx @@ -26,7 +26,7 @@ const treeNodeFX = new Keyframes('ant-tree-node-fx-do-not-use', { const getSwitchStyle = (prefixCls: string, token: DerivativeToken): CSSObject => ({ [`.${prefixCls}-switcher-icon`]: { display: 'inline-block', - fontSize: 10, // FIXME: missing token + fontSize: 10, verticalAlign: 'baseline', svg: { diff --git a/components/typography/style/index.tsx b/components/typography/style/index.tsx index a4f1ed2fbd..bdfe2a0e0e 100644 --- a/components/typography/style/index.tsx +++ b/components/typography/style/index.tsx @@ -1,6 +1,6 @@ // deps-lint-skip-all import { useStyleRegister, useToken } from '../../_util/theme'; -import type { UseComponentStyleResult, GenerateStyle } from '../../_util/theme'; +import type { UseComponentStyleResult, GenerateStyle, AliasToken } from '../../_util/theme'; import { operationUnit } from '../../_util/theme/util/operationUnit'; import { getTitleStyles, @@ -10,12 +10,22 @@ import { getCopiableStyles, getEllipsisStyles, } from './mixins'; -import type { TypographyToken } from './mixins'; + +/** Component only token. Which will handle additional calculation of alias token */ +export interface ComponentToken { + sizeMarginHeadingVerticalStart: number | string; + sizeMarginHeadingVerticalEnd: number | string; +} + +export interface TypographyToken extends AliasToken, ComponentToken { + typographyCls: string; +} const genTypographyStyle: GenerateStyle = token => { - const { prefixCls, titleMarginTop } = token.typography; + const { typographyCls, sizeMarginHeadingVerticalStart } = token; + return { - [`.${prefixCls}`]: { + [typographyCls]: { color: token.colorText, overflowWrap: 'break-word', '&&-secondary': { @@ -59,7 +69,7 @@ const genTypographyStyle: GenerateStyle = token => { & + h4&, & + h5& `]: { - marginTop: titleMarginTop, + marginTop: sizeMarginHeadingVerticalStart, }, [` @@ -79,7 +89,7 @@ const genTypographyStyle: GenerateStyle = token => { + h4, + h5 `]: { - marginTop: titleMarginTop, + marginTop: sizeMarginHeadingVerticalStart, }, }, @@ -89,9 +99,9 @@ const genTypographyStyle: GenerateStyle = token => { // Operation [` - .${prefixCls}-expand, - .${prefixCls}-edit, - .${prefixCls}-copy + ${typographyCls}-expand, + ${typographyCls}-edit, + ${typographyCls}-copy `]: { ...operationUnit(token), marginInlineStart: token.marginXXS, @@ -114,20 +124,23 @@ const genTypographyStyle: GenerateStyle = token => { export default function useStyle(prefixCls: string): UseComponentStyleResult { const [theme, token, hashId] = useToken(); - const typographyToken: TypographyToken = { - ...token, - typography: { - prefixCls, - titleMarginTop: '1.2em', - titleMarginBottom: '0.5em', - titleFontWeight: 600, - }, - }; - return [ - useStyleRegister({ theme, token, hashId, path: [prefixCls] }, () => [ - genTypographyStyle(typographyToken), - ]), + useStyleRegister({ theme, token, hashId, path: [prefixCls] }, () => { + const { typography } = token; + + const typographyToken: TypographyToken = { + ...token, + + typographyCls: `.${prefixCls}`, + + sizeMarginHeadingVerticalStart: '1.2em', + sizeMarginHeadingVerticalEnd: '0.5em', + + ...typography, + }; + + return [genTypographyStyle(typographyToken)]; + }), hashId, ]; } diff --git a/components/typography/style/mixins.tsx b/components/typography/style/mixins.tsx index 73c16129b9..dc401f06a3 100644 --- a/components/typography/style/mixins.tsx +++ b/components/typography/style/mixins.tsx @@ -9,37 +9,28 @@ */ import { gold } from '@ant-design/colors'; import type { CSSObject } from '@ant-design/cssinjs'; -import type { DerivativeToken, GenerateStyle } from '../../_util/theme'; +import type { GenerateStyle } from '../../_util/theme'; import { operationUnit } from '../../_util/theme/util/operationUnit'; import { initInputToken } from '../../input/style'; - -export interface TypographyToken extends DerivativeToken { - typography: { - prefixCls: string; - titleMarginTop: string; - titleMarginBottom: string; - titleFontWeight: number; - }; -} +import type { TypographyToken } from '.'; // eslint-disable-next-line import/prefer-default-export -const getTitleStyle = ({ - fontSize, - lineHeight, - color, - typographyToken, -}: { - fontSize: number; - lineHeight: number; - color: string; - typographyToken: TypographyToken['typography']; -}) => ({ - marginBottom: typographyToken.titleMarginBottom, - color, - fontWeight: typographyToken.titleFontWeight, - fontSize, - lineHeight, -}); +const getTitleStyle = ( + fontSize: number, + lineHeight: number, + color: string, + token: TypographyToken, +) => { + const { sizeMarginHeadingVerticalEnd, fontWeightStrong } = token; + + return { + marginBottom: sizeMarginHeadingVerticalEnd, + color, + fontWeight: fontWeightStrong, + fontSize, + lineHeight, + }; +}; // eslint-disable-next-line import/prefer-default-export export const getTitleStyles: GenerateStyle = token => { @@ -54,39 +45,43 @@ export const getTitleStyles: GenerateStyle = token = div&-h${headingLevel} > textarea, h${headingLevel} ` - ] = getTitleStyle({ - fontSize: token[`fontSizeHeading${headingLevel}`], - lineHeight: token[`lineHeightHeading${headingLevel}`], - color: token.colorTextHeading, - typographyToken: token.typography, - }); + ] = getTitleStyle( + token[`fontSizeHeading${headingLevel}`], + token[`lineHeightHeading${headingLevel}`], + token.colorTextHeading, + token, + ); }); return styles; }; -export const getLinkStyles: GenerateStyle = token => ({ - 'a&, a': { - ...operationUnit(token), - textDecoration: token.linkDecoration, +export const getLinkStyles: GenerateStyle = token => { + const { typographyCls } = token; - '&:active, &:hover': { - textDecoration: token.linkHoverDecoration, - }, - - [`&[disabled], &.${token.typography.prefixCls}-disabled`]: { - color: token.colorTextDisabled, - cursor: 'not-allowed', + return { + 'a&, a': { + ...operationUnit(token), + textDecoration: token.linkDecoration, '&:active, &:hover': { - color: '@disabled-color', + textDecoration: token.linkHoverDecoration, }, - '&:active': { - pointerEvents: 'none', + [`&[disabled], &${typographyCls}-disabled`]: { + color: token.colorTextDisabled, + cursor: 'not-allowed', + + '&:active, &:hover': { + color: token.colorTextDisabled, + }, + + '&:active': { + pointerEvents: 'none', + }, }, }, - }, -}); + }; +}; export const getResetStyles = (): CSSObject => ({ code: { @@ -188,6 +183,8 @@ export const getResetStyles = (): CSSObject => ({ }); export const getEditableStyles: GenerateStyle = token => { + const { typographyCls } = token; + const inputToken = initInputToken(token, '', ''); const inputShift = inputToken.inputPaddingVertical + 1; return { @@ -200,7 +197,7 @@ export const getEditableStyles: GenerateStyle = toke marginBottom: `calc(1em - ${inputShift}px)`, }, - [`.${token.typography.prefixCls}-edit-content-confirm`]: { + [`${typographyCls}-edit-content-confirm`]: { position: 'absolute', insetInlineEnd: token.marginXS + 2, insetBlockEnd: token.marginXS, From 1935ece58204e450b5cd79d4b6d1830b3305f9a9 Mon Sep 17 00:00:00 2001 From: afc163 Date: Fri, 25 Mar 2022 19:38:28 +0800 Subject: [PATCH 10/11] fix: notification prevent interaction on elements which under it (#34716) * fix: notification prevent interaction on elements which under it close #34700 * fix test case --- .../__snapshots__/demo-extend.test.ts.snap | 14 ++-- .../__tests__/__snapshots__/demo.test.js.snap | 14 ++-- .../notification/__tests__/placement.test.js | 10 +-- components/notification/demo/placement.md | 46 ++++++++----- components/notification/index.tsx | 10 +-- components/notification/style/index.less | 32 +-------- components/notification/style/placement.less | 68 +++++++++++++++++++ 7 files changed, 125 insertions(+), 69 deletions(-) create mode 100644 components/notification/style/placement.less diff --git a/components/notification/__tests__/__snapshots__/demo-extend.test.ts.snap b/components/notification/__tests__/__snapshots__/demo-extend.test.ts.snap index 586575b02d..70d1afe20d 100644 --- a/components/notification/__tests__/__snapshots__/demo-extend.test.ts.snap +++ b/components/notification/__tests__/__snapshots__/demo-extend.test.ts.snap @@ -188,7 +188,7 @@ Array [ `; exports[`renders ./components/notification/demo/placement.md extend context correctly 1`] = ` -
+Array [
@@ -255,11 +255,11 @@ exports[`renders ./components/notification/demo/placement.md extend context corr
-
+
, +
, -
+
, +] `; exports[`renders ./components/notification/demo/update.md extend context correctly 1`] = ` diff --git a/components/notification/__tests__/__snapshots__/demo.test.js.snap b/components/notification/__tests__/__snapshots__/demo.test.js.snap index 419ebc8e60..bbb7b6fca1 100644 --- a/components/notification/__tests__/__snapshots__/demo.test.js.snap +++ b/components/notification/__tests__/__snapshots__/demo.test.js.snap @@ -188,7 +188,7 @@ Array [ `; exports[`renders ./components/notification/demo/placement.md correctly 1`] = ` -
+Array [
@@ -255,11 +255,11 @@ exports[`renders ./components/notification/demo/placement.md correctly 1`] = `
-
+
, +
, -
+
, +] `; exports[`renders ./components/notification/demo/update.md correctly 1`] = ` diff --git a/components/notification/__tests__/placement.test.js b/components/notification/__tests__/placement.test.js index e7fed3a720..054b109e80 100644 --- a/components/notification/__tests__/placement.test.js +++ b/components/notification/__tests__/placement.test.js @@ -41,8 +41,9 @@ describe('Notification.placement', () => { }); style = getStyle($$('.ant-notification-top')[0]); expect(style.top).toBe('50px'); - expect(style.left).toBe('0px'); - expect(style.right).toBe('0px'); + expect(style.left).toBe('50%'); + expect(style.transform).toBe('translateX(-50%)'); + expect(style.right).toBe(''); expect(style.bottom).toBe(''); open({ @@ -86,8 +87,9 @@ describe('Notification.placement', () => { }); style = getStyle($$('.ant-notification-bottom')[0]); expect(style.top).toBe(''); - expect(style.left).toBe('0px'); - expect(style.right).toBe('0px'); + expect(style.left).toBe('50%'); + expect(style.transform).toBe('translateX(-50%)'); + expect(style.right).toBe(''); expect(style.bottom).toBe('100px'); open({ diff --git a/components/notification/demo/placement.md b/components/notification/demo/placement.md index 73531c20ab..874366e943 100755 --- a/components/notification/demo/placement.md +++ b/components/notification/demo/placement.md @@ -7,11 +7,11 @@ title: ## zh-CN -通知从右上角、右下角、左下角、左上角弹出。 +使用 `placement` 可以配置通知从右上角、右下角、左下角、左上角弹出。 ## en-US -A notification box can appear from the `topRight`, `bottomRight`, `bottomLeft` or `topLeft` of the viewport. +A notification box can appear from the `topRight`, `bottomRight`, `bottomLeft` or `topLeft` of the viewport via `placement`. ```jsx import { Button, notification, Divider, Space } from 'antd'; @@ -34,40 +34,54 @@ const openNotification = placement => { }; ReactDOM.render( -
+ <> - - - - - - -
, + , mountNode, ); ``` diff --git a/components/notification/index.tsx b/components/notification/index.tsx index 620a192405..15fb147454 100755 --- a/components/notification/index.tsx +++ b/components/notification/index.tsx @@ -87,8 +87,9 @@ function getPlacementStyle( switch (placement) { case 'top': style = { - left: 0, - right: 0, + left: '50%', + transform: 'translateX(-50%)', + right: 'auto', top, bottom: 'auto', }; @@ -109,8 +110,9 @@ function getPlacementStyle( break; case 'bottom': style = { - left: 0, - right: 0, + left: '50%', + transform: 'translateX(-50%)', + right: 'auto', top: 'auto', bottom, }; diff --git a/components/notification/style/index.less b/components/notification/style/index.less index fd457e392a..ae0d0a6744 100644 --- a/components/notification/style/index.less +++ b/components/notification/style/index.less @@ -16,25 +16,6 @@ z-index: @zindex-notification; margin-right: @notification-margin-edge; - &-top, - &-bottom, - &-topLeft, - &-bottomLeft { - margin-right: 0; - margin-left: @notification-margin-edge; - - .@{notification-prefix-cls}-fade-enter.@{notification-prefix-cls}-fade-enter-active, - .@{notification-prefix-cls}-fade-appear.@{notification-prefix-cls}-fade-appear-active { - animation-name: NotificationLeftFadeIn; - } - } - - &-top, - &-bottom { - margin-right: auto; - margin-left: auto; - } - &-close-icon { font-size: @font-size-base; cursor: pointer; @@ -206,18 +187,6 @@ } } -@keyframes NotificationLeftFadeIn { - 0% { - right: @notification-width; - opacity: 0; - } - - 100% { - right: 0; - opacity: 1; - } -} - @keyframes NotificationFadeOut { 0% { max-height: 150px; @@ -235,3 +204,4 @@ } @import './rtl'; +@import './placement'; diff --git a/components/notification/style/placement.less b/components/notification/style/placement.less new file mode 100644 index 0000000000..9a60fecac4 --- /dev/null +++ b/components/notification/style/placement.less @@ -0,0 +1,68 @@ +.@{notification-prefix-cls} { + &-top, + &-bottom { + margin-right: 0; + margin-left: 0; + } + + &-top { + .@{notification-prefix-cls}-fade-enter.@{notification-prefix-cls}-fade-enter-active, + .@{notification-prefix-cls}-fade-appear.@{notification-prefix-cls}-fade-appear-active { + animation-name: NotificationTopFadeIn; + } + } + + &-bottom { + .@{notification-prefix-cls}-fade-enter.@{notification-prefix-cls}-fade-enter-active, + .@{notification-prefix-cls}-fade-appear.@{notification-prefix-cls}-fade-appear-active { + animation-name: NotificationBottomFadeIn; + } + } + + &-topLeft, + &-bottomLeft { + margin-right: 0; + margin-left: @notification-margin-edge; + + .@{notification-prefix-cls}-fade-enter.@{notification-prefix-cls}-fade-enter-active, + .@{notification-prefix-cls}-fade-appear.@{notification-prefix-cls}-fade-appear-active { + animation-name: NotificationLeftFadeIn; + } + } +} + +@keyframes NotificationTopFadeIn { + 0% { + margin-top: -100%; + opacity: 0; + } + + 100% { + margin-top: 0; + opacity: 1; + } +} + +@keyframes NotificationBottomFadeIn { + 0% { + margin-bottom: -100%; + opacity: 0; + } + + 100% { + margin-bottom: 0; + opacity: 1; + } +} + +@keyframes NotificationLeftFadeIn { + 0% { + right: @notification-width; + opacity: 0; + } + + 100% { + right: 0; + opacity: 1; + } +} From 9af935f7d3cce846be45f8e4c29ed7bf45672048 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=91=E9=9B=A8?= Date: Fri, 25 Mar 2022 20:11:33 +0800 Subject: [PATCH 11/11] refactor: use useContext in skeleton (#34699) * feat: use useContext in skeleton * feat: use useContext in skeleton * feat: update for lint --- components/skeleton/Avatar.tsx | 39 ++++--- components/skeleton/Button.tsx | 41 ++++---- components/skeleton/Image.tsx | 36 +++---- components/skeleton/Input.tsx | 41 ++++---- components/skeleton/Skeleton.tsx | 171 +++++++++++++++---------------- 5 files changed, 160 insertions(+), 168 deletions(-) diff --git a/components/skeleton/Avatar.tsx b/components/skeleton/Avatar.tsx index 59fdb79ee1..c708829d91 100644 --- a/components/skeleton/Avatar.tsx +++ b/components/skeleton/Avatar.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import omit from 'rc-util/lib/omit'; import classNames from 'classnames'; -import { ConfigConsumer, ConfigConsumerProps } from '../config-provider'; +import { ConfigContext } from '../config-provider'; import Element, { SkeletonElementProps } from './Element'; export interface AvatarProps extends Omit { @@ -9,25 +9,24 @@ export interface AvatarProps extends Omit { } const SkeletonAvatar = (props: AvatarProps) => { - const renderSkeletonAvatar = ({ getPrefixCls }: ConfigConsumerProps) => { - const { prefixCls: customizePrefixCls, className, active } = props; - const prefixCls = getPrefixCls('skeleton', customizePrefixCls); - const otherProps = omit(props, ['prefixCls', 'className']); - const cls = classNames( - prefixCls, - `${prefixCls}-element`, - { - [`${prefixCls}-active`]: active, - }, - className, - ); - return ( -
- -
- ); - }; - return {renderSkeletonAvatar}; + const { prefixCls: customizePrefixCls, className, active } = props; + const { getPrefixCls } = React.useContext(ConfigContext); + const prefixCls = getPrefixCls('skeleton', customizePrefixCls); + + const otherProps = omit(props, ['prefixCls', 'className']); + const cls = classNames( + prefixCls, + `${prefixCls}-element`, + { + [`${prefixCls}-active`]: active, + }, + className, + ); + return ( +
+ +
+ ); }; SkeletonAvatar.defaultProps = { diff --git a/components/skeleton/Button.tsx b/components/skeleton/Button.tsx index 4f51d08ab9..5ca1872257 100644 --- a/components/skeleton/Button.tsx +++ b/components/skeleton/Button.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import omit from 'rc-util/lib/omit'; import classNames from 'classnames'; import Element, { SkeletonElementProps } from './Element'; -import { ConfigConsumer, ConfigConsumerProps } from '../config-provider'; +import { ConfigContext } from '../config-provider'; export interface SkeletonButtonProps extends Omit { size?: 'large' | 'small' | 'default'; @@ -10,26 +10,25 @@ export interface SkeletonButtonProps extends Omit } const SkeletonButton = (props: SkeletonButtonProps) => { - const renderSkeletonButton = ({ getPrefixCls }: ConfigConsumerProps) => { - const { prefixCls: customizePrefixCls, className, active, block = false } = props; - const prefixCls = getPrefixCls('skeleton', customizePrefixCls); - const otherProps = omit(props, ['prefixCls']); - const cls = classNames( - prefixCls, - `${prefixCls}-element`, - { - [`${prefixCls}-active`]: active, - [`${prefixCls}-block`]: block, - }, - className, - ); - return ( -
- -
- ); - }; - return {renderSkeletonButton}; + const { prefixCls: customizePrefixCls, className, active, block = false } = props; + const { getPrefixCls } = React.useContext(ConfigContext); + const prefixCls = getPrefixCls('skeleton', customizePrefixCls); + + const otherProps = omit(props, ['prefixCls']); + const cls = classNames( + prefixCls, + `${prefixCls}-element`, + { + [`${prefixCls}-active`]: active, + [`${prefixCls}-block`]: block, + }, + className, + ); + return ( +
+ +
+ ); }; SkeletonButton.defaultProps = { diff --git a/components/skeleton/Image.tsx b/components/skeleton/Image.tsx index ccde31bc18..3f31a7179b 100644 --- a/components/skeleton/Image.tsx +++ b/components/skeleton/Image.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import classNames from 'classnames'; import { SkeletonElementProps } from './Element'; -import { ConfigConsumer, ConfigConsumerProps } from '../config-provider'; +import { ConfigContext } from '../config-provider'; export interface SkeletonImageProps extends Omit {} @@ -10,26 +10,24 @@ const path = 'M365.714286 329.142857q0 45.714286-32.036571 77.677714t-77.677714 32.036571-77.677714-32.036571-32.036571-77.677714 32.036571-77.677714 77.677714-32.036571 77.677714 32.036571 32.036571 77.677714zM950.857143 548.571429l0 256-804.571429 0 0-109.714286 182.857143-182.857143 91.428571 91.428571 292.571429-292.571429zM1005.714286 146.285714l-914.285714 0q-7.460571 0-12.873143 5.412571t-5.412571 12.873143l0 694.857143q0 7.460571 5.412571 12.873143t12.873143 5.412571l914.285714 0q7.460571 0 12.873143-5.412571t5.412571-12.873143l0-694.857143q0-7.460571-5.412571-12.873143t-12.873143-5.412571zM1097.142857 164.571429l0 694.857143q0 37.741714-26.843429 64.585143t-64.585143 26.843429l-914.285714 0q-37.741714 0-64.585143-26.843429t-26.843429-64.585143l0-694.857143q0-37.741714 26.843429-64.585143t64.585143-26.843429l914.285714 0q37.741714 0 64.585143 26.843429t26.843429 64.585143z'; const SkeletonImage = (props: SkeletonImageProps) => { - const renderSkeletonImage = ({ getPrefixCls }: ConfigConsumerProps) => { - const { prefixCls: customizePrefixCls, className, style } = props; - const prefixCls = getPrefixCls('skeleton', customizePrefixCls); - const cls = classNames(prefixCls, `${prefixCls}-element`, className); + const { prefixCls: customizePrefixCls, className, style } = props; + const { getPrefixCls } = React.useContext(ConfigContext); + const prefixCls = getPrefixCls('skeleton', customizePrefixCls); + const cls = classNames(prefixCls, `${prefixCls}-element`, className); - return ( -
-
- - - -
+ return ( +
+
+ + +
- ); - }; - return {renderSkeletonImage}; +
+ ); }; export default SkeletonImage; diff --git a/components/skeleton/Input.tsx b/components/skeleton/Input.tsx index 1cb5e31f85..61532c4756 100644 --- a/components/skeleton/Input.tsx +++ b/components/skeleton/Input.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import omit from 'rc-util/lib/omit'; import classNames from 'classnames'; import Element, { SkeletonElementProps } from './Element'; -import { ConfigConsumer, ConfigConsumerProps } from '../config-provider'; +import { ConfigContext } from '../config-provider'; export interface SkeletonInputProps extends Omit { size?: 'large' | 'small' | 'default'; @@ -10,26 +10,25 @@ export interface SkeletonInputProps extends Omit { - const renderSkeletonInput = ({ getPrefixCls }: ConfigConsumerProps) => { - const { prefixCls: customizePrefixCls, className, active, block } = props; - const prefixCls = getPrefixCls('skeleton', customizePrefixCls); - const otherProps = omit(props, ['prefixCls']); - const cls = classNames( - prefixCls, - `${prefixCls}-element`, - { - [`${prefixCls}-active`]: active, - [`${prefixCls}-block`]: block, - }, - className, - ); - return ( -
- -
- ); - }; - return {renderSkeletonInput}; + const { prefixCls: customizePrefixCls, className, active, block } = props; + const { getPrefixCls } = React.useContext(ConfigContext); + const prefixCls = getPrefixCls('skeleton', customizePrefixCls); + + const otherProps = omit(props, ['prefixCls']); + const cls = classNames( + prefixCls, + `${prefixCls}-element`, + { + [`${prefixCls}-active`]: active, + [`${prefixCls}-block`]: block, + }, + className, + ); + return ( +
+ +
+ ); }; SkeletonInput.defaultProps = { diff --git a/components/skeleton/Skeleton.tsx b/components/skeleton/Skeleton.tsx index 41b64629b7..a809371ba1 100644 --- a/components/skeleton/Skeleton.tsx +++ b/components/skeleton/Skeleton.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import classNames from 'classnames'; import Title, { SkeletonTitleProps } from './Title'; import Paragraph, { SkeletonParagraphProps } from './Paragraph'; -import { ConfigConsumer, ConfigConsumerProps } from '../config-provider'; +import { ConfigContext } from '../config-provider'; import Element from './Element'; import SkeletonAvatar, { AvatarProps } from './Avatar'; import SkeletonButton from './Button'; @@ -72,99 +72,96 @@ function getParagraphBasicProps(hasAvatar: boolean, hasTitle: boolean): Skeleton } const Skeleton = (props: SkeletonProps) => { - const renderSkeleton = ({ getPrefixCls, direction }: ConfigConsumerProps) => { - const { - prefixCls: customizePrefixCls, - loading, - className, - style, - children, - avatar, - title, - paragraph, - active, - round, - } = props; + const { + prefixCls: customizePrefixCls, + loading, + className, + style, + children, + avatar, + title, + paragraph, + active, + round, + } = props; - const prefixCls = getPrefixCls('skeleton', customizePrefixCls); + const { getPrefixCls, direction } = React.useContext(ConfigContext); + const prefixCls = getPrefixCls('skeleton', customizePrefixCls); - if (loading || !('loading' in props)) { - const hasAvatar = !!avatar; - const hasTitle = !!title; - const hasParagraph = !!paragraph; + if (loading || !('loading' in props)) { + const hasAvatar = !!avatar; + const hasTitle = !!title; + const hasParagraph = !!paragraph; - // Avatar - let avatarNode; - if (hasAvatar) { - const avatarProps: SkeletonAvatarProps = { - prefixCls: `${prefixCls}-avatar`, - ...getAvatarBasicProps(hasTitle, hasParagraph), - ...getComponentProps(avatar), - }; - // We direct use SkeletonElement as avatar in skeleton internal. - avatarNode = ( -
- -
- ); - } - - let contentNode; - if (hasTitle || hasParagraph) { - // Title - let $title; - if (hasTitle) { - const titleProps: SkeletonTitleProps = { - prefixCls: `${prefixCls}-title`, - ...getTitleBasicProps(hasAvatar, hasParagraph), - ...getComponentProps(title), - }; - - $title = ; - } - - // Paragraph - let paragraphNode; - if (hasParagraph) { - const paragraphProps: SkeletonParagraphProps = { - prefixCls: `${prefixCls}-paragraph`, - ...getParagraphBasicProps(hasAvatar, hasTitle), - ...getComponentProps(paragraph), - }; - - paragraphNode = <Paragraph {...paragraphProps} />; - } - - contentNode = ( - <div className={`${prefixCls}-content`}> - {$title} - {paragraphNode} - </div> - ); - } - - const cls = classNames( - prefixCls, - { - [`${prefixCls}-with-avatar`]: hasAvatar, - [`${prefixCls}-active`]: active, - [`${prefixCls}-rtl`]: direction === 'rtl', - [`${prefixCls}-round`]: round, - }, - className, - ); - - return ( - <div className={cls} style={style}> - {avatarNode} - {contentNode} + // Avatar + let avatarNode; + if (hasAvatar) { + const avatarProps: SkeletonAvatarProps = { + prefixCls: `${prefixCls}-avatar`, + ...getAvatarBasicProps(hasTitle, hasParagraph), + ...getComponentProps(avatar), + }; + // We direct use SkeletonElement as avatar in skeleton internal. + avatarNode = ( + <div className={`${prefixCls}-header`}> + <Element {...avatarProps} /> </div> ); } - return children; - }; - return <ConfigConsumer>{renderSkeleton}</ConfigConsumer>; + let contentNode; + if (hasTitle || hasParagraph) { + // Title + let $title; + if (hasTitle) { + const titleProps: SkeletonTitleProps = { + prefixCls: `${prefixCls}-title`, + ...getTitleBasicProps(hasAvatar, hasParagraph), + ...getComponentProps(title), + }; + + $title = <Title {...titleProps} />; + } + + // Paragraph + let paragraphNode; + if (hasParagraph) { + const paragraphProps: SkeletonParagraphProps = { + prefixCls: `${prefixCls}-paragraph`, + ...getParagraphBasicProps(hasAvatar, hasTitle), + ...getComponentProps(paragraph), + }; + + paragraphNode = <Paragraph {...paragraphProps} />; + } + + contentNode = ( + <div className={`${prefixCls}-content`}> + {$title} + {paragraphNode} + </div> + ); + } + + const cls = classNames( + prefixCls, + { + [`${prefixCls}-with-avatar`]: hasAvatar, + [`${prefixCls}-active`]: active, + [`${prefixCls}-rtl`]: direction === 'rtl', + [`${prefixCls}-round`]: round, + }, + className, + ); + + return ( + <div className={cls} style={style}> + {avatarNode} + {contentNode} + </div> + ); + } + return React.isValidElement(children) ? children : null; }; Skeleton.defaultProps = {