From 08d1a71ff4b8c430b0fb967854c8ebc05eaffa6c Mon Sep 17 00:00:00 2001 From: afc163 Date: Mon, 25 Apr 2022 18:46:53 +0800 Subject: [PATCH] refactor: Move Upload from less to css in js (#34528) * refactor: Upload to CSS-in-JS * chore: clean up outdated code * chore: add FIXME * revert useless change of UploadList * fix: upload animation --- components/_util/theme/interface.ts | 2 + components/_util/theme/themes/default.ts | 6 +- components/card/style/index.tsx | 4 +- .../__snapshots__/components.test.js.snap | 720 ++-- .../__snapshots__/demo-extend.test.ts.snap | 8 +- .../__tests__/__snapshots__/demo.test.js.snap | 8 +- .../__snapshots__/demo-extend.test.ts.snap | 4 +- .../__tests__/__snapshots__/demo.test.js.snap | 4 +- components/upload/Upload.tsx | 40 +- components/upload/UploadList/ListItem.tsx | 53 +- components/upload/UploadList/index.tsx | 7 +- .../__snapshots__/demo-extend.test.ts.snap | 2938 ++++++++--------- .../__tests__/__snapshots__/demo.test.js.snap | 2938 ++++++++--------- .../__snapshots__/upload.test.js.snap | 6 +- .../__snapshots__/uploadlist.test.js.snap | 2098 ++++++------ components/upload/__tests__/upload.test.js | 8 +- .../upload/__tests__/uploadlist.test.js | 4 +- components/upload/demo/picture-style.md | 4 +- components/upload/interface.tsx | 5 +- components/upload/style/dragger.tsx | 68 + components/upload/style/index.less | 1126 +++---- components/upload/style/index.tsx | 61 +- components/upload/style/list.tsx | 125 + components/upload/style/motion.tsx | 50 + components/upload/style/picture.tsx | 242 ++ components/upload/style/rtl.less | 288 +- components/upload/style/rtl.tsx | 14 + 27 files changed, 5372 insertions(+), 5459 deletions(-) create mode 100644 components/upload/style/dragger.tsx create mode 100644 components/upload/style/list.tsx create mode 100644 components/upload/style/motion.tsx create mode 100644 components/upload/style/picture.tsx create mode 100644 components/upload/style/rtl.tsx diff --git a/components/_util/theme/interface.ts b/components/_util/theme/interface.ts index 18dd247409..b9f49c33bc 100644 --- a/components/_util/theme/interface.ts +++ b/components/_util/theme/interface.ts @@ -13,6 +13,7 @@ import type { ComponentToken as BackTopComponentToken } from '../../back-top/sty import type { ComponentToken as DatePickerComponentToken } from '../../date-picker/style'; import type { ComponentToken as TimelineComponentToken } from '../../timeline/style'; import type { ComponentToken as MenuComponentToken } from '../../menu/style'; +import type { ComponentToken as UploadComponentToken } from '../../upload/style'; import type { ComponentToken as CarouselComponentToken } from '../../carousel/style'; export const PresetColors = [ @@ -88,6 +89,7 @@ export interface OverrideToken { Steps?: {}; Menu?: MenuComponentToken; Layout?: {}; + Upload?: UploadComponentToken; } /** Final token which contains the components level override */ diff --git a/components/_util/theme/themes/default.ts b/components/_util/theme/themes/default.ts index c2b4a008a3..8adc2c817b 100644 --- a/components/_util/theme/themes/default.ts +++ b/components/_util/theme/themes/default.ts @@ -73,9 +73,9 @@ export function derivative(token: SeedToken): DerivativeToken { ...colorPalettes, // motion - motionDurationFast: `${motionBase + motionUnit * 1}s`, - motionDurationMid: `${motionBase + motionUnit * 2}s`, - motionDurationSlow: `${motionBase + motionUnit * 3}s`, + motionDurationFast: `${(motionBase + motionUnit * 1).toFixed(1)}s`, + motionDurationMid: `${(motionBase + motionUnit * 2).toFixed(1)}s`, + motionDurationSlow: `${(motionBase + motionUnit * 3).toFixed(1)}s`, // font fontSizes: fontSizes.map(fs => fs.size), diff --git a/components/card/style/index.tsx b/components/card/style/index.tsx index f807dc7a23..7b0e2ed1b2 100644 --- a/components/card/style/index.tsx +++ b/components/card/style/index.tsx @@ -132,7 +132,7 @@ const genCardGridStyle: GenerateStyle = (token): CSSObject => { 1px 1px 0 0 ${borderColorSplit}, 1px 0 0 0 ${borderColorSplit} inset, 0 1px 0 0 ${borderColorSplit} inset; - transition: all ${token.motionDurationSlow}s + transition: all ${token.motionDurationSlow} `, // FIXME: hardcode in v4 '&-hoverable:hover': { @@ -352,7 +352,7 @@ const genCardStyle: GenerateStyle = (token): CSSObject => { [`${componentCls}-hoverable`]: { cursor: 'pointer', - transition: `box-shadow ${token.motionDurationSlow}s, border-color ${token.motionDurationSlow}s`, + transition: `box-shadow ${token.motionDurationSlow}, border-color ${token.motionDurationSlow}`, '&:hover': { borderColor: cardHoverableHoverBorder, diff --git a/components/config-provider/__tests__/__snapshots__/components.test.js.snap b/components/config-provider/__tests__/__snapshots__/components.test.js.snap index 3803c8be3b..9bfc1455ba 100644 --- a/components/config-provider/__tests__/__snapshots__/components.test.js.snap +++ b/components/config-provider/__tests__/__snapshots__/components.test.js.snap @@ -37300,10 +37300,10 @@ exports[`ConfigProvider components TreeSelect prefixCls 1`] = ` exports[`ConfigProvider components Upload configProvider 1`] = `
- - - xxx.png - - - - + +
+ + xxx.png + + + +
@@ -37402,10 +37394,10 @@ exports[`ConfigProvider components Upload configProvider 1`] = ` exports[`ConfigProvider components Upload configProvider componentSize large 1`] = `
- - - xxx.png - - - - + +
+ + xxx.png + + + +
@@ -37504,10 +37488,10 @@ exports[`ConfigProvider components Upload configProvider componentSize large 1`] exports[`ConfigProvider components Upload configProvider componentSize middle 1`] = `
- - - xxx.png - - - - + +
+ + xxx.png + + + +
@@ -37606,10 +37582,10 @@ exports[`ConfigProvider components Upload configProvider componentSize middle 1` exports[`ConfigProvider components Upload configProvider virtual and dropdownMatchSelectWidth 1`] = `
- - - xxx.png - - - - + +
+ + xxx.png + + + +
@@ -37708,10 +37676,10 @@ exports[`ConfigProvider components Upload configProvider virtual and dropdownMat exports[`ConfigProvider components Upload normal 1`] = `
- - - xxx.png - - - - + +
+ + xxx.png + + + +
@@ -37810,10 +37770,10 @@ exports[`ConfigProvider components Upload normal 1`] = ` exports[`ConfigProvider components Upload prefixCls 1`] = `
- - - xxx.png - - - - + +
+ + xxx.png + + + +
diff --git a/components/form/__tests__/__snapshots__/demo-extend.test.ts.snap b/components/form/__tests__/__snapshots__/demo-extend.test.ts.snap index 3c7fdd2972..5931608b89 100644 --- a/components/form/__tests__/__snapshots__/demo-extend.test.ts.snap +++ b/components/form/__tests__/__snapshots__/demo-extend.test.ts.snap @@ -16360,10 +16360,10 @@ exports[`renders ./components/form/demo/validate-other.md extend context correct class="ant-form-item-control-input-content" >
- +
diff --git a/components/form/__tests__/__snapshots__/demo.test.js.snap b/components/form/__tests__/__snapshots__/demo.test.js.snap index a3dd8ebfdb..53672eef9b 100644 --- a/components/form/__tests__/__snapshots__/demo.test.js.snap +++ b/components/form/__tests__/__snapshots__/demo.test.js.snap @@ -7421,10 +7421,10 @@ exports[`renders ./components/form/demo/validate-other.md correctly 1`] = ` class="ant-form-item-control-input-content" >
- +
diff --git a/components/space/__tests__/__snapshots__/demo-extend.test.ts.snap b/components/space/__tests__/__snapshots__/demo-extend.test.ts.snap index be1acfb350..85433888d4 100644 --- a/components/space/__tests__/__snapshots__/demo-extend.test.ts.snap +++ b/components/space/__tests__/__snapshots__/demo-extend.test.ts.snap @@ -179,10 +179,10 @@ exports[`renders ./components/space/demo/base.md extend context correctly 1`] = style="margin-right:8px" >
= (pr delete rcUploadProps.id; } + const [wrapSSR, hashId] = useStyle(prefixCls); + const renderUploadList = (button?: React.ReactNode, buttonVisible?: boolean) => showUploadList ? ( @@ -365,6 +368,10 @@ const InternalUpload: React.ForwardRefRenderFunction = (pr button ); + const rtlCls = { + [`${prefixCls}-rtl`]: direction === 'rtl', + }; + if (type === 'drag') { const dragCls = classNames( prefixCls, @@ -375,10 +382,10 @@ const InternalUpload: React.ForwardRefRenderFunction = (pr [`${prefixCls}-disabled`]: disabled, [`${prefixCls}-rtl`]: direction === 'rtl', }, - className, + hashId, ); - return ( - + return wrapSSR( +
= (pr
{renderUploadList()} -
+
, ); } - const uploadButtonCls = classNames(prefixCls, { - [`${prefixCls}-select`]: true, - [`${prefixCls}-select-${listType}`]: true, + const uploadButtonCls = classNames(prefixCls, `${prefixCls}-select`, { [`${prefixCls}-disabled`]: disabled, - [`${prefixCls}-rtl`]: direction === 'rtl', }); const renderUploadButton = (uploadButtonStyle?: React.CSSProperties) => ( @@ -409,18 +413,26 @@ const InternalUpload: React.ForwardRefRenderFunction = (pr ); if (listType === 'picture-card') { - return ( - + return wrapSSR( + {renderUploadList(renderUploadButton(), !!children)} - + , ); } - return ( - + return wrapSSR( + {renderUploadButton(children ? undefined : { display: 'none' })} {renderUploadList()} - + , ); }; diff --git a/components/upload/UploadList/ListItem.tsx b/components/upload/UploadList/ListItem.tsx index e869cbde7d..96a677e5dd 100644 --- a/components/upload/UploadList/ListItem.tsx +++ b/components/upload/UploadList/ListItem.tsx @@ -85,12 +85,8 @@ const ListItem = React.forwardRef( }; }, []); - // This is used for legacy span make scrollHeight the wrong value. - // We will force these to be `display: block` with non `picture-card` - const spanClassName = `${prefixCls}-span`; - const iconNode = iconRender(file); - let icon =
{iconNode}
; + let icon =
{iconNode}
; if (listType === 'picture' || listType === 'picture-card') { if (file.status === 'uploading' || (!file.thumbUrl && !file.url)) { const uploadingClassName = classNames({ @@ -127,11 +123,10 @@ const ListItem = React.forwardRef( } } - const infoUploadingClass = classNames({ - [`${prefixCls}-list-item`]: true, - [`${prefixCls}-list-item-${file.status}`]: true, - [`${prefixCls}-list-item-list-type-${listType}`]: true, - }); + const listItemClassName = classNames( + `${prefixCls}-list-item`, + `${prefixCls}-list-item-${file.status}`, + ); const linkProps = typeof file.linkProps === 'string' ? JSON.parse(file.linkProps) : file.linkProps; @@ -160,7 +155,7 @@ const ListItem = React.forwardRef( const downloadOrDelete = listType !== 'picture-card' && ( @@ -169,7 +164,7 @@ const ListItem = React.forwardRef( ); const listItemNameClass = classNames(`${prefixCls}-list-item-name`); - const preview = file.url + const fileName = file.url ? [ ) : null; - const actions = listType === 'picture-card' && file.status !== 'uploading' && ( + const pictureCardActions = listType === 'picture-card' && file.status !== 'uploading' && ( {previewIcon} {file.status === 'done' && downloadIcon} @@ -223,25 +219,14 @@ const ListItem = React.forwardRef( ); - let message; - if (file.response && typeof file.response === 'string') { - message = file.response; - } else { - message = file.error?.statusText || file.error?.message || locale.uploadError; - } - const iconAndPreview = ( - - {icon} - {preview} - - ); const { getPrefixCls } = React.useContext(ConfigContext); const rootPrefixCls = getPrefixCls(); const dom = ( -
-
{iconAndPreview}
- {actions} +
+ {icon} + {fileName} + {pictureCardActions} {showProgress && ( ); - const listContainerNameClass = classNames(`${prefixCls}-list-${listType}-container`, className); + + const message = + file.response && typeof file.response === 'string' + ? file.response + : file.error?.statusText || file.error?.message || locale.uploadError; const item = file.status === 'error' ? ( node.parentNode as HTMLElement}> @@ -276,7 +265,11 @@ const ListItem = React.forwardRef( ); return ( -
+
{itemRender ? itemRender(item, file, items, { download: onDownload.bind(null, file), diff --git a/components/upload/UploadList/index.tsx b/components/upload/UploadList/index.tsx index 11f7083ea6..f0adf0783e 100644 --- a/components/upload/UploadList/index.tsx +++ b/components/upload/UploadList/index.tsx @@ -6,13 +6,13 @@ import PaperClipOutlined from '@ant-design/icons/PaperClipOutlined'; import PictureTwoTone from '@ant-design/icons/PictureTwoTone'; import FileTwoTone from '@ant-design/icons/FileTwoTone'; import { cloneElement, isValidElement } from '../../_util/reactNode'; -import { UploadListProps, UploadFile, UploadListType, InternalUploadFile } from '../interface'; import { previewImage, isImageUrl } from '../utils'; import collapseMotion from '../../_util/motion'; import { ConfigContext } from '../../config-provider'; import Button, { ButtonProps } from '../../button'; import useForceUpdate from '../../_util/hooks/useForceUpdate'; import ListItem from './ListItem'; +import type { UploadListProps, UploadFile, UploadListType, InternalUploadFile } from '../interface'; const listItemMotion: Partial = { ...collapseMotion, @@ -133,7 +133,7 @@ const InternalUploadList: React.ForwardRefRenderFunction>> Motion config diff --git a/components/upload/__tests__/__snapshots__/demo-extend.test.ts.snap b/components/upload/__tests__/__snapshots__/demo-extend.test.ts.snap index 8872edf356..5fc6434dc5 100644 --- a/components/upload/__tests__/__snapshots__/demo-extend.test.ts.snap +++ b/components/upload/__tests__/__snapshots__/demo-extend.test.ts.snap @@ -2,10 +2,10 @@ exports[`renders ./components/upload/demo/avatar.md extend context correctly 1`] = `
- + image.png + + + image.png + @@ -176,7 +168,7 @@ exports[`renders ./components/upload/demo/crop-image.md extend context correctly
- - - xxx.png - - - - + +
+ + xxx.png + + + +
- - - yyy.png - - - - + +
+ + yyy.png + + + +
- - - zzz.png - - - - + +
+ + zzz.png + + + +
+
@@ -704,10 +674,10 @@ exports[`renders ./components/upload/demo/drag.md extend context correctly 1`] = exports[`renders ./components/upload/demo/drag-sorting.md extend context correctly 1`] = `
- - - image1.png - - - - + +
+ + image1.png + + + +
- - - image2.png - - - - + +
+ + image2.png + + + +
- - - image3.png - - - - + +
+ + image3.png + + + +
- - - image4.png - - - - + +
+ + image4.png + + + +
- - - image.png - - - - + +
+ + image.png + + + +
- + + + pdf.pdf + @@ -1294,7 +1216,7 @@ exports[`renders ./components/upload/demo/file-type.md extend context correctly
- + + + doc.doc + @@ -1410,7 +1324,7 @@ exports[`renders ./components/upload/demo/file-type.md extend context correctly
- - - image.png - + + + + + +
+ + image.png + @@ -1528,7 +1434,7 @@ exports[`renders ./components/upload/demo/file-type.md extend context correctly
- - - pdf.pdf - + + + + + +
+ + pdf.pdf + @@ -1670,7 +1568,7 @@ exports[`renders ./components/upload/demo/file-type.md extend context correctly
- - - doc.doc - + + + +
+ + doc.doc + @@ -1804,7 +1694,7 @@ exports[`renders ./components/upload/demo/file-type.md extend context correctly
- - - xxx.png - - - - + +
+ + xxx.png + + + +
@@ -2047,10 +1929,10 @@ exports[`renders ./components/upload/demo/max-count.md extend context correctly style="margin-bottom:24px" >
- + image.png + + + image.png + @@ -2225,7 +2099,7 @@ exports[`renders ./components/upload/demo/picture-card.md extend context correct
- + image.png + + + image.png + @@ -2318,7 +2184,7 @@ exports[`renders ./components/upload/demo/picture-card.md extend context correct
- + image.png + + + image.png + @@ -2411,7 +2269,7 @@ exports[`renders ./components/upload/demo/picture-card.md extend context correct
- + image.png + + + image.png + @@ -2504,7 +2354,7 @@ exports[`renders ./components/upload/demo/picture-card.md extend context correct
- -
- Uploading... -
- - image.png - -
+ Uploading...
+ + image.png +
- - - image.png - + + + + + +
+ + image.png + @@ -2652,7 +2486,7 @@ exports[`renders ./components/upload/demo/picture-card.md extend context correct
-
- + + + xxx.png + + + + + - -
+ +
- - - yyy.png - - - - + + + + + +
+ + yyy.png + + + +
,
,
-
- + + + xxx.png + + + + + - -
+ +
- - - yyy.png - - - - + + + + + +
+ + yyy.png + + + +
- - - xxx.png - - - - - + +
+ + xxx.png + + + + +
- - - yyy.png - - - - - + +
+ + yyy.png + + + + +
- - - zzz.png - - - - + +
+ + zzz.png + + + +
- + image.png + + + image.png + @@ -176,7 +168,7 @@ exports[`renders ./components/upload/demo/crop-image.md correctly 1`] = `
- - - xxx.png - - - - + +
+ + xxx.png + + + +
- - - yyy.png - - - - + +
+ + yyy.png + + + +
- - - zzz.png - - - - + +
+ + zzz.png + + + +
@@ -565,10 +533,10 @@ exports[`renders ./components/upload/demo/defaultFileList.md correctly 1`] = ` exports[`renders ./components/upload/demo/directory.md correctly 1`] = `
+
@@ -680,10 +650,10 @@ exports[`renders ./components/upload/demo/drag.md correctly 1`] = ` exports[`renders ./components/upload/demo/drag-sorting.md correctly 1`] = `
- - - image1.png - - - - + +
+ + image1.png + + + +
- - - image2.png - - - - + +
+ + image2.png + + + +
- - - image3.png - - - - + +
+ + image3.png + + + +
- - - image4.png - - - - + +
+ + image4.png + + + +
- - - image.png - - - - + +
+ + image.png + + + +
@@ -1145,77 +1075,69 @@ exports[`renders ./components/upload/demo/drag-sorting.md correctly 1`] = ` exports[`renders ./components/upload/demo/file-type.md correctly 1`] = `
- + + + pdf.pdf + @@ -1246,7 +1168,7 @@ exports[`renders ./components/upload/demo/file-type.md correctly 1`] = `
- + + + doc.doc + @@ -1362,7 +1276,7 @@ exports[`renders ./components/upload/demo/file-type.md correctly 1`] = `
- - - image.png - + + + + + +
+ + image.png + @@ -1480,7 +1386,7 @@ exports[`renders ./components/upload/demo/file-type.md correctly 1`] = `
- - - pdf.pdf - + + + + + +
+ + pdf.pdf + @@ -1598,7 +1496,7 @@ exports[`renders ./components/upload/demo/file-type.md correctly 1`] = `
- - - doc.doc - + + + +
+ + doc.doc + @@ -1708,7 +1598,7 @@ exports[`renders ./components/upload/demo/file-type.md correctly 1`] = `
- - - xxx.png - - - - + +
+ + xxx.png + + + +
@@ -1927,10 +1809,10 @@ exports[`renders ./components/upload/demo/max-count.md correctly 1`] = ` style="margin-bottom:24px" >
- + image.png + + + image.png + @@ -2105,7 +1979,7 @@ exports[`renders ./components/upload/demo/picture-card.md correctly 1`] = `
- + image.png + + + image.png + @@ -2198,7 +2064,7 @@ exports[`renders ./components/upload/demo/picture-card.md correctly 1`] = `
- + image.png + + + image.png + @@ -2291,7 +2149,7 @@ exports[`renders ./components/upload/demo/picture-card.md correctly 1`] = `
- + image.png + + + image.png + @@ -2384,7 +2234,7 @@ exports[`renders ./components/upload/demo/picture-card.md correctly 1`] = `
- -
- Uploading... -
- - image.png - -
+ Uploading...
+ + image.png +
- - - image.png - + + + + + +
+ + image.png + @@ -2532,7 +2366,7 @@ exports[`renders ./components/upload/demo/picture-card.md correctly 1`] = `
-
- + + + xxx.png + + + + + - -
+ +
- - - yyy.png - - - - + + + + + +
+ + yyy.png + + + +
@@ -2823,10 +2641,10 @@ Array [
,
,
-
- + + + xxx.png + + + + + - -
+ +
- - - yyy.png - - - - + + + + + +
+ + yyy.png + + + +
@@ -3036,10 +2838,10 @@ Array [ exports[`renders ./components/upload/demo/preview-file.md correctly 1`] = `
- - - xxx.png - - - - - + +
+ + xxx.png + + + + +
- - - yyy.png - - - - - + +
+ + yyy.png + + + + +
- - - zzz.png - - - - + +
+ + zzz.png + + + +
@@ -3446,10 +3224,10 @@ exports[`renders ./components/upload/demo/upload-custom-action-icon.md correctly exports[`renders ./components/upload/demo/upload-manually.md correctly 1`] = ` Array [
`; diff --git a/components/upload/__tests__/__snapshots__/uploadlist.test.js.snap b/components/upload/__tests__/__snapshots__/uploadlist.test.js.snap index 407303977e..4479073492 100644 --- a/components/upload/__tests__/__snapshots__/uploadlist.test.js.snap +++ b/components/upload/__tests__/__snapshots__/uploadlist.test.js.snap @@ -2,10 +2,10 @@ exports[`Upload List handle error 1`] = `
- - - foo.png - - - - + +
+ + foo.png + + + +
@@ -112,7 +104,7 @@ exports[`Upload List itemRender 1`] = ` class="ant-upload-list ant-upload-list-text" >
- - - foo.png - - - - + +
+ + foo.png + + + +
@@ -275,10 +259,10 @@ exports[`Upload List should be uploading when upload a file 1`] = ` exports[`Upload List should be uploading when upload a file 2`] = `
- - - foo.png - - - - + +
+ + foo.png + + + +
@@ -382,10 +358,10 @@ exports[`Upload List should be uploading when upload a file 2`] = ` exports[`Upload List should non-image format file preview 1`] = `
-
- - - not-image - - - - - -
-
-
-
-
-
- - - image - - - image - - - - - -
-
-
-
-
-
- - - - - - - - not-image - - - - - -
-
-
-
-
-
- - - - - - - - not-image - - - - - -
-
-
-
-
-
- - - image - - - image - - - - + -
+ + + not-image + + + +
-
- + + + image + + + + + - -
+ +
-
- - - image - - - - + + -
+ + + not-image + + + +
-
- - - image - - - - + + -
+ + + not-image + + + +
-
- + + + image + + + + + - -
+ +
-
- + + + image + + + + + - -
+ + +
+
+
+
+ + image + + + image + + + + +
+
+
+
+ + image + + + image + + + + +
+
+
+
+ + image + + + image + + + + +
+
+
+
+ + image + + + image + + + +
@@ -1140,10 +1036,10 @@ exports[`Upload List should non-image format file preview 1`] = ` exports[`Upload List should support removeIcon and downloadIcon 1`] = `
- - - image - - - - + +
+ + image + + + +
-
- + + + image + + + - - - -
+ + DL + + + +
@@ -1291,10 +1171,10 @@ exports[`Upload List should support removeIcon and downloadIcon 1`] = ` exports[`Upload List should support removeIcon and downloadIcon 2`] = `
- - - image - - - - + +
+ + image + + + +
-
- + + + image + + + - - - -
+ + DL + + + +
@@ -1442,10 +1306,10 @@ exports[`Upload List should support removeIcon and downloadIcon 2`] = ` exports[`Upload List should support showRemoveIcon and showPreviewIcon 1`] = `
- - - image - - + +
+ + image + +
-
- - - image - - - image - - - -
+ image + + + image + +
diff --git a/components/upload/__tests__/upload.test.js b/components/upload/__tests__/upload.test.js index 1d72e7e2cb..cea3e0a94e 100644 --- a/components/upload/__tests__/upload.test.js +++ b/components/upload/__tests__/upload.test.js @@ -844,7 +844,7 @@ describe('Upload', () => { const frozenFileList = fileList.map(file => Object.freeze(file)); const wrapper = mount(); - const rmBtn = wrapper.find('.ant-upload-list-item-card-actions-btn').last(); + const rmBtn = wrapper.find('.ant-upload-list-item-action').last(); rmBtn.simulate('click'); // Wait for Upload async remove @@ -888,7 +888,7 @@ describe('Upload', () => { ); rerender(); - expect(container.querySelector('.ant-upload-select-picture-card')).not.toHaveStyle({ + expect(container.querySelector('.ant-upload-select')).not.toHaveStyle({ display: 'none', }); @@ -897,9 +897,9 @@ describe('Upload', () => { jest.runAllTimers(); }); - fireEvent.animationEnd(container.querySelector('.ant-upload-select-picture-card')); + fireEvent.animationEnd(container.querySelector('.ant-upload-select')); - expect(container.querySelector('.ant-upload-select-picture-card')).toHaveStyle({ + expect(container.querySelector('.ant-upload-select')).toHaveStyle({ display: 'none', }); diff --git a/components/upload/__tests__/uploadlist.test.js b/components/upload/__tests__/uploadlist.test.js index 1e9957fd9e..9936ad3b47 100644 --- a/components/upload/__tests__/uploadlist.test.js +++ b/components/upload/__tests__/uploadlist.test.js @@ -138,7 +138,7 @@ describe('Upload List', () => { await sleep(1000); wrapper.update(); - const domNode = wrapper.find('.ant-upload-list-text-container').at(0).hostNodes().instance(); + const domNode = wrapper.find('.ant-upload-list-item-container').at(0).hostNodes().instance(); const transitionEndEvent = new Event('transitionend'); domNode.dispatchEvent(transitionEndEvent); wrapper.update(); @@ -146,7 +146,7 @@ describe('Upload List', () => { // console.log(wrapper.html()); - expect(wrapper.find('.ant-upload-list-text-container').hostNodes().length).toBe(1); + expect(wrapper.find('.ant-upload-list-item-container').hostNodes().length).toBe(1); wrapper.unmount(); }); diff --git a/components/upload/demo/picture-style.md b/components/upload/demo/picture-style.md index 5169fd9c91..dad504804a 100644 --- a/components/upload/demo/picture-style.md +++ b/components/upload/demo/picture-style.md @@ -60,10 +60,10 @@ export default () => ( .upload-list-inline .ant-upload-list-item { float: left; width: 200px; - margin-right: 8px; + margin-inline-end: 8px; } -.upload-list-inline [class*='-upload-list-rtl'] .ant-upload-list-item { +.ant-upload-rtl.upload-list-inline .ant-upload-list-item { float: right; } ``` diff --git a/components/upload/interface.tsx b/components/upload/interface.tsx index 9db210ade6..67eb70e8eb 100755 --- a/components/upload/interface.tsx +++ b/components/upload/interface.tsx @@ -1,10 +1,10 @@ import * as React from 'react'; -import { +import type { RcFile as OriRcFile, UploadRequestOption as RcCustomRequestOptions, UploadProps as RcUploadProps, } from 'rc-upload/lib/interface'; -import { ProgressProps } from '../progress'; +import type { ProgressProps } from '../progress'; export interface RcFile extends OriRcFile { readonly lastModifiedDate: Date; @@ -146,6 +146,7 @@ export interface UploadListProps { items?: Array>; progress?: UploadListProgressProps; prefixCls?: string; + className?: string; showRemoveIcon?: boolean; showDownloadIcon?: boolean; showPreviewIcon?: boolean; diff --git a/components/upload/style/dragger.tsx b/components/upload/style/dragger.tsx new file mode 100644 index 0000000000..5562b4a542 --- /dev/null +++ b/components/upload/style/dragger.tsx @@ -0,0 +1,68 @@ +import type { GenerateStyle, FullToken } from '../../_util/theme'; + +const genDraggerStyle: GenerateStyle> = token => { + const { componentCls, iconCls } = token; + + return { + [`${componentCls}-wrapper`]: { + [`${componentCls}-drag`]: { + position: 'relative', + width: '100%', + height: '100%', + textAlign: 'center', + background: token.colorBgComponentSecondary, + border: `${token.controlLineWidth}px dashed ${token.colorBorder}`, + borderRadius: token.radiusBase, + cursor: 'pointer', + transition: `border-color ${token.motionDurationSlow}`, + + [componentCls]: { + padding: `${token.padding}px 0`, + }, + + [`${componentCls}${componentCls}-disabled`]: { + cursor: 'not-allowed', + }, + + [`${componentCls}-btn`]: { + display: 'table', + height: '100%', + outline: 'none', + }, + + [`${componentCls}-drag-container`]: { + display: 'table-cell', + verticalAlign: 'middle', + }, + + [`${componentCls}:not(${componentCls}-disabled):hover`]: { + borderColor: token.colorPrimaryHover, + }, + + [`p${componentCls}-drag-icon`]: { + // FIXME: upload token + marginBottom: 20, + + [iconCls]: { + color: token.colorPrimary, + // FIXME: upload token + fontSize: 48, + }, + }, + + [`p${componentCls}-text`]: { + margin: `0 0 ${token.marginXXS}px`, + color: token.colorTextHeading, + fontSize: token.fontSizeLG, + }, + + [`p${componentCls}-hint`]: { + color: token.colorTextSecondary, + fontSize: token.fontSizeBase, + }, + }, + }, + }; +}; + +export default genDraggerStyle; diff --git a/components/upload/style/index.less b/components/upload/style/index.less index 80c0672204..23b0be2aea 100644 --- a/components/upload/style/index.less +++ b/components/upload/style/index.less @@ -1,563 +1,563 @@ -@import '../../style/themes/index'; -@import '../../style/mixins/index'; - -@upload-prefix-cls: ~'@{ant-prefix}-upload'; -@upload-item: ~'@{ant-prefix}-upload-list-item'; -@upload-picture-card-size: 104px; -@upload-picture-card-border-style: @border-style-base; - -.@{upload-prefix-cls} { - .reset-component(); - - outline: 0; - - p { - margin: 0; - } - - &-btn { - display: block; - width: 100%; - outline: none; - } - - input[type='file'] { - cursor: pointer; - } - - &&-select { - display: inline-block; - } - - &&-disabled { - cursor: not-allowed; - } - - &&-select-picture-card { - width: @upload-picture-card-size; - height: @upload-picture-card-size; - margin-right: 8px; - margin-bottom: 8px; - text-align: center; - vertical-align: top; - background-color: @background-color-light; - border: @border-width-base dashed @border-color-base; - border-radius: @border-radius-base; - cursor: pointer; - transition: border-color 0.3s; - - > .@{upload-prefix-cls} { - display: flex; - align-items: center; - justify-content: center; - height: 100%; - text-align: center; - } - - &:hover { - border-color: @primary-color; - .@{upload-prefix-cls}-disabled& { - border-color: @border-color-base; - } - } - } - - &&-drag { - position: relative; - width: 100%; - height: 100%; - text-align: center; - background: @background-color-light; - border: @border-width-base dashed @border-color-base; - border-radius: @border-radius-base; - cursor: pointer; - transition: border-color 0.3s; - - .@{upload-prefix-cls} { - padding: @padding-md 0; - } - - &.@{upload-prefix-cls}-drag-hover:not(.@{upload-prefix-cls}-disabled) { - border-color: @primary-7; - } - - &.@{upload-prefix-cls}-disabled { - cursor: not-allowed; - } - - .@{upload-prefix-cls}-btn { - display: table; - height: 100%; - } - - .@{upload-prefix-cls}-drag-container { - display: table-cell; - vertical-align: middle; - } - - &:not(.@{upload-prefix-cls}-disabled):hover { - border-color: @primary-5; - } - - p.@{upload-prefix-cls}-drag-icon { - .@{iconfont-css-prefix} { - color: @primary-5; - font-size: 48px; - } - - margin-bottom: 20px; - } - p.@{upload-prefix-cls}-text { - margin: 0 0 4px; - color: @heading-color; - font-size: @font-size-lg; - } - p.@{upload-prefix-cls}-hint { - color: @text-color-secondary; - font-size: @font-size-base; - } - - .@{iconfont-css-prefix}-plus { - color: @disabled-color; - font-size: 30px; - transition: all 0.3s; - - &:hover { - color: @text-color-secondary; - } - } - &:hover .@{iconfont-css-prefix}-plus { - color: @text-color-secondary; - } - } - - &-picture-card-wrapper { - .clearfix(); - - display: inline-block; - width: 100%; - } -} - -.@{upload-prefix-cls}-list { - .reset-component(); - .clearfix(); - line-height: @line-height-base; - - // ============================ Item ============================ - &-item { - position: relative; - height: @line-height-base * @font-size-base; - margin-top: @margin-xs; - font-size: @font-size-base; - - &-name { - display: inline-block; - width: 100%; - padding-left: @font-size-base + 8px; - overflow: hidden; - line-height: @line-height-base; - white-space: nowrap; - text-overflow: ellipsis; - } - - &-card-actions { - position: absolute; - right: 0; - - &-btn { - opacity: 0; - } - - &-btn.@{ant-prefix}-btn-sm { - height: @line-height-base * @font-size-base; - line-height: 1; - vertical-align: top; - } - - &.picture { - top: 22px; - line-height: 0; - } - - &-btn:focus, - &.picture &-btn { - opacity: 1; - } - - .@{iconfont-css-prefix} { - color: @upload-actions-color; - transition: all 0.3s; - } - - &:hover .@{iconfont-css-prefix} { - color: @text-color; - } - } - - &-info { - height: 100%; - transition: background-color 0.3s; - - > span { - display: block; - width: 100%; - height: 100%; - } - - .@{iconfont-css-prefix}-loading, - .@{upload-prefix-cls}-text-icon { - .@{iconfont-css-prefix} { - position: absolute; - top: (@font-size-base / 2) - 2px; - color: @text-color-secondary; - font-size: @font-size-base; - } - } - } - - &:hover &-info { - background-color: @item-hover-bg; - } - - &:hover &-card-actions-btn { - opacity: 1; - } - - &-error, - &-error .@{upload-prefix-cls}-text-icon > .@{iconfont-css-prefix}, - &-error &-name { - color: @error-color; - } - - &-error &-card-actions { - .@{iconfont-css-prefix} { - color: @error-color; - } - - &-btn { - opacity: 1; - } - } - - &-progress { - position: absolute; - bottom: -12px; - width: 100%; - padding-left: @font-size-base + 12px; - font-size: @font-size-base; - line-height: 0; - } - } - - // =================== Picture & Picture Card =================== - &-picture, - &-picture-card { - .@{upload-item} { - position: relative; - height: 66px; - padding: @padding-xs; - border: @border-width-base @upload-picture-card-border-style @border-color-base; - border-radius: @border-radius-base; - - &:hover { - background: transparent; - } - - &-error { - border-color: @error-color; - } - } - - .@{upload-item}-info { - padding: 0; - } - - .@{upload-item}:hover .@{upload-item}-info { - background: transparent; - } - - .@{upload-item}-uploading { - border-style: dashed; - } - - .@{upload-item}-thumbnail { - width: 48px; - height: 48px; - line-height: 60px; - text-align: center; - opacity: 0.8; - - .@{iconfont-css-prefix} { - font-size: 26px; - } - } - - // Adjust the color of the error icon : https://github.com/ant-design/ant-design/pull/24160 - .@{upload-item}-error .@{upload-item}-thumbnail { - .@{iconfont-css-prefix} { - svg path { - &[fill='#e6f7ff'] { - fill: @error-color-deprecated-bg; - } - - &[fill='#1890ff'] { - fill: @error-color; - } - } - } - } - - .@{upload-item}-icon { - position: absolute; - top: 50%; - left: 50%; - font-size: 26px; - transform: translate(-50%, -50%); - - .@{iconfont-css-prefix} { - font-size: 26px; - } - } - - .@{upload-item}-image { - max-width: 100%; - } - - .@{upload-item}-thumbnail img { - display: block; - width: 48px; - height: 48px; - overflow: hidden; - } - - .@{upload-item}-name { - display: inline-block; - box-sizing: border-box; - max-width: 100%; - margin: 0 0 0 8px; - padding-right: 8px; - padding-left: 48px; - overflow: hidden; - line-height: 44px; - white-space: nowrap; - text-overflow: ellipsis; - transition: all 0.3s; - } - - .@{upload-item}-uploading .@{upload-item}-name { - margin-bottom: 12px; - } - - .@{upload-item}-progress { - bottom: 14px; - width: ~'calc(100% - 24px)'; - margin-top: 0; - padding-left: 56px; - } - } - - // ======================== Picture Card ======================== - &-picture-card { - &-container { - display: inline-block; - width: @upload-picture-card-size; - height: @upload-picture-card-size; - margin: 0 @margin-xs @margin-xs 0; - vertical-align: top; - } - - .@{upload-item} { - height: 100%; - margin: 0; - } - - .@{upload-item}-info { - position: relative; - height: 100%; - overflow: hidden; - - &::before { - position: absolute; - z-index: 1; - width: 100%; - height: 100%; - background-color: fade(@black, 50%); - opacity: 0; - transition: all 0.3s; - content: ' '; - } - } - - .@{upload-item}:hover .@{upload-item}-info::before { - opacity: 1; - } - - .@{upload-item}-actions { - position: absolute; - top: 50%; - left: 50%; - z-index: 10; - white-space: nowrap; - transform: translate(-50%, -50%); - opacity: 0; - transition: all 0.3s; - - .@{iconfont-css-prefix}-eye, - .@{iconfont-css-prefix}-download, - .@{iconfont-css-prefix}-delete { - z-index: 10; - width: 16px; - margin: 0 4px; - color: @text-color-dark; - font-size: 16px; - cursor: pointer; - transition: all 0.3s; - - &:hover { - color: @text-color-inverse; - } - } - } - - .@{upload-item}-info:hover + .@{upload-item}-actions, - .@{upload-item}-actions:hover { - opacity: 1; - } - - .@{upload-item}-thumbnail, - .@{upload-item}-thumbnail img { - position: static; - display: block; - width: 100%; - height: 100%; - object-fit: contain; - } - - .@{upload-item}-name { - display: none; - margin: 8px 0 0; - padding: 0; - line-height: @line-height-base; - text-align: center; - } - - .@{upload-item}-file + .@{upload-item}-name { - position: absolute; - bottom: 10px; - display: block; - } - - .@{upload-item}-uploading { - &.@{upload-item} { - background-color: @background-color-light; - } - - .@{upload-item}-info { - height: auto; - - &::before, - .@{iconfont-css-prefix}-eye, - .@{iconfont-css-prefix}-delete { - display: none; - } - } - } - - .@{upload-item}-progress { - bottom: 32px; - width: calc(100% - 14px); - padding-left: 0; - } - } - - // ======================= Picture & Text ======================= - &-text, - &-picture { - &-container { - transition: opacity @animation-duration-slow, height @animation-duration-slow; - - &::before { - display: table; - width: 0; - height: 0; - content: ''; - } - - // Don't know why span here, just stretch it - .@{upload-prefix-cls}-span { - display: block; - flex: auto; - } - } - - // text & picture no need this additional element. - // But it used for picture-card, let's keep it. - .@{upload-prefix-cls}-span { - display: flex; - align-items: center; - - > * { - flex: none; - } - } - - .@{upload-item}-name { - flex: auto; - margin: 0; - padding: 0 @padding-xs; - } - - .@{upload-item}-card-actions { - position: static; - } - } - - // ============================ Text ============================ - &-text { - .@{upload-prefix-cls}-text-icon { - .@{iconfont-css-prefix} { - position: static; - } - } - } - - // =========================== Motion =========================== - .@{upload-prefix-cls}-animate-inline-appear, - .@{upload-prefix-cls}-animate-inline-enter, - .@{upload-prefix-cls}-animate-inline-leave { - animation-duration: @animation-duration-slow; - animation-fill-mode: @ease-in-out-circ; - } - - .@{upload-prefix-cls}-animate-inline-appear, - .@{upload-prefix-cls}-animate-inline-enter { - animation-name: uploadAnimateInlineIn; - } - - .@{upload-prefix-cls}-animate-inline-leave { - animation-name: uploadAnimateInlineOut; - } -} - -@keyframes uploadAnimateInlineIn { - from { - width: 0; - height: 0; - margin: 0; - padding: 0; - opacity: 0; - } -} - -@keyframes uploadAnimateInlineOut { - to { - width: 0; - height: 0; - margin: 0; - padding: 0; - opacity: 0; - } -} - -@import './rtl'; +// @import '../../style/themes/index'; +// @import '../../style/mixins/index'; + +// @upload-prefix-cls: ~'@{ant-prefix}-upload'; +// @upload-item: ~'@{ant-prefix}-upload-list-item'; +// @upload-picture-card-size: 104px; +// @upload-picture-card-border-style: @border-style-base; + +// .@{upload-prefix-cls} { +// .reset-component(); + +// outline: 0; + +// p { +// margin: 0; +// } + +// &-btn { +// display: block; +// width: 100%; +// outline: none; +// } + +// input[type='file'] { +// cursor: pointer; +// } + +// &&-select { +// display: inline-block; +// } + +// &&-disabled { +// cursor: not-allowed; +// } + +// &&-select-picture-card { +// width: @upload-picture-card-size; +// height: @upload-picture-card-size; +// margin-right: 8px; +// margin-bottom: 8px; +// text-align: center; +// vertical-align: top; +// background-color: @background-color-light; +// border: @border-width-base dashed @border-color-base; +// border-radius: @border-radius-base; +// cursor: pointer; +// transition: border-color 0.3s; + +// > .@{upload-prefix-cls} { +// display: flex; +// align-items: center; +// justify-content: center; +// height: 100%; +// text-align: center; +// } + +// &:hover { +// border-color: @primary-color; +// .@{upload-prefix-cls}-disabled& { +// border-color: @border-color-base; +// } +// } +// } + +// &&-drag { +// position: relative; +// width: 100%; +// height: 100%; +// text-align: center; +// background: @background-color-light; +// border: @border-width-base dashed @border-color-base; +// border-radius: @border-radius-base; +// cursor: pointer; +// transition: border-color 0.3s; + +// .@{upload-prefix-cls} { +// padding: @padding-md 0; +// } + +// &.@{upload-prefix-cls}-drag-hover:not(.@{upload-prefix-cls}-disabled) { +// border-color: @primary-7; +// } + +// &.@{upload-prefix-cls}-disabled { +// cursor: not-allowed; +// } + +// .@{upload-prefix-cls}-btn { +// display: table; +// height: 100%; +// } + +// .@{upload-prefix-cls}-drag-container { +// display: table-cell; +// vertical-align: middle; +// } + +// &:not(.@{upload-prefix-cls}-disabled):hover { +// border-color: @primary-5; +// } + +// p.@{upload-prefix-cls}-drag-icon { +// .@{iconfont-css-prefix} { +// color: @primary-5; +// font-size: 48px; +// } + +// margin-bottom: 20px; +// } +// p.@{upload-prefix-cls}-text { +// margin: 0 0 4px; +// color: @heading-color; +// font-size: @font-size-lg; +// } +// p.@{upload-prefix-cls}-hint { +// color: @text-color-secondary; +// font-size: @font-size-base; +// } + +// .@{iconfont-css-prefix}-plus { +// color: @disabled-color; +// font-size: 30px; +// transition: all 0.3s; + +// &:hover { +// color: @text-color-secondary; +// } +// } +// &:hover .@{iconfont-css-prefix}-plus { +// color: @text-color-secondary; +// } +// } + +// &-picture-card-wrapper { +// .clearfix(); + +// display: inline-block; +// width: 100%; +// } +// } + +// .@{upload-prefix-cls}-list { +// .reset-component(); +// .clearfix(); +// line-height: @line-height-base; + +// // ============================ Item ============================ +// &-item { +// position: relative; +// height: @line-height-base * @font-size-base; +// margin-top: @margin-xs; +// font-size: @font-size-base; + +// &-name { +// display: inline-block; +// width: 100%; +// padding-left: @font-size-base + 8px; +// overflow: hidden; +// line-height: @line-height-base; +// white-space: nowrap; +// text-overflow: ellipsis; +// } + +// &-card-actions { +// position: absolute; +// right: 0; + +// &-btn { +// opacity: 0; +// } + +// &-btn.@{ant-prefix}-btn-sm { +// height: @line-height-base * @font-size-base; +// line-height: 1; +// vertical-align: top; +// } + +// &.picture { +// top: 22px; +// line-height: 0; +// } + +// &-btn:focus, +// &.picture &-btn { +// opacity: 1; +// } + +// .@{iconfont-css-prefix} { +// color: @upload-actions-color; +// transition: all 0.3s; +// } + +// &:hover .@{iconfont-css-prefix} { +// color: @text-color; +// } +// } + +// &-info { +// height: 100%; +// transition: background-color 0.3s; + +// > span { +// display: block; +// width: 100%; +// height: 100%; +// } + +// .@{iconfont-css-prefix}-loading, +// .@{upload-prefix-cls}-text-icon { +// .@{iconfont-css-prefix} { +// position: absolute; +// top: (@font-size-base / 2) - 2px; +// color: @text-color-secondary; +// font-size: @font-size-base; +// } +// } +// } + +// &:hover &-info { +// background-color: @item-hover-bg; +// } + +// &:hover &-card-actions-btn { +// opacity: 1; +// } + +// &-error, +// &-error .@{upload-prefix-cls}-text-icon > .@{iconfont-css-prefix}, +// &-error &-name { +// color: @error-color; +// } + +// &-error &-card-actions { +// .@{iconfont-css-prefix} { +// color: @error-color; +// } + +// &-btn { +// opacity: 1; +// } +// } + +// &-progress { +// position: absolute; +// bottom: -12px; +// width: 100%; +// padding-left: @font-size-base + 12px; +// font-size: @font-size-base; +// line-height: 0; +// } +// } + +// // =================== Picture & Picture Card =================== +// &-picture, +// &-picture-card { +// .@{upload-item} { +// position: relative; +// height: 66px; +// padding: @padding-xs; +// border: @border-width-base @upload-picture-card-border-style @border-color-base; +// border-radius: @border-radius-base; + +// &:hover { +// background: transparent; +// } + +// &-error { +// border-color: @error-color; +// } +// } + +// .@{upload-item}-info { +// padding: 0; +// } + +// .@{upload-item}:hover .@{upload-item}-info { +// background: transparent; +// } + +// .@{upload-item}-uploading { +// border-style: dashed; +// } + +// .@{upload-item}-thumbnail { +// width: 48px; +// height: 48px; +// line-height: 60px; +// text-align: center; +// opacity: 0.8; + +// .@{iconfont-css-prefix} { +// font-size: 26px; +// } +// } + +// // Adjust the color of the error icon : https://github.com/ant-design/ant-design/pull/24160 +// .@{upload-item}-error .@{upload-item}-thumbnail { +// .@{iconfont-css-prefix} { +// svg path { +// &[fill='#e6f7ff'] { +// fill: @error-color-deprecated-bg; +// } + +// &[fill='#1890ff'] { +// fill: @error-color; +// } +// } +// } +// } + +// .@{upload-item}-icon { +// position: absolute; +// top: 50%; +// left: 50%; +// font-size: 26px; +// transform: translate(-50%, -50%); + +// .@{iconfont-css-prefix} { +// font-size: 26px; +// } +// } + +// .@{upload-item}-image { +// max-width: 100%; +// } + +// .@{upload-item}-thumbnail img { +// display: block; +// width: 48px; +// height: 48px; +// overflow: hidden; +// } + +// .@{upload-item}-name { +// display: inline-block; +// box-sizing: border-box; +// max-width: 100%; +// margin: 0 0 0 8px; +// padding-right: 8px; +// padding-left: 48px; +// overflow: hidden; +// line-height: 44px; +// white-space: nowrap; +// text-overflow: ellipsis; +// transition: all 0.3s; +// } + +// .@{upload-item}-uploading .@{upload-item}-name { +// margin-bottom: 12px; +// } + +// .@{upload-item}-progress { +// bottom: 14px; +// width: ~'calc(100% - 24px)'; +// margin-top: 0; +// padding-left: 56px; +// } +// } + +// // ======================== Picture Card ======================== +// &-picture-card { +// &-container { +// display: inline-block; +// width: @upload-picture-card-size; +// height: @upload-picture-card-size; +// margin: 0 @margin-xs @margin-xs 0; +// vertical-align: top; +// } + +// .@{upload-item} { +// height: 100%; +// margin: 0; +// } + +// .@{upload-item}-info { +// position: relative; +// height: 100%; +// overflow: hidden; + +// &::before { +// position: absolute; +// z-index: 1; +// width: 100%; +// height: 100%; +// background-color: fade(@black, 50%); +// opacity: 0; +// transition: all 0.3s; +// content: ' '; +// } +// } + +// .@{upload-item}:hover .@{upload-item}-info::before { +// opacity: 1; +// } + +// .@{upload-item}-actions { +// position: absolute; +// top: 50%; +// left: 50%; +// z-index: 10; +// white-space: nowrap; +// transform: translate(-50%, -50%); +// opacity: 0; +// transition: all 0.3s; + +// .@{iconfont-css-prefix}-eye, +// .@{iconfont-css-prefix}-download, +// .@{iconfont-css-prefix}-delete { +// z-index: 10; +// width: 16px; +// margin: 0 4px; +// color: @text-color-dark; +// font-size: 16px; +// cursor: pointer; +// transition: all 0.3s; + +// &:hover { +// color: @text-color-inverse; +// } +// } +// } + +// .@{upload-item}-info:hover + .@{upload-item}-actions, +// .@{upload-item}-actions:hover { +// opacity: 1; +// } + +// .@{upload-item}-thumbnail, +// .@{upload-item}-thumbnail img { +// position: static; +// display: block; +// width: 100%; +// height: 100%; +// object-fit: contain; +// } + +// .@{upload-item}-name { +// display: none; +// margin: 8px 0 0; +// padding: 0; +// line-height: @line-height-base; +// text-align: center; +// } + +// .@{upload-item}-file + .@{upload-item}-name { +// position: absolute; +// bottom: 10px; +// display: block; +// } + +// .@{upload-item}-uploading { +// &.@{upload-item} { +// background-color: @background-color-light; +// } + +// .@{upload-item}-info { +// height: auto; + +// &::before, +// .@{iconfont-css-prefix}-eye, +// .@{iconfont-css-prefix}-delete { +// display: none; +// } +// } +// } + +// .@{upload-item}-progress { +// bottom: 32px; +// width: calc(100% - 14px); +// padding-left: 0; +// } +// } + +// // ======================= Picture & Text ======================= +// &-text, +// &-picture { +// &-container { +// transition: opacity @animation-duration-slow, height @animation-duration-slow; + +// &::before { +// display: table; +// width: 0; +// height: 0; +// content: ''; +// } + +// // Don't know why span here, just stretch it +// .@{upload-prefix-cls}-span { +// display: block; +// flex: auto; +// } +// } + +// // text & picture no need this additional element. +// // But it used for picture-card, let's keep it. +// .@{upload-prefix-cls}-span { +// display: flex; +// align-items: center; + +// > * { +// flex: none; +// } +// } + +// .@{upload-item}-name { +// flex: auto; +// margin: 0; +// padding: 0 @padding-xs; +// } + +// .@{upload-item}-card-actions { +// position: static; +// } +// } + +// // ============================ Text ============================ +// &-text { +// .@{upload-prefix-cls}-text-icon { +// .@{iconfont-css-prefix} { +// position: static; +// } +// } +// } + +// // =========================== Motion =========================== +// .@{upload-prefix-cls}-animate-inline-appear, +// .@{upload-prefix-cls}-animate-inline-enter, +// .@{upload-prefix-cls}-animate-inline-leave { +// animation-duration: @animation-duration-slow; +// animation-fill-mode: @ease-in-out-circ; +// } + +// .@{upload-prefix-cls}-animate-inline-appear, +// .@{upload-prefix-cls}-animate-inline-enter { +// animation-name: uploadAnimateInlineIn; +// } + +// .@{upload-prefix-cls}-animate-inline-leave { +// animation-name: uploadAnimateInlineOut; +// } +// } + +// @keyframes uploadAnimateInlineIn { +// from { +// width: 0; +// height: 0; +// margin: 0; +// padding: 0; +// opacity: 0; +// } +// } + +// @keyframes uploadAnimateInlineOut { +// to { +// width: 0; +// height: 0; +// margin: 0; +// padding: 0; +// opacity: 0; +// } +// } + +// @import './rtl'; diff --git a/components/upload/style/index.tsx b/components/upload/style/index.tsx index 591032d5dd..eb0bdcb23a 100644 --- a/components/upload/style/index.tsx +++ b/components/upload/style/index.tsx @@ -1,8 +1,55 @@ -import '../../style/index.less'; -import './index.less'; +// deps-lint-skip-all +import { CSSObject } from '@ant-design/cssinjs'; +import { genComponentStyleHook, resetComponent } from '../../_util/theme'; +import genDraggerStyle from './dragger'; +import genListStyle from './list'; +import genMotionStyle from './motion'; +import genRtlStyle from './rtl'; +import { genPictureStyle, genPictureCardStyle } from './picture'; +import type { GenerateStyle, FullToken } from '../../_util/theme'; -// style dependencies -// deps-lint-skip: form -import '../../button/style'; -import '../../progress/style'; -import '../../tooltip/style'; +export interface ComponentToken { + uploadActionsColor: CSSObject['color']; +} + +const genBaseStyle: GenerateStyle> = token => { + const { componentCls } = token; + + return { + [`${componentCls}-wrapper`]: { + ...resetComponent(token), + + [componentCls]: { + outline: 0, + "input[type='file']": { + cursor: 'pointer', + }, + }, + + [`${componentCls}-select`]: { + display: 'inline-block', + }, + + [`${componentCls}-disabled`]: { + cursor: 'not-allowed', + }, + }, + }; +}; + +// ============================== Export ============================== +export default genComponentStyleHook( + 'Upload', + token => [ + genBaseStyle(token), + genDraggerStyle(token), + genPictureStyle(token), + genPictureCardStyle(token), + genListStyle(token), + genMotionStyle(token), + genRtlStyle(token), + ], + token => ({ + uploadActionsColor: token.colorTextSecondary, + }), +); diff --git a/components/upload/style/list.tsx b/components/upload/style/list.tsx new file mode 100644 index 0000000000..a7e7bc68b3 --- /dev/null +++ b/components/upload/style/list.tsx @@ -0,0 +1,125 @@ +import { clearFix } from '../../_util/theme'; +import type { GenerateStyle, FullToken } from '../../_util/theme'; + +const genListStyle: GenerateStyle> = token => { + const { componentCls, antCls, iconCls } = token; + const itemCls = `${componentCls}-list-item`; + const actionsCls = `${itemCls}-actions`; + const actionCls = `${itemCls}-action`; + + return { + [`${componentCls}-wrapper`]: { + [`${componentCls}-list`]: { + ...clearFix(), + lineHeight: token.lineHeight, + + [itemCls]: { + position: 'relative', + height: token.lineHeight * token.fontSizeBase, + marginTop: token.marginXS, + fontSize: token.fontSizeBase, + display: 'flex', + alignItems: 'center', + transition: `background-color ${token.motionDurationSlow}`, + + '&:hover': { + backgroundColor: token.controlItemBgHover, + }, + + [`${itemCls}-name`]: { + padding: `0 ${token.paddingXS}px`, + overflow: 'hidden', + lineHeight: token.lineHeight, + whiteSpace: 'nowrap', + textOverflow: 'ellipsis', + flex: 'auto', + transition: `all ${token.motionDurationSlow}`, + }, + + [actionsCls]: { + [actionCls]: { + opacity: 0, + }, + + [`${actionCls}${antCls}-btn-sm`]: { + // FIXME: upload token + height: 20, + lineHeight: 1, + // FIXME: should not override small button + '> span': { + transform: 'scale(1)', + }, + }, + + [` + ${actionCls}:focus, + &.picture ${actionCls} + `]: { + opacity: 1, + }, + + [iconCls]: { + color: token.uploadActionsColor, + transition: `all ${token.motionDurationSlow}`, + }, + + [`&:hover ${iconCls}`]: { + color: token.colorText, + }, + }, + + [`${componentCls}-icon ${iconCls}`]: { + color: token.colorTextSecondary, + fontSize: token.fontSizeBase, + }, + + [`${itemCls}-progress`]: { + position: 'absolute', + // FIXME: upload token + bottom: -12, + width: '100%', + paddingInlineStart: token.fontSizeBase + token.paddingXS, + fontSize: token.fontSizeBase, + lineHeight: 0, + }, + }, + + [`${itemCls}:hover ${actionCls}`]: { + opacity: 1, + color: token.colorText, + }, + + [`${itemCls}-error`]: { + color: token.colorError, + [`${itemCls}-name, ${componentCls}-icon ${iconCls}`]: { + color: token.colorError, + }, + + [actionsCls]: { + [`${iconCls}, ${iconCls}:hover`]: { + color: token.colorError, + }, + + [actionCls]: { + opacity: 1, + }, + }, + }, + + [`${componentCls}-list-item-container`]: { + transition: `opacity ${token.motionDurationSlow}, height ${token.motionDurationSlow}`, + + // For smooth removing animation + '&::before': { + display: 'table', + width: 0, + height: 0, + content: '""', + }, + }, + }, + }, + }; +}; + +export default genListStyle; diff --git a/components/upload/style/motion.tsx b/components/upload/style/motion.tsx new file mode 100644 index 0000000000..3c5df66b04 --- /dev/null +++ b/components/upload/style/motion.tsx @@ -0,0 +1,50 @@ +import { Keyframes } from '@ant-design/cssinjs'; +import type { GenerateStyle, FullToken } from '../../_util/theme'; + +const uploadAnimateInlineIn = new Keyframes('uploadAnimateInlineIn', { + from: { + width: 0, + height: 0, + margin: 0, + padding: 0, + opacity: 0, + }, +}); + +const uploadAnimateInlineOut = new Keyframes('uploadAnimateInlineOut', { + to: { + width: 0, + height: 0, + margin: 0, + padding: 0, + opacity: 0, + }, +}); +// =========================== Motion =========================== +const genMotionStyle: GenerateStyle> = token => { + const { componentCls } = token; + const inlineCls = `${componentCls}-animate-inline`; + + return [ + { + [`${componentCls}-wrapper`]: { + [`${inlineCls}-appear, ${inlineCls}-enter, ${inlineCls}-leave`]: { + animationDuration: token.motionDurationSlow, + animationFillMode: token.motionEaseInOutCirc, + }, + + [`${inlineCls}-appear, ${inlineCls}-enter`]: { + animationName: uploadAnimateInlineIn, + }, + + [`${inlineCls}-leave`]: { + animationName: uploadAnimateInlineOut, + }, + }, + }, + uploadAnimateInlineIn, + uploadAnimateInlineOut, + ]; +}; + +export default genMotionStyle; diff --git a/components/upload/style/picture.tsx b/components/upload/style/picture.tsx new file mode 100644 index 0000000000..761eb96063 --- /dev/null +++ b/components/upload/style/picture.tsx @@ -0,0 +1,242 @@ +import { TinyColor } from '@ctrl/tinycolor'; +import { clearFix } from '../../_util/theme'; +import type { GenerateStyle, FullToken } from '../../_util/theme'; + +const genPictureStyle: GenerateStyle> = token => { + const { componentCls, iconCls } = token; + const listCls = `${componentCls}-list`; + const itemCls = `${listCls}-item`; + // FIXME: upload token + const uploadPictureThumbnailSize = 48; + + return { + [`${componentCls}-wrapper`]: { + // ${listCls} 增加优先级 + [`${listCls}${listCls}-picture, ${listCls}${listCls}-picture-card`]: { + [itemCls]: { + position: 'relative', + height: uploadPictureThumbnailSize + token.controlLineWidth * 2 + token.paddingXS * 2, + padding: token.paddingXS, + border: `${token.controlLineWidth}px ${token.controlLineType} ${token.colorBorder}`, + borderRadius: token.radiusBase, + + '&:hover': { + background: 'transparent', + }, + + [`${itemCls}-thumbnail`]: { + width: uploadPictureThumbnailSize, + height: uploadPictureThumbnailSize, + lineHeight: `${uploadPictureThumbnailSize + token.paddingSM}px`, + textAlign: 'center', + // FIXME: upload token + opacity: 0.8, + flex: 'none', + overflow: 'hidden', + textOverflow: 'ellipsis', + whiteSpace: 'nowrap', + + [iconCls]: { + fontSize: uploadPictureThumbnailSize / 2 + 2, + }, + + img: { + display: 'block', + width: '100%', + height: '100%', + overflow: 'hidden', + }, + }, + + [`${itemCls}-progress`]: { + // FIXME: upload token + bottom: 14, + width: `calc(100% - ${token.paddingSM * 2}px)`, + marginTop: 0, + // FIXME: upload token + paddingInlineStart: uploadPictureThumbnailSize + token.paddingXS, + }, + }, + + [`${itemCls}-error`]: { + borderColor: token.colorError, + + // Adjust the color of the error icon : https://github.com/ant-design/ant-design/pull/24160 + [`${itemCls}-thumbnail ${iconCls}`]: { + [`svg path[fill='#e6f7ff']`]: { + fill: token.colorBgError, + }, + [`svg path[fill='#1890ff']`]: { + fill: token.colorError, + }, + }, + }, + + [`${itemCls}-uploading`]: { + borderStyle: 'dashed', + + [`${itemCls}-name`]: { + // FIXME: upload token + marginBottom: 12, + }, + }, + }, + }, + }; +}; + +const genPictureCardStyle: GenerateStyle> = token => { + const { componentCls, iconCls } = token; + const listCls = `${componentCls}-list`; + const itemCls = `${listCls}-item`; + + // FIXME: upload token + const uploadPictureCardThumbnailSize = 88; + const uploadPictureCardSize = uploadPictureCardThumbnailSize + token.paddingXS * 2; + + return { + [`${componentCls}-wrapper${componentCls}-picture-card-wrapper`]: { + ...clearFix(), + display: 'inline-block', + width: '100%', + + [`${componentCls}${componentCls}-select`]: { + width: uploadPictureCardSize, + height: uploadPictureCardSize, + marginInlineEnd: token.marginXS, + marginBottom: token.marginXS, + textAlign: 'center', + verticalAlign: 'top', + backgroundColor: token.colorBgComponentSecondary, + border: `${token.controlLineWidth}px dashed ${token.colorBorder}`, + borderRadius: token.radiusBase, + cursor: 'pointer', + transition: `border-color ${token.motionDurationSlow}`, + + [`> ${componentCls}`]: { + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + height: '100%', + textAlign: 'center', + }, + + [`&:not(${componentCls}-disabled):hover`]: { + borderColor: token.colorPrimary, + }, + }, + + // list + [`${listCls}${listCls}-picture-card`]: { + [`${listCls}-item-container`]: { + display: 'inline-block', + width: uploadPictureCardSize, + height: uploadPictureCardSize, + marginBlock: `0 ${token.marginXS}px`, + marginInline: `0 ${token.marginXS}px`, + verticalAlign: 'top', + }, + + '&::after': { + display: 'none', + }, + + [itemCls]: { + height: '100%', + margin: 0, + + '&::before': { + position: 'absolute', + zIndex: 1, + width: `calc(100% - ${token.paddingXS * 2}px)`, + height: `calc(100% - ${token.paddingXS * 2}px)`, + // FIXME: upload token + backgroundColor: new TinyColor('#000').setAlpha(0.5).toRgbString(), + opacity: 0, + transition: `all ${token.motionDurationSlow}`, + content: '" "', + }, + }, + + [`${itemCls}:hover`]: { + [`&::before, ${itemCls}-actions`]: { + opacity: 1, + }, + }, + + [`${itemCls}-actions`]: { + position: 'absolute', + insetInlineStart: 0, + zIndex: 10, + width: '100%', + whiteSpace: 'nowrap', + textAlign: 'center', + opacity: 0, + transition: `all ${token.motionDurationSlow}`, + + [`${iconCls}-eye, ${iconCls}-download, ${iconCls}-delete`]: { + zIndex: 10, + // FIXME: upload token + width: 16, + margin: `0 ${token.marginXXS}px`, + // FIXME: upload token + fontSize: 16, + cursor: 'pointer', + transition: `all ${token.motionDurationSlow}`, + }, + }, + + [`${itemCls}-actions, ${itemCls}-actions:hover`]: { + [`${iconCls}-eye, ${iconCls}-download, ${iconCls}-delete`]: { + // FIXME: @text-color-dark: fade(@white, 85%); + color: new TinyColor('#fff').setAlpha(0.85).toRgbString(), + '&:hover': { + // FIXME: @text-color-dark: fade(@white, 85%); + color: '#fff', + }, + }, + }, + + [`${itemCls}-thumbnail, ${itemCls}-thumbnail img`]: { + position: 'static', + display: 'block', + width: '100%', + height: '100%', + objectFit: 'contain', + }, + + [`${itemCls}-name`]: { + display: 'none', + textAlign: 'center', + }, + + [`${itemCls}-file + ${itemCls}-name`]: { + position: 'absolute', + // FIXME: upload token + bottom: 18, + display: 'block', + width: `calc(100% - ${token.paddingXS * 2}px)`, + }, + + [`${itemCls}-uploading`]: { + [`&${itemCls}`]: { + backgroundColor: token.colorBgComponentSecondary, + }, + + [`&::before, ${iconCls}-eye, ${iconCls}-download, ${iconCls}-delete`]: { + display: 'none', + }, + }, + + [`${itemCls}-progress`]: { + // FIXME: upload token + bottom: 32, + width: `calc(100% - ${token.paddingXS * 2}px)`, + paddingInlineStart: 0, + }, + }, + }, + }; +}; + +export { genPictureStyle, genPictureCardStyle }; diff --git a/components/upload/style/rtl.less b/components/upload/style/rtl.less index a7054731f0..14ccf81b18 100644 --- a/components/upload/style/rtl.less +++ b/components/upload/style/rtl.less @@ -1,165 +1,165 @@ -@import '../../style/themes/index'; -@import '../../style/mixins/index'; +// @import '../../style/themes/index'; +// @import '../../style/mixins/index'; -@upload-prefix-cls: ~'@{ant-prefix}-upload'; -@upload-item: ~'@{ant-prefix}-upload-list-item'; +// @upload-prefix-cls: ~'@{ant-prefix}-upload'; +// @upload-item: ~'@{ant-prefix}-upload-list-item'; -.@{upload-prefix-cls} { - &-rtl { - direction: rtl; - } +// .@{upload-prefix-cls} { +// &-rtl { +// direction: rtl; +// } - &&-select-picture-card { - .@{upload-prefix-cls}-rtl& { - margin-right: auto; - margin-left: 8px; - } - } -} +// &&-select-picture-card { +// .@{upload-prefix-cls}-rtl& { +// margin-right: auto; +// margin-left: 8px; +// } +// } +// } -.@{upload-prefix-cls}-list { - &-rtl { - direction: rtl; - } +// .@{upload-prefix-cls}-list { +// &-rtl { +// direction: rtl; +// } - &-item-list-type-text { - &:hover { - .@{upload-prefix-cls}-list-item-name-icon-count-1 { - .@{upload-prefix-cls}-list-rtl & { - padding-right: 22px; - padding-left: 14px; - } - } - .@{upload-prefix-cls}-list-item-name-icon-count-2 { - .@{upload-prefix-cls}-list-rtl & { - padding-right: 22px; - padding-left: 28px; - } - } - } - } +// &-item-list-type-text { +// &:hover { +// .@{upload-prefix-cls}-list-item-name-icon-count-1 { +// .@{upload-prefix-cls}-list-rtl & { +// padding-right: 22px; +// padding-left: 14px; +// } +// } +// .@{upload-prefix-cls}-list-item-name-icon-count-2 { +// .@{upload-prefix-cls}-list-rtl & { +// padding-right: 22px; +// padding-left: 28px; +// } +// } +// } +// } - &-item { - &-name { - .@{upload-prefix-cls}-list-rtl & { - padding-right: @font-size-base + 8px; - padding-left: 0; - } - } +// &-item { +// &-name { +// .@{upload-prefix-cls}-list-rtl & { +// padding-right: @font-size-base + 8px; +// padding-left: 0; +// } +// } - &-name-icon-count-1 { - .@{upload-prefix-cls}-list-rtl & { - padding-left: 14px; - } - } +// &-name-icon-count-1 { +// .@{upload-prefix-cls}-list-rtl & { +// padding-left: 14px; +// } +// } - &-card-actions { - .@{upload-prefix-cls}-list-rtl & { - right: auto; - left: 0; - } - .@{iconfont-css-prefix} { - .@{upload-prefix-cls}-list-rtl & { - padding-right: 0; - padding-left: 5px; - } - } - } +// &-card-actions { +// .@{upload-prefix-cls}-list-rtl & { +// right: auto; +// left: 0; +// } +// .@{iconfont-css-prefix} { +// .@{upload-prefix-cls}-list-rtl & { +// padding-right: 0; +// padding-left: 5px; +// } +// } +// } - &-info { - .@{upload-prefix-cls}-list-rtl & { - padding: 0 4px 0 12px; - } - } +// &-info { +// .@{upload-prefix-cls}-list-rtl & { +// padding: 0 4px 0 12px; +// } +// } - &-error &-card-actions { - .@{iconfont-css-prefix} { - .@{upload-prefix-cls}-list-rtl & { - padding-right: 0; - padding-left: 5px; - } - } - } +// &-error &-card-actions { +// .@{iconfont-css-prefix} { +// .@{upload-prefix-cls}-list-rtl & { +// padding-right: 0; +// padding-left: 5px; +// } +// } +// } - &-progress { - .@{upload-prefix-cls}-list-rtl & { - padding-right: @font-size-base + 12px; - padding-left: 0; - } - } - } +// &-progress { +// .@{upload-prefix-cls}-list-rtl & { +// padding-right: @font-size-base + 12px; +// padding-left: 0; +// } +// } +// } - &-picture, - &-picture-card { - .@{upload-item}-info { - padding: 0; - } +// &-picture, +// &-picture-card { +// .@{upload-item}-info { +// padding: 0; +// } - .@{upload-item}-thumbnail { - .@{upload-prefix-cls}-list-rtl& { - right: 8px; - left: auto; - } - } +// .@{upload-item}-thumbnail { +// .@{upload-prefix-cls}-list-rtl& { +// right: 8px; +// left: auto; +// } +// } - .@{upload-item}-icon { - .@{upload-prefix-cls}-list-rtl& { - right: 50%; - left: auto; - transform: translate(50%, -50%); - } - } +// .@{upload-item}-icon { +// .@{upload-prefix-cls}-list-rtl& { +// right: 50%; +// left: auto; +// transform: translate(50%, -50%); +// } +// } - .@{upload-item}-name { - .@{upload-prefix-cls}-list-rtl& { - margin: 0 8px 0 0; - padding-right: 48px; - padding-left: 8px; - } - } +// .@{upload-item}-name { +// .@{upload-prefix-cls}-list-rtl& { +// margin: 0 8px 0 0; +// padding-right: 48px; +// padding-left: 8px; +// } +// } - .@{upload-item}-name-icon-count-1 { - .@{upload-prefix-cls}-list-rtl& { - padding-right: 48px; - padding-left: 18px; - } - } +// .@{upload-item}-name-icon-count-1 { +// .@{upload-prefix-cls}-list-rtl& { +// padding-right: 48px; +// padding-left: 18px; +// } +// } - .@{upload-item}-name-icon-count-2 { - .@{upload-prefix-cls}-list-rtl& { - padding-right: 48px; - padding-left: 36px; - } - } +// .@{upload-item}-name-icon-count-2 { +// .@{upload-prefix-cls}-list-rtl& { +// padding-right: 48px; +// padding-left: 36px; +// } +// } - .@{upload-item}-progress { - .@{upload-prefix-cls}-list-rtl& { - padding-right: 0; - padding-left: 0; - } - } - } +// .@{upload-item}-progress { +// .@{upload-prefix-cls}-list-rtl& { +// padding-right: 0; +// padding-left: 0; +// } +// } +// } - &-picture-card { - &-container { - .@{upload-prefix-cls}-list-rtl & { - margin: 0 0 @margin-xs @margin-xs; - } - } +// &-picture-card { +// &-container { +// .@{upload-prefix-cls}-list-rtl & { +// margin: 0 0 @margin-xs @margin-xs; +// } +// } - .@{upload-item}-actions { - .@{upload-prefix-cls}-list-rtl& { - right: 50%; - left: auto; - transform: translate(50%, -50%); - } - } +// .@{upload-item}-actions { +// .@{upload-prefix-cls}-list-rtl& { +// right: 50%; +// left: auto; +// transform: translate(50%, -50%); +// } +// } - .@{upload-item}-file + .@{upload-item}-name { - .@{upload-prefix-cls}-list-rtl& { - margin: 8px 0 0; - padding: 0; - } - } - } -} +// .@{upload-item}-file + .@{upload-item}-name { +// .@{upload-prefix-cls}-list-rtl& { +// margin: 8px 0 0; +// padding: 0; +// } +// } +// } +// } diff --git a/components/upload/style/rtl.tsx b/components/upload/style/rtl.tsx new file mode 100644 index 0000000000..1cfdb786a8 --- /dev/null +++ b/components/upload/style/rtl.tsx @@ -0,0 +1,14 @@ +import type { GenerateStyle, FullToken } from '../../_util/theme'; + +// =========================== Motion =========================== +const genRtlStyle: GenerateStyle> = token => { + const { componentCls } = token; + + return { + [`${componentCls}-rtl`]: { + direction: 'rtl', + }, + }; +}; + +export default genRtlStyle;