Compare commits

...

348 Commits
4.1.2 ... 4.2.2

Author SHA1 Message Date
二货机器人
40a987e059 chore: Fix pub script (#24063) 2020-05-11 23:38:54 +08:00
信鑫-King
705a6d63a1 release: 4.2.2 changelog (#24060)
* docs: changelog

* chore: version 4.2.2

* docs: changelog

* Update CHANGELOG.zh-CN.md

Co-authored-by: 偏右 <afc163@gmail.com>

Co-authored-by: 偏右 <afc163@gmail.com>
2020-05-11 21:56:17 +08:00
偏右
79289fa708 fix: generate-version not found (#24059)
close #24057
2020-05-11 21:04:18 +08:00
偏右
4dccbd8eab style: add @modal-close-color (#24053)
* 🆕 Add @modal-close-color

close #24050

* update snapshot

* fix var name
2020-05-11 20:08:46 +08:00
偏右
2ab7c3f182 fix @menu-item-font-size not working (#24052)
close #24051
2020-05-11 19:12:04 +08:00
信鑫-King
313f2df632 docs: changelog 4.2.1 (#24025)
* docs: changelog 4.2.1

* docs: changelog

* docs: changelog

* docs: changelog

* docs: changelog

* chore: datepicker rtl

* chore: classification

* chore: size

* chore: locale

* Update CHANGELOG.zh-CN.md

Co-authored-by: 偏右 <afc163@gmail.com>

* docs: changelog

* chore: add version

Co-authored-by: 偏右 <afc163@gmail.com>
2020-05-11 16:58:42 +08:00
afc163
626f918597 🗑️ remove checkbox PropTypes 2020-05-11 14:02:23 +08:00
xrkffgg
04eb91dc8e style: fix datepicker panel style (#24028) 2020-05-11 12:02:24 +08:00
偏右
e188537c00 refactor: Dropdown.Button icon prop (#24020)
ref #24017
2020-05-10 23:53:29 +08:00
xrkffgg
e26eb5f892 docs: optimize site of rtl (#23995) 2020-05-10 22:11:09 +08:00
Rick Zhou
d7c7b86f31 fix en_GB's description (#24016) 2020-05-10 17:16:44 +08:00
偏右
0a70563e44 chore: fix drawer demo (#24015)
* 🎬 improve drawer demo

* 🎬 fix drawer demo glitch

close #24011
2020-05-10 17:15:41 +08:00
初心Yearth
7f1e7a3120 Update use-with-create-react-app.zh-CN.md (#23938) 2020-05-10 13:12:32 +08:00
Jenna Van Conett
8cce0383a1 Update drag-sorting.md (#24013) 2020-05-10 12:54:57 +08:00
偏右
237c205169 🆙 upgrade eslint (#24000) 2020-05-09 20:40:35 +08:00
偏右
2beb28518c test: Alert and AutoComplete test coverage (#24004)
* 🔨 refactor demo code style

* refactor alert code and fix test cov

* add test case for AutoComplete

* fix test
2020-05-09 19:32:02 +08:00
mraiguo
28f71921ea fix: Tooltip in Upload components location error (#24001) 2020-05-09 18:58:44 +08:00
xrkffgg
338733d70f docs: optimize input demo (#23990)
* docs: optimize input demo

* docs: optimize input demo

* fix: style

* remove
2020-05-09 18:02:18 +08:00
xrkffgg
dd6c855028 style: fix input clear icon in rtl (#23999) 2020-05-09 18:02:08 +08:00
Vitaly Budovski
60d45d8d37 docs: Add documentation for responsive table columns (#23987) 2020-05-09 18:01:16 +08:00
Xuhao
9c0f12c7e8 fix: #23986 [Comment] Should not render avatar wrapper when avatar is… (#23994)
* fix: #23986 [Comment] Should not render avatar wrapper when avatar is not present

* #23986 test snapshots revision
2020-05-09 16:50:34 +08:00
偏右
e6a8736b9d Update FUNDING.yml 2020-05-09 14:42:42 +08:00
xrkffgg
c393ca700e style: fix select focused in input group (#23985) 2020-05-09 14:41:00 +08:00
偏右
ee58a34175 fix: 🆙 upgrade rc-steps@3.6.0 (#23989)
* 🆙 upgrade rc-steps@3.6.0

* update snapshot
2020-05-09 14:01:02 +08:00
xrkffgg
015109b42b style: opt datepicker active bar style in rtl (#23981) 2020-05-09 10:00:23 +08:00
偏右
cc11b95194 🆙 upgrade rc-switch/rc-drawer to remove react-lifecycles-compat (#23969) 2020-05-08 19:21:21 +08:00
偏右
333e8ffeb2 💄 Tweak Select close x position (#23963)
close #23886
2020-05-08 18:13:38 +08:00
xrkffgg
48c7011f67 style: fix transfer search padding in rtl (#23962) 2020-05-08 18:13:08 +08:00
偏右
d221458939 refactor: 📦 Generate version.js from package.json (#23957)
* 📦 generate version.js from package.json

* components/version/version.ts

* remove version.js

* fix scripts

* Add pretest and predist

* clean up finalizeCompile

* fix lint
2020-05-08 17:49:22 +08:00
偏右
612bcdf4a6 refactor: 📦 use webpack-plugin-esbuild (#23930)
* 📦 use webpack-plugin-esbuild

* rename esbuild-webpack-plugin

* fix npm run dist error

* fix npm run dist error

* code style improve

* remove extra finalizeDist

* Add process.env.ESBUILD
2020-05-08 15:48:21 +08:00
xrkffgg
3d578c87be site: fix css of direction (#23953) 2020-05-08 14:06:32 +08:00
偏右
f8c1e794da refactor: 🆙 upgrade rc-animate to 3.x (#23937)
* 🆙 upgrade rc-animate to 3.x

drop dep of component-classes

* 🆙 upgrade deps which deps on rc-animate

*  fix snapshot
2020-05-08 13:47:51 +08:00
偏右
22f615200a fix rebase.yml 2020-05-08 13:43:15 +08:00
Eric Chen
dfe2477b87 docs(Divider): Move Divider to layout (#23952) 2020-05-08 10:34:50 +08:00
二货机器人
c4b602e835 fix: FormItem with help (#23945)
* fix: Help status error

* update logic

* adjust ref

* fix ts

* adjust hidden logic
2020-05-07 23:26:07 +08:00
zoomdong
5f825d8172 docs: fix typo (#23946) 2020-05-07 23:22:31 +08:00
二货机器人
c9fada3222 docs: Update cra doc (#23944) 2020-05-07 21:01:42 +08:00
臧甲彬 fadeaway
1abe5495a2 docs: add modao.cc resource link (#23939)
* 添加墨刀资源链接

* 添加墨刀资源链接

* fix letters spaces

Co-authored-by: 偏右 <afc163@gmail.com>

Co-authored-by: 偏右 <afc163@gmail.com>
2020-05-07 20:51:44 +08:00
mjfwebb
d643d113ff Adds default English localisations for Form. (#23859)
Co-authored-by: mjfwebb <michael@w3bb.net>
2020-05-07 17:39:09 +08:00
afc163
968e7edec3 📖 add dumi in footer 2020-05-07 16:50:32 +08:00
偏右
9a9aa94cfd chore: Removed workaround since it's fixed
935698dea8
2020-05-07 16:40:38 +08:00
偏右
22c313d032 chore: 🔨 replace css-animation by @ant-design/css-animation (#23932)
* 🆙 use @ant-design/css-animation

* fix ci

* fix ci
2020-05-07 16:29:41 +08:00
Nariman Movaffaghi
540fc211df feat: fa_IR is updated based on latest options. (#23926)
* Update FA_IR based on EN_US

* Update fa_IR based on zh_CN

* typeTemplate has been added

* Update fa_IR.tsx

Co-authored-by: Amumu <yoyo837@hotmail.com>
2020-05-07 14:57:31 +08:00
偏右
b0593c8a41 🔰 update badge image url 2020-05-07 14:05:25 +08:00
Tom Xu
cf01c8649f docs: improve tooltip (#23928)
* docs: improve tooltip

* remove version
2020-05-07 13:57:50 +08:00
偏右
2ba90f7ff5 💄 Drawer with percentage width cannot show when no mask (#23925)
close #23910
2020-05-07 11:38:51 +08:00
xrkffgg
ee80a2f710 style: optimize layout rtl (#23921) 2020-05-07 10:18:51 +08:00
Ty Mick
c102053f3a Fix English syntax in heading (#23917) 2020-05-07 09:37:01 +08:00
偏右
1444043fd8 Revert "test: Fix Table test (#23915)" (#23916)
This reverts commit ce17f19ca0.
2020-05-06 23:38:58 +08:00
二货机器人
ce17f19ca0 test: Fix Table test (#23915) 2020-05-06 23:00:02 +08:00
二货机器人
701f35d0eb chore: Adjust table col className priority (#23914)
* adjust col class

* update snapshot
2020-05-06 22:15:29 +08:00
Tom Xu
2961dda311 docs: improve popconfirm (#23905)
* docs: improve popconfirm

* Update index.zh-CN.md
2020-05-06 17:37:49 +08:00
偏右
6e8e36080e docs: 📖 update notFoundContent (#23901) 2020-05-06 15:04:08 +08:00
Kol Chen
41bfb79cb7 docs: 📖 update contributing.zh-CN.md (#23897) 2020-05-06 12:40:29 +08:00
偏右
012969e742 docs: refactor tutorial code to React hooks (#23896) 2020-05-06 12:25:06 +08:00
偏右
fdf0f2e585 docs: fix moment locale faq (#23895)
close #23891
2020-05-06 12:03:46 +08:00
偏右
aa3413b086 increase code cov (#23885) 2020-05-05 21:41:50 +08:00
二货机器人
0d46d07ad1 test: Add test coverage (#23884) 2020-05-05 21:08:56 +08:00
偏右
633d064640 increase code cov (#23880) 2020-05-05 19:33:33 +08:00
偏右
6ded8588ed chore: @radio-solid-checked-color typo (#23878)
* Update default.less

* Update dark.less
2020-05-05 18:13:46 +08:00
二货机器人
2a0df4f465 fix: FormItem getValueProps warning (#23875) 2020-05-05 16:15:36 +08:00
Jurriaan BW
5c8ffd473b Fix for #12795: InputNumber onChange type (#23871) 2020-05-05 15:38:05 +08:00
偏右
97fde3a304 🆙 upgrade jest to 26.0.0 (#23870) 2020-05-05 14:08:38 +08:00
xrkffgg
cffcd0378a style: optimize steps style (#23855)
* style: optimize steps style

* fix: name

* Update

Co-authored-by: 偏右 <afc163@gmail.com>

* fix: sm

Co-authored-by: 偏右 <afc163@gmail.com>
2020-05-05 13:55:05 +08:00
twoye
2b2a6a3d22 Update index.zh-CN.md (#23868)
* Update index.zh-CN.md

* Update index.zh-CN.md

Co-authored-by: 偏右 <afc163@gmail.com>
2020-05-05 13:17:50 +08:00
二货机器人
dff19af744 chore: Update Popconfirm & Modal okType type (#23867)
* chore: Update Popconfirm & Modal okType type

* add test case

* update test case
2020-05-05 12:03:16 +08:00
偏右
b9e7d853a4 chore: upgrade moment (#23856)
* 🆙 upgrade moment

* Update package.json
2020-05-04 22:58:42 +08:00
二货机器人
3d2ccd8081 refactor: Use flex of divider (#23849)
* refactor: Use flex of divider

* fix style lint
2020-05-04 18:14:25 +08:00
偏右
91f2dc522f fix progress snapshot (#23850) 2020-05-04 13:38:04 +08:00
Tom Xu
107731a988 docs: improve link path (#23844) 2020-05-04 13:12:42 +08:00
二货机器人
e15773e25b fix: Form.Item warning for initialValue (#23846)
* fix: Form.Item warning for initialValue

* Update index.test.js

* Update index.test.js
2020-05-04 12:13:44 +08:00
二货机器人
72bb377628 fix: Textarea height (#23835)
* fix: Textarea height

* update snapshot
2020-05-03 20:32:34 +08:00
afc163
39456263b5 🎬 improve table demo 2020-05-03 19:46:52 +08:00
二货机器人
74645b7baf docs: Add table render cache faq (#23833) 2020-05-03 16:10:37 +08:00
二货机器人
e4a1a45b09 fix: Menu a color (#23832)
* fix: Menu a color

* update snapshot

* fix menu item
2020-05-03 11:28:15 +08:00
二货机器人
0f83783709 docs: Update notification onClose desc (#23831) 2020-05-03 09:16:33 +08:00
二货机器人
1489903d9d fix: Modal async (#23826)
* make async

* fix tesst
2020-05-03 00:53:32 +08:00
偏右
33cb4c9bb4 fix: Menu inlineCollapsed behavior (#23822)
* fix: Menu should onOpenChange when collapse inline menu

close #23755

* fix snapshot
2020-05-03 00:10:21 +08:00
Amazing Turtle
5c1257d726 docs: Remove deprecated supportServerRender doc 2020-05-02 23:14:43 +08:00
Amazing Turtle
83dcc0016f Update index.zh-CN.md (#23824)
Remove deprecated supportServerRender doc
2020-05-02 23:13:45 +08:00
Tom Xu
cbb46a86b3 docs: fix less-loader@6 customize-cra (#23821)
* docs: fix less-loader@6 customize-cra

* Update use-with-create-react-app.en-US.md
2020-05-02 22:29:01 +08:00
Tom Xu
009f2c8f33 docs: fix customize-cra addLessLoader link (#23819)
* docs: fix customize-cra addLessLoader link

* update snap
2020-05-02 21:58:38 +08:00
二货机器人
34bf3fdb66 fix: DatePicker miss placeholder when it's undefined (#23818)
* fix placeholder

* add test case

* update snapshot
2020-05-02 21:55:23 +08:00
Tom Xu
3d355fde08 refactor(timeline): rewrite with hook (#23631)
* refactor(timeline): rewrite with hook

* add test

* Revert "add test"

This reverts commit 39540589d7.

* Update TimelineItem.tsx

* Update TimelineItem.tsx

* fix lint
2020-05-02 18:55:56 +08:00
Vasilii Artemchuk
50c3f89e19 fix: switch loading dark theme (#23766) 2020-05-02 15:27:27 +08:00
偏右
ca896092e2 fix snapshot (#23816) 2020-05-02 15:18:23 +08:00
偏右
c9267469a0 Revert "[Snyk] Fix for 1 vulnerabilities (#23807)" (#23815)
This reverts commit 08dd4435df.
2020-05-02 14:27:04 +08:00
xrkffgg
bd692bef71 style: optimize button loading style in rtl (#23776)
* style: optimize button loading style in rtl

* opt rtl

* reback
2020-05-02 09:00:47 +08:00
偏右
78b7cf22a1 style: 💄 Fix DatePicker clear icon style (#23811) 2020-05-01 22:16:05 +08:00
二货机器人
58fcee34c1 docs: Add FAQ of form onFieldsChange (#23808) 2020-05-01 16:20:37 +08:00
二货机器人
5f2874b292 fix: Table selection col width not correct (#23806)
* update snapshot

* Update package.json

* update snapshot
2020-05-01 16:02:32 +08:00
Snyk bot
08dd4435df [Snyk] Fix for 1 vulnerabilities (#23807)
* fix: package.json & .snyk to reduce vulnerabilities


The following vulnerabilities are fixed with a Snyk patch:
- https://snyk.io/vuln/SNYK-JS-LODASH-567746

* fix: package.json & .snyk to reduce vulnerabilities


The following vulnerabilities are fixed with a Snyk patch:
- https://snyk.io/vuln/SNYK-JS-LODASH-567746
2020-05-01 15:05:18 +08:00
afc163
7d3cb95f17 fix Tooltip test case 2020-05-01 15:03:27 +08:00
xrkffgg
df1555c6c7 style: optimize input search style in rtl (#23797)
* style: optimize input search style in rtl

* fix lint
2020-05-01 14:50:35 +08:00
偏右
7139493258 refactor menu code (#23793) 2020-04-30 21:29:16 +08:00
xrkffgg
01b98e79d9 docs: optimize site of components 3 (#23779)
* docs: optimize site of components in rtl 3

* add
2020-04-30 21:04:19 +08:00
xrkffgg
ba9d75e3bd fix: switch style (#23791) 2020-04-30 21:02:03 +08:00
Zester Quinn Albano
9f2af262ef docs: add a link to FieldData in setFields FormInstance (#23790) 2020-04-30 20:49:33 +08:00
骗你是小猫咪
e34fc4a7c4 improve: Button loading smooth (#23783) 2020-04-30 17:18:24 +08:00
chenlei
b57c000678 docs: Fix Upload index.en-US.md (#23781)
* docs: fix Upload index.en-US.md

* docs: update Upload index.zh-CN.md
2020-04-30 17:06:05 +08:00
偏右
0b5d09dd4b docs: 🎬 fix Grid demo slider tooltip (#23772)
close #23768
2020-04-30 11:39:16 +08:00
偏右
10cf054b93 style: 💄 Slider marks should not be selected (#23773) 2020-04-30 11:38:59 +08:00
afc163
9c3bf77b92 docs: 🎬 fix Grid demo slider tooltip
close #23768
2020-04-30 11:19:09 +08:00
Eric Wang
815baee4d9 chore: Transform anchor test to typescript (#23499)
* chore: Transform anchor test to typescript

* Separate dom

* use hash

* .

* chagnelog

* chore: Transform anchor test to typescript

* Separate dom

* use hash

* .

* rebase
2020-04-30 10:33:29 +08:00
二货机器人
a243aba422 docs: Fix changelog (#23769) 2020-04-30 10:15:29 +08:00
二货机器人
5ccf03f498 docs: 4.2.0 changelog (#23761)
* docs: 4.2.0 changelog

* Update CHANGELOG.en-US.md

Co-Authored-By: xrkffgg <xrkffgg@gmail.com>

* Update CHANGELOG.zh-CN.md

Co-Authored-By: xrkffgg <xrkffgg@gmail.com>

Co-authored-by: xrkffgg <xrkffgg@gmail.com>
2020-04-29 22:34:06 +08:00
Amumu
245deed4b6 fix proper react import again (#23762) 2020-04-29 22:06:04 +08:00
二货机器人
9cd8f79366 fix snapshot (#23760) 2020-04-29 21:41:58 +08:00
Amumu
935b0e5887 fix: Fix crash when mismatch placement (#23756)
* fix Fix crash when mismatch placement

* add test case
2020-04-29 21:30:36 +08:00
二货机器人
e1299bfcc9 Merge pull request #23758 from ant-design/feature
chore: Merge feature into master
2020-04-29 20:42:52 +08:00
二货机器人
bb1f157645 feat: ConfigProvider support getTargetContainer (#23751)
* add getTargetContainer

* support affix

* test case

* anchor use new context api

* Anchor support getTargetContainer

* doc it

* update patch
2020-04-29 20:22:16 +08:00
xrkffgg
f606ca23f4 site: optimize site of components 2 (#23731)
* docs: optimize site of component 2

* add demo

* fix snap

* remove class
2020-04-29 16:21:56 +08:00
James Yeung
5c79e642ba fix: blazor links (#23649)
* fix: blazor links

* switch to github.io

* Update index.tsx

* Update Footer.tsx

* Update More.tsx

* Update introduce.en-US.md

* Update introduce.zh-CN.md

* Update introduce.zh-CN.md

* Update introduce.en-US.md

* Update introduce.zh-CN.md

Co-authored-by: 偏右 <afc163@gmail.com>
2020-04-29 15:49:00 +08:00
偏右
4fdad9a2f5 docs: fix toc covered by footer (#23753)
close #23702
2020-04-29 15:48:39 +08:00
偏右
0b61b13e56 docs: 🆙 Upgrade input number (#23742)
* 🆙 upgrade to rc-input-number@4.6.0

* 🆙 upgrade to rc-input-number@4.6.1

*  update snapshot

* fix version
2020-04-29 14:18:19 +08:00
xrkffgg
e5c664f7f0 style: fix result style in rtl (#23733) 2020-04-29 13:20:43 +08:00
二货机器人
7f347ec5f2 Merge pull request #23743 from ant-design/feature-merge-master
chore: Feature merge master
2020-04-29 12:58:44 +08:00
zombiej
80017a0f92 update snapshot 2020-04-29 12:17:00 +08:00
xrkffgg
6391df163b fix: table pagination position in rtl (#23747) 2020-04-29 12:12:54 +08:00
zombiej
2c531a827d merge master 2020-04-29 11:29:26 +08:00
xrkffgg
e41340ac4d style: add divider rtl support (#23734)
* style: add divider rtl support

* add base
2020-04-29 10:17:37 +08:00
二货机器人
53a76f0bf7 fix: Table should not crash pageSize is undefined (#23724)
* fix: Table crash when pageSize is undefined

* test case

* fix test case
2020-04-28 20:29:34 +08:00
Baic
7790046ce2 docs: update createFromIconfontCN scriptUrl new array usage (#23704)
* scriptUrl新增数组类型支持,增加文档说明,修改@ant-design/icons最低版本号

* 增加scriptUrl支持数组的代码演示,增加类型说明

* Icon 修改代码演示标题,补充文档

* 根据建议修改文档格式

* 增加scriptUrl为数组时候的覆盖关系说明

* 修改覆盖说明文案
2020-04-28 18:14:07 +08:00
Simon Altschuler
4119c9324a Move "Related Articles" out of code snippet (#23719)
In the customize theme section
2020-04-28 18:13:07 +08:00
Tom Xu
f0c82d5aa7 fix: PageHeader tag ts typo (#23712) 2020-04-28 17:42:23 +08:00
xrkffgg
16a1feb8fb fix: alert base rtl style (#23714) 2020-04-28 17:14:21 +08:00
偏右
d37c16aeaf 🤖 fix rebase action 2020-04-28 17:02:37 +08:00
偏右
7bf44c417c test: fix test case for RangePicker presetted ranges (#23710)
*  fix test case for RangePicker presetted ranges

* 🆙 upgrade simple-git
2020-04-28 16:48:06 +08:00
Tom Xu
699978bcf0 docs: improve rate character (#23713) 2020-04-28 16:46:50 +08:00
偏右
c3c2c157d0 fix: correct Button type="danger" TypeScript definition (#23709)
* fix: remove Button type danger in TypeScript

close #23708

* docs: fix Table dataSource type in document

close #23697

* add warning about type="danger"

* reverse button type warning logic
2020-04-28 16:14:38 +08:00
afc163
e4bdfb218c add test case for RangePicker presetted ranges 2020-04-28 16:00:04 +08:00
偏右
b70d607b9f 💄 Fix RangePicker ranges color when custom theme (#23705)
close #23687
2020-04-28 14:59:17 +08:00
xrkffgg
f6d12c5d88 style: optimize table rtl style (#23706) 2020-04-28 14:48:42 +08:00
偏右
190e2a28a7 🎬 improve tag demo (#23703) 2020-04-28 14:33:39 +08:00
偏右
c27a3a40a7 chore: 📦 Optimize npm package size (#23698)
* improve custom theme import path

* reduce npm package size
2020-04-28 14:11:43 +08:00
Tom Xu
f5153ab950 docs: improve style type (#23700) 2020-04-28 14:09:54 +08:00
二货机器人
3967f12f3d docs: Add mutable data warning (#23696) 2020-04-28 12:19:15 +08:00
xrkffgg
156ff7652c fix: table filter dropdown in rtl (#23695) 2020-04-28 12:16:37 +08:00
Tom Xu
313a68c15f style: fix Transfer empty custom (#23694) 2020-04-28 12:15:48 +08:00
zefeng
14417f1614 feat(theme): adjust font-size in compact mode (#23135)
* feat(theme): adjust font-size in compact mode

With compact theme mode, we adjust default font-size from 14px to 12px.

Closes #23015

* patch: update docs min font-size

* patch

* patch

* patch

* patch

* patch

* patch
2020-04-28 11:16:01 +08:00
xrkffgg
5183592ece style: fix table row select style in rtl (#23690) 2020-04-28 09:55:16 +08:00
Tom Xu
62eaa4193b fix: docs Modal confirmLoading default value (#23682) 2020-04-27 23:45:45 +08:00
Tom Xu
a9d44593b3 fix: Table pagination position ts typo (#23681)
* fix: Table pagination postion ts typo

* fix
2020-04-27 23:45:14 +08:00
MengZhaoFly
a534e4a56a doc: fix layout demo (#23683) 2020-04-27 23:42:51 +08:00
Tom Xu
5f1d5a17de fix: Table demo dynamic settings pagination (#23679)
* fix: Table demo dynamic settings pagination

* fix test
2020-04-27 21:48:13 +08:00
xrkffgg
a823400b79 docs: optimize site of components 1 (#23670)
* docs: optimize site of components 1

* fix: lint

* fix: use space

* fix: snap

* revert: button demo

* fix snap
2020-04-27 21:40:52 +08:00
xrkffgg
3e38e4448c style: optimize list rtl style (#23676) 2020-04-27 21:40:16 +08:00
偏右
d1c39d7ec5 Merge pull request #23678 from ant-design/mergefeature
chore: Merge master branch into feature branch
2020-04-27 21:39:42 +08:00
hengkx
9868a4dc59 Merge branch 'feature' into mergefeature 2020-04-27 21:02:16 +08:00
Yu Mao
e199a7a301 fix: preserve caret position🐛 (#23633)
* 🐛 fix: preserve caret position

*  update test case for preserving caret position

* Update Password.tsx

* Update Password.test.js

* Update Password.test.js

Co-authored-by: 偏右 <afc163@gmail.com>
2020-04-27 18:02:51 +08:00
偏右
5e4d8f10ac 🐛 Fix Button icon only align issue (#23671)
https://github.com/ant-design/ant-design/pull/23670#discussion_r415662549
2020-04-27 17:54:13 +08:00
偏右
053497724d feat: List grid support more column count (#23630)
* list grid

* 🎬 update demo/useBreakpoint.md

* List grid support all number

* refactor object entries

* docs: update List grid API

*  fix snapshot

* fix ci

* use max-width instead of flex %
2020-04-27 16:59:33 +08:00
偏右
939660ec86 💄 Fix Menu duplicated shadow style (#23664)
close #23625
2020-04-27 16:39:41 +08:00
Jocker
e12b560329 docs: 📖 update use-with-create-react-app (#23661)
* Update use-with-create-react-app.zh-CN.md

官网上babel-import-plugin引用的教程有误,会误导新手
https://github.com/ant-design/ant-design/issues/23660

* Update use-with-create-react-app.zh-CN.md

* Update use-with-create-react-app.en-US.md

Co-authored-by: 偏右 <afc163@gmail.com>
2020-04-27 15:42:45 +08:00
偏右
57d36f5b68 Delete tutorial.md 2020-04-27 15:29:51 +08:00
二货机器人
2da7e29198 feat: Table summary support fixed columns (#23647)
* feat: Summary support fixed column

* update snapshot

* update demo
2020-04-27 15:08:54 +08:00
Tom Xu
2325a4438d fix: npm run site (#23658) 2020-04-27 15:02:07 +08:00
Pubudu Kodikara
1a428e852a Fix Why use the svg icon link (#23653) 2020-04-27 13:59:32 +08:00
xrkffgg
df63f2567a refactor(rate): rewrite with hook (#23545)
* refactor(rate): rewrite with hook

* fix: useContext

* fix

* remove

* fix: add displayName
2020-04-27 13:42:04 +08:00
xrkffgg
0d927a18f1 docs: optimize site of sources (#23648) 2020-04-27 13:17:53 +08:00
Tom Xu
8ae2b1f542 feat: tag support ref (#23632)
* feat: tag support ref

* feat done

* Update index.tsx
2020-04-27 13:14:00 +08:00
Tom Xu
c2dc6305f3 refactor(popover): rewrite with hook (#23535)
* refactor(popover): rewrite with hook

* Update index.tsx
2020-04-27 11:59:05 +08:00
Tom Xu
90a12fa3d0 docs: fix popconfirm doc (#23644)
* docs:  fix popconfirm doc

* Update index.en-US.md
2020-04-27 11:52:31 +08:00
xrkffgg
22b5f65830 docs: optimize site of docs (#23642)
* docs: optimize site of docs

* fix: gitee link

* fix lint
2020-04-27 11:36:04 +08:00
偏右
8934bbfffa feat: Menu.Item support icon (#23629)
* feat: Menu.Item support icon

* docs: update menu item usage

* docs: remove span wrap,when use icon

* fix: Collapsed depends on the span

*  fix demo snapshot

* do not wrap children when it is span

* Menu.SubMenu support icon prop

* fix sub menu title

* fix eslint

* update dropdown demo

* fix extra icon attribute on li

Co-authored-by: MengZhaoFly <1424254461@qq.com>
2020-04-26 23:16:15 +08:00
xrkffgg
dabec4c833 refactor(switch): rewrite with hook (#23552)
* refactor(switch): rewrite with hook

* fix: size

* fix

* fix test

* fix

* fix: size
2020-04-26 22:33:36 +08:00
Tom Xu
48ee1a68c6 refactor(popconfirm): rewrite with hook (#23536)
* refactor(popconfirm): rewrite with hook

* fix lint
2020-04-26 22:24:13 +08:00
xrkffgg
2cb635e921 docs: optimize site of spec (#23628)
* docs: optimize site of spec

* fix: lint
2020-04-26 22:13:15 +08:00
偏右
c53329a27d Merge pull request #23627 from ant-design/master
chore: merge master into feature
2020-04-26 22:12:30 +08:00
Tom Xu
9ff7f31dfe refactor(list): rewrite with hook (#23542)
* refactor(list): rewrite with hook

* fix lint

* fix lint

* fix lint

* fix Empty style dep

Co-authored-by: afc163 <afc163@gmail.com>
2020-04-26 21:23:25 +08:00
afc163
75440c47c8 docs: 📖 update customize-theme 2020-04-26 18:36:35 +08:00
xrkffgg
7e53cc7f2a docs: optimize site (#23617) 2020-04-26 17:53:08 +08:00
诸岳
8d4ede4a5a Merge pull request #23607 from ant-design/merge-master
chore: Merge master branch into feature branch
2020-04-26 17:49:16 +08:00
诸岳
a400014efe Merge branch 'master' of github.com:ant-design/ant-design into merge-master 2020-04-26 17:12:58 +08:00
诸岳
eda0064e83 fix(ci): lint error 2020-04-26 16:25:42 +08:00
偏右
89bccf5752 🐛 Fix Button loading style of icon-only (#23614)
close #23610
2020-04-26 16:21:07 +08:00
吴泽康
4c9d03874b fix: anchor regexp (#23577) (#23595)
* fix: anchor regexp (#23577)

* test: fix anchor complete href scrollTo test

* test: anchor sharp matcher regexp

* test: Anchor render perfectly for complete href - hash router
2020-04-26 16:11:37 +08:00
诸岳
f955620601 chore: Merge master branch and fix conflicts 2020-04-26 13:34:11 +08:00
偏右
3ddc99c28f 🐛 Fix Input suffix align issue (#23606)
close #23588
2020-04-26 12:46:59 +08:00
Amumu
656b5abf65 docs: update docs for less-loader@6 (#23603)
* update docs for less-loader@6

* Revert "update docs for less-loader@6"

This reverts commit 5be1a428dc.

* update

* update

* update

* in line
2020-04-26 12:11:01 +08:00
afc163
c9c44c173f fix demo snapshot 2020-04-26 11:00:13 +08:00
Heechan Bak
88cab9547b Update: Add lessOptions in the use-with-create-react-app (#23596) 2020-04-26 10:49:10 +08:00
Tom Xu
60f3e775d0 style: fix table size nest table margin (#23602) 2020-04-26 10:42:05 +08:00
xrkffgg
41da9de946 docs: add symbol (#23600) 2020-04-26 09:34:46 +08:00
诸岳
44da4125fa fix(site): frameworky => framework 2020-04-26 00:09:23 +08:00
诸岳
ac14f44f2b Merge branch 'master' of github.com:ant-design/ant-design 2020-04-25 23:47:08 +08:00
偏右
569b6539d3 🆙 eslint-plugin-unicorn 2020-04-25 23:20:30 +08:00
诸岳
454a02b4d9 chore(test): Update snapshots 2020-04-25 22:54:11 +08:00
Tom Xu
8cdf1c017a fix: ConfigProvider getPopupContainer invalid (#23594)
* fix: ConfigProvider getPopupContainer invalid

* slider getPopupContainer

* Create container.test.js

* Update container.test.js
2020-04-25 22:46:21 +08:00
Tom Xu
8f30a14790 refactor(badge): rewrite with hook (#23488)
* refactor(badge): rewrite with hook

* Update ScrollNumber.tsx
2020-04-25 20:53:21 +08:00
Tom Xu
7379cfa4c2 feat: button support ref (#23571)
* feat: button support ref

* improve

* improve button displayName
2020-04-25 20:45:28 +08:00
偏右
2785d22e5c Update README.md 2020-04-25 19:49:45 +08:00
诸岳
9963e515d1 docs: Add the changelog of 4.1.5 (#23589)
* docs: Add the changelog of 4.1.5

* docs: Update changelog of 4.1.5

* Bump 4.1.5
2020-04-25 19:29:07 +08:00
afc163
5e9bf9fdc0 📖 upgrade less-loader@6 usage 2020-04-25 18:55:29 +08:00
afc163
99bcad6dd6 fix unused import 2020-04-25 18:47:36 +08:00
ibrahim velinov
336a6fba42 docs: Rephrase 500 error (#23570)
* Rephrase 500 error

'Server is wrong' is not a clear sentence for users. I propose to use 'Something went wrong' with 500.

* Update demo.test.js.snap
2020-04-25 18:16:12 +08:00
Benjamin Vertonghen
175e0aaa14 feat: Link Ant Design Blazor (#23579)
* Link Ant Design Blazor

* Indent and align

Co-authored-by: Benjamin Vertonghen <benjamin.vertonghen@apped.be>
2020-04-25 18:12:29 +08:00
二货机器人
22ffa61da0 fix: Legacy button group style (#23590) 2020-04-25 18:03:35 +08:00
Tom Xu
54f2abfe47 refactor(tree): rewrite with hook (#23550)
* refactor(tree): rewrite with hook

* fix codecov

* Update directory.test.js

* Update README.md

* 🆙 upgrade intersection-observer

* refactor(tree): rewrite with hook

* fix codecov

* Update directory.test.js

Co-authored-by: 偏右 <afc163@gmail.com>
2020-04-25 15:30:13 +08:00
二货机器人
efbb2849dc fix: Tree with quick loadData frozen the virtual scroll (#23581)
* update version

* add deadline

* clean up
2020-04-25 11:13:14 +08:00
afc163
d50cc55d87 📖 fix site description and rtl className 2020-04-24 18:48:48 +08:00
偏右
6a49973bb9 docs: 📖 Update data-display.zh-CN.md (#23567)
* Update data-display.zh-CN.md

* Update data-display.en-US.md
2020-04-24 18:24:20 +08:00
Adriano Ruberto
d2140490d8 Fix ie11 flex in steps (#23566) 2020-04-24 18:12:09 +08:00
xrkffgg
dfcaa408c2 style: optimize steps rtl (#23564) 2020-04-24 17:55:44 +08:00
Amumu
fb46b8a864 chore: Add navigation for China mirror site (#23562)
* Add navigation for domestic mirror sites

* use A tag
2020-04-24 17:17:03 +08:00
偏右
d860358f94 chore: 🎬 optimize Table demo code (#23560)
* 🎬 optimize Table demo code

*  fix demo snapshot

* 🐛 Fix Table warning when pageSize is changed

close #23554

* remove console.log

* optimize demo code
2020-04-24 17:16:44 +08:00
Adriano Ruberto
289dd080b9 fix(steps): Add flex on steps to fix ie11 (#23561)
* Add flex on steps to fix ie11

* Ordering
2020-04-24 16:46:46 +08:00
偏右
7cf20f18a1 🆙 upgrade intersection-observer 2020-04-24 13:32:56 +08:00
偏右
6556b583bd Update README.md 2020-04-24 13:29:50 +08:00
Vitaly Budovski
f09686d3df feat: Responsive table columns (#23298) 2020-04-24 12:17:42 +08:00
Sonjeet Paul
4f1ad3ef4b url navigates to correct component listing (#23540) 2020-04-24 10:41:38 +08:00
Tom Xu
eb83d6b341 docs: fixed link path for components (#23533) 2020-04-24 10:40:23 +08:00
Sonjeet Paul
f9c56b6eb4 docs: 📖 fixed link path for components 2020-04-23 21:10:57 +08:00
Tom Xu
6401da2082 refactor(comment): rewrite with hook (#23498)
* refactor(comment): rewrite with hook

* improve comment code
2020-04-23 20:52:15 +08:00
偏右
d2c541b4e2 fix: 🐛 Input.Search height affected by suffix (#23527)
* 🎬 improve Input demo code

* style: fix Input.Search height stretched by suffix

close #23523

* fix react key warning

*  fix demo snapshot
2020-04-23 18:11:11 +08:00
xrkffgg
facbe46251 style: optimize alert rtl tyle (#23526)
* style: optimize alert rtl tyle

* fix dark
2020-04-23 17:58:36 +08:00
xrkffgg
be72d1762a fix: upload disabled hover border (#23522) 2020-04-23 15:58:17 +08:00
xrkffgg
eb5c7ffc7e style: complete upload rtl (#23520) 2020-04-23 15:01:20 +08:00
二货机器人
8ec4d3f64f docs: Update research result image (#23519) 2020-04-23 13:57:32 +08:00
Amumu
fb2ef64036 update Compatibility intro (#23513) 2020-04-23 11:55:37 +08:00
偏右
cd34b624b3 🐛 Fix Menu behavior when hover gap (#23511)
close #13955
2020-04-23 11:17:21 +08:00
偏右
835bcabdbc 💄 fix DatePicker/TimePicker icon color (#23508)
should be same as 3.x
2020-04-23 10:48:51 +08:00
xiaoxintang
937beba421 fix: Table selections type when use Table.SELECTION_ALL or Table.SELECTION_INVERT (#23462)
* fix:selections type when use SELECTION_ALL | SELECTION_INVERT

* fix: Table selections type when use Table.SELECTION_ALL or Table.SELECTION_INVERT

* fix: Table selections type when use Table.SELECTION_ALL or Table.SELECTION_INVERT

* Update useSelection.tsx

* Update type.test.tsx

Co-authored-by: 二货机器人 <smith3816@gmail.com>
2020-04-22 21:59:18 +08:00
二货机器人
d77c2e8ba7 docs: Mention filterOption params change in doc (#23501)
* Update migration-v4.zh-CN.md

* Update migration-v4.en-US.md
2020-04-22 21:24:36 +08:00
偏右
17f7e2f4d2 fix: Tree custom icon missing when loading (#23494)
close #23470
2020-04-22 21:11:57 +08:00
Eric Wang
800871166c chore: Transform alert test to typescript (#23495) 2020-04-22 18:16:03 +08:00
Tom Xu
b7e877aeef refactor(slider): rewrite with hook (#23474)
* refactor(slider): rewrite with hook

* improve test

* Revert "improve test"

This reverts commit 48cd83d0cc.

* improve test

* improve test 2
2020-04-22 15:58:57 +08:00
偏右
c550cb050b 💄 fix DatePicker/TimePicker disabled icon color (#23478) 2020-04-22 15:16:51 +08:00
Eric Wang
64cb9584ce fix: include tests in type check (#23452)
* fix: include tests in type check

* Do lint *.md

* Improve types in tests
2020-04-22 13:37:23 +08:00
Eric Wang
55265ac4ef chore: Replace domhook with jest.spyon (#23469)
* chore: Replace domhook with jest.spyon

* use mockreturn value when possible

* Update tests/shared/focusTest.js
2020-04-22 11:59:56 +08:00
xrkffgg
677168b007 style: optimize tabs rtl style (#23471) 2020-04-22 11:57:06 +08:00
偏右
7935651899 style: select arrow won't rotate now (#23468)
* style: 💄 Select arrow won't rotate when open

* Update index.less
2020-04-22 11:54:13 +08:00
Tom Xu
cf3d611f59 refactor(tag): rewrite with hook (#23466)
* refactor(tag): rewrite with hook

* fix lint
2020-04-22 10:59:24 +08:00
偏右
a4c07fc0af Merge pull request #23465 from ant-design/master
chore: merge master into feature
2020-04-22 10:42:00 +08:00
二货机器人
a1e0c41c8b feat: ConfigProvider support config Input autoComplete (#23455)
* support autoComplete

* update doc

* fix lint
2020-04-22 10:38:43 +08:00
xrkffgg
d7e97aa996 style: optimize tag rtl style (#23464) 2020-04-22 10:00:59 +08:00
Tom Xu
4a3e01ff0b refactor(input-number): rewrite with hook (#23461) 2020-04-22 09:48:10 +08:00
pdeva
3e22b505a3 fix: proper react import (#23381)
* proper react import

fix for #22708

* update iconutil in select

* update in tree component
2020-04-22 09:37:46 +08:00
偏右
db97c5788e chore: add remark lint (#23457)
* 💄 Add remark lint for markdown files

* 💄 Add remark lint for markdown files

* 💄 Add remark lint for markdown files
2020-04-21 23:40:41 +08:00
二货机器人
1163d8e23d docs: Update demo (#23451) 2020-04-21 23:26:41 +08:00
xrkffgg
5e09660a3e fix: collapse default position in rtl (#23445)
* fix: collapse default position in rtl

* update snap

* up

* fix

* fix

* fix var

* fix
2020-04-21 23:23:37 +08:00
Eric Wang
9a43e439b3 chore: Use override instead of env to control eslint on markdown (#23454) 2020-04-21 23:21:56 +08:00
偏右
428b07625c fix: Select arrow cannot trigger open (#23448)
close #23447
2020-04-21 18:03:47 +08:00
Amumu
17c63e52bf chore: improve less variable @form-item-margin-bottom (#23436)
* improve @formItemMarginBottom

* Revert "improve @formItemMarginBottom"

This reverts commit 6d8da5bdb9.

* update style
2020-04-21 17:48:15 +08:00
偏右
02faa4bcf1 💄 tweak Table selected row hover background (#23313) 2020-04-21 16:53:06 +08:00
偏右
4902c5a4f0 docs: 📖 update Form ts demo for createRef (#23440)
close #23417
2020-04-21 16:42:56 +08:00
偏右
8bd8eee573 fix: first Divider render bug (#23438)
close #23432
2020-04-21 16:16:13 +08:00
xrkffgg
f467df5fe2 feat: add rtl calendar (#23394) 2020-04-21 15:29:36 +08:00
偏右
1dab17eef0 feat: 💄 Divider support plain for lighter style (#23405)
* 💄 Divider support `asHeading` for lighter style

*  fix demo snapshot

* docs: 📖 Divider asHeading documentation

* fix tsd

*  fix demo snapshot

* asHeading to plain

*  fix demo snapshot

* fix css
2020-04-21 14:16:33 +08:00
偏右
e206b4146b chore: add gitleaks.yml (#23425)
* Add gitleaks.yml

* Update gitleaks.yml

* chore: add gitleaks (#23428)

* chore: add gitleaks

* chore: remove gitleaks

* Apply suggestions from code review

Co-authored-by: pr <pr>
Co-authored-by: 偏右 <afc163@gmail.com>

Co-authored-by: 信鑫-King <chaolin.jcl@alibaba-inc.com>
2020-04-21 12:19:23 +08:00
偏右
c3e263f2f2 chore: 🚮 remove console (#23431) 2020-04-21 11:47:09 +08:00
二货机器人
2105a330dd docs: Remove dead link & Update dead images (#23427)
* docs: Replace image

* update link
2020-04-21 11:34:26 +08:00
xrkffgg
6d238a734d feat: search rtl (#23424) 2020-04-21 11:25:53 +08:00
偏右
2c86aebfa3 Merge pull request #23426 from ant-design/master
chore: merge master into feature
2020-04-21 11:24:57 +08:00
二货机器人
5a10d29796 fix: ConfigProvider with nest prefixCls (#23423)
* fix: ConfigProvider with nest prefixCls

* update

* update

* update
2020-04-21 11:16:33 +08:00
xrkffgg
3d76859bbc style: add dropdown group title rtl style (#23404)
* style: add dropdown group title rtl style

* fix margin

* fix lint
2020-04-21 10:49:59 +08:00
二货机器人
1d50004644 feat: Typography support onEllipsis (#23414)
* feat: support onEllipsis

* add test case

* update doc
2020-04-21 10:13:57 +08:00
二货机器人
ac7865a6fc chore: Adjust search style (#23406)
* chore: Adjust search style

* fix lint

* Update demo.test.js.snap

* update style

* update cover area

* area it
2020-04-21 09:41:09 +08:00
偏右
fc98ab7222 test: increase test cov for Layout and Typography (#23407) 2020-04-20 19:18:53 +08:00
二货机器人
40afa44673 chore: Move preview res to cdn (#23408) 2020-04-20 18:40:18 +08:00
xrkffgg
43bc7196ea docs: fix site subtitle in rtl (#23403) 2020-04-20 17:25:11 +08:00
xrkffgg
089591ac34 style: add steps disabled style (#23402) 2020-04-20 17:05:41 +08:00
xrkffgg
f748c4ef17 style: optimize pageheader rtl style (#23401) 2020-04-20 16:50:38 +08:00
xrkffgg
0b6d34d474 style: optimize statistic rtl style (#23397) 2020-04-20 16:29:30 +08:00
xrkffgg
e2dacde754 style: fix button loading rtl (#23399) 2020-04-20 16:25:43 +08:00
afc163
e797d44c9e chore: upgrade rc-upload to fix ci 2020-04-20 15:47:25 +08:00
linye
62d51034c4 Update MorePage.tsx (#23389) 2020-04-20 11:52:50 +08:00
linye
849ab34189 docs: Update RecommendPage.tsx (#23387)
* Update RecommendPage.tsx

* Update site/theme/template/Home/RecommendPage.tsx

Co-authored-by: 偏右 <afc163@gmail.com>
2020-04-20 11:11:02 +08:00
xrkffgg
757c57622b feat: add rate direction (#23321)
* feat: add rate direction

* fix: remove css

* remove classname
2020-04-20 11:05:27 +08:00
偏右
fd38c347a8 Update FUNDING.yml 2020-04-19 20:22:27 +08:00
偏右
54d050324a 🐛 Fix Carousel tabindex in non-active slide (#23380)
close #23294
2020-04-19 01:28:54 +08:00
偏右
76ee9668ef docs: 📖 update react-slick API link (#23379)
* Update index.en-US.md

* Update index.zh-CN.md
2020-04-19 00:51:56 +08:00
偏右
fabec4831c Merge pull request #23377 from ant-design/master
chore: Merge master into feature
2020-04-18 23:54:51 +08:00
陈帅
7489786d22 docs: add 4.1.4 changelog (#23373)
* doc: add 4.1.4 changelog

* fix error version

* sort log

* groud log

* add #23331

* fix review doc

* fix review doc
2020-04-18 21:59:24 +08:00
二货机器人
31267c5648 docs: Update migration for Select events (#23376)
* docs: Update migration for Select events

* Update migration-v4.en-US.md
2020-04-18 21:10:01 +08:00
Tom Xu
6e1ffb96ca fix: Input.Search ConfigProvider size (#23331)
* fix: Input.Search ConfigProvider size

* Update Search.tsx

* add test

* Update size.md
2020-04-18 18:31:03 +08:00
偏右
5ca5f44a7e 🆙 upgrade intersection-observer 2020-04-18 16:23:31 +08:00
Tom Xu
50416b3a7b improvement: Form default locale (#23165)
* improve: Form default locale

* fix lint

* fix lint

* improve form doc

* add test case

* improve form validate messages
2020-04-18 13:18:51 +08:00
Tom Xu
09e69c385e refactor(button): rewrite with hook (#23367) 2020-04-18 13:06:04 +08:00
偏右
f4c489553f fix: Modal.info onOk execute times (#23360)
* refactor: modal confirm onOk code

* fix: Modal.xxx onOk execute time when has close argument

close #23358

* Add test case

* fix lint
2020-04-18 01:09:14 +08:00
Eric Wang
95f6f0f14a Chore: Refactor affix test to typescript (#23364) 2020-04-18 00:31:31 +08:00
Amumu
c70b49a709 fix: fix tree key ts type (#23348)
* fix tree key ts type

* revert snap
2020-04-17 23:31:39 +08:00
Amumu
5e7f3cc67e firstActiveValue has been deprecated, remove it (#23354) 2020-04-17 18:10:10 +08:00
kenve
edcd1b2609 docs(components): improve link (#23355) 2020-04-17 17:56:42 +08:00
偏右
8ab146220e 💄 Fix Input[type=color] height (#23351)
close #23334
2020-04-17 16:04:20 +08:00
xrkffgg
6c451865eb site: add title upload picture-card (#23312)
* style: fix modal body padding without header

* change demo

* add url
2020-04-17 14:28:18 +08:00
xrkffgg
7d5910faf0 style: fix menu rtl style (#23319) 2020-04-16 17:40:13 +08:00
二货机器人
7e9fe271ed feat: Space support align (#23306)
* support align

* update demo & snapshot

* update comment

* update docs

* Update components/space/index.en-US.md

Co-Authored-By: 骗你是小猫咪 <darryshaw@gmail.com>

* update doc

Co-authored-by: 骗你是小猫咪 <darryshaw@gmail.com>
2020-04-16 12:28:04 +08:00
Misha Kav
cff24d5dcb add missings translations in he_IL (#23302) 2020-04-16 10:08:37 +08:00
Misha Kav
f9cb1522f3 add missing translations in ru_IL (#23303) 2020-04-16 10:07:38 +08:00
偏右
0716d1498f fix: Dropdown submenu background (#23296)
* 🐛 Fix Dropdown submenu background

close #23293

* remove unused code
2020-04-15 23:00:51 +08:00
二货机器人
f7d1d41220 fix: multiple selector disabled remove icon (#23295)
* fix: Select remove icon

* revert demo
2020-04-15 22:54:59 +08:00
偏右
ff509bccd0 fix: optimize PageHeader responsive behavior (#23277)
* 💄 optimize PageHeader responsive behavior

close #23260

*  add test case

* remove console
2020-04-15 12:44:35 +08:00
zefeng
bff09f8fde fix: fix ${theme}-theme.js file order (#23243)
* fix: fix ${theme}-theme.js file order

* chore: add generateThemeFileContent test

* chore: add test

* patch

* update docs

* update docs

* update docs
2020-04-15 11:37:29 +08:00
偏右
c7cc8d40c8 🐛 Select custom suffixIcon could be operated (#23274)
close #23263
2020-04-15 11:29:38 +08:00
二货机器人
c2a1fe5b1f docs: Update Table edit row example (#23270) 2020-04-15 10:39:16 +08:00
二货机器人
9c08bb2482 docs: Add listHeight desc (#23268) 2020-04-15 10:04:01 +08:00
二货机器人
02d7292576 fix: Input inline allowClear style (#23259)
* fix: Input allow clear icon

* update test case

* update snapshot
2020-04-14 23:04:23 +08:00
myeunhyuk
178ccbee6a Update resources.en-US.md (#23254) 2020-04-14 21:06:41 +08:00
myeunhyuk
d3b367ad04 docs: Update resources page sketch file (#23253) 2020-04-14 21:06:13 +08:00
Dongcheng Wang
ac5050f4ed doc(slider): value & defaultValue not consistent with definition (#23252) 2020-04-14 19:33:49 +08:00
nick
87da7bfe67 feat: add custom isImgurl prop to Upload Component (#23248)
* feat: customize isImageUrl support

* docs: Update Upload doc

* docs: Add isImgUrl default implement link

* docs: update default link address
2020-04-14 19:32:16 +08:00
zefeng
efd25100a5 fix: tree-select render blank in compact mode (#23231) 2020-04-14 19:17:42 +08:00
偏右
4ad5830eec fix: Select caret missing in Collapse (#23250)
close #23059
close #23175
2020-04-14 18:20:24 +08:00
Christian Fleschhut
54b11b2ae3 docs(Empty component): 📖 Fix typo in image prop description (#23251) 2020-04-14 18:20:14 +08:00
afc163
19a7b55a9f 🆙 upgrade intersection-observer 2020-04-14 17:32:09 +08:00
Tanmoy Bhowmik
e3d2754b1d fix: Fix popupClassName prop in timepicker (#23214)
* fix(time-picker): combine dropdownClassName and popupClassName prop

* test(time-picker): add test for popupClassName and dropdownClassName prop

* chore(time-picker): add demo for popupClassName prop

* test(time-picker): remove rc-picker dependency

* doc(time-picker): change default prop of popupClassName to undefined

* fix(time-picker): remove the use of dropdownClassName

* Apply suggestions from code review

Co-authored-by: 偏右 <afc163@gmail.com>
2020-04-14 16:49:58 +08:00
Evan Charlton
58c6900175 chore: Fix console warning typo (validate -> valid) (#23240)
Clean up the typos in the helpful console warning messages which get
emitted if the incorrect prop is passed to certain components.
2020-04-14 16:48:23 +08:00
xrkffgg
1855fef437 fix: fix select rtl (#23235)
* fix: fix select rtl

* fix lint

Co-Authored-By: Amumu <yoyo837@hotmail.com>

Co-authored-by: Amumu <yoyo837@hotmail.com>
2020-04-14 16:42:39 +08:00
二货机器人
c338569cff docs: Update Form required desc (#23238)
* Update index.zh-CN.md

* Update index.en-US.md
2020-04-14 15:41:15 +08:00
Amumu
2c6733b0c8 add release date (#23229) 2020-04-14 12:46:30 +08:00
偏右
b1f3587e02 Update visual.zh-CN.md (#23218) 2020-04-14 10:38:06 +08:00
Rustin
13fda44fb1 refactor(skeleton): rewrite with hook (#23206)
* refactor(skeleton): rewrite with hook

* fix(skeleton): refine lint and compile issues

* fix(skeleton): refine compile issues

* chore: ignore eslint warning
2020-04-14 10:30:14 +08:00
二货机器人
8c11676afa fix: Table selection childrenColumnName not work (#23205)
* fix childrenPropName

* test case

* update test case
2020-04-13 22:56:26 +08:00
Eric Wang
436d4b1be5 improvement: Fix types in form item (#22962)
* Fix types in form item

* use jsx.element
2020-04-13 21:30:55 +08:00
afc163
3f4f5864fe fix test case which fails a lot 2020-04-13 20:38:31 +08:00
afc163
59c0cdf3a2 fix test case which fails a lot 2020-04-13 20:21:30 +08:00
偏右
0ca9c69da2 release 4.1.3 (#23199) 2020-04-13 19:35:12 +08:00
HouXiancheng
8c3081788c fix: table fixed bug (#23181) 2020-04-13 19:32:50 +08:00
偏右
f7ead77f88 chore: Improve changelog workflow (#23198)
*  improve changelog workflow

* chore: fill missing changelog

* allow custom input
2020-04-13 19:04:49 +08:00
二货机器人
ca93757747 fix: vertial from label height (#23192) 2020-04-13 16:59:05 +08:00
xrkffgg
fca1367085 feat: add notification rtl config (#23185)
* feat: add notification rtl config

* test: add test
2020-04-13 15:45:49 +08:00
xrkffgg
d160016959 style: fix steps rtl (#23183) 2020-04-13 13:53:42 +08:00
Eric Wang
7bc3d4f222 chore: Refactor the button test to use typescript (#22953)
* Refactor the button test to use typescript

* update tsconfig.json

* Change file name as a workaround

* update antd-tools
2020-04-13 13:36:23 +08:00
HouXiancheng
653724b79e fix: tabs_animation_bug (#23151)
* fix: tabs_animation_bug

* fix: fix lint error

Co-authored-by: 侯先诚 <houxiancheng@houxianchengdeMacBook-Pro.local>
2020-04-13 12:19:06 +08:00
zefeng
65293f62d6 feat: add getThemeVar file to support theme config and fix 4.1.2 them… (#23171)
* feat: add getThemeVar file to support theme config and fix 4.1.2 theme config breaking change

* patch
2020-04-13 00:05:48 +08:00
baozefeng
9c2473ab25 Revert "feat: add getThemeVar file to support theme config and fix 4.1.2 theme config breaking change"
This reverts commit 3d9b891a26.
2020-04-12 22:48:53 +08:00
baozefeng
3d9b891a26 feat: add getThemeVar file to support theme config and fix 4.1.2 theme config breaking change 2020-04-12 22:48:10 +08:00
二货机器人
de68e37da2 fix @tabs-card-height (#23168) 2020-04-12 21:01:14 +08:00
二货机器人
12ce6aba06 fix: Safari12 fixed column (#23161)
* fix: Safari12 fixed column

* fix lint
2020-04-12 17:55:30 +08:00
二货机器人
6bb6c4c243 small size (#23160) 2020-04-12 15:33:43 +08:00
zefeng
5999aa7414 docs: update customize theme docs (#23159) 2020-04-12 15:32:15 +08:00
二货机器人
90e952a920 Merge pull request #23158 from ant-design/master-to-merge-feature
chore: Merge master into feature
2020-04-12 15:30:20 +08:00
afc163
78ec790311 resolve merge conflict 2020-04-12 14:44:29 +08:00
afc163
89ce33f5d8 update snapshot 2020-04-12 12:55:42 +08:00
Chiciuc Nicușor
eb90c5b0a0 fix: Use ElementOf<T> instead of array indexing (#23132) 2020-04-11 20:46:09 +08:00
二货机器人
deafd3fcce fix: compact group style (#23149)
* fix: compact group style

* updat snapshot
2020-04-11 20:33:08 +08:00
二货机器人
ff30366d22 chore: add preview (#23128)
* chore: add preview

* update template

* update ignore lint

* update template

* support quota analysis

* comment it

* trigger build

* trigger build

* force trigger
2020-04-11 19:52:55 +08:00
Joker Wang
f93f86123e fix: Pagination missing showTitle (#23134) (#23144)
* fix: Pagination missing showTitle (#23134)

* Update Chinese description of showTitle

Co-Authored-By: 偏右 <afc163@gmail.com>

Co-authored-by: 偏右 <afc163@gmail.com>
2020-04-11 16:36:12 +08:00
Chris Young
ca616647ce modify table size.less to accomodate size prop for footer padding (#23140) 2020-04-11 16:11:28 +08:00
二货机器人
50d908662e docs: Update Form FAQ (#23138)
* docs: Update Form FAQ

* Update index.en-US.md
2020-04-11 10:30:05 +08:00
偏右
bfd5d7c910 fix: PageHeader style breaks when title is too long (#23133)
* fix: PageHeader style breaks when title is too long

close #15664

*  update snapshot

* 💄 Improve PageHeader responsive design
2020-04-10 19:25:31 +08:00
二货机器人
49acc871b9 chore: Fix compile error (#23131) 2020-04-10 18:47:08 +08:00
二货机器人
77d45690c0 feat: Form.Item support initialValue & getValueProps (#22993)
* add getValueProps

* field initialValue

* add faq
2020-04-07 21:57:27 +08:00
二货机器人
77dd5af0eb Merge pull request #22998 from ant-design/master
chore: Feature merge master
2020-04-07 21:00:00 +08:00
偏右
939ea047ad Merge pull request #22952 from ant-design/master
chore: Merge master into feature
2020-04-06 19:13:37 +08:00
二货机器人
678168a74e Merge pull request #22880 from ant-design/master
chore: Feature merge master
2020-04-03 13:58:35 +08:00
二货机器人
1cc9ffdd3e Merge pull request #22823 from ant-design/master
feature merge master
2020-04-01 18:10:00 +08:00
547 changed files with 27077 additions and 9201 deletions

View File

@@ -1,38 +1,20 @@
const fs = require('fs');
const path = require('path');
// eslint-disable-next-line import/no-extraneous-dependencies
const packageInfo = require('./package.json');
const defaultVars = require('./scripts/default-vars');
const darkVars = require('./scripts/dark-vars');
const compactVars = require('./scripts/compact-vars');
function generateThemeFileContent(theme) {
return `const { ${theme}ThemeSingle } = require('./theme');\nconst defaultTheme = require('./default-theme');\n
module.exports = {
...defaultTheme,
...${theme}ThemeSingle
}`;
}
// We need compile additional content for antd user
function finalizeCompile() {
if (fs.existsSync(path.join(__dirname, './lib'))) {
// Build package.json version to lib/version/index.js
// prevent json-loader needing in user-side
const versionFilePath = path.join(process.cwd(), 'lib', 'version', 'index.js');
const versionFileContent = fs.readFileSync(versionFilePath).toString();
fs.writeFileSync(
versionFilePath,
versionFileContent.replace(
/require\(('|")\.\.\/\.\.\/package\.json('|")\)/,
`{ version: '${packageInfo.version}' }`,
),
);
// eslint-disable-next-line no-console
console.log('Wrote version into lib/version/index.js');
// Build package.json version to lib/version/index.d.ts
// prevent https://github.com/ant-design/ant-design/issues/4935
const versionDefPath = path.join(process.cwd(), 'lib', 'version', 'index.d.ts');
fs.writeFileSync(
versionDefPath,
`declare var _default: "${packageInfo.version}";\nexport default _default;\n`,
);
// eslint-disable-next-line no-console
console.log('Wrote version into lib/version/index.d.ts');
// Build a entry less file to dist/antd.less
const componentsPath = path.join(process.cwd(), 'components');
let componentsLessContent = '';
@@ -53,19 +35,34 @@ function finalizeCompile() {
function buildThemeFile(theme, vars) {
// Build less entry file: dist/antd.${theme}.less
fs.writeFileSync(
path.join(process.cwd(), 'dist', `antd.${theme}.less`),
`@import "../lib/style/${theme}.less";\n@import "../lib/style/components.less";`,
);
// eslint-disable-next-line no-console
console.log(`Built a entry less file to dist/antd.${theme}.less`);
if (theme !== 'default') {
fs.writeFileSync(
path.join(process.cwd(), 'dist', `antd.${theme}.less`),
`@import "../lib/style/${theme}.less";\n@import "../lib/style/components.less";`,
);
// eslint-disable-next-line no-console
console.log(`Built a entry less file to dist/antd.${theme}.less`);
} else {
fs.writeFileSync(
path.join(process.cwd(), 'dist', `default-theme.js`),
`module.exports = ${JSON.stringify(vars, null, 2)};\n`,
);
return;
}
// Build ${theme}.js: dist/${theme}-theme.js, for less-loader
fs.writeFileSync(
path.join(process.cwd(), 'dist', `theme.js`),
`const ${theme}ThemeSingle = ${JSON.stringify(vars, null, 2)};\n`,
{
flag: 'a',
},
);
fs.writeFileSync(
path.join(process.cwd(), 'dist', `${theme}-theme.js`),
`module.exports = ${JSON.stringify(vars, null, 2)};`,
generateThemeFileContent(theme),
);
// eslint-disable-next-line no-console
@@ -80,10 +77,47 @@ function finalizeDist() {
'@import "../lib/style/index.less";\n@import "../lib/style/components.less";',
);
// eslint-disable-next-line no-console
fs.writeFileSync(
path.join(process.cwd(), 'dist', 'theme.js'),
`const defaultTheme = require('./default-theme.js');\n`,
);
// eslint-disable-next-line no-console
console.log('Built a entry less file to dist/antd.less');
buildThemeFile('default', defaultVars);
buildThemeFile('dark', darkVars);
buildThemeFile('compact', compactVars);
fs.writeFileSync(
path.join(process.cwd(), 'dist', `theme.js`),
`
function getThemeVariables(options = {}) {
let themeVar = {
'hack': \`true;@import "\${require.resolve('antd/lib/style/color/colorPalette.less')}";\`,
...defaultTheme
};
if(options.dark) {
themeVar = {
...themeVar,
...darkThemeSingle
}
}
if(options.compact){
themeVar = {
...themeVar,
...compactThemeSingle
}
}
return themeVar;
}
module.exports = {
darkThemeSingle,
compactThemeSingle,
getThemeVariables
}`,
{
flag: 'a',
},
);
}
}
@@ -94,4 +128,5 @@ module.exports = {
dist: {
finalize: finalizeDist,
},
generateThemeFileContent,
};

View File

@@ -10,6 +10,10 @@ module.exports = {
'**/*.json',
],
modulePattern: [
{
pattern: /ConfigContext.*renderEmpty/ms,
module: '../empty',
},
{
pattern: /ConfigConsumer.*renderEmpty/ms,
module: '../empty',

View File

@@ -24,3 +24,5 @@ node_modules
_site
dist
**/*.d.ts
# Scripts
scripts/previewEditor/**/*

View File

@@ -1,4 +1,4 @@
const eslintrc = {
module.exports = {
extends: [
'airbnb',
'prettier',
@@ -31,6 +31,29 @@ const eslintrc = {
'@typescript-eslint/no-unused-expressions': 2,
},
},
{
files: ['*.md'],
globals: {
React: true,
ReactDOM: true,
mountNode: true,
},
rules: {
indent: 0,
'no-console': 0,
'no-plusplus': 0,
'eol-last': 0,
'no-script-url': 0,
'prefer-rest-params': 0,
'react/no-access-state-in-setstate': 0,
'react/destructuring-assignment': 0,
'react/no-multi-comp': 0,
'jsx-a11y/href-no-hash': 0,
'import/no-extraneous-dependencies': 0,
'import/no-unresolved': 0,
'jsx-a11y/control-has-associated-label': 0,
},
},
],
rules: {
camelcase: 0,
@@ -91,38 +114,12 @@ const eslintrc = {
'jest/no-test-callback': 0,
'jest/expect-expect': 0,
'react-hooks/rules-of-hooks': 2, // Checks rules of Hooks
"unicorn/better-regex": 2,
"unicorn/prefer-trim-start-end": 2,
"unicorn/expiring-todo-comments": 2,
"unicorn/no-abusive-eslint-disable": 2,
'unicorn/better-regex': 2,
'unicorn/prefer-trim-start-end': 2,
'unicorn/expiring-todo-comments': 2,
'unicorn/no-abusive-eslint-disable': 2,
},
globals: {
gtag: true,
},
};
if (process.env.RUN_ENV === 'DEMO') {
eslintrc.globals = Object.assign(eslintrc.globals, {
React: true,
ReactDOM: true,
mountNode: true,
});
Object.assign(eslintrc.rules, {
indent: 0,
'no-console': 0,
'no-plusplus': 0,
'eol-last': 0,
'no-script-url': 0,
'prefer-rest-params': 0,
'react/no-access-state-in-setstate': 0,
'react/destructuring-assignment': 0,
'react/no-multi-comp': 0,
'jsx-a11y/href-no-hash': 0,
'import/no-extraneous-dependencies': 0,
'import/no-unresolved': 0,
'jsx-a11y/control-has-associated-label': 0,
});
}
module.exports = eslintrc;

3
.github/FUNDING.yml vendored
View File

@@ -4,5 +4,6 @@ github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, u
open_collective: ant-design
patreon: ant_design
ko_fi: # Replace with a single Ko-fi username
issuehunt: ant-design/ant-design
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
custom: # Replace with a single custom sponsorship URL
custom: https://www.buymeacoffee.com/antdesign

17
.github/workflows/gitleaks.yml vendored Normal file
View File

@@ -0,0 +1,17 @@
name: gitleaks
on: [push,pull_request]
jobs:
gitleaks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: '1'
- name: wget
uses: wei/wget@v1
with:
args: -O .gitleaks.toml https://raw.githubusercontent.com/ycjcl868/gitleaks/master/.gitleaks.toml
- name: gitleaks-action
uses: zricethezav/gitleaks-action@master

View File

@@ -1,22 +1,20 @@
on:
name: Automatic Rebase
# https://github.com/marketplace/actions/automatic-rebase
on:
issue_comment:
types: [created]
name: Automatic Rebase
jobs:
rebase:
name: Rebase
if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/rebase')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: Automatic Rebase
uses: cirrus-actions/rebase@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# https://github.community/t5/GitHub-Actions/Workflow-is-failing-if-no-job-can-be-ran-due-to-condition/m-p/38186#M3250
always_job:
name: Always run job
runs-on: ubuntu-latest
steps:
- name: Always run
run: echo "This job is used to prevent the workflow to fail when all other jobs are skipped."
- uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Automatic Rebase
uses: cirrus-actions/rebase@1.2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

5
.gitignore vendored
View File

@@ -25,6 +25,7 @@ nohup.out
_site
_data
dist
report.html
/lib
/es
elasticsearch-*
@@ -54,4 +55,6 @@ site/theme/template/Content/Article.jsx
site/theme/template/Content/EditButton.jsx
site/theme/template/Resources/*.jsx
site/theme/template/Resources/**/*.jsx
site/theme/template/NotFound.jsx
site/theme/template/NotFound.jsx
scripts/previewEditor/index.html
components/version/version.tsx

View File

@@ -1,12 +1,17 @@
const libDir = process.env.LIB_DIR;
const transformIgnorePatterns = [
'/dist/',
// Ignore modules without es dir.
// Update: @babel/runtime should also be transformed
'node_modules/(?!.*@babel)[^/]+?/(?!(es|node_modules)/)',
'node_modules/(?!.*@(babel|ant-design))[^/]+?/(?!(es|node_modules)/)',
];
function getTestRegex(libDir) {
if (libDir === 'dist') {
return 'demo\\.test\\.js$';
}
return '.*\\.test\\.(j|t)sx?$';
}
module.exports = {
verbose: true,
setupFiles: ['./tests/setup.js'],
@@ -28,7 +33,7 @@ module.exports = {
'\\.md$': './node_modules/@ant-design/tools/lib/jest/demoPreprocessor',
'\\.(jpg|png|gif|svg)$': './node_modules/@ant-design/tools/lib/jest/imagePreprocessor',
},
testRegex: `${libDir === 'dist' ? 'demo' : '.*'}\\.test\\.js$`,
testRegex: getTestRegex(process.env.LIB_DIR),
collectCoverageFrom: [
'components/**/*.{ts,tsx}',
'!components/*/style/index.tsx',

View File

@@ -12,7 +12,7 @@ module.exports = {
'\\.md$': './node_modules/@ant-design/tools/lib/jest/demoPreprocessor',
'\\.(jpg|png|gif|svg)$': './node_modules/@ant-design/tools/lib/jest/imagePreprocessor',
},
testRegex: 'demo\\.test\\.js$',
testRegex: 'demo\\.test\\.(j|t)s$',
testEnvironment: 'node',
transformIgnorePatterns,
snapshotSerializers: ['enzyme-to-json/serializer'],

View File

@@ -1,2 +1 @@
~*
dist/report.html

9
.remarkrc.js Normal file
View File

@@ -0,0 +1,9 @@
const config = {
plugins: [
'remark-preset-lint-recommended',
['remark-lint-list-item-indent', 'space'],
['remark-lint-no-literal-urls', false],
],
};
module.exports = config;

View File

@@ -15,8 +15,191 @@ timeline: true
---
## 4.2.2
`2020-05-11`
- 🐞 Fix `npm run version` install error. [#24059](https://github.com/ant-design/ant-design/pull/24059)
- 🐞 Fix Menu `@menu-item-font-size` not working. [#24052](https://github.com/ant-design/ant-design/pull/24052)
- 💄 Add `@modal-close-color` less variable. [#24053](https://github.com/ant-design/ant-design/pull/24053)
## 4.2.1
`2020-05-11`
- Form
- 🐞 Fix Form.Item get React warning for `getValueProps`. [#23875](https://github.com/ant-design/ant-design/pull/23875)
- 🐞 Fix Form.Item `help` style issue when `validateStatus` is not `error`. [#23945](https://github.com/ant-design/ant-design/pull/23945)
- Table
- 🐞 Fix selection column width issue when fix header. [#23806](https://github.com/ant-design/ant-design/pull/23806)
- 💄 Adjust selection column css selector priority to enable customize width. [#23914](https://github.com/ant-design/ant-design/pull/23914)
- DatePicker
- 🐞 Fix miss placeholder when `placeholder` is `undefined`. [#23818](https://github.com/ant-design/ant-design/pull/23818)
- 🐞 Fix clear icon color style. [#23811](https://github.com/ant-design/ant-design/pull/23811)
- Switch
- 🐞 Fix loading style for the dark theme. [#23766](https://github.com/ant-design/ant-design/pull/23766) [@vsn4ik](https://github.com/vsn4ik)
- 🐞 Fix `unCheckedChildren` not showing. [#23791](https://github.com/ant-design/ant-design/pull/23791)
- 🐞 Fix Upload error message location to scroll in the float layer. [#24001](https://github.com/ant-design/ant-design/pull/24001) [@mraiguo](https://github.com/mraiguo)
- 💄 Tweak Comment render unnecessary div style when `avatar` is empty. [#23994](https://github.com/ant-design/ant-design/pull/23994) [@Xuhao](https://github.com/Xuhao)
- 🐞 Fix Select `focus` border style in Input.Group. [#23985](https://github.com/ant-design/ant-design/pull/23985)
- 🐞 Fix Steps `subTitle` showing `[object Object]` title. [#23989](https://github.com/ant-design/ant-design/pull/23989)
- 💄 Tweak Select close icon position. [#23963](https://github.com/ant-design/ant-design/pull/23963)
- 🐞 Fix Drawer `width="50%"` hidden problem when no mask. [#23925](https://github.com/ant-design/ant-design/pull/23925)
- 🐞 Fix Textarea with `allowClear` has error height style. [#23835](https://github.com/ant-design/ant-design/pull/23835)
- 💄 Adjust Modal.xxx function async to avoid block React events. [#23826](https://github.com/ant-design/ant-design/pull/23826)
- 🐞 Fix Menu with controlled `openKeys` abnormal behavior when `inlineCollapsed` changed. [#23822](https://github.com/ant-design/ant-design/pull/23822)
- 🐞 Fix Button `loading` animation. [#23783](https://github.com/ant-design/ant-design/pull/23783)
- 🐞 Fix Slider `marks` selected problem when dragging. [#23773](https://github.com/ant-design/ant-design/pull/23773)
- 🛠 Timeline refactors with React Hooks. [#23631](https://github.com/ant-design/ant-design/pull/23631) [@hengkx](https://github.com/hengkx)
- 🌎 Localization
- 🌐 Add Farsi `fa_IR` default locale template localisations. [#23926](https://github.com/ant-design/ant-design/pull/23926) [@NarimanMov](https://github.com/NarimanMov)
- 🌐 Add default `en` default locale template localisations for Form. [#23859](https://github.com/ant-design/ant-design/pull/23859) [@mjfwebb](https://github.com/mjfwebb)
- 📦 Reduce bundle size
- 🗑 Reduce bundle size via removing `react-lifecycles-compat`. [#23969](https://github.com/ant-design/ant-design/pull/23969)
- 🛠 Reduce bundle size via excluding `package.json` from source code. [#23957](https://github.com/ant-design/ant-design/pull/23957)
- 🛠 Upgrade `rc-animate` to 3.x to reduce bundle size. [#23937](https://github.com/ant-design/ant-design/pull/23937)
- RTL
- 🐞 Fix Input clear icon style in RTL. [#23999](https://github.com/ant-design/ant-design/pull/23999)
- 🐞 Fix DatePicker panel style in RTL. [#24028](https://github.com/ant-design/ant-design/pull/24028) [@xrkffgg](https://github.com/xrkffgg)
- 💄 Optimize DatePicker active bar style in `RTL`. [#23981](https://github.com/ant-design/ant-design/pull/23981)
- 🐞 Fix Transfer search padding style in `RTL`. [#23962](https://github.com/ant-design/ant-design/pull/23962)
- 💄 Optimize Layout style of RTL. [#23921](https://github.com/ant-design/ant-design/pull/23921)
- 💄 Optimize Button `loading` style in RT. [#23776](https://github.com/ant-design/ant-design/pull/23776)
- 💄 Optimize Input.Search style in RTL. [#23797](https://github.com/ant-design/ant-design/pull/23797)
- TypeScript
- 🐞 Fix InputNumber `onChange` type. [#23871](https://github.com/ant-design/ant-design/pull/23871) [@jjhbw](https://github.com/jjhbw)
## 4.2.0
`2020-04-29`
- 🆕 List `grid` support all column count like 5. [#23630](https://github.com/ant-design/ant-design/pull/23630)
- 🆕 Divider add `plain` prop which allows a non-heading style divider text. [#23405](https://github.com/ant-design/ant-design/pull/23405)
- 🆕 Typography `ellipsis` support `onEllipsis` event handler. [#23414](https://github.com/ant-design/ant-design/pull/23414)
- 🆕 Space support `align` prop. [#23306](https://github.com/ant-design/ant-design/pull/23306)
- 🆕 Upload support `isImageUrl` to force trade file as image. [#23248](https://github.com/ant-design/ant-design/pull/23248) [@onjuju](https://github.com/onjuju)
- 🆕 Form.Item support `initialValue` and `getValueProps` props. [#22993](https://github.com/ant-design/ant-design/pull/22993)
- ConfigProvider
- 🆕 ConfigProvider support `getTargetContainer` to config Affix `target` props. [#23751](https://github.com/ant-design/ant-design/pull/23751)
- 🆕 ConfigProvider support `input` prop to config Input `autoComplete`. [#23455](https://github.com/ant-design/ant-design/pull/23455)
- 🐞 Fix ConfigProvider `getPopupContainer` not working on DatePicker and Slider. [#23594](https://github.com/ant-design/ant-design/pull/23594) [@hengkx](https://github.com/hengkx)
- Table
- 🆕 Table `summary` support fixed columns. [#23647](https://github.com/ant-design/ant-design/pull/23647)
- 🆕 Table support responsive columns. [#23298](https://github.com/ant-design/ant-design/pull/23298) [@vbudovski](https://github.com/vbudovski)
- 🐞 Fix Table pagination default position in RTL. [#23747](https://github.com/ant-design/ant-design/pull/23747)
- 🐞 Fix Table crash when `pageSize` is `undefined`. [#23724](https://github.com/ant-design/ant-design/pull/23724)
- 🐞 fix Table nested margin when size is `small` or `middle`. [#23602](https://github.com/ant-design/ant-design/pull/23602) [@hengkx](https://github.com/hengkx)
- 🐞 Fix RangePicker `ranges` tag color to primary color. [#23705](https://github.com/ant-design/ant-design/pull/23705)
- 🐞 Fix Transfer with custom empty style issue. [#23694](https://github.com/ant-design/ant-design/pull/23694) [@hengkx](https://github.com/hengkx)
- Input
- 🐞 Fix Password caret position. [#23633](https://github.com/ant-design/ant-design/pull/23633) [@huntdream](https://github.com/huntdream)
- 💄 Adjust Input.Search icon style. [#23406](https://github.com/ant-design/ant-design/pull/23406)
- Button
- 🐞 Fix Button align problem of icon only. [#23671](https://github.com/ant-design/ant-design/pull/23671)
- 🐞 Fix Button of icon only wrong `loading` style. [#23614](https://github.com/ant-design/ant-design/pull/23614)
- 🐞 fix Button cannot be directly called by `react-dnd`. [#23571](https://github.com/ant-design/ant-design/pull/23571) [@hengkx](https://github.com/hengkx)
- Menu
- 🆕 Menu Item and SubMenu support `icon` prop. [#23629](https://github.com/ant-design/ant-design/pull/23629)
- 🐞 Fix Menu duplicated shadow style. [#23664](https://github.com/ant-design/ant-design/pull/23664)
- 🐞 Fix Tag cannot be directly called by `react-dnd`. [#23632](https://github.com/ant-design/ant-design/pull/23632) [@hengkx](https://github.com/hengkx)
- Anchor
- 🐞 Fix Anchor Link with multiple `#` can not jump correctly. [#23595](https://github.com/ant-design/ant-design/pull/23595) [@wuzekang](https://github.com/wuzekang)
- 🐞 Fix Input with `suffix` align problem. [#23606](https://github.com/ant-design/ant-design/pull/23606)
- 💄 Select arrow won't rotate when open. [#23468](https://github.com/ant-design/ant-design/pull/23468)
- 💄 Rate support `direction`. [#23321](https://github.com/ant-design/ant-design/pull/23321)
- 💄 Adjust font-size in compact mode. [#23135](https://github.com/ant-design/ant-design/pull/23135)
- RTL
- 💄 Optimize Result button style in RTL. [#23733](https://github.com/ant-design/ant-design/pull/23733)
- 💄 Add Divider RTL support. [#23734](https://github.com/ant-design/ant-design/pull/23734)
- 💄 Fix Alert style in RTL when no-icon. [#23714](https://github.com/ant-design/ant-design/pull/23714)
- 💄 Optimize Table expand animation and pagination style in RTL. [#23706](https://github.com/ant-design/ant-design/pull/23706)
- 💄 Fix Table filter dropdown position in RTL. [#23695](https://github.com/ant-design/ant-design/pull/23695)
- 💄 Fix Table rowSelect icon style in RTL. [#23690](https://github.com/ant-design/ant-design/pull/23690)
- 💄 Optimize List style in RTL. [#23676](https://github.com/ant-design/ant-design/pull/23676)
- 💄 Add Calendar RTL. [#23394](https://github.com/ant-design/ant-design/pull/23394)
- 💄 Optimize Input.Search style in RTL. [#23424](https://github.com/ant-design/ant-design/pull/23424)
- 💄 Add Notification RTL config. [#23185](https://github.com/ant-design/ant-design/pull/23185)
- TypeScript
- 🐞 Fix PageHeader `tag` definition. [#23712](https://github.com/ant-design/ant-design/pull/23712) [@hengkx](https://github.com/hengkx)
- 🗑 Remove Button deprecated `type="danger"` TypeScript definition and warn it. [#23709](https://github.com/ant-design/ant-design/pull/23709)
- 🐞 Fix Table pagination `position` definition. [#23681](https://github.com/ant-design/ant-design/pull/23681) [@hengkx](https://github.com/hengkx)
## 4.1.5
`2020-04-25`
- 🐞 Fix Button.Group align style. [#23590](https://github.com/ant-design/ant-design/pull/23590)
- 🐞 Fix Select cannot trigger open by clicking arrow icon. [#23448](https://github.com/ant-design/ant-design/pull/23448)
- 🐞 Fix Form fields shake when `@form-item-margin-bottom` is customize and switching the validing info. [#23436](https://github.com/ant-design/ant-design/pull/23436) [@yoyo837](https://github.com/yoyo837)
- 🐞 Fix the first Divider render differently with others. [#23438](https://github.com/ant-design/ant-design/pull/23438)
- 🐞 Fix nest ConfigProvider missing `prefixCls` value. [#23423](https://github.com/ant-design/ant-design/pull/23423)
- 🐞 Fix Carousel tabbed Radio/Checkbox to non-active slide. [#23380](https://github.com/ant-design/ant-design/pull/23380)
- 🐞 Fix Tree with virtual scroll frozen by quick `loadData`. [#23581](https://github.com/ant-design/ant-design/pull/23581)
- 🐞 Fix Steps style in IE11 when direction is vertical. [#23561](https://github.com/ant-design/ant-design/pull/23561) [@AdrianoRuberto](https://github.com/AdrianoRuberto)
- 🐞 Fix Input.Search height affected by `suffix` and `react key` warning. [#23527](https://github.com/ant-design/ant-design/pull/23527)
- 🐞 Fix Menu behavior when hover on submenu gap. [#23511](https://github.com/ant-design/ant-design/pull/23511)
- 🐞 Fix Tree custom icon missing when node is loading data. [#23494](https://github.com/ant-design/ant-design/pull/23494)
- RTL
- 🐞 Fix Alert RTL style when set both `showIcon` and `closable`. [#23526](https://github.com/ant-design/ant-design/pull/23526)
- 🐞 Fix Button RTL style when loading. [#23399](https://github.com/ant-design/ant-design/pull/23399)
- 🐞 Fix Collapse that icon position is incorrect in RTL. [#23445](https://github.com/ant-design/ant-design/pull/23445)
- 🐞 Fix Select group label style in RTL. [#23404](https://github.com/ant-design/ant-design/pull/23404)
- 🐞 Fix Statistic RTL style. [#23397](https://github.com/ant-design/ant-design/pull/23397)
- TypeScript
- 🐞 Fix type definition of `selections` for Table. [#23462](https://github.com/ant-design/ant-design/pull/23462) [@xiaoxintang](https://github.com/xiaoxintang)
## 4.1.4
`2020-04-18`
- 🐞 Fix dark theme and compact theme not working. [#23243](https://github.com/ant-design/ant-design/pull/23243)
- 🐞 Fix Modal.info executed only once when has argument. [#23360](https://github.com/ant-design/ant-design/pull/23360)
- 🐞 Fix Dropdown submenu background missing. [#23296](https://github.com/ant-design/ant-design/pull/23296)
- 💄 Optimize PageHeader responsive behavior. [#23277](https://github.com/ant-design/ant-design/pull/23277)
- 🐞 Fix TreeSelect render blank in compact mode. [#23231](https://github.com/ant-design/ant-design/pull/23231)
- 🛎 Fix Checkbox and Switch console warning typo (validate -> a valid). [#23240](https://github.com/ant-design/ant-design/pull/23240) [@evancharlton](https://github.com/evancharlton)
- 🐞 Fix Table `rowSelection` params issue when `childrenColumnName` configured. [#23205](https://github.com/ant-design/ant-design/pull/23205)
- Input
- 🐞 Fix Input `type="color"` height issue. [#23351](https://github.com/ant-design/ant-design/pull/23351)
- 🐞 Fix Input width shaking when trigger clear icon. [#23259](https://github.com/ant-design/ant-design/pull/23259)
- 🐞 Fix Input.Search `size` not affected by ConfigProvider `componentSize`. [#23331](https://github.com/ant-design/ant-design/pull/23331)
- Select
- 🐞 Fix multiple Select show remove icon when `disabled`. [#23295](https://github.com/ant-design/ant-design/pull/23295)
- 🐞 Fix Select custom `suffixIcon` cannot be access. [#23274](https://github.com/ant-design/ant-design/pull/23274)
- 🐞 Fix Select search input caret missing in Collapse. [#23250](https://github.com/ant-design/ant-design/pull/23250)
- Globalization
- 🇨🇳 Form validation messages support internalization and add zh_CN locale. [#23165](https://github.com/ant-design/ant-design/pull/23165) [@hengkx](https://github.com/hengkx)
- 🌐 Add missing translations in he_IL. [#23302](https://github.com/ant-design/ant-design/pull/23302) [@MishaKav](https://github.com/MishaKav)
- 🌐 Add missing translations in ru_RU. [#23303](https://github.com/ant-design/ant-design/pull/23303) [@MishaKav](https://github.com/MishaKav)
- TypeScript
- 🔷 Form.Item type upgrade. [#22962](https://github.com/ant-design/ant-design/pull/22962) [@fa93hws](https://github.com/fa93hws)
- 🔷 Tree type upgrade. [#23348](https://github.com/ant-design/ant-design/pull/23348) [@yoyo837](https://github.com/yoyo837)
- 🐞 Pass `popupClassName` prop to `rc-picker`. [#23214](https://github.com/ant-design/ant-design/pull/23214) [@tanmoyopenroot](https://github.com/tanmoyopenroot)
- RTL
- 💄 Fix Select RTL style. [#23235](https://github.com/ant-design/ant-design/pull/23235)
- 💄 Fix Menu RTL style. [#23319](https://github.com/ant-design/ant-design/pull/23319)
## 4.1.3
`2020-04-13`
- 💄 Adjust Form.Item `label` height style in vertical layout. [#23192](https://github.com/ant-design/ant-design/pull/23192)
- 🐞 Fix `Variable is undefined` when importing dark or compact theme and provide a `getThemeVariables` methold for getting theme variables easily. [#23171](https://github.com/ant-design/ant-design/pull/23171)
- 🐞 Fix PageHeader style breaks when `title` is too long and improve it's responsive design. [#23133](https://github.com/ant-design/ant-design/pull/23133)
- Tabs
- 🐞 Fix Tabs `@tabs-card-height` less variable not working. [#23168](https://github.com/ant-design/ant-design/pull/23168)
- 🐞 Fix Tabs cannot be displayed in Safari 13. [#23151](https://github.com/ant-design/ant-design/pull/23151) [@imhxc](https://github.com/imhxc)
- Table
- 🐞 Fix Table fixed columns cannot pin in Safari 12. [#23161](https://github.com/ant-design/ant-design/pull/23161)
- 🐞 Fix Table `summary` padding in small size. [#23140](https://github.com/ant-design/ant-design/pull/23140) [@someyoungideas](https://github.com/someyoungideas)
- 🐞 Fix Select align style with different size. [#23160](https://github.com/ant-design/ant-design/pull/23160)
- 🐞 Fix RangePicker under Input.Group style issue. [#23149](https://github.com/ant-design/ant-design/pull/23149)
- 🐞 Fix Pagination missing TypeScript definition of `showTitle`. [#23144](https://github.com/ant-design/ant-design/pull/23144) [@DongchengWang](https://github.com/DongchengWang)
## 4.1.2
`2020-04-10`
- Menu
- 🐞 Fix Menu SubMenu background in dark mode. [#22981](https://github.com/ant-design/ant-design/pull/22981) [@AshoneA](https://github.com/AshoneA)
- 🐞 Fix long SubMenu title being overlayed by arrow icon. [#23028](https://github.com/ant-design/ant-design/pull/23028) [@wwyx778](https://github.com/wwyx778)
@@ -52,6 +235,8 @@ timeline: true
## 4.1.1
`2020-04-05`
- 🐞 Fix Tabs panel focus outline style. [#22752](https://github.com/ant-design/ant-design/pull/22752) [@MrHeer](https://github.com/MrHeer)
- 🐞 Fix Input affix with popup element can not get click focus. [#22887](https://github.com/ant-design/ant-design/pull/22887)
- Table

View File

@@ -15,8 +15,191 @@ timeline: true
---
## 4.2.2
`2020-05-11`
- 🐞 修复安装 antd `npm run version` 报错的问题。[#24059](https://github.com/ant-design/ant-design/pull/24059)
- 🐞 修复 Menu `@menu-item-font-size` 变量失效的问题。[#24052](https://github.com/ant-design/ant-design/pull/24052)
- 💄 新增 `@modal-close-color` less 变量。[#24053](https://github.com/ant-design/ant-design/pull/24053)
## 4.2.1
`2020-05-11`
- Form
- 🐞 修复 Form.Item 使用 `getValueProps` React 会报警的问题。[#23875](https://github.com/ant-design/ant-design/pull/23875)
- 🐞 修复 Form.Item `help``validateStatus` 不是 `error` 时的样式问题。[#23945](https://github.com/ant-design/ant-design/pull/23945)
- Table
- 🐞 修复 Table 固定表头时选择列的宽度问题。[#23806](https://github.com/ant-design/ant-design/pull/23806)
- 💄 调整 Table 选择列 css 选择器优先级以支持自定义宽度。[#23914](https://github.com/ant-design/ant-design/pull/23914)
- DatePicker
- 🐞 修复在 `placeholder``undefined` 时不展示的问题。[#23818](https://github.com/ant-design/ant-design/pull/23818)
- 🐞 修复清除图标的颜色。[#23811](https://github.com/ant-design/ant-design/pull/23811)
- Switch
- 🐞 修复暗色主题下的加载样式。[#23766](https://github.com/ant-design/ant-design/pull/23766) [@vsn4ik](https://github.com/vsn4ik)
- 🐞 修复 `unCheckedChildren` 不显示的问题。[#23791](https://github.com/ant-design/ant-design/pull/23791)
- 🐞 修复 Upload 在浮层中错误提示滚动定位问题。[#24001](https://github.com/ant-design/ant-design/pull/24001) [@mraiguo](https://github.com/mraiguo)
- 💄 调整 Comment 中 `avatar` 为空时不必要的 div 样式[#23994](https://github.com/ant-design/ant-design/pull/23994) [@Xuhao](https://github.com/Xuhao)
- 🐞 修复 Input.Group 中 Select 选项 `focus` 边框样式[#23985](https://github.com/ant-design/ant-design/pull/23985)
- 🐞 修复 Steps `subTitle` 上会显示 `[object Object]` 提示的问题。[#23989](https://github.com/ant-design/ant-design/pull/23989)
- 💄 微调 Select 移除图标的位置。[#23963](https://github.com/ant-design/ant-design/pull/23963)
- 🐞 修复无遮罩的 Drawer 设置 `50%` 宽度时不显示的问题。[#23925](https://github.com/ant-design/ant-design/pull/23925)
- 🐞 修复 Textarea 开启 `allowClear` 时高度错误的问题。[#23835](https://github.com/ant-design/ant-design/pull/23835)
- 💄 调整 Modal.xxx 方法为异步以防止其影响 React 事件响应。[#23826](https://github.com/ant-design/ant-design/pull/23826)
- 🐞 修复受控模式 Menu `inlineCollapsed` 折叠时的表现。[#23822](https://github.com/ant-design/ant-design/pull/23822)
- 🐞 修复 Button `loading` 动画切换不平滑的问题。[#23783](https://github.com/ant-design/ant-design/pull/23783)
- 🐞 修复 Slider 拖拽中选中 `marks` 文本的问题。[#23773](https://github.com/ant-design/ant-design/pull/23773)
- 🛠 Timeline 使用 React Hooks 重构。[#23631](https://github.com/ant-design/ant-design/pull/23631) [@hengkx](https://github.com/hengkx)
- 🌎 国际化
- 🌐 增加波斯语 `fa_IR` 国际化默认提示模板。[#23926](https://github.com/ant-design/ant-design/pull/23926) [@NarimanMov](https://github.com/NarimanMov)
- 🌐 增加 Form `en` 国际化默认提示模板[#23859](https://github.com/ant-design/ant-design/pull/23859) [@mjfwebb](https://github.com/mjfwebb)
- 📦 包体积优化
- 🗑 移除 `react-lifecycles-compat` 依赖以优化包体积。[#23969](https://github.com/ant-design/ant-design/pull/23969)
- 🛠 源码中不再引用 `package.json` 从而优化了一点包体积。[#23957](https://github.com/ant-design/ant-design/pull/23957)
- 🛠 更新 `rc-animate` 到 3.x 以优化包体积。[#23937](https://github.com/ant-design/ant-design/pull/23937)
- RTL
- 🐞 修复 Input 在 RTL 模式下清空按钮的样式。[#23999](https://github.com/ant-design/ant-design/pull/23999)
- 🐞 修复 DatePicker 下拉框在 RTL 模式下样式。[#24028](https://github.com/ant-design/ant-design/pull/24028) [@xrkffgg](https://github.com/xrkffgg)
- 💄 优化 DatePick 在 `RTL` 模式下的激活条样式。[#23981](https://github.com/ant-design/ant-design/pull/23981)
- 🐞 修复 Transfer 查询框在 `RTL` 模式下的边距样式。[#23962](https://github.com/ant-design/ant-design/pull/23962)
- 💄 优化 Layout RTL 样式。[#23921](https://github.com/ant-design/ant-design/pull/23921)
- 💄 优化 Button `loading` 状态在 RTL 下样式。[#23776](https://github.com/ant-design/ant-design/pull/23776)
- 💄 优化 Input.Search RTL 样式。[#23797](https://github.com/ant-design/ant-design/pull/23797)
- TypeScript
- 🐞 修复 InputNumber `onChange` 类型。[#23871](https://github.com/ant-design/ant-design/pull/23871) [@jjhbw](https://github.com/jjhbw)
## 4.2.0
`2020-04-29`
- 🆕 List `grid` 支持所有分栏数字,比如分为 5 栏。[#23630](https://github.com/ant-design/ant-design/pull/23630)
- 🆕 Divider 新增 `plain` 属性,可用于设置一个非标题样式的分割文字。[#23405](https://github.com/ant-design/ant-design/pull/23405)
- 🆕 Typography `ellipsis` 支持 `onEllipsis` 事件。[#23414](https://github.com/ant-design/ant-design/pull/23414)
- 🆕 Space 支持 `align` 属性。[#23306](https://github.com/ant-design/ant-design/pull/23306)
- 🆕 Upload 添加 `isImageUrl` 属性以强制将文件作为图标文件。[#23248](https://github.com/ant-design/ant-design/pull/23248) [@onjuju](https://github.com/onjuju)
- 🆕 Form.Item 支持 `initialValue``getValueProps` 属性。[#22993](https://github.com/ant-design/ant-design/pull/22993)
- ConfigProvider
- 🆕 ConfigProvider 支持 `getTargetContainer` 以配置 Affix `target` 属性。[#23751](https://github.com/ant-design/ant-design/pull/23751)
- 🆕 ConfigProvider 添加 `input` 属性以支持全局化配置 Input `autoComplete` 的默认值。[#23455](https://github.com/ant-design/ant-design/pull/23455)
- 🐞 修复 ConfigProvider `getPopupContainer` 对 DatePicker 和 Slider 不生效的问题。[#23594](https://github.com/ant-design/ant-design/pull/23594) [@hengkx](https://github.com/hengkx)
- Table
- 🆕 Table `summary` 支持固定列。[#23647](https://github.com/ant-design/ant-design/pull/23647)
- 🆕 Table 支持响应式展现列。[#23298](https://github.com/ant-design/ant-design/pull/23298) [@vbudovski](https://github.com/vbudovski)
- 🐞 修复 Table pagination 在 RTL 下默认位置。[#23747](https://github.com/ant-design/ant-design/pull/23747)
- 🐞 修复 Table 在 `pageSize``undefined` 时崩溃的问题。[#23724](https://github.com/ant-design/ant-design/pull/23724)
- 🐞 修复 Table 大小为 `small``middle` 时嵌套表格错位的问题。[#23602](https://github.com/ant-design/ant-design/pull/23602) [@hengkx](https://github.com/hengkx)
- 🐞 修正 RangePicker 范围标签的颜色为主色。[#23705](https://github.com/ant-design/ant-design/pull/23705)
- 🐞 修复 Transfer 为空自定义图片样式问题。[#23694](https://github.com/ant-design/ant-design/pull/23694) [@hengkx](https://github.com/hengkx)
- Input
- 🐞 修复 Password 组件输入光标位置。[#23633](https://github.com/ant-design/ant-design/pull/23633) [@huntdream](https://github.com/huntdream)
- 💄 调整 Input.Search 的搜索图标样式。[#23406](https://github.com/ant-design/ant-design/pull/23406)
- Button
- 🐞 修复 Button 图标类型按钮的对齐问题。[#23671](https://github.com/ant-design/ant-design/pull/23671)
- 🐞 修复 Button 图标按钮 `loading` 样式错误的问题。[#23614](https://github.com/ant-design/ant-design/pull/23614)
- 🐞 解决 Button 无法直接被 `react-dnd` 调用的问题。[#23571](https://github.com/ant-design/ant-design/pull/23571) [@hengkx](https://github.com/hengkx)
- Menu
- 🆕 Menu Item 和 SubMenu 新增 `icon` 属性。[#23629](https://github.com/ant-design/ant-design/pull/23629)
- 🐞 修复 Menu 菜单重复阴影的问题。[#23664](https://github.com/ant-design/ant-design/pull/23664)
- 🐞 解决 Tag 无法直接被 `react-dnd` 调用的问题。[#23632](https://github.com/ant-design/ant-design/pull/23632) [@hengkx](https://github.com/hengkx)
- Anchor
- 🐞 修复 Anchor Link 包含多个 `#` 时无法跳转的问题。[#23595](https://github.com/ant-design/ant-design/pull/23595) [@wuzekang](https://github.com/wuzekang)
- 🐞 修复 Input 带 `suffix` 时的元素对齐问题。[#23606](https://github.com/ant-design/ant-design/pull/23606)
- 💄 Select 箭头打开时不再翻转。[#23468](https://github.com/ant-design/ant-design/pull/23468)
- 💄 新增 Rate 的 `direction` 支持优化。[#23321](https://github.com/ant-design/ant-design/pull/23321)
- 💄 调整紧凑模式下默认的字体大小。[#23135](https://github.com/ant-design/ant-design/pull/23135)
- RTL
- 💄 优化 Result RTL 下按钮样式。[#23733](https://github.com/ant-design/ant-design/pull/23733)
- 💄 新增 Divider RTL 支持。[#23734](https://github.com/ant-design/ant-design/pull/23734)
- 💄 修复 Alert 在 RTL 下无 icon 的间隔问题。[#23714](https://github.com/ant-design/ant-design/pull/23714)
- 💄 优化 Table RTL 模式下扩展按钮动画与分页样式问题。[#23706](https://github.com/ant-design/ant-design/pull/23706)
- 💄 修复 Table 筛选下拉框在 RTL 下的位置。[#23695](https://github.com/ant-design/ant-design/pull/23695)
- 💄 修复 Table 勾选框图标 RTL 样式。[#23690](https://github.com/ant-design/ant-design/pull/23690)
- 💄 优化 List RTL 样式。[#23676](https://github.com/ant-design/ant-design/pull/23676)
- 💄 新增 Calendar RTL 支持。[#23394](https://github.com/ant-design/ant-design/pull/23394)
- 💄 优化 Input.Search RTL 样式。[#23424](https://github.com/ant-design/ant-design/pull/23424)
- 💄 增加 Notification RTL 设置。[#23185](https://github.com/ant-design/ant-design/pull/23185)
- TypeScript
- 🐞 修复 PageHeader `tag` 属性定义错误。[#23712](https://github.com/ant-design/ant-design/pull/23712) [@hengkx](https://github.com/hengkx)
- 🗑 移除已废弃的 Button `type="danger"` TypeScript 定义并增加警告信息。[#23709](https://github.com/ant-design/ant-design/pull/23709)
- 🐞 修复 Table pagination `position` Typescript 定义错误。[#23681](https://github.com/ant-design/ant-design/pull/23681) [@hengkx](https://github.com/hengkx)
## 4.1.5
`2020-04-25`
- 🐞 修复 Button.Group 中按钮没有对齐的问题。[#23590](https://github.com/ant-design/ant-design/pull/23590)
- 🐞 修复 Select 箭头图标点击无法触发下拉的问题。[#23448](https://github.com/ant-design/ant-design/pull/23448)
- 🐞 修复 Form 自定义 `@form-item-margin-bottom` 变量时表单校验抖动的问题。[#23436](https://github.com/ant-design/ant-design/pull/23436) [@yoyo837](https://github.com/yoyo837)
- 🐞 修复第一个 Divider 渲染时样式不一致的问题。[#23438](https://github.com/ant-design/ant-design/pull/23438)
- 🐞 修复嵌套 ConfigProvider 会丢失 `prefixCls` 值的问题。[#23423](https://github.com/ant-design/ant-design/pull/23423)
- 🐞 修复 Carousel 键盘切换到非活跃 slide 上的 Radio/Checkbox 的问题。[#23380](https://github.com/ant-design/ant-design/pull/23380)
- 🐞 修复 Tree 使用虚拟滚动时会因为 `loadData` 更新过快而锁死的问题。[#23581](https://github.com/ant-design/ant-design/pull/23581)
- 🐞 修复 Steps 组件竖直展示时在 IE11 下样式错误的问题。[#23561](https://github.com/ant-design/ant-design/pull/23561) [@AdrianoRuberto](https://github.com/AdrianoRuberto)
- 🐞 修复 Input.Search 高度被 `suffix` 撑高的问题和报 `react key` 重复警告的问题。[#23527](https://github.com/ant-design/ant-design/pull/23527)
- 🐞 修复 Menu 鼠标移到缝隙处子菜单会消失的问题。[#23511](https://github.com/ant-design/ant-design/pull/23511)
- 🐞 修复 Tree 自定义图标在加载状态下消失的问题。[#23494](https://github.com/ant-design/ant-design/pull/23494)
- RTL
- 🐞 修复 Alert 在 `showIcon``closable` 都存在时的 RTL 样式问题。[#23526](https://github.com/ant-design/ant-design/pull/23526)
- 🐞 修复 Button 在 RTL 下 loading 样式不正确的问题。[#23399](https://github.com/ant-design/ant-design/pull/23399)
- 🐞 修复 Collapse 在 RTL 下切换图标位置不正确的问题。[#23445](https://github.com/ant-design/ant-design/pull/23445)
- 🐞 修复 Select 分组名称的 RTL 样式问题。[#23404](https://github.com/ant-design/ant-design/pull/23404)
- 🐞 修复 Statistic 的 RTL 样式不正确的问题。[#23397](https://github.com/ant-design/ant-design/pull/23397)
- TypeScript
- 🐞 修复 Table 的 `selections` 类型定义。[#23462](https://github.com/ant-design/ant-design/pull/23462) [@xiaoxintang](https://github.com/xiaoxintang)
## 4.1.4
`2020-04-18`
- 🐞 修复暗黑主题和紧凑主题不生效的问题。[#23243](https://github.com/ant-design/ant-design/pull/23243)
- 🐞 修复 Modal.info 等方法的 `onOk` 函数有参数时只触发一次的问题。[#23360](https://github.com/ant-design/ant-design/pull/23360)
- 🐞 修复 Dropdown 弹出菜单背景样式问题。[#23296](https://github.com/ant-design/ant-design/pull/23296)
- 💄 优化 PageHeader 的响应式表现。[#23277](https://github.com/ant-design/ant-design/pull/23277)
- 🐞 修复紧凑模式下树选择出现空白。[#23231](https://github.com/ant-design/ant-design/pull/23231)
- 🛎 修改 Checkbox 和 Switch 中控制台输出的错别字 (validate -> a valid)。[#23240](https://github.com/ant-design/ant-design/pull/23240) [@evancharlton](https://github.com/evancharlton)
- 🐞 修复 Table `rowSelection` 在设置 `childrenColumnName` 时事件参数不正确的问题。[#23205](https://github.com/ant-design/ant-design/pull/23205)
- Input
- 🐞 修复 Input `type="color"` 的高度问题。[#23351](https://github.com/ant-design/ant-design/pull/23351)
- 🐞 修复 Input 设置 `allowClear` 内联展示时,触发清除按钮样式抖动的问题。[#23259](https://github.com/ant-design/ant-design/pull/23259)
- 🐞 修复 Input.Search 全局设置 `size` 不生效问题。[#23331](https://github.com/ant-design/ant-design/pull/23331)
- Select
- 🐞 修复 Select 多选时设置 `disabled` 选项仍然会展示移除按钮的问题。[#23295](https://github.com/ant-design/ant-design/pull/23295)
- 🐞 修复 Select 自定义 `suffixIcon` 无法交互的问题。[#23274](https://github.com/ant-design/ant-design/pull/23274)
- 🐞 修复 Select 输入光标在 Collapse 内不显示的问题。[#23250](https://github.com/ant-design/ant-design/pull/23250)
- 国际化
- 🌐 Form 校验信息支持国际化并增加中文文案。[#23165](https://github.com/ant-design/ant-design/pull/23165) [@hengkx](https://github.com/hengkx)
- 🌐 完善希伯来语(以色列) 国际化。[#23302](https://github.com/ant-design/ant-design/pull/23302) [@MishaKav](https://github.com/MishaKav)
- 🌐 完善俄语国际化。[#23303](https://github.com/ant-design/ant-design/pull/23303) [@MishaKav](https://github.com/MishaKav)
- TypeScript
- 🔷 更新 Tree 的类型定义。[#23348](https://github.com/ant-design/ant-design/pull/23348) [@yoyo837](https://github.com/yoyo837)
- 🔷 更新 Form Item 的类型定义。[#22962](https://github.com/ant-design/ant-design/pull/22962) [@fa93hws](https://github.com/fa93hws)
- 🐞 修复 Slider 组件 `value``defaultValue` 文档与 TypeScript 定义不一致的问题。[#23252](https://github.com/ant-design/ant-design/pull/23252) [@DongchengWang](https://github.com/DongchengWang)
- RTL
- 🐞 修复 Menu RTL 样式。[#23319](https://github.com/ant-design/ant-design/pull/23319)
- 💄 修复 Select 的 RTL 样式。[#23235](https://github.com/ant-design/ant-design/pull/23235)
## 4.1.3
`2020-04-13`
- 💄 调整 Form.Item `label` 在垂直布局下的高度样式。[#23192](https://github.com/ant-design/ant-design/pull/23192)
- 🐞 修复引用暗黑或紧凑主题时提示 `Variable is undefined` 的问题,并提供 `getThemeVariables` 方便获取对应主题变量。[#23171](https://github.com/ant-design/ant-design/pull/23171)
- 🐞 修复 PageHeader `title` 超长时布局被破坏的问题并优化响应式表现。[#23133](https://github.com/ant-design/ant-design/pull/23133)
- Tabs
- 🐞 修复 Tabs `@tabs-card-height` less 变量无效的问题。[#23168](https://github.com/ant-design/ant-design/pull/23168)
- 🐞 修复 Tabs 在 Safair 浏览器下无法显示的问题。[#23151](https://github.com/ant-design/ant-design/pull/23151) [@imhxc](https://github.com/imhxc)
- Table
- 🐞 修复 Table 固定列在 Safari 12 中不能固定的问题。[#23161](https://github.com/ant-design/ant-design/pull/23161)
- 🐞 修复 Table `summary` 在小尺寸下的内边距样式。[#23140](https://github.com/ant-design/ant-design/pull/23140) [@someyoungideas](https://github.com/someyoungideas)
- 🐞 修复 Select 不同尺寸下的对齐样式问题。[#23160](https://github.com/ant-design/ant-design/pull/23160)
- 🐞 修复 RangePicker 在 Input.Group 内的样式问题。[#23149](https://github.com/ant-design/ant-design/pull/23149)
- 🐞 修复 Pagination 缺少 `showTitle` TypeScript 定义的问题。[#23144](https://github.com/ant-design/ant-design/pull/23144) [@DongchengWang](https://github.com/DongchengWang)
## 4.1.2
`2020-04-10`
- Menu
- 🐞 修复暗色 Menu 弹出菜单背景色为白色的问题。[#22981](https://github.com/ant-design/ant-design/pull/22981) [@AshoneA](https://github.com/AshoneA)
- 🐞 修复 SubMenu 标题过长而导致被箭头图标部分覆盖的问题。[#23028](https://github.com/ant-design/ant-design/pull/23028) [@wwyx778](https://github.com/wwyx778)
@@ -52,6 +235,8 @@ timeline: true
## 4.1.1
`2020-04-05`
- 🐞 移除 Tabs 的内容区域的 focus 蓝色轮廓线。[#22752](https://github.com/ant-design/ant-design/pull/22752) [@MrHeer](https://github.com/MrHeer)
- 🐞 修复 Input 前后缀添加弹出元素不能点击获得焦点的问题。[#22887](https://github.com/ant-design/ant-design/pull/22887)
- Table

View File

@@ -34,7 +34,7 @@ This Code of Conduct applies both within project spaces and in public spaces whe
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at xingmin.zhu@alipay.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at [xingmin.zhu@alipay.com.](mailto:xingmin.zhu@alipay.com.) The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.

View File

@@ -33,7 +33,7 @@ Uma solução empresarial de design e biblioteca UI para React.
## 🖥 Suporte aos ambientes
- Navegadores modernos e Internet Explorer 11+ (com [polyfills](https://ant.design/docs/react/getting-started#Compatibility))
- Navegadores modernos e Internet Explorer 11 (com [polyfills](https://ant.design/docs/react/getting-started#Compatibility))
- Renderização no lado do servidor (server-side)
- [Electron](https://www.electronjs.org/)

View File

@@ -33,7 +33,7 @@
## 🖥 支持环境
- 现代浏览器和 IE11 及以上
- 现代浏览器和 IE11(需要 [polyfills](https://ant.design/docs/react/getting-started-cn#兼容性)
- 支持服务端渲染。
- [Electron](https://www.electronjs.org/)

View File

@@ -14,7 +14,7 @@ An enterprise-class UI design language and React UI library.
[![david deps][david-image]][david-url] [![david devDeps][david-dev-image]][david-dev-url] [![Total alerts][lgtm-image]][lgtm-url] [![FOSSA Status][fossa-image]][fossa-url] [![Issues need help][help-wanted-image]][help-wanted-url]
[![Follow Twitter][twitter-image]][twitter-url] [![Gitter][gitter-english-image]][gitter-english-url] [![Gitter][gitter-chinese-image]][gitter-chinese-url]
[![Follow Twitter][twitter-image]][twitter-url] [![Gitter][gitter-english-image]][gitter-english-url] [![Gitter][gitter-chinese-image]][gitter-chinese-url] [![[SemVer stability]][semver-stability-image]][semver-stability-url]
[npm-image]: http://img.shields.io/npm/v/antd.svg?style=flat-square
[npm-url]: http://npmjs.org/package/antd
@@ -24,26 +24,26 @@ An enterprise-class UI design language and React UI library.
[github-action-url]: https://github.com/ant-design/ant-design/actions?query=workflow%3Atest
[codecov-image]: https://img.shields.io/codecov/c/github/ant-design/ant-design/master.svg?style=flat-square
[codecov-url]: https://codecov.io/gh/ant-design/ant-design/branch/master
[david-image]: https://david-dm.org/ant-design/ant-design/status.svg?style=flat-square
[david-image]: https://img.shields.io/david/ant-design/ant-design?style=flat-square
[david-dev-url]: https://david-dm.org/ant-design/ant-design?type=dev
[david-dev-image]: https://david-dm.org/ant-design/ant-design/dev-status.svg?style=flat-square
[david-dev-image]: https://img.shields.io/david/dev/ant-design/ant-design?style=flat-square
[david-url]: https://david-dm.org/ant-design/ant-design
[download-image]: https://img.shields.io/npm/dm/antd.svg?style=flat-square
[download-url]: https://npmjs.org/package/antd
[lgtm-image]: https://flat.badgen.net/lgtm/alerts/g/ant-design/ant-design
[lgtm-url]: https://lgtm.com/projects/g/ant-design/ant-design/alerts/
[lgtm-image]: https://flat.badgen.net/lgtm/alerts/g/ant-design/ant-design
[lgtm-url]: https://lgtm.com/projects/g/ant-design/ant-design/alerts/
[fossa-image]: https://app.fossa.io/api/projects/git%2Bgithub.com%2Fant-design%2Fant-design.svg?type=shield
[fossa-url]: https://app.fossa.io/projects/git%2Bgithub.com%2Fant-design%2Fant-design?ref=badge_shield
[help-wanted-image]: https://flat.badgen.net/github/label-issues/ant-design/ant-design/help%20wanted/open
[help-wanted-url]: https://github.com/ant-design/ant-design/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22
[twitter-image]: https://img.shields.io/twitter/follow/AntDesignUI.svg?label=Ant%20Design&style=social
[twitter-url]: https://twitter.com/AntDesignUI
[gitter-english-image]: https://img.shields.io/gitter/room/ant-design/ant-design-english.svg?style=flat-square&logoWidth=20&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4NCjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgd2lkdGg9IjEyMzUiIGhlaWdodD0iNjUwIiB2aWV3Qm94PSIwIDAgNzQxMCAzOTAwIj4NCjxyZWN0IHdpZHRoPSI3NDEwIiBoZWlnaHQ9IjM5MDAiIGZpbGw9IiNiMjIyMzQiLz4NCjxwYXRoIGQ9Ik0wLDQ1MEg3NDEwbTAsNjAwSDBtMCw2MDBINzQxMG0wLDYwMEgwbTAsNjAwSDc0MTBtMCw2MDBIMCIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjMwMCIvPg0KPHJlY3Qgd2lkdGg9IjI5NjQiIGhlaWdodD0iMjEwMCIgZmlsbD0iIzNjM2I2ZSIvPg0KPGcgZmlsbD0iI2ZmZiI%2BDQo8ZyBpZD0iczE4Ij4NCjxnIGlkPSJzOSI%2BDQo8ZyBpZD0iczUiPg0KPGcgaWQ9InM0Ij4NCjxwYXRoIGlkPSJzIiBkPSJNMjQ3LDkwIDMxNy41MzQyMzAsMzA3LjA4MjAzOSAxMzIuODczMjE4LDE3Mi45MTc5NjFIMzYxLjEyNjc4MkwxNzYuNDY1NzcwLDMwNy4wODIwMzl6Ii8%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzIiB5PSI0MjAiLz4NCjx1c2UgeGxpbms6aHJlZj0iI3MiIHk9Ijg0MCIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgeT0iMTI2MCIvPg0KPC9nPg0KPHVzZSB4bGluazpocmVmPSIjcyIgeT0iMTY4MCIvPg0KPC9nPg0KPHVzZSB4bGluazpocmVmPSIjczQiIHg9IjI0NyIgeT0iMjEwIi8%2BDQo8L2c%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzOSIgeD0iNDk0Ii8%2BDQo8L2c%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzMTgiIHg9Ijk4OCIvPg0KPHVzZSB4bGluazpocmVmPSIjczkiIHg9IjE5NzYiLz4NCjx1c2UgeGxpbms6aHJlZj0iI3M1IiB4PSIyNDcwIi8%2BDQo8L2c%2BDQo8L3N2Zz4%3D
[gitter-english-image]: https://img.shields.io/gitter/room/ant-design/ant-design-english.svg?style=flat-square&logoWidth=18&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4NCjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgd2lkdGg9IjEyMzUiIGhlaWdodD0iNjUwIiB2aWV3Qm94PSIwIDAgNzQxMCAzOTAwIj4NCjxyZWN0IHdpZHRoPSI3NDEwIiBoZWlnaHQ9IjM5MDAiIGZpbGw9IiNiMjIyMzQiLz4NCjxwYXRoIGQ9Ik0wLDQ1MEg3NDEwbTAsNjAwSDBtMCw2MDBINzQxMG0wLDYwMEgwbTAsNjAwSDc0MTBtMCw2MDBIMCIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjMwMCIvPg0KPHJlY3Qgd2lkdGg9IjI5NjQiIGhlaWdodD0iMjEwMCIgZmlsbD0iIzNjM2I2ZSIvPg0KPGcgZmlsbD0iI2ZmZiI%2BDQo8ZyBpZD0iczE4Ij4NCjxnIGlkPSJzOSI%2BDQo8ZyBpZD0iczUiPg0KPGcgaWQ9InM0Ij4NCjxwYXRoIGlkPSJzIiBkPSJNMjQ3LDkwIDMxNy41MzQyMzAsMzA3LjA4MjAzOSAxMzIuODczMjE4LDE3Mi45MTc5NjFIMzYxLjEyNjc4MkwxNzYuNDY1NzcwLDMwNy4wODIwMzl6Ii8%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzIiB5PSI0MjAiLz4NCjx1c2UgeGxpbms6aHJlZj0iI3MiIHk9Ijg0MCIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgeT0iMTI2MCIvPg0KPC9nPg0KPHVzZSB4bGluazpocmVmPSIjcyIgeT0iMTY4MCIvPg0KPC9nPg0KPHVzZSB4bGluazpocmVmPSIjczQiIHg9IjI0NyIgeT0iMjEwIi8%2BDQo8L2c%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzOSIgeD0iNDk0Ii8%2BDQo8L2c%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzMTgiIHg9Ijk4OCIvPg0KPHVzZSB4bGluazpocmVmPSIjczkiIHg9IjE5NzYiLz4NCjx1c2UgeGxpbms6aHJlZj0iI3M1IiB4PSIyNDcwIi8%2BDQo8L2c%2BDQo8L3N2Zz4%3D
[gitter-english-url]: https://gitter.im/ant-design/ant-design-english?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge
[gitter-chinese-image]: https://img.shields.io/gitter/room/ant-design/ant-design.svg?style=flat-square&logoWidth=20&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4NCjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgd2lkdGg9IjkwMCIgaGVpZ2h0PSI2MDAiIHZpZXdCb3g9IjAgMCAzMCAyMCI%2BDQo8ZGVmcz4NCjxwYXRoIGlkPSJzIiBkPSJNMCwtMSAwLjU4Nzc4NSwwLjgwOTAxNyAtMC45NTEwNTcsLTAuMzA5MDE3SDAuOTUxMDU3TC0wLjU4Nzc4NSwwLjgwOTAxN3oiIGZpbGw9IiNmZmRlMDAiLz4NCjwvZGVmcz4NCjxyZWN0IHdpZHRoPSIzMCIgaGVpZ2h0PSIyMCIgZmlsbD0iI2RlMjkxMCIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNSw1KSBzY2FsZSgzKSIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTAsMikgcm90YXRlKDIzLjAzNjI0MykiLz4NCjx1c2UgeGxpbms6aHJlZj0iI3MiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDEyLDQpIHJvdGF0ZSg0NS44Njk4OTgpIi8%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMiw3KSByb3RhdGUoNjkuOTQ1Mzk2KSIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTAsOSkgcm90YXRlKDIwLjY1OTgwOCkiLz4NCjwvc3ZnPg%3D%3D
[gitter-chinese-image]: https://img.shields.io/gitter/room/ant-design/ant-design.svg?style=flat-square&logoWidth=18&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4NCjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgd2lkdGg9IjkwMCIgaGVpZ2h0PSI2MDAiIHZpZXdCb3g9IjAgMCAzMCAyMCI%2BDQo8ZGVmcz4NCjxwYXRoIGlkPSJzIiBkPSJNMCwtMSAwLjU4Nzc4NSwwLjgwOTAxNyAtMC45NTEwNTcsLTAuMzA5MDE3SDAuOTUxMDU3TC0wLjU4Nzc4NSwwLjgwOTAxN3oiIGZpbGw9IiNmZmRlMDAiLz4NCjwvZGVmcz4NCjxyZWN0IHdpZHRoPSIzMCIgaGVpZ2h0PSIyMCIgZmlsbD0iI2RlMjkxMCIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNSw1KSBzY2FsZSgzKSIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTAsMikgcm90YXRlKDIzLjAzNjI0MykiLz4NCjx1c2UgeGxpbms6aHJlZj0iI3MiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDEyLDQpIHJvdGF0ZSg0NS44Njk4OTgpIi8%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMiw3KSByb3RhdGUoNjkuOTQ1Mzk2KSIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTAsOSkgcm90YXRlKDIwLjY1OTgwOCkiLz4NCjwvc3ZnPg%3D%3D
[gitter-chinese-url]: https://gitter.im/ant-design/ant-design?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
[semver-stability-url]: https://dependabot.com/compatibility-score.html/?dependency-name=antd&package-manager=npm_and_yarn&new-version=latest
[semver-stability-image]: https://api.dependabot.com/badges/compatibility_score?dependency-name=antd&package-manager=npm_and_yarn&target-version=latest&version-scheme=semver
</div>
@@ -62,7 +62,7 @@ English | [Português](./README-pt_BR.md) | [简体中文](./README-zh_CN.md)
## 🖥 Environment Support
- Modern browsers and Internet Explorer 11+ (with [polyfills](https://ant.design/docs/react/getting-started#Compatibility))
- Modern browsers and Internet Explorer 11 (with [polyfills](https://ant.design/docs/react/getting-started#Compatibility))
- Server-side Rendering
- [Electron](https://www.electronjs.org/)
@@ -112,7 +112,7 @@ See [i18n](http://ant.design/docs/react/i18n).
## 🔗 Links
- [Home page](http://ant.design/)
- [Components](http://ant.design/docs/react/introduce)
- [Components](https://ant.design/components/button/)
- [Ant Design Pro](http://pro.ant.design/)
- [Change Log](CHANGELOG.en-US.md)
- [rc-components](http://react-component.github.io/)

View File

@@ -1,58 +0,0 @@
const __NULL__ = { notExist: true };
export function spyElementPrototypes(Element, properties) {
const propNames = Object.keys(properties);
const originDescriptors = {};
propNames.forEach(propName => {
const originDescriptor = Object.getOwnPropertyDescriptor(Element.prototype, propName);
originDescriptors[propName] = originDescriptor || __NULL__;
const spyProp = properties[propName];
if (typeof spyProp === 'function') {
// If is a function
Element.prototype[propName] = function spyFunc(...args) {
return spyProp.call(this, originDescriptor, ...args);
};
} else {
// Otherwise tread as a property
Object.defineProperty(Element.prototype, propName, {
...spyProp,
set(value) {
if (spyProp.set) {
return spyProp.set.call(this, originDescriptor, value);
}
return originDescriptor.set(value);
},
get() {
if (spyProp.get) {
return spyProp.get.call(this, originDescriptor);
}
return originDescriptor.get();
},
});
}
});
return {
mockRestore() {
propNames.forEach(propName => {
const originDescriptor = originDescriptors[propName];
if (originDescriptor === __NULL__) {
delete Element.prototype[propName];
} else if (typeof originDescriptor === 'function') {
Element.prototype[propName] = originDescriptor;
} else {
Object.defineProperty(Element.prototype, propName, originDescriptor);
}
});
},
};
}
export function spyElementPrototype(Element, propName, property) {
return spyElementPrototypes(Element, {
[propName]: property,
});
}

View File

@@ -1,4 +1,4 @@
import { tuple } from './type';
import { ElementOf, tuple } from './type';
export const PresetStatusColorTypes = tuple('success', 'processing', 'error', 'default', 'warning');
// eslint-disable-next-line import/prefer-default-export
@@ -18,5 +18,5 @@ export const PresetColorTypes = tuple(
'lime',
);
export type PresetColorType = typeof PresetColorTypes[number];
export type PresetStatusColorType = typeof PresetStatusColorTypes[number];
export type PresetColorType = ElementOf<typeof PresetColorTypes>;
export type PresetStatusColorType = ElementOf<typeof PresetStatusColorTypes>;

View File

@@ -1,4 +1,4 @@
import React from 'react';
import * as React from 'react';
export type RenderFunction = () => React.ReactNode;

View File

@@ -9,6 +9,7 @@ interface Motion {
motionEnter?: boolean;
motionLeave?: boolean;
motionLeaveImmediately?: boolean; // Trigger leave motion immediately
motionDeadline?: number;
removeOnLeave?: boolean;
leavedClassName?: string;
onAppearStart?: MotionFunc;
@@ -35,6 +36,7 @@ const collapseMotion: Motion = {
onEnterActive: getRealHeight,
onLeaveStart: getCurrentHeight,
onLeaveActive: getCollapsedHeight,
motionDeadline: 500,
};
export default collapseMotion;

View File

@@ -2,7 +2,7 @@
* Deprecated. We should replace the animation with pure react motion instead of modify style directly.
* If you are creating new component with animation, please use `./motion`.
*/
import cssAnimation from 'css-animation';
import cssAnimation from '@ant-design/css-animation';
import raf from 'raf';
function animate(node: HTMLElement, show: boolean, done: () => void) {

View File

@@ -1,4 +1,4 @@
import React from 'react';
import * as React from 'react';
export function fillRef<T>(ref: React.Ref<T>, node: T) {
if (typeof ref === 'function') {

View File

@@ -1,6 +1,6 @@
import * as React from 'react';
import { findDOMNode } from 'react-dom';
import TransitionEvents from 'css-animation/lib/Event';
import TransitionEvents from '@ant-design/css-animation/lib/Event';
import raf from './raf';
import { ConfigConsumer, ConfigConsumerProps, CSPConfig } from '../config-provider';

View File

@@ -1,201 +0,0 @@
import React from 'react';
import { mount } from 'enzyme';
import Affix from '..';
import { getObserverEntities } from '../utils';
import Button from '../../button';
import { spyElementPrototype } from '../../__tests__/util/domHook';
import rtlTest from '../../../tests/shared/rtlTest';
import { sleep } from '../../../tests/utils';
const events = {};
class AffixMounter extends React.Component {
componentDidMount() {
this.container.addEventListener = jest.fn().mockImplementation((event, cb) => {
events[event] = cb;
});
}
getTarget = () => this.container;
render() {
return (
<div
ref={node => {
this.container = node;
}}
className="container"
>
<Affix
className="fixed"
target={this.getTarget}
ref={ele => {
this.affix = ele;
}}
{...this.props}
>
<Button type="primary">Fixed at the top of container</Button>
</Affix>
</div>
);
}
}
describe('Affix Render', () => {
rtlTest(Affix);
let wrapper;
let domMock;
const classRect = {
container: {
top: 0,
bottom: 100,
},
};
beforeAll(() => {
domMock = spyElementPrototype(HTMLElement, 'getBoundingClientRect', function mockBounding() {
return (
classRect[this.className] || {
top: 0,
bottom: 0,
}
);
});
});
afterAll(() => {
domMock.mockRestore();
});
const movePlaceholder = async top => {
classRect.fixed = {
top,
bottom: top,
};
events.scroll({
type: 'scroll',
});
await sleep(20);
};
it('Anchor render perfectly', async () => {
document.body.innerHTML = '<div id="mounter" />';
wrapper = mount(<AffixMounter />, { attachTo: document.getElementById('mounter') });
await sleep(20);
await movePlaceholder(0);
expect(wrapper.instance().affix.state.affixStyle).toBeFalsy();
await movePlaceholder(-100);
expect(wrapper.instance().affix.state.affixStyle).toBeTruthy();
await movePlaceholder(0);
expect(wrapper.instance().affix.state.affixStyle).toBeFalsy();
});
it('support offsetBottom', async () => {
document.body.innerHTML = '<div id="mounter" />';
wrapper = mount(<AffixMounter offsetBottom={0} />, {
attachTo: document.getElementById('mounter'),
});
await sleep(20);
await movePlaceholder(300);
expect(wrapper.instance().affix.state.affixStyle).toBeTruthy();
await movePlaceholder(0);
expect(wrapper.instance().affix.state.affixStyle).toBeFalsy();
await movePlaceholder(300);
expect(wrapper.instance().affix.state.affixStyle).toBeTruthy();
});
it('updatePosition when offsetTop changed', async () => {
document.body.innerHTML = '<div id="mounter" />';
wrapper = mount(<AffixMounter offsetTop={0} />, {
attachTo: document.getElementById('mounter'),
});
await sleep(20);
await movePlaceholder(-100);
expect(wrapper.instance().affix.state.affixStyle.top).toBe(0);
wrapper.setProps({
offsetTop: 10,
});
await sleep(20);
expect(wrapper.instance().affix.state.affixStyle.top).toBe(10);
});
describe('updatePosition when target changed', () => {
it('function change', () => {
document.body.innerHTML = '<div id="mounter" />';
const container = document.querySelector('#id');
const getTarget = () => container;
wrapper = mount(<Affix target={getTarget} />);
wrapper.setProps({ target: null });
expect(wrapper.instance().state.status).toBe(0);
expect(wrapper.instance().state.affixStyle).toBe(undefined);
expect(wrapper.instance().state.placeholderStyle).toBe(undefined);
});
it('instance change', async () => {
const getObserverLength = () => Object.keys(getObserverEntities()).length;
const container = document.createElement('div');
document.body.appendChild(container);
let target = container;
const originLength = getObserverLength();
const getTarget = () => target;
wrapper = mount(<Affix target={getTarget} />);
await sleep(50);
expect(getObserverLength()).toBe(originLength + 1);
target = null;
wrapper.setProps({});
wrapper.update();
await sleep(50);
expect(getObserverLength()).toBe(originLength);
});
});
describe('updatePosition when size changed', () => {
function test(name, index) {
it(name, async () => {
document.body.innerHTML = '<div id="mounter" />';
const updateCalled = jest.fn();
wrapper = mount(<AffixMounter offsetBottom={0} onTestUpdatePosition={updateCalled} />, {
attachTo: document.getElementById('mounter'),
});
await sleep(20);
await movePlaceholder(300);
expect(wrapper.instance().affix.state.affixStyle).toBeTruthy();
await sleep(20);
wrapper.update();
// Mock trigger resize
updateCalled.mockReset();
wrapper
.find('ResizeObserver')
.at(index)
.instance()
.onResize([{ target: { getBoundingClientRect: () => ({ width: 99, height: 99 }) } }]);
await sleep(20);
expect(updateCalled).toHaveBeenCalled();
});
}
test('inner', 0);
test('outer', 1);
});
});

View File

@@ -0,0 +1,230 @@
import React from 'react';
import { mount, ReactWrapper, HTMLAttributes } from 'enzyme';
import ResizeObserverImpl from 'rc-resize-observer';
import Affix, { AffixProps, AffixState } from '..';
import { getObserverEntities } from '../utils';
import Button from '../../button';
import rtlTest from '../../../tests/shared/rtlTest';
import { sleep } from '../../../tests/utils';
const events: Partial<Record<keyof HTMLElementEventMap, (ev: Partial<Event>) => void>> = {};
class AffixMounter extends React.Component<{
offsetBottom?: number;
offsetTop?: number;
onTestUpdatePosition?(): void;
}> {
private container: HTMLDivElement;
public affix: Affix;
componentDidMount() {
this.container.addEventListener = jest
.fn()
.mockImplementation((event: keyof HTMLElementEventMap, cb: (ev: Partial<Event>) => void) => {
events[event] = cb;
});
}
getTarget = () => this.container;
render() {
return (
<div
ref={node => {
this.container = node!;
}}
className="container"
>
<Affix
className="fixed"
target={this.getTarget}
ref={ele => {
this.affix = ele!;
}}
{...this.props}
>
<Button type="primary">Fixed at the top of container</Button>
</Affix>
</div>
);
}
}
describe('Affix Render', () => {
rtlTest(Affix);
const domMock = jest.spyOn(HTMLElement.prototype, 'getBoundingClientRect');
let affixMounterWrapper: ReactWrapper<unknown, unknown, AffixMounter>;
let affixWrapper: ReactWrapper<AffixProps, AffixState, Affix>;
const classRect: Record<string, DOMRect> = {
container: {
top: 0,
bottom: 100,
} as DOMRect,
};
beforeAll(() => {
domMock.mockImplementation(function fn(this: HTMLElement) {
return (
classRect[this.className] || {
top: 0,
bottom: 0,
}
);
});
});
afterAll(() => {
domMock.mockRestore();
});
const movePlaceholder = async (top: number) => {
classRect.fixed = {
top,
bottom: top,
} as DOMRect;
if (events.scroll == null) {
throw new Error('scroll should be set');
}
events.scroll({
type: 'scroll',
});
await sleep(20);
};
it('Anchor render perfectly', async () => {
document.body.innerHTML = '<div id="mounter" />';
affixMounterWrapper = mount(<AffixMounter />, { attachTo: document.getElementById('mounter') });
await sleep(20);
await movePlaceholder(0);
expect(affixMounterWrapper.instance().affix.state.affixStyle).toBeFalsy();
await movePlaceholder(-100);
expect(affixMounterWrapper.instance().affix.state.affixStyle).toBeTruthy();
await movePlaceholder(0);
expect(affixMounterWrapper.instance().affix.state.affixStyle).toBeFalsy();
});
it('support offsetBottom', async () => {
document.body.innerHTML = '<div id="mounter" />';
affixMounterWrapper = mount(<AffixMounter offsetBottom={0} />, {
attachTo: document.getElementById('mounter'),
});
await sleep(20);
await movePlaceholder(300);
expect(affixMounterWrapper.instance().affix.state.affixStyle).toBeTruthy();
await movePlaceholder(0);
expect(affixMounterWrapper.instance().affix.state.affixStyle).toBeFalsy();
await movePlaceholder(300);
expect(affixMounterWrapper.instance().affix.state.affixStyle).toBeTruthy();
});
it('updatePosition when offsetTop changed', async () => {
document.body.innerHTML = '<div id="mounter" />';
affixMounterWrapper = mount(<AffixMounter offsetTop={0} />, {
attachTo: document.getElementById('mounter'),
});
await sleep(20);
await movePlaceholder(-100);
expect(affixMounterWrapper.instance().affix.state.affixStyle?.top).toBe(0);
affixMounterWrapper.setProps({
offsetTop: 10,
});
await sleep(20);
expect(affixMounterWrapper.instance().affix.state.affixStyle?.top).toBe(10);
});
describe('updatePosition when target changed', () => {
it('function change', () => {
document.body.innerHTML = '<div id="mounter" />';
const container = document.querySelector('#id') as HTMLDivElement;
const getTarget = () => container;
affixWrapper = mount(<Affix target={getTarget}>{null}</Affix>);
affixWrapper.setProps({ target: () => null });
expect(affixWrapper.instance().state.status).toBe(0);
expect(affixWrapper.instance().state.affixStyle).toBe(undefined);
expect(affixWrapper.instance().state.placeholderStyle).toBe(undefined);
});
it('instance change', async () => {
const getObserverLength = () => Object.keys(getObserverEntities()).length;
const container = document.createElement('div');
document.body.appendChild(container);
let target: HTMLDivElement | null = container;
const originLength = getObserverLength();
const getTarget = () => target;
affixWrapper = mount(<Affix target={getTarget}>{null}</Affix>);
await sleep(50);
expect(getObserverLength()).toBe(originLength + 1);
target = null;
affixWrapper.setProps({});
affixWrapper.update();
await sleep(50);
expect(getObserverLength()).toBe(originLength);
});
});
describe('updatePosition when size changed', () => {
it.each([
{ name: 'inner', index: 0 },
{ name: 'outer', index: 1 },
])(name, async ({ index }) => {
document.body.innerHTML = '<div id="mounter" />';
const updateCalled = jest.fn();
affixMounterWrapper = mount(
<AffixMounter offsetBottom={0} onTestUpdatePosition={updateCalled} />,
{
attachTo: document.getElementById('mounter'),
},
);
await sleep(20);
await movePlaceholder(300);
expect(affixMounterWrapper.instance().affix.state.affixStyle).toBeTruthy();
await sleep(20);
affixMounterWrapper.update();
// Mock trigger resize
updateCalled.mockReset();
const resizeObserverInstance: ReactWrapper<
HTMLAttributes,
unknown,
ResizeObserverImpl
> = affixMounterWrapper.find('ResizeObserver') as any;
resizeObserverInstance
.at(index)
.instance()
.onResize(
[
{
target: {
getBoundingClientRect: () => ({ width: 99, height: 99 }),
} as Element,
contentRect: {} as DOMRect,
},
],
({} as unknown) as ResizeObserver,
);
await sleep(20);
expect(updateCalled).toHaveBeenCalled();
});
});
});

View File

@@ -2,7 +2,7 @@ import * as React from 'react';
import classNames from 'classnames';
import omit from 'omit.js';
import ResizeObserver from 'rc-resize-observer';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import { ConfigContext, ConfigConsumerProps } from '../config-provider';
import { throttleByAnimationFrameDecorator } from '../_util/throttleByAnimationFrame';
import {
@@ -32,7 +32,7 @@ export interface AffixProps {
target?: () => Window | HTMLElement | null;
prefixCls?: string;
className?: string;
children: React.ReactElement;
children: React.ReactNode;
}
enum AffixStatus {
@@ -50,9 +50,7 @@ export interface AffixState {
}
class Affix extends React.Component<AffixProps, AffixState> {
static defaultProps = {
target: getDefaultTarget,
};
static contextType = ConfigContext;
state: AffixState = {
status: AffixStatus.None,
@@ -66,14 +64,27 @@ class Affix extends React.Component<AffixProps, AffixState> {
private timeout: number;
context: ConfigConsumerProps;
private getTargetFunc() {
const { getTargetContainer } = this.context;
const { target } = this.props;
if (target !== undefined) {
return target;
}
return getTargetContainer || getDefaultTarget;
}
// Event handler
componentDidMount() {
const { target } = this.props;
if (target) {
const targetFunc = this.getTargetFunc();
if (targetFunc) {
// [Legacy] Wait for parent component ref has its value.
// We should use target as directly element instead of function which makes element check hard.
this.timeout = setTimeout(() => {
addObserveTarget(target(), this);
addObserveTarget(targetFunc(), this);
// Mock Event object.
this.updatePosition();
});
@@ -82,10 +93,10 @@ class Affix extends React.Component<AffixProps, AffixState> {
componentDidUpdate(prevProps: AffixProps) {
const { prevTarget } = this.state;
const { target } = this.props;
const targetFunc = this.getTargetFunc();
let newTarget = null;
if (target) {
newTarget = target() || null;
if (targetFunc) {
newTarget = targetFunc() || null;
}
if (prevTarget !== newTarget) {
@@ -141,15 +152,16 @@ class Affix extends React.Component<AffixProps, AffixState> {
// =================== Measure ===================
measure = () => {
const { status, lastAffix } = this.state;
const { target, onChange } = this.props;
if (status !== AffixStatus.Prepare || !this.fixedNode || !this.placeholderNode || !target) {
const { onChange } = this.props;
const targetFunc = this.getTargetFunc();
if (status !== AffixStatus.Prepare || !this.fixedNode || !this.placeholderNode || !targetFunc) {
return;
}
const offsetTop = this.getOffsetTop();
const offsetBottom = this.getOffsetBottom();
const targetNode = target();
const targetNode = targetFunc();
if (!targetNode) {
return;
}
@@ -220,15 +232,15 @@ class Affix extends React.Component<AffixProps, AffixState> {
@throttleByAnimationFrameDecorator()
lazyUpdatePosition() {
const { target } = this.props;
const targetFunc = this.getTargetFunc();
const { affixStyle } = this.state;
// Check position change before measure to make Safari smooth
if (target && affixStyle) {
if (targetFunc && affixStyle) {
const offsetTop = this.getOffsetTop();
const offsetBottom = this.getOffsetBottom();
const targetNode = target();
const targetNode = targetFunc();
if (targetNode && this.placeholderNode) {
const targetRect = getTargetRect(targetNode);
const placeholderReact = getTargetRect(this.placeholderNode);
@@ -249,7 +261,8 @@ class Affix extends React.Component<AffixProps, AffixState> {
}
// =================== Render ===================
renderAffix = ({ getPrefixCls }: ConfigConsumerProps) => {
render = () => {
const { getPrefixCls } = this.context;
const { affixStyle, placeholderStyle } = this.state;
const { prefixCls, children } = this.props;
const className = classNames({
@@ -283,10 +296,6 @@ class Affix extends React.Component<AffixProps, AffixState> {
</ResizeObserver>
);
};
render() {
return <ConfigConsumer>{this.renderAffix}</ConfigConsumer>;
}
}
export default Affix;

View File

@@ -163,7 +163,7 @@ exports[`renders ./components/alert/demo/basic.md correctly 1`] = `
`;
exports[`renders ./components/alert/demo/closable.md correctly 1`] = `
<div>
Array [
<div
class="ant-alert ant-alert-warning ant-alert-no-icon ant-alert-closable"
data-show="true"
@@ -202,7 +202,7 @@ exports[`renders ./components/alert/demo/closable.md correctly 1`] = `
</svg>
</span>
</button>
</div>
</div>,
<div
class="ant-alert ant-alert-error ant-alert-with-description ant-alert-no-icon ant-alert-closable"
data-show="true"
@@ -243,8 +243,8 @@ exports[`renders ./components/alert/demo/closable.md correctly 1`] = `
</svg>
</span>
</button>
</div>
</div>
</div>,
]
`;
exports[`renders ./components/alert/demo/close-text.md correctly 1`] = `
@@ -275,7 +275,7 @@ exports[`renders ./components/alert/demo/close-text.md correctly 1`] = `
`;
exports[`renders ./components/alert/demo/custom-icon.md correctly 1`] = `
<div>
Array [
<div
class="ant-alert ant-alert-success ant-alert-no-icon"
data-show="true"
@@ -288,7 +288,7 @@ exports[`renders ./components/alert/demo/custom-icon.md correctly 1`] = `
<span
class="ant-alert-description"
/>
</div>
</div>,
<div
class="ant-alert ant-alert-success"
data-show="true"
@@ -321,7 +321,7 @@ exports[`renders ./components/alert/demo/custom-icon.md correctly 1`] = `
<span
class="ant-alert-description"
/>
</div>
</div>,
<div
class="ant-alert ant-alert-info"
data-show="true"
@@ -354,7 +354,7 @@ exports[`renders ./components/alert/demo/custom-icon.md correctly 1`] = `
<span
class="ant-alert-description"
/>
</div>
</div>,
<div
class="ant-alert ant-alert-warning"
data-show="true"
@@ -387,7 +387,7 @@ exports[`renders ./components/alert/demo/custom-icon.md correctly 1`] = `
<span
class="ant-alert-description"
/>
</div>
</div>,
<div
class="ant-alert ant-alert-error"
data-show="true"
@@ -420,7 +420,7 @@ exports[`renders ./components/alert/demo/custom-icon.md correctly 1`] = `
<span
class="ant-alert-description"
/>
</div>
</div>,
<div
class="ant-alert ant-alert-success ant-alert-with-description"
data-show="true"
@@ -455,7 +455,7 @@ exports[`renders ./components/alert/demo/custom-icon.md correctly 1`] = `
>
Detailed description and advices about successful copywriting.
</span>
</div>
</div>,
<div
class="ant-alert ant-alert-info ant-alert-with-description"
data-show="true"
@@ -490,7 +490,7 @@ exports[`renders ./components/alert/demo/custom-icon.md correctly 1`] = `
>
Additional description and informations about copywriting.
</span>
</div>
</div>,
<div
class="ant-alert ant-alert-warning ant-alert-with-description"
data-show="true"
@@ -525,7 +525,7 @@ exports[`renders ./components/alert/demo/custom-icon.md correctly 1`] = `
>
This is a warning notice about copywriting.
</span>
</div>
</div>,
<div
class="ant-alert ant-alert-error ant-alert-with-description"
data-show="true"
@@ -560,12 +560,12 @@ exports[`renders ./components/alert/demo/custom-icon.md correctly 1`] = `
>
This is an error message about copywriting.
</span>
</div>
</div>
</div>,
]
`;
exports[`renders ./components/alert/demo/description.md correctly 1`] = `
<div>
Array [
<div
class="ant-alert ant-alert-success ant-alert-with-description ant-alert-no-icon"
data-show="true"
@@ -580,7 +580,7 @@ exports[`renders ./components/alert/demo/description.md correctly 1`] = `
>
Success Description Success Description Success Description
</span>
</div>
</div>,
<div
class="ant-alert ant-alert-info ant-alert-with-description ant-alert-no-icon"
data-show="true"
@@ -595,7 +595,7 @@ exports[`renders ./components/alert/demo/description.md correctly 1`] = `
>
Info Description Info Description Info Description Info Description
</span>
</div>
</div>,
<div
class="ant-alert ant-alert-warning ant-alert-with-description ant-alert-no-icon"
data-show="true"
@@ -610,7 +610,7 @@ exports[`renders ./components/alert/demo/description.md correctly 1`] = `
>
Warning Description Warning Description Warning Description Warning Description
</span>
</div>
</div>,
<div
class="ant-alert ant-alert-error ant-alert-with-description ant-alert-no-icon"
data-show="true"
@@ -625,8 +625,8 @@ exports[`renders ./components/alert/demo/description.md correctly 1`] = `
>
Error Description Error Description Error Description Error Description
</span>
</div>
</div>
</div>,
]
`;
exports[`renders ./components/alert/demo/error-boundary.md correctly 1`] = `
@@ -641,7 +641,7 @@ exports[`renders ./components/alert/demo/error-boundary.md correctly 1`] = `
`;
exports[`renders ./components/alert/demo/icon.md correctly 1`] = `
<div>
Array [
<div
class="ant-alert ant-alert-success"
data-show="true"
@@ -674,7 +674,7 @@ exports[`renders ./components/alert/demo/icon.md correctly 1`] = `
<span
class="ant-alert-description"
/>
</div>
</div>,
<div
class="ant-alert ant-alert-info"
data-show="true"
@@ -707,9 +707,9 @@ exports[`renders ./components/alert/demo/icon.md correctly 1`] = `
<span
class="ant-alert-description"
/>
</div>
</div>,
<div
class="ant-alert ant-alert-warning"
class="ant-alert ant-alert-warning ant-alert-closable"
data-show="true"
>
<span
@@ -740,7 +740,33 @@ exports[`renders ./components/alert/demo/icon.md correctly 1`] = `
<span
class="ant-alert-description"
/>
</div>
<button
class="ant-alert-close-icon"
tabindex="0"
type="button"
>
<span
aria-label="close"
class="anticon anticon-close"
role="img"
>
<svg
aria-hidden="true"
class=""
data-icon="close"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
/>
</svg>
</span>
</button>
</div>,
<div
class="ant-alert ant-alert-error"
data-show="true"
@@ -773,7 +799,7 @@ exports[`renders ./components/alert/demo/icon.md correctly 1`] = `
<span
class="ant-alert-description"
/>
</div>
</div>,
<div
class="ant-alert ant-alert-success ant-alert-with-description"
data-show="true"
@@ -811,7 +837,7 @@ exports[`renders ./components/alert/demo/icon.md correctly 1`] = `
>
Detailed description and advice about successful copywriting.
</span>
</div>
</div>,
<div
class="ant-alert ant-alert-info ant-alert-with-description"
data-show="true"
@@ -849,9 +875,9 @@ exports[`renders ./components/alert/demo/icon.md correctly 1`] = `
>
Additional description and information about copywriting.
</span>
</div>
</div>,
<div
class="ant-alert ant-alert-warning ant-alert-with-description"
class="ant-alert ant-alert-warning ant-alert-with-description ant-alert-closable"
data-show="true"
>
<span
@@ -887,7 +913,33 @@ exports[`renders ./components/alert/demo/icon.md correctly 1`] = `
>
This is a warning notice about copywriting.
</span>
</div>
<button
class="ant-alert-close-icon"
tabindex="0"
type="button"
>
<span
aria-label="close"
class="anticon anticon-close"
role="img"
>
<svg
aria-hidden="true"
class=""
data-icon="close"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
/>
</svg>
</span>
</button>
</div>,
<div
class="ant-alert ant-alert-error ant-alert-with-description"
data-show="true"
@@ -925,8 +977,8 @@ exports[`renders ./components/alert/demo/icon.md correctly 1`] = `
>
This is an error message about copywriting.
</span>
</div>
</div>
</div>,
]
`;
exports[`renders ./components/alert/demo/loop-banner.md correctly 1`] = `
@@ -1028,7 +1080,7 @@ exports[`renders ./components/alert/demo/smooth-closed.md correctly 1`] = `
`;
exports[`renders ./components/alert/demo/style.md correctly 1`] = `
<div>
Array [
<div
class="ant-alert ant-alert-success ant-alert-no-icon"
data-show="true"
@@ -1041,7 +1093,7 @@ exports[`renders ./components/alert/demo/style.md correctly 1`] = `
<span
class="ant-alert-description"
/>
</div>
</div>,
<div
class="ant-alert ant-alert-info ant-alert-no-icon"
data-show="true"
@@ -1054,7 +1106,7 @@ exports[`renders ./components/alert/demo/style.md correctly 1`] = `
<span
class="ant-alert-description"
/>
</div>
</div>,
<div
class="ant-alert ant-alert-warning ant-alert-no-icon"
data-show="true"
@@ -1067,7 +1119,7 @@ exports[`renders ./components/alert/demo/style.md correctly 1`] = `
<span
class="ant-alert-description"
/>
</div>
</div>,
<div
class="ant-alert ant-alert-error ant-alert-no-icon"
data-show="true"
@@ -1080,6 +1132,6 @@ exports[`renders ./components/alert/demo/style.md correctly 1`] = `
<span
class="ant-alert-description"
/>
</div>
</div>
</div>,
]
`;

View File

@@ -22,6 +22,27 @@ exports[`Alert ErrorBoundary 1`] = `
</div>
`;
exports[`Alert could accept none react element icon 1`] = `
<div
class="ant-alert ant-alert-success"
data-show="true"
>
<span
class="ant-alert-icon"
>
icon
</span>
<span
class="ant-alert-message"
>
Success Tips
</span>
<span
class="ant-alert-description"
/>
</div>
`;
exports[`Alert rtl render component should be rendered correctly in RTL direction 1`] = `
<div
class="ant-alert ant-alert-info ant-alert-no-icon ant-alert-rtl"

View File

@@ -39,20 +39,20 @@ describe('Alert', () => {
describe('data and aria props', () => {
it('sets data attributes on input', () => {
const wrapper = mount(<Alert data-test="test-id" data-id="12345" />);
const wrapper = mount(<Alert data-test="test-id" data-id="12345" message={null} />);
const input = wrapper.find('.ant-alert').getDOMNode();
expect(input.getAttribute('data-test')).toBe('test-id');
expect(input.getAttribute('data-id')).toBe('12345');
});
it('sets aria attributes on input', () => {
const wrapper = mount(<Alert aria-describedby="some-label" />);
const wrapper = mount(<Alert aria-describedby="some-label" message={null} />);
const input = wrapper.find('.ant-alert').getDOMNode();
expect(input.getAttribute('aria-describedby')).toBe('some-label');
});
it('sets role attribute on input', () => {
const wrapper = mount(<Alert role="status" />);
const wrapper = mount(<Alert role="status" message={null} />);
const input = wrapper.find('.ant-alert').getDOMNode();
expect(input.getAttribute('role')).toBe('status');
});
@@ -60,6 +60,8 @@ describe('Alert', () => {
const testIt = process.env.REACT === '15' ? it.skip : it;
testIt('ErrorBoundary', () => {
// TODO: Change to @ts-expect-error once typescript is at 3.9
// @ts-ignore
// eslint-disable-next-line react/jsx-no-undef
const ThrowError = () => <NotExisted />;
const wrapper = mount(
@@ -83,19 +85,15 @@ describe('Alert', () => {
);
wrapper.find('.ant-alert').simulate('mouseenter');
await sleep(0);
expect(
wrapper
.find(Tooltip)
.instance()
.getPopupDomNode(),
).toBeTruthy();
expect(wrapper.find<Tooltip>(Tooltip).instance().getPopupDomNode()).toBeTruthy();
jest.useFakeTimers();
});
it('could be used with Popconfirm', async () => {
const ref = React.createRef<any>();
jest.useRealTimers();
const wrapper = mount(
<Popconfirm title="xxx">
<Popconfirm ref={ref} title="xxx">
<Alert
message="Warning Text Warning Text Warning TextW arning Text Warning Text Warning TextWarning Text"
type="warning"
@@ -104,12 +102,12 @@ describe('Alert', () => {
);
wrapper.find('.ant-alert').simulate('click');
await sleep(0);
expect(
wrapper
.find(Popconfirm)
.instance()
.getPopupDomNode(),
).toBeTruthy();
expect(ref.current.getPopupDomNode()).toBeTruthy();
jest.useFakeTimers();
});
it('could accept none react element icon', () => {
const wrapper = mount(<Alert message="Success Tips" type="success" showIcon icon="icon" />);
expect(wrapper).toMatchRenderedSnapshot();
});
});

View File

@@ -21,7 +21,7 @@ const onClose = (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
};
ReactDOM.render(
<div>
<>
<Alert
message="Warning Text Warning Text Warning TextW arning Text Warning Text Warning TextWarning Text"
type="warning"
@@ -35,7 +35,7 @@ ReactDOM.render(
closable
onClose={onClose}
/>
</div>,
</>,
mountNode,
);
```

View File

@@ -21,7 +21,7 @@ import { SmileOutlined } from '@ant-design/icons';
const icon = <SmileOutlined />;
ReactDOM.render(
<div>
<>
<Alert icon={icon} message="showIcon = false" type="success" />
<Alert icon={icon} message="Success Tips" type="success" showIcon />
<Alert icon={icon} message="Informational Notes" type="info" showIcon />
@@ -55,7 +55,7 @@ ReactDOM.render(
type="error"
showIcon
/>
</div>,
</>,
mountNode,
);
```

View File

@@ -17,7 +17,7 @@ Additional description for alert message.
import { Alert } from 'antd';
ReactDOM.render(
<div>
<>
<Alert
message="Success Text"
description="Success Description Success Description Success Description"
@@ -38,7 +38,7 @@ ReactDOM.render(
description="Error Description Error Description Error Description Error Description"
type="error"
/>
</div>,
</>,
mountNode,
);
```

View File

@@ -17,10 +17,10 @@ A relevant icon will make information clearer and more friendly.
import { Alert } from 'antd';
ReactDOM.render(
<div>
<>
<Alert message="Success Tips" type="success" showIcon />
<Alert message="Informational Notes" type="info" showIcon />
<Alert message="Warning" type="warning" showIcon />
<Alert message="Warning" type="warning" showIcon closable />
<Alert message="Error" type="error" showIcon />
<Alert
message="Success Tips"
@@ -39,6 +39,7 @@ ReactDOM.render(
description="This is a warning notice about copywriting."
type="warning"
showIcon
closable
/>
<Alert
message="Error"
@@ -46,7 +47,7 @@ ReactDOM.render(
type="error"
showIcon
/>
</div>,
</>,
mountNode,
);
```

View File

@@ -17,12 +17,18 @@ There are 4 types of Alert: `success`, `info`, `warning`, `error`.
import { Alert } from 'antd';
ReactDOM.render(
<div>
<>
<Alert message="Success Text" type="success" />
<Alert message="Info Text" type="info" />
<Alert message="Warning Text" type="warning" />
<Alert message="Error Text" type="error" />
</div>,
</>,
mountNode,
);
```
<style>
[data-theme="compact"] .code-box-demo .ant-alert {
margin-bottom: 8px;
}
</style>

View File

@@ -16,8 +16,6 @@ import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import getDataOrAriaProps from '../_util/getDataOrAriaProps';
import ErrorBoundary from './ErrorBoundary';
function noop() {}
export interface AlertProps {
/**
* Type of Alert styles, options:`success`, `info`, `warning`, `error`
@@ -37,6 +35,8 @@ export interface AlertProps {
afterClose?: () => void;
/** Whether to show icon */
showIcon?: boolean;
/** https://www.w3.org/TR/2014/REC-html5-20141028/dom.html#aria-role-attribute */
role?: string;
style?: React.CSSProperties;
prefixCls?: string;
className?: string;
@@ -85,7 +85,7 @@ export default class Alert extends React.Component<AlertProps, AlertState> {
this.setState({
closing: true,
});
(this.props.onClose || noop)(e);
this.props.onClose?.(e);
};
animationEnd = () => {
@@ -93,56 +93,56 @@ export default class Alert extends React.Component<AlertProps, AlertState> {
closing: false,
closed: true,
});
(this.props.afterClose || noop)();
this.props.afterClose?.();
};
renderAlert = ({ getPrefixCls, direction }: ConfigConsumerProps) => {
const {
description,
prefixCls: customizePrefixCls,
message,
closeText,
banner,
className = '',
style,
icon,
onMouseEnter,
onMouseLeave,
onClick,
} = this.props;
let { closable, type, showIcon } = this.props;
const { closing, closed } = this.state;
getShowIcon() {
const { banner, showIcon } = this.props;
// banner 模式默认有 Icon
return banner && showIcon === undefined ? true : showIcon;
}
const prefixCls = getPrefixCls('alert', customizePrefixCls);
// banner模式默认有 Icon
showIcon = banner && showIcon === undefined ? true : showIcon;
// banner模式默认为警告
type = banner && type === undefined ? 'warning' : type || 'info';
// use outline icon in alert with description
const iconType = (description ? iconMapOutlined : iconMapFilled)[type] || null;
// closeable when closeText is assigned
if (closeText) {
closable = true;
getType() {
const { banner, type } = this.props;
if (type !== undefined) {
return type;
}
// banner 模式默认为警告
return banner ? 'warning' : 'info';
}
const alertCls = classNames(
prefixCls,
`${prefixCls}-${type}`,
{
[`${prefixCls}-closing`]: closing,
[`${prefixCls}-with-description`]: !!description,
[`${prefixCls}-no-icon`]: !showIcon,
[`${prefixCls}-banner`]: !!banner,
[`${prefixCls}-closable`]: closable,
[`${prefixCls}-rtl`]: direction === 'rtl',
},
className,
);
getClosable() {
const { closable, closeText } = this.props;
// closeable when closeText is assigned
return closeText ? true : closable;
}
const closeIcon = closable ? (
getIconType() {
const { description } = this.props;
// use outline icon in alert with description
return (description ? iconMapOutlined : iconMapFilled)[this.getType()] || null;
}
renderIconNode({ prefixCls }: { prefixCls: string }) {
const { icon } = this.props;
const iconType = this.getIconType();
if (icon) {
return React.isValidElement<{ className?: string }>(icon) ? (
React.cloneElement(icon, {
className: classNames(`${prefixCls}-icon`, {
[icon.props.className as string]: icon.props.className,
}),
})
) : (
<span className={`${prefixCls}-icon`}>{icon}</span>
);
}
return React.createElement(iconType, { className: `${prefixCls}-icon` });
}
renderCloseIcon({ prefixCls }: { prefixCls: string }) {
const { closeText } = this.props;
return this.getClosable() ? (
<button
type="button"
onClick={this.handleClose}
@@ -156,21 +156,47 @@ export default class Alert extends React.Component<AlertProps, AlertState> {
)}
</button>
) : null;
}
renderAlert = ({ getPrefixCls, direction }: ConfigConsumerProps) => {
const {
description,
prefixCls: customizePrefixCls,
message,
banner,
className = '',
style,
onMouseEnter,
onMouseLeave,
onClick,
} = this.props;
const { closing, closed } = this.state;
const prefixCls = getPrefixCls('alert', customizePrefixCls);
const isShowIcon = this.getShowIcon();
const type = this.getType();
const closable = this.getClosable();
const alertCls = classNames(
prefixCls,
`${prefixCls}-${type}`,
{
[`${prefixCls}-closing`]: closing,
[`${prefixCls}-with-description`]: !!description,
[`${prefixCls}-no-icon`]: !isShowIcon,
[`${prefixCls}-banner`]: !!banner,
[`${prefixCls}-closable`]: closable,
[`${prefixCls}-rtl`]: direction === 'rtl',
},
className,
);
const closeIcon = this.renderCloseIcon({ prefixCls });
const dataOrAriaProps = getDataOrAriaProps(this.props);
const iconNode =
(icon &&
(React.isValidElement<{ className?: string }>(icon) ? (
React.cloneElement(icon, {
className: classNames(`${prefixCls}-icon`, {
[icon.props.className as string]: icon.props.className,
}),
})
) : (
<span className={`${prefixCls}-icon`}>{icon}</span>
))) ||
React.createElement(iconType, { className: `${prefixCls}-icon` });
const iconNode = this.renderIconNode({ prefixCls });
return closed ? null : (
<Animate
@@ -188,7 +214,7 @@ export default class Alert extends React.Component<AlertProps, AlertState> {
onClick={onClick}
{...dataOrAriaProps}
>
{showIcon ? iconNode : null}
{isShowIcon ? iconNode : null}
<span className={`${prefixCls}-message`}>{message}</span>
<span className={`${prefixCls}-description`}>{description}</span>
{closeIcon}

View File

@@ -13,6 +13,10 @@
&&-no-icon {
padding: @alert-no-icon-padding-vertical 15px;
.@{alert-prefix-cls}-close-icon {
top: @alert-no-icon-padding-vertical + @font-size-base * @line-height-base / 2 -
@font-size-base / 2;
}
}
&&-closable {
@@ -21,14 +25,14 @@
&-icon {
position: absolute;
top: 8px + @font-size-base * @line-height-base / 2 - @font-size-base / 2;
top: @alert-icon-top;
left: 16px;
}
&-description {
display: none;
font-size: @font-size-base;
line-height: 22px;
line-height: @font-size-base + 8px;
}
&-success {
@@ -71,12 +75,12 @@
&-close-icon {
position: absolute;
top: @padding-xs;
top: 8px + @font-size-base * @line-height-base / 2 - @font-size-base / 2;
right: 16px;
padding: 0;
overflow: hidden;
font-size: @font-size-sm;
line-height: 22px;
line-height: @font-size-sm;
background-color: transparent;
border: none;
outline: none;
@@ -101,7 +105,7 @@
&-with-description {
position: relative;
padding: 15px 15px 15px 64px;
padding: @alert-with-description-padding;
color: @alert-text-color;
line-height: @line-height-base;
border-radius: @border-radius-base;
@@ -113,15 +117,15 @@
&-with-description &-icon {
position: absolute;
top: 16px;
left: 24px;
font-size: 24px;
top: @alert-with-description-icon-top;
left: @alert-with-description-icon-size;
font-size: @alert-with-description-icon-size;
}
&-with-description &-close-icon {
position: absolute;
top: 16px;
right: 16px;
top: @padding-xs;
right: @padding-xs;
font-size: @font-size-base;
cursor: pointer;
}
@@ -188,4 +192,4 @@
}
}
@import './rtl.less';
@import './rtl';

View File

@@ -4,13 +4,26 @@
@alert-prefix-cls: ~'@{ant-prefix}-alert';
.@{alert-prefix-cls} {
&-rtl {
&&-rtl {
padding: 8px 37px 8px 15px;
direction: rtl;
}
&&-closable {
&&-no-icon {
.@{alert-prefix-cls}-rtl& {
padding: @alert-no-icon-padding-vertical 15px;
}
}
&&-closable {
.@{alert-prefix-cls}.@{alert-prefix-cls}-rtl& {
padding-right: 37px;
padding-left: 30px;
}
}
&&-no-icon&-closable {
.@{alert-prefix-cls}.@{alert-prefix-cls}-rtl& {
padding-right: 15px;
padding-left: 30px;
}
@@ -30,14 +43,15 @@
}
}
&-with-description {
.@{alert-prefix-cls}-rtl& {
&-with-description,
&-with-description&-closable {
.@{alert-prefix-cls}.@{alert-prefix-cls}-rtl& {
padding: 15px 64px 15px 15px;
}
}
&-with-description&-no-icon {
.@{alert-prefix-cls}-rtl& {
.@{alert-prefix-cls}.@{alert-prefix-cls}-rtl& {
padding: 15px;
}
}

View File

@@ -1,23 +1,19 @@
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import * as PropTypes from 'prop-types';
import classNames from 'classnames';
import addEventListener from 'rc-util/lib/Dom/addEventListener';
import Affix from '../affix';
import AnchorLink from './AnchorLink';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import { ConfigContext, ConfigConsumerProps } from '../config-provider';
import scrollTo from '../_util/scrollTo';
import getScroll from '../_util/getScroll';
import AnchorContext from './context';
function getDefaultContainer() {
return window;
}
function getOffsetTop(element: HTMLElement, container: AnchorContainer): number {
if (!element) {
return 0;
}
if (!element.getClientRects().length) {
return 0;
}
@@ -35,7 +31,7 @@ function getOffsetTop(element: HTMLElement, container: AnchorContainer): number
return rect.top;
}
const sharpMatcherRegx = /#([^#]+)$/;
const sharpMatcherRegx = /#(\S+)$/;
type Section = {
link: string;
@@ -88,23 +84,22 @@ export interface AntAnchor {
) => void;
}
export default class Anchor extends React.Component<AnchorProps, AnchorState> {
export default class Anchor extends React.Component<AnchorProps, AnchorState, ConfigConsumerProps> {
static Link: typeof AnchorLink;
static defaultProps = {
affix: true,
showInkInFixed: false,
getContainer: getDefaultContainer,
};
static childContextTypes = {
antAnchor: PropTypes.object,
};
static contextType = ConfigContext;
state = {
activeLink: null,
};
content: ConfigConsumerProps;
private inkNode: HTMLSpanElement;
// scroll scope's container
@@ -118,37 +113,38 @@ export default class Anchor extends React.Component<AnchorProps, AnchorState> {
private prefixCls?: string;
getChildContext() {
const antAnchor: AntAnchor = {
registerLink: (link: string) => {
if (!this.links.includes(link)) {
this.links.push(link);
}
},
unregisterLink: (link: string) => {
const index = this.links.indexOf(link);
if (index !== -1) {
this.links.splice(index, 1);
}
},
activeLink: this.state.activeLink,
scrollTo: this.handleScrollTo,
onClick: this.props.onClick,
};
return { antAnchor };
}
// Context
registerLink = (link: string) => {
if (!this.links.includes(link)) {
this.links.push(link);
}
};
unregisterLink = (link: string) => {
const index = this.links.indexOf(link);
if (index !== -1) {
this.links.splice(index, 1);
}
};
getContainer = () => {
const { getTargetContainer } = this.context;
const { getContainer } = this.props;
const getFunc = getContainer || getTargetContainer || getDefaultContainer;
return getFunc();
};
componentDidMount() {
const { getContainer } = this.props as AnchorDefaultProps;
this.scrollContainer = getContainer();
this.scrollContainer = this.getContainer();
this.scrollEvent = addEventListener(this.scrollContainer, 'scroll', this.handleScroll);
this.handleScroll();
}
componentDidUpdate() {
if (this.scrollEvent) {
const { getContainer } = this.props as AnchorDefaultProps;
const currentContainer = getContainer();
const currentContainer = this.getContainer();
if (this.scrollContainer !== currentContainer) {
this.scrollContainer = currentContainer;
this.scrollEvent.remove();
@@ -172,14 +168,8 @@ export default class Anchor extends React.Component<AnchorProps, AnchorState> {
return getCurrentAnchor();
}
const activeLink = '';
if (typeof document === 'undefined') {
return activeLink;
}
const linkSections: Array<Section> = [];
const { getContainer } = this.props as AnchorDefaultProps;
const container = getContainer();
const container = this.getContainer();
this.links.forEach(link => {
const sharpLinkMatch = sharpMatcherRegx.exec(link.toString());
if (!sharpLinkMatch) {
@@ -205,10 +195,10 @@ export default class Anchor extends React.Component<AnchorProps, AnchorState> {
}
handleScrollTo = (link: string) => {
const { offsetTop, getContainer, targetOffset } = this.props as AnchorDefaultProps;
const { offsetTop, targetOffset } = this.props;
this.setCurrentActiveLink(link);
const container = getContainer();
const container = this.getContainer();
const scrollTop = getScroll(container, true);
const sharpLinkMatch = sharpMatcherRegx.exec(link);
if (!sharpLinkMatch) {
@@ -228,7 +218,7 @@ export default class Anchor extends React.Component<AnchorProps, AnchorState> {
callback: () => {
this.animating = false;
},
getContainer,
getContainer: this.getContainer,
});
};
@@ -263,9 +253,6 @@ export default class Anchor extends React.Component<AnchorProps, AnchorState> {
};
updateInk = () => {
if (typeof document === 'undefined') {
return;
}
const { prefixCls } = this;
const anchorNode = ReactDOM.findDOMNode(this) as Element;
const linkNode = anchorNode.getElementsByClassName(`${prefixCls}-link-title-active`)[0];
@@ -274,7 +261,9 @@ export default class Anchor extends React.Component<AnchorProps, AnchorState> {
}
};
renderAnchor = ({ getPrefixCls, direction }: ConfigConsumerProps) => {
render = () => {
const { getPrefixCls, direction } = this.context;
const {
prefixCls: customizePrefixCls,
className = '',
@@ -283,7 +272,6 @@ export default class Anchor extends React.Component<AnchorProps, AnchorState> {
affix,
showInkInFixed,
children,
getContainer,
} = this.props;
const { activeLink } = this.state;
@@ -322,16 +310,24 @@ export default class Anchor extends React.Component<AnchorProps, AnchorState> {
</div>
);
return !affix ? (
anchorContent
) : (
<Affix offsetTop={offsetTop} target={getContainer}>
{anchorContent}
</Affix>
return (
<AnchorContext.Provider
value={{
registerLink: this.registerLink,
unregisterLink: this.unregisterLink,
activeLink: this.state.activeLink,
scrollTo: this.handleScrollTo,
onClick: this.props.onClick,
}}
>
{!affix ? (
anchorContent
) : (
<Affix offsetTop={offsetTop} target={this.getContainer}>
{anchorContent}
</Affix>
)}
</AnchorContext.Provider>
);
};
render() {
return <ConfigConsumer>{this.renderAnchor}</ConfigConsumer>;
}
}

View File

@@ -1,8 +1,8 @@
import * as React from 'react';
import * as PropTypes from 'prop-types';
import classNames from 'classnames';
import { AntAnchor } from './Anchor';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import AnchorContext from './context';
export interface AnchorLinkProps {
prefixCls?: string;
@@ -13,37 +13,33 @@ export interface AnchorLinkProps {
className?: string;
}
class AnchorLink extends React.Component<AnchorLinkProps, any> {
class AnchorLink extends React.Component<AnchorLinkProps, any, AntAnchor> {
static defaultProps = {
href: '#',
};
static contextTypes = {
antAnchor: PropTypes.object,
};
static contextType = AnchorContext;
context: {
antAnchor: AntAnchor;
};
context: AntAnchor;
componentDidMount() {
this.context.antAnchor.registerLink(this.props.href);
this.context.registerLink(this.props.href);
}
componentDidUpdate({ href: prevHref }: AnchorLinkProps) {
const { href } = this.props;
if (prevHref !== href) {
this.context.antAnchor.unregisterLink(prevHref);
this.context.antAnchor.registerLink(href);
this.context.unregisterLink(prevHref);
this.context.registerLink(href);
}
}
componentWillUnmount() {
this.context.antAnchor.unregisterLink(this.props.href);
this.context.unregisterLink(this.props.href);
}
handleClick = (e: React.MouseEvent<HTMLElement>) => {
const { scrollTo, onClick } = this.context.antAnchor;
const { scrollTo, onClick } = this.context;
const { href, title } = this.props;
if (onClick) {
onClick(e, { title, href });
@@ -54,7 +50,7 @@ class AnchorLink extends React.Component<AnchorLinkProps, any> {
renderAnchorLink = ({ getPrefixCls }: ConfigConsumerProps) => {
const { prefixCls: customizePrefixCls, href, title, children, className, target } = this.props;
const prefixCls = getPrefixCls('anchor', customizePrefixCls);
const active = this.context.antAnchor.activeLink === href;
const active = this.context.activeLink === href;
const wrapperClassName = classNames(className, `${prefixCls}-link`, {
[`${prefixCls}-link-active`]: active,
});

View File

@@ -1,336 +0,0 @@
import React from 'react';
import { mount } from 'enzyme';
import Anchor from '..';
import { spyElementPrototypes } from '../../__tests__/util/domHook';
import { sleep } from '../../../tests/utils';
const { Link } = Anchor;
describe('Anchor Render', () => {
const getBoundingClientRectMock = jest.fn(() => ({
width: 100,
height: 100,
top: 1000,
}));
const getClientRectsMock = jest.fn(() => ({
length: 1,
}));
const headingSpy = spyElementPrototypes(HTMLHeadingElement, {
getBoundingClientRect: getBoundingClientRectMock,
getClientRects: getClientRectsMock,
});
afterAll(() => {
headingSpy.mockRestore();
});
it('Anchor render perfectly', () => {
const wrapper = mount(
<Anchor>
<Link href="#API" title="API" />
</Anchor>,
);
wrapper.find('a[href="#API"]').simulate('click');
wrapper.instance().handleScroll();
expect(wrapper.instance().state).not.toBe(null);
});
it('Anchor render perfectly for complete href - click', () => {
const wrapper = mount(
<Anchor>
<Link href="http://www.example.com/#API" title="API" />
</Anchor>,
);
wrapper.find('a[href="http://www.example.com/#API"]').simulate('click');
expect(wrapper.instance().state.activeLink).toBe('http://www.example.com/#API');
});
it('Anchor render perfectly for complete href - scroll', () => {
let root = document.getElementById('root');
if (!root) {
root = document.createElement('div', { id: 'root' });
root.id = 'root';
document.body.appendChild(root);
}
mount(<div id="API">Hello</div>, { attachTo: root });
const wrapper = mount(
<Anchor>
<Link href="http://www.example.com/#API" title="API" />
</Anchor>,
);
wrapper.instance().handleScroll();
expect(wrapper.instance().state.activeLink).toBe('http://www.example.com/#API');
});
it('Anchor render perfectly for complete href - scrollTo', async () => {
const scrollToSpy = jest.spyOn(window, 'scrollTo');
let root = document.getElementById('root');
if (!root) {
root = document.createElement('div', { id: 'root' });
root.id = 'root';
document.body.appendChild(root);
}
mount(<div id="API">Hello</div>, { attachTo: root });
const wrapper = mount(
<Anchor>
<Link href="##API" title="API" />
</Anchor>,
);
wrapper.instance().handleScrollTo('##API');
expect(wrapper.instance().state.activeLink).toBe('##API');
expect(scrollToSpy).not.toHaveBeenCalled();
await sleep(1000);
expect(scrollToSpy).toHaveBeenCalled();
});
it('should remove listener when unmount', async () => {
const wrapper = mount(
<Anchor>
<Link href="#API" title="API" />
</Anchor>,
);
const removeListenerSpy = jest.spyOn(wrapper.instance().scrollEvent, 'remove');
wrapper.unmount();
expect(removeListenerSpy).toHaveBeenCalled();
});
it('should unregister link when unmount children', async () => {
const wrapper = mount(
<Anchor>
<Link href="#API" title="API" />
</Anchor>,
);
expect(wrapper.instance().links).toEqual(['#API']);
wrapper.setProps({ children: null });
expect(wrapper.instance().links).toEqual([]);
});
it('should update links when link href update', async () => {
let anchorInstance = null;
function AnchorUpdate({ href }) {
return (
<Anchor
ref={c => {
anchorInstance = c;
}}
>
<Link href={href} title="API" />
</Anchor>
);
}
const wrapper = mount(<AnchorUpdate href="#API" />);
expect(anchorInstance.links).toEqual(['#API']);
wrapper.setProps({ href: '#API_1' });
expect(anchorInstance.links).toEqual(['#API_1']);
});
it('Anchor onClick event', () => {
let event;
let link;
const handleClick = (...arg) => {
[event, link] = arg;
};
const href = '#API';
const title = 'API';
const wrapper = mount(
<Anchor onClick={handleClick}>
<Link href={href} title={title} />
</Anchor>,
);
wrapper.find(`a[href="${href}"]`).simulate('click');
wrapper.instance().handleScroll();
expect(event).not.toBe(undefined);
expect(link).toEqual({ href, title });
});
it('Different function returns the same DOM', async () => {
let root = document.getElementById('root');
if (!root) {
root = document.createElement('div', { id: 'root' });
root.id = 'root';
document.body.appendChild(root);
}
mount(<div id="API">Hello</div>, { attachTo: root });
const getContainerA = () => {
return document.getElementById('API');
};
const getContainerB = () => {
return document.getElementById('API');
};
const wrapper = mount(
<Anchor getContainer={getContainerA}>
<Link href="#API" title="API" />
</Anchor>,
);
const removeListenerSpy = jest.spyOn(wrapper.instance().scrollEvent, 'remove');
await sleep(1000);
wrapper.setProps({ getContainer: getContainerB });
expect(removeListenerSpy).not.toHaveBeenCalled();
});
it('Different function returns different DOM', async () => {
let root = document.getElementById('root');
if (!root) {
root = document.createElement('div', { id: 'root' });
root.id = 'root';
document.body.appendChild(root);
}
mount(
<div>
<div id="API1">Hello</div>
<div id="API2">World</div>
</div>,
{ attachTo: root },
);
const getContainerA = () => {
return document.getElementById('API1');
};
const getContainerB = () => {
return document.getElementById('API2');
};
const wrapper = mount(
<Anchor getContainer={getContainerA}>
<Link href="#API1" title="API1" />
<Link href="#API2" title="API2" />
</Anchor>,
);
const removeListenerSpy = jest.spyOn(wrapper.instance().scrollEvent, 'remove');
expect(removeListenerSpy).not.toHaveBeenCalled();
await sleep(1000);
wrapper.setProps({ getContainer: getContainerB });
expect(removeListenerSpy).toHaveBeenCalled();
});
it('Same function returns the same DOM', () => {
let root = document.getElementById('root');
if (!root) {
root = document.createElement('div', { id: 'root' });
root.id = 'root';
document.body.appendChild(root);
}
mount(<div id="API">Hello</div>, { attachTo: root });
const getContainer = () => document.getElementById('API');
const wrapper = mount(
<Anchor getContainer={getContainer}>
<Link href="#API" title="API" />
</Anchor>,
);
wrapper.find('a[href="#API"]').simulate('click');
wrapper.instance().handleScroll();
expect(wrapper.instance().state).not.toBe(null);
});
it('Same function returns different DOM', async () => {
let root = document.getElementById('root');
if (!root) {
root = document.createElement('div', { id: 'root' });
root.id = 'root';
document.body.appendChild(root);
}
mount(
<div>
<div id="API1">Hello</div>
<div id="API2">World</div>
</div>,
{ attachTo: root },
);
const holdContainer = {
container: document.getElementById('API1'),
};
const getContainer = () => {
return holdContainer.container;
};
const wrapper = mount(
<Anchor getContainer={getContainer}>
<Link href="#API1" title="API1" />
<Link href="#API2" title="API2" />
</Anchor>,
);
const removeListenerSpy = jest.spyOn(wrapper.instance().scrollEvent, 'remove');
expect(removeListenerSpy).not.toHaveBeenCalled();
await sleep(1000);
holdContainer.container = document.getElementById('API2');
wrapper.setProps({ 'data-only-trigger-re-render': true });
expect(removeListenerSpy).toHaveBeenCalled();
});
it('Anchor getCurrentAnchor prop', () => {
const getCurrentAnchor = () => '#API2';
const wrapper = mount(
<Anchor getCurrentAnchor={getCurrentAnchor}>
<Link href="#API1" title="API1" />
<Link href="#API2" title="API2" />
</Anchor>,
);
expect(wrapper.instance().state.activeLink).toBe('#API2');
});
it('Anchor targetOffset prop', async () => {
let dateNowMock;
function dataNowMockFn() {
let start = 0;
const handler = () => {
return (start += 1000);
};
return jest.spyOn(Date, 'now').mockImplementation(handler);
}
dateNowMock = dataNowMockFn();
const scrollToSpy = jest.spyOn(window, 'scrollTo');
let root = document.getElementById('root');
if (!root) {
root = document.createElement('div', { id: 'root' });
root.id = 'root';
document.body.appendChild(root);
}
mount(<h1 id="API">Hello</h1>, { attachTo: root });
const wrapper = mount(
<Anchor>
<Link href="#API" title="API" />
</Anchor>,
);
wrapper.instance().handleScrollTo('#API');
await sleep(20);
expect(scrollToSpy).toHaveBeenLastCalledWith(0, 1000);
dateNowMock = dataNowMockFn();
wrapper.setProps({ offsetTop: 100 });
wrapper.instance().handleScrollTo('#API');
await sleep(20);
expect(scrollToSpy).toHaveBeenLastCalledWith(0, 900);
dateNowMock = dataNowMockFn();
wrapper.setProps({ targetOffset: 200 });
wrapper.instance().handleScrollTo('#API');
await sleep(20);
expect(scrollToSpy).toHaveBeenLastCalledWith(0, 800);
dateNowMock.mockRestore();
});
it('Anchor onChange prop', async () => {
const onChange = jest.fn();
const wrapper = mount(
<Anchor onChange={onChange}>
<Link href="#API1" title="API1" />
<Link href="#API2" title="API2" />
</Anchor>,
);
expect(onChange).toHaveBeenCalledTimes(1);
wrapper.instance().handleScrollTo('#API2');
expect(onChange).toHaveBeenCalledTimes(2);
expect(onChange).toHaveBeenCalledWith('#API2');
});
});

View File

@@ -0,0 +1,469 @@
import React from 'react';
import { mount } from 'enzyme';
import Anchor from '..';
import { sleep } from '../../../tests/utils';
const { Link } = Anchor;
function createGetContainer(id: string) {
return () => {
const container = document.getElementById(id);
if (container == null) {
throw new Error();
}
return container;
};
}
function createDiv() {
const root = document.createElement('div');
document.body.appendChild(root);
return root;
}
let idCounter = 0;
const getHashUrl = () => `Anchor-API-${idCounter++}`;
describe('Anchor Render', () => {
const getBoundingClientRectMock = jest.spyOn(
HTMLHeadingElement.prototype,
'getBoundingClientRect',
);
const getClientRectsMock = jest.spyOn(HTMLHeadingElement.prototype, 'getClientRects');
beforeAll(() => {
getBoundingClientRectMock.mockReturnValue({
width: 100,
height: 100,
top: 1000,
} as DOMRect);
getClientRectsMock.mockReturnValue({ length: 1 } as DOMRectList);
});
afterAll(() => {
getBoundingClientRectMock.mockRestore();
getClientRectsMock.mockRestore();
});
it('Anchor render perfectly', () => {
const hash = getHashUrl();
const wrapper = mount<Anchor>(
<Anchor>
<Link href={`#${hash}`} title={hash} />
</Anchor>,
);
wrapper.find(`a[href="#${hash}"]`).simulate('click');
wrapper.instance().handleScroll();
expect(wrapper.instance().state).not.toBe(null);
});
it('Anchor render perfectly for complete href - click', () => {
const hash = getHashUrl();
const wrapper = mount<Anchor>(
<Anchor>
<Link href={`http://www.example.com/#${hash}`} title={hash} />
</Anchor>,
);
wrapper.find(`a[href="http://www.example.com/#${hash}"]`).simulate('click');
expect(wrapper.instance().state.activeLink).toBe(`http://www.example.com/#${hash}`);
});
it('Anchor render perfectly for complete href - hash router', async () => {
const root = createDiv();
const scrollToSpy = jest.spyOn(window, 'scrollTo');
mount(<div id="/faq?locale=en#Q1">Q1</div>, { attachTo: root });
const wrapper = mount<Anchor>(
<Anchor>
<Link href="/#/faq?locale=en#Q1" title="Q1" />
</Anchor>,
);
wrapper.instance().handleScrollTo('/#/faq?locale=en#Q1');
expect(wrapper.instance().state.activeLink).toBe('/#/faq?locale=en#Q1');
expect(scrollToSpy).not.toHaveBeenCalled();
await sleep(1000);
expect(scrollToSpy).toHaveBeenCalled();
});
it('Anchor render perfectly for complete href - scroll', () => {
const hash = getHashUrl();
const root = createDiv();
mount(<div id={hash}>Hello</div>, { attachTo: root });
const wrapper = mount<Anchor>(
<Anchor>
<Link href={`http://www.example.com/#${hash}`} title={hash} />
</Anchor>,
);
wrapper.instance().handleScroll();
expect(wrapper.instance().state.activeLink).toBe(`http://www.example.com/#${hash}`);
});
it('Anchor render perfectly for complete href - scrollTo', async () => {
const hash = getHashUrl();
const scrollToSpy = jest.spyOn(window, 'scrollTo');
const root = createDiv();
mount(<div id={`#${hash}`}>Hello</div>, { attachTo: root });
const wrapper = mount<Anchor>(
<Anchor>
<Link href={`##${hash}`} title={hash} />
</Anchor>,
);
wrapper.instance().handleScrollTo(`##${hash}`);
expect(wrapper.instance().state.activeLink).toBe(`##${hash}`);
const calls = scrollToSpy.mock.calls.length;
await sleep(1000);
expect(scrollToSpy.mock.calls.length).toBeGreaterThan(calls);
});
it('should remove listener when unmount', async () => {
const hash = getHashUrl();
const wrapper = mount<Anchor>(
<Anchor>
<Link href={`#${hash}`} title={hash} />
</Anchor>,
);
const removeListenerSpy = jest.spyOn((wrapper.instance() as any).scrollEvent, 'remove');
wrapper.unmount();
expect(removeListenerSpy).toHaveBeenCalled();
});
it('should unregister link when unmount children', async () => {
const hash = getHashUrl();
const wrapper = mount<Anchor>(
<Anchor>
<Link href={`#${hash}`} title={hash} />
</Anchor>,
);
expect((wrapper.instance() as any).links).toEqual([`#${hash}`]);
wrapper.setProps({ children: null });
expect((wrapper.instance() as any).links).toEqual([]);
});
it('should update links when link href update', async () => {
const hash = getHashUrl();
let anchorInstance: Anchor | null = null;
function AnchorUpdate({ href }: { href: string }) {
return (
<Anchor
ref={c => {
anchorInstance = c;
}}
>
<Link href={href} title={hash} />
</Anchor>
);
}
const wrapper = mount(<AnchorUpdate href={`#${hash}`} />);
if (anchorInstance == null) {
throw new Error('anchorInstance should not be null');
}
expect((anchorInstance as any).links).toEqual([`#${hash}`]);
wrapper.setProps({ href: `#${hash}_1` });
expect((anchorInstance as any).links).toEqual([`#${hash}_1`]);
});
it('Anchor onClick event', () => {
const hash = getHashUrl();
let event;
let link;
const handleClick = (
e: React.MouseEvent<HTMLElement>,
_link: { title: React.ReactNode; href: string },
) => {
event = e;
link = _link;
};
const href = `#${hash}`;
const title = hash;
const wrapper = mount<Anchor>(
<Anchor onClick={handleClick}>
<Link href={href} title={title} />
</Anchor>,
);
wrapper.find(`a[href="${href}"]`).simulate('click');
wrapper.instance().handleScroll();
expect(event).not.toBe(undefined);
expect(link).toEqual({ href, title });
});
it('Different function returns the same DOM', async () => {
const hash = getHashUrl();
const root = createDiv();
mount(<div id={hash}>Hello</div>, { attachTo: root });
const getContainerA = createGetContainer(hash);
const getContainerB = createGetContainer(hash);
const wrapper = mount<Anchor>(
<Anchor getContainer={getContainerA}>
<Link href={`#${hash}`} title={hash} />
</Anchor>,
);
const removeListenerSpy = jest.spyOn((wrapper.instance() as any).scrollEvent, 'remove');
await sleep(1000);
wrapper.setProps({ getContainer: getContainerB });
expect(removeListenerSpy).not.toHaveBeenCalled();
});
it('Different function returns different DOM', async () => {
const hash1 = getHashUrl();
const hash2 = getHashUrl();
const root = createDiv();
mount(
<div>
<div id={hash1}>Hello</div>
<div id={hash2}>World</div>
</div>,
{ attachTo: root },
);
const getContainerA = createGetContainer(hash1);
const getContainerB = createGetContainer(hash2);
const wrapper = mount<Anchor>(
<Anchor getContainer={getContainerA}>
<Link href={`#${hash1}`} title={hash1} />
<Link href={`#${hash2}`} title={hash2} />
</Anchor>,
);
const removeListenerSpy = jest.spyOn((wrapper.instance() as any).scrollEvent, 'remove');
expect(removeListenerSpy).not.toHaveBeenCalled();
await sleep(1000);
wrapper.setProps({ getContainer: getContainerB });
expect(removeListenerSpy).toHaveBeenCalled();
});
it('Same function returns the same DOM', () => {
const hash = getHashUrl();
const root = createDiv();
mount(<div id={hash}>Hello</div>, { attachTo: root });
const getContainer = createGetContainer(hash);
const wrapper = mount(
<Anchor getContainer={getContainer}>
<Link href={`#${hash}`} title={hash} />
</Anchor>,
);
wrapper.find(`a[href="#${hash}"]`).simulate('click');
(wrapper.instance() as any).handleScroll();
expect(wrapper.instance().state).not.toBe(null);
});
it('Same function returns different DOM', async () => {
const hash1 = getHashUrl();
const hash2 = getHashUrl();
const root = createDiv();
mount(
<div>
<div id={hash1}>Hello</div>
<div id={hash2}>World</div>
</div>,
{ attachTo: root },
);
const holdContainer = {
container: document.getElementById(hash1),
};
const getContainer = () => {
if (holdContainer.container == null) {
throw new Error('container should not be null');
}
return holdContainer.container;
};
const wrapper = mount(
<Anchor getContainer={getContainer}>
<Link href={`#${hash1}`} title={hash1} />
<Link href={`#${hash2}`} title={hash2} />
</Anchor>,
);
const removeListenerSpy = jest.spyOn((wrapper.instance() as any).scrollEvent, 'remove');
expect(removeListenerSpy).not.toHaveBeenCalled();
await sleep(1000);
holdContainer.container = document.getElementById(hash2);
wrapper.setProps({ 'data-only-trigger-re-render': true });
expect(removeListenerSpy).toHaveBeenCalled();
});
it('Anchor getCurrentAnchor prop', () => {
const hash1 = getHashUrl();
const hash2 = getHashUrl();
const getCurrentAnchor = () => `#${hash2}`;
const wrapper = mount<Anchor>(
<Anchor getCurrentAnchor={getCurrentAnchor}>
<Link href={`#${hash1}`} title={hash1} />
<Link href={`#${hash2}`} title={hash2} />
</Anchor>,
);
expect(wrapper.instance().state.activeLink).toBe(`#${hash2}`);
});
it('Anchor targetOffset prop', async () => {
const hash = getHashUrl();
let dateNowMock;
function dataNowMockFn() {
let start = 0;
const handler = () => {
return (start += 1000);
};
return jest.spyOn(Date, 'now').mockImplementation(handler);
}
dateNowMock = dataNowMockFn();
const scrollToSpy = jest.spyOn(window, 'scrollTo');
const root = createDiv();
mount(<h1 id={hash}>Hello</h1>, { attachTo: root });
const wrapper = mount<Anchor>(
<Anchor>
<Link href={`#${hash}`} title={hash} />
</Anchor>,
);
wrapper.instance().handleScrollTo(`#${hash}`);
await sleep(30);
expect(scrollToSpy).toHaveBeenLastCalledWith(0, 1000);
dateNowMock = dataNowMockFn();
wrapper.setProps({ offsetTop: 100 });
wrapper.instance().handleScrollTo(`#${hash}`);
await sleep(30);
expect(scrollToSpy).toHaveBeenLastCalledWith(0, 900);
dateNowMock = dataNowMockFn();
wrapper.setProps({ targetOffset: 200 });
wrapper.instance().handleScrollTo(`#${hash}`);
await sleep(30);
expect(scrollToSpy).toHaveBeenLastCalledWith(0, 800);
dateNowMock.mockRestore();
});
it('Anchor onChange prop', async () => {
const hash1 = getHashUrl();
const hash2 = getHashUrl();
const onChange = jest.fn();
const wrapper = mount<Anchor>(
<Anchor onChange={onChange}>
<Link href={`#${hash1}`} title={hash1} />
<Link href={`#${hash2}`} title={hash2} />
</Anchor>,
);
expect(onChange).toHaveBeenCalledTimes(1);
wrapper.instance().handleScrollTo(hash2);
expect(onChange).toHaveBeenCalledTimes(2);
expect(onChange).toHaveBeenCalledWith(hash2);
});
it('invalid hash', async () => {
const wrapper = mount<Anchor>(
<Anchor>
<Link href="notexsited" title="title" />
</Anchor>,
);
wrapper.find(`a[href="notexsited"]`).simulate('click');
wrapper.instance().handleScrollTo('notexsited');
expect(wrapper.instance().state).not.toBe(null);
});
it('test edge case when getBoundingClientRect return zero size', async () => {
getBoundingClientRectMock.mockReturnValue({
width: 0,
height: 0,
top: 1000,
} as DOMRect);
const hash = getHashUrl();
let dateNowMock;
function dataNowMockFn() {
let start = 0;
const handler = () => {
return (start += 1000);
};
return jest.spyOn(Date, 'now').mockImplementation(handler);
}
dateNowMock = dataNowMockFn();
const scrollToSpy = jest.spyOn(window, 'scrollTo');
const root = createDiv();
mount(<h1 id={hash}>Hello</h1>, { attachTo: root });
const wrapper = mount<Anchor>(
<Anchor>
<Link href={`#${hash}`} title={hash} />
</Anchor>,
);
wrapper.instance().handleScrollTo(`#${hash}`);
await sleep(30);
expect(scrollToSpy).toHaveBeenLastCalledWith(0, 1000);
dateNowMock = dataNowMockFn();
wrapper.setProps({ offsetTop: 100 });
wrapper.instance().handleScrollTo(`#${hash}`);
await sleep(30);
expect(scrollToSpy).toHaveBeenLastCalledWith(0, 900);
dateNowMock = dataNowMockFn();
wrapper.setProps({ targetOffset: 200 });
wrapper.instance().handleScrollTo(`#${hash}`);
await sleep(30);
expect(scrollToSpy).toHaveBeenLastCalledWith(0, 800);
dateNowMock.mockRestore();
getBoundingClientRectMock.mockReturnValue({
width: 100,
height: 100,
top: 1000,
} as DOMRect);
});
it('test edge case when container is not windows', async () => {
const hash = getHashUrl();
let dateNowMock;
function dataNowMockFn() {
let start = 0;
const handler = () => {
return (start += 1000);
};
return jest.spyOn(Date, 'now').mockImplementation(handler);
}
dateNowMock = dataNowMockFn();
const scrollToSpy = jest.spyOn(window, 'scrollTo');
const root = createDiv();
mount(<h1 id={hash}>Hello</h1>, { attachTo: root });
const wrapper = mount<Anchor>(
<Anchor getContainer={() => document.body}>
<Link href={`#${hash}`} title={hash} />
</Anchor>,
);
wrapper.instance().handleScrollTo(`#${hash}`);
await sleep(30);
expect(scrollToSpy).toHaveBeenLastCalledWith(0, 800);
dateNowMock = dataNowMockFn();
wrapper.setProps({ offsetTop: 100 });
wrapper.instance().handleScrollTo(`#${hash}`);
await sleep(30);
expect(scrollToSpy).toHaveBeenLastCalledWith(0, 800);
dateNowMock = dataNowMockFn();
wrapper.setProps({ targetOffset: 200 });
wrapper.instance().handleScrollTo(`#${hash}`);
await sleep(30);
expect(scrollToSpy).toHaveBeenLastCalledWith(0, 800);
dateNowMock.mockRestore();
});
});

View File

@@ -0,0 +1,6 @@
import * as React from 'react';
import { AntAnchor } from './Anchor';
const AnchorContext = React.createContext<AntAnchor>(null as any);
export default AnchorContext;

View File

@@ -52,7 +52,7 @@
}
&-link {
padding: 7px 0 7px 16px;
padding: @anchor-link-padding;
line-height: 1.143;
&-title {

View File

@@ -1,7 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders ./components/auto-complete/demo/basic.md correctly 1`] = `
<div>
Array [
<div
class="ant-select ant-select-auto-complete ant-select-single ant-select-show-search"
style="width:200px"
@@ -30,9 +30,9 @@ exports[`renders ./components/auto-complete/demo/basic.md correctly 1`] = `
input here
</span>
</div>
</div>
<br />
<br />
</div>,
<br />,
<br />,
<div
class="ant-select ant-select-auto-complete ant-select-single ant-select-show-search"
style="width:200px"
@@ -61,8 +61,8 @@ exports[`renders ./components/auto-complete/demo/basic.md correctly 1`] = `
control mode
</span>
</div>
</div>
</div>
</div>,
]
`;
exports[`renders ./components/auto-complete/demo/certain-category.md correctly 1`] = `

View File

@@ -1,6 +1,86 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`AutoComplete with Custom Input Element Render rtl render component should be rendered correctly in RTL direction 1`] = `
exports[`AutoComplete legacy dataSource should accept react element option 1`] = `
<div
class="ant-select ant-select-auto-complete ant-select-single ant-select-open ant-select-show-search"
>
<div
class="ant-select-selector"
>
<span
class="ant-select-selection-search"
>
<input
aria-activedescendant="undefined_list_0"
aria-autocomplete="list"
aria-controls="undefined_list"
aria-expanded="true"
aria-haspopup="listbox"
aria-owns="undefined_list"
autocomplete="off"
class="ant-select-selection-search-input"
role="combobox"
value=""
/>
</span>
<span
class="ant-select-selection-placeholder"
/>
</div>
<div>
<div
class="ant-select-dropdown"
style="opacity:0"
>
<div>
<div
id="undefined_list"
role="listbox"
style="height:0;width:0;overflow:hidden"
>
<div
aria-selected="false"
id="undefined_list_0"
role="option"
>
key
</div>
</div>
<div
class=""
style="height:256px"
>
<div>
<div
class=""
style="display:flex;flex-direction:column"
>
<div
aria-selected="false"
class="ant-select-item ant-select-item-option ant-select-item-option-active"
>
<div
class="ant-select-item-option-content"
>
ReactNode
</div>
<span
aria-hidden="true"
class="ant-select-item-option-state"
style="user-select:none;-webkit-user-select:none"
unselectable="on"
/>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
`;
exports[`AutoComplete rtl render component should be rendered correctly in RTL direction 1`] = `
<div
class="ant-select ant-select-auto-complete ant-select-rtl ant-select-single ant-select-show-search"
>

View File

@@ -4,7 +4,7 @@ import AutoComplete from '..';
import mountTest from '../../../tests/shared/mountTest';
import rtlTest from '../../../tests/shared/rtlTest';
describe('AutoComplete with Custom Input Element Render', () => {
describe('AutoComplete', () => {
mountTest(AutoComplete);
rtlTest(AutoComplete);
@@ -52,4 +52,21 @@ describe('AutoComplete with Custom Input Element Render', () => {
// eslint-disable-next-line no-console
console.error.mockRestore();
});
it('legacy dataSource should accept react element option', () => {
const wrapper = mount(<AutoComplete open dataSource={[<span key="key">ReactNode</span>]} />);
expect(wrapper).toMatchRenderedSnapshot();
});
it('legacy AutoComplete.Option should be compatiable', () => {
const wrapper = mount(
<AutoComplete>
<AutoComplete.Option value="111">111</AutoComplete.Option>
<AutoComplete.Option value="222">222</AutoComplete.Option>
</AutoComplete>,
);
expect(wrapper.find('input').length).toBe(1);
wrapper.find('input').simulate('change', { target: { value: '1' } });
expect(wrapper.find('.ant-select-item-option').length).toBe(2);
});
});

View File

@@ -37,7 +37,7 @@ const Complete: React.FC = () => {
setValue(data);
};
return (
<div>
<>
<AutoComplete
options={options}
style={{ width: 200 }}
@@ -56,7 +56,7 @@ const Complete: React.FC = () => {
onChange={onChange}
placeholder="control mode"
/>
</div>
</>
);
};

View File

@@ -67,18 +67,16 @@ const options = [
},
];
const Complete: React.FC = () => {
return (
<AutoComplete
dropdownClassName="certain-category-search-dropdown"
dropdownMatchSelectWidth={500}
style={{ width: 250 }}
options={options}
>
<Input.Search size="large" placeholder="input here" />
</AutoComplete>
);
};
const Complete: React.FC = () => (
<AutoComplete
dropdownClassName="certain-category-search-dropdown"
dropdownMatchSelectWidth={500}
style={{ width: 250 }}
options={options}
>
<Input.Search size="large" placeholder="input here" />
</AutoComplete>
);
ReactDOM.render(<Complete />, mountNode);
```

View File

@@ -22,25 +22,25 @@ const formItemLayout = {
};
ReactDOM.render(
<Form style={{ margin: '0 auto' }}>
<Form.Item label="单独 AutoComplete" {...formItemLayout}>
<Form style={{ margin: '0 auto' }} {...formItemLayout}>
<Form.Item label="单独 AutoComplete">
<AutoComplete />
</Form.Item>
<Form.Item label="单独 TreeSelect" {...formItemLayout}>
<Form.Item label="单独 TreeSelect">
<TreeSelect />
</Form.Item>
<Form.Item label="添加 Input.Group 正常" {...formItemLayout}>
<Form.Item label="添加 Input.Group 正常">
<Input.Group compact>
<TreeSelect style={{ width: '30%' }} />
<AutoComplete />
</Input.Group>
</Form.Item>
<Form.Item label="包含 search 图标正常" {...formItemLayout}>
<Form.Item label="包含 search 图标正常">
<AutoComplete>
<Input suffix={<SearchOutlined />} />
</AutoComplete>
</Form.Item>
<Form.Item label="同时有 Input.Group 和图标发生移位" {...formItemLayout}>
<Form.Item label="同时有 Input.Group 和图标发生移位">
<Input.Group compact>
<TreeSelect style={{ width: '30%' }} />
<AutoComplete>
@@ -48,7 +48,7 @@ ReactDOM.render(
</AutoComplete>
</Input.Group>
</Form.Item>
<Form.Item label="同时有 Input.Group 和 Search 组件发生移位" {...formItemLayout}>
<Form.Item label="同时有 Input.Group 和 Search 组件发生移位">
<Input.Group compact>
<TreeSelect style={{ width: '30%' }} />
<AutoComplete>
@@ -56,7 +56,7 @@ ReactDOM.render(
</AutoComplete>
</Input.Group>
</Form.Item>
<Form.Item label="Input Group 和 Button 结合" {...formItemLayout}>
<Form.Item label="Input Group 和 Button 结合">
<Input.Group compact>
<TreeSelect style={{ width: '20%' }} />
<AutoComplete>

View File

@@ -22,18 +22,16 @@ const options = [
{ value: 'Wall Street' },
];
const Complete: React.FC = () => {
return (
<AutoComplete
style={{ width: 200 }}
options={options}
placeholder="try to type `b`"
filterOption={(inputValue, option) =>
option.value.toUpperCase().indexOf(inputValue.toUpperCase()) !== -1
}
/>
);
}
const Complete: React.FC = () => (
<AutoComplete
style={{ width: 200 }}
options={options}
placeholder="try to type `b`"
filterOption={(inputValue, option) =>
option.value.toUpperCase().indexOf(inputValue.toUpperCase()) !== -1
}
/>
);
ReactDOM.render(<Complete />, mountNode);
```

View File

@@ -30,14 +30,13 @@ const Complete: React.FC = () => {
}
setResult(res);
};
const children = result.map((email: string) => (
<Option key={email} value={email}>
{email}
</Option>
));
return (
<AutoComplete style={{ width: 200 }} onSearch={handleSearch} placeholder="input here">
{children}
{result.map((email: string) => (
<Option key={email} value={email}>
{email}
</Option>
))}
</AutoComplete>
);
};

View File

@@ -34,6 +34,7 @@ When there is a need for autocomplete functionality.
| defaultOpen | Initial open state of dropdown | boolean | - | |
| open | Controlled open state of dropdown | boolean | - | |
| onDropdownVisibleChange | Call when dropdown open | function(open) | - | |
| notFoundContent | Specify content to show when no result matches.. | string | 'Not Found' | |
## Methods

View File

@@ -36,6 +36,7 @@ title: AutoComplete
| defaultOpen | 是否默认展开下拉菜单 | boolean | - | |
| open | 是否展开下拉菜单 | boolean | - | |
| onDropdownVisibleChange | 展开下拉菜单的回调 | function(open) | - | |
| notFoundContent | 当下拉列表为空时显示的内容 | ReactNode | - | |
## 方法

View File

@@ -41,4 +41,8 @@ ReactDOM.render(
margin-top: 16px;
margin-right: 16px;
}
.ant-row-rtl #components-avatar-demo-basic .ant-avatar {
margin-right: 0;
margin-left: 16px;
}
</style>

View File

@@ -35,4 +35,8 @@ ReactDOM.render(
margin-top: 16px;
margin-right: 16px;
}
.ant-row-rtl #components-avatar-demo-type .ant-avatar {
margin-right: 0;
margin-left: 16px;
}
</style>

View File

@@ -50,73 +50,50 @@ export interface ScrollNumberState {
count?: string | number | null;
}
class ScrollNumber extends React.Component<ScrollNumberProps, ScrollNumberState> {
static defaultProps = {
count: null,
onAnimated() {},
};
const ScrollNumber: React.FC<ScrollNumberProps> = props => {
const [animateStarted, setAnimateStarted] = React.useState(true);
const [count, setCount] = React.useState(props.count);
const [prevCount, setPrevCount] = React.useState(props.count);
const [lastCount, setLastCount] = React.useState(props.count);
static getDerivedStateFromProps(nextProps: ScrollNumberProps, nextState: ScrollNumberState) {
if ('count' in nextProps) {
if (nextState.count === nextProps.count) {
return null;
}
return {
animateStarted: true,
};
}
return null;
if (prevCount !== props.count) {
setAnimateStarted(true);
setPrevCount(props.count);
}
lastCount?: string | number | null;
private timeout?: number;
constructor(props: ScrollNumberProps) {
super(props);
this.state = {
animateStarted: true,
count: props.count,
};
}
componentDidUpdate(_: any, prevState: ScrollNumberState) {
this.lastCount = prevState.count;
const { animateStarted } = this.state;
React.useEffect(() => {
setLastCount(count);
let timeout: number;
if (animateStarted) {
this.clearTimeout();
// Let browser has time to reset the scroller before actually
// performing the transition.
this.timeout = setTimeout(() => {
// eslint-disable-next-line react/no-did-update-set-state
this.setState(
(__, props) => ({
animateStarted: false,
count: props.count,
}),
this.onAnimated,
);
timeout = setTimeout(() => {
setAnimateStarted(false);
setCount(props.count);
if (props.onAnimated) {
props.onAnimated();
}
});
}
}
return () => {
if (timeout) {
clearTimeout(timeout);
}
};
}, [animateStarted, count, props.count, props.onAnimated]);
componentWillUnmount() {
this.clearTimeout();
}
getPositionByNum(num: number, i: number) {
const { count } = this.state;
const getPositionByNum = (num: number, i: number) => {
const currentCount = Math.abs(Number(count));
const lastCount = Math.abs(Number(this.lastCount));
const currentDigit = Math.abs(getNumberArray(this.state.count)[i] as number);
const lastDigit = Math.abs(getNumberArray(this.lastCount)[i] as number);
const lstCount = Math.abs(Number(lastCount));
const currentDigit = Math.abs(getNumberArray(count)[i] as number);
const lastDigit = Math.abs(getNumberArray(lstCount)[i] as number);
if (this.state.animateStarted) {
if (animateStarted) {
return 10 + num;
}
// 同方向则在同一侧切换数字
if (currentCount > lastCount) {
if (currentCount > lstCount) {
if (currentDigit >= lastDigit) {
return 10 + num;
}
@@ -126,20 +103,12 @@ class ScrollNumber extends React.Component<ScrollNumberProps, ScrollNumberState>
return 10 + num;
}
return num;
}
onAnimated = () => {
const { onAnimated } = this.props;
if (onAnimated) {
onAnimated();
}
};
renderCurrentNumber(prefixCls: string, num: number | string, i: number) {
const renderCurrentNumber = (prefixCls: string, num: number | string, i: number) => {
if (typeof num === 'number') {
const position = this.getPositionByNum(num, i);
const removeTransition =
this.state.animateStarted || getNumberArray(this.lastCount)[i] === undefined;
const position = getPositionByNum(num, i);
const removeTransition = animateStarted || getNumberArray(lastCount)[i] === undefined;
return React.createElement(
'span',
{
@@ -161,19 +130,18 @@ class ScrollNumber extends React.Component<ScrollNumberProps, ScrollNumberState>
{num}
</span>
);
}
};
renderNumberElement(prefixCls: string) {
const { count } = this.state;
const renderNumberElement = (prefixCls: string) => {
if (count && Number(count) % 1 === 0) {
return getNumberArray(count)
.map((num, i) => this.renderCurrentNumber(prefixCls, num, i))
.map((num, i) => renderCurrentNumber(prefixCls, num, i))
.reverse();
}
return count;
}
};
renderScrollNumber = ({ getPrefixCls }: ConfigConsumerProps) => {
const renderScrollNumber = ({ getPrefixCls }: ConfigConsumerProps) => {
const {
prefixCls: customizePrefixCls,
className,
@@ -181,9 +149,9 @@ class ScrollNumber extends React.Component<ScrollNumberProps, ScrollNumberState>
title,
component = 'sup',
displayComponent,
} = this.props;
} = props;
// fix https://fb.me/react-unknown-prop
const restProps = omit(this.props, [
const restProps = omit(props, [
'count',
'onAnimated',
'component',
@@ -214,19 +182,15 @@ class ScrollNumber extends React.Component<ScrollNumberProps, ScrollNumberState>
),
});
}
return React.createElement(component as any, newProps, this.renderNumberElement(prefixCls));
return React.createElement(component as any, newProps, renderNumberElement(prefixCls));
};
render() {
return <ConfigConsumer>{this.renderScrollNumber}</ConfigConsumer>;
}
return <ConfigConsumer>{renderScrollNumber}</ConfigConsumer>;
};
private clearTimeout(): void {
if (this.timeout) {
clearTimeout(this.timeout);
this.timeout = undefined;
}
}
}
ScrollNumber.defaultProps = {
count: null,
onAnimated() {},
};
export default ScrollNumber;

View File

@@ -32,40 +32,47 @@ function isPresetColor(color?: string): boolean {
return (PresetColorTypes as any[]).indexOf(color) !== -1;
}
export default class Badge extends React.Component<BadgeProps, any> {
static defaultProps = {
count: null,
showZero: false,
dot: false,
overflowCount: 99,
};
getNumberedDisplayCount() {
const { count, overflowCount } = this.props;
const Badge: React.FC<BadgeProps> = props => {
const getNumberedDisplayCount = () => {
const { count, overflowCount } = props;
const displayCount =
(count as number) > (overflowCount as number) ? `${overflowCount}+` : count;
return displayCount as string | number | null;
}
};
getDisplayCount() {
const isDot = this.isDot();
const hasStatus = (): boolean => {
const { status, color } = props;
return !!status || !!color;
};
const isZero = () => {
const numberedDisplayCount = getNumberedDisplayCount();
return numberedDisplayCount === '0' || numberedDisplayCount === 0;
};
const isDot = () => {
const { dot } = props;
return (dot && !isZero()) || hasStatus();
};
const getDisplayCount = () => {
// dot mode don't need count
if (isDot) {
if (isDot()) {
return '';
}
return this.getNumberedDisplayCount();
}
return getNumberedDisplayCount();
};
getScrollNumberTitle() {
const { title, count } = this.props;
const getScrollNumberTitle = () => {
const { title, count } = props;
if (title) {
return title;
}
return typeof count === 'string' || typeof count === 'number' ? count : undefined;
}
};
getStyleWithOffset() {
const { offset, style } = this.props;
const getStyleWithOffset = () => {
const { offset, style } = props;
return offset
? {
right: -parseInt(offset[0] as string, 10),
@@ -73,79 +80,61 @@ export default class Badge extends React.Component<BadgeProps, any> {
...style,
}
: style;
}
};
getBadgeClassName(prefixCls: string, direction: string = 'ltr') {
const { className, children } = this.props;
const getBadgeClassName = (prefixCls: string, direction: string = 'ltr') => {
const { className, children } = props;
return classNames(className, prefixCls, {
[`${prefixCls}-status`]: this.hasStatus(),
[`${prefixCls}-status`]: hasStatus(),
[`${prefixCls}-not-a-wrapper`]: !children,
[`${prefixCls}-rtl`]: direction === 'rtl',
}) as string;
}
};
hasStatus(): boolean {
const { status, color } = this.props;
return !!status || !!color;
}
isZero() {
const numberedDisplayCount = this.getNumberedDisplayCount();
return numberedDisplayCount === '0' || numberedDisplayCount === 0;
}
isDot() {
const { dot } = this.props;
const isZero = this.isZero();
return (dot && !isZero) || this.hasStatus();
}
isHidden() {
const { showZero } = this.props;
const displayCount = this.getDisplayCount();
const isZero = this.isZero();
const isDot = this.isDot();
const isHidden = () => {
const { showZero } = props;
const displayCount = getDisplayCount();
const isEmpty = displayCount === null || displayCount === undefined || displayCount === '';
return (isEmpty || (isZero && !showZero)) && !isDot;
}
return (isEmpty || (isZero() && !showZero)) && !isDot();
};
renderStatusText(prefixCls: string) {
const { text } = this.props;
const hidden = this.isHidden();
const renderStatusText = (prefixCls: string) => {
const { text } = props;
const hidden = isHidden();
return hidden || !text ? null : <span className={`${prefixCls}-status-text`}>{text}</span>;
}
};
renderDisplayComponent() {
const { count } = this.props;
const renderDisplayComponent = () => {
const { count } = props;
const customNode = count as React.ReactElement<any>;
if (!customNode || typeof customNode !== 'object') {
return undefined;
}
return React.cloneElement(customNode, {
style: {
...this.getStyleWithOffset(),
...getStyleWithOffset(),
...(customNode.props && customNode.props.style),
},
});
}
};
renderBadgeNumber(prefixCls: string, scrollNumberPrefixCls: string) {
const { status, count, color } = this.props;
const renderBadgeNumber = (prefixCls: string, scrollNumberPrefixCls: string) => {
const { status, count, color } = props;
const displayCount = this.getDisplayCount();
const isDot = this.isDot();
const hidden = this.isHidden();
const displayCount = getDisplayCount();
const dot = isDot();
const hidden = isHidden();
const scrollNumberCls = classNames({
[`${prefixCls}-dot`]: isDot,
[`${prefixCls}-count`]: !isDot,
[`${prefixCls}-dot`]: dot,
[`${prefixCls}-count`]: !dot,
[`${prefixCls}-multiple-words`]:
!isDot && count && count.toString && count.toString().length > 1,
!dot && count && count.toString && count.toString().length > 1,
[`${prefixCls}-status-${status}`]: !!status,
[`${prefixCls}-status-${color}`]: isPresetColor(color),
});
let statusStyle: React.CSSProperties | undefined = this.getStyleWithOffset();
let statusStyle: React.CSSProperties | undefined = getStyleWithOffset();
if (color && !isPresetColor(color)) {
statusStyle = statusStyle || {};
statusStyle.background = color;
@@ -157,15 +146,15 @@ export default class Badge extends React.Component<BadgeProps, any> {
data-show={!hidden}
className={scrollNumberCls}
count={displayCount}
displayComponent={this.renderDisplayComponent()} // <Badge status="success" count={<Icon type="xxx" />}></Badge>
title={this.getScrollNumberTitle()}
displayComponent={renderDisplayComponent()} // <Badge status="success" count={<Icon type="xxx" />}></Badge>
title={getScrollNumberTitle()}
style={statusStyle}
key="scrollNumber"
/>
);
}
};
renderBadge = ({ getPrefixCls, direction }: ConfigConsumerProps) => {
const renderBadge = ({ getPrefixCls, direction }: ConfigConsumerProps) => {
const {
prefixCls: customizePrefixCls,
scrollNumberPrefixCls: customizeScrollNumberPrefixCls,
@@ -174,7 +163,7 @@ export default class Badge extends React.Component<BadgeProps, any> {
text,
color,
...restProps
} = this.props;
} = props;
const omitArr = [
'count',
'showZero',
@@ -189,11 +178,11 @@ export default class Badge extends React.Component<BadgeProps, any> {
const prefixCls = getPrefixCls('badge', customizePrefixCls);
const scrollNumberPrefixCls = getPrefixCls('scroll-number', customizeScrollNumberPrefixCls);
const scrollNumber = this.renderBadgeNumber(prefixCls, scrollNumberPrefixCls);
const statusText = this.renderStatusText(prefixCls);
const scrollNumber = renderBadgeNumber(prefixCls, scrollNumberPrefixCls);
const statusText = renderStatusText(prefixCls);
const statusCls = classNames({
[`${prefixCls}-status-dot`]: this.hasStatus(),
[`${prefixCls}-status-dot`]: hasStatus(),
[`${prefixCls}-status-${status}`]: !!status,
[`${prefixCls}-status-${color}`]: isPresetColor(color),
});
@@ -203,13 +192,13 @@ export default class Badge extends React.Component<BadgeProps, any> {
}
// <Badge status="success" />
if (!children && this.hasStatus()) {
const styleWithOffset = this.getStyleWithOffset();
if (!children && hasStatus()) {
const styleWithOffset = getStyleWithOffset();
const statusTextColor = styleWithOffset && styleWithOffset.color;
return (
<span
{...omit(restProps, omitArr)}
className={this.getBadgeClassName(prefixCls, direction)}
className={getBadgeClassName(prefixCls, direction)}
style={styleWithOffset}
>
<span className={statusCls} style={statusStyle} />
@@ -221,7 +210,7 @@ export default class Badge extends React.Component<BadgeProps, any> {
}
return (
<span {...omit(restProps, omitArr)} className={this.getBadgeClassName(prefixCls, direction)}>
<span {...omit(restProps, omitArr)} className={getBadgeClassName(prefixCls, direction)}>
{children}
<Animate
component=""
@@ -236,7 +225,14 @@ export default class Badge extends React.Component<BadgeProps, any> {
);
};
render() {
return <ConfigConsumer>{this.renderBadge}</ConfigConsumer>;
}
}
return <ConfigConsumer>{renderBadge}</ConfigConsumer>;
};
Badge.defaultProps = {
count: null,
showZero: false,
dot: false,
overflowCount: 99,
};
export default Badge;

View File

@@ -531,8 +531,66 @@ exports[`renders ./components/button/demo/legacy-group.md correctly 1`] = `
Button 2
</span>
</button>
<span
class="ant-tooltip-disabled-compatible-wrapper"
style="display:inline-block;cursor:not-allowed"
>
<button
class="ant-btn ant-btn-primary ant-btn-icon-only"
disabled=""
style="pointer-events:none"
type="button"
>
<span
aria-label="download"
class="anticon anticon-download"
role="img"
>
<svg
aria-hidden="true"
class=""
data-icon="download"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M505.7 661a8 8 0 0012.6 0l112-141.7c4.1-5.2.4-12.9-6.3-12.9h-74.1V168c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v338.3H400c-6.7 0-10.4 7.7-6.3 12.9l112 141.8zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"
/>
</svg>
</span>
</button>
</span>
<button
class="ant-btn ant-btn-primary ant-btn-icon-only"
type="button"
>
<span
aria-label="download"
class="anticon anticon-download"
role="img"
>
<svg
aria-hidden="true"
class=""
data-icon="download"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M505.7 661a8 8 0 0012.6 0l112-141.7c4.1-5.2.4-12.9-6.3-12.9h-74.1V168c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v338.3H400c-6.7 0-10.4 7.7-6.3 12.9l112 141.8zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"
/>
</svg>
</span>
</button>
</div>
</div>
<br />
<div>
<div
class="ant-btn-group"
@@ -553,8 +611,66 @@ exports[`renders ./components/button/demo/legacy-group.md correctly 1`] = `
Button 2
</span>
</button>
<span
class="ant-tooltip-disabled-compatible-wrapper"
style="display:inline-block;cursor:not-allowed"
>
<button
class="ant-btn ant-btn-primary ant-btn-icon-only"
disabled=""
style="pointer-events:none"
type="button"
>
<span
aria-label="download"
class="anticon anticon-download"
role="img"
>
<svg
aria-hidden="true"
class=""
data-icon="download"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M505.7 661a8 8 0 0012.6 0l112-141.7c4.1-5.2.4-12.9-6.3-12.9h-74.1V168c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v338.3H400c-6.7 0-10.4 7.7-6.3 12.9l112 141.8zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"
/>
</svg>
</span>
</button>
</span>
<button
class="ant-btn ant-btn-primary ant-btn-icon-only"
type="button"
>
<span
aria-label="download"
class="anticon anticon-download"
role="img"
>
<svg
aria-hidden="true"
class=""
data-icon="download"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M505.7 661a8 8 0 0012.6 0l112-141.7c4.1-5.2.4-12.9-6.3-12.9h-74.1V168c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v338.3H400c-6.7 0-10.4 7.7-6.3 12.9l112 141.8zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"
/>
</svg>
</span>
</button>
</div>
</div>
<br />
<div>
<div
class="ant-btn-group ant-btn-group-lg"
@@ -575,13 +691,70 @@ exports[`renders ./components/button/demo/legacy-group.md correctly 1`] = `
Button 2
</span>
</button>
<span
class="ant-tooltip-disabled-compatible-wrapper"
style="display:inline-block;cursor:not-allowed"
>
<button
class="ant-btn ant-btn-primary ant-btn-icon-only"
disabled=""
style="pointer-events:none"
type="button"
>
<span
aria-label="download"
class="anticon anticon-download"
role="img"
>
<svg
aria-hidden="true"
class=""
data-icon="download"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M505.7 661a8 8 0 0012.6 0l112-141.7c4.1-5.2.4-12.9-6.3-12.9h-74.1V168c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v338.3H400c-6.7 0-10.4 7.7-6.3 12.9l112 141.8zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"
/>
</svg>
</span>
</button>
</span>
<button
class="ant-btn ant-btn-primary ant-btn-icon-only"
type="button"
>
<span
aria-label="download"
class="anticon anticon-download"
role="img"
>
<svg
aria-hidden="true"
class=""
data-icon="download"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M505.7 661a8 8 0 0012.6 0l112-141.7c4.1-5.2.4-12.9-6.3-12.9h-74.1V168c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v338.3H400c-6.7 0-10.4 7.7-6.3 12.9l112 141.8zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"
/>
</svg>
</span>
</button>
</div>
</div>
</div>
`;
exports[`renders ./components/button/demo/loading.md correctly 1`] = `
<div>
Array [
<button
class="ant-btn ant-btn-primary ant-btn-loading"
type="button"
@@ -613,7 +786,7 @@ exports[`renders ./components/button/demo/loading.md correctly 1`] = `
<span>
Loading
</span>
</button>
</button>,
<button
class="ant-btn ant-btn-primary ant-btn-sm ant-btn-loading"
type="button"
@@ -645,8 +818,37 @@ exports[`renders ./components/button/demo/loading.md correctly 1`] = `
<span>
Loading
</span>
</button>
<br />
</button>,
<button
class="ant-btn ant-btn-primary ant-btn-icon-only ant-btn-loading"
type="button"
>
<span
class="ant-btn-loading-icon"
>
<span
aria-label="loading"
class="anticon anticon-loading"
role="img"
>
<svg
aria-hidden="true"
class="anticon-spin"
data-icon="loading"
fill="currentColor"
focusable="false"
height="1em"
viewBox="0 0 1024 1024"
width="1em"
>
<path
d="M988 548c-19.9 0-36-16.1-36-36 0-59.4-11.6-117-34.6-171.3a440.45 440.45 0 00-94.3-139.9 437.71 437.71 0 00-139.9-94.3C629 83.6 571.4 72 512 72c-19.9 0-36-16.1-36-36s16.1-36 36-36c69.1 0 136.2 13.5 199.3 40.3C772.3 66 827 103 874 150c47 47 83.9 101.8 109.7 162.7 26.7 63.1 40.2 130.2 40.2 199.3.1 19.9-16 36-35.9 36z"
/>
</svg>
</span>
</span>
</button>,
<br />,
<button
class="ant-btn ant-btn-primary"
type="button"
@@ -654,7 +856,7 @@ exports[`renders ./components/button/demo/loading.md correctly 1`] = `
<span>
Click me!
</span>
</button>
</button>,
<button
class="ant-btn ant-btn-primary"
type="button"
@@ -682,8 +884,33 @@ exports[`renders ./components/button/demo/loading.md correctly 1`] = `
<span>
Click me!
</span>
</button>
</div>
</button>,
<button
class="ant-btn ant-btn-primary ant-btn-icon-only"
type="button"
>
<span
aria-label="poweroff"
class="anticon anticon-poweroff"
role="img"
>
<svg
aria-hidden="true"
class=""
data-icon="poweroff"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M705.6 124.9a8 8 0 00-11.6 7.2v64.2c0 5.5 2.9 10.6 7.5 13.6a352.2 352.2 0 0162.2 49.8c32.7 32.8 58.4 70.9 76.3 113.3a355 355 0 0127.9 138.7c0 48.1-9.4 94.8-27.9 138.7a355.92 355.92 0 01-76.3 113.3 353.06 353.06 0 01-113.2 76.4c-43.8 18.6-90.5 28-138.5 28s-94.7-9.4-138.5-28a353.06 353.06 0 01-113.2-76.4A355.92 355.92 0 01184 650.4a355 355 0 01-27.9-138.7c0-48.1 9.4-94.8 27.9-138.7 17.9-42.4 43.6-80.5 76.3-113.3 19-19 39.8-35.6 62.2-49.8 4.7-2.9 7.5-8.1 7.5-13.6V132c0-6-6.3-9.8-11.6-7.2C178.5 195.2 82 339.3 80 506.3 77.2 745.1 272.5 943.5 511.2 944c239 .5 432.8-193.3 432.8-432.4 0-169.2-97-315.7-238.4-386.7zM480 560h64c4.4 0 8-3.6 8-8V88c0-4.4-3.6-8-8-8h-64c-4.4 0-8 3.6-8 8v464c0 4.4 3.6 8 8 8z"
/>
</svg>
</span>
</button>,
]
`;
exports[`renders ./components/button/demo/multiple.md correctly 1`] = `

View File

@@ -1,12 +1,12 @@
import React, { Component } from 'react';
import { mount, render } from 'enzyme';
import renderer from 'react-test-renderer';
import { SearchOutlined } from '@ant-design/icons';
import Button from '..';
import ConfigProvider from '../../config-provider';
import mountTest from '../../../tests/shared/mountTest';
import rtlTest from '../../../tests/shared/rtlTest';
import { sleep } from '../../../tests/utils';
import { SizeType } from '../../config-provider/SizeContext';
describe('Button', () => {
mountTest(Button);
@@ -30,13 +30,14 @@ describe('Button', () => {
});
it('mount correctly', () => {
expect(() => renderer.create(<Button>Follow</Button>)).not.toThrow();
expect(() => mount(<Button>Follow</Button>)).not.toThrow();
});
it('warns if size is wrong', () => {
const mockWarn = jest.fn();
jest.spyOn(console, 'warn').mockImplementation(mockWarn);
render(<Button.Group size="who am I" />);
const size = ('who am I' as any) as SizeType;
render(<Button.Group size={size} />);
expect(mockWarn).toHaveBeenCalledTimes(1);
expect(mockWarn.mock.calls[0][0]).toMatchObject({
message: 'unreachable case: "who am I"',
@@ -74,7 +75,7 @@ describe('Button', () => {
});
it('renders Chinese characters correctly in HOC', () => {
const Text = ({ children }) => <span>{children}</span>;
const Text = ({ children }: { children: React.ReactNode }) => <span>{children}</span>;
const wrapper = mount(
<Button>
<Text></Text>
@@ -110,7 +111,7 @@ describe('Button', () => {
it('have static property for type detecting', () => {
const wrapper = mount(<Button>Button Text</Button>);
expect(wrapper.type().__ANT_BUTTON).toBe(true);
expect((wrapper.type() as any).__ANT_BUTTON).toBe(true);
});
it('should change loading state instantly by default', () => {
@@ -189,7 +190,7 @@ describe('Button', () => {
it('should has click wave effect', async () => {
const wrapper = mount(<Button type="primary">button</Button>);
wrapper.find('.ant-btn').getDOMNode().click();
wrapper.find('.ant-btn').getDOMNode<HTMLButtonElement>().click();
await new Promise(resolve => setTimeout(resolve, 0));
expect(wrapper.render()).toMatchSnapshot();
});
@@ -262,6 +263,5 @@ describe('Button', () => {
throw new Error('Should not called!!!');
},
});
wrapper.find('Button').instance().forceUpdate();
});
});

View File

@@ -4,7 +4,7 @@ import classNames from 'classnames';
import omit from 'omit.js';
import Group from './button-group';
import { ConfigContext, ConfigConsumerProps } from '../config-provider';
import { ConfigContext } from '../config-provider';
import Wave from '../_util/wave';
import { Omit, tuple } from '../_util/type';
import warning from '../_util/warning';
@@ -65,13 +65,21 @@ function spaceChildren(children: React.ReactNode, needInserted: boolean) {
);
}
const ButtonTypes = tuple('default', 'primary', 'ghost', 'dashed', 'danger', 'link');
const ButtonTypes = tuple('default', 'primary', 'ghost', 'dashed', 'link');
export type ButtonType = typeof ButtonTypes[number];
const ButtonShapes = tuple('circle', 'circle-outline', 'round');
export type ButtonShape = typeof ButtonShapes[number];
const ButtonHTMLTypes = tuple('submit', 'button', 'reset');
export type ButtonHTMLType = typeof ButtonHTMLTypes[number];
export type LegacyButtonType = ButtonType | 'danger';
export function convertLegacyProps(type?: LegacyButtonType): ButtonProps {
if (type === 'danger') {
return { danger: true };
}
return { type };
}
export interface BaseButtonProps {
type?: ButtonType;
icon?: React.ReactNode;
@@ -104,72 +112,59 @@ export type NativeButtonProps = {
export type ButtonProps = Partial<AnchorButtonProps & NativeButtonProps>;
interface ButtonState {
loading?: boolean | { delay?: number };
hasTwoCNChar: boolean;
interface CompoundedComponent
extends React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLElement>> {
Group: typeof Group;
__ANT_BUTTON: boolean;
}
class Button extends React.Component<ButtonProps, ButtonState> {
static Group: typeof Group;
const InternalButton: React.ForwardRefRenderFunction<unknown, ButtonProps> = (props, ref) => {
const size = React.useContext(SizeContext);
const [loading, setLoading] = React.useState(props.loading);
const [hasTwoCNChar, setHasTwoCNChar] = React.useState(false);
const { getPrefixCls, autoInsertSpaceInButton, direction } = React.useContext(ConfigContext);
const buttonRef = (ref as any) || React.createRef<HTMLElement>();
let delayTimeout: number;
static __ANT_BUTTON = true;
static contextType = ConfigContext;
static defaultProps = {
loading: false,
ghost: false,
block: false,
htmlType: 'button' as ButtonProps['htmlType'],
const isNeedInserted = () => {
const { icon, children, type } = props;
return React.Children.count(children) === 1 && !icon && type !== 'link';
};
private delayTimeout: number;
private buttonNode: HTMLElement | null;
constructor(props: ButtonProps) {
super(props);
this.state = {
loading: props.loading,
hasTwoCNChar: false,
};
}
componentDidMount() {
this.fixTwoCNChar();
}
componentDidUpdate(prevProps: ButtonProps) {
this.fixTwoCNChar();
if (prevProps.loading && typeof prevProps.loading !== 'boolean') {
clearTimeout(this.delayTimeout);
const fixTwoCNChar = () => {
// Fix for HOC usage like <FormatMessage />
if (!buttonRef || !buttonRef.current || autoInsertSpaceInButton === false) {
return;
}
const { loading } = this.props;
if (loading && typeof loading !== 'boolean' && loading.delay) {
this.delayTimeout = window.setTimeout(() => {
this.setState({ loading });
}, loading.delay);
} else if (prevProps.loading !== loading) {
// eslint-disable-next-line react/no-did-update-set-state
this.setState({ loading });
const buttonText = buttonRef.current.textContent;
if (isNeedInserted() && isTwoCNChar(buttonText)) {
if (!hasTwoCNChar) {
setHasTwoCNChar(true);
}
} else if (hasTwoCNChar) {
setHasTwoCNChar(false);
}
}
componentWillUnmount() {
if (this.delayTimeout) {
clearTimeout(this.delayTimeout);
}
}
saveButtonRef = (node: HTMLElement | null) => {
this.buttonNode = node;
};
handleClick: React.MouseEventHandler<HTMLButtonElement | HTMLAnchorElement> = e => {
const { loading } = this.state;
const { onClick } = this.props;
React.useEffect(() => {
if (props.loading && typeof props.loading !== 'boolean') {
clearTimeout(delayTimeout);
}
if (props.loading && typeof props.loading !== 'boolean' && props.loading.delay) {
delayTimeout = window.setTimeout(() => {
setLoading(props.loading);
}, props.loading.delay);
} else if (props.loading !== loading) {
setLoading(props.loading);
}
}, [props.loading]);
React.useEffect(() => {
fixTwoCNChar();
}, [buttonRef]);
const handleClick = (e: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement, MouseEvent>) => {
const { onClick } = props;
if (loading) {
return;
}
@@ -177,144 +172,115 @@ class Button extends React.Component<ButtonProps, ButtonState> {
(onClick as React.MouseEventHandler<HTMLButtonElement | HTMLAnchorElement>)(e);
}
};
const {
prefixCls: customizePrefixCls,
type,
danger,
shape,
size: customizeSize,
className,
children,
icon,
ghost,
block,
...rest
} = props;
fixTwoCNChar() {
const { autoInsertSpaceInButton }: ConfigConsumerProps = this.context;
warning(
!(typeof icon === 'string' && icon.length > 2),
'Button',
`\`icon\` is using ReactNode instead of string naming in v4. Please check \`${icon}\` at https://ant.design/components/icon`,
);
// Fix for HOC usage like <FormatMessage />
if (!this.buttonNode || autoInsertSpaceInButton === false) {
return;
}
const buttonText = this.buttonNode.textContent;
if (this.isNeedInserted() && isTwoCNChar(buttonText)) {
if (!this.state.hasTwoCNChar) {
this.setState({
hasTwoCNChar: true,
});
}
} else if (this.state.hasTwoCNChar) {
this.setState({
hasTwoCNChar: false,
});
}
const prefixCls = getPrefixCls('btn', customizePrefixCls);
const autoInsertSpace = autoInsertSpaceInButton !== false;
// large => lg
// small => sm
let sizeCls = '';
switch (customizeSize || size) {
case 'large':
sizeCls = 'lg';
break;
case 'small':
sizeCls = 'sm';
break;
default:
break;
}
isNeedInserted() {
const { icon, children, type } = this.props;
return React.Children.count(children) === 1 && !icon && type !== 'link';
}
const iconType = loading ? 'loading' : icon;
render() {
const { getPrefixCls, autoInsertSpaceInButton, direction }: ConfigConsumerProps = this.context;
const classes = classNames(prefixCls, className, {
[`${prefixCls}-${type}`]: type,
[`${prefixCls}-${shape}`]: shape,
[`${prefixCls}-${sizeCls}`]: sizeCls,
[`${prefixCls}-icon-only`]: !children && children !== 0 && iconType,
[`${prefixCls}-background-ghost`]: ghost,
[`${prefixCls}-loading`]: loading,
[`${prefixCls}-two-chinese-chars`]: hasTwoCNChar && autoInsertSpace,
[`${prefixCls}-block`]: block,
[`${prefixCls}-dangerous`]: !!danger,
[`${prefixCls}-rtl`]: direction === 'rtl',
});
const iconNode =
icon && !loading ? (
icon
) : (
<LoadingIcon existIcon={!!icon} prefixCls={prefixCls} loading={loading} />
);
const kids =
children || children === 0
? spaceChildren(children, isNeedInserted() && autoInsertSpace)
: null;
const linkButtonRestProps = omit(rest as AnchorButtonProps, ['htmlType', 'loading']);
if (linkButtonRestProps.href !== undefined) {
return (
<SizeContext.Consumer>
{size => {
const {
prefixCls: customizePrefixCls,
type,
danger,
shape,
size: customizeSize,
className,
children,
icon,
ghost,
block,
...rest
} = this.props;
const { loading, hasTwoCNChar } = this.state;
warning(
!(typeof icon === 'string' && icon.length > 2),
'Button',
`\`icon\` is using ReactNode instead of string naming in v4. Please check \`${icon}\` at https://ant.design/components/icon`,
);
const prefixCls = getPrefixCls('btn', customizePrefixCls);
const autoInsertSpace = autoInsertSpaceInButton !== false;
// large => lg
// small => sm
let sizeCls = '';
switch (customizeSize || size) {
case 'large':
sizeCls = 'lg';
break;
case 'small':
sizeCls = 'sm';
break;
default:
break;
}
const iconType = loading ? 'loading' : icon;
const classes = classNames(prefixCls, className, {
[`${prefixCls}-${type}`]: type,
[`${prefixCls}-${shape}`]: shape,
[`${prefixCls}-${sizeCls}`]: sizeCls,
[`${prefixCls}-icon-only`]: !children && children !== 0 && iconType,
[`${prefixCls}-background-ghost`]: ghost,
[`${prefixCls}-loading`]: loading,
[`${prefixCls}-two-chinese-chars`]: hasTwoCNChar && autoInsertSpace,
[`${prefixCls}-block`]: block,
[`${prefixCls}-dangerous`]: !!danger,
[`${prefixCls}-rtl`]: direction === 'rtl',
});
const iconNode =
icon && !loading ? (
icon
) : (
<LoadingIcon existIcon={!!icon} prefixCls={prefixCls} loading={loading} />
);
const kids =
children || children === 0
? spaceChildren(children, this.isNeedInserted() && autoInsertSpace)
: null;
const linkButtonRestProps = omit(rest as AnchorButtonProps, ['htmlType', 'loading']);
if (linkButtonRestProps.href !== undefined) {
return (
<a
{...linkButtonRestProps}
className={classes}
onClick={this.handleClick}
ref={this.saveButtonRef}
>
{iconNode}
{kids}
</a>
);
}
// React does not recognize the `htmlType` prop on a DOM element. Here we pick it out of `rest`.
const { htmlType, ...otherProps } = rest as NativeButtonProps;
const buttonNode = (
<button
{...(omit(otherProps, ['loading']) as NativeButtonProps)}
type={htmlType}
className={classes}
onClick={this.handleClick}
ref={this.saveButtonRef}
>
{iconNode}
{kids}
</button>
);
if (type === 'link') {
return buttonNode;
}
return <Wave>{buttonNode}</Wave>;
}}
</SizeContext.Consumer>
<a {...linkButtonRestProps} className={classes} onClick={handleClick} ref={buttonRef}>
{iconNode}
{kids}
</a>
);
}
}
// React does not recognize the `htmlType` prop on a DOM element. Here we pick it out of `rest`.
const { htmlType, ...otherProps } = rest as NativeButtonProps;
const buttonNode = (
<button
{...(omit(otherProps, ['loading']) as NativeButtonProps)}
type={htmlType}
className={classes}
onClick={handleClick}
ref={buttonRef}
>
{iconNode}
{kids}
</button>
);
if (type === 'link') {
return buttonNode;
}
return <Wave>{buttonNode}</Wave>;
};
const Button = React.forwardRef<unknown, ButtonProps>(InternalButton) as CompoundedComponent;
Button.displayName = 'Button';
Button.defaultProps = {
loading: false,
ghost: false,
block: false,
htmlType: 'button' as ButtonProps['htmlType'],
};
Button.Group = Group;
Button.__ANT_BUTTON = true;
export default Button;

View File

@@ -15,7 +15,8 @@ Debug usage
Debug usage
```jsx
import { Button } from 'antd';
import { Button, Tooltip } from 'antd';
import { DownloadOutlined } from '@ant-design/icons';
function getGroup(props) {
return (
@@ -23,6 +24,12 @@ function getGroup(props) {
<Button.Group {...props}>
<Button type="primary">Button 1</Button>
<Button type="primary">Button 2</Button>
<Tooltip title="Tooltip">
<Button type="primary" icon={<DownloadOutlined />} disabled />
</Tooltip>
<Tooltip title="Tooltip">
<Button type="primary" icon={<DownloadOutlined />} />
</Tooltip>
</Button.Group>
</div>
);
@@ -31,9 +38,17 @@ function getGroup(props) {
ReactDOM.render(
<div>
{getGroup({ size: 'small' })}
<br />
{getGroup()}
<br />
{getGroup({ size: 'large' })}
</div>,
mountNode,
);
```
```css
#components-button-demo-legacy-group .ant-btn {
margin: 0;
}
```

View File

@@ -19,46 +19,51 @@ import { PoweroffOutlined } from '@ant-design/icons';
class App extends React.Component {
state = {
loading: false,
iconLoading: false,
loadings: [],
};
enterLoading = () => {
this.setState({ loading: true });
enterLoading = index => {
const newLoadings = [...this.state.loadings];
newLoadings[index] = true;
this.setState({
loadings: newLoadings,
});
setTimeout(() => {
this.setState({ loading: false });
}, 8000);
};
enterIconLoading = () => {
this.setState({ iconLoading: true });
setTimeout(() => {
this.setState({ iconLoading: false });
}, 8000);
newLoadings[index] = false;
this.setState({ loadings: newLoadings });
}, 6000);
};
render() {
const { loadings } = this.state;
return (
<div>
<>
<Button type="primary" loading>
Loading
</Button>
<Button type="primary" size="small" loading>
Loading
</Button>
<Button type="primary" icon={<PoweroffOutlined />} loading />
<br />
<Button type="primary" loading={this.state.loading} onClick={this.enterLoading}>
<Button type="primary" loading={loadings[0]} onClick={() => this.enterLoading(0)}>
Click me!
</Button>
<Button
type="primary"
icon={<PoweroffOutlined />}
loading={this.state.iconLoading}
onClick={this.enterIconLoading}
loading={loadings[1]}
onClick={() => this.enterLoading(1)}
>
Click me!
</Button>
</div>
<Button
type="primary"
icon={<PoweroffOutlined />}
loading={loadings[2]}
onClick={() => this.enterLoading(2)}
/>
</>
);
}
}

View File

@@ -54,12 +54,15 @@ Following the Ant Design specification, we will add one space between if Button
<img src="https://gw.alipayobjects.com/zos/antfincdn/MY%26THAPZrW/38f06cb9-293a-4b42-b183-9f443e79ffea.png" style="box-shadow: none; margin: 0; width: 100px" alt="Button with two Chinese characters" />
<style>
[id^=components-button-demo-] .ant-btn {
margin-right: 8px;
margin-bottom: 12px;
}
[id^="components-button-demo-"] .ant-btn-rtl {
margin-right: 0;
margin-left: 8px;
}
[id^=components-button-demo-] .ant-btn-group > .ant-btn,
[id^=components-button-demo-] .ant-btn-group > span > .ant-btn {
margin-right: 0;

View File

@@ -1,9 +1,7 @@
import Button from './button';
import ButtonGroup from './button-group';
export { ButtonProps, ButtonShape, ButtonType } from './button';
export { ButtonGroupProps } from './button-group';
export { SizeType as ButtonSize } from '../config-provider/SizeContext';
Button.Group = ButtonGroup;
export default Button;

View File

@@ -11,7 +11,7 @@ subtitle: 按钮
标记了一个(或封装一组)操作命令,响应用户点击行为,触发相应的业务逻辑。
在 Ant Design 中我们四种按钮。
在 Ant Design 中我们提供了四种按钮。
- 主按钮:用于主行动点,一个操作区域只能有一个主按钮。
- 默认按钮:用于没有主次之分的一组行动点。
@@ -62,6 +62,10 @@ subtitle: 按钮
margin-right: 8px;
margin-bottom: 12px;
}
[id^="components-button-demo-"] .ant-btn-rtl {
margin-right: 0;
margin-left: 8px;
}
[id^="components-button-demo-"] .ant-btn-group > .ant-btn {
margin-right: 0;
}

View File

@@ -94,10 +94,7 @@
&-icon-only {
.btn-square(@btn-prefix-cls);
> i {
vertical-align: middle;
}
vertical-align: -0.5px;
}
&-round {
@@ -158,6 +155,12 @@
.@{iconfont-css-prefix} {
padding-right: @margin-xs;
}
&:only-child {
.@{iconfont-css-prefix} {
padding-right: 0;
}
}
}
&-group {

View File

@@ -165,7 +165,7 @@
}
.button-group-base(@btnClassName) {
position: relative;
display: inline-block;
display: inline-flex;
> .@{btnClassName},
> span > .@{btnClassName} {
position: relative;
@@ -179,7 +179,7 @@
z-index: 0;
}
}
> .@{btnClassName}-icon-only {
.@{btnClassName}-icon-only {
font-size: @font-size-base;
}
// size
@@ -187,7 +187,7 @@
&-lg > span > .@{btnClassName} {
.button-size(@btn-height-lg; @btn-padding-horizontal-lg; @btn-font-size-lg; 0);
}
&-lg > .@{btnClassName}.@{btnClassName}-icon-only {
&-lg .@{btnClassName}.@{btnClassName}-icon-only {
.square(@btn-height-lg);
padding-right: 0;
padding-left: 0;
@@ -199,7 +199,7 @@
font-size: @font-size-base;
}
}
&-sm > .@{btnClassName}.@{btnClassName}-icon-only {
&-sm .@{btnClassName}.@{btnClassName}-icon-only {
.square(@btn-height-sm);
padding-right: 0;
padding-left: 0;

View File

@@ -24,30 +24,18 @@
}
}
&&-loading:not(&-circle):not(&-circle-outline):not(&-icon-only) {
.@{btn-prefix-cls}-rtl& {
padding-right: 29px;
padding-left: @padding-md - 1px;
}
.@{iconfont-css-prefix}:not(:last-child) {
.@{btn-prefix-cls}-rtl& {
margin-right: -14px;
margin-left: 0;
}
}
}
&-sm&-loading:not(&-circle):not(&-circle-outline):not(&-icon-only) {
.@{btn-prefix-cls}-rtl& {
padding-right: 24px;
padding-left: @padding-xs - 1px;
}
& > &-loading-icon {
.@{iconfont-css-prefix} {
.@{btn-prefix-cls}-rtl& {
margin-right: -17px;
margin-left: 0;
padding-right: 0;
padding-left: @margin-xs;
}
}
&:only-child {
.@{iconfont-css-prefix} {
padding-right: 0;
padding-left: 0;
}
}
}

View File

@@ -942,7 +942,7 @@ exports[`Calendar Calendar should support locale 1`] = `
exports[`Calendar rtl render component should be rendered correctly in RTL direction 1`] = `
<div
class="ant-picker-calendar ant-picker-calendar-full"
class="ant-picker-calendar ant-picker-calendar-full ant-picker-calendar-rtl"
>
<div
class="ant-picker-calendar-header"

View File

@@ -98,7 +98,7 @@ function generateCalendar<DateType>(generateConfig: GenerateConfig<DateType>) {
onPanelChange,
onSelect,
} = props;
const { getPrefixCls } = React.useContext(ConfigContext);
const { getPrefixCls, direction } = React.useContext(ConfigContext);
const prefixCls = getPrefixCls('picker', customizePrefixCls);
const calendarPrefixCls = `${prefixCls}-calendar`;
const today = generateConfig.getNow();
@@ -239,6 +239,7 @@ function generateCalendar<DateType>(generateConfig: GenerateConfig<DateType>) {
className={classNames(calendarPrefixCls, className, {
[`${calendarPrefixCls}-full`]: fullscreen,
[`${calendarPrefixCls}-mini`]: !fullscreen,
[`${calendarPrefixCls}-rtl`]: direction === 'rtl',
})}
style={style}
>

View File

@@ -14,7 +14,6 @@
justify-content: flex-end;
padding: @padding-sm 0;
.@{calendar-prefix-cls}-year-select {
min-width: 80px;
}
@@ -190,3 +189,4 @@
}
}
@import './rtl';

View File

@@ -0,0 +1,44 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
@calendar-prefix-cls: ~'@{ant-prefix}-picker-calendar';
@calendar-picker-prefix-cls: ~'@{ant-prefix}-picker';
.@{calendar-prefix-cls} {
&-rtl {
direction: rtl;
}
&-header {
.@{calendar-prefix-cls}-month-select {
.@{calendar-prefix-cls}-rtl & {
margin-right: @padding-xs;
margin-left: 0;
}
}
.@{calendar-prefix-cls}-mode-switch {
.@{calendar-prefix-cls}-rtl & {
margin-right: @padding-xs;
margin-left: 0;
}
}
}
// ========================== Full ==========================
&-full {
.@{calendar-picker-prefix-cls}-panel {
.@{calendar-prefix-cls}-rtl& {
text-align: left;
}
.@{calendar-picker-prefix-cls}-body {
th {
.@{calendar-prefix-cls}-rtl& {
padding: 0 0 5px 12px;
}
}
}
}
}
}

View File

@@ -23,8 +23,8 @@ A card can be used to display content related to a single subject. The content c
| --- | --- | --- | --- | --- |
| actions | The action list, shows at the bottom of the Card. | Array&lt;ReactNode> | - | |
| activeTabKey | Current TabPane's key | string | - | |
| headStyle | Inline style to apply to the card head | object | - | |
| bodyStyle | Inline style to apply to the card content | object | - | |
| headStyle | Inline style to apply to the card head | CSSProperties | - | |
| bodyStyle | Inline style to apply to the card content | CSSProperties | - | |
| bordered | Toggles rendering of the border around the card | boolean | `true` | |
| cover | Card cover | ReactNode | - | |
| defaultActiveTabKey | Initial active TabPane's key, if `activeTabKey` is not set. | string | - | |
@@ -37,22 +37,22 @@ A card can be used to display content related to a single subject. The content c
| title | Card title | string\|ReactNode | - | |
| type | Card style type, can be set to `inner` or not set | string | - | |
| onTabChange | Callback when tab is switched | (key) => void | - | |
| tabProps | [Tabs](https://ant.design/components/tabs/#Tabs) | - | - | |
| tabProps | [Tabs](/components/tabs/#Tabs) | - | - | |
### Card.Grid
| Property | Description | Type | Default | Version |
| --------- | ------------------------------- | ------- | ------- | ------- |
| className | className of container | string | - | |
| hoverable | Lift up when hovering card grid | boolean | true | |
| style | style object of container | object | - | |
| Property | Description | Type | Default | Version |
| --------- | ------------------------------- | ------------- | ------- | ------- |
| className | className of container | string | - | |
| hoverable | Lift up when hovering card grid | boolean | true | |
| style | style object of container | CSSProperties | - | |
### Card.Meta
| Property | Description | Type | Default | Version |
| ----------- | ------------------------- | --------- | ------- | ------- |
| avatar | avatar or icon | ReactNode | - | |
| className | className of container | string | - | |
| description | description content | ReactNode | - | |
| style | style object of container | object | - | |
| title | title content | ReactNode | - | |
| Property | Description | Type | Default | Version |
| ----------- | ------------------------- | ------------- | ------- | ------- |
| avatar | avatar or icon | ReactNode | - | |
| className | className of container | string | - | |
| description | description content | ReactNode | - | |
| style | style object of container | CSSProperties | - | |
| title | title content | ReactNode | - | |

View File

@@ -24,8 +24,8 @@ cols: 1
| --- | --- | --- | --- | --- |
| actions | 卡片操作组,位置在卡片底部 | Array&lt;ReactNode> | - | |
| activeTabKey | 当前激活页签的 key | string | - | |
| headStyle | 自定义标题区域样式 | object | - | |
| bodyStyle | 内容区域自定义样式 | object | - | |
| headStyle | 自定义标题区域样式 | CSSProperties | - | |
| bodyStyle | 内容区域自定义样式 | CSSProperties | - | |
| bordered | 是否有边框 | boolean | true | |
| cover | 卡片封面 | ReactNode | - | |
| defaultActiveTabKey | 初始化选中页签的 key如果没有设置 activeTabKey | string | 第一个页签 | |
@@ -38,22 +38,22 @@ cols: 1
| title | 卡片标题 | string\|ReactNode | - | |
| type | 卡片类型,可设置为 `inner` 或 不设置 | string | - | |
| onTabChange | 页签切换的回调 | (key) => void | - | |
| tabProps | [Tabs](https://ant.design/components/tabs-cn/#Tabs) | - | - | |
| tabProps | [Tabs](/components/tabs/#Tabs) | - | - | |
### Card.Grid
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| --------- | ---------------------- | ------- | ------ | ---- |
| className | 网格容器类名 | string | - | |
| hoverable | 鼠标移过时可浮起 | boolean | true | |
| style | 定义网格容器类名的样式 | object | - | |
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| --------- | ---------------------- | ------------- | ------ | ---- |
| className | 网格容器类名 | string | - | |
| hoverable | 鼠标移过时可浮起 | boolean | true | |
| style | 定义网格容器类名的样式 | CSSProperties | - | |
### Card.Meta
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| ----------- | ------------------ | --------- | ------ | ---- |
| avatar | 头像/图标 | ReactNode | - | |
| className | 容器类名 | string | - | |
| description | 描述内容 | ReactNode | - | |
| style | 定义容器类名的样式 | object | - | |
| title | 标题内容 | ReactNode | - | |
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| ----------- | ------------------ | ------------- | ------ | ---- |
| avatar | 头像/图标 | ReactNode | - | |
| className | 容器类名 | string | - | |
| description | 描述内容 | ReactNode | - | |
| style | 定义容器类名的样式 | CSSProperties | - | |
| title | 标题内容 | ReactNode | - | |

View File

@@ -166,7 +166,7 @@
display: block;
min-width: 32px;
font-size: @font-size-base;
line-height: 22px;
line-height: @line-height-base;
cursor: pointer;
&:hover {

View File

@@ -451,7 +451,7 @@ exports[`renders ./components/carousel/demo/fade.md correctly 1`] = `
aria-hidden="false"
class="slick-slide slick-active slick-current"
data-index="0"
style="outline:none;width:11.11111111111111%;position:relative;left:0;opacity:1;transition:opacity 500ms ease, visibility 500ms ease;-webkit-transition:opacity 500ms ease, visibility 500ms ease"
style="outline:none;width:11.11111111111111%;position:relative;left:0;opacity:1;transition:opacity 500ms ease, visibility 500ms ease"
tabindex="-1"
>
<div>
@@ -469,7 +469,7 @@ exports[`renders ./components/carousel/demo/fade.md correctly 1`] = `
aria-hidden="true"
class="slick-slide"
data-index="1"
style="outline:none;width:11.11111111111111%;position:relative;left:-11px;opacity:0;transition:opacity 500ms ease, visibility 500ms ease;-webkit-transition:opacity 500ms ease, visibility 500ms ease"
style="outline:none;width:11.11111111111111%;position:relative;left:-11px;opacity:0;transition:opacity 500ms ease, visibility 500ms ease"
tabindex="-1"
>
<div>
@@ -487,7 +487,7 @@ exports[`renders ./components/carousel/demo/fade.md correctly 1`] = `
aria-hidden="true"
class="slick-slide"
data-index="2"
style="outline:none;width:11.11111111111111%;position:relative;left:-22px;opacity:0;transition:opacity 500ms ease, visibility 500ms ease;-webkit-transition:opacity 500ms ease, visibility 500ms ease"
style="outline:none;width:11.11111111111111%;position:relative;left:-22px;opacity:0;transition:opacity 500ms ease, visibility 500ms ease"
tabindex="-1"
>
<div>
@@ -505,7 +505,7 @@ exports[`renders ./components/carousel/demo/fade.md correctly 1`] = `
aria-hidden="true"
class="slick-slide"
data-index="3"
style="outline:none;width:11.11111111111111%;position:relative;left:-33px;opacity:0;transition:opacity 500ms ease, visibility 500ms ease;-webkit-transition:opacity 500ms ease, visibility 500ms ease"
style="outline:none;width:11.11111111111111%;position:relative;left:-33px;opacity:0;transition:opacity 500ms ease, visibility 500ms ease"
tabindex="-1"
>
<div>

View File

@@ -32,4 +32,4 @@ A carousel component. Scales with its container.
| next() | Change current slide to next slide |
| prev() | Change current slide to previous slide |
For more info on the parameters, refer to the <https://github.com/akiran/react-slick>
Find more APIs in react-slick [documentation](https://react-slick.neostack.com/docs/api).

View File

@@ -33,4 +33,4 @@ subtitle: 走马灯
| next() | 切换到下一面板 |
| prev() | 切换到上一面板 |
更多参数可参考:<https://github.com/akiran/react-slick>
更多 API 可参考:<https://react-slick.neostack.com/docs/api>

View File

@@ -33,8 +33,19 @@
.slick-slide {
pointer-events: none;
// https://github.com/ant-design/ant-design/issues/23294
input.@{ant-prefix}-radio-input,
input.@{ant-prefix}-checkbox-input {
visibility: hidden;
}
&.slick-active {
pointer-events: auto;
input.@{ant-prefix}-radio-input,
input.@{ant-prefix}-checkbox-input {
visibility: visible;
}
}
}
}

View File

@@ -40,7 +40,7 @@ Cascade selection box.
| popupVisible | set visible of cascader popup | boolean | - | |
| showSearch | Whether show search input in single mode. | boolean\|object | false | |
| size | input size | `large` \| `middle` \| `small` | | |
| style | additional style | string | - | |
| style | additional style | CSSProperties | - | |
| suffixIcon | The custom suffix icon | ReactNode | - | |
| value | selected value | string\[] | - | |
| onChange | callback when finishing cascader select | `(value, selectedOptions) => void` | - | |

View File

@@ -41,7 +41,7 @@ subtitle: 级联选择
| popupVisible | 控制浮层显隐 | boolean | - | |
| showSearch | 在选择框中显示搜索框 | boolean | false | |
| size | 输入框大小 | `large` \| `middle` \| `small` | 无 | |
| style | 自定义样式 | string | - | |
| style | 自定义样式 | CSSProperties | - | |
| suffixIcon | 自定义的选择框后缀图标 | ReactNode | - | |
| value | 指定选中项 | string\[] | - | |
| onChange | 选择完成后的回调 | `(value, selectedOptions) => void` | - | |

View File

@@ -63,7 +63,7 @@ class Checkbox extends React.PureComponent<CheckboxProps, {}> {
warning(
'checked' in this.props || this.context || !('value' in this.props),
'Checkbox',
'`value` is not validate prop, do you mean `checked`?',
'`value` is not a valid prop, do you mean `checked`?',
);
}

View File

@@ -1,5 +1,4 @@
import * as React from 'react';
import * as PropTypes from 'prop-types';
import classNames from 'classnames';
import omit from 'omit.js';
import Checkbox, { CheckboxChangeEvent } from './Checkbox';
@@ -48,13 +47,6 @@ class CheckboxGroup extends React.PureComponent<CheckboxGroupProps, CheckboxGrou
options: [],
};
static propTypes = {
defaultValue: PropTypes.array,
value: PropTypes.array,
options: PropTypes.array.isRequired,
onChange: PropTypes.func,
};
static getDerivedStateFromProps(nextProps: CheckboxGroupProps) {
if ('value' in nextProps) {
return {

View File

@@ -30,7 +30,7 @@ describe('Checkbox', () => {
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
mount(<Checkbox value />);
expect(errorSpy).toHaveBeenCalledWith(
'Warning: [antd: Checkbox] `value` is not validate prop, do you mean `checked`?',
'Warning: [antd: Checkbox] `value` is not a valid prop, do you mean `checked`?',
);
errorSpy.mockRestore();
});

View File

@@ -171,7 +171,7 @@
display: inline-block;
&-item {
display: inline-block;
margin-right: 8px;
margin-right: @checkbox-group-item-margin-right;
&:last-child {
margin-right: 0;
}

View File

@@ -7,7 +7,7 @@ import CollapsePanel from './CollapsePanel';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import animation from '../_util/openAnimation';
export type ExpandIconPosition = 'left' | 'right';
export type ExpandIconPosition = 'left' | 'right' | undefined;
export interface CollapseProps {
activeKey?: Array<string | number> | string | number;
@@ -40,9 +40,16 @@ export default class Collapse extends React.Component<CollapseProps, any> {
static defaultProps = {
bordered: true,
expandIconPosition: 'left' as CollapseProps['expandIconPosition'],
};
getIconPosition(direction: string = 'ltr') {
const { expandIconPosition } = this.props;
if (expandIconPosition !== undefined) {
return expandIconPosition;
}
return direction === 'rtl' ? 'right' : 'left';
}
renderExpandIcon = (panelProps: PanelProps = {}, prefixCls: string) => {
const { expandIcon } = this.props;
const icon = (expandIcon ? (
@@ -59,17 +66,13 @@ export default class Collapse extends React.Component<CollapseProps, any> {
};
renderCollapse = ({ getPrefixCls, direction }: ConfigConsumerProps) => {
const {
prefixCls: customizePrefixCls,
className = '',
bordered,
expandIconPosition,
} = this.props;
const { prefixCls: customizePrefixCls, className = '', bordered } = this.props;
const prefixCls = getPrefixCls('collapse', customizePrefixCls);
const iconPosition = this.getIconPosition(direction);
const collapseClassName = classNames(
{
[`${prefixCls}-borderless`]: !bordered,
[`${prefixCls}-icon-position-${expandIconPosition}`]: true,
[`${prefixCls}-icon-position-${iconPosition}`]: true,
[`${prefixCls}-rtl`]: direction === 'rtl',
},
className,

View File

@@ -658,6 +658,7 @@ exports[`renders ./components/collapse/demo/extra.md correctly 1`] = `
</span>
<div
class="ant-select ant-select-single ant-select-show-arrow"
style="margin:0 8px"
>
<div
class="ant-select-selector"

View File

@@ -51,7 +51,7 @@ exports[`Collapse could override default openAnimation 1`] = `
exports[`Collapse rtl render component should be rendered correctly in RTL direction 1`] = `
<div
class="ant-collapse ant-collapse-icon-position-left ant-collapse-rtl"
class="ant-collapse ant-collapse-icon-position-right ant-collapse-rtl"
/>
`;

View File

@@ -69,7 +69,11 @@ class Demo extends React.Component {
</Collapse>
<br />
<span>Expand Icon Position: </span>
<Select value={expandIconPosition} onChange={this.onPositionChange}>
<Select
value={expandIconPosition}
style={{ margin: '0 8px' }}
onChange={this.onPositionChange}
>
<Option value="left">left</Option>
<Option value="right">right</Option>
</Select>

View File

@@ -26,7 +26,7 @@
padding: @collapse-header-padding;
padding-left: @collapse-header-padding-extra;
color: @heading-color;
line-height: 22px;
line-height: @line-height-base;
cursor: pointer;
transition: all 0.3s;
.clearfix;
@@ -36,7 +36,7 @@
position: absolute;
top: 50%;
left: @padding-md;
left: @collapse-header-arrow-left;
display: inline-block;
font-size: @font-size-sm;
transform: translateY(-50%);

Some files were not shown because too many files have changed in this diff Show More