diff --git a/.eslintignore b/.eslintignore index 4691c01d71..fe29fe2bac 100644 --- a/.eslintignore +++ b/.eslintignore @@ -25,6 +25,7 @@ site/**/*.tsx typings es/**/* lib/**/* +locale node_modules _site dist diff --git a/.eslintrc.js b/.eslintrc.js index d4e10723de..88fc62f258 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -20,6 +20,9 @@ module.exports = { version: 'detect', }, polyfills: ['Promise', 'URL'], + 'import/resolver': { + typescript: {}, + }, }, parser: '@typescript-eslint/parser', plugins: ['react', 'babel', 'jest', '@typescript-eslint', 'react-hooks', 'unicorn', 'markdown'], diff --git a/.gitignore b/.gitignore index 3b019c72da..b7f1125964 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,7 @@ dist report.html /lib /es +/locale elasticsearch-* config/base.yaml /.vscode/ diff --git a/AUTHORS.txt b/AUTHORS.txt index 69a745a89e..c2070fc45a 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -6,6 +6,7 @@ 778758944 <778758944@qq.com> Aaron Cawte Aaron Planell López +Aaron674092290 Adam Stankiewicz Aditya Padhi Adrian Dimitrov @@ -19,6 +20,7 @@ Aiello <770540123@qq.com> AkiJoey Akshat Mittal Alan Braithwaite +Alan Deng Albert Mañosa Albert Zhang Albert Zheng @@ -40,6 +42,7 @@ Alexey Vinogradov Alexey Yakovlev Alfred Qiu Ali Zhdanov +AliRezaBeigy Aliaksandr Alireza Alvin Abia @@ -52,6 +55,7 @@ Anas Tawfeek Andre Perunicic Andre Zyczkowski Andrea Blanco +Andrew Horn Andrew Murray Andrew Shearer Andrey G @@ -107,6 +111,7 @@ Bruno Maia Bryan Berger BugHiding <609228186@qq.com> C <4019980@qq.com> +C. T. Lin C.J. Winslow CORP\lianyufeng <15275222711@163.com> Calin Vlad @@ -124,6 +129,7 @@ Cemre Mengu Chalk Chandler Moisen Chang Wang +Chang Wei Chang Wei <867597730@qq.com> Charles Covey-Brandt Charlie Jonas @@ -151,11 +157,13 @@ Cong Yoo Cong Zhang Connor White Conway Anderson +Cooper Veysey Cordaro CornerSkyless <573196853@qq.com> Curly.Water D & R Daewoong Moon +Dalton Craven Damian Green Damian Green Dan Minshew @@ -183,7 +191,7 @@ Dean van Niekerk Debiancc DengYun Denis -Dennis273 +Dennis Chen Derrick Di Wu DiamondYuan @@ -205,6 +213,8 @@ Dorian DosLin Douglas Mason Dreamcreative +Dunqing +Dunqing <1247748612@qq.com> Dzmitry Yarmoshkin Eager <1226393396@qq.com> Eber Rodrigues @@ -233,6 +243,7 @@ Eric Lee Eric Turriff Eric Wang Eric Wang +Ernest Folch Erwann Mest Eslam Yahya Eugene Matvejev @@ -261,6 +272,7 @@ Fullstop000 GJ Wang GSBL <2602140596@qq.com> Gabe Medrash +Gabriel Haruki Gabriel Henrique Gabriel Le Breton Gabriel Mendez Reyes @@ -295,10 +307,10 @@ Guru Mahendran HJin.me Hai Phan Nguyen Haibin Yu -Hal-pan Hale Deng Han Han Hanai +Haniel Cui Hanjun Kim Hanz Luo HarlanLuo @@ -326,6 +338,8 @@ Hsuan Lee Hubert Argasinski Hughen <446370503@163.com> Hugo LEHMANN +Humble <745653239@qq.com> +Hyunseok.Kim ILdar Nogmanov Igor Igor Andriushchenko @@ -363,6 +377,7 @@ James James Tsang James Yeung JamesYin +Jamki <13414367591@163.com> Jan Václavík Janry Jaroslav Bereza @@ -377,6 +392,7 @@ Jay Fong Jean-Luc Sorak Jean-Philippe Roy Jeff Wen +Jefferson Rafael Kozerski Jeffrey Carl Faden Jehu Jelle de Jong @@ -413,6 +429,7 @@ John Carlo John Johnson III John Nguyen Johnny Lim +Johnny-young <1571779481@qq.com> Johnsen Jonatas Walker Jonathan Gabaut @@ -426,6 +443,7 @@ Josué JounQin JribiBelhassen Jtree03 +Ju/Smwhr JuFeng Zhang Juan Carlos Lloret H Juan Rodrigo Venegas Boesch @@ -442,7 +460,7 @@ Jógvan Olsen Kaan KÜÇÜK Kaien Liao Kamal Mahmudi -Karott Schu +Karott Kasra Bigdeli Kayson Wu <772663139@qq.com> Kelvin Chu @@ -478,6 +496,7 @@ Kuitos Kurt Furbush Kyle Kelley Kyle Rosenberg +Kyrielin LLinFan- LT246-VINHNPH\vinhnph Laith @@ -485,6 +504,7 @@ Larry Laski LaySent LeeHarlan <709886167@qq.com> LeezQ +Len LeoYang Leon Koole Leon Shi @@ -508,6 +528,7 @@ Lu Yu Lucien Lee Ludwig Bäcklund Luke Vella +Luobo Zhang Lyndon001 M Mitchell M. Burak Kalkan @@ -528,8 +549,10 @@ MaoYiWei <137308365@qq.com> Map1en_ Marcel Jackwerth Marcela Bomfim +Marcia Sun Marcio Pamplona Marco Afonso +Marco Heinrich Marcus Bransbury Marcus Stenbeck Marius Ileana @@ -547,6 +570,7 @@ Matt Wilkinson Max Maximilian Meyer Md_ZubairAhmed +Mehdi Salem Naraghi MeiLin MengZhaoFly <1424254461@qq.com> Meow-z <372086270@qq.com> @@ -596,6 +620,7 @@ Mr.jiangzhiguo Ms. Wang <767074895@qq.com> MuYu Muhammad Sameer +Mykyta Velykanov Mário Gonçalves Nariman Movaffaghi Nathan Broadbent @@ -605,6 +630,7 @@ Nathan Tavares Nascimento Nathan Wells Naveen Neekey +Neil <100huming@gmail.com> Nekron Neo Tan Neto Braghetto @@ -621,6 +647,7 @@ Nikolay Nikolay Solovyov Nima Dehnashi Nimo +NinJa <386805508@qq.com> Nishant Arora Niyaz Akhmetov Nokecy @@ -637,7 +664,6 @@ Oren Kosto Oren Kosto Orkhan Huseynli OuYancey -PCCCCCCC Pablo Recalde Panjie Setiawan Wicaksono Patrick Gidich @@ -647,6 +673,7 @@ Paul Julien Paul Julien Peach Pengsha Ying <810998652@qq.com> +Peritot Chan Peter Peter Berg Phanupong Janthapoon @@ -689,6 +716,7 @@ Regan Langford Renny Ren Renovate Bot Rex +Rex Zeng Ricardo Morais Ricardo Raphael Joson Richard D. Worth @@ -698,6 +726,7 @@ Robin Pokorny Rodrigo Ehlers Rohan Bagchi Rohan Malhotra +Ron Šmeral Rongjian Zhang Rrrandom RunningCoderLee @@ -748,6 +777,7 @@ Shun Shuvalov Anton SimaQ Simo Aleksandrov +Simon Simon Altschuler Simon Knott Siou @@ -767,12 +797,15 @@ Stevche Radevski Steven.zhong <953665604@qq.com> Subroto Suki小火车 <463355954@qq.com> +Sukka Sumit Vekariya Sunny Luo Sven Efftinge +Svyatoslav SyMind SylvanasGone <397009765@qq.com> TTC <345866517@qq.com> +TangLL Tanmoy Bhowmik Tannmay S Gupta Tao @@ -792,7 +825,6 @@ Thiebaud Thomas Thomas Thomas Ladd Thomas Zipner -Tianyuan Zhang Tino D Tmk Tom Gao @@ -809,7 +841,9 @@ TsesamLi Ty Mick Tyler Ubaldo Quintana +Uladzimir Atroshchanka Uladzimir Atroshchanka +Umberto Gariggio Vadim Macagon Valentin Vichnal Van Nguyen @@ -823,6 +857,7 @@ Vijay Thirugnanam Vincent Zhang Vineet Srivastav Viorel Cojocaru +Vishal Jagtap Vitaliy Mazurenko Vitaly Budovski ViviaRui @@ -838,22 +873,26 @@ Wang yb Warren Seymour Webber Takken Wei Zhu -WeijieChen Wenchao Hu Wendell Wendell Wenqi Chen <1264578441@qq.com> Wensheng Xu +Wesley Will Will Chen Will Soares +William Bergeron-Drouin William Cai William Stein WingGao Wu Haotian WuJiali <18767152447@163.com> +Wuxh +Wuxh X-Jagger XBTop1! +XIN HU XTY <^@xty.dev> Xiaoming Xie Guanglei @@ -869,6 +908,8 @@ Yaindrop YanYuan <1025138284@qq.com> Yang Bin Yangzhedi +Yanlin Jiang +Yanming Deng Yann Normand Yann Pringault Yash Joshi @@ -883,6 +924,7 @@ YuChao Liang YuTao Yuan <1076849402@qq.com> Yuhang Liu <644186735@qq.com> +Yuki Zhang Yulia Maximova Yunfly <120562638@qq.com> Yunus EŞ @@ -892,6 +934,7 @@ Yury Kozyrev Yusuke Ito Yuwei Ba Yuxuan Huo +Yuyao Nie YuyingWu ZHANGYU <723156735@qq.com> ZYSzys @@ -902,7 +945,9 @@ Zap ZeroToOne Zester Quinn Albano Zhang Zhi +Zheeeng Zheeeng +ZhiHao Li <940166841@qq.com> Zhiqiang Gong ZhouZhen <503633021@qq.com> Zhuo Chen @@ -915,6 +960,7 @@ aashutoshrathi acfasj adam afc163 +agarciaguillo agent-z <1607291079@qq.com> aghArdeshir ahalimkara @@ -943,6 +989,7 @@ benben bigbigbo binyellow <571704908@qq.com> blankzust <450811238@qq.com> +bobo <625391250@qq.com> btea <2356281422@qq.com> bukas byuanama @@ -960,6 +1007,8 @@ chen-jingjie <2383844893@qq.com> chencheng (云谦) chenlei <745512023@qq.com> chenlong +chensw +chenxiang <597219320@qq.com> chenxiaochun chequerNoel chisus @@ -968,10 +1017,12 @@ cieldon32 cjahv cjmafei <1135328499@qq.com> cjmafei +clean99 clinyong cnjs <1269075501@qq.com> codesign corneyl +csr632 <632882184@qq.com> daczczcz1 damon.chen david.lv @@ -980,7 +1031,6 @@ davidhatten ddcat1115 decade delesseps -dengqing <1247748612@qq.com> denzw dependabot[bot] desperado @@ -988,18 +1038,21 @@ detailyang devqin dian.li digz6666 +dingkang djorkaeff dolfje douxc dpyzo0o dujun duzliang +edc-hui edgji eidonjoe <806488716@qq.com> elios elrrrrrrr eruca ezpub +fairyland feeng feng zhi hao fengmk2 @@ -1008,6 +1061,7 @@ fkysly flashback313 flyerH frezc <504021398@qq.com> +gaokaifeis gaoryrt gaozhenqian <837856276@qq.com> genie @@ -1019,6 +1073,7 @@ gyh9457 gzq haianweifeng <1531297152@qq.com> haimrait +haipeng handy hank hanpei <75189218@qq.com> @@ -1034,6 +1089,7 @@ hello-chinese <841030329@qq.com> henryv0 hi-caicai hicrystal <295247343@qq.com> +hms181231 hongxuWei howard huangyan.py @@ -1063,13 +1119,16 @@ jiang.an jiang.he <573748150jh@163.com> jieniu$ jinouwuque +jinrui jinyaqiao1102 <405782493@QQ.com> jojoLockLock +joson <373693643@qq.com> jueinin <1014397160@qq.com> junjing.zhang kacjay <45483388@qq.com> kaifei <150641329@qq.com> kailunyao +kalykun <984757534@qq.com> kanweiwei <475801900@qq.com> kaoding <41830859@qq.com> kasinooya @@ -1081,6 +1140,7 @@ keng kenve kermolaev kily zhou +kiner-tang(文辉) <1127031143@qq.com> klouskingsley ko konakona @@ -1088,6 +1148,7 @@ kossel kristof0425 kuang kun sam +lalalazero leadream <857098475@qq.com> lehug leijingdao @@ -1100,19 +1161,25 @@ lhyt <515593899@qq.com> liangfei lich-yoo liekkas +lihao lihqi <455711093@qq.com> +lijianan <574980606@qq.com> lilun limingxin <906529775@qq.com> +linqiqi077 <865530219@qq.com> lisenenkov littleLane <857183384@qq.com> +littledian <1197434548@qq.com> liuchuzhang liuchuzhang +liuycy lixiaochou077 lixiaoyang1992 liyuanqiu lizhen llwslc loganpowell +losgif luyiming lvren lxnxbnq @@ -1135,6 +1202,7 @@ mraiguo <810158465@qq.com> mraiguo mumiao mushan0x0 +muxin muzuiget natergj netcon @@ -1143,15 +1211,18 @@ nick-ChenZe niko <644506165@qq.com> nitinknolder nnecec +nuintun nuintun oldchicken paleface001 +parabolazz paranoidjk parlop paul <34345790@qq.com> pbrink231 peiming pengtikui <949828390@qq.com> +pfsu picodoth picodoth pinggod @@ -1168,6 +1239,7 @@ qramilq qubaoming ravirambles realEago <774855001@qq.com> +rendaoer renzhao1113 <547249523@qq.com> richardison ryangun @@ -1186,6 +1258,7 @@ shelwin shlice shmilyKang <953333436@qq.com> shouyong +simplejason siyu77 slientcloud sliwey @@ -1215,6 +1288,7 @@ tom tom toshi1127 twobin +ty888 <1506125048@qq.com> u3u ubuntugod uchanlee @@ -1268,7 +1342,6 @@ xiejiahe xilihuasi <2857818553@qq.com> xinhui.zxh xrkffgg -xrkffgg xuqiang xyb <576420147@qq.com> xz @@ -1284,6 +1357,7 @@ yehq yeliex yeshan333 <1329441308@qq.com> yibu.wang +yifanwww yiminanci yiminghe yingxirz @@ -1292,6 +1366,7 @@ youngz yuche yuezk yui <1151815317@qq.com> +yykoypj <601924094@qq.com> z zack zefeng @@ -1308,6 +1383,7 @@ zhao-huo-long zhaocai zhaopeidong zhenfan.yu +zhengjitf zhuguibiao <505418722@qq.com> zhujun24 zhyupe @@ -1317,16 +1393,19 @@ zj9495 zkwolf zlljqn zollero -zombiej zongzi531 zoomdong <1344492820@qq.com> +zpc7 zqran ztplz +zty zuiidea zx6658 zxyao zytjs +zz <2418184580@qq.com> °))))彡 +Ömer Faruk APLAK Ștefan Filip रोहन मल्होत्रा 一喵呜 @@ -1337,6 +1416,7 @@ zytjs 九思⚡⚡⚡ <2228429150@qq.com> 二哲 二手掉包工程师 +二货爱吃白萝卜 云剪者 <584518260@qq.com> 付引 何乐 @@ -1344,6 +1424,7 @@ zytjs 何锦余 佛门耶稣 信鑫-King +元凛 兼续 冷方冰 <664930912@qq.com> 刘红 @@ -1360,6 +1441,7 @@ zytjs 小哈husky <951565664@qq.com> 小菜 <645801890@qq.com> 小鹅鹅鹅 +尾宿君 山客 崔宏森 <948346354@qq.com> 广彬-梁 <326741518@qq.com> @@ -1384,6 +1466,7 @@ zytjs 柚子男 沐霖 <304647173@qq.com> 爱but的苍蝇 <354788473@qq.com> +王小王 王林涛 王浩 王集鹄 @@ -1391,6 +1474,7 @@ zytjs 白羊座小葛 砖家 砖家 <576679268@qq.com> +社长长 章鱼 竹尔 米老朱 @@ -1398,6 +1482,7 @@ zytjs 约修亚 <510448079@qq.com> 翁润雨 <593110501@qq.com> 臧甲彬 fadeaway <498497303@qq.com> +舜岳 <1277952981@qq.com> 苏秦 <646382806@qq.com> 英布 萧琚 @@ -1406,6 +1491,7 @@ zytjs 蔡伦 薛定谔的猫 薛定谔的猫 +行冥 <571748236@qq.com> 诸岳 诸岳 诸岳 @@ -1414,6 +1500,7 @@ zytjs 谭真 <736420282@qq.com> 超能刚哥 迷渡 +郑国庆 郑旭 <332171564@qq.com> 闲耘™ 陆离 @@ -1434,4 +1521,5 @@ zytjs 黄文鉴 黄斌 黑雨 +龙风 <455947455@qq.com> 龚方闻 \ No newline at end of file diff --git a/components/_util/reactNode.ts b/components/_util/reactNode.ts index 38e23ee422..8e5b73c016 100644 --- a/components/_util/reactNode.ts +++ b/components/_util/reactNode.ts @@ -2,7 +2,7 @@ import * as React from 'react'; export const { isValidElement } = React; -export function isFragment(child: React.ReactElement): boolean { +export function isFragment(child: any): boolean { return child && isValidElement(child) && child.type === React.Fragment; } diff --git a/components/_util/wave/index.tsx b/components/_util/wave/index.tsx index eea5408a50..fc4ffeba20 100644 --- a/components/_util/wave/index.tsx +++ b/components/_util/wave/index.tsx @@ -114,7 +114,7 @@ class InternalWave extends React.Component { onClick = (node: HTMLElement, waveColor: string) => { const { insertExtraNode, disabled } = this.props; - if (disabled || !node || isHidden(node) || node.className.indexOf('-leave') >= 0) { + if (disabled || !node || isHidden(node) || node.className.includes('-leave')) { return; } @@ -183,7 +183,7 @@ class InternalWave extends React.Component { !node || !node.getAttribute || node.getAttribute('disabled') || - node.className.indexOf('disabled') >= 0 + node.className.includes('disabled') ) { return; } diff --git a/components/alert/index.en-US.md b/components/alert/index.en-US.md index 754dbca099..03a1cd2885 100644 --- a/components/alert/index.en-US.md +++ b/components/alert/index.en-US.md @@ -33,20 +33,20 @@ Alert component for feedback. ## API -| Property | Description | Type | Default | Version | -| --- | --- | --- | --- | --- | -| action | The action of Alert | ReactNode | - | 4.9.0 | -| afterClose | Called when close animation is finished | () => void | - | | -| banner | Whether to show as banner | boolean | false | | -| closable | Whether Alert can be closed | boolean | - | | -| closeText | Close text to show | ReactNode | - | | -| closeIcon | Custom close icon | ReactNode | `` | 4.17.0 | -| description | Additional content of Alert | ReactNode | - | | -| icon | Custom icon, effective when `showIcon` is true | ReactNode | - | | -| message | Content of Alert | ReactNode | - | | -| showIcon | Whether to show icon | boolean | false, in `banner` mode default is true | | -| type | Type of Alert styles, options: `success`, `info`, `warning`, `error` | string | `info`, in `banner` mode default is `warning` | | -| onClose | Callback when Alert is closed | (e: MouseEvent) => void | - | | +| Property | Description | Type | Default | Version | +| ----------- | -------------------------------------------------------------------- | ----------------------- | --------------------------------------------- | ------- | +| action | The action of Alert | ReactNode | - | 4.9.0 | +| afterClose | Called when close animation is finished | () => void | - | | +| banner | Whether to show as banner | boolean | false | | +| closable | Whether Alert can be closed | boolean | - | | +| closeText | Close text to show | ReactNode | - | | +| closeIcon | Custom close icon | ReactNode | `` | 4.18.0 | +| description | Additional content of Alert | ReactNode | - | | +| icon | Custom icon, effective when `showIcon` is true | ReactNode | - | | +| message | Content of Alert | ReactNode | - | | +| showIcon | Whether to show icon | boolean | false, in `banner` mode default is true | | +| type | Type of Alert styles, options: `success`, `info`, `warning`, `error` | string | `info`, in `banner` mode default is `warning` | | +| onClose | Callback when Alert is closed | (e: MouseEvent) => void | - | | ### Alert.ErrorBoundary diff --git a/components/alert/index.zh-CN.md b/components/alert/index.zh-CN.md index ca8c164b04..6f5ada3200 100644 --- a/components/alert/index.zh-CN.md +++ b/components/alert/index.zh-CN.md @@ -34,24 +34,24 @@ group: ## API -| 参数 | 说明 | 类型 | 默认值 | 版本 | -| --- | --- | --- | --- | --- | -| action | 自定义操作项 | ReactNode | - | 4.9.0 | -| afterClose | 关闭动画结束后触发的回调函数 | () => void | - | | -| banner | 是否用作顶部公告 | boolean | false | | -| closable | 默认不显示关闭按钮 | boolean | - | | -| closeText | 自定义关闭按钮 | ReactNode | - | | -| closeIcon | 自定义关闭 Icon | ReactNode | `` | 4.17.0 | -| description | 警告提示的辅助性文字介绍 | ReactNode | - | | -| icon | 自定义图标,`showIcon` 为 true 时有效 | ReactNode | - | | -| message | 警告提示内容 | ReactNode | - | | -| showIcon | 是否显示辅助图标 | boolean | false,`banner` 模式下默认值为 true | | -| type | 指定警告提示的样式,有四种选择 `success`、`info`、`warning`、`error` | string | `info`,`banner` 模式下默认值为 `warning` | | -| onClose | 关闭时触发的回调函数 | (e: MouseEvent) => void | - | | +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| ----------- | -------------------------------------------------------------------- | ----------------------- | ----------------------------------------- | ------ | +| action | 自定义操作项 | ReactNode | - | 4.9.0 | +| afterClose | 关闭动画结束后触发的回调函数 | () => void | - | | +| banner | 是否用作顶部公告 | boolean | false | | +| closable | 默认不显示关闭按钮 | boolean | - | | +| closeText | 自定义关闭按钮 | ReactNode | - | | +| closeIcon | 自定义关闭 Icon | ReactNode | `` | 4.18.0 | +| description | 警告提示的辅助性文字介绍 | ReactNode | - | | +| icon | 自定义图标,`showIcon` 为 true 时有效 | ReactNode | - | | +| message | 警告提示内容 | ReactNode | - | | +| showIcon | 是否显示辅助图标 | boolean | false,`banner` 模式下默认值为 true | | +| type | 指定警告提示的样式,有四种选择 `success`、`info`、`warning`、`error` | string | `info`,`banner` 模式下默认值为 `warning` | | +| onClose | 关闭时触发的回调函数 | (e: MouseEvent) => void | - | | ### Alert.ErrorBoundary -| 参数 | 说明 | 类型 | 默认值 | 版本 | -| --- | --- | --- | --- | --- | -| description | 自定义错误内容,如果未指定会展示报错堆栈 | ReactNode | {{ error stack }} | | -| message | 自定义错误标题,如果未指定会展示原生报错信息 | ReactNode | {{ error }} | | +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| ----------- | -------------------------------------------- | --------- | ----------------- | ---- | +| description | 自定义错误内容,如果未指定会展示报错堆栈 | ReactNode | {{ error stack }} | | +| message | 自定义错误标题,如果未指定会展示原生报错信息 | ReactNode | {{ error }} | | diff --git a/components/alert/style/index.tsx b/components/alert/style/index.tsx index 904d8ca28a..afa1d391d7 100644 --- a/components/alert/style/index.tsx +++ b/components/alert/style/index.tsx @@ -7,6 +7,7 @@ export interface ComponentToken {} type AlertToken = FullToken<'Alert'> & { alertIconSizeLG: number; + alertPaddingHorizontal: number; }; const genAlertTypeStyle = ( @@ -36,10 +37,10 @@ export const genBaseStyle: GenerateStyle = (token: AlertToken): CSSO motionEaseInOutCirc, alertIconSizeLG, colorText, - paddingSM, - paddingXS, - paddingTmp, - paddingLG, + paddingContentVerticalSM, + alertPaddingHorizontal, + paddingMD, + paddingContentHorizontalLG, } = token; return { @@ -48,7 +49,7 @@ export const genBaseStyle: GenerateStyle = (token: AlertToken): CSSO position: 'relative', display: 'flex', alignItems: 'center', - padding: `${paddingXS}px ${paddingSM}px`, + padding: `${paddingContentVerticalSM}px ${alertPaddingHorizontal}px`, // Fixed horizontal padding here. wordWrap: 'break-word', borderRadius, @@ -95,8 +96,8 @@ export const genBaseStyle: GenerateStyle = (token: AlertToken): CSSO [`${componentCls}-with-description`]: { alignItems: 'flex-start', - paddingInline: paddingLG, - paddingBlock: paddingTmp, + paddingInline: paddingContentHorizontalLG, + paddingBlock: paddingMD, [`${componentCls}-icon`]: { marginInlineEnd: marginSM, @@ -232,6 +233,7 @@ export default genComponentStyleHook('Alert', token => { const alertToken = mergeToken(token, { alertIconSizeLG: fontSizeHeading3, + alertPaddingHorizontal: 12, // Fixed value here. }); return [genAlertStyle(alertToken)]; diff --git a/components/back-top/__tests__/index.test.tsx b/components/back-top/__tests__/index.test.tsx index 60a35804be..8328029294 100644 --- a/components/back-top/__tests__/index.test.tsx +++ b/components/back-top/__tests__/index.test.tsx @@ -2,13 +2,15 @@ import React from 'react'; import BackTop from '..'; import mountTest from '../../../tests/shared/mountTest'; import rtlTest from '../../../tests/shared/rtlTest'; -import { fireEvent, render, sleep } from '../../../tests/utils'; +import { fireEvent, render, waitFakeTimer } from '../../../tests/utils'; describe('BackTop', () => { mountTest(BackTop); rtlTest(BackTop); it('should scroll to top after click it', async () => { + jest.useFakeTimers(); + const { container } = render(); const scrollToSpy = jest.spyOn(window, 'scrollTo').mockImplementation((_, y) => { window.scrollY = y; @@ -18,9 +20,12 @@ describe('BackTop', () => { window.scrollTo(0, 400); expect(document.documentElement.scrollTop).toBe(400); fireEvent.click(container.querySelector('.ant-back-top')!); - await sleep(500); + await waitFakeTimer(); expect(document.documentElement.scrollTop).toBe(0); scrollToSpy.mockRestore(); + + jest.clearAllTimers(); + jest.useRealTimers(); }); it('support onClick', async () => { diff --git a/components/badge/utils.tsx b/components/badge/utils.tsx index ada1c6580c..2c9a500e88 100644 --- a/components/badge/utils.tsx +++ b/components/badge/utils.tsx @@ -2,5 +2,5 @@ import { PresetColorTypes } from '../_util/colors'; // eslint-disable-next-line import/prefer-default-export export function isPresetColor(color?: string): boolean { - return (PresetColorTypes as any[]).indexOf(color) !== -1; + return (PresetColorTypes as any[]).includes(color); } diff --git a/components/button/button.tsx b/components/button/button.tsx index 8d6ea8843f..04a5bbd785 100644 --- a/components/button/button.tsx +++ b/components/button/button.tsx @@ -8,7 +8,7 @@ import DisabledContext from '../config-provider/DisabledContext'; import type { SizeType } from '../config-provider/SizeContext'; import SizeContext from '../config-provider/SizeContext'; import { useCompactItemContext } from '../space/Compact'; -import { cloneElement } from '../_util/reactNode'; +import { cloneElement, isFragment } from '../_util/reactNode'; import { tuple } from '../_util/type'; import warning from '../_util/warning'; import Wave from '../_util/wave'; @@ -28,10 +28,6 @@ function isUnBorderedButtonType(type: ButtonType | undefined) { return type === 'text' || type === 'link'; } -function isReactFragment(node: React.ReactNode) { - return React.isValidElement(node) && node.type === React.Fragment; -} - // Insert one space between two chinese characters automatically. function insertSpace(child: React.ReactElement | string | number, needInserted: boolean) { // Check the child if is undefined or null. @@ -53,7 +49,7 @@ function insertSpace(child: React.ReactElement | string | number, needInserted: if (typeof child === 'string') { return isTwoCNChar(child) ? {child.split('').join(SPACE)} : {child}; } - if (isReactFragment(child)) { + if (isFragment(child)) { return {child}; } return child; diff --git a/components/button/style/index.tsx b/components/button/style/index.tsx index 74ea3acd2c..5db9af5623 100644 --- a/components/button/style/index.tsx +++ b/components/button/style/index.tsx @@ -10,6 +10,7 @@ export interface ComponentToken {} export interface ButtonToken extends FullToken<'Button'> { // FIXME: should be removed colorOutlineDefault: string; + buttonPaddingHorizontal: number; } // ============================== Shared ============================== @@ -344,7 +345,7 @@ const genSizeButtonStyle = (token: ButtonToken, sizePrefixCls: string = ''): CSS 0, (token.controlHeight - token.fontSize * token.lineHeight) / 2 - token.controlLineWidth, ); - const paddingHorizontal = token.padding - token.controlLineWidth; + const paddingHorizontal = token.buttonPaddingHorizontal - token.controlLineWidth; const iconOnlyCls = `${componentCls}-icon-only`; @@ -399,6 +400,7 @@ const genSizeSmallButtonStyle: GenerateStyle = token => { const smallToken = mergeToken(token, { controlHeight: token.controlHeightSM, padding: token.paddingXS, + buttonPaddingHorizontal: 8, // Fixed padding controlRadius: token.controlRadiusSM, }); @@ -417,10 +419,11 @@ const genSizeLargeButtonStyle: GenerateStyle = token => { // ============================== Export ============================== export default genComponentStyleHook('Button', token => { - const { controlTmpOutline } = token; + const { controlTmpOutline, paddingContentHorizontal } = token; const buttonToken = mergeToken(token, { colorOutlineDefault: controlTmpOutline, + buttonPaddingHorizontal: paddingContentHorizontal, }); return [ diff --git a/components/card/style/index.tsx b/components/card/style/index.tsx index e126b2d453..bc39e73ed1 100644 --- a/components/card/style/index.tsx +++ b/components/card/style/index.tsx @@ -4,10 +4,15 @@ import type { FullToken, GenerateStyle } from '../../theme'; import { genComponentStyleHook, mergeToken } from '../../theme'; import { clearFix, resetComponent } from '../../style'; +export interface ComponentToken {} + interface CardToken extends FullToken<'Card'> { + cardHeaderHeight: number; + cardHeaderHeightSM: number; cardShadow: string; cardHeadHeight: number; cardHeadPadding: number; + cardPaddingSM: number; cardPaddingBase: number; cardHeadTabsMarginBottom: number; cardInnerHeadPadding: number; @@ -236,9 +241,9 @@ const genCardStyle: GenerateStyle = (token): CSSObject => { cardShadow, cardHeadHeight, cardHeadPadding, - cardPaddingBase, colorBorderSecondary, boxShadow, + cardPaddingBase, } = token; return { @@ -345,15 +350,14 @@ const genCardStyle: GenerateStyle = (token): CSSObject => { // ============================== Size ============================== const genCardSizeStyle: GenerateStyle = (token): CSSObject => { - const { componentCls, cardPaddingBase, cardHeadPadding } = token; - const cardPaddingBaseSM = cardPaddingBase / 2; - const cardHeadPaddingSM = cardHeadPadding / 2; + const { componentCls, cardPaddingSM, fontSize, lineHeight, cardHeaderHeightSM } = token; + const cardHeadPaddingSM = (cardHeaderHeightSM - fontSize * lineHeight) / 2; return { [`${componentCls}-small`]: { [`> ${componentCls}-head`]: { - minHeight: cardHeadPaddingSM * 2 + token.fontSize, - padding: `0 ${cardPaddingBaseSM}px`, + minHeight: cardHeaderHeightSM, + padding: `0 ${cardPaddingSM}px`, fontSize: token.fontSize, [`> ${componentCls}-head-wrapper`]: { @@ -369,7 +373,7 @@ const genCardSizeStyle: GenerateStyle = (token): CSSObject => { }, [`> ${componentCls}-body`]: { - padding: cardPaddingBaseSM, + padding: cardPaddingSM, }, }, }; @@ -377,17 +381,17 @@ const genCardSizeStyle: GenerateStyle = (token): CSSObject => { // ============================== Export ============================== export default genComponentStyleHook('Card', token => { - const cardHeadPadding = token.padding; - const cardToken = mergeToken(token, { cardShadow: token.boxShadowCard, - cardHeadHeight: token.fontSizeLG + cardHeadPadding * 2, - cardHeadPadding, + cardHeaderHeight: token.fontSizeLG * token.lineHeightLG + token.padding * 2, + cardHeaderHeightSM: token.fontSize * token.lineHeight + token.paddingXS * 2, + cardHeadPadding: token.padding, cardPaddingBase: token.paddingLG, cardHeadTabsMarginBottom: -token.padding - token.lineWidth, cardInnerHeadPadding: token.paddingSM, cardActionsLiMargin: `${token.paddingSM}px 0`, cardActionsIconSize: token.fontSize, + cardPaddingSM: 12, // Fixed padding. }); return [ diff --git a/components/carousel/__tests__/index.test.tsx b/components/carousel/__tests__/index.test.tsx index 85e85fc458..3865f8f94f 100644 --- a/components/carousel/__tests__/index.test.tsx +++ b/components/carousel/__tests__/index.test.tsx @@ -3,7 +3,7 @@ import type { CarouselRef } from '..'; import Carousel from '..'; import mountTest from '../../../tests/shared/mountTest'; import rtlTest from '../../../tests/shared/rtlTest'; -import { sleep, render, act } from '../../../tests/utils'; +import { waitFakeTimer, render } from '../../../tests/utils'; describe('Carousel', () => { mountTest(Carousel); @@ -17,14 +17,6 @@ describe('Carousel', () => { jest.useRealTimers(); }); - function runAllTimersWithAct(times = 1) { - for (let i = 0; i < times; i++) { - act(() => { - jest.runAllTimers(); - }); - } - } - it('should has innerSlider', () => { const ref = React.createRef(); render( @@ -51,16 +43,16 @@ describe('Carousel', () => { expect(typeof goTo).toBe('function'); expect(ref.current?.innerSlider.state.currentSlide).toBe(0); ref.current?.goTo(2); - runAllTimersWithAct(1); + await waitFakeTimer(); expect(ref.current?.innerSlider.state.currentSlide).toBe(2); // wait for animation to be finished - runAllTimersWithAct(2); + await waitFakeTimer(); ref.current?.prev(); - runAllTimersWithAct(1); + await waitFakeTimer(); expect(ref.current?.innerSlider.state.currentSlide).toBe(1); - runAllTimersWithAct(2); + await waitFakeTimer(); ref.current?.next(); - runAllTimersWithAct(1); + await waitFakeTimer(); expect(ref.current?.innerSlider.state.currentSlide).toBe(2); }); @@ -77,7 +69,7 @@ describe('Carousel', () => { const spy = jest.spyOn(ref.current?.innerSlider, 'autoPlay'); window.resizeTo(1000, window.outerHeight); expect(spy).not.toHaveBeenCalled(); - await sleep(500); + await waitFakeTimer(); expect(spy).toHaveBeenCalled(); }); diff --git a/components/checkbox/Checkbox.tsx b/components/checkbox/Checkbox.tsx index 4e9d9dae03..7360fc820a 100644 --- a/components/checkbox/Checkbox.tsx +++ b/components/checkbox/Checkbox.tsx @@ -106,7 +106,7 @@ const InternalCheckbox: React.ForwardRefRenderFunction registeredValues.indexOf(val) !== -1) + .filter(val => registeredValues.includes(val)) .sort((a, b) => { const indexA = opts.findIndex(opt => opt.value === a); const indexB = opts.findIndex(opt => opt.value === b); @@ -126,7 +126,7 @@ const InternalCheckboxGroup: React.ForwardRefRenderFunction { @@ -66,6 +66,7 @@ describe('Collapse', () => { }); it('could be expand and collapse', async () => { + jest.useFakeTimers(); const { container } = render( @@ -77,10 +78,11 @@ describe('Collapse', () => { container.querySelector('.ant-collapse-item')?.classList.contains('ant-collapse-item-active'), ).toBe(false); fireEvent.click(container.querySelector('.ant-collapse-header')!); - await sleep(400); + await waitFakeTimer(); expect( container.querySelector('.ant-collapse-item')?.classList.contains('ant-collapse-item-active'), ).toBe(true); + jest.useRealTimers(); }); it('could override default openMotion', () => { diff --git a/components/collapse/style/index.tsx b/components/collapse/style/index.tsx index c06b87ad6a..11ee4f5ccd 100644 --- a/components/collapse/style/index.tsx +++ b/components/collapse/style/index.tsx @@ -3,19 +3,22 @@ import type { FullToken, GenerateStyle } from '../../theme'; import { genComponentStyleHook, mergeToken } from '../../theme'; import { resetComponent, resetIcon } from '../../style'; +export interface ComponentToken {} + type CollapseToken = FullToken<'Collapse'> & { collapseContentBg: string; - collapseContentPadding: number; collapseHeaderBg: string; collapseHeaderPadding: string; collapsePanelBorderRadius: number; + collapseContentPaddingHorizontal: number; }; export const genBaseStyle: GenerateStyle = token => { const { componentCls, collapseContentBg, - collapseContentPadding, + padding, + collapseContentPaddingHorizontal, collapseHeaderBg, collapseHeaderPadding, collapsePanelBorderRadius, @@ -130,7 +133,7 @@ export const genBaseStyle: GenerateStyle = token => { borderTop: borderBase, [`& > ${componentCls}-content-box`]: { - padding: collapseContentPadding, + padding: `${padding}px ${collapseContentPaddingHorizontal}px`, }, [`&-hidden`]: { @@ -255,10 +258,10 @@ const genGhostStyle: GenerateStyle = token => { export default genComponentStyleHook('Collapse', token => { const collapseToken = mergeToken(token, { collapseContentBg: token.colorBgContainer, - collapseContentPadding: token.padding, collapseHeaderBg: token.colorFillAlter, collapseHeaderPadding: `${token.paddingSM}px ${token.padding}px`, collapsePanelBorderRadius: token.radiusLG, + collapseContentPaddingHorizontal: 16, // Fixed value }); return [ diff --git a/components/config-provider/__tests__/theme.test.tsx b/components/config-provider/__tests__/theme.test.tsx index 609f9ae827..3a4489625c 100644 --- a/components/config-provider/__tests__/theme.test.tsx +++ b/components/config-provider/__tests__/theme.test.tsx @@ -8,7 +8,8 @@ import { useToken } from '../../theme'; import theme from '../../theme/export'; import { resetWarned } from '../../_util/warning'; -const { defaultAlgorithm, darkAlgorithm, defaultAlgorithmV4, darkAlgorithmV4 } = theme; +const { defaultAlgorithm, darkAlgorithm, defaultAlgorithmV4, darkAlgorithmV4, compactAlgorithm } = + theme; let mockCanUseDom = true; @@ -102,6 +103,33 @@ describe('ConfigProvider.Theme', () => { expect(tokenRef?.colorPrimaryText).toBe('#177ddc'); }); + it('compactAlgorithm should work', () => { + let tokenRef: any; + const Demo = () => { + const [, token] = useToken(); + tokenRef = token; + return null; + }; + render( + + + , + ); + expect(tokenRef).toEqual( + expect.objectContaining({ + sizeXXL: 48, + sizeXL: 32, + sizeLG: 16, + sizeMD: 16, + sizeMS: 12, + size: 8, + sizeSM: 8, + sizeXS: 4, + sizeXXS: 4, + }), + ); + }); + it('should support algorithm array', () => { let tokenRef: any; const Demo = () => { diff --git a/components/config-provider/index.en-US.md b/components/config-provider/index.en-US.md index 2602d0803f..a6b12f77f5 100644 --- a/components/config-provider/index.en-US.md +++ b/components/config-provider/index.en-US.md @@ -45,25 +45,25 @@ Some components use dynamic style to support wave effect. You can config `csp` p ## API -| Property | Description | Type | Default | Version | -| --- | --- | --- | --- | --- | -| autoInsertSpaceInButton | Set false to remove space between 2 chinese characters on Button | boolean | true | | -| componentDisabled | Config antd component `disabled` | boolean | - | 4.21.0 | -| componentSize | Config antd component size | `small` \| `middle` \| `large` | - | | -| csp | Set [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) config | { nonce: string } | - | | -| direction | Set direction of layout. See [demo](#components-config-provider-demo-direction) | `ltr` \| `rtl` | `ltr` | | -| dropdownMatchSelectWidth | Determine whether the dropdown menu and the select input are the same width. Default set `min-width` same as input. Will ignore when value less than select width. `false` will disable virtual scroll | boolean \| number | - | 4.3.0 | -| form | Set Form common props | { validateMessages?: [ValidateMessages](/components/form/#validateMessages), requiredMark?: boolean \| `optional` } | - | requiredMark: 4.8.0 | -| getPopupContainer | To set the container of the popup element. The default is to create a `div` element in `body` | function(triggerNode) | () => document.body | | -| getTargetContainer | Config Affix, Anchor scroll target container | () => HTMLElement | () => window | 4.2.0 | -| iconPrefixCls | Set icon prefix className (cooperated with [@iconfont-css-prefix](https://github.com/ant-design/ant-design/blob/d943b85a523bdf181dabc12c928226f3b4b893de/components/style/themes/default.less#L106)) | string | `anticon` | 4.11.0 | -| input | Set Input common props | { autoComplete?: string } | - | 4.2.0 | -| locale | Language package setting, you can find the packages in [antd/es/locale](http://unpkg.com/antd/es/locale/) | object | - | | -| pageHeader | Unify the ghost of PageHeader, ref [PageHeader](/components/page-header) | { ghost: boolean } | true | | -| prefixCls | Set prefix className (cooperated with [@ant-prefix](https://github.com/ant-design/ant-design/blob/2c6c789e3a9356f96c47aea0083f5a15538315cf/components/style/themes/default.less#L7)) | string | `ant` | | -| renderEmpty | Set empty content of components. Ref [Empty](/components/empty/) | function(componentName: string): ReactNode | - | | -| space | Set Space `size`, ref [Space](/components/space) | { size: `small` \| `middle` \| `large` \| `number` } | - | 4.1.0 | -| virtual | Disable virtual scroll when set to `false` | boolean | - | 4.3.0 | +| Property | Description | Type | Default | Version | +| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------- | ------------------- | ------------------- | +| autoInsertSpaceInButton | Set false to remove space between 2 chinese characters on Button | boolean | true | | +| componentDisabled | Config antd component `disabled` | boolean | - | 4.21.0 | +| componentSize | Config antd component size | `small` \| `middle` \| `large` | - | | +| csp | Set [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) config | { nonce: string } | - | | +| direction | Set direction of layout. See [demo](#components-config-provider-demo-direction) | `ltr` \| `rtl` | `ltr` | | +| dropdownMatchSelectWidth | Determine whether the dropdown menu and the select input are the same width. Default set `min-width` same as input. Will ignore when value less than select width. `false` will disable virtual scroll | boolean \| number | - | 4.3.0 | +| form | Set Form common props | { validateMessages?: [ValidateMessages](/components/form/#validateMessages), requiredMark?: boolean \| `optional` } | - | requiredMark: 4.8.0 | +| getPopupContainer | To set the container of the popup element. The default is to create a `div` element in `body` | function(triggerNode) | () => document.body | | +| getTargetContainer | Config Affix, Anchor scroll target container | () => HTMLElement | () => window | 4.2.0 | +| iconPrefixCls | Set icon prefix className (cooperated with [@iconfont-css-prefix](https://github.com/ant-design/ant-design/blob/d943b85a523bdf181dabc12c928226f3b4b893de/components/style/themes/default.less#L106)) | string | `anticon` | 4.11.0 | +| input | Set Input common props | { autoComplete?: string } | - | 4.2.0 | +| locale | Language package setting, you can find the packages in [antd/locale](http://unpkg.com/antd/locale/) | object | - | | +| pageHeader | Unify the ghost of PageHeader, ref [PageHeader](/components/page-header) | { ghost: boolean } | true | | +| prefixCls | Set prefix className (cooperated with [@ant-prefix](https://github.com/ant-design/ant-design/blob/2c6c789e3a9356f96c47aea0083f5a15538315cf/components/style/themes/default.less#L7)) | string | `ant` | | +| renderEmpty | Set empty content of components. Ref [Empty](/components/empty/) | function(componentName: string): ReactNode | - | | +| space | Set Space `size`, ref [Space](/components/space) | { size: `small` \| `middle` \| `large` \| `number` } | - | 4.1.0 | +| virtual | Disable virtual scroll when set to `false` | boolean | - | 4.3.0 | ### ConfigProvider.config() `4.13.0+` diff --git a/components/config-provider/index.tsx b/components/config-provider/index.tsx index f8e41ce374..15deb64ef8 100644 --- a/components/config-provider/index.tsx +++ b/components/config-provider/index.tsx @@ -8,7 +8,7 @@ import type { RequiredMark } from '../form/Form'; import type { Locale } from '../locale-provider'; import LocaleProvider, { ANT_MARK } from '../locale-provider'; import LocaleReceiver from '../locale-provider/LocaleReceiver'; -import defaultLocale from '../locale/default'; +import defaultLocale from '../locale/en_US'; import { DesignTokenContext } from '../theme'; import defaultSeedToken from '../theme/themes/seed'; import type { ConfigConsumerProps, CSPConfig, DirectionType, Theme, ThemeConfig } from './context'; diff --git a/components/config-provider/index.zh-CN.md b/components/config-provider/index.zh-CN.md index 6b1fa53d4c..eff92f855e 100644 --- a/components/config-provider/index.zh-CN.md +++ b/components/config-provider/index.zh-CN.md @@ -46,25 +46,25 @@ export default () => ( ## API -| 参数 | 说明 | 类型 | 默认值 | 版本 | -| --- | --- | --- | --- | --- | -| autoInsertSpaceInButton | 设置为 `false` 时,移除按钮中 2 个汉字之间的空格 | boolean | true | | -| componentDisabled | 设置 antd 组件禁用状态 | boolean | - | 4.21.0 | -| componentSize | 设置 antd 组件大小 | `small` \| `middle` \| `large` | - | | -| csp | 设置 [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) 配置 | { nonce: string } | - | | -| direction | 设置文本展示方向。 [示例](#components-config-provider-demo-direction) | `ltr` \| `rtl` | `ltr` | | -| dropdownMatchSelectWidth | 下拉菜单和选择器同宽。默认将设置 `min-width`,当值小于选择框宽度时会被忽略。`false` 时会关闭虚拟滚动 | boolean \| number | - | 4.3.0 | -| form | 设置 Form 组件的通用属性 | { validateMessages?: [ValidateMessages](/components/form/#validateMessages), requiredMark?: boolean \| `optional`, colon?: boolean} | - | requiredMark: 4.8.0; colon: 4.18.0 | -| getPopupContainer | 弹出框(Select, Tooltip, Menu 等等)渲染父节点,默认渲染到 body 上。 | function(triggerNode) | () => document.body | | -| getTargetContainer | 配置 Affix、Anchor 滚动监听容器。 | () => HTMLElement | () => window | 4.2.0 | -| iconPrefixCls | 设置图标统一样式前缀。注意:需要配合 `less` 变量 [@iconfont-css-prefix](https://github.com/ant-design/ant-design/blob/d943b85a523bdf181dabc12c928226f3b4b893de/components/style/themes/default.less#L106) 使用 | string | `anticon` | 4.11.0 | -| input | 设置 Input 组件的通用属性 | { autoComplete?: string } | - | 4.2.0 | -| locale | 语言包配置,语言包可到 [antd/es/locale](http://unpkg.com/antd/es/locale/) 目录下寻找 | object | - | | -| pageHeader | 统一设置 PageHeader 的 ghost,参考 [PageHeader](/components/page-header) | { ghost: boolean } | true | | -| prefixCls | 设置统一样式前缀。注意:需要配合 `less` 变量 [@ant-prefix](https://github.com/ant-design/ant-design/blob/2c6c789e3a9356f96c47aea0083f5a15538315cf/components/style/themes/default.less#L7) 使用 | string | `ant` | | -| renderEmpty | 自定义组件空状态。参考 [空状态](/components/empty/) | function(componentName: string): ReactNode | - | | -| space | 设置 Space 的 `size`,参考 [Space](/components/space) | { size: `small` \| `middle` \| `large` \| `number` } | - | 4.1.0 | -| virtual | 设置 `false` 时关闭虚拟滚动 | boolean | - | 4.3.0 | +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | ------------------- | ---------------------------------- | +| autoInsertSpaceInButton | 设置为 `false` 时,移除按钮中 2 个汉字之间的空格 | boolean | true | | +| componentDisabled | 设置 antd 组件禁用状态 | boolean | - | 4.21.0 | +| componentSize | 设置 antd 组件大小 | `small` \| `middle` \| `large` | - | | +| csp | 设置 [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) 配置 | { nonce: string } | - | | +| direction | 设置文本展示方向。 [示例](#components-config-provider-demo-direction) | `ltr` \| `rtl` | `ltr` | | +| dropdownMatchSelectWidth | 下拉菜单和选择器同宽。默认将设置 `min-width`,当值小于选择框宽度时会被忽略。`false` 时会关闭虚拟滚动 | boolean \| number | - | 4.3.0 | +| form | 设置 Form 组件的通用属性 | { validateMessages?: [ValidateMessages](/components/form/#validateMessages), requiredMark?: boolean \| `optional`, colon?: boolean} | - | requiredMark: 4.8.0; colon: 4.18.0 | +| getPopupContainer | 弹出框(Select, Tooltip, Menu 等等)渲染父节点,默认渲染到 body 上。 | function(triggerNode) | () => document.body | | +| getTargetContainer | 配置 Affix、Anchor 滚动监听容器。 | () => HTMLElement | () => window | 4.2.0 | +| iconPrefixCls | 设置图标统一样式前缀。注意:需要配合 `less` 变量 [@iconfont-css-prefix](https://github.com/ant-design/ant-design/blob/d943b85a523bdf181dabc12c928226f3b4b893de/components/style/themes/default.less#L106) 使用 | string | `anticon` | 4.11.0 | +| input | 设置 Input 组件的通用属性 | { autoComplete?: string } | - | 4.2.0 | +| locale | 语言包配置,语言包可到 [antd/locale](http://unpkg.com/antd/locale/) 目录下寻找 | object | - | | +| pageHeader | 统一设置 PageHeader 的 ghost,参考 [PageHeader](/components/page-header) | { ghost: boolean } | true | | +| prefixCls | 设置统一样式前缀。注意:需要配合 `less` 变量 [@ant-prefix](https://github.com/ant-design/ant-design/blob/2c6c789e3a9356f96c47aea0083f5a15538315cf/components/style/themes/default.less#L7) 使用 | string | `ant` | | +| renderEmpty | 自定义组件空状态。参考 [空状态](/components/empty/) | function(componentName: string): ReactNode | - | | +| space | 设置 Space 的 `size`,参考 [Space](/components/space) | { size: `small` \| `middle` \| `large` \| `number` } | - | 4.1.0 | +| virtual | 设置 `false` 时关闭虚拟滚动 | boolean | - | 4.3.0 | ### ConfigProvider.config() `4.13.0+` diff --git a/components/date-picker/index.en-US.md b/components/date-picker/index.en-US.md index 05fdd74ad2..13d60ccca0 100644 --- a/components/date-picker/index.en-US.md +++ b/components/date-picker/index.en-US.md @@ -33,7 +33,7 @@ By clicking the input box, you can select a date from a popup calendar. Controlled Panels Customized Range Picker Suffix -_InternalPanelDoNotUseOrYouWillBeFired +\_InternalPanelDoNotUseOrYouWillBeFired ## API @@ -63,7 +63,7 @@ import locale from 'antd/es/date-picker/locale/zh_CN'; // The default locale is en-US, if you want to use other locale, just set locale in entry file globally. import dayjs from 'dayjs'; import 'dayjs/locale/zh-cn'; -import locale from 'antd/es/locale/zh_CN'; +import locale from 'antd/locale/zh_CN'; @@ -74,36 +74,36 @@ import locale from 'antd/es/locale/zh_CN'; The following APIs are shared by DatePicker, RangePicker. -| Property | Description | Type | Default | Version | -| --- | --- | --- | --- | --- | -| allowClear | Whether to show clear button | boolean | true | | -| autoFocus | If get focus when component mounted | boolean | false | | -| bordered | Whether has border style | boolean | true | | -| className | The picker className | string | - | | -| dateRender | Custom rendering function for date cells | function(currentDate: dayjs, today: dayjs) => React.ReactNode | - | | -| disabled | Determine whether the DatePicker is disabled | boolean | false | | -| disabledDate | Specify the date that cannot be selected | (currentDate: dayjs) => boolean | - | | -| popupClassName | To customize the className of the popup calendar | string | - | 4.23.0 | -| getPopupContainer | To set the container of the floating layer, while the default is to create a `div` element in `body` | function(trigger) | - | | -| inputReadOnly | Set the `readonly` attribute of the input tag (avoids virtual keyboard on touch devices) | boolean | false | | -| locale | Localization configuration | object | [default](https://github.com/ant-design/ant-design/blob/master/components/date-picker/locale/example.json) | | -| mode | The picker panel mode( [Cannot select year or month anymore?](/docs/react/faq#When-set-mode-to-DatePicker/RangePicker,-cannot-select-year-or-month-anymore?) ) | `time` \| `date` \| `month` \| `year` \| `decade` | - | | -| nextIcon | The custom next icon | ReactNode | - | 4.17.0 | -| open | The open state of picker | boolean | - | | -| panelRender | Customize panel render | (panelNode) => ReactNode | - | 4.5.0 | -| picker | Set picker type | `date` \| `week` \| `month` \| `quarter` \| `year` | `date` | `quarter`: 4.1.0 | -| placeholder | The placeholder of date input | string \| \[string,string] | - | | -| placement | The position where the selection box pops up | `bottomLeft` `bottomRight` `topLeft` `topRight` | bottomLeft | | -| popupStyle | To customize the style of the popup calendar | CSSProperties | {} | | -| prevIcon | The custom prev icon | ReactNode | - | 4.17.0 | -| size | To determine the size of the input box, the height of `large` and `small`, are 40px and 24px respectively, while default size is 32px | `large` \| `middle` \| `small` | - | | -| status | Set validation status | 'error' \| 'warning' | - | 4.19.0 | -| style | To customize the style of the input box | CSSProperties | {} | | -| suffixIcon | The custom suffix icon | ReactNode | - | | -| superNextIcon | The custom super next icon | ReactNode | - | 4.17.0 | -| superPrevIcon | The custom super prev icon | ReactNode | - | 4.17.0 | -| onOpenChange | Callback function, can be executed whether the popup calendar is popped up or closed | function(open) | - | | -| onPanelChange | Callback when picker panel mode is changed | function(value, mode) | - | | +| Property | Description | Type | Default | Version | +| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | ---------------- | +| allowClear | Whether to show clear button | boolean | true | | +| autoFocus | If get focus when component mounted | boolean | false | | +| bordered | Whether has border style | boolean | true | | +| className | The picker className | string | - | | +| dateRender | Custom rendering function for date cells | function(currentDate: dayjs, today: dayjs) => React.ReactNode | - | | +| disabled | Determine whether the DatePicker is disabled | boolean | false | | +| disabledDate | Specify the date that cannot be selected | (currentDate: dayjs) => boolean | - | | +| popupClassName | To customize the className of the popup calendar | string | - | 4.23.0 | +| getPopupContainer | To set the container of the floating layer, while the default is to create a `div` element in `body` | function(trigger) | - | | +| inputReadOnly | Set the `readonly` attribute of the input tag (avoids virtual keyboard on touch devices) | boolean | false | | +| locale | Localization configuration | object | [default](https://github.com/ant-design/ant-design/blob/master/components/date-picker/locale/example.json) | | +| mode | The picker panel mode( [Cannot select year or month anymore?](/docs/react/faq#When-set-mode-to-DatePicker/RangePicker,-cannot-select-year-or-month-anymore?) ) | `time` \| `date` \| `month` \| `year` \| `decade` | - | | +| nextIcon | The custom next icon | ReactNode | - | 4.17.0 | +| open | The open state of picker | boolean | - | | +| panelRender | Customize panel render | (panelNode) => ReactNode | - | 4.5.0 | +| picker | Set picker type | `date` \| `week` \| `month` \| `quarter` \| `year` | `date` | `quarter`: 4.1.0 | +| placeholder | The placeholder of date input | string \| \[string,string] | - | | +| placement | The position where the selection box pops up | `bottomLeft` `bottomRight` `topLeft` `topRight` | bottomLeft | | +| popupStyle | To customize the style of the popup calendar | CSSProperties | {} | | +| prevIcon | The custom prev icon | ReactNode | - | 4.17.0 | +| size | To determine the size of the input box, the height of `large` and `small`, are 40px and 24px respectively, while default size is 32px | `large` \| `middle` \| `small` | - | | +| status | Set validation status | 'error' \| 'warning' | - | 4.19.0 | +| style | To customize the style of the input box | CSSProperties | {} | | +| suffixIcon | The custom suffix icon | ReactNode | - | | +| superNextIcon | The custom super next icon | ReactNode | - | 4.17.0 | +| superPrevIcon | The custom super prev icon | ReactNode | - | 4.17.0 | +| onOpenChange | Callback function, can be executed whether the popup calendar is popped up or closed | function(open) | - | | +| onPanelChange | Callback when picker panel mode is changed | function(value, mode) | - | | ### Common Methods @@ -114,88 +114,88 @@ The following APIs are shared by DatePicker, RangePicker. ### DatePicker -| Property | Description | Type | Default | Version | -| --- | --- | --- | --- | --- | -| defaultPickerValue | To set default picker date | [dayjs](https://day.js.org/) | - | | -| defaultValue | To set default date, if start time or end time is null or undefined, the date range will be an open interval | [dayjs](https://day.js.org/) | - | | -| disabledTime | To specify the time that cannot be selected | function(date) | - | | -| format | To set the date format, refer to [dayjs](https://day.js.org/). When an array is provided, all values are used for parsing and first value is used for formatting, support [Custom Format](#components-date-picker-demo-format) | string \| (value: dayjs) => string \| (string \| (value: dayjs) => string)\[] | `YYYY-MM-DD` | | -| renderExtraFooter | Render extra footer in panel | (mode) => React.ReactNode | - | | -| showNow | Whether to show 'Now' button on panel when `showTime` is set | boolean | - | 4.4.0 | -| showTime | To provide an additional time selection | object \| boolean | [TimePicker Options](/components/time-picker/#API) | | -| showTime.defaultValue | To set default time of selected date, [demo](#components-date-picker-demo-disabled-date) | [dayjs](https://day.js.org/) | dayjs() | | -| showToday | Whether to show `Today` button | boolean | true | | -| value | To set date | [dayjs](https://day.js.org/) | - | | -| onChange | Callback function, can be executed when the selected time is changing | function(date: dayjs, dateString: string) | - | | -| onOk | Callback when click ok button | function() | - | | -| onPanelChange | Callback function for panel changing | function(value, mode) | - | | +| Property | Description | Type | Default | Version | +| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------- | -------------------------------------------------- | ------- | +| defaultPickerValue | To set default picker date | [dayjs](https://day.js.org/) | - | | +| defaultValue | To set default date, if start time or end time is null or undefined, the date range will be an open interval | [dayjs](https://day.js.org/) | - | | +| disabledTime | To specify the time that cannot be selected | function(date) | - | | +| format | To set the date format, refer to [dayjs](https://day.js.org/). When an array is provided, all values are used for parsing and first value is used for formatting, support [Custom Format](#components-date-picker-demo-format) | string \| (value: dayjs) => string \| (string \| (value: dayjs) => string)\[] | `YYYY-MM-DD` | | +| renderExtraFooter | Render extra footer in panel | (mode) => React.ReactNode | - | | +| showNow | Whether to show 'Now' button on panel when `showTime` is set | boolean | - | 4.4.0 | +| showTime | To provide an additional time selection | object \| boolean | [TimePicker Options](/components/time-picker/#API) | | +| showTime.defaultValue | To set default time of selected date, [demo](#components-date-picker-demo-disabled-date) | [dayjs](https://day.js.org/) | dayjs() | | +| showToday | Whether to show `Today` button | boolean | true | | +| value | To set date | [dayjs](https://day.js.org/) | - | | +| onChange | Callback function, can be executed when the selected time is changing | function(date: dayjs, dateString: string) | - | | +| onOk | Callback when click ok button | function() | - | | +| onPanelChange | Callback function for panel changing | function(value, mode) | - | | ### DatePicker\[picker=year] -| Property | Description | Type | Default | Version | -| --- | --- | --- | --- | --- | -| defaultPickerValue | To set default picker date | [dayjs](https://day.js.org/) | - | | -| defaultValue | To set default date | [dayjs](https://day.js.org/) | - | | -| format | To set the date format, refer to [dayjs](https://day.js.org/) | string | `YYYY` | | -| renderExtraFooter | Render extra footer in panel | () => React.ReactNode | - | | -| value | To set date | [dayjs](https://day.js.org/) | - | | -| onChange | Callback function, can be executed when the selected time is changing | function(date: dayjs, dateString: string) | - | | +| Property | Description | Type | Default | Version | +| ------------------ | --------------------------------------------------------------------- | ----------------------------------------- | ------- | ------- | +| defaultPickerValue | To set default picker date | [dayjs](https://day.js.org/) | - | | +| defaultValue | To set default date | [dayjs](https://day.js.org/) | - | | +| format | To set the date format, refer to [dayjs](https://day.js.org/) | string | `YYYY` | | +| renderExtraFooter | Render extra footer in panel | () => React.ReactNode | - | | +| value | To set date | [dayjs](https://day.js.org/) | - | | +| onChange | Callback function, can be executed when the selected time is changing | function(date: dayjs, dateString: string) | - | | ### DatePicker\[picker=quarter] Added in `4.1.0`. -| Property | Description | Type | Default | Version | -| --- | --- | --- | --- | --- | -| defaultPickerValue | To set default picker date | [dayjs](https://day.js.org/) | - | | -| defaultValue | To set default date | [dayjs](https://day.js.org/) | - | | -| format | To set the date format, refer to [dayjs](https://day.js.org/) | string | `YYYY-\QQ` | | -| renderExtraFooter | Render extra footer in panel | () => React.ReactNode | - | | -| value | To set date | [dayjs](https://day.js.org/) | - | | -| onChange | Callback function, can be executed when the selected time is changing | function(date: dayjs, dateString: string) | - | | +| Property | Description | Type | Default | Version | +| ------------------ | --------------------------------------------------------------------- | ----------------------------------------- | ---------- | ------- | +| defaultPickerValue | To set default picker date | [dayjs](https://day.js.org/) | - | | +| defaultValue | To set default date | [dayjs](https://day.js.org/) | - | | +| format | To set the date format, refer to [dayjs](https://day.js.org/) | string | `YYYY-\QQ` | | +| renderExtraFooter | Render extra footer in panel | () => React.ReactNode | - | | +| value | To set date | [dayjs](https://day.js.org/) | - | | +| onChange | Callback function, can be executed when the selected time is changing | function(date: dayjs, dateString: string) | - | | ### DatePicker\[picker=month] -| Property | Description | Type | Default | Version | -| --- | --- | --- | --- | --- | -| defaultPickerValue | To set default picker date | [dayjs](https://day.js.org/) | - | | -| defaultValue | To set default date | [dayjs](https://day.js.org/) | - | | -| format | To set the date format, refer to [dayjs](https://day.js.org/) | string | `YYYY-MM` | | -| monthCellRender | Custom month cell content render method | function(date, locale): ReactNode | - | | -| renderExtraFooter | Render extra footer in panel | () => React.ReactNode | - | | -| value | To set date | [dayjs](https://day.js.org/) | - | | -| onChange | Callback function, can be executed when the selected time is changing | function(date: dayjs, dateString: string) | - | | +| Property | Description | Type | Default | Version | +| ------------------ | --------------------------------------------------------------------- | ----------------------------------------- | --------- | ------- | +| defaultPickerValue | To set default picker date | [dayjs](https://day.js.org/) | - | | +| defaultValue | To set default date | [dayjs](https://day.js.org/) | - | | +| format | To set the date format, refer to [dayjs](https://day.js.org/) | string | `YYYY-MM` | | +| monthCellRender | Custom month cell content render method | function(date, locale): ReactNode | - | | +| renderExtraFooter | Render extra footer in panel | () => React.ReactNode | - | | +| value | To set date | [dayjs](https://day.js.org/) | - | | +| onChange | Callback function, can be executed when the selected time is changing | function(date: dayjs, dateString: string) | - | | ### DatePicker\[picker=week] -| Property | Description | Type | Default | Version | -| --- | --- | --- | --- | --- | -| defaultPickerValue | To set default picker date | [dayjs](https://day.js.org/) | - | | -| defaultValue | To set default date | [dayjs](https://day.js.org/) | - | | -| format | To set the date format, refer to [dayjs](https://day.js.org/) | string | `YYYY-wo` | | -| renderExtraFooter | Render extra footer in panel | (mode) => React.ReactNode | - | | -| value | To set date | [dayjs](https://day.js.org/) | - | | -| onChange | Callback function, can be executed when the selected time is changing | function(date: dayjs, dateString: string) | - | | +| Property | Description | Type | Default | Version | +| ------------------ | --------------------------------------------------------------------- | ----------------------------------------- | --------- | ------- | +| defaultPickerValue | To set default picker date | [dayjs](https://day.js.org/) | - | | +| defaultValue | To set default date | [dayjs](https://day.js.org/) | - | | +| format | To set the date format, refer to [dayjs](https://day.js.org/) | string | `YYYY-wo` | | +| renderExtraFooter | Render extra footer in panel | (mode) => React.ReactNode | - | | +| value | To set date | [dayjs](https://day.js.org/) | - | | +| onChange | Callback function, can be executed when the selected time is changing | function(date: dayjs, dateString: string) | - | | ### RangePicker -| Property | Description | Type | Default | Version | -| --- | --- | --- | --- | --- | -| allowEmpty | Allow start or end input leave empty | \[boolean, boolean] | \[false, false] | | -| dateRender | Customize date cell. `info` argument is added in 4.3.0 | function(currentDate: dayjs, today: dayjs, info: { range: `start` \| `end` }) => React.ReactNode | - | | -| defaultPickerValue | To set default picker date | \[[dayjs](https://day.js.org/), [dayjs](https://day.js.org/)] | - | | -| defaultValue | To set default date | \[[dayjs](https://day.js.org/), [dayjs](https://day.js.org/)] | - | | -| disabled | If disable start or end | \[boolean, boolean] | - | | -| disabledTime | To specify the time that cannot be selected | function(date: dayjs, partial: `start` \| `end`) | - | | -| format | To set the date format, refer to [dayjs](https://day.js.org/). When an array is provided, all values are used for parsing and first value is used for formatting | string \| string\[] | `YYYY-MM-DD HH:mm:ss` | | -| ranges | The preseted ranges for quick selection | { \[range: string]: [dayjs](https://day.js.org/)\[] } \| { \[range: string]: () => [dayjs](https://day.js.org/)\[] } | - | | -| renderExtraFooter | Render extra footer in panel | () => React.ReactNode | - | | -| separator | Set separator between inputs | React.ReactNode | `` | | -| showTime | To provide an additional time selection | object \| boolean | [TimePicker Options](/components/time-picker/#API) | | -| showTime.defaultValue | To set default time of selected date, [demo](#components-date-picker-demo-disabled-date) | [dayjs](https://day.js.org/)\[] | \[dayjs(), dayjs()] | | -| value | To set date | \[[dayjs](https://day.js.org/), [dayjs](https://day.js.org/)] | - | | -| onCalendarChange | Callback function, can be executed when the start time or the end time of the range is changing. `info` argument is added in 4.4.0 | function(dates: \[dayjs, dayjs], dateStrings: \[string, string], info: { range:`start`\|`end` }) | - | | -| onChange | Callback function, can be executed when the selected time is changing | function(dates: \[dayjs, dayjs], dateStrings: \[string, string]) | - | | +| Property | Description | Type | Default | Version | +| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- | ------- | +| allowEmpty | Allow start or end input leave empty | \[boolean, boolean] | \[false, false] | | +| dateRender | Customize date cell. `info` argument is added in 4.3.0 | function(currentDate: dayjs, today: dayjs, info: { range: `start` \| `end` }) => React.ReactNode | - | | +| defaultPickerValue | To set default picker date | \[[dayjs](https://day.js.org/), [dayjs](https://day.js.org/)] | - | | +| defaultValue | To set default date | \[[dayjs](https://day.js.org/), [dayjs](https://day.js.org/)] | - | | +| disabled | If disable start or end | \[boolean, boolean] | - | | +| disabledTime | To specify the time that cannot be selected | function(date: dayjs, partial: `start` \| `end`) | - | | +| format | To set the date format, refer to [dayjs](https://day.js.org/). When an array is provided, all values are used for parsing and first value is used for formatting | string \| string\[] | `YYYY-MM-DD HH:mm:ss` | | +| ranges | The preseted ranges for quick selection | { \[range: string]: [dayjs](https://day.js.org/)\[] } \| { \[range: string]: () => [dayjs](https://day.js.org/)\[] } | - | | +| renderExtraFooter | Render extra footer in panel | () => React.ReactNode | - | | +| separator | Set separator between inputs | React.ReactNode | `` | | +| showTime | To provide an additional time selection | object \| boolean | [TimePicker Options](/components/time-picker/#API) | | +| showTime.defaultValue | To set default time of selected date, [demo](#components-date-picker-demo-disabled-date) | [dayjs](https://day.js.org/)\[] | \[dayjs(), dayjs()] | | +| value | To set date | \[[dayjs](https://day.js.org/), [dayjs](https://day.js.org/)] | - | | +| onCalendarChange | Callback function, can be executed when the start time or the end time of the range is changing. `info` argument is added in 4.4.0 | function(dates: \[dayjs, dayjs], dateStrings: \[string, string], info: { range:`start`\|`end` }) | - | | +| onChange | Callback function, can be executed when the selected time is changing | function(dates: \[dayjs, dayjs], dateStrings: \[string, string]) | - | | ## FAQ diff --git a/components/date-picker/index.zh-CN.md b/components/date-picker/index.zh-CN.md index 8a929239bf..bb5e02e8a9 100644 --- a/components/date-picker/index.zh-CN.md +++ b/components/date-picker/index.zh-CN.md @@ -34,7 +34,7 @@ demo: 受控面板 自定义日期范围选择 后缀图标 -_InternalPanelDoNotUseOrYouWillBeFired +\_InternalPanelDoNotUseOrYouWillBeFired ## API @@ -64,7 +64,7 @@ import locale from 'antd/es/date-picker/locale/zh_CN'; // 默认语言为 en-US,如果你需要设置其他语言,推荐在入口文件全局设置 locale import dayjs from 'dayjs'; import 'dayjs/locale/zh-cn'; -import locale from 'antd/es/locale/zh_CN'; +import locale from 'antd/locale/zh_CN'; @@ -75,36 +75,36 @@ import locale from 'antd/es/locale/zh_CN'; 以下 API 为 DatePicker、 RangePicker 共享的 API。 -| 参数 | 说明 | 类型 | 默认值 | 版本 | -| --- | --- | --- | --- | --- | -| allowClear | 是否显示清除按钮 | boolean | true | | -| autoFocus | 自动获取焦点 | boolean | false | | -| bordered | 是否有边框 | boolean | true | | -| className | 选择器 className | string | - | | -| dateRender | 自定义日期单元格的内容 | function(currentDate: dayjs, today: dayjs) => React.ReactNode | - | | -| disabled | 禁用 | boolean | false | | -| disabledDate | 不可选择的日期 | (currentDate: dayjs) => boolean | - | | -| popupClassName | 额外的弹出日历 className | string | - | 4.23.0 | -| getPopupContainer | 定义浮层的容器,默认为 body 上新建 div | function(trigger) | - | | -| inputReadOnly | 设置输入框为只读(避免在移动设备上打开虚拟键盘) | boolean | false | | -| locale | 国际化配置 | object | [默认配置](https://github.com/ant-design/ant-design/blob/master/components/date-picker/locale/example.json) | | -| mode | 日期面板的状态([设置后无法选择年份/月份?](/docs/react/faq#当我指定了-DatePicker/RangePicker-的-mode-属性后,点击后无法选择年份/月份?)) | `time` \| `date` \| `month` \| `year` \| `decade` | - | | -| nextIcon | 自定义下一个图标 | ReactNode | - | 4.17.0 | -| open | 控制弹层是否展开 | boolean | - | | -| panelRender | 自定义渲染面板 | (panelNode) => ReactNode | - | 4.5.0 | -| picker | 设置选择器类型 | `date` \| `week` \| `month` \| `quarter` \| `year` | `date` | `quarter`: 4.1.0 | -| placeholder | 输入框提示文字 | string \| \[string, string] | - | | -| placement | 选择框弹出的位置 | `bottomLeft` `bottomRight` `topLeft` `topRight` | bottomLeft | | -| popupStyle | 额外的弹出日历样式 | CSSProperties | {} | | -| prevIcon | 自定义上一个图标 | ReactNode | - | 4.17.0 | -| size | 输入框大小,`large` 高度为 40px,`small` 为 24px,默认是 32px | `large` \| `middle` \| `small` | - | | -| status | 设置校验状态 | 'error' \| 'warning' | - | 4.19.0 | -| style | 自定义输入框样式 | CSSProperties | {} | | -| suffixIcon | 自定义的选择框后缀图标 | ReactNode | - | | -| superNextIcon | 自定义 `<<` 切换图标 | ReactNode | - | 4.17.0 | -| superPrevIcon | 自定义 `>>` 切换图标 | ReactNode | - | 4.17.0 | -| onOpenChange | 弹出日历和关闭日历的回调 | function(open) | - | | -| onPanelChange | 日历面板切换的回调 | function(value, mode) | - | | +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | ---------------- | +| allowClear | 是否显示清除按钮 | boolean | true | | +| autoFocus | 自动获取焦点 | boolean | false | | +| bordered | 是否有边框 | boolean | true | | +| className | 选择器 className | string | - | | +| dateRender | 自定义日期单元格的内容 | function(currentDate: dayjs, today: dayjs) => React.ReactNode | - | | +| disabled | 禁用 | boolean | false | | +| disabledDate | 不可选择的日期 | (currentDate: dayjs) => boolean | - | | +| popupClassName | 额外的弹出日历 className | string | - | 4.23.0 | +| getPopupContainer | 定义浮层的容器,默认为 body 上新建 div | function(trigger) | - | | +| inputReadOnly | 设置输入框为只读(避免在移动设备上打开虚拟键盘) | boolean | false | | +| locale | 国际化配置 | object | [默认配置](https://github.com/ant-design/ant-design/blob/master/components/date-picker/locale/example.json) | | +| mode | 日期面板的状态([设置后无法选择年份/月份?](/docs/react/faq#当我指定了-DatePicker/RangePicker-的-mode-属性后,点击后无法选择年份/月份?)) | `time` \| `date` \| `month` \| `year` \| `decade` | - | | +| nextIcon | 自定义下一个图标 | ReactNode | - | 4.17.0 | +| open | 控制弹层是否展开 | boolean | - | | +| panelRender | 自定义渲染面板 | (panelNode) => ReactNode | - | 4.5.0 | +| picker | 设置选择器类型 | `date` \| `week` \| `month` \| `quarter` \| `year` | `date` | `quarter`: 4.1.0 | +| placeholder | 输入框提示文字 | string \| \[string, string] | - | | +| placement | 选择框弹出的位置 | `bottomLeft` `bottomRight` `topLeft` `topRight` | bottomLeft | | +| popupStyle | 额外的弹出日历样式 | CSSProperties | {} | | +| prevIcon | 自定义上一个图标 | ReactNode | - | 4.17.0 | +| size | 输入框大小,`large` 高度为 40px,`small` 为 24px,默认是 32px | `large` \| `middle` \| `small` | - | | +| status | 设置校验状态 | 'error' \| 'warning' | - | 4.19.0 | +| style | 自定义输入框样式 | CSSProperties | {} | | +| suffixIcon | 自定义的选择框后缀图标 | ReactNode | - | | +| superNextIcon | 自定义 `<<` 切换图标 | ReactNode | - | 4.17.0 | +| superPrevIcon | 自定义 `>>` 切换图标 | ReactNode | - | 4.17.0 | +| onOpenChange | 弹出日历和关闭日历的回调 | function(open) | - | | +| onPanelChange | 日历面板切换的回调 | function(value, mode) | - | | ### 共同的方法 @@ -115,88 +115,88 @@ import locale from 'antd/es/locale/zh_CN'; ### DatePicker -| 参数 | 说明 | 类型 | 默认值 | 版本 | -| --- | --- | --- | --- | --- | -| defaultPickerValue | 默认面板日期 | [dayjs](https://day.js.org/) | - | | -| defaultValue | 默认日期,如果开始时间或结束时间为 `null` 或者 `undefined`,日期范围将是一个开区间 | [dayjs](https://day.js.org/) | - | | -| disabledTime | 不可选择的时间 | function(date) | - | | -| format | 设置日期格式,为数组时支持多格式匹配,展示以第一个为准。配置参考 [dayjs](https://day.js.org/),支持[自定义格式](#components-date-picker-demo-format) | string \| (value: dayjs) => string \| (string \| (value: dayjs) => string)\[] | `YYYY-MM-DD` | | -| renderExtraFooter | 在面板中添加额外的页脚 | (mode) => React.ReactNode | - | | -| showNow | 当设定了 `showTime` 的时候,面板是否显示“此刻”按钮 | boolean | - | 4.4.0 | -| showTime | 增加时间选择功能 | Object \| boolean | [TimePicker Options](/components/time-picker/#API) | | -| showTime.defaultValue | 设置用户选择日期时默认的时分秒,[例子](#components-date-picker-demo-disabled-date) | [dayjs](https://day.js.org/) | dayjs() | | -| showToday | 是否展示“今天”按钮 | boolean | true | | -| value | 日期 | [dayjs](https://day.js.org/) | - | | -| onChange | 时间发生变化的回调 | function(date: dayjs, dateString: string) | - | | -| onOk | 点击确定按钮的回调 | function() | - | | -| onPanelChange | 日期面板变化时的回调 | function(value, mode) | - | | +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | -------------------------------------------------- | ----- | +| defaultPickerValue | 默认面板日期 | [dayjs](https://day.js.org/) | - | | +| defaultValue | 默认日期,如果开始时间或结束时间为 `null` 或者 `undefined`,日期范围将是一个开区间 | [dayjs](https://day.js.org/) | - | | +| disabledTime | 不可选择的时间 | function(date) | - | | +| format | 设置日期格式,为数组时支持多格式匹配,展示以第一个为准。配置参考 [dayjs](https://day.js.org/),支持[自定义格式](#components-date-picker-demo-format) | string \| (value: dayjs) => string \| (string \| (value: dayjs) => string)\[] | `YYYY-MM-DD` | | +| renderExtraFooter | 在面板中添加额外的页脚 | (mode) => React.ReactNode | - | | +| showNow | 当设定了 `showTime` 的时候,面板是否显示“此刻”按钮 | boolean | - | 4.4.0 | +| showTime | 增加时间选择功能 | Object \| boolean | [TimePicker Options](/components/time-picker/#API) | | +| showTime.defaultValue | 设置用户选择日期时默认的时分秒,[例子](#components-date-picker-demo-disabled-date) | [dayjs](https://day.js.org/) | dayjs() | | +| showToday | 是否展示“今天”按钮 | boolean | true | | +| value | 日期 | [dayjs](https://day.js.org/) | - | | +| onChange | 时间发生变化的回调 | function(date: dayjs, dateString: string) | - | | +| onOk | 点击确定按钮的回调 | function() | - | | +| onPanelChange | 日期面板变化时的回调 | function(value, mode) | - | | ### DatePicker\[picker=year] -| 参数 | 说明 | 类型 | 默认值 | 版本 | -| --- | --- | --- | --- | --- | -| defaultPickerValue | 默认面板日期 | [dayjs](https://day.js.org/) | - | | -| defaultValue | 默认日期 | [dayjs](https://day.js.org/) | - | | -| format | 展示的日期格式,配置参考 [dayjs](https://day.js.org/) | string | `YYYY` | | -| renderExtraFooter | 在面板中添加额外的页脚 | () => React.ReactNode | - | | -| value | 日期 | [dayjs](https://day.js.org/) | - | | -| onChange | 时间发生变化的回调,发生在用户选择时间时 | function(date: dayjs, dateString: string) | - | | +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| ------------------ | ----------------------------------------------------- | ----------------------------------------- | ------ | ---- | +| defaultPickerValue | 默认面板日期 | [dayjs](https://day.js.org/) | - | | +| defaultValue | 默认日期 | [dayjs](https://day.js.org/) | - | | +| format | 展示的日期格式,配置参考 [dayjs](https://day.js.org/) | string | `YYYY` | | +| renderExtraFooter | 在面板中添加额外的页脚 | () => React.ReactNode | - | | +| value | 日期 | [dayjs](https://day.js.org/) | - | | +| onChange | 时间发生变化的回调,发生在用户选择时间时 | function(date: dayjs, dateString: string) | - | | ### DatePicker\[picker=quarter] `4.1.0` 新增。 -| 参数 | 说明 | 类型 | 默认值 | 版本 | -| --- | --- | --- | --- | --- | -| defaultPickerValue | 默认面板日期 | [dayjs](https://day.js.org/) | - | | -| defaultValue | 默认日期 | [dayjs](https://day.js.org/) | - | | -| format | 展示的日期格式,配置参考 [dayjs](https://day.js.org/) | string | `YYYY-\QQ` | | -| renderExtraFooter | 在面板中添加额外的页脚 | () => React.ReactNode | - | | -| value | 日期 | [dayjs](https://day.js.org/) | - | | -| onChange | 时间发生变化的回调,发生在用户选择时间时 | function(date: dayjs, dateString: string) | - | | +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| ------------------ | ----------------------------------------------------- | ----------------------------------------- | ---------- | ---- | +| defaultPickerValue | 默认面板日期 | [dayjs](https://day.js.org/) | - | | +| defaultValue | 默认日期 | [dayjs](https://day.js.org/) | - | | +| format | 展示的日期格式,配置参考 [dayjs](https://day.js.org/) | string | `YYYY-\QQ` | | +| renderExtraFooter | 在面板中添加额外的页脚 | () => React.ReactNode | - | | +| value | 日期 | [dayjs](https://day.js.org/) | - | | +| onChange | 时间发生变化的回调,发生在用户选择时间时 | function(date: dayjs, dateString: string) | - | | ### DatePicker\[picker=month] -| 参数 | 说明 | 类型 | 默认值 | 版本 | -| --- | --- | --- | --- | --- | -| defaultPickerValue | 默认面板日期 | [dayjs](https://day.js.org/) | - | | -| defaultValue | 默认日期 | [dayjs](https://day.js.org/) | - | | -| format | 展示的日期格式,配置参考 [dayjs](https://day.js.org/) | string | `YYYY-MM` | | -| monthCellRender | 自定义的月份内容渲染方法 | function(date, locale): ReactNode | - | | -| renderExtraFooter | 在面板中添加额外的页脚 | () => React.ReactNode | - | | -| value | 日期 | [dayjs](https://day.js.org/) | - | | -| onChange | 时间发生变化的回调,发生在用户选择时间时 | function(date: dayjs, dateString: string) | - | | +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| ------------------ | ----------------------------------------------------- | ----------------------------------------- | --------- | ---- | +| defaultPickerValue | 默认面板日期 | [dayjs](https://day.js.org/) | - | | +| defaultValue | 默认日期 | [dayjs](https://day.js.org/) | - | | +| format | 展示的日期格式,配置参考 [dayjs](https://day.js.org/) | string | `YYYY-MM` | | +| monthCellRender | 自定义的月份内容渲染方法 | function(date, locale): ReactNode | - | | +| renderExtraFooter | 在面板中添加额外的页脚 | () => React.ReactNode | - | | +| value | 日期 | [dayjs](https://day.js.org/) | - | | +| onChange | 时间发生变化的回调,发生在用户选择时间时 | function(date: dayjs, dateString: string) | - | | ### DatePicker\[picker=week] -| 参数 | 说明 | 类型 | 默认值 | 版本 | -| --- | --- | --- | --- | --- | -| defaultPickerValue | 默认面板日期 | [dayjs](https://day.js.org/) | - | | -| defaultValue | 默认日期 | [dayjs](https://day.js.org/) | - | | -| format | 展示的日期格式,配置参考 [dayjs](https://day.js.org/) | string | `YYYY-wo` | | -| renderExtraFooter | 在面板中添加额外的页脚 | (mode) => React.ReactNode | - | | -| value | 日期 | [dayjs](https://day.js.org/) | - | | -| onChange | 时间发生变化的回调,发生在用户选择时间时 | function(date: dayjs, dateString: string) | - | | +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| ------------------ | ----------------------------------------------------- | ----------------------------------------- | --------- | ---- | +| defaultPickerValue | 默认面板日期 | [dayjs](https://day.js.org/) | - | | +| defaultValue | 默认日期 | [dayjs](https://day.js.org/) | - | | +| format | 展示的日期格式,配置参考 [dayjs](https://day.js.org/) | string | `YYYY-wo` | | +| renderExtraFooter | 在面板中添加额外的页脚 | (mode) => React.ReactNode | - | | +| value | 日期 | [dayjs](https://day.js.org/) | - | | +| onChange | 时间发生变化的回调,发生在用户选择时间时 | function(date: dayjs, dateString: string) | - | | ### RangePicker -| 参数 | 说明 | 类型 | 默认值 | 版本 | -| --- | --- | --- | --- | --- | -| allowEmpty | 允许起始项部分为空 | \[boolean, boolean] | \[false, false] | | -| dateRender | 自定义日期单元格的内容。`info` 参数自 4.3.0 添加 | function(currentDate: dayjs, today: dayjs, info: { range: `start` \| `end` }) => React.ReactNode | - | | -| defaultPickerValue | 默认面板日期 | [dayjs](https://day.js.org/)\[] | - | | -| defaultValue | 默认日期 | [dayjs](https://day.js.org/)\[] | - | | -| disabled | 禁用起始项 | \[boolean, boolean] | - | | -| disabledTime | 不可选择的时间 | function(date: dayjs, partial: `start` \| `end`) | - | | -| format | 展示的日期格式 | string | `YYYY-MM-DD HH:mm:ss` | | -| ranges | 预设时间范围快捷选择 | { \[range: string]: [dayjs](https://day.js.org/)\[] } \| { \[range: string]: () => [dayjs](https://day.js.org/)\[] } | - | | -| renderExtraFooter | 在面板中添加额外的页脚 | () => React.ReactNode | - | | -| separator | 设置分隔符 | React.ReactNode | `` | | -| showTime | 增加时间选择功能 | Object\|boolean | [TimePicker Options](/components/time-picker/#API) | | -| showTime.defaultValue | 设置用户选择日期时默认的时分秒,[例子](#components-date-picker-demo-disabled-date) | [dayjs](https://day.js.org/)\[] | \[dayjs(), dayjs()] | | -| value | 日期 | [dayjs](https://day.js.org/)\[] | - | | -| onCalendarChange | 待选日期发生变化的回调。`info` 参数自 4.4.0 添加 | function(dates: \[dayjs, dayjs], dateStrings: \[string, string], info: { range:`start`\|`end` }) | - | | -| onChange | 日期范围发生变化的回调 | function(dates: \[dayjs, dayjs], dateStrings: \[string, string]) | - | | +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --------------------- | ---------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- | ---- | +| allowEmpty | 允许起始项部分为空 | \[boolean, boolean] | \[false, false] | | +| dateRender | 自定义日期单元格的内容。`info` 参数自 4.3.0 添加 | function(currentDate: dayjs, today: dayjs, info: { range: `start` \| `end` }) => React.ReactNode | - | | +| defaultPickerValue | 默认面板日期 | [dayjs](https://day.js.org/)\[] | - | | +| defaultValue | 默认日期 | [dayjs](https://day.js.org/)\[] | - | | +| disabled | 禁用起始项 | \[boolean, boolean] | - | | +| disabledTime | 不可选择的时间 | function(date: dayjs, partial: `start` \| `end`) | - | | +| format | 展示的日期格式 | string | `YYYY-MM-DD HH:mm:ss` | | +| ranges | 预设时间范围快捷选择 | { \[range: string]: [dayjs](https://day.js.org/)\[] } \| { \[range: string]: () => [dayjs](https://day.js.org/)\[] } | - | | +| renderExtraFooter | 在面板中添加额外的页脚 | () => React.ReactNode | - | | +| separator | 设置分隔符 | React.ReactNode | `` | | +| showTime | 增加时间选择功能 | Object\|boolean | [TimePicker Options](/components/time-picker/#API) | | +| showTime.defaultValue | 设置用户选择日期时默认的时分秒,[例子](#components-date-picker-demo-disabled-date) | [dayjs](https://day.js.org/)\[] | \[dayjs(), dayjs()] | | +| value | 日期 | [dayjs](https://day.js.org/)\[] | - | | +| onCalendarChange | 待选日期发生变化的回调。`info` 参数自 4.4.0 添加 | function(dates: \[dayjs, dayjs], dateStrings: \[string, string], info: { range:`start`\|`end` }) | - | | +| onChange | 日期范围发生变化的回调 | function(dates: \[dayjs, dayjs], dateStrings: \[string, string]) | - | | ## FAQ diff --git a/components/dropdown/__tests__/index.test.tsx b/components/dropdown/__tests__/index.test.tsx index 02e87ed2ce..0f7d7db702 100644 --- a/components/dropdown/__tests__/index.test.tsx +++ b/components/dropdown/__tests__/index.test.tsx @@ -4,7 +4,7 @@ import Dropdown from '..'; import type { DropDownProps } from '..'; import mountTest from '../../../tests/shared/mountTest'; import rtlTest from '../../../tests/shared/rtlTest'; -import { act, fireEvent, render, sleep } from '../../../tests/utils'; +import { act, fireEvent, render, waitFakeTimer } from '../../../tests/utils'; import Menu from '../../menu'; import { resetWarned } from '../../_util/warning'; @@ -56,6 +56,7 @@ describe('Dropdown', () => { }); it('support Menu expandIcon', async () => { + jest.useFakeTimers(); const props: DropDownProps = { overlay: ( }> @@ -74,8 +75,9 @@ describe('Dropdown', () => { , ); - await sleep(500); + await waitFakeTimer(); expect(container.querySelectorAll('#customExpandIcon').length).toBe(1); + jest.useRealTimers(); }); it('should warn if use topCenter or bottomCenter', () => { diff --git a/components/form/FormItemLabel.tsx b/components/form/FormItemLabel.tsx index bfcf1d9d07..cb8d2d5195 100644 --- a/components/form/FormItemLabel.tsx +++ b/components/form/FormItemLabel.tsx @@ -4,7 +4,7 @@ import * as React from 'react'; import type { ColProps } from '../grid/col'; import Col from '../grid/col'; import { useLocaleReceiver } from '../locale-provider/LocaleReceiver'; -import defaultLocale from '../locale/default'; +import defaultLocale from '../locale/en_US'; import type { TooltipProps } from '../tooltip'; import Tooltip from '../tooltip'; import type { FormContextProps } from './context'; diff --git a/components/form/__tests__/list.test.tsx b/components/form/__tests__/list.test.tsx index 0010d782f7..671ada9994 100644 --- a/components/form/__tests__/list.test.tsx +++ b/components/form/__tests__/list.test.tsx @@ -1,27 +1,59 @@ import React from 'react'; import type { FormListFieldData, FormListOperation } from '..'; import Form from '..'; -import { fireEvent, render, sleep, act } from '../../../tests/utils'; +import { fireEvent, render, waitFakeTimer } from '../../../tests/utils'; import Button from '../../button'; import Input from '../../input'; describe('Form.List', () => { - const change = async ( - wrapper: ReturnType['container'], - index: number, + // const change = async ( + // wrapper: ReturnType['container'], + // index: number, + // value: string, + // ) => { + // fireEvent.change(wrapper.getElementsByClassName('ant-input')?.[index], { target: { value } }); + // await sleep(); + // }; + + const changeValue = async ( + input: HTMLElement | null | number, value: string, + advTimer = 1000, ) => { - fireEvent.change(wrapper.getElementsByClassName('ant-input')?.[index], { target: { value } }); - await sleep(); + let element: HTMLElement; + + if (typeof input === 'number') { + element = document.querySelectorAll('input')[input]; + } + + expect(element!).toBeTruthy(); + + fireEvent.change(element!, { + target: { + value, + }, + }); + + if (advTimer) { + await waitFakeTimer(advTimer / 20); + } }; + beforeEach(() => { + document.body.innerHTML = ''; + jest.useFakeTimers(); + }); + + afterAll(() => { + jest.clearAllTimers(); + jest.useRealTimers(); + }); + const testList = ( name: string, renderField: (value: FormListFieldData) => React.ReactNode, ): void => { it(name, async () => { - jest.useFakeTimers(); - const { container } = render(
@@ -39,39 +71,31 @@ describe('Form.List', () => { , ); - function operate(className: string) { + async function operate(className: string) { fireEvent.click(container.querySelector(className)!); - act(() => { - jest.runAllTimers(); - }); + await waitFakeTimer(); } - operate('.add'); - expect(container.getElementsByClassName('ant-input').length).toBe(1); + await operate('.add'); + expect(container.querySelectorAll('.ant-input').length).toBe(1); - operate('.add'); - expect(container.getElementsByClassName('ant-input').length).toBe(2); + await operate('.add'); + expect(container.querySelectorAll('.ant-input').length).toBe(2); - operate('.add'); - expect(container.getElementsByClassName('ant-input').length).toBe(3); + await operate('.add'); + expect(container.querySelectorAll('.ant-input').length).toBe(3); - await change(container, 2, ''); - for (let i = 0; i < 10; i += 1) { - act(() => { - jest.runAllTimers(); - }); - } - expect(container.getElementsByClassName('ant-form-item-explain').length).toBe(1); + await changeValue(2, ''); - operate('.remove-0'); - expect(container.getElementsByClassName('ant-input').length).toBe(2); - expect(container.getElementsByClassName('ant-form-item-explain').length).toBe(1); + expect(container.querySelectorAll('.ant-form-item-explain').length).toBe(1); - operate('.remove-1'); - expect(container.getElementsByClassName('ant-input').length).toBe(1); - expect(container.getElementsByClassName('ant-form-item-explain').length).toBe(0); + await operate('.remove-0'); + expect(container.querySelectorAll('.ant-input').length).toBe(2); + expect(container.querySelectorAll('.ant-form-item-explain').length).toBe(1); - jest.useRealTimers(); + await operate('.remove-1'); + expect(container.querySelectorAll('.ant-input').length).toBe(1); + expect(container.querySelectorAll('.ant-form-item-explain').length).toBe(0); }); }; @@ -131,28 +155,26 @@ describe('Form.List', () => { ); await click(container, '.add'); - await change(container, 0, 'input1'); + await changeValue(0, 'input1'); fireEvent.submit(container.querySelector('form')!); - await sleep(); + await waitFakeTimer(); expect(onFinish).toHaveBeenLastCalledWith({ list: ['input1'] }); await click(container, '.add'); - await change(container, 1, 'input2'); + await changeValue(1, 'input2'); await click(container, '.add'); - await change(container, 2, 'input3'); + await changeValue(2, 'input3'); fireEvent.submit(container.querySelector('form')!); - await sleep(); + await waitFakeTimer(); expect(onFinish).toHaveBeenLastCalledWith({ list: ['input1', 'input2', 'input3'] }); await click(container, '.remove'); // will remove first input fireEvent.submit(container.querySelector('form')!); - await sleep(); + await waitFakeTimer(); expect(onFinish).toHaveBeenLastCalledWith({ list: ['input2', 'input3'] }); }); it('list errors', async () => { - jest.useFakeTimers(); - let operation: FormListOperation; const { container } = render(
@@ -177,15 +199,8 @@ describe('Form.List', () => { ); async function addItem() { - await act(async () => { - operation.add(); - await sleep(100); - jest.runAllTimers(); - }); - - act(() => { - jest.runAllTimers(); - }); + operation.add(); + await waitFakeTimer(); } await addItem(); @@ -193,8 +208,6 @@ describe('Form.List', () => { await addItem(); expect(container.getElementsByClassName('ant-form-item-explain div')).toHaveLength(0); - - jest.useRealTimers(); }); it('should render empty without errors', () => { @@ -243,7 +256,7 @@ describe('Form.List', () => { const { container } = render(); fireEvent.click(container.querySelector('button')!); - await sleep(); + await waitFakeTimer(); expect(errorSpy).not.toHaveBeenCalled(); diff --git a/components/form/util.ts b/components/form/util.ts index f0f2e5df2d..890bf83ab0 100644 --- a/components/form/util.ts +++ b/components/form/util.ts @@ -22,7 +22,7 @@ export function getFieldId(namePath: InternalNamePath, formName?: string): strin return `${formName}_${mergedId}`; } - const isIllegalName = formItemNameBlackList.indexOf(mergedId) >= 0; + const isIllegalName = formItemNameBlackList.includes(mergedId); return isIllegalName ? `${defaultItemNamePrefixCls}_${mergedId}` : mergedId; } diff --git a/components/input/__tests__/__snapshots__/Password.test.tsx.snap b/components/input/__tests__/__snapshots__/Password.test.tsx.snap index 06c75164d8..90e6f477f4 100644 --- a/components/input/__tests__/__snapshots__/Password.test.tsx.snap +++ b/components/input/__tests__/__snapshots__/Password.test.tsx.snap @@ -80,7 +80,7 @@ exports[`Input.Password should change type when click 1`] = ` exports[`Input.Password should change type when click 2`] = ` { it('click outside should also get focus', () => { const { container } = render(} />); const onFocus = jest.spyOn(container.querySelector('input')!, 'focus'); - fireEvent.mouseDown(container.querySelector('.test-suffix')!); - fireEvent.mouseUp(container.querySelector('.test-suffix')!); + fireEvent.click(container.querySelector('.test-suffix')!); expect(onFocus).toHaveBeenCalled(); }); diff --git a/components/list/style/index.tsx b/components/list/style/index.tsx index ec320cc84d..fffce5abe2 100644 --- a/components/list/style/index.tsx +++ b/components/list/style/index.tsx @@ -341,9 +341,9 @@ export default genComponentStyleHook( const listToken = mergeToken(token, { listBorderedCls: `${token.componentCls}-bordered`, minHeight: token.controlHeightLG, - listItemPadding: `${token.paddingSM}px 0`, - listItemPaddingSM: `${token.paddingXS}px ${token.padding}px`, - listItemPaddingLG: `${token.padding}px ${token.paddingLG}px`, + listItemPadding: `${token.paddingContentVertical}px ${token.paddingContentHorizontalLG}px`, + listItemPaddingSM: `${token.paddingContentVerticalSM}px ${token.paddingContentHorizontal}px`, + listItemPaddingLG: `${token.paddingContentVerticalLG}px ${token.paddingContentHorizontalLG}px`, }); return [genBaseStyle(listToken), genBorderedStyle(listToken), genResponsiveStyle(listToken)]; diff --git a/components/locale-provider/LocaleReceiver.tsx b/components/locale-provider/LocaleReceiver.tsx index 0a2db40256..94685af859 100644 --- a/components/locale-provider/LocaleReceiver.tsx +++ b/components/locale-provider/LocaleReceiver.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import type { Locale } from '.'; import type { LocaleContextProps } from './context'; import LocaleContext from './context'; -import defaultLocaleData from './default'; +import defaultLocaleData from '../locale/en_US'; export type LocaleComponentName = Exclude; diff --git a/components/locale-provider/default.tsx b/components/locale-provider/default.tsx deleted file mode 100644 index 4740550189..0000000000 --- a/components/locale-provider/default.tsx +++ /dev/null @@ -1,3 +0,0 @@ -import locale from '../locale/default'; - -export default locale; diff --git a/components/locale/ar_EG.tsx b/components/locale/ar_EG.tsx index 60e26b4944..9be2083032 100644 --- a/components/locale/ar_EG.tsx +++ b/components/locale/ar_EG.tsx @@ -40,6 +40,7 @@ const localeValues: Locale = { cancelText: 'إلغاء', }, Transfer: { + titles: ['', ''], searchPlaceholder: 'ابحث هنا', itemUnit: 'عنصر', itemsUnit: 'عناصر', diff --git a/components/locale/bg_BG.tsx b/components/locale/bg_BG.tsx index f466fc1e79..a745b202f3 100644 --- a/components/locale/bg_BG.tsx +++ b/components/locale/bg_BG.tsx @@ -27,6 +27,7 @@ const localeValues: Locale = { cancelText: 'Отказ', }, Transfer: { + titles: ['', ''], searchPlaceholder: 'Търсене', itemUnit: 'избор', itemsUnit: 'избори', diff --git a/components/locale/da_DK.tsx b/components/locale/da_DK.tsx index 03414142c4..56f03be6f0 100644 --- a/components/locale/da_DK.tsx +++ b/components/locale/da_DK.tsx @@ -37,6 +37,7 @@ const localeValues: Locale = { cancelText: 'Afbryd', }, Transfer: { + titles: ['', ''], searchPlaceholder: 'Søg her', itemUnit: 'element', itemsUnit: 'elementer', diff --git a/components/locale/default.tsx b/components/locale/default.tsx deleted file mode 100644 index 6b91199db5..0000000000 --- a/components/locale/default.tsx +++ /dev/null @@ -1,136 +0,0 @@ -/* eslint-disable no-template-curly-in-string */ -import Pagination from 'rc-pagination/lib/locale/en_US'; -import Calendar from '../calendar/locale/en_US'; -import DatePicker from '../date-picker/locale/en_US'; -import type { Locale } from '../locale-provider'; -import TimePicker from '../time-picker/locale/en_US'; - -const typeTemplate = '${label} is not a valid ${type}'; - -const localeValues: Locale = { - locale: 'en', - Pagination, - DatePicker, - TimePicker, - Calendar, - global: { - placeholder: 'Please select', - }, - Table: { - filterTitle: 'Filter menu', - filterConfirm: 'OK', - filterReset: 'Reset', - filterEmptyText: 'No filters', - filterCheckall: 'Select all items', - filterSearchPlaceholder: 'Search in filters', - emptyText: 'No data', - selectAll: 'Select current page', - selectInvert: 'Invert current page', - selectNone: 'Clear all data', - selectionAll: 'Select all data', - sortTitle: 'Sort', - expand: 'Expand row', - collapse: 'Collapse row', - triggerDesc: 'Click to sort descending', - triggerAsc: 'Click to sort ascending', - cancelSort: 'Click to cancel sorting', - }, - Modal: { - okText: 'OK', - cancelText: 'Cancel', - justOkText: 'OK', - }, - Popconfirm: { - okText: 'OK', - cancelText: 'Cancel', - }, - Transfer: { - titles: ['', ''], - searchPlaceholder: 'Search here', - itemUnit: 'item', - itemsUnit: 'items', - remove: 'Remove', - selectCurrent: 'Select current page', - removeCurrent: 'Remove current page', - selectAll: 'Select all data', - removeAll: 'Remove all data', - selectInvert: 'Invert current page', - }, - Upload: { - uploading: 'Uploading...', - removeFile: 'Remove file', - uploadError: 'Upload error', - previewFile: 'Preview file', - downloadFile: 'Download file', - }, - Empty: { - description: 'No Data', - }, - Icon: { - icon: 'icon', - }, - Text: { - edit: 'Edit', - copy: 'Copy', - copied: 'Copied', - expand: 'Expand', - }, - PageHeader: { - back: 'Back', - }, - Form: { - optional: '(optional)', - defaultValidateMessages: { - default: 'Field validation error for ${label}', - required: 'Please enter ${label}', - enum: '${label} must be one of [${enum}]', - whitespace: '${label} cannot be a blank character', - date: { - format: '${label} date format is invalid', - parse: '${label} cannot be converted to a date', - invalid: '${label} is an invalid date', - }, - types: { - string: typeTemplate, - method: typeTemplate, - array: typeTemplate, - object: typeTemplate, - number: typeTemplate, - date: typeTemplate, - boolean: typeTemplate, - integer: typeTemplate, - float: typeTemplate, - regexp: typeTemplate, - email: typeTemplate, - url: typeTemplate, - hex: typeTemplate, - }, - string: { - len: '${label} must be ${len} characters', - min: '${label} must be at least ${min} characters', - max: '${label} must be up to ${max} characters', - range: '${label} must be between ${min}-${max} characters', - }, - number: { - len: '${label} must be equal to ${len}', - min: '${label} must be minimum ${min}', - max: '${label} must be maximum ${max}', - range: '${label} must be between ${min}-${max}', - }, - array: { - len: 'Must be ${len} ${label}', - min: 'At least ${min} ${label}', - max: 'At most ${max} ${label}', - range: 'The amount of ${label} must be between ${min}-${max}', - }, - pattern: { - mismatch: '${label} does not match the pattern ${pattern}', - }, - }, - }, - Image: { - preview: 'Preview', - }, -}; - -export default localeValues; diff --git a/components/locale/el_GR.tsx b/components/locale/el_GR.tsx index 644f7c6491..ba5e26b3da 100644 --- a/components/locale/el_GR.tsx +++ b/components/locale/el_GR.tsx @@ -27,6 +27,7 @@ const localeValues: Locale = { cancelText: 'Άκυρο', }, Transfer: { + titles: ['', ''], searchPlaceholder: 'Αναζήτηση', itemUnit: 'αντικείμενο', itemsUnit: 'αντικείμενα', diff --git a/components/locale/en_US.tsx b/components/locale/en_US.tsx index 5d08924d7f..6b91199db5 100644 --- a/components/locale/en_US.tsx +++ b/components/locale/en_US.tsx @@ -1,3 +1,136 @@ -import defaultLocale from './default'; +/* eslint-disable no-template-curly-in-string */ +import Pagination from 'rc-pagination/lib/locale/en_US'; +import Calendar from '../calendar/locale/en_US'; +import DatePicker from '../date-picker/locale/en_US'; +import type { Locale } from '../locale-provider'; +import TimePicker from '../time-picker/locale/en_US'; -export default defaultLocale; +const typeTemplate = '${label} is not a valid ${type}'; + +const localeValues: Locale = { + locale: 'en', + Pagination, + DatePicker, + TimePicker, + Calendar, + global: { + placeholder: 'Please select', + }, + Table: { + filterTitle: 'Filter menu', + filterConfirm: 'OK', + filterReset: 'Reset', + filterEmptyText: 'No filters', + filterCheckall: 'Select all items', + filterSearchPlaceholder: 'Search in filters', + emptyText: 'No data', + selectAll: 'Select current page', + selectInvert: 'Invert current page', + selectNone: 'Clear all data', + selectionAll: 'Select all data', + sortTitle: 'Sort', + expand: 'Expand row', + collapse: 'Collapse row', + triggerDesc: 'Click to sort descending', + triggerAsc: 'Click to sort ascending', + cancelSort: 'Click to cancel sorting', + }, + Modal: { + okText: 'OK', + cancelText: 'Cancel', + justOkText: 'OK', + }, + Popconfirm: { + okText: 'OK', + cancelText: 'Cancel', + }, + Transfer: { + titles: ['', ''], + searchPlaceholder: 'Search here', + itemUnit: 'item', + itemsUnit: 'items', + remove: 'Remove', + selectCurrent: 'Select current page', + removeCurrent: 'Remove current page', + selectAll: 'Select all data', + removeAll: 'Remove all data', + selectInvert: 'Invert current page', + }, + Upload: { + uploading: 'Uploading...', + removeFile: 'Remove file', + uploadError: 'Upload error', + previewFile: 'Preview file', + downloadFile: 'Download file', + }, + Empty: { + description: 'No Data', + }, + Icon: { + icon: 'icon', + }, + Text: { + edit: 'Edit', + copy: 'Copy', + copied: 'Copied', + expand: 'Expand', + }, + PageHeader: { + back: 'Back', + }, + Form: { + optional: '(optional)', + defaultValidateMessages: { + default: 'Field validation error for ${label}', + required: 'Please enter ${label}', + enum: '${label} must be one of [${enum}]', + whitespace: '${label} cannot be a blank character', + date: { + format: '${label} date format is invalid', + parse: '${label} cannot be converted to a date', + invalid: '${label} is an invalid date', + }, + types: { + string: typeTemplate, + method: typeTemplate, + array: typeTemplate, + object: typeTemplate, + number: typeTemplate, + date: typeTemplate, + boolean: typeTemplate, + integer: typeTemplate, + float: typeTemplate, + regexp: typeTemplate, + email: typeTemplate, + url: typeTemplate, + hex: typeTemplate, + }, + string: { + len: '${label} must be ${len} characters', + min: '${label} must be at least ${min} characters', + max: '${label} must be up to ${max} characters', + range: '${label} must be between ${min}-${max} characters', + }, + number: { + len: '${label} must be equal to ${len}', + min: '${label} must be minimum ${min}', + max: '${label} must be maximum ${max}', + range: '${label} must be between ${min}-${max}', + }, + array: { + len: 'Must be ${len} ${label}', + min: 'At least ${min} ${label}', + max: 'At most ${max} ${label}', + range: 'The amount of ${label} must be between ${min}-${max}', + }, + pattern: { + mismatch: '${label} does not match the pattern ${pattern}', + }, + }, + }, + Image: { + preview: 'Preview', + }, +}; + +export default localeValues; diff --git a/components/locale/fi_FI.tsx b/components/locale/fi_FI.tsx index df9207831d..6b0cb7cbec 100644 --- a/components/locale/fi_FI.tsx +++ b/components/locale/fi_FI.tsx @@ -31,6 +31,7 @@ const localeValues: Locale = { cancelText: 'Peruuta', }, Transfer: { + titles: ['', ''], searchPlaceholder: 'Etsi täältä', itemUnit: 'kohde', itemsUnit: 'kohdetta', diff --git a/components/locale/fr_BE.tsx b/components/locale/fr_BE.tsx index d234603cf1..dd520c9f1b 100644 --- a/components/locale/fr_BE.tsx +++ b/components/locale/fr_BE.tsx @@ -26,6 +26,7 @@ const localeValues: Locale = { cancelText: 'Annuler', }, Transfer: { + titles: ['', ''], searchPlaceholder: 'Recherche', itemUnit: 'élément', itemsUnit: 'éléments', diff --git a/components/locale/fr_CA.tsx b/components/locale/fr_CA.tsx index 21eafa6624..bee3c7a04e 100644 --- a/components/locale/fr_CA.tsx +++ b/components/locale/fr_CA.tsx @@ -35,6 +35,7 @@ const localeValues: Locale = { cancelText: 'Annuler', }, Transfer: { + titles: ['', ''], searchPlaceholder: 'Rechercher', itemUnit: 'élément', itemsUnit: 'éléments', diff --git a/components/locale/gl_ES.tsx b/components/locale/gl_ES.tsx index b6b59a0899..8e1d135901 100644 --- a/components/locale/gl_ES.tsx +++ b/components/locale/gl_ES.tsx @@ -34,6 +34,7 @@ const localeValues: Locale = { cancelText: 'Cancelar', }, Transfer: { + titles: ['', ''], searchPlaceholder: 'Buscar aquí', itemUnit: 'elemento', itemsUnit: 'elementos', diff --git a/components/locale/he_IL.tsx b/components/locale/he_IL.tsx index b9c809f627..c0fc9a6f87 100644 --- a/components/locale/he_IL.tsx +++ b/components/locale/he_IL.tsx @@ -40,6 +40,7 @@ const localeValues: Locale = { cancelText: 'ביטול', }, Transfer: { + titles: ['', ''], searchPlaceholder: 'חפש כאן', itemUnit: 'פריט', itemsUnit: 'פריטים', diff --git a/components/locale/hu_HU.tsx b/components/locale/hu_HU.tsx index cbdc228b10..d3385bf094 100644 --- a/components/locale/hu_HU.tsx +++ b/components/locale/hu_HU.tsx @@ -28,6 +28,7 @@ const localeValues: Locale = { cancelText: 'Visszavonás', }, Transfer: { + titles: ['', ''], searchPlaceholder: 'Keresés', itemUnit: 'elem', itemsUnit: 'elemek', diff --git a/components/locale/is_IS.tsx b/components/locale/is_IS.tsx index ce2905fc95..0ecec8f953 100644 --- a/components/locale/is_IS.tsx +++ b/components/locale/is_IS.tsx @@ -27,6 +27,7 @@ const localeValues: Locale = { cancelText: 'Hætta við', }, Transfer: { + titles: ['', ''], searchPlaceholder: 'Leita hér', itemUnit: 'færsla', itemsUnit: 'færslur', diff --git a/components/locale/ja_JP.tsx b/components/locale/ja_JP.tsx index 5e41daac51..2ee099d323 100644 --- a/components/locale/ja_JP.tsx +++ b/components/locale/ja_JP.tsx @@ -38,6 +38,7 @@ const localeValues: Locale = { cancelText: 'キャンセル', }, Transfer: { + titles: ['', ''], searchPlaceholder: 'ここを検索', itemUnit: 'アイテム', itemsUnit: 'アイテム', diff --git a/components/locale/km_KH.tsx b/components/locale/km_KH.tsx index 33b04c8e84..79663471a7 100644 --- a/components/locale/km_KH.tsx +++ b/components/locale/km_KH.tsx @@ -40,6 +40,7 @@ const localeValues: Locale = { cancelText: 'បោះបង់', }, Transfer: { + titles: ['', ''], searchPlaceholder: 'ស្វែងរកនៅទីនេះ', itemUnit: '', itemsUnit: 'items', diff --git a/components/locale/kmr_IQ.tsx b/components/locale/kmr_IQ.tsx index 8cd6d54bd3..147b15fbe6 100644 --- a/components/locale/kmr_IQ.tsx +++ b/components/locale/kmr_IQ.tsx @@ -27,6 +27,7 @@ const localeValues: Locale = { cancelText: 'Betal ke', }, Transfer: { + titles: ['', ''], searchPlaceholder: 'Lêgerîn', itemUnit: 'tişt', itemsUnit: 'tişt', diff --git a/components/locale/ko_KR.tsx b/components/locale/ko_KR.tsx index 647b432074..f02da311ef 100644 --- a/components/locale/ko_KR.tsx +++ b/components/locale/ko_KR.tsx @@ -32,6 +32,7 @@ const localeValues: Locale = { cancelText: '취소', }, Transfer: { + titles: ['', ''], searchPlaceholder: '여기에 검색하세요', itemUnit: '개', itemsUnit: '개', diff --git a/components/locale/ku_IQ.tsx b/components/locale/ku_IQ.tsx index d2384601f5..55ba9b3a71 100755 --- a/components/locale/ku_IQ.tsx +++ b/components/locale/ku_IQ.tsx @@ -4,7 +4,7 @@ import DatePicker from '../date-picker/locale/kmr_IQ'; import type { Locale } from '../locale-provider'; import TimePicker from '../time-picker/locale/kmr_IQ'; -// please use antd/lib/locale/kmr_IQ instead +// please use antd/locale/kmr_IQ instead // keep this file for compatibility // https://github.com/ant-design/ant-design/issues/25778 @@ -31,6 +31,7 @@ const localeValues: Locale = { cancelText: 'Betal ke', }, Transfer: { + titles: ['', ''], searchPlaceholder: 'Lêgerîn', itemUnit: 'tişt', itemsUnit: 'tişt', diff --git a/components/locale/lv_LV.tsx b/components/locale/lv_LV.tsx index a7e711638f..26ad88713a 100644 --- a/components/locale/lv_LV.tsx +++ b/components/locale/lv_LV.tsx @@ -27,6 +27,7 @@ const localeValues: Locale = { cancelText: 'Atcelt', }, Transfer: { + titles: ['', ''], searchPlaceholder: 'Meklēt šeit', itemUnit: 'vienumu', itemsUnit: 'vienumus', diff --git a/components/locale/mk_MK.tsx b/components/locale/mk_MK.tsx index d0a387cdc9..c523b35c27 100644 --- a/components/locale/mk_MK.tsx +++ b/components/locale/mk_MK.tsx @@ -30,6 +30,7 @@ const localeValues: Locale = { cancelText: 'Откажи', }, Transfer: { + titles: ['', ''], searchPlaceholder: 'Пребарај тука', itemUnit: 'предмет', itemsUnit: 'предмети', diff --git a/components/locale/mn_MN.tsx b/components/locale/mn_MN.tsx index d3d6b7f58b..94c5fe4d2d 100644 --- a/components/locale/mn_MN.tsx +++ b/components/locale/mn_MN.tsx @@ -27,6 +27,7 @@ const localeValues: Locale = { cancelText: 'Цуцлах', }, Transfer: { + titles: ['', ''], searchPlaceholder: 'Хайх', itemUnit: 'Зүйл', itemsUnit: 'Зүйлүүд', diff --git a/components/locale/ms_MY.tsx b/components/locale/ms_MY.tsx index 736083e283..993c4b9fc2 100644 --- a/components/locale/ms_MY.tsx +++ b/components/locale/ms_MY.tsx @@ -43,6 +43,7 @@ const localeValues: Locale = { cancelText: 'Batal', }, Transfer: { + titles: ['', ''], notFoundContent: 'Tidak dijumpai', searchPlaceholder: 'Carian di sini', itemUnit: 'item', diff --git a/components/locale/sl_SI.tsx b/components/locale/sl_SI.tsx index 74ca51971a..ea02ff43c4 100644 --- a/components/locale/sl_SI.tsx +++ b/components/locale/sl_SI.tsx @@ -27,6 +27,7 @@ const localeValues: Locale = { cancelText: 'Prekliči', }, Transfer: { + titles: ['', ''], searchPlaceholder: 'Išči tukaj', itemUnit: 'Objekt', itemsUnit: 'Objektov', diff --git a/components/locale/vi_VN.tsx b/components/locale/vi_VN.tsx index 0af968dd01..369686728a 100644 --- a/components/locale/vi_VN.tsx +++ b/components/locale/vi_VN.tsx @@ -27,6 +27,7 @@ const localeValues: Locale = { cancelText: 'Huỷ', }, Transfer: { + titles: ['', ''], searchPlaceholder: 'Tìm ở đây', itemUnit: 'mục', itemsUnit: 'mục', diff --git a/components/locale/zh_CN.tsx b/components/locale/zh_CN.tsx index 66d38cecad..4750fb6c16 100644 --- a/components/locale/zh_CN.tsx +++ b/components/locale/zh_CN.tsx @@ -45,6 +45,7 @@ const localeValues: Locale = { okText: '确定', }, Transfer: { + titles: ['', ''], searchPlaceholder: '请输入搜索内容', itemUnit: '项', itemsUnit: '项', diff --git a/components/locale/zh_HK.tsx b/components/locale/zh_HK.tsx index f8dce3dbd2..d8eb4800e3 100644 --- a/components/locale/zh_HK.tsx +++ b/components/locale/zh_HK.tsx @@ -42,6 +42,7 @@ const localeValues: Locale = { cancelText: '取消', }, Transfer: { + titles: ['', ''], searchPlaceholder: '搜尋資料', itemUnit: '項目', itemsUnit: '項目', diff --git a/components/locale/zh_TW.tsx b/components/locale/zh_TW.tsx index 6b3445d8e3..07ca16f0e5 100644 --- a/components/locale/zh_TW.tsx +++ b/components/locale/zh_TW.tsx @@ -42,6 +42,7 @@ const localeValues: Locale = { cancelText: '取消', }, Transfer: { + titles: ['', ''], searchPlaceholder: '搜尋資料', itemUnit: '項目', itemsUnit: '項目', diff --git a/components/message/style/index.tsx b/components/message/style/index.tsx index 4a34a9e260..3d15e187ba 100644 --- a/components/message/style/index.tsx +++ b/components/message/style/index.tsx @@ -168,7 +168,7 @@ export default genComponentStyleHook( const combinedToken = mergeToken(token, { messageNoticeContentPadding: `${ (token.controlHeightLG - token.fontSize * token.lineHeight) / 2 - }px ${token.paddingSM}px`, + }px ${token.paddingContentVertical}px`, }); return [genMessageStyle(combinedToken)]; }, diff --git a/components/modal/locale.tsx b/components/modal/locale.tsx index afb40c676b..18db43a7e8 100644 --- a/components/modal/locale.tsx +++ b/components/modal/locale.tsx @@ -1,4 +1,4 @@ -import defaultLocale from '../locale/default'; +import defaultLocale from '../locale/en_US'; export interface ModalLocale { okText: string; diff --git a/components/modal/style/index.tsx b/components/modal/style/index.tsx index 07ac0afe4c..3018064fb3 100644 --- a/components/modal/style/index.tsx +++ b/components/modal/style/index.tsx @@ -165,7 +165,7 @@ const genModalStyle: GenerateStyle = token => { borderRadius: token.radiusLG, boxShadow: token.boxShadowSecondary, pointerEvents: 'auto', - padding: `${token.paddingTmp}px ${token.paddingLG}px`, + padding: `${token.paddingMD}px ${token.paddingContentHorizontalLG}px`, }, [`${componentCls}-close`]: { diff --git a/components/modal/useModal/HookModal.tsx b/components/modal/useModal/HookModal.tsx index 543595d107..e615f8b9bb 100644 --- a/components/modal/useModal/HookModal.tsx +++ b/components/modal/useModal/HookModal.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { ConfigContext } from '../../config-provider'; import LocaleReceiver from '../../locale-provider/LocaleReceiver'; -import defaultLocale from '../../locale/default'; +import defaultLocale from '../../locale/en_US'; import ConfirmDialog from '../ConfirmDialog'; import type { ModalFuncProps } from '../Modal'; diff --git a/components/notification/style/index.tsx b/components/notification/style/index.tsx index 780b0c28b0..36f358764c 100644 --- a/components/notification/style/index.tsx +++ b/components/notification/style/index.tsx @@ -261,7 +261,7 @@ const genNotificationStyle: GenerateStyle = token => { export default genComponentStyleHook( 'Notification', token => { - const notificationPaddingVertical = token.paddingTmp; + const notificationPaddingVertical = token.paddingMD; const notificationPaddingHorizontal = token.paddingLG; const notificationToken = mergeToken(token, { @@ -270,7 +270,7 @@ export default genComponentStyleHook( notificationPaddingVertical, notificationPaddingHorizontal, // index.less variables - notificationPadding: `${notificationPaddingVertical}px ${notificationPaddingHorizontal}px`, + notificationPadding: `${token.paddingMD}px ${token.paddingContentHorizontalLG}px`, notificationMarginBottom: token.margin, notificationMarginEdge: token.marginLG, animationMaxHeight: 150, diff --git a/components/popconfirm/PurePanel.tsx b/components/popconfirm/PurePanel.tsx index 2591c2cca7..4f6dc0397c 100644 --- a/components/popconfirm/PurePanel.tsx +++ b/components/popconfirm/PurePanel.tsx @@ -6,7 +6,7 @@ import Button from '../button'; import { convertLegacyProps } from '../button/button'; import ActionButton from '../_util/ActionButton'; import LocaleReceiver from '../locale-provider/LocaleReceiver'; -import defaultLocale from '../locale/default'; +import defaultLocale from '../locale/en_US'; import { getRenderPropValue } from '../_util/getRenderPropValue'; import { ConfigContext } from '../config-provider'; import PopoverPurePanel from '../popover/PurePanel'; diff --git a/components/popover/style/index.tsx b/components/popover/style/index.tsx index 2151c3ea3e..ed1ef47421 100644 --- a/components/popover/style/index.tsx +++ b/components/popover/style/index.tsx @@ -12,7 +12,7 @@ export interface ComponentToken { export type PopoverToken = FullToken<'Popover'> & { popoverBg: string; popoverColor: string; - popoverPadding: number; + popoverPadding: number | string; }; const genBaseStyle: GenerateStyle = token => { @@ -158,12 +158,12 @@ const genWireframeStyle: GenerateStyle = token => { export default genComponentStyleHook( 'Popover', token => { - const { colorBgElevated, colorText, paddingSM, wireframe } = token; + const { colorBgElevated, colorText, wireframe } = token; const popoverToken = mergeToken(token, { popoverBg: colorBgElevated, popoverColor: colorText, - popoverPadding: paddingSM, + popoverPadding: 12, // Fixed Value }); return [ diff --git a/components/progress/progress.tsx b/components/progress/progress.tsx index 2fb09d1d74..8221dd4592 100644 --- a/components/progress/progress.tsx +++ b/components/progress/progress.tsx @@ -77,7 +77,7 @@ const Progress: React.FC = (props: ProgressProps) => { function getProgressStatus() { const { status } = props; - if (ProgressStatuses.indexOf(status!) < 0 && getPercentNumber() >= 100) { + if (!ProgressStatuses.includes(status!) && getPercentNumber() >= 100) { return 'success'; } return status || 'normal'; @@ -123,7 +123,7 @@ const Progress: React.FC = (props: ProgressProps) => { const strokeColorNotArray = Array.isArray(strokeColor) ? strokeColor[0] : strokeColor; const strokeColorNotGradient = typeof strokeColor === 'string' || Array.isArray(strokeColor) ? strokeColor : undefined; - let progress; + let progress: React.ReactNode; // Render progress shape if (type === 'line') { progress = steps ? ( diff --git a/components/radio/style/index.tsx b/components/radio/style/index.tsx index 959070c522..971bc88aac 100644 --- a/components/radio/style/index.tsx +++ b/components/radio/style/index.tsx @@ -496,7 +496,6 @@ export default genComponentStyleHook('Radio', token => { colorPrimary, marginXS, controlOutlineWidth, - paddingXXS, wireframe, } = token; @@ -506,10 +505,11 @@ export default genComponentStyleHook('Radio', token => { const radioSize = fontSizeLG; const radioTop = (Math.round(fontSize * lineHeight) - radioSize) / 2; - const radioDotDisabledSize = radioSize - paddingXXS * 2; + const dotPadding = 4; // Fixed value + const radioDotDisabledSize = radioSize - dotPadding * 2; const radioDotSize = wireframe ? radioDotDisabledSize - : radioSize - (paddingXXS + controlLineWidth) * 2; + : radioSize - (dotPadding + controlLineWidth) * 2; const radioCheckedColor = colorPrimary; // Radio buttons diff --git a/components/skeleton/Node.tsx b/components/skeleton/Node.tsx index 4183d4dcc6..841fbf63ea 100644 --- a/components/skeleton/Node.tsx +++ b/components/skeleton/Node.tsx @@ -1,6 +1,7 @@ import DotChartOutlined from '@ant-design/icons/DotChartOutlined'; import classNames from 'classnames'; import * as React from 'react'; +import useStyle from './style'; import { ConfigContext } from '../config-provider'; import type { SkeletonElementProps } from './Element'; @@ -13,6 +14,7 @@ const SkeletonNode: React.FC = props => { const { prefixCls: customizePrefixCls, className, style, active, children } = props; const { getPrefixCls } = React.useContext(ConfigContext); const prefixCls = getPrefixCls('skeleton', customizePrefixCls); + const [wrapSSR, hashId] = useStyle(prefixCls); const cls = classNames( prefixCls, @@ -20,17 +22,18 @@ const SkeletonNode: React.FC = props => { { [`${prefixCls}-active`]: active, }, + hashId, className, ); const content = children ?? ; - return ( + return wrapSSR(
{content}
-
+ , ); }; diff --git a/components/slider/style/index.tsx b/components/slider/style/index.tsx index a491c1908e..311d9fc95c 100644 --- a/components/slider/style/index.tsx +++ b/components/slider/style/index.tsx @@ -237,7 +237,7 @@ const genBaseStyle: GenerateStyle = token => { // ============================ Horizontal ============================ const genDirectionStyle = (token: SliderToken, horizontal: boolean): CSSObject => { - const { componentCls, railSize, controlSize, handleSize, dotSize } = token; + const { componentCls, railSize, handleSize, dotSize } = token; const railPadding: keyof React.CSSProperties = horizontal ? 'paddingBlock' : 'paddingInline'; const full: keyof React.CSSProperties = horizontal ? 'width' : 'height'; @@ -247,7 +247,7 @@ const genDirectionStyle = (token: SliderToken, horizontal: boolean): CSSObject = return { [railPadding]: railSize, - [part]: controlSize, + [part]: railSize * 3, [`${componentCls}-rail`]: { [full]: '100%', @@ -259,7 +259,7 @@ const genDirectionStyle = (token: SliderToken, horizontal: boolean): CSSObject = }, [`${componentCls}-handle`]: { - [handlePos]: (controlSize - handleSize) / 2, + [handlePos]: (railSize * 3 - handleSize) / 2, }, [`${componentCls}-mark`]: { @@ -336,7 +336,7 @@ export default genComponentStyleHook( const handleLineWidthHover = token.lineWidth + increaseHandleWidth * 3; return { controlSize, - railSize: controlSize / 3, + railSize: 4, handleSize: controlSize, handleSizeHover: controlSizeHover, dotSize: (controlSize / 3) * 2, diff --git a/components/statistic/utils.tsx b/components/statistic/utils.tsx index 600abbe27f..91027740f4 100644 --- a/components/statistic/utils.tsx +++ b/components/statistic/utils.tsx @@ -41,7 +41,7 @@ export function formatTimeStr(duration: number, format: string) { const templateText = format.replace(escapeRegex, '[]'); const replacedText = timeUnits.reduce((current, [name, unit]) => { - if (current.indexOf(name) !== -1) { + if (current.includes(name)) { const value = Math.floor(leftDuration / unit); leftDuration -= value * unit; return current.replace(new RegExp(`${name}+`, 'g'), (match: string) => { diff --git a/components/steps/style/index.tsx b/components/steps/style/index.tsx index 4e665efa06..1c27164c01 100644 --- a/components/steps/style/index.tsx +++ b/components/steps/style/index.tsx @@ -159,7 +159,7 @@ const genStepsItemStyle: GenerateStyle = token => { }, [`${stepsItemCls}-tail`]: { position: 'absolute', - top: token.marginSM, + top: token.stepsIconSize / 2 - token.lineWidth, insetInlineStart: 0, width: '100%', @@ -347,7 +347,7 @@ export default genComponentStyleHook( stepsIconSize, stepsIconCustomSize: stepsIconSize, stepsIconCustomTop: 0, - stepsIconCustomFontSize: fontSizeHeading3, + stepsIconCustomFontSize: controlHeightLG / 2, stepsIconTop: -0.5, // magic for ui experience stepsIconFontSize: fontSize, stepsTitleLineHeight: controlHeight, diff --git a/components/steps/style/small.ts b/components/steps/style/small.ts index 9ea9150d7b..868792ba0f 100644 --- a/components/steps/style/small.ts +++ b/components/steps/style/small.ts @@ -47,7 +47,7 @@ const genStepsSmallStyle: GenerateStyle = token => { fontSize: fontSizeBase, }, [`${componentCls}-item-tail`]: { - top: token.marginXS, + top: stepsSmallIconSize / 2 - token.lineWidth, }, [`${componentCls}-item-custom ${componentCls}-item-icon`]: { width: 'inherit', diff --git a/components/steps/style/vertical.ts b/components/steps/style/vertical.ts index f9b3c31497..a8ce48f0c9 100644 --- a/components/steps/style/vertical.ts +++ b/components/steps/style/vertical.ts @@ -35,7 +35,7 @@ const genStepsVerticalStyle: GenerateStyle = token => { [`> ${componentCls}-item > ${componentCls}-item-container > ${componentCls}-item-tail`]: { position: 'absolute', top: 0, - insetInlineStart: token.margin, + insetInlineStart: token.stepsIconSize / 2 - token.lineWidth, width: token.lineWidth, height: '100%', padding: `${stepsIconSize + token.marginXXS * 1.5}px 0 ${token.marginXXS * 1.5}px`, @@ -59,7 +59,7 @@ const genStepsVerticalStyle: GenerateStyle = token => { [`${componentCls}-item-tail`]: { position: 'absolute', top: 0, - insetInlineStart: token.marginSM, + insetInlineStart: token.stepsSmallIconSize / 2 - token.lineWidth, padding: `${stepsSmallIconSize + token.marginXXS * 1.5}px 0 ${token.marginXXS * 1.5}px`, }, [`${componentCls}-item-title`]: { diff --git a/components/switch/style/index.tsx b/components/switch/style/index.tsx index 78b94e1bcd..42e7190beb 100644 --- a/components/switch/style/index.tsx +++ b/components/switch/style/index.tsx @@ -226,15 +226,15 @@ const genSwitchInnerStyle: GenerateStyle = token => { [`&:not(${componentCls}-disabled):active`]: { [`&:not(${componentCls}-checked) ${switchInnerCls}`]: { [`${switchInnerCls}-unchecked`]: { - marginInlineStart: token.switchInnerMarginMax + token.marginXXS, - marginInlineEnd: token.switchInnerMarginMin - token.marginXXS, + marginInlineStart: token.switchInnerMarginMax + token.switchPadding * 2, + marginInlineEnd: token.switchInnerMarginMin - token.switchPadding * 2, }, }, [`&${componentCls}-checked ${switchInnerCls}`]: { [`${switchInnerCls}-checked`]: { - marginInlineStart: token.switchInnerMarginMin - token.marginXXS, - marginInlineEnd: token.switchInnerMarginMax + token.marginXXS, + marginInlineStart: token.switchInnerMarginMin - token.switchPadding * 2, + marginInlineEnd: token.switchInnerMarginMax + token.switchPadding * 2, }, }, }, @@ -299,7 +299,7 @@ const genSwitchStyle = (token: SwitchToken): CSSObject => { export default genComponentStyleHook('Switch', token => { const switchHeight = token.fontSize * token.lineHeight; const switchHeightSM = token.controlHeight / 2; - const switchPadding = token.paddingXXS / 2; + const switchPadding = 2; // This is magic const switchPinSize = switchHeight - switchPadding * 2; const switchPinSizeSM = switchHeightSM - switchPadding * 2; @@ -310,14 +310,14 @@ export default genComponentStyleHook('Switch', token => { switchColor: token.colorPrimary, switchDisabledOpacity: token.opacityLoading, switchInnerMarginMin: switchPinSize / 2, - switchInnerMarginMax: switchPinSize + switchPadding + token.paddingXXS, + switchInnerMarginMax: switchPinSize + switchPadding + switchPadding * 2, switchPadding, switchPinSize, switchBg: token.colorBgContainer, switchMinWidthSM: switchPinSizeSM * 2 + switchPadding * 2, switchHeightSM, switchInnerMarginMinSM: switchPinSizeSM / 2, - switchInnerMarginMaxSM: switchPinSizeSM + switchPadding + token.paddingXXS, + switchInnerMarginMaxSM: switchPinSizeSM + switchPadding + switchPadding * 2, switchPinSizeSM, switchHandleShadow: `0 2px 4px 0 ${new TinyColor('#00230b').setAlpha(0.2).toRgbString()}`, switchLoadingIconSize: token.fontSizeIcon * 0.75, diff --git a/components/table/Table.tsx b/components/table/Table.tsx index 53735f4265..929f90f1b5 100644 --- a/components/table/Table.tsx +++ b/components/table/Table.tsx @@ -476,8 +476,8 @@ function InternalTable( const defaultPosition = direction === 'rtl' ? 'left' : 'right'; const { position } = mergedPagination; if (position !== null && Array.isArray(position)) { - const topPos = position.find(p => p.indexOf('top') !== -1); - const bottomPos = position.find(p => p.indexOf('bottom') !== -1); + const topPos = position.find(p => p.includes('top')); + const bottomPos = position.find(p => p.includes('bottom')); const isDisable = position.every(p => `${p}` === 'none'); if (!topPos && !bottomPos && !isDisable) { bottomPaginationNode = renderPagination(defaultPosition); diff --git a/components/table/__tests__/Table.sorter.test.tsx b/components/table/__tests__/Table.sorter.test.tsx index 2509419833..8b0d93c5c5 100644 --- a/components/table/__tests__/Table.sorter.test.tsx +++ b/components/table/__tests__/Table.sorter.test.tsx @@ -108,6 +108,32 @@ describe('Table.sorter', () => { expect(getNameColumn()?.getAttribute('aria-label')).toEqual('Name sortable'); }); + it('aria-label should be use the first text content in element when title is ReactElement', () => { + const { container } = render( + createTable( + { + sortDirections: ['descend', 'ascend'], + }, + { + title: ( + + Name + kiner + + ), + defaultSortOrder: 'descend', + }, + ), + ); + + const getNameColumn = () => container.querySelector('th'); + fireEvent.click(container.querySelector('.ant-table-column-sorters')!); + expect(getNameColumn()?.getAttribute('aria-sort')).toEqual('ascending'); + expect(getNameColumn()?.getAttribute('aria-label')).toEqual(null); + fireEvent.click(container.querySelector('.ant-table-column-sorters')!); + expect(getNameColumn()?.getAttribute('aria-label')).toEqual('Name sortable'); + }); + it('sort records', () => { const { container } = render(createTable()); const getNameColumn = () => container.querySelector('th'); diff --git a/components/table/index.en-US.md b/components/table/index.en-US.md index 2e77029861..bde77f83ba 100644 --- a/components/table/index.en-US.md +++ b/components/table/index.en-US.md @@ -108,33 +108,33 @@ const columns = [ ### Table -| Property | Description | Type | Default | Version | -| --- | --- | --- | --- | --- | -| bordered | Whether to show all table borders | boolean | false | | -| columns | Columns of table | [ColumnsType](#Column)\[] | - | | -| components | Override default table elements | [TableComponents](https://github.com/react-component/table/blob/75ee0064e54a4b3215694505870c9d6c817e9e4a/src/interface.ts#L129) | - | | -| dataSource | Data record array to be displayed | object\[] | - | | -| expandable | Config expandable content | [expandable](#expandable) | - | | -| footer | Table footer renderer | function(currentPageData) | - | | -| getPopupContainer | The render container of dropdowns in table | (triggerNode) => HTMLElement | () => TableHtmlElement | | -| loading | Loading status of table | boolean \| [Spin Props](/components/spin/#API) | false | | -| locale | The i18n text including filter, sort, empty text, etc | object | [Default Value](https://github.com/ant-design/ant-design/blob/6dae4a7e18ad1ba193aedd5ab6867e1d823e2aa4/components/locale/default.tsx#L19-L37) | | -| pagination | Config of pagination. You can ref table pagination [config](#pagination) or full [`pagination`](/components/pagination/) document, hide it by setting it to `false` | object | - | | -| rowClassName | Row's className | function(record, index): string | - | | -| rowKey | Row's unique key, could be a string or function that returns a string | string \| function(record): string | `key` | | -| rowSelection | Row selection [config](#rowSelection) | object | - | | -| scroll | Whether the table can be scrollable, [config](#scroll) | object | - | | -| showHeader | Whether to show table header | boolean | true | | -| showSorterTooltip | The header show next sorter direction tooltip. It will be set as the property of Tooltip if its type is object | boolean \| [Tooltip props](/components/tooltip/#API) | true | | -| size | Size of table | `default` \| `middle` \| `small` | `default` | | -| sortDirections | Supported sort way, could be `ascend`, `descend` | Array | \[`ascend`, `descend`] | | -| sticky | Set sticky header and scroll bar | boolean \| `{offsetHeader?: number, offsetScroll?: number, getContainer?: () => HTMLElement}` | - | 4.6.0 (getContainer: 4.7.0) | -| summary | Summary content | (currentData) => ReactNode | - | | -| tableLayout | The [table-layout](https://developer.mozilla.org/en-US/docs/Web/CSS/table-layout) attribute of table element | - \| `auto` \| `fixed` | -
`fixed` when header/columns are fixed, or using `column.ellipsis` | | -| title | Table title renderer | function(currentPageData) | - | | -| onChange | Callback executed when pagination, filters or sorter is changed | function(pagination, filters, sorter, extra: { currentDataSource: \[], action: `paginate` \| `sort` \| `filter` }) | - | | -| onHeaderRow | Set props on per header row | function(columns, index) | - | | -| onRow | Set props on per row | function(record, index) | - | | +| Property | Description | Type | Default | Version | +| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------- | +| bordered | Whether to show all table borders | boolean | false | | +| columns | Columns of table | [ColumnsType](#Column)\[] | - | | +| components | Override default table elements | [TableComponents](https://github.com/react-component/table/blob/75ee0064e54a4b3215694505870c9d6c817e9e4a/src/interface.ts#L129) | - | | +| dataSource | Data record array to be displayed | object\[] | - | | +| expandable | Config expandable content | [expandable](#expandable) | - | | +| footer | Table footer renderer | function(currentPageData) | - | | +| getPopupContainer | The render container of dropdowns in table | (triggerNode) => HTMLElement | () => TableHtmlElement | | +| loading | Loading status of table | boolean \| [Spin Props](/components/spin/#API) | false | | +| locale | The i18n text including filter, sort, empty text, etc | object | [Default Value](https://github.com/ant-design/ant-design/blob/6dae4a7e18ad1ba193aedd5ab6867e1d823e2aa4/components/locale/en_US.tsx#L19-L37) | | +| pagination | Config of pagination. You can ref table pagination [config](#pagination) or full [`pagination`](/components/pagination/) document, hide it by setting it to `false` | object | - | | +| rowClassName | Row's className | function(record, index): string | - | | +| rowKey | Row's unique key, could be a string or function that returns a string | string \| function(record): string | `key` | | +| rowSelection | Row selection [config](#rowSelection) | object | - | | +| scroll | Whether the table can be scrollable, [config](#scroll) | object | - | | +| showHeader | Whether to show table header | boolean | true | | +| showSorterTooltip | The header show next sorter direction tooltip. It will be set as the property of Tooltip if its type is object | boolean \| [Tooltip props](/components/tooltip/#API) | true | | +| size | Size of table | `default` \| `middle` \| `small` | `default` | | +| sortDirections | Supported sort way, could be `ascend`, `descend` | Array | \[`ascend`, `descend`] | | +| sticky | Set sticky header and scroll bar | boolean \| `{offsetHeader?: number, offsetScroll?: number, getContainer?: () => HTMLElement}` | - | 4.6.0 (getContainer: 4.7.0) | +| summary | Summary content | (currentData) => ReactNode | - | | +| tableLayout | The [table-layout](https://developer.mozilla.org/en-US/docs/Web/CSS/table-layout) attribute of table element | - \| `auto` \| `fixed` | -
`fixed` when header/columns are fixed, or using `column.ellipsis` | | +| title | Table title renderer | function(currentPageData) | - | | +| onChange | Callback executed when pagination, filters or sorter is changed | function(pagination, filters, sorter, extra: { currentDataSource: \[], action: `paginate` \| `sort` \| `filter` }) | - | | +| onHeaderRow | Set props on per header row | function(columns, index) | - | | +| onRow | Set props on per row | function(record, index) | - | | #### onRow usage @@ -163,40 +163,40 @@ Same as `onRow` `onHeaderRow` `onCell` `onHeaderCell` One of the Table `columns` prop for describing the table's columns, Column has the same API. -| Property | Description | Type | Default | Version | -| --- | --- | --- | --- | --- | -| align | The specify which way that column is aligned | `left` \| `right` \| `center` | `left` | | -| className | The className of this column | string | - | | -| colSpan | Span of this column's title | number | - | | -| dataIndex | Display field of the data record, support nest path by string array | string \| string\[] | - | | -| defaultFilteredValue | Default filtered values | string\[] | - | | -| filterResetToDefaultFilteredValue | click the reset button, whether to restore the default filter | boolean | false | | -| defaultSortOrder | Default order of sorted values | `ascend` \| `descend` | - | | -| ellipsis | The ellipsis cell content, not working with sorter and filters for now.
tableLayout would be `fixed` when `ellipsis` is `true` or `{ showTitle?: boolean }` | boolean \| {showTitle?: boolean } | false | showTitle: 4.3.0 | -| filterDropdown | Customized filter overlay | ReactNode \| (props: [FilterDropdownProps](https://github.com/ant-design/ant-design/blob/ecc54dda839619e921c0ace530408871f0281c2a/components/table/interface.tsx#L79)) => ReactNode | - | | -| filterDropdownOpen | Whether `filterDropdown` is visible | boolean | - | | -| filtered | Whether the `dataSource` is filtered | boolean | false | | -| filteredValue | Controlled filtered value, filter icon will highlight | string\[] | - | | -| filterIcon | Customized filter icon | ReactNode \| (filtered: boolean) => ReactNode | - | | -| filterMultiple | Whether multiple filters can be selected | boolean | true | | -| filterMode | To specify the filter interface | 'menu' \| 'tree' | 'menu' | 4.17.0 | -| filterSearch | Whether to be searchable for filter menu | boolean \| function(input, record):boolean | false | boolean:4.17.0 function:4.19.0 | -| filters | Filter menu config | object\[] | - | | -| fixed | (IE not support) Set column to be fixed: `true`(same as left) `'left'` `'right'` | boolean \| string | false | | -| key | Unique key of this column, you can ignore this prop if you've set a unique `dataIndex` | string | - | | -| render | Renderer of the table cell. The return value should be a ReactNode | function(text, record, index) {} | - | | -| responsive | The list of breakpoints at which to display this column. Always visible if not set. | [Breakpoint](https://github.com/ant-design/ant-design/blob/015109b42b85c63146371b4e32b883cf97b088e8/components/_util/responsiveObserve.ts#L1)\[] | - | 4.2.0 | -| shouldCellUpdate | Control cell render logic | (record, prevRecord) => boolean | - | 4.3.0 | -| showSorterTooltip | If header show next sorter direction tooltip, override `showSorterTooltip` in table | boolean \| [Tooltip props](/components/tooltip/) | true | | -| sortDirections | Supported sort way, override `sortDirections` in `Table`, could be `ascend`, `descend` | Array | \[`ascend`, `descend`] | | -| sorter | Sort function for local sort, see [Array.sort](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort)'s compareFunction. If you need sort buttons only, set to `true` | function \| boolean | - | | -| sortOrder | Order of sorted values: `ascend` `descend` `null` | `ascend` \| `descend` \| null | - | | -| title | Title of this column | ReactNode \| ({ sortOrder, sortColumn, filters }) => ReactNode | - | | -| width | Width of this column ([width not working?](https://github.com/ant-design/ant-design/issues/13825#issuecomment-449889241)) | string \| number | - | | -| onCell | Set props on per cell | function(record, rowIndex) | - | | -| onFilter | Function that determines if the row is displayed when filtered | function(value, record) => boolean | - | | -| onFilterDropdownOpenChange | Callback executed when `filterDropdownOpen` is changed | function(visible) {} | - | | -| onHeaderCell | Set props on per header cell | function(column) | - | | +| Property | Description | Type | Default | Version | +| --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- | ------------------------------ | +| align | The specify which way that column is aligned | `left` \| `right` \| `center` | `left` | | +| className | The className of this column | string | - | | +| colSpan | Span of this column's title | number | - | | +| dataIndex | Display field of the data record, support nest path by string array | string \| string\[] | - | | +| defaultFilteredValue | Default filtered values | string\[] | - | | +| filterResetToDefaultFilteredValue | click the reset button, whether to restore the default filter | boolean | false | | +| defaultSortOrder | Default order of sorted values | `ascend` \| `descend` | - | | +| ellipsis | The ellipsis cell content, not working with sorter and filters for now.
tableLayout would be `fixed` when `ellipsis` is `true` or `{ showTitle?: boolean }` | boolean \| {showTitle?: boolean } | false | showTitle: 4.3.0 | +| filterDropdown | Customized filter overlay | ReactNode \| (props: [FilterDropdownProps](https://github.com/ant-design/ant-design/blob/ecc54dda839619e921c0ace530408871f0281c2a/components/table/interface.tsx#L79)) => ReactNode | - | | +| filterDropdownOpen | Whether `filterDropdown` is visible | boolean | - | | +| filtered | Whether the `dataSource` is filtered | boolean | false | | +| filteredValue | Controlled filtered value, filter icon will highlight | string\[] | - | | +| filterIcon | Customized filter icon | ReactNode \| (filtered: boolean) => ReactNode | - | | +| filterMultiple | Whether multiple filters can be selected | boolean | true | | +| filterMode | To specify the filter interface | 'menu' \| 'tree' | 'menu' | 4.17.0 | +| filterSearch | Whether to be searchable for filter menu | boolean \| function(input, record):boolean | false | boolean:4.17.0 function:4.19.0 | +| filters | Filter menu config | object\[] | - | | +| fixed | (IE not support) Set column to be fixed: `true`(same as left) `'left'` `'right'` | boolean \| string | false | | +| key | Unique key of this column, you can ignore this prop if you've set a unique `dataIndex` | string | - | | +| render | Renderer of the table cell. The return value should be a ReactNode | function(text, record, index) {} | - | | +| responsive | The list of breakpoints at which to display this column. Always visible if not set. | [Breakpoint](https://github.com/ant-design/ant-design/blob/015109b42b85c63146371b4e32b883cf97b088e8/components/_util/responsiveObserve.ts#L1)\[] | - | 4.2.0 | +| shouldCellUpdate | Control cell render logic | (record, prevRecord) => boolean | - | 4.3.0 | +| showSorterTooltip | If header show next sorter direction tooltip, override `showSorterTooltip` in table | boolean \| [Tooltip props](/components/tooltip/) | true | | +| sortDirections | Supported sort way, override `sortDirections` in `Table`, could be `ascend`, `descend` | Array | \[`ascend`, `descend`] | | +| sorter | Sort function for local sort, see [Array.sort](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort)'s compareFunction. If you need sort buttons only, set to `true` | function \| boolean | - | | +| sortOrder | Order of sorted values: `ascend` `descend` `null` | `ascend` \| `descend` \| null | - | | +| title | Title of this column | ReactNode \| ({ sortOrder, sortColumn, filters }) => ReactNode | - | | +| width | Width of this column ([width not working?](https://github.com/ant-design/ant-design/issues/13825#issuecomment-449889241)) | string \| number | - | | +| onCell | Set props on per cell | function(record, rowIndex) | - | | +| onFilter | Function that determines if the row is displayed when filtered | function(value, record) => boolean | - | | +| onFilterDropdownOpenChange | Callback executed when `filterDropdownOpen` is changed | function(visible) {} | - | | +| onHeaderCell | Set props on per header cell | function(column) | - | | ### ColumnGroup @@ -208,8 +208,8 @@ One of the Table `columns` prop for describing the table's columns, Column has t Properties for pagination. -| Property | Description | Type | Default | -| --- | --- | --- | --- | +| Property | Description | Type | Default | +| -------- | -------------------------------------------------------------------------------------------------------------------------------------- | ----- | ---------------- | | position | Specify the position of `Pagination`, could be`topLeft` \| `topCenter` \| `topRight` \|`bottomLeft` \| `bottomCenter` \| `bottomRight` | Array | \[`bottomRight`] | More about pagination, please check [`Pagination`](/components/pagination/). @@ -218,64 +218,64 @@ More about pagination, please check [`Pagination`](/components/pagination/). Properties for expandable. -| Property | Description | Type | Default | Version | -| --- | --- | --- | --- | --- | -| childrenColumnName | The column contains children to display | string | children | | -| columnTitle | Set the title of the expand column | ReactNode | - | 4.23.0 | -| columnWidth | Set the width of the expand column | string \| number | - | | -| defaultExpandAllRows | Expand all rows initially | boolean | false | | -| defaultExpandedRowKeys | Initial expanded row keys | string\[] | - | | -| expandedRowClassName | Expanded row's className | function(record, index, indent): string | - | | -| expandedRowKeys | Current expanded row keys | string\[] | - | | -| expandedRowRender | Expanded container render for each row | function(record, index, indent, expanded): ReactNode | - | | -| expandIcon | Customize row expand Icon. Ref [example](https://codesandbox.io/s/fervent-bird-nuzpr) | function(props): ReactNode | - | | -| expandRowByClick | Whether to expand row by clicking anywhere in the whole row | boolean | false | | -| fixed | Whether the expansion icon is fixed. Optional true `left` `right` | boolean \| string | false | 4.16.0 | -| indentSize | Indent size in pixels of tree data | number | 15 | | -| rowExpandable | Enable row can be expandable | (record) => boolean | - | | -| showExpandColumn | Show expand column | boolean | true | 4.18.0 | -| onExpand | Callback executed when the row expand icon is clicked | function(expanded, record) | - | | -| onExpandedRowsChange | Callback executed when the expanded rows change | function(expandedRows) | - | | +| Property | Description | Type | Default | Version | +| ---------------------- | ------------------------------------------------------------------------------------- | ---------------------------------------------------- | -------- | ------- | +| childrenColumnName | The column contains children to display | string | children | | +| columnTitle | Set the title of the expand column | ReactNode | - | 4.23.0 | +| columnWidth | Set the width of the expand column | string \| number | - | | +| defaultExpandAllRows | Expand all rows initially | boolean | false | | +| defaultExpandedRowKeys | Initial expanded row keys | string\[] | - | | +| expandedRowClassName | Expanded row's className | function(record, index, indent): string | - | | +| expandedRowKeys | Current expanded row keys | string\[] | - | | +| expandedRowRender | Expanded container render for each row | function(record, index, indent, expanded): ReactNode | - | | +| expandIcon | Customize row expand Icon. Ref [example](https://codesandbox.io/s/fervent-bird-nuzpr) | function(props): ReactNode | - | | +| expandRowByClick | Whether to expand row by clicking anywhere in the whole row | boolean | false | | +| fixed | Whether the expansion icon is fixed. Optional true `left` `right` | boolean \| string | false | 4.16.0 | +| indentSize | Indent size in pixels of tree data | number | 15 | | +| rowExpandable | Enable row can be expandable | (record) => boolean | - | | +| showExpandColumn | Show expand column | boolean | true | 4.18.0 | +| onExpand | Callback executed when the row expand icon is clicked | function(expanded, record) | - | | +| onExpandedRowsChange | Callback executed when the expanded rows change | function(expandedRows) | - | | ### rowSelection Properties for row selection. -| Property | Description | Type | Default | Version | -| --- | --- | --- | --- | --- | -| checkStrictly | Check table row precisely; parent row and children rows are not associated | boolean | true | 4.4.0 | -| columnTitle | Set the title of the selection column | ReactNode | - | | -| columnWidth | Set the width of the selection column | string \| number | `32px` | | -| fixed | Fixed selection column on the left | boolean | - | | -| getCheckboxProps | Get Checkbox or Radio props | function(record) | - | | -| hideSelectAll | Hide the selectAll checkbox and custom selection | boolean | false | 4.3.0 | -| preserveSelectedRowKeys | Keep selection `key` even when it removed from `dataSource` | boolean | - | 4.4.0 | -| renderCell | Renderer of the table cell. Same as `render` in column | function(checked, record, index, originNode) {} | - | 4.1.0 | -| selectedRowKeys | Controlled selected row keys | string\[] \| number\[] | \[] | | -| selections | Custom selection [config](#selection), only displays default selections when set to `true` | object\[] \| boolean | - | | -| type | `checkbox` or `radio` | `checkbox` \| `radio` | `checkbox` | | -| onChange | Callback executed when selected rows change | function(selectedRowKeys, selectedRows, info: { type }) | - | `info.type`: 4.21.0 | -| onSelect | Callback executed when select/deselect one row | function(record, selected, selectedRows, nativeEvent) | - | | -| onSelectAll | Callback executed when select/deselect all rows | function(selected, selectedRows, changeRows) | - | | -| onSelectInvert | Callback executed when row selection is inverted | function(selectedRowKeys) | - | | -| onSelectNone | Callback executed when row selection is cleared | function() | - | | -| onSelectMultiple | Callback executed when row selection is changed by pressing shift | function(selected, selectedRows, changeRows) | - | | +| Property | Description | Type | Default | Version | +| ----------------------- | ------------------------------------------------------------------------------------------ | ------------------------------------------------------- | ---------- | ------------------- | +| checkStrictly | Check table row precisely; parent row and children rows are not associated | boolean | true | 4.4.0 | +| columnTitle | Set the title of the selection column | ReactNode | - | | +| columnWidth | Set the width of the selection column | string \| number | `32px` | | +| fixed | Fixed selection column on the left | boolean | - | | +| getCheckboxProps | Get Checkbox or Radio props | function(record) | - | | +| hideSelectAll | Hide the selectAll checkbox and custom selection | boolean | false | 4.3.0 | +| preserveSelectedRowKeys | Keep selection `key` even when it removed from `dataSource` | boolean | - | 4.4.0 | +| renderCell | Renderer of the table cell. Same as `render` in column | function(checked, record, index, originNode) {} | - | 4.1.0 | +| selectedRowKeys | Controlled selected row keys | string\[] \| number\[] | \[] | | +| selections | Custom selection [config](#selection), only displays default selections when set to `true` | object\[] \| boolean | - | | +| type | `checkbox` or `radio` | `checkbox` \| `radio` | `checkbox` | | +| onChange | Callback executed when selected rows change | function(selectedRowKeys, selectedRows, info: { type }) | - | `info.type`: 4.21.0 | +| onSelect | Callback executed when select/deselect one row | function(record, selected, selectedRows, nativeEvent) | - | | +| onSelectAll | Callback executed when select/deselect all rows | function(selected, selectedRows, changeRows) | - | | +| onSelectInvert | Callback executed when row selection is inverted | function(selectedRowKeys) | - | | +| onSelectNone | Callback executed when row selection is cleared | function() | - | | +| onSelectMultiple | Callback executed when row selection is changed by pressing shift | function(selected, selectedRows, changeRows) | - | | ### scroll -| Property | Description | Type | Default | -| --- | --- | --- | --- | -| scrollToFirstRowOnChange | Whether to scroll to the top of the table when paging, sorting, filtering changes | boolean | - | -| x | Set horizontal scrolling, can also be used to specify the width of the scroll area, could be number, percent value, true and ['max-content'](https://developer.mozilla.org/zh-CN/docs/Web/CSS/width#max-content) | string \| number \| true | - | -| y | Set vertical scrolling, can also be used to specify the height of the scroll area, could be string or number | string \| number | - | +| Property | Description | Type | Default | +| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------ | ------- | +| scrollToFirstRowOnChange | Whether to scroll to the top of the table when paging, sorting, filtering changes | boolean | - | +| x | Set horizontal scrolling, can also be used to specify the width of the scroll area, could be number, percent value, true and ['max-content'](https://developer.mozilla.org/zh-CN/docs/Web/CSS/width#max-content) | string \| number \| true | - | +| y | Set vertical scrolling, can also be used to specify the height of the scroll area, could be string or number | string \| number | - | ### selection -| Property | Description | Type | Default | -| --- | --- | --- | --- | -| key | Unique key of this selection | string | - | -| text | Display text of this selection | ReactNode | - | -| onSelect | Callback executed when this selection is clicked | function(changeableRowKeys) | - | +| Property | Description | Type | Default | +| -------- | ------------------------------------------------ | --------------------------- | ------- | +| key | Unique key of this selection | string | - | +| text | Display text of this selection | ReactNode | - | +| onSelect | Callback executed when this selection is clicked | function(changeableRowKeys) | - | ## Using in TypeScript diff --git a/components/table/style/expand.tsx b/components/table/style/expand.tsx index f7772c2948..3eeb1b200f 100644 --- a/components/table/style/expand.tsx +++ b/components/table/style/expand.tsx @@ -10,7 +10,6 @@ const genExpandStyle: GenerateStyle = token => { controlInteractiveSize: checkboxSize, motionDurationSlow, controlLineWidth, - paddingXXS, paddingXS, controlLineType, tableBorderColor, @@ -24,6 +23,7 @@ const genExpandStyle: GenerateStyle = token => { tablePaddingVertical, tablePaddingHorizontal, tableExpandedRowBg, + paddingXXS, } = token; const halfInnerSize = checkboxSize / 2 - controlLineWidth; // must be odd number, unless it cannot align center diff --git a/components/table/style/index.tsx b/components/table/style/index.tsx index 62c3896cfa..02ea45b971 100644 --- a/components/table/style/index.tsx +++ b/components/table/style/index.tsx @@ -90,6 +90,7 @@ const genTableStyle: GenerateStyle = token => { tableSelectedRowHoverBg, tableFooterTextColor, tableFooterBg, + paddingContentVerticalLG, wireframe, } = token; const tableBorder = `${controlLineWidth}px ${controlLineType} ${tableBorderColor}`; @@ -122,7 +123,7 @@ const genTableStyle: GenerateStyle = token => { tfoot > tr > td `]: { position: 'relative', - padding: `${tablePaddingVertical}px ${tablePaddingHorizontal}px`, + padding: `${paddingContentVerticalLG}px ${tablePaddingHorizontal}px`, overflowWrap: 'break-word', }, diff --git a/components/table/util.ts b/components/table/util.ts index 4a355c1ef7..e6394f186e 100644 --- a/components/table/util.ts +++ b/components/table/util.ts @@ -1,4 +1,5 @@ /* eslint-disable import/prefer-default-export */ +import React from 'react'; import type { ColumnTitle, ColumnTitleProps, ColumnType, Key } from './interface'; export function getColumnKey(column: ColumnType, defaultKey: string): Key { @@ -16,6 +17,22 @@ export function getColumnPos(index: number, pos?: string) { return pos ? `${pos}-${index}` : `${index}`; } +/** + * Get first text content in Element + * + * @param node + * @returns + */ +function getElementFirstTextContent(node: React.ReactElement): string { + if (!node || !node.props || !node.props.children) return ''; + if (typeof node.props.children === 'string') return node.props.children; + return ( + node.props.children?.map?.((item: React.ReactElement) => + getElementFirstTextContent(item), + )?.[0] || '' + ); +} + export function renderColumnTitle( title: ColumnTitle, props: ColumnTitleProps, @@ -23,6 +40,12 @@ export function renderColumnTitle( if (typeof title === 'function') { return title(props); } + // fix: #38155 + if (React.isValidElement(title)) { + // if title is a React Element, we should get first text content as result, + // if there has not text content in React Element, return origin title + return getElementFirstTextContent(title) || title; + } return title; } diff --git a/components/tabs/style/index.tsx b/components/tabs/style/index.tsx index 6f8e7c8a2e..407c2eb4fb 100644 --- a/components/tabs/style/index.tsx +++ b/components/tabs/style/index.tsx @@ -880,7 +880,7 @@ export default genComponentStyleHook( }px ${token.padding}px`, tabsCardHeight, tabsCardGutter: token.marginXXS / 2, - tabsHorizontalGutter: token.marginXL, + tabsHorizontalGutter: 32, // Fixed Value tabsCardHeadBackground: token.colorFillAlter, dropdownEdgeChildVerticalPadding: token.paddingXXS, tabsActiveTextShadow: '0 0 0.25px currentcolor', diff --git a/components/tag/style/index.tsx b/components/tag/style/index.tsx index 877687f489..58b5b69b75 100644 --- a/components/tag/style/index.tsx +++ b/components/tag/style/index.tsx @@ -5,12 +5,15 @@ import { genComponentStyleHook, mergeToken, PresetColors } from '../../theme'; import capitalize from '../../_util/capitalize'; import { resetComponent } from '../../style'; +export interface ComponentToken {} + interface TagToken extends FullToken<'Tag'> { tagFontSize: number; tagLineHeight: React.CSSProperties['lineHeight']; tagDefaultBg: string; tagDefaultColor: string; tagIconSize: number; + tagPaddingHorizontal: number; } // ============================== Styles ============================== @@ -55,8 +58,8 @@ const genTagColorStyle = (token: TagToken): CSSInterpolation => }, {} as CSSObject); const genBaseStyle = (token: TagToken): CSSInterpolation => { - const { paddingXS, paddingXXS, controlLineWidth } = token; - const paddingInline = paddingXS - controlLineWidth; + const { paddingXXS, controlLineWidth, tagPaddingHorizontal } = token; + const paddingInline = tagPaddingHorizontal - controlLineWidth; const iconMarginInline = paddingXXS - controlLineWidth; return { @@ -160,6 +163,7 @@ export default genComponentStyleHook('Tag', token => { tagDefaultBg, tagDefaultColor, tagIconSize: fontSizeIcon - 2 * controlLineWidth, // Tag icon is much more smaller + tagPaddingHorizontal: 8, // Fixed padding. }); return [ diff --git a/components/theme/export.ts b/components/theme/export.ts index 1a6764f0fc..8edce6e437 100644 --- a/components/theme/export.ts +++ b/components/theme/export.ts @@ -2,6 +2,7 @@ import { useToken as useInternalToken, defaultConfig } from '.'; import defaultAlgorithm from './themes/default'; import darkAlgorithm from './themes/dark'; +import compactAlgorithm from './themes/compact'; import { defaultAlgorithmV4, darkAlgorithmV4 } from './themes/v4'; // ZombieJ: We export as object to user but array in internal. @@ -23,4 +24,5 @@ export default { darkAlgorithm, defaultAlgorithmV4, darkAlgorithmV4, + compactAlgorithm, }; diff --git a/components/theme/interface.ts b/components/theme/interface.ts index a350c4e268..16a6017b7c 100644 --- a/components/theme/interface.ts +++ b/components/theme/interface.ts @@ -6,9 +6,11 @@ import type { ComponentToken as BackTopComponentToken } from '../back-top/style' import type { ComponentToken as ButtonComponentToken } from '../button/style'; import type { ComponentToken as FloatButtonComponentToken } from '../float-button/style'; import type { ComponentToken as CalendarComponentToken } from '../calendar/style'; +import type { ComponentToken as CardComponentToken } from '../card/style'; import type { ComponentToken as CarouselComponentToken } from '../carousel/style'; import type { ComponentToken as CascaderComponentToken } from '../cascader/style'; import type { ComponentToken as CheckboxComponentToken } from '../checkbox/style'; +import type { ComponentToken as CollapseComponentToken } from '../collapse/style'; import type { ComponentToken as DatePickerComponentToken } from '../date-picker/style'; import type { ComponentToken as DividerComponentToken } from '../divider/style'; import type { ComponentToken as DropdownComponentToken } from '../dropdown/style'; @@ -38,6 +40,7 @@ import type { ComponentToken as SpinComponentToken } from '../spin/style'; import type { ComponentToken as StepsComponentToken } from '../steps/style'; import type { ComponentToken as TableComponentToken } from '../table/style'; import type { ComponentToken as TabsComponentToken } from '../tabs/style'; +import type { ComponentToken as TagComponentToken } from '../tag/style'; import type { ComponentToken as TimelineComponentToken } from '../timeline/style'; import type { ComponentToken as TooltipComponentToken } from '../tooltip/style'; import type { ComponentToken as TransferComponentToken } from '../transfer/style'; @@ -79,10 +82,11 @@ export interface ComponentTokenMap { Badge?: {}; Button?: ButtonComponentToken; Breadcrumb?: {}; + Card?: CardComponentToken; Carousel?: CarouselComponentToken; Cascader?: CascaderComponentToken; Checkbox?: CheckboxComponentToken; - Collapse?: {}; + Collapse?: CollapseComponentToken; DatePicker?: DatePickerComponentToken; Descriptions?: {}; Divider?: DividerComponentToken; @@ -112,7 +116,7 @@ export interface ComponentTokenMap { Spin?: SpinComponentToken; Statistic?: {}; Switch?: {}; - Tag?: {}; + Tag?: TagComponentToken; Tree?: {}; TreeSelect?: {}; Typography?: TypographyComponentToken; @@ -120,7 +124,6 @@ export interface ComponentTokenMap { Transfer?: TransferComponentToken; Tabs?: TabsComponentToken; Calendar?: CalendarComponentToken; - Card?: {}; Steps?: StepsComponentToken; Menu?: MenuComponentToken; Modal?: ModalComponentToken; @@ -159,10 +162,6 @@ export interface SeedToken extends PresetColorType { fontFamily: string; fontSizeBase: number; - // Grid - gridUnit: number; - gridBaseStep: number; - // Line /** Border width of base components */ lineWidth: number; @@ -296,24 +295,25 @@ export interface ColorMapToken extends NeutralColorMapToken { colorBgMask: string; } +export interface SizeMapToken { + // Size + sizeXXL: number; + sizeXL: number; + sizeLG: number; + sizeMD: number; + /** Same as size by default, but can be larger in compact mode */ + sizeMS: number; + size: number; + sizeSM: number; + sizeXS: number; + sizeXXS: number; +} + export interface CommonMapToken { // Font fontSizes: number[]; lineHeights: number[]; - // Size - sizeSpace: number; - sizeSpaceXS: number; - sizeSpaceXXS: number; - sizeSpaceSM: number; - - // Grid - gridSpaceSM: number; - gridSpaceBase: number; - gridSpaceLG: number; - gridSpaceXL: number; - gridSpaceXXL: number; - // Line lineWidthBold: number; @@ -339,7 +339,12 @@ export interface CommonMapToken { // == Map Token == // ====================================================================== // 🔥🔥🔥🔥🔥🔥🔥 DO NOT MODIFY THIS. PLEASE CONTACT DESIGNER. 🔥🔥🔥🔥🔥🔥🔥 -export interface MapToken extends SeedToken, ColorPalettes, ColorMapToken, CommonMapToken {} +export interface MapToken + extends SeedToken, + ColorPalettes, + ColorMapToken, + SizeMapToken, + CommonMapToken {} // ====================================================================== // == Alias Token == @@ -422,11 +427,35 @@ export interface AliasToken extends MapToken { controlInteractiveSize: number; controlItemBgActiveDisabled: string; // Note. It also is a color - // =============== Legacy: should be remove =============== - opacityLoading: number; - + // Padding + paddingXXS: number; + paddingXS: number; + paddingSM: number; padding: number; + paddingMD: number; + paddingLG: number; + paddingXL: number; + + // Padding Content + paddingContentHorizontalLG: number; + paddingContentHorizontal: number; + paddingContentHorizontalSM: number; + paddingContentVerticalLG: number; + paddingContentVertical: number; + paddingContentVerticalSM: number; + + // Margin + marginXXS: number; + marginXS: number; + marginSM: number; margin: number; + marginMD: number; + marginLG: number; + marginXL: number; + marginXXL: number; + + // =============== Legacy: should be remove =============== + opacityLoading: number; boxShadow: string; boxShadowSecondary: string; @@ -438,20 +467,6 @@ export interface AliasToken extends MapToken { controlPaddingHorizontal: number; controlPaddingHorizontalSM: number; - paddingSM: number; - paddingXS: number; - paddingXXS: number; - paddingLG: number; - paddingXL: number; - paddingTmp: number; - marginXXS: number; - marginXS: number; - marginSM: number; - marginLG: number; - marginXL: number; - marginXXL: number; - marginTmp: number; - // Media queries breakpoints screenXS: number; screenXSMin: number; diff --git a/components/theme/themes/compact/genCompactSizeMapToken.ts b/components/theme/themes/compact/genCompactSizeMapToken.ts new file mode 100644 index 0000000000..454f114bb5 --- /dev/null +++ b/components/theme/themes/compact/genCompactSizeMapToken.ts @@ -0,0 +1,17 @@ +import type { SeedToken, SizeMapToken } from '../../interface'; + +export default function genSizeMapToken(token: SeedToken): SizeMapToken { + const { sizeUnit, sizeBaseStep } = token; + + return { + sizeXXL: sizeUnit * (sizeBaseStep + 10), + sizeXL: sizeUnit * (sizeBaseStep + 6), + sizeLG: sizeUnit * (sizeBaseStep + 2), + sizeMD: sizeUnit * (sizeBaseStep + 2), + sizeMS: sizeUnit * (sizeBaseStep + 1), + size: sizeUnit * sizeBaseStep, + sizeSM: sizeUnit * sizeBaseStep, + sizeXS: sizeUnit * (sizeBaseStep - 1), + sizeXXS: sizeUnit * (sizeBaseStep - 1), + }; +} diff --git a/components/theme/themes/compact/index.ts b/components/theme/themes/compact/index.ts new file mode 100644 index 0000000000..5eba1b6593 --- /dev/null +++ b/components/theme/themes/compact/index.ts @@ -0,0 +1,15 @@ +import type { DerivativeFunc } from '@ant-design/cssinjs'; +import type { SeedToken, MapToken } from '../../interface'; +import defaultAlgorithm from '../default'; +import genCompactSizeMapToken from './genCompactSizeMapToken'; + +const derivative: DerivativeFunc = (token, mapToken) => { + const mergedMapToken = mapToken ?? defaultAlgorithm(token); + + return { + ...mergedMapToken, + ...genCompactSizeMapToken(token), + }; +}; + +export default derivative; diff --git a/components/theme/themes/dark/index.ts b/components/theme/themes/dark/index.ts index f8cf6a2a19..8c719fcb3e 100644 --- a/components/theme/themes/dark/index.ts +++ b/components/theme/themes/dark/index.ts @@ -3,8 +3,8 @@ import type { DerivativeFunc } from '@ant-design/cssinjs'; import type { ColorPalettes, MapToken, PresetColorType, SeedToken } from '../../interface'; import { defaultPresetColors } from '../seed'; import genColorMapToken from '../shared/genColorMapToken'; -import genCommonMapToken from '../shared/genCommonMapToken'; import { generateColorPalettes, generateNeutralColorPalettes } from './colors'; +import defaultAlgorithm from '../default'; const derivative: DerivativeFunc = (token, mapToken) => { const colorPalettes = Object.keys(defaultPresetColors) @@ -24,11 +24,10 @@ const derivative: DerivativeFunc = (token, mapToken) => { return prev; }, {} as ColorPalettes); - return { - ...token, + const mergedMapToken = mapToken ?? defaultAlgorithm(token); - // Other tokens - ...(mapToken ?? genCommonMapToken(token)), + return { + ...mergedMapToken, // Dark tokens ...colorPalettes, diff --git a/components/theme/themes/default/index.ts b/components/theme/themes/default/index.ts index d6ef507623..7686415d95 100644 --- a/components/theme/themes/default/index.ts +++ b/components/theme/themes/default/index.ts @@ -1,4 +1,5 @@ import { generate } from '@ant-design/colors'; +import genSizeMapToken from '../shared/genSizeMapToken'; import type { ColorPalettes, MapToken, PresetColorType, SeedToken } from '../../interface'; import { defaultPresetColors } from '../seed'; import genColorMapToken from '../shared/genColorMapToken'; @@ -31,7 +32,9 @@ export default function derivative(token: SeedToken): MapToken { generateColorPalettes, generateNeutralColorPalettes, }), - + // Size + ...genSizeMapToken(token), + // Others ...genCommonMapToken(token), }; } diff --git a/components/theme/themes/seed.ts b/components/theme/themes/seed.ts index e690a44b94..70b1bc61e2 100644 --- a/components/theme/themes/seed.ts +++ b/components/theme/themes/seed.ts @@ -37,10 +37,6 @@ const seedToken: SeedToken = { 'Noto Color Emoji'`, fontSizeBase: 14, - // Grid - gridUnit: 4, - gridBaseStep: 2, - // Line lineWidth: 1, lineType: 'solid', diff --git a/components/theme/themes/shared/genCommonMapToken.ts b/components/theme/themes/shared/genCommonMapToken.ts index dd6da8f301..57ceb93f16 100644 --- a/components/theme/themes/shared/genCommonMapToken.ts +++ b/components/theme/themes/shared/genCommonMapToken.ts @@ -3,24 +3,13 @@ import genFontSizes from './genFontSizes'; import genRadius from './genRadius'; export default function genCommonMapToken(token: SeedToken): CommonMapToken { - const { - motionUnit, - motionBase, - fontSizeBase, - sizeUnit, - sizeBaseStep, - gridUnit, - gridBaseStep, - radiusBase, - controlHeight, - lineWidth, - } = token; + const { motionUnit, motionBase, fontSizeBase, radiusBase, controlHeight, lineWidth } = token; const fontSizes = genFontSizes(fontSizeBase); return { // motion - motionDurationFast: `${(motionBase + motionUnit * 1).toFixed(1)}s`, + motionDurationFast: `${(motionBase + motionUnit).toFixed(1)}s`, motionDurationMid: `${(motionBase + motionUnit * 2).toFixed(1)}s`, motionDurationSlow: `${(motionBase + motionUnit * 3).toFixed(1)}s`, @@ -28,19 +17,6 @@ export default function genCommonMapToken(token: SeedToken): CommonMapToken { fontSizes: fontSizes.map(fs => fs.size), lineHeights: fontSizes.map(fs => fs.lineHeight), - // size - sizeSpaceSM: sizeUnit * (sizeBaseStep - 1), - sizeSpace: sizeUnit * sizeBaseStep, - sizeSpaceXS: sizeUnit * (sizeBaseStep - 2), - sizeSpaceXXS: sizeUnit * (sizeBaseStep - 3), - - // grid - gridSpaceSM: gridUnit * (gridBaseStep - 1), - gridSpaceBase: gridUnit * gridBaseStep, - gridSpaceLG: gridUnit * (gridBaseStep + 1), - gridSpaceXL: gridUnit * (gridBaseStep + 2), - gridSpaceXXL: gridUnit * (gridBaseStep + 5), - // line lineWidthBold: lineWidth + 1, diff --git a/components/theme/themes/shared/genSizeMapToken.ts b/components/theme/themes/shared/genSizeMapToken.ts new file mode 100644 index 0000000000..4f28f4a648 --- /dev/null +++ b/components/theme/themes/shared/genSizeMapToken.ts @@ -0,0 +1,17 @@ +import type { SeedToken, SizeMapToken } from '../../interface'; + +export default function genSizeMapToken(token: SeedToken): SizeMapToken { + const { sizeUnit, sizeBaseStep } = token; + + return { + sizeXXL: sizeUnit * (sizeBaseStep + 8), // 48 + sizeXL: sizeUnit * (sizeBaseStep + 4), // 32 + sizeLG: sizeUnit * (sizeBaseStep + 2), // 24 + sizeMD: sizeUnit * (sizeBaseStep + 1), // 20 + sizeMS: sizeUnit * sizeBaseStep, // 16 + size: sizeUnit * sizeBaseStep, // 16 + sizeSM: sizeUnit * (sizeBaseStep - 1), // 12 + sizeXS: sizeUnit * (sizeBaseStep - 2), // 8 + sizeXXS: sizeUnit * (sizeBaseStep - 3), // 4 + }; +} diff --git a/components/theme/util/alias.ts b/components/theme/util/alias.ts index 933ac39c11..f5cefbb0e3 100644 --- a/components/theme/util/alias.ts +++ b/components/theme/util/alias.ts @@ -120,23 +120,29 @@ export default function formatToken(derivativeToken: RawMergedToken): AliasToken controlPaddingHorizontal: 12, controlPaddingHorizontalSM: 8, - padding: 16, - margin: 16, - - paddingXXS: 4, - paddingXS: 8, - paddingSM: 12, - paddingLG: 24, - paddingXL: 32, - paddingTmp: 20, - - marginXXS: 4, - marginXS: 8, - marginSM: 12, - marginLG: 24, - marginXL: 32, - marginXXL: 48, - marginTmp: 20, + paddingXXS: mergedToken.sizeXXS, + paddingXS: mergedToken.sizeXS, + paddingSM: mergedToken.sizeSM, + padding: mergedToken.size, + paddingMD: mergedToken.sizeMD, + paddingLG: mergedToken.sizeLG, + paddingXL: mergedToken.sizeXL, + + paddingContentHorizontalLG: mergedToken.sizeLG, + paddingContentVerticalLG: mergedToken.sizeMS, + paddingContentHorizontal: mergedToken.sizeMS, + paddingContentVertical: mergedToken.sizeSM, + paddingContentHorizontalSM: mergedToken.size, + paddingContentVerticalSM: mergedToken.sizeXS, + + marginXXS: mergedToken.sizeXXS, + marginXS: mergedToken.sizeXS, + marginSM: mergedToken.sizeSM, + margin: mergedToken.size, + marginMD: mergedToken.sizeMD, + marginLG: mergedToken.sizeLG, + marginXL: mergedToken.sizeXL, + marginXXL: mergedToken.sizeXXL, boxShadow: ` 0 1px 2px 0 rgba(0, 0, 0, 0.03), diff --git a/components/tooltip/index.tsx b/components/tooltip/index.tsx index 36ff2ddd62..76a0cc3c4d 100644 --- a/components/tooltip/index.tsx +++ b/components/tooltip/index.tsx @@ -240,14 +240,14 @@ const Tooltip = React.forwardRef((props, ref) => { const transformOrigin = { top: '50%', left: '50%' }; - if (['top', 'Bottom'].includes(placement)) { + if (/top|Bottom/.test(placement)) { transformOrigin.top = `${rect.height - align.offset![1]}px`; - } else if (['Top', 'bottom'].includes(placement)) { + } else if (/Top|bottom/.test(placement)) { transformOrigin.top = `${-align.offset![1]}px`; } - if (['left', 'Right'].includes(placement)) { + if (/left|Right/.test(placement)) { transformOrigin.left = `${rect.width - align.offset![0]}px`; - } else if (['right', 'Left'].includes(placement)) { + } else if (/right|Left/.test(placement)) { transformOrigin.left = `${-align.offset![0]}px`; } domNode.style.transformOrigin = `${transformOrigin.left} ${transformOrigin.top}`; diff --git a/components/transfer/ListBody.tsx b/components/transfer/ListBody.tsx index d111f30f2b..e5f57703c3 100644 --- a/components/transfer/ListBody.tsx +++ b/components/transfer/ListBody.tsx @@ -71,7 +71,7 @@ class ListBody extends React.Component< onItemSelect = (item: RecordType) => { const { onItemSelect, selectedKeys } = this.props; - const checked = selectedKeys.indexOf(item.key) >= 0; + const checked = selectedKeys.includes(item.key); onItemSelect(item.key, !checked); }; @@ -144,7 +144,7 @@ class ListBody extends React.Component< > {this.getItems().map(({ renderedEl, renderedText, item }: RenderedItem) => { const { disabled } = item; - const checked = selectedKeys.indexOf(item.key) >= 0; + const checked = selectedKeys.includes(item.key); return ( = { diff --git a/components/transfer/__tests__/customize.test.tsx b/components/transfer/__tests__/customize.test.tsx index 6731a92b9d..aae9558413 100644 --- a/components/transfer/__tests__/customize.test.tsx +++ b/components/transfer/__tests__/customize.test.tsx @@ -1,5 +1,6 @@ import React from 'react'; import { render } from '../../../tests/utils'; +import type { TransferProps } from '../index'; import Transfer from '../index'; describe('Transfer.Customize', () => { @@ -15,7 +16,7 @@ describe('Transfer.Customize', () => { it('props#body does not work anymore', () => { const body = jest.fn(); - const props = { body }; + const props = { body } as TransferProps; render(); expect(errorSpy).not.toHaveBeenCalled(); expect(body).not.toHaveBeenCalled(); diff --git a/components/transfer/__tests__/list.test.tsx b/components/transfer/__tests__/list.test.tsx index 865ff42d37..1b8f65ec11 100644 --- a/components/transfer/__tests__/list.test.tsx +++ b/components/transfer/__tests__/list.test.tsx @@ -14,6 +14,11 @@ const listCommonProps: TransferListProps = { notFoundContent: 'Not Found', } as TransferListProps; +const listProps: TransferListProps = { + ...listCommonProps, + dataSource: undefined as unknown as any[], +}; + describe('Transfer.List', () => { it('should render correctly', () => { const { container } = render(); @@ -43,4 +48,9 @@ describe('Transfer.List', () => { expect(instance.current?.handleFilter({ target: 'test' })).toBe(undefined); expect(handleFilter).toHaveBeenCalled(); }); + it('should render correctly when dataSource is not exists', () => { + expect(() => { + render(); + }).not.toThrow(); + }); }); diff --git a/components/transfer/index.tsx b/components/transfer/index.tsx index d299a3f9c8..3bd2f56d20 100644 --- a/components/transfer/index.tsx +++ b/components/transfer/index.tsx @@ -5,7 +5,7 @@ import { ConfigConsumer } from '../config-provider'; import defaultRenderEmpty from '../config-provider/defaultRenderEmpty'; import { FormItemInputContext } from '../form/context'; import LocaleReceiver from '../locale-provider/LocaleReceiver'; -import defaultLocale from '../locale/default'; +import defaultLocale from '../locale/en_US'; import type { InputStatus } from '../_util/statusUtils'; import { getMergedStatus, getStatusClassNames } from '../_util/statusUtils'; import warning from '../_util/warning'; @@ -71,7 +71,7 @@ export interface TransferProps { prefixCls?: string; className?: string; disabled?: boolean; - dataSource: RecordType[]; + dataSource?: RecordType[]; targetKeys?: string[]; selectedKeys?: string[]; render?: TransferRender; @@ -137,13 +137,6 @@ class Transfer extends React.Com static Search = Search; - static defaultProps = { - dataSource: [], - locale: {}, - showSearch: false, - listStyle: () => {}, - }; - static getDerivedStateFromProps({ selectedKeys, targetKeys, @@ -177,8 +170,8 @@ class Transfer extends React.Com const { selectedKeys = [], targetKeys = [] } = props; this.state = { - sourceSelectedKeys: selectedKeys.filter(key => targetKeys.indexOf(key) === -1), - targetSelectedKeys: selectedKeys.filter(key => targetKeys.indexOf(key) > -1), + sourceSelectedKeys: selectedKeys.filter(key => !targetKeys.includes(key)), + targetSelectedKeys: selectedKeys.filter(key => targetKeys.includes(key)), }; } @@ -201,11 +194,10 @@ class Transfer extends React.Com return this.props.titles ?? transferLocale.titles ?? []; } - getLocale = (transferLocale: TransferLocale, renderEmpty: RenderEmptyHandler) => ({ - ...transferLocale, - notFoundContent: renderEmpty('Transfer'), - ...this.props.locale, - }); + getLocale = (transferLocale: TransferLocale, renderEmpty: RenderEmptyHandler) => { + const { locale = {} } = this.props; + return { ...transferLocale, notFoundContent: renderEmpty('Transfer'), ...locale }; + }; moveTo = (direction: TransferDirection) => { const { targetKeys = [], dataSource = [], onChange } = this.props; @@ -213,13 +205,13 @@ class Transfer extends React.Com const moveKeys = direction === 'right' ? sourceSelectedKeys : targetSelectedKeys; // filter the disabled options const newMoveKeys = moveKeys.filter( - (key: string) => !dataSource.some(data => !!(key === data.key && data.disabled)), + key => !dataSource.some(data => !!(key === data.key && data.disabled)), ); // move items to target box const newTargetKeys = direction === 'right' ? newMoveKeys.concat(targetKeys) - : targetKeys.filter(targetKey => newMoveKeys.indexOf(targetKey) === -1); + : targetKeys.filter(targetKey => !newMoveKeys.includes(targetKey)); // empty checked keys const oppositeDirection = direction === 'right' ? 'left' : 'right'; @@ -235,13 +227,13 @@ class Transfer extends React.Com onItemSelectAll = (direction: TransferDirection, selectedKeys: string[], checkAll: boolean) => { this.setStateKeys(direction, prevKeys => { - let mergedCheckedKeys = []; + let mergedCheckedKeys: string[] = []; if (checkAll) { // Merge current keys with origin key - mergedCheckedKeys = Array.from(new Set([...prevKeys, ...selectedKeys])); + mergedCheckedKeys = Array.from(new Set([...prevKeys, ...selectedKeys])); } else { // Remove current keys from origin keys - mergedCheckedKeys = prevKeys.filter((key: string) => selectedKeys.indexOf(key) === -1); + mergedCheckedKeys = prevKeys.filter(key => !selectedKeys.includes(key)); } this.handleSelectChange(direction, mergedCheckedKeys); @@ -345,7 +337,7 @@ class Transfer extends React.Com }; separateDataSource() { - const { dataSource, rowKey, targetKeys = [] } = this.props; + const { dataSource = [], rowKey, targetKeys = [] } = this.props; const leftDataSource: KeyWise[] = []; const rightDataSource: KeyWise[] = new Array(targetKeys.length); @@ -386,10 +378,10 @@ class Transfer extends React.Com className, disabled, operations = [], - showSearch, + showSearch = false, footer, style, - listStyle, + listStyle = {}, operationStyle, filterOption, render, @@ -427,7 +419,7 @@ class Transfer extends React.Com > prefixCls={`${prefixCls}-list`} - titleText={titles[0]} + titleText={titles?.[0]} dataSource={leftDataSource} filterOption={filterOption} style={this.handleListStyle(listStyle, 'left')} @@ -463,7 +455,7 @@ class Transfer extends React.Com /> > prefixCls={`${prefixCls}-list`} - titleText={titles[1]} + titleText={titles?.[1]} dataSource={rightDataSource} filterOption={filterOption} style={this.handleListStyle(listStyle, 'right')} diff --git a/components/transfer/list.tsx b/components/transfer/list.tsx index 00f9b5c685..725ef49dc4 100644 --- a/components/transfer/list.tsx +++ b/components/transfer/list.tsx @@ -81,12 +81,6 @@ interface TransferListState { export default class TransferList< RecordType extends KeyWiseTransferItem, > extends React.PureComponent, TransferListState> { - static defaultProps = { - dataSource: [], - titleText: '', - showSearch: false, - }; - timer: number; triggerScrollTimer: number; @@ -109,7 +103,7 @@ export default class TransferList< if (checkedKeys.length === 0) { return 'none'; } - if (filteredItems.every(item => checkedKeys.indexOf(item.key) >= 0 || !!item.disabled)) { + if (filteredItems.every(item => checkedKeys.includes(item.key) || !!item.disabled)) { return 'all'; } return 'part'; @@ -161,7 +155,7 @@ export default class TransferList< if (filterOption) { return filterOption(filterValue, item); } - return text.indexOf(filterValue) >= 0; + return text.includes(filterValue); }; // =============================== Render =============================== @@ -305,12 +299,12 @@ export default class TransferList< const { filterValue } = this.state; const { prefixCls, - dataSource, - titleText, + dataSource = [], + titleText = '', checkedKeys, disabled, footer, - showSearch, + showSearch = false, style, searchPlaceholder, notFoundContent, diff --git a/components/transfer/style/index.tsx b/components/transfer/style/index.tsx index e0fb4c2bc3..8ac9f56960 100644 --- a/components/transfer/style/index.tsx +++ b/components/transfer/style/index.tsx @@ -12,9 +12,9 @@ export interface ComponentToken { interface TransferToken extends FullToken<'Transfer'> { transferItemHeight: number; - transferHeaderHeight: number; transferHeaderVerticalPadding: number; transferItemPaddingVertical: number; + transferHeaderHeight: number; } const genTransferCustomizeStyle: GenerateStyle = ( @@ -99,7 +99,6 @@ const genTransferListStyle: GenerateStyle = (token: TransferToken listHeight, listWidth, listWidthLG, - marginXXS, fontSizeIcon, marginXS, paddingSM, @@ -142,7 +141,7 @@ const genTransferListStyle: GenerateStyle = (token: TransferToken borderRadius: `${token.controlRadiusLG}px ${token.controlRadiusLG}px 0 0`, '> *:not(:last-child)': { - marginInlineEnd: marginXXS, + marginInlineEnd: 4, // This is magic and fixed number, DO NOT use token since it may change. }, '> *': { diff --git a/components/tree/DirectoryTree.tsx b/components/tree/DirectoryTree.tsx index 96dfc84578..914973981a 100644 --- a/components/tree/DirectoryTree.tsx +++ b/components/tree/DirectoryTree.tsx @@ -52,10 +52,6 @@ const DirectoryTree: React.ForwardRefRenderFunction const cachedSelectedKeys = React.useRef(); - const treeRef = React.createRef(); - - React.useImperativeHandle(ref, () => treeRef.current!); - const getInitExpandedKeys = () => { const { keyEntities } = convertDataToEntities(getTreeData(props)); @@ -191,7 +187,7 @@ const DirectoryTree: React.ForwardRefRenderFunction return ( (({ ellipsis, rel, ...restP '`ellipsis` only supports boolean value.', ); - const baseRef = React.useRef(null); - - React.useImperativeHandle(ref, () => baseRef.current); - const mergedProps = { ...restProps, rel: rel === undefined && restProps.target === '_blank' ? 'noopener noreferrer' : rel, @@ -28,7 +24,7 @@ const Link = React.forwardRef(({ ellipsis, rel, ...restP // @ts-expect-error: https://github.com/ant-design/ant-design/issues/26622 delete mergedProps.navigate; - return ; + return ; }); export default Link; diff --git a/components/typography/Title.tsx b/components/typography/Title.tsx index 2e0ab33b1d..1cd1f84246 100644 --- a/components/typography/Title.tsx +++ b/components/typography/Title.tsx @@ -19,7 +19,7 @@ const Title = React.forwardRef((props, ref) => { const { level = 1, ...restProps } = props; let component: keyof JSX.IntrinsicElements; - if (TITLE_ELE_LIST.indexOf(level) !== -1) { + if (TITLE_ELE_LIST.includes(level)) { component = `h${level}`; } else { warning( diff --git a/components/typography/__tests__/index.test.tsx b/components/typography/__tests__/index.test.tsx index 6b786576b7..bc52a8ad81 100644 --- a/components/typography/__tests__/index.test.tsx +++ b/components/typography/__tests__/index.test.tsx @@ -262,14 +262,14 @@ describe('Typography', () => { , ); - if (triggerType === undefined || triggerType.indexOf('icon') !== -1) { + if (triggerType === undefined || triggerType.includes('icon')) { if (icon) { expect(wrapper.querySelectorAll('.anticon-highlight').length).toBeGreaterThan(0); } else { expect(wrapper.querySelectorAll('.anticon-edit').length).toBeGreaterThan(0); } - if (triggerType === undefined || triggerType.indexOf('text') === -1) { + if (triggerType === undefined || !triggerType.includes('text')) { fireEvent.click(wrapper.firstChild!); expect(onStart).not.toHaveBeenCalled(); } @@ -295,15 +295,15 @@ describe('Typography', () => { fireEvent.click(wrapper.querySelectorAll('.ant-typography-edit')[0]); expect(onStart).toHaveBeenCalled(); - if (triggerType !== undefined && triggerType.indexOf('text') !== -1) { + if (triggerType !== undefined && triggerType.includes('text')) { fireEvent.keyDown(wrapper.querySelector('textarea')!, { keyCode: KeyCode.ESC }); fireEvent.keyUp(wrapper.querySelector('textarea')!, { keyCode: KeyCode.ESC }); expect(onChange).not.toHaveBeenCalled(); } } - if (triggerType !== undefined && triggerType.indexOf('text') !== -1) { - if (triggerType.indexOf('icon') === -1) { + if (triggerType !== undefined && triggerType.includes('text')) { + if (!triggerType.includes('icon')) { expect(wrapper.querySelectorAll('.anticon-highlight').length).toBe(0); expect(wrapper.querySelectorAll('.anticon-edit').length).toBe(0); } diff --git a/components/upload/Upload.tsx b/components/upload/Upload.tsx index 446f9d5a77..8d426b673d 100644 --- a/components/upload/Upload.tsx +++ b/components/upload/Upload.tsx @@ -7,7 +7,7 @@ import { flushSync } from 'react-dom'; import { ConfigContext } from '../config-provider'; import DisabledContext from '../config-provider/DisabledContext'; import LocaleReceiver from '../locale-provider/LocaleReceiver'; -import defaultLocale from '../locale/default'; +import defaultLocale from '../locale/en_US'; import warning from '../_util/warning'; import type { RcFile, ShowUploadListInterface, UploadChangeParam, UploadFile } from './interface'; import { UploadProps } from './interface'; diff --git a/docs/react/faq.en-US.md b/docs/react/faq.en-US.md index f0b823cb21..daa9b03fce 100644 --- a/docs/react/faq.en-US.md +++ b/docs/react/faq.en-US.md @@ -49,6 +49,18 @@ See: https://ant.design/docs/react/customize-theme . While you can override a component's style, we don't recommend doing so. antd is not only a set of React components, but also a design specification as well. +## How to avoid breaking change when update version? + +antd will avoid breaking change in minor & patch version. You can safe do follow things: + +- Official demo usage +- FAQ suggestion. Including codesandbox sample, marked as FAQ issue + +And which you should avoid to do: + +- Bug as feature. It will break in any other case (e.g. Use div as Tabs children) +- Use magic code to realize requirement but which can be realized with normal API + ## How to use other data-time lib like Moment.js? Please refer to [Use custom date library](/docs/react/use-custom-date-library). diff --git a/docs/react/faq.zh-CN.md b/docs/react/faq.zh-CN.md index 6ef3c0c226..c7f9f34bf2 100644 --- a/docs/react/faq.zh-CN.md +++ b/docs/react/faq.zh-CN.md @@ -49,6 +49,18 @@ title: FAQ 你可以覆盖它们的样式,但是我们不推荐这么做。antd 是一系列 React 组件,但同样是一套设计规范。 +## 如何避免升级导致的破坏性变更? + +antd 在 minor 和 patch 版本迭代中会避免引入破坏性变更,遵从以下原则会确保不会破坏你的代码: + +- 使用出现在官方 Demo 中的写法 +- FAQ 中出现的解法,包含代码片段以及 codesandbox 示例、issue 中当前版本标记 FAQ label 的 + +而下述变更则需要开发者自行校验: + +- 特定场景的错误用法,BUG as Feature(例如 Tabs 下直接包 div 的用法) +- 可以通过正常用法实现功能需求却魔改的 + ## 如何使用其他时间日期库如 Moment.js? 可以参考[使用自定义日期库](/docs/react/use-custom-date-library)。 diff --git a/docs/react/getting-started.zh-CN.md b/docs/react/getting-started.zh-CN.md index 703e0e8fc5..b7b007dc29 100755 --- a/docs/react/getting-started.zh-CN.md +++ b/docs/react/getting-started.zh-CN.md @@ -36,7 +36,7 @@ import { ConfigProvider, DatePicker, message } from 'antd'; // 由于 antd 组件的默认文案是英文,所以需要修改为中文 import dayjs from 'dayjs'; import 'dayjs/locale/zh-cn'; -import zhCN from 'antd/es/locale/zh_CN'; +import zhCN from 'antd/locale/zh_CN'; import 'antd/dist/antd.css'; import './index.css'; diff --git a/docs/react/i18n.en-US.md b/docs/react/i18n.en-US.md index d43f63886e..0ad0b68334 100644 --- a/docs/react/i18n.en-US.md +++ b/docs/react/i18n.en-US.md @@ -11,7 +11,7 @@ The default language of `antd@2.x` is currently English. If you wish to use othe ```jsx import { ConfigProvider } from 'antd'; -import frFR from 'antd/es/locale/fr_FR'; +import frFR from 'antd/locale/fr_FR'; return ( diff --git a/docs/react/i18n.zh-CN.md b/docs/react/i18n.zh-CN.md index 019aac9f7e..77f14c37be 100644 --- a/docs/react/i18n.zh-CN.md +++ b/docs/react/i18n.zh-CN.md @@ -10,7 +10,7 @@ title: 国际化 antd 提供了一个 React 组件 [ConfigProvider](/components/config-provider) 用于全局配置国际化文案。 ```jsx -import zhCN from 'antd/es/locale/zh_CN'; +import zhCN from 'antd/locale/zh_CN'; return ( diff --git a/docs/react/migration-v5.en-US.md b/docs/react/migration-v5.en-US.md index 2f2563d81e..65fdd178d3 100644 --- a/docs/react/migration-v5.en-US.md +++ b/docs/react/migration-v5.en-US.md @@ -24,7 +24,7 @@ This document will help you upgrade from antd `4.x` version to antd `5.x` versio - All less files are removed, and less variables are no longer exported. - Css files are no longer included in package. Since CSS-in-JS supports importing on demand, the original `antd/dist/antd.css` has also been abandoned. If you need to reset some basic styles, please import `antd/dist/reset.css`. - Remove css variables and dynamic theme built on top of them. -- Remove `lib`, only provide `dist` and `es` in package. +- Remove `lib`, only provide `dist` and `es` in package, the original `antd/es/locale` has also been abandoned, you can find the packages in `antd/locale`. - Replace built-in Moment.js with Dayjs. For more: [Use custom date library](/docs/react/use-custom-date-library/). - `babel-plugin-import` is no longer supported. CSS-in-JS itself has the ability to import on demand, and plugin support is no longer required. Umi users can remove related configurations. diff --git a/docs/react/migration-v5.zh-CN.md b/docs/react/migration-v5.zh-CN.md index 07d451d88b..993b5e0782 100644 --- a/docs/react/migration-v5.zh-CN.md +++ b/docs/react/migration-v5.zh-CN.md @@ -25,7 +25,7 @@ title: 从 v4 到 v5 - 所有 less 文件全部移除,less 变量不再支持透出。 - 产物中不再包含 css 文件。由于 CSS-in-JS 支持按需引入,原本的 `antd/dist/antd.css` 也已经移除,如果需要重置一些基本样式请引入 `antd/dist/reset.css`。 - 移除 css variables 以及在此之上构筑的动态主题方案。 -- 移除 `lib` 产物,只提供 `dist` 和 `es` 产物。 +- 移除 `lib` 产物,只提供 `dist` 和 `es` 产物,原本的 `antd/es/locale` 目录也已经移除,语言包可到 `antd/locale` 目录下寻找。 - 内置的时间库使用 Dayjs 替代 Moment.js,具体请查看 [使用自定义日期库](/docs/react/use-custom-date-library-cn/)。 - 不再支持 `babel-plugin-import`,CSS-in-JS 本身具有按需加载的能力,不再需要插件支持。Umi 用户可以移除相关配置。 diff --git a/docs/react/practical-projects.en-US.md b/docs/react/practical-projects.en-US.md index b94699ad91..08911ea7da 100644 --- a/docs/react/practical-projects.en-US.md +++ b/docs/react/practical-projects.en-US.md @@ -68,10 +68,13 @@ Let's create a `ProductList` component that we can use in multiple places to sho Create `src/components/ProductList.tsx` by typing: -```js +```tsx import { Table, Popconfirm, Button } from 'antd'; -const ProductList = ({ onDelete, products }) => { +const ProductList: React.FC<{ products: { name: string }[]; onDelete: (id: string) => void }> = ({ + onDelete, + products, +}) => { const columns = [ { title: 'Name', @@ -112,16 +115,12 @@ export function queryProductList() { export function queryProductList() { return new Promise(resolve => { setTimeout(() => { - resolve([ - { - id: 1, - name: 'dva', - }, - { - id: 2, - name: 'antd', - }, - ]); + resolve({ + data: [ + { id: 1, name: 'dva' }, + { id: 2, name: 'antd' }, + ], + }); }, 2000); }); } @@ -134,7 +133,7 @@ import { useRequest } from 'umi'; import { queryProductList } from '@/services/product'; export default function useProductList(params: { pageSize: number; current: number }) { - const msg = useRequest(() => queryUserList(params)); + const msg = useRequest(() => queryProductList(params)); const deleteProducts = async (id: string) => { try { diff --git a/docs/react/practical-projects.zh-CN.md b/docs/react/practical-projects.zh-CN.md index 4751ce6ee9..dc15c52a11 100644 --- a/docs/react/practical-projects.zh-CN.md +++ b/docs/react/practical-projects.zh-CN.md @@ -109,16 +109,12 @@ export function queryProductList() { export function queryProductList() { return new Promise(resolve => { setTimeout(() => { - resolve([ - { - id: 1, - name: 'dva', - }, - { - id: 2, - name: 'antd', - }, - ]); + resolve({ + data: [ + { id: 1, name: 'dva' }, + { id: 2, name: 'antd' }, + ], + }); }, 2000); }); } diff --git a/package.json b/package.json index 3ee405ade0..661e9e61be 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "antd", - "version": "5.0.0-alpha.4", + "version": "5.0.0-alpha.31", "description": "An enterprise-class UI design language and React components implementation", "title": "Ant Design", "keywords": [ @@ -32,7 +32,8 @@ }, "files": [ "dist", - "es" + "es", + "locale" ], "sideEffects": [ "*.less" @@ -127,7 +128,7 @@ "rc-dropdown": "~4.0.0", "rc-field-form": "~1.27.0", "rc-image": "~5.9.0", - "rc-input": "~0.1.2", + "rc-input": "~0.1.3", "rc-input-number": "~7.3.9", "rc-mentions": "~1.10.0", "rc-menu": "~9.6.3", @@ -158,7 +159,7 @@ "devDependencies": { "@ant-design/bisheng-plugin": "^3.3.0-alpha.4", "@ant-design/hitu": "^0.0.0-alpha.13", - "@ant-design/tools": "^15.1.6", + "@ant-design/tools": "^15.2.0-alpha.1", "@docsearch/css": "^3.0.0", "@emotion/babel-preset-css-prop": "^11.10.0", "@emotion/react": "^11.10.4", @@ -213,6 +214,7 @@ "eslint": "^8.0.0", "eslint-config-airbnb": "^19.0.0", "eslint-config-prettier": "^8.0.0", + "eslint-import-resolver-typescript": "^3.5.2", "eslint-plugin-babel": "^5.3.0", "eslint-plugin-compat": "^4.0.0", "eslint-plugin-import": "^2.21.1", diff --git a/scripts/generate-authors.js b/scripts/generate-authors.js index 02ede750bd..716ecf8637 100644 --- a/scripts/generate-authors.js +++ b/scripts/generate-authors.js @@ -21,7 +21,7 @@ async function execute() { logs = _.remove(logs, ({ author_email: email }) => { for (let i = 0; i < excludes.length; i++) { const item = excludes[i]; - if (email.indexOf(item) !== -1) { + if (email.includes(item)) { return false; } } diff --git a/site/bisheng.config.js b/site/bisheng.config.js index 2e30880a74..e946477d36 100644 --- a/site/bisheng.config.js +++ b/site/bisheng.config.js @@ -69,6 +69,7 @@ module.exports = { config.resolve.alias = { 'antd/lib': path.join(process.cwd(), 'components'), 'antd/es': path.join(process.cwd(), 'components'), + 'antd/locale': path.join(process.cwd(), 'components/locale'), // Change antd from `index.js` to `site/antd.js` to remove deps of root style antd: path.join(process.cwd(), 'site', 'antd'), site: path.join(process.cwd(), 'site'), @@ -128,6 +129,12 @@ module.exports = { // eslint-disable-next-line no-console console.log('Site build with development mode...'); config.mode = 'development'; + + config.plugins.push( + new webpack.DefinePlugin({ + antdPreview: JSON.stringify(true), + }), + ); } // Split chunks diff --git a/site/theme/template/Color/Palette.jsx b/site/theme/template/Color/Palette.jsx index f7bbb6ac49..cfff5d67ca 100644 --- a/site/theme/template/Color/Palette.jsx +++ b/site/theme/template/Color/Palette.jsx @@ -19,7 +19,7 @@ export default class Palette extends React.Component { this.hexColors = {}; Object.keys(this.colorNodes).forEach(key => { const computedColor = getComputedStyle(this.colorNodes[key])['background-color']; - if (computedColor.indexOf('rgba') >= 0) { + if (computedColor.includes('rgba')) { this.hexColors[key] = computedColor; } else { this.hexColors[key] = rgbToHex(computedColor); diff --git a/site/theme/template/Content/MainContent.jsx b/site/theme/template/Content/MainContent.jsx index 58ffe3505c..de528f7be4 100644 --- a/site/theme/template/Content/MainContent.jsx +++ b/site/theme/template/Content/MainContent.jsx @@ -1,18 +1,16 @@ import React, { cloneElement, Component } from 'react'; -import { Link, browserHistory } from 'bisheng/router'; -import { Row, Col, Menu, Affix, Tooltip, Avatar, Dropdown, Drawer } from 'antd'; -import { injectIntl, FormattedMessage } from 'react-intl'; +import { browserHistory, Link } from 'bisheng/router'; +import { Affix, Avatar, Col, Drawer, Menu, Row, Tooltip } from 'antd'; +import { FormattedMessage, injectIntl } from 'react-intl'; import { + DoubleRightOutlined, + ExportOutlined, LeftOutlined, RightOutlined, - ExportOutlined, - DoubleRightOutlined, } from '@ant-design/icons'; import ContributorsList from '@qixian.cs/github-contributors-list'; import classNames from 'classnames'; import get from 'lodash/get'; - -import ThemeIcon from './ThemeIcon'; import Article from './Article'; import PrevAndNext from './PrevAndNext'; import Footer from '../Layout/Footer'; @@ -513,7 +511,6 @@ class MainContent extends Component { {menuItems}
); - const componentPage = /^\/?components/.test(location.pathname); return (
@@ -551,13 +548,6 @@ class MainContent extends Component {
{this.renderMainContent({ theme, setIframeTheme })}
- {componentPage && ( -
- - } /> - -
- )}