Merge pull request #15097 from ant-design/merge-master

Merge master
This commit is contained in:
zombieJ 2019-02-27 20:17:55 +08:00 committed by GitHub
commit d29e6675a5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
98 changed files with 1359 additions and 640 deletions

8
.github/main.workflow vendored Normal file
View File

@ -0,0 +1,8 @@
workflow "New workflow" {
on = "push"
resolves = ["Auto Assign"]
}
action "Auto Assign" {
uses = "kentaro-m/auto-assign@v1.0.0"
}

View File

@ -1,10 +1,11 @@
+v <ljw@live.jp>
17073025 <17073025@cnsuning.com>
282159468 <282159468@qq.com>
778758944 <778758944@qq.com>
Aaron Planell López <aaronplanell@gmail.com>
Aashutosh Rathi <aashutoshrathi@gmail.com>
Aditya Padhi <aditya.padhi@outlook.com>
Adrian Dimitrov <dimitrov.adrian@gmail.com>
Ahmed AlSammany <ahmed.alsammany@incorta.com>
Alan Braithwaite <asbraithwaite@gmail.com>
Albert Zheng <lisong.zheng@gmail.com>
Albert 理斯特 <shuaizhexu@gmail.com>
@ -14,21 +15,27 @@ Alexander Anpleenko <vaeum@yandex.com>
Alexander Suevalov <suevalov.work@gmail.com>
Alexandre Kirszenberg <a.kirszenberg@gmail.com>
Alexey Yakovlev <yallie@yandex.ru>
Alfred Qiu <sc941203@gmail.com>
Ali Zhdanov <makedonec88@gmail.com>
Alireza <alireza.mh@gmail.com>
Alvin Abia <alvin.abia@icloud.com>
Amorites <751809522@qq.com>
Amumu <yoyo837@hotmail.com>
Anas Tawfeek <anas.tawfeek@outlook.com>
Andre Perunicic <andre@intoli.com>
Andrew Murray <radarhere@gmail.com>
Andrew Shearer <andrew@ashearer.com>
Andrey G <plandem@gmail.com>
Andrzej Dybionka <andrzej@arabel.la>
André <mazoni.andre@gmail.com>
Ardo Kusuma <ardo@uber.com>
Arnab Sen <arnabsen@gmail.com>
Arthur Denner Oliveira Santos <arthurdenner7@gmail.com>
Arvin Xu <arvinx@foxmail.com>
Ash Kumar <kumar.ashwin@outlook.com>
BK Heleth <bon.hoo@hotmail.com>
Babajide Fowotade <jide.b.tade@gmail.com>
Barry <barry.yansh@gmail.com>
Bartek <bartek.kozera@gmail.com>
Benedikt Franke <benedikt@franke.tech>
Benjamin Kniffler <bkniffler@me.com>
@ -38,6 +45,8 @@ Bernie <bernie.wangbj@gmail.com>
Bilal Sirazitdinov <bilalsir@yandex.ru>
Bill Sheikh <bilawals22@gmail.com>
Bo Chen <bochen2014@yahoo.com>
Bolun Zhang <rzhangbolun@gmail.com>
Bora Ikizoglu <boraikizoglu@gmail.com>
Bozhao <yubz86@gmail.com>
Bradley Xu <xgheaven@gmail.com>
Brett Lamy <bel423@me.com>
@ -47,6 +56,7 @@ Bruno Maia <bruno.mm.maia@gmail.com>
Bryan Berger <bb@ga.co>
C <4019980@qq.com>
C.J. Winslow <whoaa512@gmail.com>
CORP\lianyufeng <15275222711@163.com>
Cam Song <neosoyn@gmail.com>
Camol <kwwnjujlc@sina.com>
Cang Ta <hoksilato176@gmail.com>
@ -58,6 +68,7 @@ Chandler Moisen <chandlermoisen@gmail.com>
Chang Wang <cheapsteak@gmail.com>
Charles Covey-Brandt <chazcb@gmail.com>
Chelsea Huang <chelsea.huang@sap.com>
Cheng Liu <liucheng.tech@outlook.com>
Chenjia <ariesjia00@hotmail.com>
Chikara Chan <chenhongtu@51xianqu.net>
Chris Kelly <cjke.7777@gmail.com>
@ -119,11 +130,16 @@ Eward Song <eward.song@gmail.com>
Federico Marcos <marcosfede@gmail.com>
Fergus Leung <fergusleung96@gmail.com>
Fernando Giarritiello <fgiarritiello@gmail.com>
Florian Orpelière <florian.orpeliere@gmail.com>
Flynn <li.fulin@foxmail.com>
For177 <mengqiang.q@gmail.com>
Gabe Medrash <gabeme@alleninstitute.org>
Gabriel Nunes <gabriel@multiverso.me>
Gao Jiangmiao <tolbkni@gmail.com>
Gautier <rollingautier2@gmail.com>
Geoff Holden <geoff@brightloudnoise.com>
George Gray <george@ummodesign.com>
Go7hic <gtfx0209@qq.com>
Graeme Yeates <gyeates@clearpath.ai>
Graeme Yeates <yeatesgraeme@gmail.com>
Grant Klinsing <gklinsing@gmail.com>
@ -133,17 +149,22 @@ Guan Yu Pan (Jacky) <jackypan1989@gmail.com>
HJin.me <hjin.me@gmail.com>
Hai Phan Nguyen <pnghai@gmail.com>
Haibin Yu <haibin.yu@oceanwing.com>
Hal-pan <hms181231@gmail.com>
Hanai <ihanai1991@gmail.com>
Hanz Luo <lhz0516@gmail.com>
Harlan <luoxwen@gmail.com>
HarlanLuo <luoxwen@gmail.com>
Haroen Viaene <fingebimus@me.com>
Harshit Mehrotra <harshitmehrotra@hotmail.com>
Heaven <ne_smalltown@163.com>
Henri Normak <henri.normak@gmail.com>
HeskeyBaozi <hezhiyu233@foxmail.com>
Hieu Ho <hieu.ho.le@lazada.com>
Higor Araújo dos Anjos <higor.araujo.anjos@gmail.com>
Hubert Argasinski <argasinski.hubert@gmail.com>
Hughen <446370503@163.com>
Hugo LEHMANN <shogi31@gmail.com>
Igor <nemytyshew@yandex.ru>
Igor G <i.gaidai4uk@gmail.com>
Ilan <hasanovtk@gmail.com>
Ilan Hasanov <hasanovtk@gmail.com>
@ -154,6 +175,7 @@ Ivan Kravets <me@ikravets.com>
Ivan Trofimov <ivan@trofimov.link>
Ivo Stratev <ivo.stratev.tues@gmail.com>
Jack Hsieh <jack@egenware.com>
Jack Lo <jack-lo@foxmail.com>
Jack Works <zjwpeter@gmail.com>
Jackie.Ls <418292038@qq.com>
Jacques Kvam <jwkvam@gmail.com>
@ -162,6 +184,7 @@ Jake Richards <jake.richards@genesys.com>
James <james@schoolshape.com>
JamesYin <elantion@gmail.com>
Jaroslav Bereza <github.com@bereza.cz>
Jason Chen <ceocjy@vip.qq.com>
Jean-Luc Sorak <jlsorak@icloud.com>
Jeffrey Carl Faden <jeffreyatw@gmail.com>
JeromeLin <jerome.lin@zhongan.com>
@ -173,6 +196,7 @@ Jieraaa <842533841@qq.com>
Jin ZHANG <jz.zhangjin@gmail.com>
Jing Ma <mjingm87@qq.com>
Jinxuan Zhu <zhujinxuan@gmail.com>
Joao Rabelo <jrabelo@tech6.com.br>
Joe <qiaolibo@126.com>
Joe Hsu <jhsu.x1@gmail.com>
Johannes Loewe <johannes@loewe.pm>
@ -181,11 +205,15 @@ John Nguyen <jtnguyen236@gmail.com>
Jonatas Walker <jonataswalker@gmail.com>
Jonny Buchanan <jonathan.buchanan@gmail.com>
Jordan Hornblow <jordan@jch254.com>
Josue Peralta <jperal77@gmail.com>
Josué <ujosuegt@outlook.com>
JribiBelhassen <belha9inzaghi@gmail.com>
Juan Rodrigo Venegas Boesch <jrvboesch@gmail.com>
Julia Passynkova <ipassynk@hotmail.com>
Junyu Zhan <irrigator@yeah.net>
Justin Reich <reich.justin@gmail.com>
Kaien Liao <liaokaien@gmail.com>
Kasra Bigdeli <kasra85@gmail.com>
Kenaniah Cerny <kenaniah@gmail.com>
Kenneth Luján Rosas <elgenio.03@gmail.com>
Kenneth Truong <kenneth.e.truong@gmail.com>
@ -200,6 +228,7 @@ Kimmo Saari <kimmo.saari@revolt.fi>
Kirill Alexander Khalitov <voronar@gmail.com>
Kirill Stiopin <kirill.stiopin@hotmail.com>
Knacktus <knacktus@gmail.com>
Konrad Machlowski <konrad.machlowski@gmail.com>
Kyle Kelley <rgbkrk@gmail.com>
Kyle Rosenberg <kyle.rosenberg@gmail.com>
LLinFan- <catfoursi@qq.com>
@ -218,9 +247,12 @@ Ludwig Bäcklund <ludli839@student.liu.se>
Lyndon001 <lld207@126.com>
MG12 <wuzhao.mail@gmail.com>
Ma Tianxiao <matx2215@outlook.com>
Maciej Czekaj <natanielcz@gmail.com>
Madis Väin <madisvain@gmail.com>
Maksym Mosyura <wmornotwm@gmail.com>
Manjit Kumar <manjit1727@gmail.com>
Manweill <mic.liangwenwei@foxmail.com>
MaoYiWei <137308365@qq.com>
Marcela Bomfim <mbomfim@live.com>
Marco Afonso <mafonso333@gmail.com>
Marcus Bransbury <marcus.bransbury@gmail.com>
@ -231,26 +263,34 @@ Martin Litvaj <kamahl19@gmail.com>
Martin Novák <martinnovak@outlook.com>
Mathew <khayaanimations@gmail.com>
Matt Lein <matt.lein@code42.com>
Max <maksym.mosyura@kruschecompany.com>
Maximilian Meyer <Maximilian.Meyer@br.de>
Meck <yesmeck@gmail.com>
MeiLin <postget.me@gmail.com>
Meow-z <372086270@qq.com>
Miaow <i@zfeng.net>
Michael Krog <michael.krog@previsto.com>
Michael Krog <mic@apaq.dk>
Michael Salaverry <barakplasma@gmail.com>
Michael Wang <ylzcylx@gmail.com>
Michalis Macheras <diodosier@gmail.com>
Michelle Zhang <michelle.chsy@gmail.com>
Mikasa33 <mikasa33@qq.com>
Min <dicklwm@163.com>
MinJeong Kim <min7859@gmail.com>
Ming Hann <eldy8888@gmail.com>
Minqi Pan <pmq2001@gmail.com>
Minsung Ryu <ryums0227@gmail.com>
Mitchell Demler <mitchell.demler@harcourts.net>
Mohamed Seada <mohamed.seada.1994@gmail.com>
Mohammad Faisal <faisalhmohd@gmail.com>
Mohan Ban <banmohan@outlook.com>
Mounish Sai <pvsmounish@gmail.com>
Mr.Tone <vector@malubei.com>
MuYu <mr.muzea@gmail.com>
Mário Gonçalves <mario.mc.goncalves@gmail.com>
Nathan Broadbent <git@ndbroadbent.com>
Nathan Griffin <nathan@gatherhere.com>
Nathan Schneider <n.l.schneider@gmail.com>
Nathan Tavares Nascimento <nathan.tnascimento@gmail.com>
Nathan Wells <nwwells@gmail.com>
Neekey <ni184775761@gmail.com>
@ -258,8 +298,10 @@ Nekron <nekron.hyt@gmail.com>
Neverland <chenjiahan@buaa.edu.cn>
Nico <nicolas@freddelacompta.com>
Nidhi Agarwal <nidhi.agarwal@zomato.com>
Niko Autio <niko.autio@fenten.fi>
Nikolay <veseliy07@gmail.com>
Nikolay Solovyov <i@mr-ozio.ru>
Nima Dehnashi <nima@getaround.com>
Nimo <nimo.jser@gmail.com>
Nishant Arora <na.nishantarora@gmail.com>
Nokecy <Nokecy@163.com>
@ -268,6 +310,8 @@ Oleg Kuzava <olegkuzava@gmail.com>
Oleksandr Kovalchuk <me.olexandr.kovalchuk@gmail.com>
Ooi Yee Wei <ywooi@yahoo.com>
Open Next <opennext@126.com>
Oren Kosto <oren@panda-os.com>
Oren Kosto <orenkosto86@gmail.com>
OuYancey <ou.yancey@gmail.com>
Panjie Setiawan Wicaksono <panjie@panjiesw.com>
Patrick Gidich <patrick.gidich@simnova.com>
@ -275,6 +319,7 @@ Patryk <longer44@gmail.com>
Peter <usstpeter@gmail.com>
Peter Berg <atticusberg@gmail.com>
Phanupong Janthapoon <panupong.jtp@gmail.com>
Philip Oliver <philipodev@gmail.com>
Pierre <pierre@bazoge.com>
Pierre Neter <pierreneter@gmail.com>
Piper Chester <piperchester@gmail.com>
@ -282,12 +327,14 @@ Pixy Yuan <pixy.bupt@gmail.com>
Pooya Parsa <pyapar@gmail.com>
Pyiner <lijiuyang1992@gmail.com>
Pyroboomka <qwaarty@mail.ru>
QC-L <github@liqichang.com>
Qiaosen Huang <joesonw@gmail.com>
Qingrong Ke <keqingrong1992@gmail.com>
Rafael Cosman <rafaelcosman@alumni.stanford.edu>
Rahul Gurung <gurungrahul2@gmail.com>
Rallets <rallet@rallets.com>
Ramsés Moreno <ramses@cuatromedios.com>
Ran Byron <ranbena@gmail.com>
Randy <randypriv@gmail.com>
RaoHai <surgesoft@gmail.com>
Raphael Chauveau <raph.chauveau@gmail.com>
@ -300,10 +347,12 @@ Robert Wilkinson <wilkinson.robert.a@gmail.com>
Rohan Malhotra <rohan.root@gmail.com>
Rongjian Zhang <pd4d10@gmail.com>
Rrrandom <emanonhere@gmail.com>
RunningCoderLee <sprint_l@aliyun.com>
RyanHui <ryanhui1996@gmail.com>
SHEN Lin <shenlin192@gmail.com>
Sakol Assawasagool <koobitor@gmail.com>
Sam Chen <chenxsan@gmail.com>
Sam Lanning <sam@samlanning.com>
Sam Maxwell <sam@paybase.io>
Samuel Gaus <sam@gaus.co.uk>
Sangle <whb97@163.com>
@ -315,23 +364,31 @@ Sean Sun <pinggodstudio@gmail.com>
Sebastian Blade <blade254353074@hotmail.com>
Sebastian Busch <mail@sebastian-bus.ch>
Sebastian Busch <s.busch@qbus-enet.de>
Sergey Volynkin <sergey.volynkin@akvelon.com>
Sergio Crisostomo <sergiosbox@gmail.com>
Shawn Sit <xueqingxiao@gmail.com>
ShiTengFei <shitengfei@goyoo.com>
Shuai Chen <wasd2144@hotmail.com>
Shubham Kanodia <shubhamsizzles@gmail.com>
Shun <polytechnics.shun@gmail.com>
Shuvalov Anton <anton@shuvalov.info>
SimaQ <sima.zhang1990@gmail.com>
Simo Aleksandrov <simo3003@me.com>
Spencer <spjy@hawaii.edu>
Stephen Esser <Stephen.Esser@gmail.com>
Subroto <shub1493biswas@gmail.com>
Sven Efftinge <sven.efftinge@typefox.io>
Tao <magicdawn@qq.com>
Tao Zhang <windse7en@gmail.com>
Taylor Sabell <taylorsabell@gmail.com>
Teng YANG <morenyang88@gmail.com>
Teng YANG <yangteng@me.com>
Tengjiao Cai <caitengjiao1987@gmail.com>
Terence <trence320@163.com>
The Rock <zhoguoxin@126.com>
Thibault Derousseaux <tde@activeviam.com>
Thiebaud Thomas <thiebaud.tom@gmail.com>
Thomas <tom@axisj.com>
Tino D <ginodeis@gmail.com>
Tom Gao <tom@zoomsoft.cc>
Tom Xu <tom.xu@antcosa.com>
@ -345,16 +402,19 @@ Tyler <chaotyler@gmail.com>
Ubaldo Quintana <blkdr@hotmail.com>
Vadim Macagon <vadim.macagon@gmail.com>
Valentin Vichnal <valentin@vichnal.com>
Van Nguyen <vnguyen94@gmail.com>
Vemund Santi <vemund@santi.no>
Vic <709147950@qq.com>
Vincent Zhang <vxzhong@qq.com>
Vitaliy Mazurenko <vitaliymazurenko@gmail.com>
ViviaRui <zr1450995198@163.com>
Vu Hoang Minh <vuhminh@gmail.com>
Walter Barbagallo <brb.walter@gmail.com>
Walter Barbagallo <turbometalskater@gmail.com>
Wang Jun <amos.callmexyz@gmail.com>
Wang Riwu <riwu0730@gmail.com>
Wang Zhengchen <wang909208@163.com>
Wang yb <wangyibu123@gmail.com>
Warren Seymour <warren@fountainhead.tech>
Wei Zhu <yesmeck@gmail.com>
Wenchao Hu <zjuhwc@gmail.com>
@ -369,6 +429,7 @@ Xiping.wang <527409987@qq.com>
XuMM_12 <owiatsq@sina.cn>
Yang <504021398@qq.com>
Yang Bin <yangkghjh@gmail.com>
Yangzhedi <uiryzd@163.com>
Yasin Uslu <nepjua@gmail.com>
Yevhen Hryhorevskyi <evgeniygrigorevskiy@gmail.com>
Yiming <ymjrcc@qq.com>
@ -390,10 +451,13 @@ Zheeeng <hi@zheeeng.me>
Zhiqiang Gong <elory0513@hotmail.com>
Ziluo <gyfzzu@gmail.com>
Zohaib Ijaz <mzohaib.qc@gmail.com>
aashutoshrathi <aashutoshrathi@gmail.com>
afc163 <afc163@gmail.com>
agent-z <1607291079@qq.com>
ahalimkara <ahalimkara@gmail.com>
alex <379118572@qq.com>
alexchen <alexchen@easyops.cn>
amedora <americandragsterracing@gmail.com>
arifemrecelik <ce.arifemre@gmail.com>
ascoders <576625322@qq.com>
ashishg-qburst <ashishg@qburst.com>
@ -402,16 +466,19 @@ bang <sqibang@gmail.com>
bang88 <sqibang@gmail.com>
baozefeng <727751065@qq.com>
blankzust <450811238@qq.com>
bukas <yhz1219@gmail.com>
byuanama <byuan@ama.com.au>
byzyk <bohdan.kh@gmail.com>
bzone <yarnbcoder@gmail.com>
caoyi <caoyi0905@mail.hfut.edu.cn>
carrie-tanminyi <12mytan@gmail.com>
cathayandy <wzm_andy@126.com>
cc189 <cc189dev@gmail.com>
chaofeis <408067385@qq.com>
chchen <cc272309126@gmail.com>
chencheng (云谦) <sorrycc@gmail.com>
chencheng <sorrycc@gmail.com>
chunlea <ichunlea@me.com>
cjahv <cjahv@qq.com>
clinyong <clinyong@gmail.com>
codesign <zuishiguang@126.com>
@ -430,6 +497,7 @@ djorkaeff <djorkae55@gmail.com>
duzliang <duzliang@gmail.com>
ecofe <150641329@qq.com>
edgji <j.edgji@gmail.com>
eidonjoe <806488716@qq.com>
elios <elios264@hotmail.com>
elrrrrrrr <elrrrrrrr@gmail.com>
ezpub <ez.foro@gmail.com>
@ -440,6 +508,7 @@ frezc <504021398@qq.com>
genie <genie88@163.com>
gregahren <grega.hren@gmail.com>
guifu <picodoth@gmail.com>
gyh9457 <gyh9457@163.com>
handycode <lihandi@gmail.com>
hank <stonehank310@gmail.com>
hanpei <75189218@qq.com>
@ -453,15 +522,21 @@ henryv0 <henryvo94@gmail.com>
hi-caicai <hi@cai-cai.me>
hongxuWei <hongxu.wei@outlook.com>
huangyan.py <huangyan.py@bytedance.com>
huishiyi <zhou1maple@gmail.com>
huzzbuzz <huzzbuzz@outlook.com>
iamcastelli <sowed@cyberdude.com>
ilanus <hasanovtk@gmail.com>
imhele <work@imhele.com>
imosapatryk <imosa.patryk@gmail.com>
infeng <fzhihao@outlook.com>
int2d <int2d@qq.com>
iojichervo <ioji@chervonagura.com.ar>
ioldfish <fish.wangl@gmail.com>
iugo <iugogogo@gmail.com>
j3l11234 <297259024@qq.com>
jasonslyvia <jasonslyvia@gmail.com>
jasonxia23 <xia.jason23@gmail.com>
jiajiangxu <minesaner@163.com>
jiang <155259966@qq.com>
jim <wasd2144@hotmail.com>
jinouwuque <ee2win@gmail.com>
@ -476,10 +551,12 @@ kayw <kayw@outlook.com>
kdenz <ksnz93@gmail.com>
kdepp <kdepp.cd@gmail.com>
keng <keng@renderinghouse.com>
kenve <zwei.xie@gmail.com>
keqingrong <keqingrong1992@gmail.com>
ko <git@yaksok.net>
konakona <lovekonakona@gmail.com>
kossel <lis.yichao@gmail.com>
kristof0425 <dombi.kristof@gmail.com>
kuang <p2227@hotmail.com>
kuitos <kuitos.lau@gmail.com>
kun sam <kunsam624@icloud.com>
@ -492,6 +569,7 @@ lgmcolin <lgmcolin@gmail.com>
liangfei <njliangfei@gmail.com>
liekkas <zjq0717@163.com>
lihqi <455711093@qq.com>
lilun <lilun_cd@keruyun.com>
littleLane <857183384@qq.com>
lixiaochou077 <qi.liqi07@gmail.com>
lixiaoyang <lixiaoyang2345@gmail.com>
@ -501,7 +579,9 @@ lizhen <lizhen@youzan.com>
loganpowell <loganp@tepper.cmu.edu>
luyiming <luyimingchn@gmail.com>
lvren <luren6049@qq.com>
lyhper <lyhper@gmail.com>
mArker <252133226@qq.com>
maks <pine3ree@gmail.com>
memoryza <jincai.wang@foxmail.com>
mgrdevport <mgrdevport@gmail.com>
mitchell.demler <mitchell.demler@harcourts.net>
@ -509,15 +589,19 @@ mkermani144 <mkermani144@gmail.com>
mmmveggies <jakeselig@gmail.com>
mofelee <mofe@me.com>
monkindey <monkindey@163.com>
mraiguo <810158465@qq.com>
mraiguo <mraiguo@gmail.com>
mushan0x0 <mushan0x0@gmail.com>
muzea <mr.muzea@gmail.com>
muzuiget <muzuiget@gmail.com>
natergj <nater_nater@me.com>
neekey <ni184775761@gmail.com>
nick-ChenZe <chenze2168@gmail.com>
niko <644506165@qq.com>
nikogu <644506165@qq.com>
nuintun <nuintun@qq.com>
ohhoney1 <1269075501@qq.com>
orzorzorzorz <zy410419243@gmail.com>
paranoidjk <hust2012jiangkai@gmail.com>
parlop <parlop@gmail.com>
pbrink231 <pbrink231@gmail.com>
@ -534,11 +618,16 @@ qixian.cs@outlook.com <wasd2144@hotmail.com>
qliu <1403927509@qq.com>
qubaoming <qubaoming@didichuxing.com>
ravirambles <ravirambles@gmail.com>
richardison <richard.ison@carleton.ca>
ryangun <ryangun@foxmail.com>
ryanhoho <hswacoal@gmail.com>
ryannz <c5e1856@gmail.com>
sadmark <zhoubin@laidian360.com>
sallen450 <jqh101@sina.com>
sdli <1669375803@qq.com>
sfturing <sfturing@gmail.com>
shangyuan.ning <shangyuan.ning@manaowan.com>
shawtung <shawtung@qq.com>
shelwin <wxfans@gmail.com>
shenlin192@gmail.com <shenlin192@gmail.com>
shlice <licesh@gmail.com>
@ -553,32 +642,45 @@ sojournerc <cmeyer@zvelo.com>
sorrycc <sorrycc@gmail.com>
sosohime <theziming@126.com>
spideeee <spideeee@github.com>
stevenyuysy <stevenyuysy@gmail.com>
stickmy <stickmyc@gmail.com>
swindme <swindme@163.com>
sylvanasGone <397009765@qq.com>
syssam <s.y.s.sam.sys@gmail.com>
tangjinzhou <415800467@qq.com>
tangjinzhou <tangjinzhou@yidian-inc.com>
taoweicn <twchn@live.com>
thegatheringstorm <tgs@tgs.blue>
thilo-behnke <jan-thilo.behnke@gmx.de>
tianli.zhao <275287902@qq.com>
tom <caolvchong@gmail.com>
twobin <twobin@live.com>
u3u <qwq@qwq.cat>
undefined <undefined>
ustccjw <317713370@qq.com>
valleykid <valleykiddy@gmail.com>
vgeyi <vgeyiz@126.com>
wangshantao <605682551@qq.com>
wangshuai <wangshuai@momenta.ai>
wangtao0101 <yuecjn@gmail.com>
wangxiaolei <fatelei@gmail.com>
wangxingkang <156148958@qq.com>
wangxingkang <wangxingkang@sensoro.com>
wangxueliang <wangxueliang@yidian-inc.com>
wanli <wanli@qunhemail.com>
warmhug <hualei5280@gmail.com>
whtang906 <whtang906@gmail.com>
wizawu <wizawu@gmail.com>
wonyun <wy393767068@163.com>
wwwxy80s <xiaowangziwxy@gmail.com>
wx1322 <289758716@qq.com>
xiaofan2406 <xiaofan2406@gmail.com>
y-take <y.takey@gmail.com>
yangwukang <yangwukang@boco.com.cn>
yangxiaolin <yangxiao2810279802@gmail.com>
ycjcl868 <45808948@qq.com>
yeliex <yeliex@yeliex.com>
yibu.wang <yibu.wang@orion.co.com>
yiminanci <yiminanci@gmail.com>
yiminghe <yiminghe@gmail.com>
yociduo <yociduo@vip.qq.com>
@ -589,22 +691,28 @@ z <haig8@msn.com>
zack <zxyah@126.com>
zelongc <nickcong123@gmail.com>
zerob4wl <zerob4wl@gmail.com>
zhangguanyu02 <zhangguanyu02@meituan.com>
zhangpc <zhangpc@tenxcloud.com>
zhangyangxue <383632607@qq.com>
zhaocai <lzc09008@gmail.com>
zhaopeidong <lwindscar@gmail.com>
zhujun24 <zhujun87654321@gmail.com>
zhuyue <fuping.dfp@antfin.com>
zilong <jzlxiaohei@163.com>
zinkey <yaya@uloveit.com.cn>
zlljqn <zlljqn@gmail.com>
zollero <corona7@163.com>
zombieJ <smith3816@gmail.com>
zombiej <smith3816@gmail.com>
zongzi531 <zongzi.xy@gmail.com>
ztplz <mysticzt@gmail.com>
zuiidea <zuiiidea@gmail.com>
zy410419243 <zy410419243@gmail.com>
°))))彡 <fisherspy@live.com>
邦 <sqibang@gmail.com>
爱but的苍蝇 <354788473@qq.com>
高力 <3071730@qq.com>
郑旭 <332171564@qq.com>
拷钉 <41830859@qq.com>
苏秦 <646382806@qq.com>
竹尔 <Juelchiang@gmail.com>
@ -615,6 +723,8 @@ zuiidea <zuiiidea@gmail.com>
诸岳 <dengfuping_develop@163.com>
逸达 <dqaria@gmail.com>
诸岳 <fuping.dfp@antfin.com>
二哲 <kodo@forchange.cn>
廖星 <liaoxing.lx@bytedance.com>
刘红 <liuhong1.happy@163.com>
宝码 <noyobo@gmail.com>
陈帅 <qixian.cs@outlook.com>
@ -623,12 +733,15 @@ zuiidea <zuiiidea@gmail.com>
愚道 <tingzhao.ytz@antfin.com>
陈帅 <wasd2144@hotmail.com>
松子 <window.pibarr@gmail.com>
何乐 <work@imhele.com>
付引 <xxxquotes@gmail.com>
可乐 <zaxlct@foxmail.com>
山客 <zeakhold@gmail.com>
曾凯 <zengkai2009@foxmail.com>
低位 <zhujun87654321@gmail.com>
信鑫-King <45808948@qq.com>
广彬-梁 <326741518@qq.com>
小哈husky <951565664@qq.com>
何志勇 <15988134176@163.com>
徐坤龙 <272992168@qq.com>
黄子毅 <576625322@qq.com>
@ -637,18 +750,25 @@ zuiidea <zuiiidea@gmail.com>
黄文鉴 <concefly@foxmail.com>
董天成 <dongtiangche@outlook.com>
方剑成 <fjc0kb@gmail.com>
陈广亮 <geraldchen890806@gmail.com>
包子熊 <hezhiyu233@foxmail.com>
闲耘™ <hotoo.cn@gmail.com>
一喵呜 <hyb628@gmail.com>
黄俊亮 <jayhuang@easyops.cn>
吕立青 <jimmy.jinglv@gmail.com>
隋鑫磊 <joshuasui@gmail.com>
米老朱 <laozhu.me@gmail.com>
乔奕轩 <qiao_yixuan@163.com>
马斯特 <sd4399340@126.com>
王集鹄 <wjhu111@21cn.com>
徐新航 <xuxinhang@bytedance.com>
杨哲迪 <yangzhedi@yidian-inc.com>
柚子男 <yozman@sina.com>
愚指导 <yutingzhao1991@sina.com>
郭延豪(708674) <gyh9457@163.com>
愚指导-TZ <yutingzhao1991@sina.com>
杨小事er <Uiryzd@163.com>
杨小事er <uiryzd@163.com>
超能刚哥 <margox@foxmail.com>
马金花儿 <o.o@mug.dog>
रोहन मल्होत्रा <rohan.malhotra@adwyze.com>

View File

@ -15,6 +15,38 @@ timeline: true
---
## 3.13.6
`2019-02-23`
- Form
- 🐞 Use new method to repair align issue of Form.Item with validate message. [#14946](https://github.com/ant-design/ant-design/issues/14946)
- 🐞 Improved warning message logic of generating Form.Item `help` and `validateStatus`. [#14911](https://github.com/ant-design/ant-design/issues/14911)
- 🐞 Fixed extra space at the bottom of Table header in chrome. [#14926](https://github.com/ant-design/ant-design/issues/14926)
- 🐞 Fixed that Select check icon is not aligned center. [#15016](https://github.com/ant-design/ant-design/issues/15016)
- 🐞 Fixed Input.Search `addonBefore` or `addonAfter` style issue. [#14959](https://github.com/ant-design/ant-design/issues/14959)
- 🐞 Fixed growing space of Tree nodes. [#14958](https://github.com/ant-design/ant-design/issues/14958) [@Yangzhedi](https://github.com/Yangzhedi)
- 🐞 Improved accessibility of Icon when `type` is falsy. [#14970](https://github.com/ant-design/ant-design/issues/14970)
- 🐞 Fixed Dropdown subMenu disabled cursor style. [#14952](https://github.com/ant-design/ant-design/issues/14952)
- 🇮🇩 Updated locale to be more natural for Indonesian. [#15013](https://github.com/ant-design/ant-design/issues/15013) [@kamalmahmudi](https://github.com/kamalmahmudi)
## 3.13.5
`2019-02-19`
- 🐞 Revert FormItem with additional place holder. [#14937](https://github.com/ant-design/ant-design/pull/14937)
- 🐞 Adjust Input style to support `text-align: inherit`. [#14912](https://github.com/ant-design/ant-design/pull/14912)
- 🐞 Fix incorrect collapse icon position when Sider in the right. [#14446](https://github.com/ant-design/ant-design/pull/14446)
- 🐞 Fix Table miss top border in some case. [#14922](https://github.com/ant-design/ant-design/pull/14922)
- 🐞 Fix some TypeScript definitions. [#14857](https://github.com/ant-design/ant-design/pull/14857) [#14903](https://github.com/ant-design/ant-design/pull/14903)
## 3.13.4
`2019-02-18`
- 🐞 Fix Table ajax load display no data. [#14898](https://github.com/ant-design/ant-design/pull/14898)
- 🐞 Fix FormItem margin style not correct. [#14886](https://github.com/ant-design/ant-design/pull/14886)
## 3.13.3
`2019-02-16`

View File

@ -15,6 +15,38 @@ timeline: true
---
## 3.13.6
`2019-02-23`
- Form
- 🐞 使用新的方式修复 Form.Item 在有错误提示时的布局对齐问题。[#14946](https://github.com/ant-design/ant-design/issues/14946)
- 🐞 优化 Form.Item 自动生成 `help``validateStatus` 的警告信息。[#14911](https://github.com/ant-design/ant-design/issues/14911)
- 🐞 修复 chrome 下 Table 列头有一点额外空白的样式问题。[#14926](https://github.com/ant-design/ant-design/issues/14926)
- 🐞 修复 Select 选中图标位置偏下的问题。[#15016](https://github.com/ant-design/ant-design/issues/15016)
- 🐞 修复 Input.Search 增加 `addonBefore``addonAfter` 时的样式问题。[#14959](https://github.com/ant-design/ant-design/issues/14959)
- 🐞 修复 Tree 节点内底部边距叠加的问题。[#14958](https://github.com/ant-design/ant-design/issues/14958) [@Yangzhedi](https://github.com/Yangzhedi)
- 🐞 优化 Icon 的 `type` 为空时的可访问性问题。[#14970](https://github.com/ant-design/ant-design/issues/14970)
- 🐞 修复 Dropdown 的菜单失效样式。[#14952](https://github.com/ant-design/ant-design/issues/14952)
- 🇮🇩 优化印度尼西亚国际化文案。[#15013](https://github.com/ant-design/ant-design/issues/15013) [@kamalmahmudi](https://github.com/kamalmahmudi)
## 3.13.5
`2019-02-19`
- 🐞 回滚 FormItem 占位符以修复额外高度的问题。[#14937](https://github.com/ant-design/ant-design/pull/14937)
- 🐞 调整 Input 样式以支持 `text-align: inherit`。[#14912](https://github.com/ant-design/ant-design/pull/14912)
- 🐞 修复 Sider 在右侧收缩时,图标位置不正确的问题。[#14446](https://github.com/ant-design/ant-design/pull/14446)
- 🐞 修复 Table 在某些情况下丢失顶部边框的问题。[#14922](https://github.com/ant-design/ant-design/pull/14922)
- 🐞 修复 TypeScript 类型定义。[#14857](https://github.com/ant-design/ant-design/pull/14857) [#14903](https://github.com/ant-design/ant-design/pull/14903)
## 3.13.4
`2019-02-18`
- 🐞 修复 Table 异步加载没有数据的问题。[#14898](https://github.com/ant-design/ant-design/pull/14898)
- 🐞 修复 FormItem margin 不正确的问题。[#14886](https://github.com/ant-design/ant-design/pull/14886)
## 3.13.3
`2019-02-16`

View File

@ -123,6 +123,6 @@ Read our [contributing guide](https://ant.design/docs/react/contributing) and le
We welcome all contributions. Please read our [CONTRIBUTING.md](https://github.com/ant-design/ant-design/blob/master/.github/CONTRIBUTING.md) first. You can submit any ideas as [pull requests](https://github.com/ant-design/ant-design/pulls) or as [GitHub issues](https://github.com/ant-design/ant-design/issues). If you'd like to improve code, check out the [Development Instructions](https://github.com/ant-design/ant-design/wiki/Development) and have a good time! :)
If you are collaborator. Please follow our [Pull Request principle](https://github.com/ant-design/ant-design/wiki/PR-principle) to create Pull Request by [collaborator template](https://github.com/ant-design/ant-design/compare?expand=1&template=collaborator.md).
If you are a collaborator, please follow our [Pull Request principle](https://github.com/ant-design/ant-design/wiki/PR-principle) to create a Pull Request by [collaborator template](https://github.com/ant-design/ant-design/compare?expand=1&template=collaborator.md).
[![Let's fund issues in this repository](https://issuehunt.io/static/embed/issuehunt-button-v1.svg)](https://issuehunt.io/repos/34526884)

View File

@ -1,9 +1,9 @@
import warning from 'warning';
const warned: Record<string, boolean> = {};
export default (valid: boolean, message: string): void => {
export default (valid: boolean, component: string, message: string): void => {
if (!valid && !warned[message]) {
warning(false, message);
warning(false, `[antd: ${component}] ${message}`);
warned[message] = true;
}
};

View File

@ -64,6 +64,7 @@ export default class Breadcrumb extends React.Component<BreadcrumbProps, any> {
const props = this.props;
warning(
!('linkRender' in props || 'nameRender' in props),
'Breadcrumb',
'`linkRender` and `nameRender` are removed, please use `itemRender` instead, ' +
'see: https://u.ant.design/item-render.',
);
@ -106,7 +107,8 @@ export default class Breadcrumb extends React.Component<BreadcrumbProps, any> {
}
warning(
element.type && element.type.__ANT_BREADCRUMB_ITEM,
"Breadcrumb only accepts Breadcrumb.Item as it's children",
'Breadcrumb',
"Only accepts Breadcrumb.Item as it's children",
);
return cloneElement(element, {
separator,

View File

@ -23,7 +23,7 @@ describe('Breadcrumb', () => {
);
expect(errorSpy.mock.calls).toHaveLength(1);
expect(errorSpy.mock.calls[0][0]).toMatch(
"Breadcrumb only accepts Breadcrumb.Item as it's children",
"Warning: [antd: Breadcrumb] Only accepts Breadcrumb.Item as it's children",
);
});

View File

@ -147,4 +147,18 @@ describe('Calendar', () => {
expect(wrapper.render()).toMatchSnapshot();
MockDate.reset();
});
it('should trigger onPanelChange when click last month of date', () => {
const onPanelChange = jest.fn();
const date = new Moment('1990-09-03');
const wrapper = mount(<Calendar onPanelChange={onPanelChange} value={date} />);
wrapper
.find('.ant-fullcalendar-cell')
.at(0)
.simulate('click');
expect(onPanelChange).toBeCalled();
expect(onPanelChange.mock.calls[0][0].month()).toEqual(date.month() - 1);
});
});

View File

@ -128,15 +128,21 @@ export default class Calendar extends React.Component<CalendarProps, CalendarSta
};
setValue = (value: moment.Moment, way: 'select' | 'changePanel') => {
const prevValue = this.props.value || this.state.value;
const { mode } = this.state;
if (!('value' in this.props)) {
this.setState({ value });
}
if (way === 'select') {
if (prevValue && prevValue.month() !== value.month()) {
this.onPanelChange(value, mode);
}
if (this.props.onSelect) {
this.props.onSelect(value);
}
} else if (way === 'changePanel') {
this.onPanelChange(value, this.state.mode);
this.onPanelChange(value, mode);
}
};

View File

@ -8,7 +8,7 @@ export interface CardGridProps {
className?: string;
}
export default (props: CardGridProps) => (
const Grid: React.SFC<CardGridProps> = props => (
<ConfigConsumer>
{({ getPrefixCls }: ConfigConsumerProps) => {
const { prefixCls: customizePrefixCls, className, ...others } = props;
@ -18,3 +18,5 @@ export default (props: CardGridProps) => (
}}
</ConfigConsumer>
);
export default Grid;

View File

@ -11,7 +11,7 @@ export interface CardMetaProps {
description?: React.ReactNode;
}
export default (props: CardMetaProps) => (
const Meta: React.SFC<CardMetaProps> = props => (
<ConfigConsumer>
{({ getPrefixCls }: ConfigConsumerProps) => {
const {
@ -45,3 +45,5 @@ export default (props: CardMetaProps) => (
}}
</ConfigConsumer>
);
export default Meta;

View File

@ -71,11 +71,13 @@ export default class Card extends React.Component<CardProps, CardState> {
if ('noHovering' in this.props) {
warning(
!this.props.noHovering,
'`noHovering` of Card is deprecated, you can remove it safely or use `hoverable` instead.',
'Card',
'`noHovering` is deprecated, you can remove it safely or use `hoverable` instead.',
);
warning(
!!this.props.noHovering,
'`noHovering={false}` of Card is deprecated, use `hoverable` instead.',
'Card',
'`noHovering={false}` is deprecated, use `hoverable` instead.',
);
}
}

View File

@ -425,7 +425,7 @@ describe('Cascader', () => {
wrapper.find('input').simulate('change', { target: { value: 'a' } });
expect(wrapper.find('.ant-cascader-menu-item').length).toBe(2);
expect(errorSpy).toBeCalledWith(
"Warning: 'limit' of showSearch in Cascader should be positive number or false.",
"Warning: [antd: Cascader] 'limit' of showSearch should be positive number or false.",
);
});
});

View File

@ -366,7 +366,8 @@ class Cascader extends React.Component<CascaderProps, CascaderState> {
} else {
warning(
typeof limit !== 'number',
"'limit' of showSearch in Cascader should be positive number or false.",
'Cascader',
"'limit' of showSearch should be positive number or false.",
);
filtered = flattenOptions.filter(path => filter(this.state.inputValue, path, names));
}

View File

@ -164,9 +164,6 @@ exports[`renders ./components/comment/demo/editor.md correctly 1`] = `
rows="4"
/>
</span>
<div
class="ant-form-explain-holder"
/>
</div>
</div>
</div>
@ -191,9 +188,6 @@ exports[`renders ./components/comment/demo/editor.md correctly 1`] = `
</span>
</button>
</span>
<div
class="ant-form-explain-holder"
/>
</div>
</div>
</div>

View File

@ -7043,13 +7043,9 @@ exports[`ConfigProvider components Form configProvider 1`] = `
/>
</span>
<div
class="config-form-explain-holder"
class="config-form-explain"
>
<span
class="config-form-explain"
>
Bamboo is Light
</span>
Bamboo is Light
</div>
</div>
</div>
@ -7080,13 +7076,9 @@ exports[`ConfigProvider components Form normal 1`] = `
/>
</span>
<div
class="ant-form-explain-holder"
class="ant-form-explain"
>
<span
class="ant-form-explain"
>
Bamboo is Light
</span>
Bamboo is Light
</div>
</div>
</div>
@ -7117,13 +7109,9 @@ exports[`ConfigProvider components Form prefixCls 1`] = `
/>
</span>
<div
class="prefix-Form-explain-holder"
class="prefix-Form-explain"
>
<span
class="prefix-Form-explain"
>
Bamboo is Light
</span>
Bamboo is Light
</div>
</div>
</div>

View File

@ -291,7 +291,11 @@ class RangePicker extends React.Component<any, RangePickerState> {
fixLocale(value, localeCode);
fixLocale(showDate, localeCode);
warning(!('onOK' in props), 'It should be `RangePicker[onOk]`, instead of `onOK`!');
warning(
!('onOK' in props),
'RangePicker',
'It should be `RangePicker[onOk]`, instead of `onOK`!',
);
const calendarClassName = classNames({
[`${prefixCls}-time`]: showTime,

View File

@ -17,6 +17,11 @@ describe('DatePicker', () => {
MockDate.reset();
});
it('support name prop', () => {
const wrapper = mount(<DatePicker name="bamboo" />);
expect(wrapper.find('input').props().name).toBe('bamboo');
});
it('prop locale should works', () => {
const locale = {
lang: {

View File

@ -172,6 +172,7 @@ export default function createPicker(TheCalendar: React.ComponentClass): any {
warning(
!('onOK' in props),
'DatePicker',
'It should be `DatePicker[onOk]` or `MonthPicker[onOk]`, instead of `onOK`!',
);
const calendar = (
@ -230,6 +231,7 @@ export default function createPicker(TheCalendar: React.ComponentClass): any {
placeholder={placeholder}
className={props.pickerInputClass}
tabIndex={props.tabIndex}
name={props.name}
{...dataOrAriaProps}
/>
{clearIcon}

View File

@ -22,7 +22,7 @@ subtitle: 日期选择框
### 国际化配置
默认配置为 en-US如果你需要设置其他语言推荐在入口处使用我们提供的国际化组件,详见:[LocaleProvider国际化](http://ant.design/components/locale-provider-cn/)。
默认配置为 en-US如果你需要设置其他语言推荐在入口处使用我们提供的国际化组件详见:[LocaleProvider国际化](http://ant.design/components/locale-provider-cn/)。
如有特殊需求(仅修改单一组件的语言),请使用 locale 参数,参考:[默认配置](https://github.com/ant-design/ant-design/blob/master/components/date-picker/locale/example.json)。

View File

@ -1,9 +1,11 @@
import * as React from 'react';
import * as moment from 'moment';
import { TimePickerProps } from '../time-picker';
import { tuple } from '../_util/type';
export interface PickerProps {
id?: number | string;
name?: string;
prefixCls?: string;
inputPrefixCls?: string;
format?: string | string[];
@ -31,6 +33,9 @@ export interface SinglePickerProps {
onChange?: (date: moment.Moment, dateString: string) => void;
}
const DatePickerModes = tuple('time', 'date', 'month', 'year');
export type DatePickerMode = (typeof DatePickerModes)[number];
export interface DatePickerProps extends PickerProps, SinglePickerProps {
className?: string;
showTime?: TimePickerProps | boolean;
@ -44,9 +49,10 @@ export interface DatePickerProps extends PickerProps, SinglePickerProps {
disabledSeconds?: () => number[];
};
onOpenChange?: (status: boolean) => void;
onPanelChange?: (value: moment.Moment | undefined, mode: DatePickerMode) => void;
onOk?: (selectedTime: moment.Moment) => void;
placeholder?: string;
mode?: 'time' | 'date' | 'month' | 'year';
mode?: DatePickerMode;
}
export interface MonthPickerProps extends PickerProps, SinglePickerProps {

View File

@ -37,6 +37,7 @@ export interface DrawerProps {
placement?: placementType;
onClose?: (e: EventType) => void;
className?: string;
handler?: React.ReactNode;
}
export interface IDrawerState {
@ -234,6 +235,7 @@ class Drawer extends React.Component<DrawerProps & ConfigConsumerProps, IDrawerS
} = this.props;
warning(
wrapClassName === undefined,
'Drawer',
'wrapClassName is deprecated, please use className instead.',
);
const haveMask = rest.mask ? '' : 'no-mask';

View File

@ -19,13 +19,26 @@ type Placement = (typeof Placements)[number];
type OverlayFunc = () => React.ReactNode;
type Align = {
points?: [string, string];
offset?: [number, number];
targetOffset?: [number, number];
overflow?: {
adjustX?: boolean;
adjustY?: boolean;
};
useCssRight?: boolean;
useCssBottom?: boolean;
useCssTransform?: boolean;
};
export interface DropDownProps {
trigger?: ('click' | 'hover' | 'contextMenu')[];
overlay: React.ReactNode | OverlayFunc;
onVisibleChange?: (visible: boolean) => void;
visible?: boolean;
disabled?: boolean;
align?: Object;
align?: Align;
getPopupContainer?: (triggerNode: Element) => HTMLElement;
prefixCls?: string;
className?: string;
@ -76,6 +89,7 @@ export default class Dropdown extends React.Component<DropDownProps, any> {
// Warning if use other mode
warning(
!overlayProps.mode || overlayProps.mode === 'vertical',
'Dropdown',
`mode="${overlayProps.mode}" is not supported for Dropdown\'s Menu.`,
);

View File

@ -162,6 +162,8 @@
&,
.@{dropdown-prefix-cls}-menu-submenu-arrow-icon {
color: @disabled-color;
background-color: @component-background;
cursor: not-allowed;
}
}
}

View File

@ -226,7 +226,7 @@ export default class Form extends React.Component<FormProps, any> {
constructor(props: FormProps) {
super(props);
warning(!props.form, 'It is unnecessary to pass `form` to `Form` after antd@1.7.0.');
warning(!props.form, 'Form', 'It is unnecessary to pass `form` to `Form` after antd@1.7.0.');
}
renderForm = ({ getPrefixCls }: ConfigConsumerProps) => {

View File

@ -57,9 +57,12 @@ export default class FormItem extends React.Component<FormItemProps, any> {
helpShow = false;
componentDidMount() {
const { children, help, validateStatus } = this.props;
warning(
this.getControls(this.props.children, true).length <= 1,
'`Form.Item` cannot generate `validateStatus` and `help` automatically, ' +
this.getControls(children, true).length <= 1 ||
(help !== undefined || validateStatus !== undefined),
'Form.Item',
'Cannot generate `validateStatus` and `help` automatically, ' +
'while there are more than one `getFieldDecorator` in it.',
);
}
@ -148,26 +151,23 @@ export default class FormItem extends React.Component<FormItemProps, any> {
renderHelp(prefixCls: string) {
const help = this.getHelpMessage();
const children = help ? (
<span className={`${prefixCls}-explain`} key="help">
<div className={`${prefixCls}-explain`} key="help">
{help}
</span>
</div>
) : null;
if (children) {
this.helpShow = !!children;
}
return (
<div className={`${prefixCls}-explain-holder`}>
<Animate
transitionName="show-help"
component=""
transitionAppear
key="help"
onEnd={this.onHelpAnimEnd}
>
{children}
</Animate>
</div>
<Animate
transitionName="show-help"
component=""
transitionAppear
key="help"
onEnd={this.onHelpAnimEnd}
>
{children}
</Animate>
);
}

File diff suppressed because it is too large Load Diff

View File

@ -35,21 +35,17 @@ exports[`Form should display custom message 1`] = `
/>
</span>
<div
class="ant-form-explain-holder"
class="ant-form-explain show-help-enter"
>
<span
class="ant-form-explain show-help-enter"
>
<span>
Account does not exist,
<a
href="https://www.alipay.com/"
rel="noopener noreferrer"
target="_blank"
>
Forgot account?
</a>
</span>
<span>
Account does not exist,
<a
href="https://www.alipay.com/"
rel="noopener noreferrer"
target="_blank"
>
Forgot account?
</a>
</span>
</div>
</div>
@ -93,13 +89,9 @@ exports[`Form should display two message 1`] = `
/>
</span>
<div
class="ant-form-explain-holder"
class="ant-form-explain show-help-enter"
>
<span
class="ant-form-explain show-help-enter"
>
Error message 1 Error message 2
</span>
Error message 1 Error message 2
</div>
</div>
</div>
@ -142,19 +134,15 @@ exports[`Form support error message with reactNode 1`] = `
/>
</span>
<div
class="ant-form-explain-holder"
class="ant-form-explain show-help-enter"
>
<span
class="ant-form-explain show-help-enter"
>
<div>
Error 1
</div>
<div>
Error 2
</div>
</span>
<div>
Error 1
</div>
<div>
Error 2
</div>
</div>
</div>
</div>

View File

@ -5,7 +5,7 @@ import Form from '..';
describe('Form', () => {
// Mock of `querySelector`
const originQuerySelector = HTMLElement.prototype.querySelector;
HTMLElement.prototype.querySelector = function(str) {
HTMLElement.prototype.querySelector = function querySelector(str) {
const match = str.match(/^\[id=('|")(.*)('|")]$/);
const id = match && match[2];

View File

@ -87,4 +87,43 @@ describe('Form', () => {
expect(wrapper.render()).toMatchSnapshot();
});
it('should print warning for not generating help and validateStatus automatically', () => {
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
const Form1 = Form.create()(({ form }) => {
return (
<Form>
<Form.Item label="Account">
{form.getFieldDecorator('account')(<input />)}
{form.getFieldDecorator('account')(<input />)}
</Form.Item>
</Form>
);
});
mount(<Form1 />);
expect(errorSpy).toBeCalledWith(
'Warning: [antd: Form.Item] Cannot generate `validateStatus` and `help` automatically, while there are more than one `getFieldDecorator` in it.',
);
errorSpy.mockRestore();
});
// https://github.com/ant-design/ant-design/issues/14911
it('should not print warning for not generating help and validateStatus automatically when help or validateStatus is specified', () => {
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
const Form1 = Form.create()(({ form }) => {
return (
<Form>
<Form.Item label="Account" help="custom help information">
{form.getFieldDecorator('account')(<input />)}
{form.getFieldDecorator('account')(<input />)}
</Form.Item>
</Form>
);
});
mount(<Form1 />);
expect(errorSpy).not.toHaveBeenCalled();
errorSpy.mockRestore();
});
});

View File

@ -10,14 +10,18 @@ title:
自定义或第三方的表单控件,也可以与 Form 组件一起使用。只要该组件遵循以下的约定:
> * 提供受控属性 `value` 或其它与 [`valuePropName`](http://ant.design/components/form/#getFieldDecorator-参数) 的值同名的属性。
> * 提供 `onChange` 事件或 [`trigger`](http://ant.design/components/form/#getFieldDecorator-参数) 的值同名的事件。
> * 不能是函数式组件。
> * 支持 ref
> * React@16.8.0 之前只有 Class 组件支持。
> * React@16.8.0 及之后可以通过 [useImperativeHandle](https://reactjs.org/docs/hooks-reference.html#useimperativehandle) 添加 ref 支持。([示例](https://codesandbox.io/s/31mv8004rp)
## en-US
Customized or third-party form controls can be used in Form, too. Controls must follow these conventions:
> * It has a controlled property `value` or other name which is equal to the value of [`valuePropName`](http://ant.design/components/form/?locale=en-US#getFieldDecorator's-parameters).
> * It has event `onChange` or an event which name is equal to the value of [`trigger`](http://ant.design/components/form/?locale=en-US#getFieldDecorator's-parameters).
> * It must be a class component.
> * Support ref:
> * Can only use class component before React@16.8.0.
> * Can use [useImperativeHandle](https://reactjs.org/docs/hooks-reference.html#useimperativehandle) to add ref support after React@16.8.0. ([Sample](https://codesandbox.io/s/31mv8004rp))
````jsx
import {

View File

@ -0,0 +1,162 @@
---
order: 99
title:
zh-CN: 提交修改前看看这个对不对
en-US: Please check this before commit
debug: true
---
## zh-CN
提交修改前看看这个对不对。
## en-US
Please check this before commit.
````jsx
import {
Button, Modal, Form, Row, Col, Input, Select, InputNumber, Radio, DatePicker,
} from 'antd';
const RadioGroup = Radio.Group;
const ColSpan = {lg:12,md:24};
class App extends React.Component {
constructor() {
super();
this.state = {
visible: false,
};
}
handleClick = () => {
this.setState({
visible: true,
});
};
handleCancel = () => {
this.setState({
visible: false,
});
};
handleSubmit = e => {
e.preventDefault();
const { form } = this.props;
form.validateFields((error, values) => {
console.log(error, values);
});
};
render() {
const {
form: { getFieldDecorator },
} = this.props;
const { Item } = Form;
const itemLayout = {
labelCol: { span: 6 },
wrapperCol: { span: 16 },
};
const span = 12;
return (
<div>
{/* Case 1: Form in modal */}
<Button onClick={this.handleClick}>打开</Button>
<Modal
onOk={this.handleSubmit}
onCancel={this.handleCancel}
title="弹出层"
visible={this.state.visible}
>
<Form layout="horizontal" onSubmit={this.handleSubmit}>
<Row>
<Col span={span}>
<Item {...itemLayout} label="测试字段">
{getFieldDecorator("item1", {
rules: [{ required: true, message: "请必须填写此字段" }],
})(<Input />)}
</Item>
</Col>
<Col span={span}>
<Item {...itemLayout} label="测试字段">
{getFieldDecorator("item2", {
rules: [{ required: true, message: "请必须填写此字段" }],
})(<Input />)}
</Item>
</Col>
<Col span={span}>
<Item {...itemLayout} label="测试字段">
{getFieldDecorator("item3")(<Input />)}
</Item>
</Col>
<Col span={span}>
<Item {...itemLayout} label="测试字段">
{getFieldDecorator("item4", {
rules: [{ required: true, message: "请必须填写此字段" }],
})(<Input />)}
</Item>
</Col>
<Col span={span}>
<Item {...itemLayout} label="测试字段">
{getFieldDecorator("item5", {
rules: [{ required: true, message: "请必须填写此字段" }],
})(<Input />)}
</Item>
</Col>
<Col span={span}>
<Item {...itemLayout} label="测试字段">
{getFieldDecorator("item6", {
rules: [{ required: true, message: "请必须填写此字段" }],
})(<Input />)}
</Item>
</Col>
</Row>
</Form>
</Modal>
{/* case 2: Form different item */}
<Form>
<Row gutter={16}>
<Col {...ColSpan}>
<Item label="input:64.5px">
<Input />
</Item>
</Col>
<Col {...ColSpan}>
<Item label="select:64px">
<Select />
</Item>
</Col>
<Col {...ColSpan}>
<Item label="InputNumber:64px">
<InputNumber />
</Item>
</Col>
<Col {...ColSpan}>
<Item label="DatePicker: 64.5px">
<DatePicker />
</Item>
</Col>
<Col {...ColSpan}>
<Item label="RadioGroup: 64px">
<RadioGroup>
<Radio value={0}></Radio>
<Radio value={1}></Radio>
</RadioGroup>
</Item>
</Col>
</Row>
</Form>
</div>
);
}
}
const WrapApp = Form.create()(App);
ReactDOM.render(<WrapApp />, mountNode);
````

View File

@ -10,6 +10,11 @@
@form-component-max-height: @input-height-lg;
@form-feedback-icon-size: @font-size-base;
@form-help-margin-top: (@form-component-height - @form-component-max-height) / 2 + 2px;
// Extends additional 1px to fix precision issue.
// https://github.com/ant-design/ant-design/issues/12803
// https://github.com/ant-design/ant-design/issues/8220
@form-explain-precision: 1px;
@form-explain-height: floor(@font-size-base * @line-height-base);
.@{form-prefix-cls} {
.reset-component;
@ -71,13 +76,12 @@ input[type='checkbox'] {
}
.reset-component;
margin-bottom: @form-item-margin-bottom - @font-size-base * @line-height-base -
@form-help-margin-top;
margin-bottom: @form-item-margin-bottom;
vertical-align: top;
&-control {
position: relative;
line-height: @form-component-max-height - 0.0001px; // https://github.com/ant-design/ant-design/issues/8220
line-height: @form-component-max-height;
.clearfix;
}
@ -85,6 +89,10 @@ input[type='checkbox'] {
position: relative;
}
&-with-help {
margin-bottom: @form-item-margin-bottom - @form-explain-height - @form-help-margin-top;
}
&-label {
display: inline-block;
overflow: hidden;
@ -119,29 +127,20 @@ input[type='checkbox'] {
}
}
.@{form-prefix-cls}-explain-holder {
line-height: @line-height-base;
&::before {
content: '\00A0'; // Use non-space character to keep the same height
display: inline-block;
width: 0;
overflow: hidden;
}
.@{form-prefix-cls}-explain {
display: inline-block;
}
}
.@{form-prefix-cls}-explain,
.@{form-prefix-cls}-extra {
clear: both;
min-height: @form-explain-height + @form-explain-precision;
margin-top: @form-help-margin-top;
color: @text-color-secondary;
line-height: @line-height-base;
transition: color 0.3s @ease-out; // sync input color transition
}
.@{form-prefix-cls}-explain {
margin-bottom: -@form-explain-precision;
}
.@{form-prefix-cls}-extra {
padding-top: 4px;
}
@ -343,7 +342,10 @@ form {
.@{form-prefix-cls}-item-control {
line-height: @line-height-base;
}
.@{form-prefix-cls}-explain,
.@{form-prefix-cls}-explain {
margin-top: 2px;
margin-bottom: -4px - @form-explain-precision;
}
.@{form-prefix-cls}-extra {
margin-top: 2px;
margin-bottom: -4px;
@ -389,11 +391,7 @@ form {
margin-bottom: 0;
&-with-help {
margin-bottom: 24px;
}
&::before {
display: none;
margin-bottom: @form-item-margin-bottom;
}
> .@{form-prefix-cls}-item-control-wrapper,
@ -599,6 +597,16 @@ form {
}
}
.@{ant-prefix}-advanced-search-form {
.@{form-prefix-cls}-item {
margin-bottom: @form-item-margin-bottom;
&-with-help {
margin-bottom: @form-item-margin-bottom - @form-explain-height - @form-help-margin-top;
}
}
}
.show-help-motion(@className, @keyframeName, @duration: @animation-duration-slow) {
.make-motion(@className, @keyframeName, @duration);
.@{className}-enter,

View File

@ -100,10 +100,10 @@ export default class Col extends React.Component<ColProps, {}> {
<RowContext.Consumer>
{({ gutter }) => {
let style = others.style;
if ((gutter as number) > 0) {
if (gutter! > 0) {
style = {
paddingLeft: (gutter as number) / 2,
paddingRight: (gutter as number) / 2,
paddingLeft: gutter! / 2,
paddingRight: gutter! / 2,
...style,
};
}

View File

@ -138,10 +138,10 @@ export default class Row extends React.Component<RowProps, RowState> {
className,
);
const rowStyle =
(gutter as number) > 0
gutter! > 0
? {
marginLeft: (gutter as number) / -2,
marginRight: (gutter as number) / -2,
marginLeft: gutter! / -2,
marginRight: gutter! / -2,
...style,
}
: style;

View File

@ -2,7 +2,6 @@
exports[`Icon \`component\` prop can access to svg defs if has children 1`] = `
<i
aria-label="icon: undefined"
class="anticon my-home-icon"
>
<svg
@ -25,7 +24,6 @@ exports[`Icon \`component\` prop can access to svg defs if has children 1`] = `
exports[`Icon should give warning and render <i>{null}</i> 1`] = `
<i
aria-label="icon: undefined"
class="anticon"
/>
`;
@ -258,7 +256,6 @@ exports[`Icon should support older usage 1`] = `
exports[`Icon should support pass svg paths as children 1`] = `
<i
aria-label="icon: undefined"
class="anticon"
>
<svg
@ -282,7 +279,6 @@ exports[`Icon should support pass svg paths as children 1`] = `
exports[`Icon should support svg react component 1`] = `
<i
aria-label="icon: undefined"
class="anticon my-home-icon"
>
<svg
@ -335,7 +331,6 @@ exports[`Icon should support two-tone icon 1`] = `
exports[`Icon support render svg as component 1`] = `
<i
aria-label="icon: undefined"
class="anticon"
>
<svg
@ -352,7 +347,6 @@ exports[`Icon.createFromIconfontCN() should support iconfont.cn 1`] = `
class="icons-list"
>
<i
aria-label="icon: undefined"
class="anticon"
>
<svg
@ -369,7 +363,6 @@ exports[`Icon.createFromIconfontCN() should support iconfont.cn 1`] = `
</svg>
</i>
<i
aria-label="icon: undefined"
class="anticon"
>
<svg
@ -386,7 +379,6 @@ exports[`Icon.createFromIconfontCN() should support iconfont.cn 1`] = `
</svg>
</i>
<i
aria-label="icon: undefined"
class="anticon"
>
<svg

View File

@ -121,7 +121,7 @@ describe('Icon', () => {
it('warns', () => {
mount(<Icon type="clock-circle-o" theme="filled" />);
expect(errorSpy).toBeCalledWith(
"Warning: The icon name 'clock-circle-o' already specify a theme 'outlined', the 'theme' prop 'filled' will be ignored.",
"Warning: [antd: Icon] The icon name 'clock-circle-o' already specify a theme 'outlined', the 'theme' prop 'filled' will be ignored.",
);
});
});

View File

@ -91,7 +91,8 @@ const Icon: IconComponent<IconProps> = props => {
warning(
Boolean(type || Component || children),
'Icon should have `type` prop or `component` prop or `children`.',
'Icon',
'Should have `type` prop or `component` prop or `children`.',
);
const classString = classNames(
@ -137,6 +138,7 @@ const Icon: IconComponent<IconProps> = props => {
(React.Children.count(children) === 1 &&
React.isValidElement(children) &&
React.Children.only(children).type === 'use'),
'Icon',
'Make sure that you provide correct `viewBox`' +
' prop (default `0 0 1024 1024`) to the icon.',
);
@ -153,6 +155,7 @@ const Icon: IconComponent<IconProps> = props => {
const themeInName = getThemeFromTypeName(type);
warning(
!themeInName || theme === themeInName,
'Icon',
`The icon name '${type}' already specify a theme '${themeInName}',` +
` the 'theme' prop '${theme}' will be ignored.`,
);
@ -180,7 +183,7 @@ const Icon: IconComponent<IconProps> = props => {
<LocaleReceiver componentName="Icon">
{(locale: TransferLocale) => (
<i
aria-label={`${locale.icon}: ${type}`}
aria-label={type && `${locale.icon}: ${type}`}
{...restProps}
tabIndex={iconTabIndex}
onClick={onClick}
@ -196,6 +199,7 @@ const Icon: IconComponent<IconProps> = props => {
function unstable_ChangeThemeOfIconsDangerously(theme?: ThemeType) {
warning(
false,
'Icon',
`You are using the unstable method 'Icon.unstable_ChangeThemeOfAllIconsDangerously', ` +
`make sure that all the icons with theme '${theme}' display correctly.`,
);
@ -205,6 +209,7 @@ function unstable_ChangeThemeOfIconsDangerously(theme?: ThemeType) {
function unstable_ChangeDefaultThemeOfIcons(theme: ThemeType) {
warning(
false,
'Icon',
`You are using the unstable method 'Icon.unstable_ChangeDefaultThemeOfIcons', ` +
`make sure that all the icons with theme '${theme}' display correctly.`,
);

View File

@ -43,7 +43,7 @@ export function withThemeSuffix(type: string, theme: ThemeType) {
} else if (theme === 'twoTone') {
result += '-twotone';
} else {
warning(false, `This icon '${type}' has unknown theme '${theme}'`);
warning(false, 'Icon', `This icon '${type}' has unknown theme '${theme}'`);
}
return result;
}

View File

@ -10,6 +10,7 @@ import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import Password from './Password';
import Icon from '../icon';
import { Omit, tuple } from '../_util/type';
import warning from '../_util/warning';
function fixControlledValue<T>(value: T) {
if (typeof value === 'undefined' || value === null) {
@ -18,6 +19,10 @@ function fixControlledValue<T>(value: T) {
return value;
}
function hasPrefixSuffix(props: InputProps) {
return 'prefix' in props || props.suffix || props.allowClear;
}
const InputSizes = tuple('small', 'default', 'large');
export interface InputProps
@ -84,6 +89,21 @@ class Input extends React.Component<InputProps, any> {
};
}
getSnapshotBeforeUpdate(prevProps: InputProps) {
if (hasPrefixSuffix(prevProps) !== hasPrefixSuffix(this.props)) {
warning(
this.input !== document.activeElement,
'Input',
`When Input is focused, dynamic add or remove prefix / suffix will make it lose focus caused by dom structure change. Read more: https://ant.design/components/input/#FAQ`,
);
}
return null;
}
// Since polyfill `getSnapshotBeforeUpdate` need work with `componentDidUpdate`.
// We keep an empty function here.
componentDidUpdate() {}
handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
const { onPressEnter, onKeyDown } = this.props;
if (e.keyCode === 13 && onPressEnter) {
@ -224,7 +244,7 @@ class Input extends React.Component<InputProps, any> {
const { props } = this;
const suffix = this.renderSuffix(prefixCls);
if (!('prefix' in props) && !suffix) {
if (!hasPrefixSuffix(props)) {
return children;
}

View File

@ -245,22 +245,29 @@ exports[`renders ./components/input/demo/group.md correctly 1`] = `
class="ant-input-group ant-input-group-lg"
>
<div
class="ant-col-5"
class="ant-row"
style="margin-left:-4px;margin-right:-4px"
>
<input
class="ant-input"
type="text"
value="0571"
/>
</div>
<div
class="ant-col-8"
>
<input
class="ant-input"
type="text"
value="26888888"
/>
<div
class="ant-col-5"
style="padding-left:4px;padding-right:4px"
>
<input
class="ant-input"
type="text"
value="0571"
/>
</div>
<div
class="ant-col-8"
style="padding-left:4px;padding-right:4px"
>
<input
class="ant-input"
type="text"
value="26888888"
/>
</div>
</div>
</span>
<br />

View File

@ -19,7 +19,7 @@ Note: You don't need `Col` to control the width in the `compact` mode.
````jsx
import {
Input, Col, Select, InputNumber, DatePicker, AutoComplete, Cascader,
Input, Col, Row, Select, InputNumber, DatePicker, AutoComplete, Cascader,
} from 'antd';
const InputGroup = Input.Group;
@ -68,12 +68,14 @@ class CompactDemo extends React.Component {
return (
<div>
<InputGroup size="large">
<Col span={5}>
<Input defaultValue="0571" />
</Col>
<Col span={8}>
<Input defaultValue="26888888" />
</Col>
<Row gutter={8}>
<Col span={5}>
<Input defaultValue="0571" />
</Col>
<Col span={8}>
<Input defaultValue="26888888" />
</Col>
</Row>
</InputGroup>
<br />
<InputGroup compact>

View File

@ -1,8 +1,8 @@
---
order: 8
title:
zh-CN: 前缀和后缀
en-US: prefix and suffix
zh-CN: 前缀和后缀
en-US: prefix and suffix
---
## zh-CN

View File

@ -45,7 +45,7 @@ class NumericInput extends React.Component {
onBlur = () => {
const { value, onBlur, onChange } = this.props;
if (value.charAt(value.length - 1) === '.' || value === '-') {
onChange({ value: value.slice(0, -1) });
onChange(value.slice(0, -1));
}
if (onBlur) {
onBlur();

View File

@ -56,7 +56,7 @@ The rest of the props of `Input.TextArea` are the same as the original [textarea
| Property | Description | Type | Default |
| -------- | ----------- | ---- | ------- |
| enterButton | to show an enter button after input | boolean\|ReactNode | false |
| enterButton | to show an enter button after input. This prop is conflict with addon. | boolean\|ReactNode | false |
| onSearch | The callback function that is triggered when you click on the search-icon or press Enter key. | function(value, event) | |
Supports all props of `Input`.
@ -80,3 +80,16 @@ Supports all props of `Input`.
| Property | Description | Type | Default |
| --- | --- | --- | --- |
| visibilityToggle | Whether show toggle button | boolean | true |
## FAQ
### Why Input lose focus when change `prefix/suffix`
When Input dynamic add or remove `prefix/suffix` will make React recreate the dom structure and new input will be not focused.
You can set an empty `<span />` element to keep the dom structure:
```jsx
const suffix = condition ? <Icon type="smile" /> : <span />;
<Input suffix={suffix} />
```

View File

@ -53,7 +53,7 @@ Input 的其他属性和 React 自带的 [input](https://facebook.github.io/reac
| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| enterButton | 是否有确认按钮,可设为按钮文字 | boolean\|ReactNode | false |
| enterButton | 是否有确认按钮,可设为按钮文字。该属性会与 addon 冲突。 | boolean\|ReactNode | false |
| onSearch | 点击搜索或按下回车键时的回调 | function(value, event) | |
其余属性和 Input 一致。
@ -77,3 +77,16 @@ Input 的其他属性和 React 自带的 [input](https://facebook.github.io/reac
| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| visibilityToggle | 是否显示切换按钮 | boolean | true |
## FAQ
### 为什么我动态改变 `prefix/suffix`Input 会失去焦点?
当 Input 动态添加或者删除 `prefix/suffix`React 会重新创建 DOM 结构而新的 input 是没有焦点的。
你可以预设一个空的 `<span />` 来保持 DOM 结构不变:
```jsx
const suffix = condition ? <Icon type="smile" /> : <span />;
<Input suffix={suffix} />
```

View File

@ -15,6 +15,7 @@
&-wrapper {
display: inline-block;
width: 100%;
text-align: start;
vertical-align: top; // https://github.com/ant-design/ant-design/issues/6403
}
}

View File

@ -135,6 +135,7 @@
float: left;
width: 100%;
margin-bottom: 0;
text-align: inherit;
&:focus {
z-index: 1; // Fix https://gw.alipayobjects.com/zos/rmsportal/DHNpoqfMXSfrSnlZvhsJ.png
border-right-width: 1px;
@ -346,6 +347,7 @@
position: relative;
display: inline-block;
width: 100%;
text-align: start;
&:hover .@{inputClass}:not(.@{inputClass}-disabled) {
.hover();
@ -353,6 +355,7 @@
.@{inputClass} {
position: relative;
text-align: inherit;
}
.@{inputClass}-prefix,

View File

@ -15,14 +15,20 @@
}
}
.@{ant-prefix}-input-group-addon {
padding: 0;
border: 0;
&-enter-button {
input {
border-right: 0;
}
.@{search-prefix}-button {
width: 100%;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
input + .@{ant-prefix}-input-group-addon {
padding: 0;
border: 0;
.@{search-prefix}-button {
width: 100%;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
}
}
}

View File

@ -213,7 +213,12 @@ class Sider extends React.Component<SiderProps, SiderState> {
// special trigger when collapsedWidth == 0
const zeroWidthTrigger =
parseFloat(String(collapsedWidth || 0)) === 0 ? (
<span onClick={this.toggle} className={`${prefixCls}-zero-width-trigger`}>
<span
onClick={this.toggle}
className={`${prefixCls}-zero-width-trigger ${prefixCls}-zero-width-trigger-${
reverseArrow ? 'right' : 'left'
}`}
>
<Icon type="bars" />
</span>
) : null;

View File

@ -110,6 +110,10 @@
&:hover {
background: tint(@layout-sider-background, 10%);
}
&-right {
left: -@layout-zero-trigger-width;
}
}
}
}

View File

@ -97,16 +97,16 @@ export default class List extends React.Component<ListProps> {
};
}
renderItem = (item: React.ReactElement<any>, index: number) => {
const { dataSource, renderItem, rowKey } = this.props;
renderItem = (item: any, index: number) => {
const { renderItem, rowKey } = this.props;
let key;
if (typeof rowKey === 'function') {
key = rowKey(dataSource[index]);
key = rowKey(item);
} else if (typeof rowKey === 'string') {
key = dataSource[rowKey];
key = item[rowKey];
} else {
key = dataSource.key;
key = item.key;
}
if (!key) {

View File

@ -97265,7 +97265,7 @@ exports[`Locale Provider should display the text as id 1`] = `
type="button"
>
<span>
Membatalkan
Batal
</span>
</button>
<button
@ -97273,7 +97273,7 @@ exports[`Locale Provider should display the text as id 1`] = `
type="button"
>
<span>
baik
OK
</span>
</button>
</div>
@ -97312,7 +97312,7 @@ exports[`Locale Provider should display the text as id 1`] = `
class="ant-transfer-list-header-selected"
>
<span>
0 barang
0 item
</span>
<span
class="ant-transfer-list-header-title"
@ -97328,7 +97328,7 @@ exports[`Locale Provider should display the text as id 1`] = `
<div>
<input
class="ant-input ant-transfer-list-search"
placeholder="Cari di sini"
placeholder="Cari"
type="text"
value=""
/>
@ -97457,7 +97457,7 @@ exports[`Locale Provider should display the text as id 1`] = `
class="ant-transfer-list-header-selected"
>
<span>
0 barang
0 item
</span>
<span
class="ant-transfer-list-header-title"
@ -97473,7 +97473,7 @@ exports[`Locale Provider should display the text as id 1`] = `
<div>
<input
class="ant-input ant-transfer-list-search"
placeholder="Cari di sini"
placeholder="Cari"
type="text"
value=""
/>
@ -98603,7 +98603,7 @@ exports[`Locale Provider should display the text as id 1`] = `
aria-label="icon: filter"
class="anticon anticon-filter ant-dropdown-trigger"
tabindex="-1"
title="Menu filter"
title="Saring"
>
<svg
aria-hidden="true"
@ -98737,7 +98737,7 @@ exports[`Locale Provider should display the text as id 1`] = `
type="button"
>
<span>
Membatalkan
Batal
</span>
</button>
<button
@ -98745,7 +98745,7 @@ exports[`Locale Provider should display the text as id 1`] = `
type="button"
>
<span>
baik
OK
</span>
</button>
</div>

View File

@ -10,26 +10,26 @@ export default {
TimePicker,
Calendar,
Table: {
filterTitle: 'Menu filter',
filterConfirm: 'baik',
filterReset: 'Setel ulang',
selectAll: 'Pilih halaman saat ini',
selectInvert: 'Balikkan halaman saat ini',
sortTitle: 'Menyortir',
filterTitle: 'Saring',
filterConfirm: 'OK',
filterReset: 'Hapus',
selectAll: 'Pilih semua di halaman ini',
selectInvert: 'Balikkan pilihan di halaman ini',
sortTitle: 'Urutkan',
},
Modal: {
okText: 'baik',
cancelText: 'Membatalkan',
justOkText: 'baik',
okText: 'OK',
cancelText: 'Batal',
justOkText: 'OK',
},
Popconfirm: {
okText: 'baik',
cancelText: 'Membatalkan',
okText: 'OK',
cancelText: 'Batal',
},
Transfer: {
titles: ['', ''],
searchPlaceholder: 'Cari di sini',
itemUnit: 'barang',
searchPlaceholder: 'Cari',
itemUnit: 'item',
itemsUnit: 'item',
},
Upload: {

View File

@ -336,9 +336,6 @@ exports[`renders ./components/mention/demo/controlled.md correctly 1`] = `
</div>
</div>
</span>
<div
class="ant-form-explain-holder"
/>
</div>
</div>
</div>
@ -372,9 +369,6 @@ exports[`renders ./components/mention/demo/controlled.md correctly 1`] = `
</span>
</button>
</span>
<div
class="ant-form-explain-holder"
/>
</div>
</div>
</div>

View File

@ -88,13 +88,15 @@ export default class Menu extends React.Component<MenuProps, MenuState> {
warning(
!('onOpen' in props || 'onClose' in props),
'Menu',
'`onOpen` and `onClose` are removed, please use `onOpenChange` instead, ' +
'see: https://u.ant.design/menu-on-open-change.',
);
warning(
!('inlineCollapsed' in props && props.mode !== 'inline'),
"`inlineCollapsed` should only be used when Menu's `mode` is inline.",
'Menu',
'`inlineCollapsed` should only be used when `mode` is inline.',
);
let openKeys;

View File

@ -122,9 +122,11 @@
&-vertical&-sub,
&-vertical-left&-sub,
&-vertical-right&-sub {
min-width: 160px;
padding: 0;
border-right: 0;
transform-origin: 0 0;
.@{menu-prefix-cls}-item {
left: 0;
margin-left: 0;
@ -139,11 +141,8 @@
}
}
&-horizontal&-sub,
&-vertical&-sub,
&-vertical-left&-sub,
&-vertical-right&-sub {
min-width: 160px;
&-horizontal&-sub {
min-width: 114px; // in case of submenu width is too big: https://codesandbox.io/s/qvpwm6mk66
}
&-item,

View File

@ -24,15 +24,18 @@ export default class ActionButton extends React.Component<ActionButtonProps, Act
loading: false,
};
}
componentDidMount() {
if (this.props.autoFocus) {
const $this = ReactDOM.findDOMNode(this) as HTMLInputElement;
this.timeoutId = setTimeout(() => $this.focus());
}
}
componentWillUnmount() {
clearTimeout(this.timeoutId);
}
onClick = () => {
const { actionFn, closeModal } = this.props;
if (actionFn) {

View File

@ -33,6 +33,7 @@ const ConfirmDialog = (props: ConfirmDialogProps) => {
} = props;
warning(
!('iconType' in props),
'Modal',
`The property 'iconType' is deprecated. Use the property 'icon' instead.`,
);
const icon = props.icon ? props.icon : iconType;

View File

@ -28,7 +28,8 @@ export default class Popover extends React.Component<PopoverProps, {}> {
const { title, content } = this.props;
warning(
!('overlay' in this.props),
'Popover[overlay] is removed, please use Popover[content] instead, ' +
'Popover',
'`overlay` is removed, please use `content` instead, ' +
'see: https://u.ant.design/popover-content',
);
return (

View File

@ -123,6 +123,15 @@ describe('Radio', () => {
expect(onChange.mock.calls.length).toBe(2);
});
it('should only trigger once when in group with options', () => {
const onChange = jest.fn();
const options = [{ label: 'Bamboo', value: 'Bamboo' }];
const wrapper = mount(<RadioGroup options={options} onChange={onChange} />);
wrapper.find('input').simulate('change');
expect(onChange).toHaveBeenCalledTimes(1);
});
it("won't fire change events when value not changes", () => {
const onChange = jest.fn();

View File

@ -124,7 +124,6 @@ class RadioGroup extends React.Component<RadioGroupProps, RadioGroupState> {
prefixCls={prefixCls}
disabled={this.props.disabled}
value={option}
onChange={this.onRadioChange}
checked={this.state.value === option}
>
{option}
@ -138,7 +137,6 @@ class RadioGroup extends React.Component<RadioGroupProps, RadioGroupState> {
prefixCls={prefixCls}
disabled={option.disabled || this.props.disabled}
value={option.value}
onChange={this.onRadioChange}
checked={this.state.value === option.value}
>
{option.label}

View File

@ -131,7 +131,8 @@ export default class Select<T = SelectValue> extends React.Component<SelectProps
warning(
props.mode !== 'combobox',
'The combobox mode of Select is deprecated, ' +
'Select',
'The combobox mode is deprecated, ' +
'it will be removed in next major version, ' +
'please use AutoComplete instead',
);

View File

@ -553,10 +553,10 @@
right: @control-padding-horizontal;
color: transparent;
font-weight: bold;
font-size: 12px;
text-shadow: 0 0.1px 0, 0.1px 0 0, 0 -0.1px 0, -0.1px 0;
transform: translateY(-50%);
transition: all 0.2s ease;
.iconfont-size-under-12px(10px);
transition: all 0.2s;
}
&:hover .@{select-prefix-cls}-selected-icon {

View File

@ -24,6 +24,8 @@
position: relative;
> div > .@{spin-prefix-cls} {
position: absolute;
top: 0;
left: 0;
z-index: 4;
display: block;
width: 100%;

View File

@ -5,22 +5,24 @@ import Icon from '../icon';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
export interface StepsProps {
prefixCls?: string;
iconPrefix?: string;
className?: string;
current?: number;
direction?: 'horizontal' | 'vertical';
iconPrefix?: string;
initial?: number;
labelPlacement?: 'horizontal' | 'vertical';
status?: 'wait' | 'process' | 'finish' | 'error';
size?: 'default' | 'small';
direction?: 'horizontal' | 'vertical';
prefixCls?: string;
progressDot?: boolean | Function;
size?: 'default' | 'small';
status?: 'wait' | 'process' | 'finish' | 'error';
style?: React.CSSProperties;
}
export interface StepProps {
className?: string;
description?: React.ReactNode;
icon?: React.ReactNode;
onClick?: React.MouseEventHandler<any>;
status?: 'wait' | 'process' | 'finish' | 'error';
title?: React.ReactNode;
}

View File

@ -114,12 +114,14 @@ export default class Table<T> extends React.Component<TableProps<T>, TableState<
warning(
!('columnsPageRange' in props || 'columnsPageSize' in props),
'Table',
'`columnsPageRange` and `columnsPageSize` are removed, please use ' +
'fixed columns instead, see: https://u.ant.design/fixed-columns.',
);
warning(
!('expandedRowRender' in props) || !('scroll' in props),
'Table',
'`expandedRowRender` and `scroll` are not compatible. Please use one of them at one time.',
);
@ -731,6 +733,7 @@ export default class Table<T> extends React.Component<TableProps<T>, TableState<
typeof rowKey === 'function' ? rowKey(record, index) : (record as any)[rowKey!];
warning(
recordKey !== undefined,
'Table',
'Each record in dataSource of table should have a unique `key` prop, ' +
'or set `rowKey` of Table to an unique primary key, ' +
'see https://u.ant.design/table-row-key',
@ -1020,7 +1023,6 @@ export default class Table<T> extends React.Component<TableProps<T>, TableState<
let current: number;
let pageSize: number;
const state = this.state;
const pagination = this.props.pagination || {};
// 如果没有分页的话,默认全部展示
if (!this.hasPagination()) {
pageSize = Number.MAX_VALUE;
@ -1034,11 +1036,7 @@ export default class Table<T> extends React.Component<TableProps<T>, TableState<
// ---
// 当数据量少于等于每页数量时,直接设置数据
// 否则进行读取分页数据
if (
data.length > pageSize ||
pageSize === Number.MAX_VALUE ||
(pagination.current === undefined && current * pageSize > data.length)
) {
if (data.length > pageSize || pageSize === Number.MAX_VALUE) {
data = data.filter((_, i) => {
return i >= (current - 1) * pageSize && i < current * pageSize;
});

View File

@ -5,6 +5,15 @@ import Table from '..';
import Input from '../../input';
import Button from '../../button';
function getDropdownWrapper(wrapper) {
return mount(
wrapper
.find('Trigger')
.instance()
.getComponent(),
);
}
describe('Table.filter', () => {
const filterFn = (value, record) => record.name.indexOf(value) !== -1;
const column = {
@ -268,12 +277,7 @@ describe('Table.filter', () => {
it('fires change event', () => {
const handleChange = jest.fn();
const wrapper = mount(createTable({ onChange: handleChange }));
const dropdownWrapper = mount(
wrapper
.find('Trigger')
.instance()
.getComponent(),
);
const dropdownWrapper = getDropdownWrapper(wrapper);
dropdownWrapper
.find('MenuItem')
@ -294,12 +298,7 @@ describe('Table.filter', () => {
it('should not fire change event on close filterDropdown without changing anything', () => {
const handleChange = jest.fn();
const wrapper = mount(createTable({ onChange: handleChange }));
const dropdownWrapper = mount(
wrapper
.find('Trigger')
.instance()
.getComponent(),
);
const dropdownWrapper = getDropdownWrapper(wrapper);
dropdownWrapper.find('.clear').simulate('click');
@ -339,12 +338,7 @@ describe('Table.filter', () => {
}),
);
jest.useFakeTimers();
const dropdownWrapper = mount(
wrapper
.find('Trigger')
.instance()
.getComponent(),
);
const dropdownWrapper = getDropdownWrapper(wrapper);
dropdownWrapper
.find('.ant-dropdown-menu-submenu-title')
.at(0)
@ -367,6 +361,40 @@ describe('Table.filter', () => {
jest.useRealTimers();
});
describe('should support value types', () => {
[['Light', 93], ['Bamboo', false]].forEach(([text, value]) => {
it(`${typeof value} type`, () => {
const onFilter = jest.fn();
const filters = [{ text, value }];
const wrapper = mount(
createTable({
columns: [
{
...column,
filters,
onFilter,
},
],
}),
);
jest.useFakeTimers();
const dropdownWrapper = getDropdownWrapper(wrapper);
dropdownWrapper
.find('MenuItem')
.first()
.simulate('click');
dropdownWrapper.find('.confirm').simulate('click');
wrapper.update();
expect(onFilter.mock.calls.length > 0).toBeTruthy();
onFilter.mock.calls.forEach(([val]) => {
expect(val).toBe(value);
});
jest.useRealTimers();
});
});
});
it('works with JSX in controlled mode', () => {
const { Column } = Table;
@ -397,12 +425,7 @@ describe('Table.filter', () => {
}
const wrapper = mount(<App />);
const dropdownWrapper = mount(
wrapper
.find('Trigger')
.instance()
.getComponent(),
);
const dropdownWrapper = getDropdownWrapper(wrapper);
dropdownWrapper
.find('MenuItem')

View File

@ -182,20 +182,6 @@ describe('Table.pagination', () => {
).toHaveLength(1);
});
// https://github.com/ant-design/ant-design/issues/14557
it('Show correct page data when pagination data length is less than pageSize.', () => {
const wrapper = mount(
createTable({ pagination: { pageSize: 10, total: 100 }, dataSource: data }),
);
expect(renderedNames(wrapper)[0]).toEqual('Jack');
wrapper.find('.ant-pagination-item-2').simulate('click');
expect(renderedNames(wrapper)).toEqual([]);
wrapper.setProps({ pagination: { current: 1, pageSize: 10, total: 100 } });
expect(renderedNames(wrapper)[0]).toEqual('Jack');
wrapper.setProps({ pagination: { current: 2, pageSize: 10, total: 100 } });
expect(renderedNames(wrapper)).toHaveLength(4);
});
/**
* `pagination` is not designed to accept `true` value,
* but in practice, many people assign `true` to `pagination`,
@ -205,4 +191,24 @@ describe('Table.pagination', () => {
const wrapper = render(createTable({ pagination: true }));
expect(wrapper).toMatchSnapshot();
});
it('ajax render should keep display by the dataSource', () => {
const onChange = jest.fn();
const wrapper = mount(
createTable({
onChange,
pagination: {
total: 200,
},
}),
);
expect(wrapper.find('.ant-table-tbody tr.ant-table-row')).toHaveLength(data.length);
wrapper.find('.ant-pagination .ant-pagination-item-2').simulate('click');
expect(onChange.mock.calls[0][0].current).toBe(2);
expect(wrapper.find('.ant-table-tbody tr.ant-table-row')).toHaveLength(data.length);
});
});

View File

@ -90,7 +90,7 @@ describe('Table', () => {
it('warning if both `expandedRowRender` & `scroll` are used', () => {
mount(<Table expandedRowRender={() => null} scroll={{}} />);
expect(warnSpy).toBeCalledWith(
'Warning: `expandedRowRender` and `scroll` are not compatible. Please use one of them at one time.',
'Warning: [antd: Table] `expandedRowRender` and `scroll` are not compatible. Please use one of them at one time.',
);
});
});

View File

@ -1582,9 +1582,6 @@ exports[`renders ./components/table/demo/dynamic-settings.md correctly 1`] = `
/>
</button>
</span>
<div
class="ant-form-explain-holder"
/>
</div>
</div>
</div>
@ -1621,9 +1618,6 @@ exports[`renders ./components/table/demo/dynamic-settings.md correctly 1`] = `
/>
</button>
</span>
<div
class="ant-form-explain-holder"
/>
</div>
</div>
</div>
@ -1660,9 +1654,6 @@ exports[`renders ./components/table/demo/dynamic-settings.md correctly 1`] = `
/>
</button>
</span>
<div
class="ant-form-explain-holder"
/>
</div>
</div>
</div>
@ -1700,9 +1691,6 @@ exports[`renders ./components/table/demo/dynamic-settings.md correctly 1`] = `
/>
</button>
</span>
<div
class="ant-form-explain-holder"
/>
</div>
</div>
</div>
@ -1740,9 +1728,6 @@ exports[`renders ./components/table/demo/dynamic-settings.md correctly 1`] = `
/>
</button>
</span>
<div
class="ant-form-explain-holder"
/>
</div>
</div>
</div>
@ -1780,9 +1765,6 @@ exports[`renders ./components/table/demo/dynamic-settings.md correctly 1`] = `
/>
</button>
</span>
<div
class="ant-form-explain-holder"
/>
</div>
</div>
</div>
@ -1820,9 +1802,6 @@ exports[`renders ./components/table/demo/dynamic-settings.md correctly 1`] = `
/>
</button>
</span>
<div
class="ant-form-explain-holder"
/>
</div>
</div>
</div>
@ -1859,9 +1838,6 @@ exports[`renders ./components/table/demo/dynamic-settings.md correctly 1`] = `
/>
</button>
</span>
<div
class="ant-form-explain-holder"
/>
</div>
</div>
</div>
@ -1899,9 +1875,6 @@ exports[`renders ./components/table/demo/dynamic-settings.md correctly 1`] = `
/>
</button>
</span>
<div
class="ant-form-explain-holder"
/>
</div>
</div>
</div>
@ -1990,9 +1963,6 @@ exports[`renders ./components/table/demo/dynamic-settings.md correctly 1`] = `
</label>
</div>
</span>
<div
class="ant-form-explain-holder"
/>
</div>
</div>
</div>
@ -2100,9 +2070,6 @@ exports[`renders ./components/table/demo/dynamic-settings.md correctly 1`] = `
</label>
</div>
</span>
<div
class="ant-form-explain-holder"
/>
</div>
</div>
</div>

View File

@ -34,18 +34,6 @@ class EditableCell extends React.Component {
editing: false,
}
componentDidMount() {
if (this.props.editable) {
document.addEventListener('click', this.handleClickOutside, true);
}
}
componentWillUnmount() {
if (this.props.editable) {
document.removeEventListener('click', this.handleClickOutside, true);
}
}
toggleEdit = () => {
const editing = !this.state.editing;
this.setState({ editing }, () => {
@ -55,13 +43,6 @@ class EditableCell extends React.Component {
});
}
handleClickOutside = (e) => {
const { editing } = this.state;
if (editing && this.cell !== e.target && !this.cell.contains(e.target)) {
this.save();
}
}
save = () => {
const { record, handleSave } = this.props;
this.form.validateFields((error, values) => {
@ -103,6 +84,7 @@ class EditableCell extends React.Component {
<Input
ref={node => (this.input = node)}
onPressEnter={this.save}
onBlur={this.save}
/>
)}
</FormItem>

View File

@ -203,6 +203,9 @@ class EditableTable extends React.Component {
dataSource={this.state.data}
columns={columns}
rowClassName="editable-row"
pagination={{
onChange: this.cancel,
}}
/>
);
}

View File

@ -1,5 +1,6 @@
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { polyfill } from 'react-lifecycles-compat';
import Menu, { SubMenu, Item as MenuItem } from 'rc-menu';
import closest from 'dom-closest';
import classNames from 'classnames';
@ -10,6 +11,7 @@ import Checkbox from '../checkbox';
import Radio from '../radio';
import FilterDropdownMenuWrapper from './FilterDropdownMenuWrapper';
import { FilterMenuProps, FilterMenuState, ColumnProps, ColumnFilterItem } from './interface';
import { generateValueMaps } from './util';
function stopPropagation(e: React.SyntheticEvent<any>) {
e.stopPropagation();
@ -18,38 +20,18 @@ function stopPropagation(e: React.SyntheticEvent<any>) {
}
}
export default class FilterMenu<T> extends React.Component<FilterMenuProps<T>, FilterMenuState> {
class FilterMenu<T> extends React.Component<FilterMenuProps<T>, FilterMenuState<T>> {
static defaultProps = {
handleFilter() {},
column: {},
};
neverShown: boolean;
constructor(props: FilterMenuProps<T>) {
super(props);
const visible =
'filterDropdownVisible' in props.column ? props.column.filterDropdownVisible : false;
this.state = {
selectedKeys: props.selectedKeys,
keyPathOfSelectedItem: {}, // 记录所有有选中子菜单的祖先菜单
visible,
};
}
componentDidMount() {
const { column } = this.props;
this.setNeverShown(column);
}
componentWillReceiveProps(nextProps: FilterMenuProps<T>) {
static getDerivedStateFromProps<T>(nextProps: FilterMenuProps<T>, prevState: FilterMenuState<T>) {
const { column } = nextProps;
this.setNeverShown(column);
const newState = {} as {
selectedKeys: string[];
visible: boolean;
const { prevProps } = prevState;
const newState: Partial<FilterMenuState<T>> = {
prevProps: nextProps,
};
/**
@ -61,16 +43,44 @@ export default class FilterMenu<T> extends React.Component<FilterMenuProps<T>, F
*/
if (
'selectedKeys' in nextProps &&
!shallowequal(this.props.selectedKeys, nextProps.selectedKeys)
!shallowequal(prevProps.selectedKeys, nextProps.selectedKeys)
) {
newState.selectedKeys = nextProps.selectedKeys;
}
if (!shallowequal((prevProps.column || {}).filters, (nextProps.column || {}).filters)) {
newState.valueKeys = generateValueMaps(nextProps.column.filters);
}
if ('filterDropdownVisible' in column) {
newState.visible = column.filterDropdownVisible as boolean;
}
if (Object.keys(newState).length > 0) {
this.setState(newState);
}
return newState;
}
neverShown: boolean;
constructor(props: FilterMenuProps<T>) {
super(props);
const visible =
'filterDropdownVisible' in props.column ? props.column.filterDropdownVisible : false;
this.state = {
selectedKeys: props.selectedKeys,
valueKeys: generateValueMaps(props.column.filters),
keyPathOfSelectedItem: {}, // 记录所有有选中子菜单的祖先菜单
visible,
prevProps: props,
};
}
componentDidMount() {
const { column } = this.props;
this.setNeverShown(column);
}
componentDidUpdate() {
const { column } = this.props;
this.setNeverShown(column);
}
getDropdownVisible() {
@ -128,10 +138,14 @@ export default class FilterMenu<T> extends React.Component<FilterMenuProps<T>, F
};
confirmFilter() {
const { selectedKeys } = this.state;
const { selectedKeys, valueKeys } = this.state;
const { filterDropdown } = this.props.column;
if (!shallowequal(selectedKeys, this.props.selectedKeys)) {
this.props.confirmFilter(this.props.column, selectedKeys);
this.props.confirmFilter(
this.props.column,
filterDropdown ? selectedKeys : selectedKeys.map(key => valueKeys[key]),
);
}
}
@ -227,6 +241,7 @@ export default class FilterMenu<T> extends React.Component<FilterMenuProps<T>, F
};
render() {
const { selectedKeys: originSelectedKeys } = this.state;
const { column, locale, prefixCls, dropdownPrefixCls, getPopupContainer } = this.props;
// default multiple selection in filter dropdown
const multiple = 'filterMultiple' in column ? column.filterMultiple : true;
@ -238,7 +253,7 @@ export default class FilterMenu<T> extends React.Component<FilterMenuProps<T>, F
filterDropdown = filterDropdown({
prefixCls: `${dropdownPrefixCls}-custom`,
setSelectedKeys: (selectedKeys: Array<any>) => this.setSelectedKeys({ selectedKeys }),
selectedKeys: this.state.selectedKeys,
selectedKeys: originSelectedKeys,
confirm: this.handleConfirm,
clearFilters: this.handleClearFilters,
filters: column.filters,
@ -259,7 +274,7 @@ export default class FilterMenu<T> extends React.Component<FilterMenuProps<T>, F
className={dropdownMenuClass}
onSelect={this.setSelectedKeys}
onDeselect={this.setSelectedKeys}
selectedKeys={this.state.selectedKeys}
selectedKeys={originSelectedKeys && originSelectedKeys.map(val => val.toString())}
getPopupContainer={(triggerNode: HTMLElement) => triggerNode.parentNode}
>
{this.renderMenus(column.filters!)}
@ -290,3 +305,7 @@ export default class FilterMenu<T> extends React.Component<FilterMenuProps<T>, F
);
}
}
polyfill(FilterMenu);
export default FilterMenu;

View File

@ -243,10 +243,12 @@ export interface FilterMenuProps<T> {
getPopupContainer?: GetPopupContainer;
}
export interface FilterMenuState {
export interface FilterMenuState<T> {
selectedKeys: string[];
valueKeys: { [name: string]: any };
keyPathOfSelectedItem: { [key: string]: string };
visible?: boolean;
prevProps: FilterMenuProps<T>;
}
export type PrepareParamsArgumentsReturn<T> = [

View File

@ -99,6 +99,8 @@
&.@{table-prefix-cls}-column-has-actions {
position: relative;
background-clip: padding-box; // For Firefox background bug, https://github.com/ant-design/ant-design/issues/12628
/* stylelint-disable-next-line */
-webkit-background-clip: border-box; // For Chrome extra space: https://github.com/ant-design/ant-design/issues/14926
&.@{table-prefix-cls}-column-has-filters {
.@{iconfont-css-prefix}-filter,
@ -366,11 +368,11 @@
}
.@{table-prefix-cls}-body > table {
border-top: 0;
border-top-left-radius: 0;
border-top-right-radius: 0;
}
.@{table-prefix-cls}-header + .@{table-prefix-cls}-body > table,
.@{table-prefix-cls}-body-inner > table {
border-top: 0;
}

View File

@ -1,4 +1,5 @@
import * as React from 'react';
import { ColumnFilterItem } from './interface';
export function flatArray(data: any[] = [], childrenName = 'children') {
const result: any[] = [];
@ -69,3 +70,11 @@ export function normalizeColumns(elements: React.ReactChildren) {
});
return columns;
}
export function generateValueMaps(items?: ColumnFilterItem[], maps: { [name: string]: any } = {}) {
(items || []).forEach(({ value, children }) => {
maps[value.toString()] = value;
generateValueMaps(children, maps);
});
return maps;
}

View File

@ -110,7 +110,8 @@ export default class Tabs extends React.Component<TabsProps, any> {
warning(
!(type.indexOf('card') >= 0 && (size === 'small' || size === 'large')),
"Tabs[type=card|editable-card] doesn't have small or large size, it's by design.",
'Tabs',
"`type=card|editable-card` doesn't have small or large size, it's by design.",
);
const prefixCls = getPrefixCls('tabs', customizePrefixCls);
const cls = classNames(className, {

View File

@ -30,7 +30,7 @@ describe('TimePicker', () => {
it('allowEmpty deprecated', () => {
mount(<TimePicker allowEmpty />);
expect(errorSpy).toBeCalledWith(
'Warning: `allowEmpty` in TimePicker is deprecated. Please use `allowClear` instead.',
'Warning: [antd: TimePicker] `allowEmpty` is deprecated. Please use `allowClear` instead.',
);
});

View File

@ -99,7 +99,8 @@ class TimePicker extends React.Component<TimePickerProps, any> {
warning(
!('allowEmpty' in props),
'`allowEmpty` in TimePicker is deprecated. Please use `allowClear` instead.',
'TimePicker',
'`allowEmpty` is deprecated. Please use `allowClear` instead.',
);
}

View File

@ -269,7 +269,7 @@ describe('Transfer', () => {
).toEqual('old1');
expect(consoleErrorSpy).toBeCalledWith(
'Warning: Transfer[notFoundContent] and Transfer[searchPlaceholder] will be removed, please use Transfer[locale] instead.',
'Warning: [antd: Transfer] `notFoundContent` and `searchPlaceholder` will be removed, please use `locale` instead.',
);
consoleErrorSpy.mockRestore();
});

View File

@ -83,7 +83,7 @@ describe('Search', () => {
.simulate('change', { target: { value: 'a' } });
expect(errorSpy.mock.calls[0][0]).toMatch(
'Warning: `onSearchChange` in Transfer is deprecated. Please use `onSearch` instead.',
'Warning: [antd: Transfer] `onSearchChange` is deprecated. Please use `onSearch` instead.',
);
expect(onSearchChange.mock.calls[0][0]).toEqual('left');
expect(onSearchChange.mock.calls[0][1].target.value).toEqual('a');

View File

@ -110,8 +110,9 @@ export default class Transfer extends React.Component<TransferProps, any> {
warning(
!('notFoundContent' in props || 'searchPlaceholder' in props),
'Transfer[notFoundContent] and Transfer[searchPlaceholder] will be removed, ' +
'please use Transfer[locale] instead.',
'Transfer',
'`notFoundContent` and `searchPlaceholder` will be removed, ' +
'please use `locale` instead.',
);
const { selectedKeys = [], targetKeys = [] } = props;
@ -277,7 +278,7 @@ export default class Transfer extends React.Component<TransferProps, any> {
[`${direction}Filter`]: value,
});
if (onSearchChange) {
warning(false, '`onSearchChange` in Transfer is deprecated. Please use `onSearch` instead.');
warning(false, 'Transfer', '`onSearchChange` is deprecated. Please use `onSearch` instead.');
onSearchChange(direction, e);
}
if (onSearch) {

View File

@ -29,6 +29,7 @@ export default class TreeSelect extends React.Component<TreeSelectProps, any> {
warning(
props.multiple !== false || !props.treeCheckable,
'TreeSelect',
'`multiple` will alway be `true` when `treeCheckable` is true',
);
}

View File

@ -4,6 +4,7 @@ import omit from 'omit.js';
import debounce from 'lodash/debounce';
import { conductExpandParent, convertTreeToEntities } from 'rc-tree/lib/util';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import { polyfill } from 'react-lifecycles-compat';
import Tree, {
TreeProps,
@ -34,12 +35,23 @@ function getIcon(props: AntdTreeNodeAttribute): React.ReactNode {
return <Icon type={expanded ? 'folder-open' : 'folder'} />;
}
export default class DirectoryTree extends React.Component<DirectoryTreeProps, DirectoryTreeState> {
class DirectoryTree extends React.Component<DirectoryTreeProps, DirectoryTreeState> {
static defaultProps = {
showIcon: true,
expandAction: 'click',
};
static getDerivedStateFromProps(nextProps: DirectoryTreeProps) {
const newState: DirectoryTreeState = {};
if ('expandedKeys' in nextProps) {
newState.expandedKeys = nextProps.expandedKeys;
}
if ('selectedKeys' in nextProps) {
newState.selectedKeys = nextProps.selectedKeys;
}
return newState;
}
state: DirectoryTreeState;
tree: Tree;
onDebounceExpand: (event: React.MouseEvent<HTMLElement>, node: AntTreeNode) => void;
@ -82,15 +94,6 @@ export default class DirectoryTree extends React.Component<DirectoryTreeProps, D
});
}
componentWillReceiveProps(nextProps: DirectoryTreeProps) {
if ('expandedKeys' in nextProps) {
this.setState({ expandedKeys: nextProps.expandedKeys });
}
if ('selectedKeys' in nextProps) {
this.setState({ selectedKeys: nextProps.selectedKeys });
}
}
onExpand = (expandedKeys: string[], info: AntTreeNodeExpandedEvent) => {
const { onExpand } = this.props;
@ -226,3 +229,7 @@ export default class DirectoryTree extends React.Component<DirectoryTreeProps, D
return <ConfigConsumer>{this.renderDirectoryTree}</ConfigConsumer>;
}
}
polyfill(DirectoryTree);
export default DirectoryTree;

View File

@ -6,6 +6,7 @@
@tree-prefix-cls: ~'@{ant-prefix}-tree';
@tree-showline-icon-color: @text-color-secondary;
@tree-node-padding: 4px;
.antCheckboxFn(@checkbox-prefix-cls: ~'@{ant-prefix}-tree-checkbox');
@ -23,7 +24,7 @@
li {
margin: 0;
padding: 4px 0;
padding: @tree-node-padding 0;
white-space: nowrap;
list-style: none;
outline: 0;
@ -177,6 +178,19 @@
&-open {
display: block;
}
// https://github.com/ant-design/ant-design/issues/14958
> li {
// Provide additional padding between top child node and parent node
&:first-child {
padding-top: 2 * @tree-node-padding;
}
// Hide additional padding between last child node and next parent node
&:last-child {
padding-bottom: 0;
}
}
}
li&-treenode-disabled {
> span:not(.@{tree-prefix-cls}-switcher),

View File

@ -110,7 +110,8 @@ class Base extends React.Component<InternalBlockProps & ConfigConsumerProps, Bas
warning(
!editable || typeof children === 'string',
'When `editable` is enabled, the `children` of Text component should use string.',
'Typography',
'When `editable` is enabled, the `children` should use string.',
);
return {};
@ -286,7 +287,8 @@ class Base extends React.Component<InternalBlockProps & ConfigConsumerProps, Bas
warning(
toArray(children).every((child: React.ReactNode) => typeof child === 'string'),
'`ellipsis` for Typography should use string as children only.',
'Typography',
'`ellipsis` should use string as children only.',
);
const { content, text, ellipsis } = measure(

View File

@ -9,7 +9,8 @@ interface TextProps extends BlockProps {
const Text: React.SFC<TextProps> = ({ ellipsis, ...restProps }) => {
warning(
typeof ellipsis !== 'object',
'`ellipsis` in Typography.Text is only support boolean value.',
'Typography.Text',
'`ellipsis` is only support boolean value.',
);
return <Base {...restProps} ellipsis={!!ellipsis} component="span" />;
};

View File

@ -53,7 +53,7 @@ class Upload extends React.Component<UploadProps, UploadState> {
progressTimer: any;
private upload: any;
upload: any;
constructor(props: UploadProps) {
super(props);

View File

@ -360,4 +360,14 @@ describe('Upload', () => {
done();
});
});
// https://github.com/ant-design/ant-design/issues/14439
it('should allow call abort function through upload instance', () => {
const wrapper = mount(
<Upload>
<button type="button">upload</button>
</Upload>,
);
expect(typeof wrapper.instance().upload.abort).toBe('function');
});
});

View File

@ -7,17 +7,14 @@ Here are the frequently asked questions about Ant Design and antd that you shoul
---
### Are you going to provide Vue(etc...) edition?
No, but [the LICENSE of ant-design](https://github.com/ant-design/ant-design/blob/master/LICENSE) is MIT. So, you can try to implement it with ant-design's [style](https://github.com/ant-design/ant-design/tree/master/style), like: [ant-design-vue](https://github.com/vueComponent/ant-design-vue) [vue-beauty](https://github.com/FE-Driver/vue-beauty) or [antue](https://github.com/zzuu666/antue).
### Are you going to provide Sass/Stylus(etc...) style file?
No, actually, you can convert Less to Sass/Stylus(etc...) with tools (which you can Google).
### `Select Dropdown DatePicker TimePicker Popover Popconfirm` disappear when I click another popup component inside it, How to resolve it?
Use `<Select getPopupContainer={trigger => trigger.parentNode}>` to render component inside Popover. (Or other getXxxxContainer props)
This has been fixed since 3.11.x.
If you're still using old version, you can use `<Select getPopupContainer={trigger => trigger.parentNode}>` to render component inside Popover. (Or other getXxxxContainer props)
https://ant.design/components/select/#Select-props

View File

@ -7,17 +7,14 @@ title: FAQ
---
### 你们会提供 Vue 版本的 Ant Design 吗?
不,但是 [ant-design 基于 MIT 协议开源](https://github.com/ant-design/ant-design/blob/master/LICENSE),所以你可以尝试用 ant-design 的[样式](https://github.com/ant-design/ant-design/tree/master/style)去实现一套,例如:[ant-design-vue](https://github.com/vueComponent/ant-design-vue) [vue-beauty](https://github.com/FE-Driver/vue-beauty) 或者 [antue](https://github.com/zzuu666/antue)。
### 你们会提供 Sass/Stylus 等格式的样式文件吗?
不。事实上你可以使用工具(请自行 Google将 Less 转换成 Sass/Stylus 等。
### 当我点击 `Select Dropdown DatePicker TimePicker Popover Popconfirm` 内的另一个 popup 组件时它会消失,如何解决?
使用 `<Select getPopupContainer={trigger => trigger.parentNode}>` 来在 Popover 中渲染组件,或者使用其他的 getXxxxContainer 参数。
该问题在 3.11.0 后已经解决。
如果你仍在使用旧版本,你可以通过 `<Select getPopupContainer={trigger => trigger.parentNode}>` 来在 Popover 中渲染组件,或者使用其他的 getXxxxContainer 参数。
https://ant.design/components/select/#Select-props

View File

@ -51,7 +51,7 @@ You can subscribe to this feed for new version notifications: https://github.com
**We recommend using npm or yarn to install**, it not only makes development easier, but also allow you to take advantage of the rich ecosystem of Javascript packages and tooling.
```bash
$ npm install antd --save
$ npm install antd
```
```bash

View File

@ -1,6 +1,6 @@
{
"name": "antd",
"version": "3.13.3",
"version": "3.13.6",
"title": "Ant Design",
"description": "An enterprise-class UI design language and React-based implementation",
"homepage": "http://ant.design/",
@ -106,6 +106,7 @@
"antd-theme-generator": "^1.1.4",
"antd-tools": "^7.0.1",
"babel-eslint": "^10.0.1",
"babel-plugin-add-react-displayname": "^0.0.5",
"bisheng": "^1.1.0",
"bisheng-plugin-antd": "^1.0.0",
"bisheng-plugin-description": "^0.1.4",
@ -139,6 +140,8 @@
"jsdom": "^13.0.0",
"jsonml.js": "^0.1.0",
"lint-staged": "^8.0.2",
"logrocket": "^0.6.19",
"logrocket-react": "^3.0.0",
"lz-string": "^1.4.4",
"majo": "^0.7.1",
"mockdate": "^2.0.2",
@ -177,7 +180,7 @@
"rimraf": "^2.6.2",
"scrollama": "^1.4.4",
"stylelint": "~9.10.1",
"stylelint-config-prettier": "^4.0.0",
"stylelint-config-prettier": "^5.0.0",
"stylelint-config-rational-order": "^0.0.4",
"stylelint-config-standard": "^18.2.0",
"stylelint-declaration-block-no-ignored-properties": "^1.1.0",

View File

@ -15,6 +15,8 @@ function alertBabelConfig(rules) {
rule.options.plugins = rule.options.plugins.filter(
plugin => !plugin.indexOf || plugin.indexOf('babel-plugin-add-module-exports') === -1,
);
// Add babel-plugin-add-react-displayname
rule.options.plugins.push(require.resolve('babel-plugin-add-react-displayname'));
} else if (rule.use) {
alertBabelConfig(rule.use);
}

View File

@ -57,6 +57,7 @@ export const categories = {
'radius-bottomleft',
'radius-bottomright',
'radius-upleft',
'radius-upright',
'fullscreen',
'fullscreen-exit',
],

View File

@ -5,6 +5,8 @@ import { enquireScreen } from 'enquire-js';
import { addLocaleData, IntlProvider } from 'react-intl';
import 'moment/locale/zh-cn';
import { LocaleProvider } from 'antd';
import LogRocket from 'logrocket';
import setupLogRocketReact from 'logrocket-react';
import zhCN from 'antd/lib/locale-provider/zh_CN';
import Header from './Header';
import enLocale from '../../en-US';
@ -26,6 +28,20 @@ if (typeof window !== 'undefined') {
window['react-dom'] = ReactDOM;
window.antd = require('antd');
/* eslint-enable global-require */
// Error log statistic
window.addEventListener('error', function(e) {
// Ignore ResizeObserver error
if (e.message === 'ResizeObserver loop limit exceeded') {
e.stopPropagation();
e.stopImmediatePropagation();
}
});
if (process.env.NODE_ENV === 'production') {
LogRocket.init('kpuw4z/ant-design');
setupLogRocketReact(LogRocket);
}
}
let isMobile = false;